Worked Propagator into basic.Container
This commit is contained in:
parent
56e11ae1de
commit
165d0835bf
@ -14,11 +14,11 @@ import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
|||||||
// them in a layout.
|
// them in a layout.
|
||||||
type Container struct {
|
type Container struct {
|
||||||
*core.Core
|
*core.Core
|
||||||
|
*core.Propagator
|
||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
|
|
||||||
layout layouts.Layout
|
layout layouts.Layout
|
||||||
children []layouts.LayoutEntry
|
children []layouts.LayoutEntry
|
||||||
drags [10]elements.MouseTarget
|
|
||||||
warping bool
|
warping bool
|
||||||
focused bool
|
focused bool
|
||||||
focusable bool
|
focusable bool
|
||||||
@ -27,9 +27,9 @@ type Container struct {
|
|||||||
config config.Wrapped
|
config config.Wrapped
|
||||||
theme theme.Wrapped
|
theme theme.Wrapped
|
||||||
|
|
||||||
|
onFlexibleHeightChange func ()
|
||||||
onFocusRequest func () (granted bool)
|
onFocusRequest func () (granted bool)
|
||||||
onFocusMotionRequest func (input.KeynavDirection) (granted bool)
|
onFocusMotionRequest func (input.KeynavDirection) (granted bool)
|
||||||
onFlexibleHeightChange func ()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContainer creates a new container.
|
// NewContainer creates a new container.
|
||||||
@ -241,11 +241,7 @@ func (element *Container) redoAll () {
|
|||||||
func (element *Container) SetTheme (new theme.Theme) {
|
func (element *Container) SetTheme (new theme.Theme) {
|
||||||
if new == element.theme.Theme { return }
|
if new == element.theme.Theme { return }
|
||||||
element.theme.Theme = new
|
element.theme.Theme = new
|
||||||
for _, child := range element.children {
|
element.Propagator.SetTheme(new)
|
||||||
if child0, ok := child.Element.(elements.Themeable); ok {
|
|
||||||
child0.SetTheme(element.theme.Theme)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.redoAll()
|
element.redoAll()
|
||||||
}
|
}
|
||||||
@ -253,188 +249,34 @@ func (element *Container) SetTheme (new theme.Theme) {
|
|||||||
// SetConfig sets the element's configuration.
|
// SetConfig sets the element's configuration.
|
||||||
func (element *Container) SetConfig (new config.Config) {
|
func (element *Container) SetConfig (new config.Config) {
|
||||||
if new == element.config.Config { return }
|
if new == element.config.Config { return }
|
||||||
element.config.Config = new
|
element.Propagator.SetConfig(new)
|
||||||
for _, child := range element.children {
|
|
||||||
if child0, ok := child.Element.(elements.Configurable); ok {
|
|
||||||
child0.SetConfig(element.config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
element.redoAll()
|
element.redoAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleMouseDown (x, y int, button input.Button) {
|
|
||||||
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget)
|
|
||||||
if !handlesMouse { return }
|
|
||||||
element.drags[button] = child
|
|
||||||
child.HandleMouseDown(x, y, button)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) HandleMouseUp (x, y int, button input.Button) {
|
|
||||||
child := element.drags[button]
|
|
||||||
if child == nil { return }
|
|
||||||
element.drags[button] = nil
|
|
||||||
child.HandleMouseUp(x, y, button)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) HandleMouseMove (x, y int) {
|
|
||||||
for _, child := range element.drags {
|
|
||||||
if child == nil { continue }
|
|
||||||
child.HandleMouseMove(x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) HandleMouseScroll (x, y int, deltaX, deltaY float64) {
|
|
||||||
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget)
|
|
||||||
if !handlesMouse { return }
|
|
||||||
child.HandleMouseScroll(x, y, deltaX, deltaY)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
|
||||||
element.forFocused (func (child elements.Focusable) bool {
|
|
||||||
child0, handlesKeyboard := child.(elements.KeyboardTarget)
|
|
||||||
if handlesKeyboard {
|
|
||||||
child0.HandleKeyDown(key, modifiers)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
|
|
||||||
element.forFocused (func (child elements.Focusable) bool {
|
|
||||||
child0, handlesKeyboard := child.(elements.KeyboardTarget)
|
|
||||||
if handlesKeyboard {
|
|
||||||
child0.HandleKeyUp(key, modifiers)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) FlexibleHeightFor (width int) (height int) {
|
func (element *Container) FlexibleHeightFor (width int) (height int) {
|
||||||
margin := element.theme.Margin(theme.PatternBackground)
|
margin := element.theme.Margin(theme.PatternBackground)
|
||||||
// TODO: have layouts take in x and y margins
|
padding := element.theme.Padding(theme.PatternBackground)
|
||||||
|
// TODO: have layouts take in entire margins/padding
|
||||||
return element.layout.FlexibleHeightFor (
|
return element.layout.FlexibleHeightFor (
|
||||||
element.children,
|
element.children,
|
||||||
margin.X, width)
|
margin.X, padding.Horizontal(), width)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) OnFlexibleHeightChange (callback func ()) {
|
func (element *Container) OnFlexibleHeightChange (callback func ()) {
|
||||||
element.onFlexibleHeightChange = callback
|
element.onFlexibleHeightChange = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) Focused () (focused bool) {
|
|
||||||
return element.focused
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) Focus () {
|
|
||||||
if element.onFocusRequest != nil {
|
|
||||||
element.onFocusRequest()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) HandleFocus (direction input.KeynavDirection) (ok bool) {
|
|
||||||
if !element.focusable { return false }
|
|
||||||
direction = direction.Canon()
|
|
||||||
|
|
||||||
firstFocused := element.firstFocused()
|
|
||||||
if firstFocused < 0 {
|
|
||||||
// no element is currently focused, so we need to focus either
|
|
||||||
// the first or last focusable element depending on the
|
|
||||||
// direction.
|
|
||||||
switch direction {
|
|
||||||
case input.KeynavDirectionNeutral, input.KeynavDirectionForward:
|
|
||||||
// if we recieve a neutral or forward direction, focus
|
|
||||||
// the first focusable element.
|
|
||||||
return element.focusFirstFocusableElement(direction)
|
|
||||||
|
|
||||||
case input.KeynavDirectionBackward:
|
|
||||||
// if we recieve a backward direction, focus the last
|
|
||||||
// focusable element.
|
|
||||||
return element.focusLastFocusableElement(direction)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// an element is currently focused, so we need to move the
|
|
||||||
// focus in the specified direction
|
|
||||||
firstFocusedChild :=
|
|
||||||
element.children[firstFocused].Element.(elements.Focusable)
|
|
||||||
|
|
||||||
// before we move the focus, the currently focused child
|
|
||||||
// may also be able to move its focus. if the child is able
|
|
||||||
// to do that, we will let it and not move ours.
|
|
||||||
if firstFocusedChild.HandleFocus(direction) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the previous/next focusable element relative to the
|
|
||||||
// currently focused element, if it exists.
|
|
||||||
for index := firstFocused + int(direction);
|
|
||||||
index < len(element.children) && index >= 0;
|
|
||||||
index += int(direction) {
|
|
||||||
|
|
||||||
child, focusable :=
|
|
||||||
element.children[index].
|
|
||||||
Element.(elements.Focusable)
|
|
||||||
if focusable && child.HandleFocus(direction) {
|
|
||||||
// we have found one, so we now actually move
|
|
||||||
// the focus.
|
|
||||||
firstFocusedChild.HandleUnfocus()
|
|
||||||
element.focused = true
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) focusFirstFocusableElement (
|
|
||||||
direction input.KeynavDirection,
|
|
||||||
) (
|
|
||||||
ok bool,
|
|
||||||
) {
|
|
||||||
element.forFocusable (func (child elements.Focusable) bool {
|
|
||||||
if child.HandleFocus(direction) {
|
|
||||||
element.focused = true
|
|
||||||
ok = true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) focusLastFocusableElement (
|
|
||||||
direction input.KeynavDirection,
|
|
||||||
) (
|
|
||||||
ok bool,
|
|
||||||
) {
|
|
||||||
element.forFocusableBackward (func (child elements.Focusable) bool {
|
|
||||||
if child.HandleFocus(direction) {
|
|
||||||
element.focused = true
|
|
||||||
ok = true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) HandleUnfocus () {
|
|
||||||
element.focused = false
|
|
||||||
element.forFocused (func (child elements.Focusable) bool {
|
|
||||||
child.HandleUnfocus()
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) OnFocusRequest (callback func () (granted bool)) {
|
func (element *Container) OnFocusRequest (callback func () (granted bool)) {
|
||||||
element.onFocusRequest = callback
|
element.onFocusRequest = callback
|
||||||
|
element.Propagator.OnFocusRequest(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) OnFocusMotionRequest (
|
func (element *Container) OnFocusMotionRequest (
|
||||||
callback func (direction input.KeynavDirection) (granted bool),
|
callback func (direction input.KeynavDirection) (granted bool),
|
||||||
) {
|
) {
|
||||||
element.onFocusMotionRequest = callback
|
element.onFocusMotionRequest = callback
|
||||||
|
element.Propagator.OnFocusMotionRequest(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) forFocused (callback func (child elements.Focusable) bool) {
|
func (element *Container) forFocused (callback func (child elements.Focusable) bool) {
|
||||||
@ -518,19 +360,23 @@ func (element *Container) childFocusRequestCallback (
|
|||||||
|
|
||||||
func (element *Container) updateMinimumSize () {
|
func (element *Container) updateMinimumSize () {
|
||||||
margin := element.theme.Margin(theme.PatternBackground)
|
margin := element.theme.Margin(theme.PatternBackground)
|
||||||
// TODO: have layouts take in x and y margins
|
padding := element.theme.Padding(theme.PatternBackground)
|
||||||
width, height := element.layout.MinimumSize(element.children, margin.X)
|
// TODO: have layouts take in entire margins/padding
|
||||||
|
width, height := element.layout.MinimumSize (
|
||||||
|
element.children, margin.X, padding.Horizontal())
|
||||||
if element.flexible {
|
if element.flexible {
|
||||||
height = element.layout.FlexibleHeightFor (
|
height = element.layout.FlexibleHeightFor (
|
||||||
element.children,
|
element.children, margin.X,
|
||||||
margin.X, width)
|
padding.Horizontal(), width)
|
||||||
}
|
}
|
||||||
element.core.SetMinimumSize(width, height)
|
element.core.SetMinimumSize(width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) doLayout () {
|
func (element *Container) doLayout () {
|
||||||
margin := element.theme.Margin(theme.PatternBackground)
|
margin := element.theme.Margin(theme.PatternBackground)
|
||||||
// TODO: have layouts take in x and y margins
|
padding := element.theme.Padding(theme.PatternBackground)
|
||||||
|
// TODO: have layouts take in entire margins/padding
|
||||||
element.layout.Arrange (
|
element.layout.Arrange (
|
||||||
element.children, margin.X, element.Bounds())
|
element.children, margin.X,
|
||||||
|
padding.Horizontal(), element.Bounds())
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ type Propagator struct {
|
|||||||
focused bool
|
focused bool
|
||||||
|
|
||||||
onFocusRequest func () (granted bool)
|
onFocusRequest func () (granted bool)
|
||||||
onFocusMotionRequest func (input.KeynavDirection) (granted bool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPropagator creates a new event propagator that uses the specified parent
|
// NewPropagator creates a new event propagator that uses the specified parent
|
||||||
@ -137,9 +136,7 @@ func (propagator *Propagator) OnFocusRequest (callback func () (granted bool)) {
|
|||||||
// was granted, and false if it was not.
|
// was granted, and false if it was not.
|
||||||
func (propagator *Propagator) OnFocusMotionRequest (
|
func (propagator *Propagator) OnFocusMotionRequest (
|
||||||
callback func (direction input.KeynavDirection) (granted bool),
|
callback func (direction input.KeynavDirection) (granted bool),
|
||||||
) {
|
) { }
|
||||||
propagator.onFocusMotionRequest = callback
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleKeyDown propogates the keyboard event to the currently selected child.
|
// HandleKeyDown propogates the keyboard event to the currently selected child.
|
||||||
func (propagator *Propagator) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
func (propagator *Propagator) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||||
|
Reference in New Issue
Block a user