Noah Petherbridge
7d9ba79cd2
* Adds Window Manager support to the Supervisor, so that Window widgets can be dragged by their title bar, clicked to focus, etc. * Create a ui.Window as normal, but instead of Packing or Placing it into a parent container as before, you call .Supervise() and give it your Supervisor. The window registers itself to be managed and drawn by the Supervisor itself. * Supervisor manages the focused window order using a doubly linked list. When a window takes focus it moves to the top of the list. Widgets in the active window take event priority. * Extended DragDrop API to support holding a widget pointer in the drag operation. * Changed widget event Handle functions to return an error: so that they could return ErrStopPropagation to prevent events going to more widgets once handled (for important events). Some bugs remain around overlapping windows and event propagation.
130 lines
2.5 KiB
Go
130 lines
2.5 KiB
Go
package ui
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"git.kirsle.net/go/render"
|
|
"git.kirsle.net/go/ui/theme"
|
|
)
|
|
|
|
// Button is a clickable button.
|
|
type Button struct {
|
|
BaseWidget
|
|
child Widget
|
|
|
|
// Private options.
|
|
hovering bool
|
|
clicked bool
|
|
}
|
|
|
|
// NewButton creates a new Button.
|
|
func NewButton(name string, child Widget) *Button {
|
|
w := &Button{
|
|
child: child,
|
|
}
|
|
w.IDFunc(func() string {
|
|
return fmt.Sprintf("Button<%s>", name)
|
|
})
|
|
|
|
w.Configure(Config{
|
|
BorderSize: 2,
|
|
BorderStyle: BorderRaised,
|
|
OutlineSize: 1,
|
|
OutlineColor: theme.ButtonOutlineColor,
|
|
Background: theme.ButtonBackgroundColor,
|
|
})
|
|
|
|
w.Handle(MouseOver, func(e EventData) error {
|
|
w.hovering = true
|
|
w.SetBackground(theme.ButtonHoverColor)
|
|
return nil
|
|
})
|
|
w.Handle(MouseOut, func(e EventData) error {
|
|
w.hovering = false
|
|
w.SetBackground(theme.ButtonBackgroundColor)
|
|
return nil
|
|
})
|
|
|
|
w.Handle(MouseDown, func(e EventData) error {
|
|
w.clicked = true
|
|
w.SetBorderStyle(BorderSunken)
|
|
return nil
|
|
})
|
|
w.Handle(MouseUp, func(e EventData) error {
|
|
w.clicked = false
|
|
w.SetBorderStyle(BorderRaised)
|
|
return nil
|
|
})
|
|
|
|
return w
|
|
}
|
|
|
|
// Children returns the button's child widget.
|
|
func (w *Button) Children() []Widget {
|
|
return []Widget{w.child}
|
|
}
|
|
|
|
// Compute the size of the button.
|
|
func (w *Button) Compute(e render.Engine) {
|
|
// Compute the size of the inner widget first.
|
|
w.child.Compute(e)
|
|
|
|
// Auto-resize only if we haven't been given a fixed size.
|
|
if !w.FixedSize() {
|
|
size := w.child.Size()
|
|
w.Resize(render.Rect{
|
|
W: size.W + w.BoxThickness(2),
|
|
H: size.H + w.BoxThickness(2),
|
|
})
|
|
}
|
|
|
|
w.BaseWidget.Compute(e)
|
|
}
|
|
|
|
// SetText conveniently sets the button text, for Label children only.
|
|
func (w *Button) SetText(text string) error {
|
|
if label, ok := w.child.(*Label); ok {
|
|
label.Text = text
|
|
}
|
|
return errors.New("child is not a Label widget")
|
|
}
|
|
|
|
// Present the button.
|
|
func (w *Button) Present(e render.Engine, P render.Point) {
|
|
if w.Hidden() {
|
|
return
|
|
}
|
|
|
|
w.Compute(e)
|
|
var (
|
|
S = w.Size()
|
|
ChildSize = w.child.Size()
|
|
)
|
|
|
|
// Draw the widget's border and everything.
|
|
w.DrawBox(e, P)
|
|
|
|
// Offset further if we are currently sunken.
|
|
var clickOffset int
|
|
if w.clicked {
|
|
clickOffset++
|
|
}
|
|
|
|
// Where to place the child widget.
|
|
moveTo := render.Point{
|
|
X: P.X + w.BoxThickness(1) + clickOffset,
|
|
Y: P.Y + w.BoxThickness(1) + clickOffset,
|
|
}
|
|
|
|
// If we're bigger than we need to be, center the child widget.
|
|
if S.Bigger(ChildSize) {
|
|
moveTo.X = P.X + (S.W / 2) - (ChildSize.W / 2)
|
|
}
|
|
|
|
// Draw the text label inside.
|
|
w.child.Present(e, moveTo)
|
|
|
|
w.BaseWidget.Present(e, P)
|
|
}
|