2023-01-27 22:55:49 +00:00
|
|
|
package core
|
|
|
|
|
2023-03-12 06:57:56 +00:00
|
|
|
// import "runtime/debug"
|
2023-03-31 03:19:04 +00:00
|
|
|
import "git.tebibyte.media/sashakoshka/tomo"
|
2023-02-02 06:48:16 +00:00
|
|
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
2023-01-27 22:55:49 +00:00
|
|
|
|
2023-01-30 22:01:47 +00:00
|
|
|
// FocusableCore is a struct that can be embedded into objects to make them
|
|
|
|
// focusable, giving them the default keynav behavior.
|
|
|
|
type FocusableCore struct {
|
2023-03-14 22:30:32 +00:00
|
|
|
core CoreControl
|
2023-01-30 22:01:47 +00:00
|
|
|
focused bool
|
|
|
|
enabled bool
|
|
|
|
drawFocusChange func ()
|
2023-01-27 22:55:49 +00:00
|
|
|
}
|
|
|
|
|
2023-01-30 22:01:47 +00:00
|
|
|
// NewFocusableCore creates a new focusability core and its corresponding
|
|
|
|
// control. If your element needs to visually update itself when it's focus
|
2023-01-27 22:55:49 +00:00
|
|
|
// state changes (which it should), a callback to draw and push the update can
|
|
|
|
// be specified.
|
2023-01-30 22:01:47 +00:00
|
|
|
func NewFocusableCore (
|
2023-03-14 22:30:32 +00:00
|
|
|
core CoreControl,
|
2023-01-30 22:01:47 +00:00
|
|
|
drawFocusChange func (),
|
2023-01-27 22:55:49 +00:00
|
|
|
) (
|
2023-03-14 22:30:32 +00:00
|
|
|
focusable *FocusableCore,
|
2023-01-30 22:01:47 +00:00
|
|
|
control FocusableCoreControl,
|
2023-01-27 22:55:49 +00:00
|
|
|
) {
|
2023-03-14 22:30:32 +00:00
|
|
|
focusable = &FocusableCore {
|
|
|
|
core: core,
|
2023-01-30 22:01:47 +00:00
|
|
|
drawFocusChange: drawFocusChange,
|
2023-01-27 22:55:49 +00:00
|
|
|
enabled: true,
|
|
|
|
}
|
2023-03-14 22:30:32 +00:00
|
|
|
control = FocusableCoreControl { core: focusable }
|
2023-01-27 22:55:49 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-01-30 22:01:47 +00:00
|
|
|
// Focused returns whether or not this element is currently focused.
|
|
|
|
func (core *FocusableCore) Focused () (focused bool) {
|
|
|
|
return core.focused
|
2023-01-27 22:55:49 +00:00
|
|
|
}
|
|
|
|
|
2023-01-30 22:01:47 +00:00
|
|
|
// Focus focuses this element, if its parent element grants the request.
|
|
|
|
func (core *FocusableCore) Focus () {
|
2023-02-09 06:30:14 +00:00
|
|
|
if !core.enabled || core.focused { return }
|
2023-03-14 22:30:32 +00:00
|
|
|
parent := core.core.Parent()
|
2023-03-31 03:19:04 +00:00
|
|
|
if parent, ok := parent.(tomo.FocusableParent); ok {
|
2023-03-14 22:30:32 +00:00
|
|
|
core.focused = parent.RequestFocus (
|
2023-03-31 03:19:04 +00:00
|
|
|
core.core.Outer().(tomo.Focusable))
|
2023-01-27 22:55:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-30 22:01:47 +00:00
|
|
|
// HandleFocus causes this element to mark itself as focused, if it can
|
2023-01-27 22:55:49 +00:00
|
|
|
// currently be. Otherwise, it will return false and do nothing.
|
2023-01-30 22:01:47 +00:00
|
|
|
func (core *FocusableCore) HandleFocus (
|
2023-02-02 06:48:16 +00:00
|
|
|
direction input.KeynavDirection,
|
2023-01-27 22:55:49 +00:00
|
|
|
) (
|
|
|
|
accepted bool,
|
|
|
|
) {
|
|
|
|
direction = direction.Canon()
|
|
|
|
if !core.enabled { return false }
|
2023-02-02 06:48:16 +00:00
|
|
|
if core.focused && direction != input.KeynavDirectionNeutral {
|
2023-01-27 22:55:49 +00:00
|
|
|
return false
|
|
|
|
}
|
2023-02-09 06:30:14 +00:00
|
|
|
|
|
|
|
if core.focused == false {
|
|
|
|
core.focused = true
|
|
|
|
if core.drawFocusChange != nil { core.drawFocusChange() }
|
|
|
|
}
|
2023-01-27 22:55:49 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-01-30 22:01:47 +00:00
|
|
|
// HandleUnfocus causes this element to mark itself as unfocused.
|
|
|
|
func (core *FocusableCore) HandleUnfocus () {
|
|
|
|
core.focused = false
|
2023-03-12 06:57:56 +00:00
|
|
|
// debug.PrintStack()
|
2023-01-30 22:01:47 +00:00
|
|
|
if core.drawFocusChange != nil { core.drawFocusChange() }
|
2023-01-27 22:55:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Enabled returns whether or not the element is enabled.
|
2023-01-30 22:01:47 +00:00
|
|
|
func (core *FocusableCore) Enabled () (enabled bool) {
|
2023-01-27 22:55:49 +00:00
|
|
|
return core.enabled
|
|
|
|
}
|
|
|
|
|
2023-01-30 22:01:47 +00: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
|
2023-01-27 22:55:49 +00:00
|
|
|
// alongside it.
|
2023-01-30 22:01:47 +00:00
|
|
|
type FocusableCoreControl struct {
|
|
|
|
core *FocusableCore
|
2023-01-27 22:55:49 +00:00
|
|
|
}
|
|
|
|
|
2023-01-30 22:01:47 +00:00
|
|
|
// SetEnabled sets whether the focusability core is enabled. If the state
|
|
|
|
// changes, this will call drawFocusChange.
|
|
|
|
func (control FocusableCoreControl) SetEnabled (enabled bool) {
|
2023-01-27 22:55:49 +00:00
|
|
|
if control.core.enabled == enabled { return }
|
|
|
|
control.core.enabled = enabled
|
2023-01-30 22:01:47 +00:00
|
|
|
if !enabled { control.core.focused = false }
|
|
|
|
if control.core.drawFocusChange != nil {
|
|
|
|
control.core.drawFocusChange()
|
2023-01-27 22:55:49 +00:00
|
|
|
}
|
|
|
|
}
|