Supervisor, Frame Pack and Misc Fixes
* Button: do not call MoveTo inside of Compute(). * Label: do not call MoveTo inside of Compute(). * MainWindow: add OnLoop callback function support so you can run custom code each loop and react to the event.State before the UI updates. * Supervisor: locate widgets using AbsolutePosition() instead of w.Point() to play nice with Frame and Window packed widgets. * Widget interface: rename Adopt() to SetParent() which makes more sense for what the function actually does. * Window: set itself as the parent of the body Frame so that the Supervisor can locate widgets anywhere inside a window's frames. Frame packing fixes: * Widgets with Expand:true grow their space with ResizeAuto to preserve the FixedSize() boolean, instead of being hard-resized to fill the Frame. * Widgets that Fill their space are resized with ResizeAuto too. Outstanding bugs: * Labels don't expand (window title bars, etc.)
This commit is contained in:
parent
9d6b172878
commit
4ba563d48d
22
README.md
22
README.md
|
@ -11,8 +11,8 @@ applications (SDL2, for Linux, MacOS and Windows) as well as web browsers
|
||||||
> _(Screenshot is from Project: Doodle's GUITest debug screen showing a_
|
> _(Screenshot is from Project: Doodle's GUITest debug screen showing a_
|
||||||
> _Window, several Frames, Labels, Buttons and a Checkbox widget.)_
|
> _Window, several Frames, Labels, Buttons and a Checkbox widget.)_
|
||||||
|
|
||||||
It is very much a **work in progress** and it's a bit buggy. See the
|
It is very much a **work in progress** and may contain bugs and its API may
|
||||||
[Known Issues](#known-issues) at the bottom of this document.
|
change as bugs are fixed or features added.
|
||||||
|
|
||||||
This library is being developed in conjunction with my drawing-based maze
|
This library is being developed in conjunction with my drawing-based maze
|
||||||
game, [Project: Doodle](https://www.kirsle.net/doodle). The rendering engine
|
game, [Project: Doodle](https://www.kirsle.net/doodle). The rendering engine
|
||||||
|
@ -214,24 +214,6 @@ MainWindow includes its own Supervisor: just call the `.Add(Widget)`
|
||||||
method to add interactive widgets to the supervisor. The MainLoop() of the
|
method to add interactive widgets to the supervisor. The MainLoop() of the
|
||||||
window calls Supervisor.Loop() automatically.
|
window calls Supervisor.Loop() automatically.
|
||||||
|
|
||||||
# Known Issues
|
|
||||||
|
|
||||||
The frame packing algorithm (frame_pack.go) is currently very buggy and in
|
|
||||||
need of a re-write. Some examples of issues with it:
|
|
||||||
|
|
||||||
* Currently, when the Frame is iterating over packed widgets to decide their
|
|
||||||
location and size, it explicitly calls MoveTo() and Resize() giving them
|
|
||||||
their pixel-coordinates, relative to the Frame's own position.
|
|
||||||
* When Frames nest other Frames this becomes more of an issue.
|
|
||||||
* The Supervisor sometimes can't determine the correct position of a
|
|
||||||
button packed inside of nested frames. It currently checks the
|
|
||||||
Point() of the button (set by its parent Frame) and this doesn't
|
|
||||||
account for the grandparent frame's position. Using the
|
|
||||||
AbsolutePosition() helper function (which recursively crawls up a
|
|
||||||
widget tree) also yields incorrect results, as the position of each
|
|
||||||
Frame is _added_ to the position of the Button which throws it off even
|
|
||||||
further.
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
MIT.
|
MIT.
|
||||||
|
|
|
@ -91,7 +91,6 @@ func (w *Button) Present(e render.Engine, P render.Point) {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Compute(e)
|
w.Compute(e)
|
||||||
w.MoveTo(P)
|
|
||||||
var (
|
var (
|
||||||
S = w.Size()
|
S = w.Size()
|
||||||
ChildSize = w.child.Size()
|
ChildSize = w.child.Size()
|
||||||
|
|
19
debug.go
19
debug.go
|
@ -1,15 +1,28 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// WidgetTree returns a string representing the tree of widgets starting
|
// WidgetTree returns a string representing the tree of widgets starting
|
||||||
// at a given widget.
|
// at a given widget.
|
||||||
func WidgetTree(root Widget) []string {
|
func WidgetTree(root Widget) []string {
|
||||||
var crawl func(int, Widget) []string
|
var crawl func(int, Widget) []string
|
||||||
|
|
||||||
crawl = func(depth int, node Widget) []string {
|
crawl = func(depth int, node Widget) []string {
|
||||||
var (
|
var (
|
||||||
prefix = strings.Repeat(" ", depth)
|
prefix = strings.Repeat(" ", depth)
|
||||||
lines = []string{prefix + node.ID()}
|
size = node.Size()
|
||||||
|
width = size.W
|
||||||
|
height = size.H
|
||||||
|
fixedSize = node.FixedSize()
|
||||||
|
|
||||||
|
lines = []string{
|
||||||
|
fmt.Sprintf("%s%s P:%s S:%dx%d (fixedSize: %+v)",
|
||||||
|
prefix, node.ID(), node.Point(), width, height, fixedSize,
|
||||||
|
),
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, child := range node.Children() {
|
for _, child := range node.Children() {
|
||||||
|
|
|
@ -47,7 +47,7 @@ func (w *Frame) Pack(child Widget, config ...Pack) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adopt the child widget so it can access the Frame.
|
// Adopt the child widget so it can access the Frame.
|
||||||
child.Adopt(w)
|
child.SetParent(w)
|
||||||
|
|
||||||
w.packs[C.Side] = append(w.packs[C.Side], packedWidget{
|
w.packs[C.Side] = append(w.packs[C.Side], packedWidget{
|
||||||
widget: child,
|
widget: child,
|
||||||
|
@ -65,7 +65,7 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
// that the Frame must be to contain all of its children. If the Frame
|
// that the Frame must be to contain all of its children. If the Frame
|
||||||
// was configured with an explicit Size, the Frame will be that Size,
|
// was configured with an explicit Size, the Frame will be that Size,
|
||||||
// but we still calculate how much space the widgets _actually_ take
|
// but we still calculate how much space the widgets _actually_ take
|
||||||
// so we can expand them to fill remaining space in fixed size widgets.
|
// so we can expand them to fill remaining space in fixed size Frames.
|
||||||
maxWidth int
|
maxWidth int
|
||||||
maxHeight int
|
maxHeight int
|
||||||
visited = []packedWidget{}
|
visited = []packedWidget{}
|
||||||
|
@ -82,8 +82,8 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
var (
|
var (
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
yDirection int = 1
|
yDirection = 1
|
||||||
xDirection int = 1
|
xDirection = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
if side.IsSouth() {
|
if side.IsSouth() {
|
||||||
|
@ -128,12 +128,15 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
x -= size.W - pack.PadX
|
x -= size.W - pack.PadX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: we place the child's position relative to the Frame's
|
||||||
|
// position. So a child placed at the top/left of the Frame gets
|
||||||
|
// an x,y near zero regardless of the Frame's position.
|
||||||
child.MoveTo(render.NewPoint(x, y))
|
child.MoveTo(render.NewPoint(x, y))
|
||||||
|
|
||||||
if side.IsNorth() {
|
if side.IsNorth() {
|
||||||
y += size.H + pack.PadY
|
y += size.H + pack.PadY
|
||||||
}
|
}
|
||||||
if side == W {
|
if side.IsWest() {
|
||||||
x += size.W + pack.PadX
|
x += size.W + pack.PadX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,14 +150,20 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
// If we have extra space in the Frame and any expanding widgets, let the
|
// If we have extra space in the Frame and any expanding widgets, let the
|
||||||
// expanding widgets grow and share the remaining space.
|
// expanding widgets grow and share the remaining space.
|
||||||
computedSize := render.NewRect(maxWidth, maxHeight)
|
computedSize := render.NewRect(maxWidth, maxHeight)
|
||||||
if len(expanded) > 0 && !frameSize.IsZero() && frameSize.Bigger(computedSize) {
|
if len(expanded) > 0 && !frameSize.IsZero() { // && frameSize.Bigger(computedSize) {
|
||||||
// Divy up the size available.
|
// Divy up the size available.
|
||||||
growBy := render.Rect{
|
growBy := render.Rect{
|
||||||
W: ((frameSize.W - computedSize.W) / len(expanded)) - w.BoxThickness(4),
|
W: ((frameSize.W - computedSize.W) / len(expanded)) - w.BoxThickness(4),
|
||||||
H: ((frameSize.H - computedSize.H) / len(expanded)) - w.BoxThickness(4),
|
H: ((frameSize.H - computedSize.H) / len(expanded)) - w.BoxThickness(4),
|
||||||
}
|
}
|
||||||
for _, pw := range expanded {
|
for _, pw := range expanded {
|
||||||
pw.widget.ResizeBy(growBy)
|
// Grow the widget but maintain its auto-size flag, in case the widget
|
||||||
|
// was not given an explicit size before.
|
||||||
|
size := pw.widget.Size()
|
||||||
|
pw.widget.ResizeAuto(render.Rect{
|
||||||
|
W: size.W + growBy.W,
|
||||||
|
H: size.H + growBy.H,
|
||||||
|
})
|
||||||
pw.widget.Compute(e)
|
pw.widget.Compute(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,10 +199,16 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
)
|
)
|
||||||
|
|
||||||
if pack.Side.IsNorth() || pack.Side.IsSouth() {
|
if pack.Side.IsNorth() || pack.Side.IsSouth() {
|
||||||
|
// Aligned to the top or bottom. If the widget Fills horizontally,
|
||||||
|
// resize it so its Width matches the frame's Width.
|
||||||
if pack.FillX && resize.W < innerFrameSize.W {
|
if pack.FillX && resize.W < innerFrameSize.W {
|
||||||
resize.W = innerFrameSize.W - w.BoxThickness(2)
|
resize.W = innerFrameSize.W - w.BoxThickness(2) // TODO: child.BoxThickness instead??
|
||||||
resized = true
|
resized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If it does not Fill horizontally and there is extra horizontal
|
||||||
|
// space, center the widget inside the space. TODO: Anchor option
|
||||||
|
// could align the widget to the left or right instead of center.
|
||||||
if resize.W < innerFrameSize.W-w.BoxThickness(4) {
|
if resize.W < innerFrameSize.W-w.BoxThickness(4) {
|
||||||
if pack.Side.IsCenter() {
|
if pack.Side.IsCenter() {
|
||||||
point.X = (innerFrameSize.W / 2) - (resize.W / 2)
|
point.X = (innerFrameSize.W / 2) - (resize.W / 2)
|
||||||
|
@ -206,19 +221,19 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
moved = true
|
moved = true
|
||||||
}
|
}
|
||||||
} else if pack.Side.IsWest() || pack.Side.IsEast() {
|
} else if pack.Side.IsWest() || pack.Side.IsEast() {
|
||||||
|
// Similar logic to the above, but widget is packed against the
|
||||||
|
// left or right edge. Handle vertical Fill to grow the widget.
|
||||||
if pack.FillY && resize.H < innerFrameSize.H {
|
if pack.FillY && resize.H < innerFrameSize.H {
|
||||||
resize.H = innerFrameSize.H - w.BoxThickness(2) // BoxThickness(2) for parent + child
|
resize.H = innerFrameSize.H - w.BoxThickness(2) // TODO: child.BoxThickness instead??
|
||||||
// point.Y -= (w.BoxThickness(4) + child.BoxThickness(2))
|
|
||||||
moved = true
|
|
||||||
resized = true
|
resized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertically align the widgets.
|
// Vertically align the widgets.
|
||||||
if resize.H < innerFrameSize.H {
|
if resize.H < innerFrameSize.H {
|
||||||
if pack.Side.IsMiddle() {
|
if pack.Side.IsMiddle() {
|
||||||
point.Y = (innerFrameSize.H / 2) - (resize.H / 2) - w.BoxThickness(1)
|
point.Y = (innerFrameSize.H / 2) - (resize.H / 2) // - w.BoxThickness(1)
|
||||||
} else if pack.Side.IsNorth() {
|
} else if pack.Side.IsNorth() {
|
||||||
point.Y = pack.PadY - w.BoxThickness(4)
|
point.Y = pack.PadY // - w.BoxThickness(4)
|
||||||
} else if pack.Side.IsSouth() {
|
} else if pack.Side.IsSouth() {
|
||||||
point.Y = innerFrameSize.H - resize.H - pack.PadY
|
point.Y = innerFrameSize.H - resize.H - pack.PadY
|
||||||
}
|
}
|
||||||
|
@ -229,7 +244,7 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if resized && size != resize {
|
if resized && size != resize {
|
||||||
child.Resize(resize)
|
child.ResizeAuto(resize)
|
||||||
child.Compute(e)
|
child.Compute(e)
|
||||||
}
|
}
|
||||||
if moved {
|
if moved {
|
||||||
|
@ -237,6 +252,9 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: the Frame should ResizeAuto so it doesn't mark fixedSize=true.
|
||||||
|
// Currently there's a bug where frames will grow when the window grows but
|
||||||
|
// never shrink again when the window shrinks.
|
||||||
// if !w.FixedSize() {
|
// if !w.FixedSize() {
|
||||||
w.Resize(render.NewRect(
|
w.Resize(render.NewRect(
|
||||||
frameSize.W-w.BoxThickness(2),
|
frameSize.W-w.BoxThickness(2),
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
import "git.kirsle.net/go/render"
|
import (
|
||||||
|
"git.kirsle.net/go/render"
|
||||||
|
)
|
||||||
|
|
||||||
// AbsolutePosition computes a widget's absolute X,Y position on the
|
// AbsolutePosition computes a widget's absolute X,Y position on the
|
||||||
// window on screen by crawling its parent widget tree.
|
// window on screen by crawling its parent widget tree.
|
||||||
|
|
5
label.go
5
label.go
|
@ -101,11 +101,6 @@ func (w *Label) Compute(e render.Engine) {
|
||||||
H: maxRect.H + (padY * 2),
|
H: maxRect.H + (padY * 2),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
w.MoveTo(render.Point{
|
|
||||||
X: maxRect.X + w.BoxThickness(1),
|
|
||||||
Y: maxRect.Y + w.BoxThickness(1),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present the label widget.
|
// Present the label widget.
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
|
"git.kirsle.net/go/render/event"
|
||||||
"git.kirsle.net/go/render/sdl"
|
"git.kirsle.net/go/render/sdl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,20 +18,22 @@ var (
|
||||||
|
|
||||||
// MainWindow is the parent window of a UI application.
|
// MainWindow is the parent window of a UI application.
|
||||||
type MainWindow struct {
|
type MainWindow struct {
|
||||||
Engine render.Engine
|
Engine render.Engine
|
||||||
supervisor *Supervisor
|
supervisor *Supervisor
|
||||||
frame *Frame
|
frame *Frame
|
||||||
w int
|
loopCallbacks []func(*event.State)
|
||||||
h int
|
w int
|
||||||
|
h int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMainWindow initializes the MainWindow. You should probably only have one
|
// NewMainWindow initializes the MainWindow. You should probably only have one
|
||||||
// of these per application.
|
// of these per application.
|
||||||
func NewMainWindow(title string) (*MainWindow, error) {
|
func NewMainWindow(title string) (*MainWindow, error) {
|
||||||
mw := &MainWindow{
|
mw := &MainWindow{
|
||||||
w: 800,
|
w: 800,
|
||||||
h: 600,
|
h: 600,
|
||||||
supervisor: NewSupervisor(),
|
supervisor: NewSupervisor(),
|
||||||
|
loopCallbacks: []func(*event.State){},
|
||||||
}
|
}
|
||||||
|
|
||||||
mw.Engine = sdl.New(
|
mw.Engine = sdl.New(
|
||||||
|
@ -64,6 +67,11 @@ func (mw *MainWindow) Pack(w Widget, pack Pack) {
|
||||||
mw.frame.Pack(w, pack)
|
mw.frame.Pack(w, pack)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Frame returns the window's main frame, if needed.
|
||||||
|
func (mw *MainWindow) Frame() *Frame {
|
||||||
|
return mw.frame
|
||||||
|
}
|
||||||
|
|
||||||
// resized handles the window being resized.
|
// resized handles the window being resized.
|
||||||
func (mw *MainWindow) resized() {
|
func (mw *MainWindow) resized() {
|
||||||
mw.frame.Resize(render.Rect{
|
mw.frame.Resize(render.Rect{
|
||||||
|
@ -82,6 +90,14 @@ func (mw *MainWindow) Present() {
|
||||||
mw.supervisor.Present(mw.Engine)
|
mw.supervisor.Present(mw.Engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnLoop registers a function to be called on every loop of the main window.
|
||||||
|
// This enables your application to register global event handlers or whatnot.
|
||||||
|
// The function is called between the event polling and the updating of any UI
|
||||||
|
// elements.
|
||||||
|
func (mw *MainWindow) OnLoop(callback func(*event.State)) {
|
||||||
|
mw.loopCallbacks = append(mw.loopCallbacks, callback)
|
||||||
|
}
|
||||||
|
|
||||||
// MainLoop starts the main event loop and blocks until there's an error.
|
// MainLoop starts the main event loop and blocks until there's an error.
|
||||||
func (mw *MainWindow) MainLoop() error {
|
func (mw *MainWindow) MainLoop() error {
|
||||||
for true {
|
for true {
|
||||||
|
@ -114,11 +130,16 @@ func (mw *MainWindow) Loop() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ping any loop callbacks.
|
||||||
|
for _, cb := range mw.loopCallbacks {
|
||||||
|
cb(ev)
|
||||||
|
}
|
||||||
|
|
||||||
mw.frame.Compute(mw.Engine)
|
mw.frame.Compute(mw.Engine)
|
||||||
|
|
||||||
// Render the child widgets.
|
// Render the child widgets.
|
||||||
mw.supervisor.Loop(ev)
|
mw.supervisor.Loop(ev)
|
||||||
mw.supervisor.Present(mw.Engine)
|
mw.frame.Present(mw.Engine, mw.frame.Point())
|
||||||
mw.Engine.Present()
|
mw.Engine.Present()
|
||||||
|
|
||||||
// Delay to maintain target frames per second.
|
// Delay to maintain target frames per second.
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
|
@ -165,7 +166,7 @@ func (s *Supervisor) Hovering(cursor render.Point) (hovering, outside []WidgetSl
|
||||||
for child := range s.Widgets() {
|
for child := range s.Widgets() {
|
||||||
var (
|
var (
|
||||||
w = child.widget
|
w = child.widget
|
||||||
P = w.Point()
|
P = AbsolutePosition(w)
|
||||||
S = w.Size()
|
S = w.Size()
|
||||||
P2 = render.Point{
|
P2 = render.Point{
|
||||||
X: P.X + S.W,
|
X: P.X + S.W,
|
||||||
|
@ -204,10 +205,11 @@ func (s *Supervisor) Present(e render.Engine) {
|
||||||
s.lock.RLock()
|
s.lock.RLock()
|
||||||
defer s.lock.RUnlock()
|
defer s.lock.RUnlock()
|
||||||
|
|
||||||
for child := range s.Widgets() {
|
fmt.Println("!!! ui.Supervisor.Present() is deprecated")
|
||||||
var w = child.widget
|
// for child := range s.Widgets() {
|
||||||
w.Present(e, w.Point())
|
// var w = child.widget
|
||||||
}
|
// w.Present(e, w.Point())
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a widget to be supervised.
|
// Add a widget to be supervised.
|
||||||
|
|
19
widget.go
19
widget.go
|
@ -1,8 +1,6 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
"git.kirsle.net/go/ui/theme"
|
"git.kirsle.net/go/ui/theme"
|
||||||
)
|
)
|
||||||
|
@ -67,8 +65,8 @@ type Widget interface {
|
||||||
// Container widgets like Frames can wire up associations between the
|
// Container widgets like Frames can wire up associations between the
|
||||||
// child widgets and the parent.
|
// child widgets and the parent.
|
||||||
Parent() (parent Widget, ok bool)
|
Parent() (parent Widget, ok bool)
|
||||||
Adopt(parent Widget) // for the container to assign itself the parent
|
SetParent(parent Widget) // for the container to assign itself the parent
|
||||||
Children() []Widget // for containers to return their children
|
Children() []Widget // for containers to return their children
|
||||||
|
|
||||||
// Run any render computations; by the end the widget must know its
|
// Run any render computations; by the end the widget must know its
|
||||||
// Width and Height. For example the Label widget will render itself onto
|
// Width and Height. For example the Label widget will render itself onto
|
||||||
|
@ -254,18 +252,13 @@ func (w *BaseWidget) ResizeBy(v render.Rect) {
|
||||||
|
|
||||||
// ResizeAuto sets the size of the widget but doesn't set the fixedSize flag.
|
// ResizeAuto sets the size of the widget but doesn't set the fixedSize flag.
|
||||||
func (w *BaseWidget) ResizeAuto(v render.Rect) {
|
func (w *BaseWidget) ResizeAuto(v render.Rect) {
|
||||||
if w.ID() == "Frame<Window Body>" {
|
|
||||||
fmt.Printf("%s: ResizeAuto Called: %+v\n",
|
|
||||||
w.ID(),
|
|
||||||
v,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
w.width = v.W
|
w.width = v.W
|
||||||
w.height = v.H
|
w.height = v.H
|
||||||
}
|
}
|
||||||
|
|
||||||
// BoxThickness returns the full sum of the padding, border and outline.
|
// BoxThickness returns the full sum of the padding, border and outline.
|
||||||
// m = multiplier, i.e., 1 or 2
|
// m = multiplier, i.e., 1 or 2. If m=1 this returns the box thickness of one
|
||||||
|
// edge of the widget, if m=2 it would account for both edges of the widget.
|
||||||
func (w *BaseWidget) BoxThickness(m int) int {
|
func (w *BaseWidget) BoxThickness(m int) int {
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
m = 1
|
m = 1
|
||||||
|
@ -279,10 +272,10 @@ func (w *BaseWidget) Parent() (Widget, bool) {
|
||||||
return w.parent, w.hasParent
|
return w.parent, w.hasParent
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adopt sets the widget's parent. This function is called by container
|
// SetParent sets the widget's parent. This function is called by container
|
||||||
// widgets like Frame when they add a child widget to their care.
|
// widgets like Frame when they add a child widget to their care.
|
||||||
// Pass a nil parent to unset the parent.
|
// Pass a nil parent to unset the parent.
|
||||||
func (w *BaseWidget) Adopt(parent Widget) {
|
func (w *BaseWidget) SetParent(parent Widget) {
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
w.hasParent = false
|
w.hasParent = false
|
||||||
w.parent = nil
|
w.parent = nil
|
||||||
|
|
Loading…
Reference in New Issue
Block a user