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.
89 lines
2.0 KiB
Go
89 lines
2.0 KiB
Go
package ui
|
|
|
|
import (
|
|
"git.kirsle.net/go/render"
|
|
)
|
|
|
|
// AbsolutePosition computes a widget's absolute X,Y position on the
|
|
// window on screen by crawling its parent widget tree.
|
|
func AbsolutePosition(w Widget) render.Point {
|
|
abs := w.Point()
|
|
|
|
var (
|
|
node = w
|
|
ok bool
|
|
)
|
|
|
|
for {
|
|
node, ok = node.Parent()
|
|
if !ok { // reached the top of the tree
|
|
return abs
|
|
}
|
|
|
|
abs.Add(node.Point())
|
|
}
|
|
}
|
|
|
|
// AbsoluteRect returns a Rect() offset with the absolute position.
|
|
func AbsoluteRect(w Widget) render.Rect {
|
|
var (
|
|
P = AbsolutePosition(w)
|
|
R = w.Rect()
|
|
)
|
|
return render.Rect{
|
|
X: P.X,
|
|
Y: P.Y,
|
|
W: R.W + P.X,
|
|
H: R.H, // TODO: the Canvas in EditMode lets you draw pixels
|
|
// below the status bar if we do `+ R.Y` here.
|
|
}
|
|
}
|
|
|
|
// widgetInFocusedWindow returns whether a widget (like a Button) is a
|
|
// descendant of a Window that is being Window Managed by Supervisor, and
|
|
// said window is in a Focused state.
|
|
//
|
|
// This is used by Supervisor to decide whether the widget should be given
|
|
// events or not: a widget in a non-focused window ignores events, so that a
|
|
// button in a "lower" window could not be clicked through a "higher" window
|
|
// that overlaps it.
|
|
func widgetInFocusedWindow(w Widget) (isManaged, isFocused bool) {
|
|
var node = w
|
|
|
|
for {
|
|
// Is the node a Window?
|
|
if window, ok := node.(*Window); ok {
|
|
return true, window.Focused()
|
|
}
|
|
|
|
node, _ = node.Parent()
|
|
if node == nil {
|
|
return false, true // reached the root
|
|
}
|
|
}
|
|
}
|
|
|
|
// WidgetInManagedWindow returns true if the widget is owned by a ui.Window
|
|
// which is being Window Managed by the Supervisor.
|
|
//
|
|
// Returns true if any parent widget is a Window with managed=true. This
|
|
// boolean is set when you call .Supervise() on the window to be managed by
|
|
// Supervisor.
|
|
func WidgetInManagedWindow(w Widget) bool {
|
|
var node = w
|
|
|
|
for {
|
|
// Is the node a Window?
|
|
if window, ok := node.(*Window); ok {
|
|
if window.managed {
|
|
return true
|
|
}
|
|
}
|
|
|
|
node, _ = node.Parent()
|
|
if node == nil {
|
|
return false // reached the root
|
|
}
|
|
}
|
|
}
|