This repository has been archived on 2023-08-08. You can view files and clone it, but cannot push or open issues or pull requests.
tomo-old/elements/core/focusable.go

102 lines
3.0 KiB
Go
Raw Normal View History

package core
// import "runtime/debug"
2023-03-30 21:19:04 -06:00
import "git.tebibyte.media/sashakoshka/tomo"
2023-02-01 23:48:16 -07:00
import "git.tebibyte.media/sashakoshka/tomo/input"
2023-01-30 15:01:47 -07:00
// FocusableCore is a struct that can be embedded into objects to make them
// focusable, giving them the default keynav behavior.
type FocusableCore struct {
core CoreControl
2023-01-30 15:01:47 -07:00
focused bool
enabled bool
drawFocusChange func ()
}
2023-01-30 15:01:47 -07:00
// NewFocusableCore creates a new focusability core and its corresponding
// control. If your element needs to visually update itself when it's focus
// state changes (which it should), a callback to draw and push the update can
// be specified.
2023-01-30 15:01:47 -07:00
func NewFocusableCore (
core CoreControl,
2023-01-30 15:01:47 -07:00
drawFocusChange func (),
) (
focusable *FocusableCore,
2023-01-30 15:01:47 -07:00
control FocusableCoreControl,
) {
focusable = &FocusableCore {
core: core,
2023-01-30 15:01:47 -07:00
drawFocusChange: drawFocusChange,
enabled: true,
}
control = FocusableCoreControl { core: focusable }
return
}
2023-01-30 15:01:47 -07:00
// Focused returns whether or not this element is currently focused.
func (core *FocusableCore) Focused () (focused bool) {
return core.focused
}
2023-01-30 15:01:47 -07:00
// Focus focuses this element, if its parent element grants the request.
func (core *FocusableCore) Focus () {
if !core.enabled || core.focused { return }
parent := core.core.Parent()
2023-03-30 21:19:04 -06:00
if parent, ok := parent.(tomo.FocusableParent); ok {
core.focused = parent.RequestFocus (
2023-03-30 21:19:04 -06:00
core.core.Outer().(tomo.Focusable))
}
}
2023-01-30 15:01:47 -07:00
// HandleFocus causes this element to mark itself as focused, if it can
// currently be. Otherwise, it will return false and do nothing.
2023-01-30 15:01:47 -07:00
func (core *FocusableCore) HandleFocus (
2023-02-01 23:48:16 -07:00
direction input.KeynavDirection,
) (
accepted bool,
) {
direction = direction.Canon()
if !core.enabled { return false }
2023-02-01 23:48:16 -07:00
if core.focused && direction != input.KeynavDirectionNeutral {
return false
}
if core.focused == false {
core.focused = true
if core.drawFocusChange != nil { core.drawFocusChange() }
}
return true
}
2023-01-30 15:01:47 -07:00
// HandleUnfocus causes this element to mark itself as unfocused.
func (core *FocusableCore) HandleUnfocus () {
core.focused = false
// debug.PrintStack()
2023-01-30 15:01:47 -07:00
if core.drawFocusChange != nil { core.drawFocusChange() }
}
// Enabled returns whether or not the element is enabled.
2023-01-30 15:01:47 -07:00
func (core *FocusableCore) Enabled () (enabled bool) {
return core.enabled
}
2023-01-30 15:01:47 -07:00
// FocusableCoreControl is a struct that can be used to exert control over a
// focusability core. It must not be directly embedded into an element, but
// instead kept as a private member. When a FocusableCore struct is created, a
// corresponding FocusableCoreControl struct is linked to it and returned
// alongside it.
2023-01-30 15:01:47 -07:00
type FocusableCoreControl struct {
core *FocusableCore
}
2023-01-30 15:01:47 -07:00
// SetEnabled sets whether the focusability core is enabled. If the state
// changes, this will call drawFocusChange.
func (control FocusableCoreControl) SetEnabled (enabled bool) {
if control.core.enabled == enabled { return }
control.core.enabled = enabled
2023-01-30 15:01:47 -07:00
if !enabled { control.core.focused = false }
if control.core.drawFocusChange != nil {
control.core.drawFocusChange()
}
}