make-containers-better #10
@ -11,6 +11,8 @@ import "git.tebibyte.media/sashakoshka/tomo/elements"
|
|||||||
// the iterator stops the current loop and OverChildren returns.
|
// the iterator stops the current loop and OverChildren returns.
|
||||||
type ChildIterator interface {
|
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
|
// 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
|
// marks itself as focused along with any applicable children and returns
|
||||||
// true.
|
// true.
|
||||||
func (propagator *Propagator) HandleFocus (direction input.KeynavDirection) (accepted bool) {
|
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
|
// 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 ----------- //
|
// ----------- 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) {
|
func (propagator *Propagator) childAt (position image.Point) (child elements.Element) {
|
||||||
propagator.iterator.OverChildren (func (current elements.Element) bool {
|
propagator.iterator.OverChildren (func (current elements.Element) bool {
|
||||||
if position.In(current.Bounds()) {
|
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) {
|
func (propagator *Propagator) firstFocused () (index int) {
|
||||||
index = -1
|
index = -1
|
||||||
currentIndex := 0
|
currentIndex := 0
|
||||||
|
Reference in New Issue
Block a user