package ui import "9front/gui/draw" // An Item is one line of a menu. type Item struct { Label string Do func() } // Menu pops up at p and tracks until button 3 comes back up, the way // page(1) and vdir(1) do it: press 3, drag, release on an item. // // It keeps itself on the screen, which is the detail everyone forgets // until the menu opens near the bottom edge and half of it is missing. // redraw is called if the menu is dismissed without a choice. func (u *UI) Menu(items []Item, at draw.Point, mc *draw.Mousectl, redraw func()) { if len(items) == 0 { return } lh := int32(u.F.Height) + 4 var w int32 for _, it := range items { if x := u.F.Width(it.Label) + 20; x > w { w = x } } h := lh*int32(len(items)) + 4 win := u.Win.Rect() r := draw.Rect(at.X, at.Y, at.X+w, at.Y+h) if r.Max.X > win.Max.X { r = r.Add(draw.Point{X: win.Max.X - r.Max.X}) } if r.Max.Y > win.Max.Y { r = r.Add(draw.Point{Y: win.Max.Y - r.Max.Y}) } sel := -1 paint := func() { u.Fill(r, "tag") u.Border(r, "border") for i, it := range items { ir := draw.Rect(r.Min.X+1, r.Min.Y+2+int32(i)*lh, r.Max.X-1, r.Min.Y+2+int32(i+1)*lh) if i == sel { u.Fill(ir, "today") } u.Text(draw.Point{X: ir.Min.X + 8, Y: ir.Min.Y + 2}, "ink", it.Label) } u.D.Flush() } itemAt := func(p draw.Point) int { if p.X < r.Min.X || p.X >= r.Max.X { return -1 } i := int((p.Y - r.Min.Y - 2) / lh) if i < 0 || i >= len(items) || p.Y < r.Min.Y+2 { return -1 } return i } paint() for m := range mc.C { if n := itemAt(m.Point); n != sel { sel = n paint() } if m.Buttons&4 == 0 { if sel >= 0 { items[sel].Do() } else { redraw() } return } } }