diff options
Diffstat (limited to 'gui/ui/menu.go')
| -rw-r--r-- | gui/ui/menu.go | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/gui/ui/menu.go b/gui/ui/menu.go new file mode 100644 index 0000000..7fe7ff8 --- /dev/null +++ b/gui/ui/menu.go @@ -0,0 +1,79 @@ +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 + } + } +} |
