Fully implemented Propagator

This commit is contained in:
Sasha Koshka 2023-03-04 00:57:17 -05:00
parent c13cdd570d
commit 1d9fb6024d

View File

@ -10,7 +10,9 @@ import "git.tebibyte.media/sashakoshka/tomo/elements"
// calling a specified iterator function for each one. When keepGoing is false,
// the iterator stops the current loop and OverChildren returns.
type ChildIterator interface {
OverChildren (func (child elements.Element) (keepGoing bool))
OverChildren (func (child elements.Element) (keepGoing bool))
Child (index int) elements.Element
CountChildren () int
}
// Propagator is a struct that can be embedded into elements that contain one or
@ -59,7 +61,58 @@ func (propagator *Propagator) Focus () {
// marks itself as focused along with any applicable children and returns
// true.
func (propagator *Propagator) HandleFocus (direction input.KeynavDirection) (accepted bool) {
// TODO
direction = direction.Canon()
firstFocused := propagator.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 propagator.focusFirstFocusableElement(direction)
case input.KeynavDirectionBackward:
// if we recieve a backward direction, focus the last
// focusable element.
return propagator.focusLastFocusableElement(direction)
}
} else {
// an element is currently focused, so we need to move the
// focus in the specified direction
firstFocusedChild :=
propagator.iterator.Child(firstFocused).
(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 < propagator.iterator.CountChildren() && index >= 0;
index += int(direction) {
child, focusable :=
propagator.iterator.Child(index).
(elements.Focusable)
if focusable && child.HandleFocus(direction) {
// we have found one, so we now actually move
// the focus.
firstFocusedChild.HandleUnfocus()
propagator.focused = true
return true
}
}
}
return false
}
// HandleDeselection causes this element to mark itself and all of its children
@ -189,8 +242,53 @@ func (propagator *Propagator) SetConfig (config config.Config) {
})
}
// ----------- Focusing utilities ----------- //
func (propagator *Propagator) focusFirstFocusableElement (
direction input.KeynavDirection,
) (
ok bool,
) {
propagator.forFocusable (func (child elements.Focusable) bool {
if child.HandleFocus(direction) {
propagator.focused = true
ok = true
return false
}
return true
})
return
}
func (propagator *Propagator) focusLastFocusableElement (
direction input.KeynavDirection,
) (
ok bool,
) {
focusables := []elements.Focusable { }
propagator.forFocusable (func (child elements.Focusable) bool {
focusables = append(focusables, child)
return true
})
for index := len(focusables) - 1; index >= 0; index -- {
child, focusable := focusables[index].(elements.Focusable)
if focusable && child.HandleFocus(direction) {
propagator.focused = true
ok = true
break
}
}
return
}
// ----------- Iterator utilities ----------- //
// TODO: remove ChildIterator.OverChildren, reimplement that here, rework these
// methods based on that, add a reverse iteration method, and then rework
// focusLastFocusableElement based on that.
func (propagator *Propagator) childAt (position image.Point) (child elements.Element) {
propagator.iterator.OverChildren (func (current elements.Element) bool {
if position.In(current.Bounds()) {
@ -231,15 +329,6 @@ func (propagator *Propagator) forFlexible (callback func (child elements.Flexibl
})
}
// func (propagator *Propagator) forFocusableBackward (callback func (child elements.Focusable) bool) {
// for index := len(element.children) - 1; index >= 0; index -- {
// child, focusable := element.children[index].Element.(elements.Focusable)
// if focusable {
// if !callback(child) { break }
// }
// }
// }
func (propagator *Propagator) firstFocused () (index int) {
index = -1
currentIndex := 0