package ui import ( "github.com/gdamore/tcell/v2" "codeberg.org/turbo-editors/turbo-core/theme" ) // Widget is anything the framework draws and hands events to. // // Bounds are in absolute screen coordinates. That makes hit-testing a mouse // click a plain rectangle test, at the cost of every container having to place // its children in screen space — a trade this package makes everywhere. // // HandleKey and HandleMouse return whether they consumed the event. An // unconsumed event travels on to whatever is behind, which is how a click that // misses every control lands on the window underneath. type Widget interface { Bounds() Rect SetBounds(r Rect) Draw(p *Painter, th *theme.Theme) HandleKey(ev *tcell.EventKey) bool HandleMouse(ev *tcell.EventMouse) bool } // Focusable is a widget that can hold the keyboard focus inside a dialog. type Focusable interface { Widget SetFocused(focused bool) Focused() bool CanFocus() bool } // Box is the state every widget has: where it is. Embed it to get Bounds, // SetBounds and event handlers that ignore everything, then override only what // the widget actually reacts to. type Box struct { bounds Rect } // Bounds returns the widget's rectangle, in absolute screen coordinates. func (b *Box) Bounds() Rect { return b.bounds } // SetBounds places the widget. Containers call it when they lay out. func (b *Box) SetBounds(r Rect) { b.bounds = r } // HandleKey ignores the key. Widgets that react to keys override this. func (b *Box) HandleKey(*tcell.EventKey) bool { return false } // HandleMouse ignores the click. Widgets that react to the mouse override it. func (b *Box) HandleMouse(*tcell.EventMouse) bool { return false } // hit reports whether a mouse event landed on the widget. func (b *Box) hit(ev *tcell.EventMouse) bool { x, y := ev.Position() return b.bounds.Contains(x, y) } // FocusBox is Box plus the focus flag, for widgets that live in a dialog. type FocusBox struct { Box focused bool } // Focused reports whether this widget currently has the keyboard focus. func (f *FocusBox) Focused() bool { return f.focused } // SetFocused gives or takes the keyboard focus. func (f *FocusBox) SetFocused(focused bool) { f.focused = focused } // CanFocus reports whether the focus ring should stop here. Widgets that are // only decoration, such as a label, override this to return false. func (f *FocusBox) CanFocus() bool { return true }