129 lines
2.3 KiB
Go
129 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"opslag.de/schobers/zntg/ui"
|
|
)
|
|
|
|
type Menu struct {
|
|
ui.StackPanel
|
|
|
|
OnEscape func(ui.Context)
|
|
|
|
active int
|
|
buttons []*MenuButton
|
|
}
|
|
|
|
func NewMenu() *Menu {
|
|
return &Menu{
|
|
StackPanel: ui.StackPanel{
|
|
Orientation: ui.OrientationVertical,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (m *Menu) Activate(i int) {
|
|
if len(m.buttons) == 0 || i < 0 {
|
|
return
|
|
}
|
|
m.updateActiveButton(i % len(m.buttons))
|
|
}
|
|
|
|
func (m *Menu) Add(text string, click func(ui.Context)) {
|
|
button := NewMenuButton(text, click)
|
|
if len(m.buttons) == 0 {
|
|
button.Over = true
|
|
}
|
|
m.buttons = append(m.buttons, button)
|
|
m.AddChild(button)
|
|
}
|
|
|
|
func (m *Menu) Handle(ctx ui.Context, e ui.Event) bool {
|
|
if m.StackPanel.Handle(ctx, e) {
|
|
return true
|
|
}
|
|
|
|
if len(m.buttons) == 0 {
|
|
return false
|
|
}
|
|
|
|
switch e := e.(type) {
|
|
case *ui.KeyDownEvent:
|
|
switch e.Key {
|
|
case ui.KeyEscape:
|
|
if onEscape := m.OnEscape; onEscape != nil {
|
|
onEscape(ctx)
|
|
}
|
|
case ui.KeyDown:
|
|
m.updateActiveButton((m.active + 1) % len(m.buttons))
|
|
case ui.KeyUp:
|
|
m.updateActiveButton((m.active + len(m.buttons) - 1) % len(m.buttons))
|
|
case ui.KeyEnter:
|
|
m.buttons[m.active].InvokeClick(ctx)
|
|
}
|
|
case *ui.MouseMoveEvent:
|
|
for i, button := range m.buttons {
|
|
if button.IsOver() {
|
|
m.updateActiveButton(i)
|
|
break
|
|
}
|
|
}
|
|
m.updateActiveButton(m.active)
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (m *Menu) updateActiveButton(active int) {
|
|
m.active = active
|
|
for i, btn := range m.buttons {
|
|
btn.Over = i == m.active
|
|
}
|
|
}
|
|
|
|
type MenuButton struct {
|
|
ui.Label
|
|
|
|
Over bool
|
|
Click func(ui.Context)
|
|
}
|
|
|
|
func NewMenuButton(text string, click func(ui.Context)) *MenuButton {
|
|
b := &MenuButton{
|
|
Label: ui.Label{
|
|
Text: text,
|
|
},
|
|
Click: click,
|
|
}
|
|
b.ControlClicked().AddHandler(func(ctx ui.Context, _ ui.ControlClickedArgs) {
|
|
b.InvokeClick(ctx)
|
|
})
|
|
return b
|
|
}
|
|
|
|
func (b *MenuButton) Handle(ctx ui.Context, e ui.Event) bool {
|
|
if b.ControlBase.Handle(ctx, e) {
|
|
return true
|
|
}
|
|
if b.IsOver() {
|
|
b.Over = true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (b *MenuButton) InvokeClick(ctx ui.Context) {
|
|
if b.Click != nil {
|
|
b.Click(ctx)
|
|
}
|
|
}
|
|
|
|
func (b *MenuButton) Render(ctx ui.Context) {
|
|
font := b.ActualFont(ctx)
|
|
textWidth := font.WidthOf(b.Text)
|
|
bounds := b.Bounds()
|
|
left := .5 * (bounds.Dx() - textWidth)
|
|
color := ctx.Style().Palette.Text
|
|
if b.Over {
|
|
color = ctx.Style().Palette.Primary
|
|
}
|
|
ctx.Renderer().Text(font, bounds.Min.Add2D(left, 0), color, b.Text)
|
|
}
|