2019-04-10 00:35:44 +00:00
|
|
|
package ui
|
|
|
|
|
2019-12-29 07:56:00 +00:00
|
|
|
import (
|
|
|
|
"git.kirsle.net/go/render"
|
|
|
|
)
|
2019-04-10 00:35:44 +00:00
|
|
|
|
|
|
|
// 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.
|
2020-04-09 00:29:04 +00:00
|
|
|
// X and Y are the AbsolutePosition of the widget.
|
|
|
|
// W and H are the widget's width and height. (X,Y not added to them)
|
2019-04-10 00:35:44 +00:00
|
|
|
func AbsoluteRect(w Widget) render.Rect {
|
|
|
|
var (
|
|
|
|
P = AbsolutePosition(w)
|
|
|
|
R = w.Rect()
|
|
|
|
)
|
|
|
|
return render.Rect{
|
|
|
|
X: P.X,
|
|
|
|
Y: P.Y,
|
2020-04-09 00:29:04 +00:00
|
|
|
W: R.W,
|
2019-04-10 00:35:44 +00:00
|
|
|
H: R.H, // TODO: the Canvas in EditMode lets you draw pixels
|
|
|
|
// below the status bar if we do `+ R.Y` here.
|
|
|
|
}
|
|
|
|
}
|
2020-04-07 05:57:28 +00:00
|
|
|
|
2020-06-04 07:50:06 +00:00
|
|
|
// HasParent returns whether the target widget is a descendant of the parent.
|
|
|
|
// This scans the parents of the widget recursively until it finds a match.
|
|
|
|
func HasParent(w Widget, parent Widget) bool {
|
|
|
|
next, ok := w.Parent()
|
|
|
|
for ok {
|
|
|
|
if next == parent {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
next, ok = next.Parent()
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-04-07 05:57:28 +00:00
|
|
|
// 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 {
|
2020-04-09 00:29:04 +00:00
|
|
|
return window.managed, window.Focused()
|
2020-04-07 05:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
node, _ = node.Parent()
|
|
|
|
if node == nil {
|
|
|
|
return false, true // reached the root
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|