tins2021/cmd/tins2021/menu.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)
}