Hocus focus
This commit is contained in:
parent
35870951a2
commit
801c3ef6f5
@ -124,14 +124,14 @@ func (window *Window) handleKeyPress (
|
|||||||
modifiers.NumberPad = numberPad
|
modifiers.NumberPad = numberPad
|
||||||
|
|
||||||
if key == tomo.KeyTab && modifiers.Alt {
|
if key == tomo.KeyTab && modifiers.Alt {
|
||||||
if child, ok := window.child.(tomo.Selectable); ok {
|
if child, ok := window.child.(tomo.Focusable); ok {
|
||||||
direction := tomo.SelectionDirectionForward
|
direction := tomo.KeynavDirectionForward
|
||||||
if modifiers.Shift {
|
if modifiers.Shift {
|
||||||
direction = tomo.SelectionDirectionBackward
|
direction = tomo.KeynavDirectionBackward
|
||||||
}
|
}
|
||||||
|
|
||||||
if !child.HandleSelection(direction) {
|
if !child.HandleFocus(direction) {
|
||||||
child.HandleDeselection()
|
child.HandleUnfocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if child, ok := window.child.(tomo.KeyboardTarget); ok {
|
} else if child, ok := window.child.(tomo.KeyboardTarget); ok {
|
||||||
|
@ -87,11 +87,11 @@ func (window *Window) Adopt (child tomo.Element) {
|
|||||||
if previousChild, ok := window.child.(tomo.Flexible); ok {
|
if previousChild, ok := window.child.(tomo.Flexible); ok {
|
||||||
previousChild.OnFlexibleHeightChange(nil)
|
previousChild.OnFlexibleHeightChange(nil)
|
||||||
}
|
}
|
||||||
if previousChild, ok := window.child.(tomo.Selectable); ok {
|
if previousChild, ok := window.child.(tomo.Focusable); ok {
|
||||||
previousChild.OnSelectionRequest(nil)
|
previousChild.OnFocusRequest(nil)
|
||||||
previousChild.OnSelectionMotionRequest(nil)
|
previousChild.OnFocusMotionRequest(nil)
|
||||||
if previousChild.Selected() {
|
if previousChild.Focused() {
|
||||||
previousChild.HandleDeselection()
|
previousChild.HandleUnfocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,8 +100,8 @@ func (window *Window) Adopt (child tomo.Element) {
|
|||||||
if newChild, ok := child.(tomo.Flexible); ok {
|
if newChild, ok := child.(tomo.Flexible); ok {
|
||||||
newChild.OnFlexibleHeightChange(window.resizeChildToFit)
|
newChild.OnFlexibleHeightChange(window.resizeChildToFit)
|
||||||
}
|
}
|
||||||
if newChild, ok := child.(tomo.Selectable); ok {
|
if newChild, ok := child.(tomo.Focusable); ok {
|
||||||
newChild.OnSelectionRequest(window.childSelectionRequestCallback)
|
newChild.OnFocusRequest(window.childSelectionRequestCallback)
|
||||||
}
|
}
|
||||||
if child != nil {
|
if child != nil {
|
||||||
child.OnDamage(window.childDrawCallback)
|
child.OnDamage(window.childDrawCallback)
|
||||||
@ -282,20 +282,20 @@ func (window *Window) childMinimumSizeChangeCallback (width, height int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (window *Window) childSelectionRequestCallback () (granted bool) {
|
func (window *Window) childSelectionRequestCallback () (granted bool) {
|
||||||
if child, ok := window.child.(tomo.Selectable); ok {
|
if child, ok := window.child.(tomo.Focusable); ok {
|
||||||
child.HandleSelection(tomo.SelectionDirectionNeutral)
|
child.HandleFocus(tomo.KeynavDirectionNeutral)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *Window) childSelectionMotionRequestCallback (
|
func (window *Window) childSelectionMotionRequestCallback (
|
||||||
direction tomo.SelectionDirection,
|
direction tomo.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
granted bool,
|
granted bool,
|
||||||
) {
|
) {
|
||||||
if child, ok := window.child.(tomo.Selectable); ok {
|
if child, ok := window.child.(tomo.Focusable); ok {
|
||||||
if !child.HandleSelection(direction) {
|
if !child.HandleFocus(direction) {
|
||||||
child.HandleDeselection()
|
child.HandleUnfocus()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
57
element.go
57
element.go
@ -28,58 +28,61 @@ type Element interface {
|
|||||||
OnMinimumSizeChange (callback func ())
|
OnMinimumSizeChange (callback func ())
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectionDirection represents a keyboard navigation direction.
|
// KeynavDirection represents a keyboard navigation direction.
|
||||||
type SelectionDirection int
|
type KeynavDirection int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SelectionDirectionNeutral SelectionDirection = 0
|
KeynavDirectionNeutral KeynavDirection = 0
|
||||||
SelectionDirectionBackward SelectionDirection = -1
|
KeynavDirectionBackward KeynavDirection = -1
|
||||||
SelectionDirectionForward SelectionDirection = 1
|
KeynavDirectionForward KeynavDirection = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// Canon returns a well-formed direction.
|
// Canon returns a well-formed direction.
|
||||||
func (direction SelectionDirection) Canon () (canon SelectionDirection) {
|
func (direction KeynavDirection) Canon () (canon KeynavDirection) {
|
||||||
if direction > 0 {
|
if direction > 0 {
|
||||||
return SelectionDirectionForward
|
return KeynavDirectionForward
|
||||||
} else if direction == 0 {
|
} else if direction == 0 {
|
||||||
return SelectionDirectionNeutral
|
return KeynavDirectionNeutral
|
||||||
} else {
|
} else {
|
||||||
return SelectionDirectionBackward
|
return KeynavDirectionBackward
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Selectable represents an element that has keyboard navigation support. This
|
// Focusable represents an element that has keyboard navigation support. This
|
||||||
// includes inputs, buttons, sliders, etc. as well as any elements that have
|
// includes inputs, buttons, sliders, etc. as well as any elements that have
|
||||||
// children (so keyboard navigation events can be propagated downward).
|
// children (so keyboard navigation events can be propagated downward).
|
||||||
type Selectable interface {
|
type Focusable interface {
|
||||||
Element
|
Element
|
||||||
|
|
||||||
// Selected returns whether or not this element is currently selected.
|
// Focused returns whether or not this element is currently focused.
|
||||||
Selected () (selected bool)
|
Focused () (selected bool)
|
||||||
|
|
||||||
// Select selects this element, if its parent element grants the
|
// Focus focuses this element, if its parent element grants the
|
||||||
// request.
|
// request.
|
||||||
Select ()
|
Focus ()
|
||||||
|
|
||||||
// HandleSelection causes this element to mark itself as selected, if it
|
// HandleFocus causes this element to mark itself as focused. If the
|
||||||
// can currently be. Otherwise, it will return false and do nothing.
|
// element does not have children, it is disabled, or there are no more
|
||||||
HandleSelection (direction SelectionDirection) (accepted bool)
|
// selectable children in the given direction, it should return false
|
||||||
|
// and do nothing. Otherwise, it should select itself and any children
|
||||||
|
// (if applicable) and return true.
|
||||||
|
HandleFocus (direction KeynavDirection) (accepted bool)
|
||||||
|
|
||||||
// HandleDeselection causes this element to mark itself and all of its
|
// HandleDeselection causes this element to mark itself and all of its
|
||||||
// children as deselected.
|
// children as unfocused.
|
||||||
HandleDeselection ()
|
HandleUnfocus ()
|
||||||
|
|
||||||
// OnSelectionRequest sets a function to be called when this element
|
// OnFocusRequest sets a function to be called when this element wants
|
||||||
// wants its parent element to select it. Parent elements should return
|
// its parent element to focus it. Parent elements should return true if
|
||||||
// true if the request was granted, and false if it was not.
|
// the request was granted, and false if it was not.
|
||||||
OnSelectionRequest (func () (granted bool))
|
OnFocusRequest (func () (granted bool))
|
||||||
|
|
||||||
// OnSelectionMotionRequest sets a function to be called when this
|
// OnFocusMotionRequest sets a function to be called when this
|
||||||
// element wants its parent element to select the element behind or in
|
// element wants its parent element to focus the element behind or in
|
||||||
// front of it, depending on the specified direction. Parent elements
|
// front of it, depending on the specified direction. Parent elements
|
||||||
// should return true if the request was granted, and false if it was
|
// should return true if the request was granted, and false if it was
|
||||||
// not.
|
// not.
|
||||||
OnSelectionMotionRequest (func (SelectionDirection) (granted bool))
|
OnFocusMotionRequest (func (direction KeynavDirection) (granted bool))
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyboardTarget represents an element that can receive keyboard input.
|
// KeyboardTarget represents an element that can receive keyboard input.
|
||||||
|
@ -11,9 +11,9 @@ var buttonCase = theme.C("basic", "button")
|
|||||||
// Button is a clickable button.
|
// Button is a clickable button.
|
||||||
type Button struct {
|
type Button struct {
|
||||||
*core.Core
|
*core.Core
|
||||||
*core.SelectableCore
|
*core.FocusableCore
|
||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
selectableControl core.SelectableCoreControl
|
focusableControl core.FocusableCoreControl
|
||||||
drawer artist.TextDrawer
|
drawer artist.TextDrawer
|
||||||
|
|
||||||
pressed bool
|
pressed bool
|
||||||
@ -26,8 +26,8 @@ type Button struct {
|
|||||||
func NewButton (text string) (element *Button) {
|
func NewButton (text string) (element *Button) {
|
||||||
element = &Button { }
|
element = &Button { }
|
||||||
element.Core, element.core = core.NewCore(element)
|
element.Core, element.core = core.NewCore(element)
|
||||||
element.SelectableCore,
|
element.FocusableCore,
|
||||||
element.selectableControl = core.NewSelectableCore (func () {
|
element.focusableControl = core.NewFocusableCore (func () {
|
||||||
if element.core.HasImage () {
|
if element.core.HasImage () {
|
||||||
element.draw()
|
element.draw()
|
||||||
element.core.DamageAll()
|
element.core.DamageAll()
|
||||||
@ -45,7 +45,7 @@ func (element *Button) Resize (width, height int) {
|
|||||||
|
|
||||||
func (element *Button) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *Button) HandleMouseDown (x, y int, button tomo.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
if !element.Selected() { element.Select() }
|
if !element.Focused() { element.Focus() }
|
||||||
if button != tomo.ButtonLeft { return }
|
if button != tomo.ButtonLeft { return }
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
@ -106,7 +106,7 @@ func (element *Button) OnClick (callback func ()) {
|
|||||||
|
|
||||||
// SetEnabled sets whether this button can be clicked or not.
|
// SetEnabled sets whether this button can be clicked or not.
|
||||||
func (element *Button) SetEnabled (enabled bool) {
|
func (element *Button) SetEnabled (enabled bool) {
|
||||||
element.selectableControl.SetEnabled(enabled)
|
element.focusableControl.SetEnabled(enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetText sets the button's label text.
|
// SetText sets the button's label text.
|
||||||
@ -131,7 +131,7 @@ func (element *Button) draw () {
|
|||||||
pattern, inset := theme.ButtonPattern(theme.PatternState {
|
pattern, inset := theme.ButtonPattern(theme.PatternState {
|
||||||
Case: buttonCase,
|
Case: buttonCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Focused: element.Focused(),
|
||||||
Pressed: element.pressed,
|
Pressed: element.pressed,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ var checkboxCase = theme.C("basic", "checkbox")
|
|||||||
// Checkbox is a toggle-able checkbox with a label.
|
// Checkbox is a toggle-able checkbox with a label.
|
||||||
type Checkbox struct {
|
type Checkbox struct {
|
||||||
*core.Core
|
*core.Core
|
||||||
*core.SelectableCore
|
*core.FocusableCore
|
||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
selectableControl core.SelectableCoreControl
|
focusableControl core.FocusableCoreControl
|
||||||
drawer artist.TextDrawer
|
drawer artist.TextDrawer
|
||||||
|
|
||||||
pressed bool
|
pressed bool
|
||||||
@ -27,8 +27,8 @@ type Checkbox struct {
|
|||||||
func NewCheckbox (text string, checked bool) (element *Checkbox) {
|
func NewCheckbox (text string, checked bool) (element *Checkbox) {
|
||||||
element = &Checkbox { checked: checked }
|
element = &Checkbox { checked: checked }
|
||||||
element.Core, element.core = core.NewCore(element)
|
element.Core, element.core = core.NewCore(element)
|
||||||
element.SelectableCore,
|
element.FocusableCore,
|
||||||
element.selectableControl = core.NewSelectableCore (func () {
|
element.focusableControl = core.NewFocusableCore (func () {
|
||||||
if element.core.HasImage () {
|
if element.core.HasImage () {
|
||||||
element.draw()
|
element.draw()
|
||||||
element.core.DamageAll()
|
element.core.DamageAll()
|
||||||
@ -47,7 +47,7 @@ func (element *Checkbox) Resize (width, height int) {
|
|||||||
|
|
||||||
func (element *Checkbox) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *Checkbox) HandleMouseDown (x, y int, button tomo.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
element.Select()
|
element.Focus()
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
element.draw()
|
element.draw()
|
||||||
@ -113,7 +113,7 @@ func (element *Checkbox) Value () (checked bool) {
|
|||||||
|
|
||||||
// SetEnabled sets whether this checkbox can be toggled or not.
|
// SetEnabled sets whether this checkbox can be toggled or not.
|
||||||
func (element *Checkbox) SetEnabled (enabled bool) {
|
func (element *Checkbox) SetEnabled (enabled bool) {
|
||||||
element.selectableControl.SetEnabled(enabled)
|
element.focusableControl.SetEnabled(enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetText sets the checkbox's label text.
|
// SetText sets the checkbox's label text.
|
||||||
@ -150,7 +150,7 @@ func (element *Checkbox) draw () {
|
|||||||
pattern, inset := theme.ButtonPattern(theme.PatternState {
|
pattern, inset := theme.ButtonPattern(theme.PatternState {
|
||||||
Case: checkboxCase,
|
Case: checkboxCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Focused: element.Focused(),
|
||||||
Pressed: element.pressed,
|
Pressed: element.pressed,
|
||||||
})
|
})
|
||||||
artist.FillRectangle(element.core, pattern, boxBounds)
|
artist.FillRectangle(element.core, pattern, boxBounds)
|
||||||
|
@ -14,16 +14,16 @@ type Container struct {
|
|||||||
*core.Core
|
*core.Core
|
||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
|
|
||||||
layout tomo.Layout
|
layout tomo.Layout
|
||||||
children []tomo.LayoutEntry
|
children []tomo.LayoutEntry
|
||||||
drags [10]tomo.MouseTarget
|
drags [10]tomo.MouseTarget
|
||||||
warping bool
|
warping bool
|
||||||
selected bool
|
focused bool
|
||||||
selectable bool
|
focusable bool
|
||||||
flexible bool
|
flexible bool
|
||||||
|
|
||||||
onSelectionRequest func () (granted bool)
|
onFocusRequest func () (granted bool)
|
||||||
onSelectionMotionRequest func (tomo.SelectionDirection) (granted bool)
|
onFocusMotionRequest func (tomo.KeynavDirection) (granted bool)
|
||||||
onFlexibleHeightChange func ()
|
onFlexibleHeightChange func ()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,14 +57,14 @@ func (element *Container) Adopt (child tomo.Element, expand bool) {
|
|||||||
if child0, ok := child.(tomo.Flexible); ok {
|
if child0, ok := child.(tomo.Flexible); ok {
|
||||||
child0.OnFlexibleHeightChange(element.updateMinimumSize)
|
child0.OnFlexibleHeightChange(element.updateMinimumSize)
|
||||||
}
|
}
|
||||||
if child0, ok := child.(tomo.Selectable); ok {
|
if child0, ok := child.(tomo.Focusable); ok {
|
||||||
child0.OnSelectionRequest (func () (granted bool) {
|
child0.OnFocusRequest (func () (granted bool) {
|
||||||
return element.childSelectionRequestCallback(child0)
|
return element.childFocusRequestCallback(child0)
|
||||||
})
|
})
|
||||||
child0.OnSelectionMotionRequest (
|
child0.OnFocusMotionRequest (
|
||||||
func (direction tomo.SelectionDirection) (granted bool) {
|
func (direction tomo.KeynavDirection) (granted bool) {
|
||||||
if element.onSelectionMotionRequest == nil { return }
|
if element.onFocusMotionRequest == nil { return }
|
||||||
return element.onSelectionMotionRequest(direction)
|
return element.onFocusMotionRequest(direction)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,11 +132,11 @@ func (element *Container) Disown (child tomo.Element) {
|
|||||||
func (element *Container) clearChildEventHandlers (child tomo.Element) {
|
func (element *Container) clearChildEventHandlers (child tomo.Element) {
|
||||||
child.OnDamage(nil)
|
child.OnDamage(nil)
|
||||||
child.OnMinimumSizeChange(nil)
|
child.OnMinimumSizeChange(nil)
|
||||||
if child0, ok := child.(tomo.Selectable); ok {
|
if child0, ok := child.(tomo.Focusable); ok {
|
||||||
child0.OnSelectionRequest(nil)
|
child0.OnFocusRequest(nil)
|
||||||
child0.OnSelectionMotionRequest(nil)
|
child0.OnFocusMotionRequest(nil)
|
||||||
if child0.Selected() {
|
if child0.Focused() {
|
||||||
child0.HandleDeselection()
|
child0.HandleUnfocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if child0, ok := child.(tomo.Flexible); ok {
|
if child0, ok := child.(tomo.Flexible); ok {
|
||||||
@ -238,7 +238,7 @@ func (element *Container) HandleMouseScroll (x, y int, deltaX, deltaY float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
||||||
element.forSelected (func (child tomo.Selectable) bool {
|
element.forFocused (func (child tomo.Focusable) bool {
|
||||||
child0, handlesKeyboard := child.(tomo.KeyboardTarget)
|
child0, handlesKeyboard := child.(tomo.KeyboardTarget)
|
||||||
if handlesKeyboard {
|
if handlesKeyboard {
|
||||||
child0.HandleKeyDown(key, modifiers)
|
child0.HandleKeyDown(key, modifiers)
|
||||||
@ -248,7 +248,7 @@ func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
|
||||||
element.forSelected (func (child tomo.Selectable) bool {
|
element.forFocused (func (child tomo.Focusable) bool {
|
||||||
child0, handlesKeyboard := child.(tomo.KeyboardTarget)
|
child0, handlesKeyboard := child.(tomo.KeyboardTarget)
|
||||||
if handlesKeyboard {
|
if handlesKeyboard {
|
||||||
child0.HandleKeyUp(key, modifiers)
|
child0.HandleKeyUp(key, modifiers)
|
||||||
@ -257,103 +257,6 @@ func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) Selected () (selected bool) {
|
|
||||||
return element.selected
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) Select () {
|
|
||||||
if element.onSelectionRequest != nil {
|
|
||||||
element.onSelectionRequest()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) HandleSelection (direction tomo.SelectionDirection) (ok bool) {
|
|
||||||
if !element.selectable { return false }
|
|
||||||
direction = direction.Canon()
|
|
||||||
|
|
||||||
firstSelected := element.firstSelected()
|
|
||||||
if firstSelected < 0 {
|
|
||||||
// no element is currently selected, so we need to select either
|
|
||||||
// the first or last selectable element depending on the
|
|
||||||
// direction.
|
|
||||||
switch direction {
|
|
||||||
case tomo.SelectionDirectionNeutral, tomo.SelectionDirectionForward:
|
|
||||||
// if we recieve a neutral or forward direction, select
|
|
||||||
// the first selectable element.
|
|
||||||
return element.selectFirstSelectableElement(direction)
|
|
||||||
|
|
||||||
case tomo.SelectionDirectionBackward:
|
|
||||||
// if we recieve a backward direction, select the last
|
|
||||||
// selectable element.
|
|
||||||
return element.selectLastSelectableElement(direction)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// an element is currently selected, so we need to move the
|
|
||||||
// selection in the specified direction
|
|
||||||
firstSelectedChild :=
|
|
||||||
element.children[firstSelected].Element.(tomo.Selectable)
|
|
||||||
|
|
||||||
// before we move the selection, the currently selected child
|
|
||||||
// may also be able to move its selection. if the child is able
|
|
||||||
// to do that, we will let it and not move ours.
|
|
||||||
if firstSelectedChild.HandleSelection(direction) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the previous/next selectable element relative to the
|
|
||||||
// currently selected element, if it exists.
|
|
||||||
for index := firstSelected + int(direction);
|
|
||||||
index < len(element.children) && index >= 0;
|
|
||||||
index += int(direction) {
|
|
||||||
|
|
||||||
child, selectable :=
|
|
||||||
element.children[index].
|
|
||||||
Element.(tomo.Selectable)
|
|
||||||
if selectable && child.HandleSelection(direction) {
|
|
||||||
// we have found one, so we now actually move
|
|
||||||
// the selection.
|
|
||||||
firstSelectedChild.HandleDeselection()
|
|
||||||
element.selected = true
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) selectFirstSelectableElement (
|
|
||||||
direction tomo.SelectionDirection,
|
|
||||||
) (
|
|
||||||
ok bool,
|
|
||||||
) {
|
|
||||||
element.forSelectable (func (child tomo.Selectable) bool {
|
|
||||||
if child.HandleSelection(direction) {
|
|
||||||
element.selected = true
|
|
||||||
ok = true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) selectLastSelectableElement (
|
|
||||||
direction tomo.SelectionDirection,
|
|
||||||
) (
|
|
||||||
ok bool,
|
|
||||||
) {
|
|
||||||
element.forSelectableBackward (func (child tomo.Selectable) bool {
|
|
||||||
if child.HandleSelection(direction) {
|
|
||||||
element.selected = true
|
|
||||||
ok = true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (element *Container) FlexibleHeightFor (width int) (height int) {
|
func (element *Container) FlexibleHeightFor (width int) (height int) {
|
||||||
return element.layout.FlexibleHeightFor(element.children, width)
|
return element.layout.FlexibleHeightFor(element.children, width)
|
||||||
}
|
}
|
||||||
@ -362,37 +265,134 @@ func (element *Container) OnFlexibleHeightChange (callback func ()) {
|
|||||||
element.onFlexibleHeightChange = callback
|
element.onFlexibleHeightChange = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleDeselection () {
|
func (element *Container) Focused () (focused bool) {
|
||||||
element.selected = false
|
return element.focused
|
||||||
element.forSelected (func (child tomo.Selectable) bool {
|
}
|
||||||
child.HandleDeselection()
|
|
||||||
|
func (element *Container) Focus () {
|
||||||
|
if element.onFocusRequest != nil {
|
||||||
|
element.onFocusRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (element *Container) HandleFocus (direction tomo.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 tomo.KeynavDirectionNeutral, tomo.KeynavDirectionForward:
|
||||||
|
// if we recieve a neutral or forward direction, focus
|
||||||
|
// the first focusable element.
|
||||||
|
return element.focusFirstFocusableElement(direction)
|
||||||
|
|
||||||
|
case tomo.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.(tomo.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.(tomo.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 tomo.KeynavDirection,
|
||||||
|
) (
|
||||||
|
ok bool,
|
||||||
|
) {
|
||||||
|
element.forFocusable (func (child tomo.Focusable) bool {
|
||||||
|
if child.HandleFocus(direction) {
|
||||||
|
element.focused = true
|
||||||
|
ok = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (element *Container) focusLastFocusableElement (
|
||||||
|
direction tomo.KeynavDirection,
|
||||||
|
) (
|
||||||
|
ok bool,
|
||||||
|
) {
|
||||||
|
element.forFocusableBackward (func (child tomo.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 tomo.Focusable) bool {
|
||||||
|
child.HandleUnfocus()
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) OnSelectionRequest (callback func () (granted bool)) {
|
func (element *Container) OnFocusRequest (callback func () (granted bool)) {
|
||||||
element.onSelectionRequest = callback
|
element.onFocusRequest = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) OnSelectionMotionRequest (
|
func (element *Container) OnFocusMotionRequest (
|
||||||
callback func (direction tomo.SelectionDirection) (granted bool),
|
callback func (direction tomo.KeynavDirection) (granted bool),
|
||||||
) {
|
) {
|
||||||
element.onSelectionMotionRequest = callback
|
element.onFocusMotionRequest = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) forSelected (callback func (child tomo.Selectable) bool) {
|
func (element *Container) forFocused (callback func (child tomo.Focusable) bool) {
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
child, selectable := entry.Element.(tomo.Selectable)
|
child, focusable := entry.Element.(tomo.Focusable)
|
||||||
if selectable && child.Selected() {
|
if focusable && child.Focused() {
|
||||||
if !callback(child) { break }
|
if !callback(child) { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) forSelectable (callback func (child tomo.Selectable) bool) {
|
func (element *Container) forFocusable (callback func (child tomo.Focusable) bool) {
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
child, selectable := entry.Element.(tomo.Selectable)
|
child, focusable := entry.Element.(tomo.Focusable)
|
||||||
if selectable {
|
if focusable {
|
||||||
if !callback(child) { break }
|
if !callback(child) { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,26 +400,26 @@ func (element *Container) forSelectable (callback func (child tomo.Selectable) b
|
|||||||
|
|
||||||
func (element *Container) forFlexible (callback func (child tomo.Flexible) bool) {
|
func (element *Container) forFlexible (callback func (child tomo.Flexible) bool) {
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
child, selectable := entry.Element.(tomo.Flexible)
|
child, flexible := entry.Element.(tomo.Flexible)
|
||||||
if selectable {
|
if flexible {
|
||||||
if !callback(child) { break }
|
if !callback(child) { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) forSelectableBackward (callback func (child tomo.Selectable) bool) {
|
func (element *Container) forFocusableBackward (callback func (child tomo.Focusable) bool) {
|
||||||
for index := len(element.children) - 1; index >= 0; index -- {
|
for index := len(element.children) - 1; index >= 0; index -- {
|
||||||
child, selectable := element.children[index].Element.(tomo.Selectable)
|
child, focusable := element.children[index].Element.(tomo.Focusable)
|
||||||
if selectable {
|
if focusable {
|
||||||
if !callback(child) { break }
|
if !callback(child) { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) firstSelected () (index int) {
|
func (element *Container) firstFocused () (index int) {
|
||||||
for currentIndex, entry := range element.children {
|
for currentIndex, entry := range element.children {
|
||||||
child, selectable := entry.Element.(tomo.Selectable)
|
child, focusable := entry.Element.(tomo.Focusable)
|
||||||
if selectable && child.Selected() {
|
if focusable && child.Focused() {
|
||||||
return currentIndex
|
return currentIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -427,9 +427,9 @@ func (element *Container) firstSelected () (index int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) reflectChildProperties () {
|
func (element *Container) reflectChildProperties () {
|
||||||
element.selectable = false
|
element.focusable = false
|
||||||
element.forSelectable (func (tomo.Selectable) bool {
|
element.forFocusable (func (tomo.Focusable) bool {
|
||||||
element.selectable = true
|
element.focusable = true
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
element.flexible = false
|
element.flexible = false
|
||||||
@ -437,22 +437,22 @@ func (element *Container) reflectChildProperties () {
|
|||||||
element.flexible = true
|
element.flexible = true
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
if !element.selectable {
|
if !element.focusable {
|
||||||
element.selected = false
|
element.focused = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) childSelectionRequestCallback (
|
func (element *Container) childFocusRequestCallback (
|
||||||
child tomo.Selectable,
|
child tomo.Focusable,
|
||||||
) (
|
) (
|
||||||
granted bool,
|
granted bool,
|
||||||
) {
|
) {
|
||||||
if element.onSelectionRequest != nil && element.onSelectionRequest() {
|
if element.onFocusRequest != nil && element.onFocusRequest() {
|
||||||
element.forSelected (func (child tomo.Selectable) bool {
|
element.forFocused (func (child tomo.Focusable) bool {
|
||||||
child.HandleDeselection()
|
child.HandleUnfocus()
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
child.HandleSelection(tomo.SelectionDirectionNeutral)
|
child.HandleFocus(tomo.KeynavDirectionNeutral)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
@ -12,9 +12,9 @@ var listCase = theme.C("basic", "list")
|
|||||||
// List is an element that contains several objects that a user can select.
|
// List is an element that contains several objects that a user can select.
|
||||||
type List struct {
|
type List struct {
|
||||||
*core.Core
|
*core.Core
|
||||||
*core.SelectableCore
|
*core.FocusableCore
|
||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
selectableControl core.SelectableCoreControl
|
focusableControl core.FocusableCoreControl
|
||||||
|
|
||||||
pressed bool
|
pressed bool
|
||||||
|
|
||||||
@ -34,8 +34,8 @@ type List struct {
|
|||||||
func NewList (entries ...ListEntry) (element *List) {
|
func NewList (entries ...ListEntry) (element *List) {
|
||||||
element = &List { selectedEntry: -1 }
|
element = &List { selectedEntry: -1 }
|
||||||
element.Core, element.core = core.NewCore(element)
|
element.Core, element.core = core.NewCore(element)
|
||||||
element.SelectableCore,
|
element.FocusableCore,
|
||||||
element.selectableControl = core.NewSelectableCore (func () {
|
element.focusableControl = core.NewFocusableCore (func () {
|
||||||
if element.core.HasImage () {
|
if element.core.HasImage () {
|
||||||
element.draw()
|
element.draw()
|
||||||
element.core.DamageAll()
|
element.core.DamageAll()
|
||||||
@ -78,7 +78,7 @@ func (element *List) Collapse (width, height int) {
|
|||||||
|
|
||||||
func (element *List) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *List) HandleMouseDown (x, y int, button tomo.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
if !element.Selected() { element.Select() }
|
if !element.Focused() { element.Focus() }
|
||||||
if button != tomo.ButtonLeft { return }
|
if button != tomo.ButtonLeft { return }
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
if element.selectUnderMouse(x, y) && element.core.HasImage() {
|
if element.selectUnderMouse(x, y) && element.core.HasImage() {
|
||||||
@ -377,7 +377,7 @@ func (element *List) draw () {
|
|||||||
pattern, inset := theme.ListPattern(theme.PatternState {
|
pattern, inset := theme.ListPattern(theme.PatternState {
|
||||||
Case: listCase,
|
Case: listCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Focused: element.Focused(),
|
||||||
})
|
})
|
||||||
artist.FillRectangle(element.core, pattern, bounds)
|
artist.FillRectangle(element.core, pattern, bounds)
|
||||||
|
|
||||||
@ -394,6 +394,6 @@ func (element *List) draw () {
|
|||||||
if entryPosition.Y > bounds.Max.Y { break }
|
if entryPosition.Y > bounds.Max.Y { break }
|
||||||
entry.Draw (
|
entry.Draw (
|
||||||
innerCanvas, entryPosition,
|
innerCanvas, entryPosition,
|
||||||
element.Selected(), element.selectedEntry == index)
|
element.Focused(), element.selectedEntry == index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,14 +55,14 @@ func (entry *ListEntry) updateBounds () {
|
|||||||
func (entry *ListEntry) Draw (
|
func (entry *ListEntry) Draw (
|
||||||
destination tomo.Canvas,
|
destination tomo.Canvas,
|
||||||
offset image.Point,
|
offset image.Point,
|
||||||
selected bool,
|
focused bool,
|
||||||
on bool,
|
on bool,
|
||||||
) (
|
) (
|
||||||
updatedRegion image.Rectangle,
|
updatedRegion image.Rectangle,
|
||||||
) {
|
) {
|
||||||
pattern, _ := theme.ItemPattern(theme.PatternState {
|
pattern, _ := theme.ItemPattern(theme.PatternState {
|
||||||
Case: listEntryCase,
|
Case: listEntryCase,
|
||||||
Selected: selected,
|
Focused: focused,
|
||||||
On: on,
|
On: on,
|
||||||
})
|
})
|
||||||
artist.FillRectangle (
|
artist.FillRectangle (
|
||||||
@ -71,7 +71,7 @@ func (entry *ListEntry) Draw (
|
|||||||
entry.Bounds().Add(offset))
|
entry.Bounds().Add(offset))
|
||||||
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
foreground, _ := theme.ForegroundPattern (theme.PatternState {
|
||||||
Case: listEntryCase,
|
Case: listEntryCase,
|
||||||
Selected: selected,
|
Focused: focused,
|
||||||
On: on,
|
On: on,
|
||||||
})
|
})
|
||||||
return entry.drawer.Draw (
|
return entry.drawer.Draw (
|
||||||
|
@ -15,7 +15,7 @@ var scrollBarVerticalCase = theme.C("basic", "scrollBarVertical")
|
|||||||
type ScrollContainer struct {
|
type ScrollContainer struct {
|
||||||
*core.Core
|
*core.Core
|
||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
selected bool
|
focused bool
|
||||||
|
|
||||||
child tomo.Scrollable
|
child tomo.Scrollable
|
||||||
childWidth, childHeight int
|
childWidth, childHeight int
|
||||||
@ -40,8 +40,8 @@ type ScrollContainer struct {
|
|||||||
bar image.Rectangle
|
bar image.Rectangle
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectionRequest func () (granted bool)
|
onFocusRequest func () (granted bool)
|
||||||
onSelectionMotionRequest func (tomo.SelectionDirection) (granted bool)
|
onFocusMotionRequest func (tomo.KeynavDirection) (granted bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScrollContainer creates a new scroll container with the specified scroll
|
// NewScrollContainer creates a new scroll container with the specified scroll
|
||||||
@ -80,11 +80,11 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
|
|||||||
child.OnDamage(element.childDamageCallback)
|
child.OnDamage(element.childDamageCallback)
|
||||||
child.OnMinimumSizeChange(element.updateMinimumSize)
|
child.OnMinimumSizeChange(element.updateMinimumSize)
|
||||||
child.OnScrollBoundsChange(element.childScrollBoundsChangeCallback)
|
child.OnScrollBoundsChange(element.childScrollBoundsChangeCallback)
|
||||||
if newChild, ok := child.(tomo.Selectable); ok {
|
if newChild, ok := child.(tomo.Focusable); ok {
|
||||||
newChild.OnSelectionRequest (
|
newChild.OnFocusRequest (
|
||||||
element.childSelectionRequestCallback)
|
element.childFocusRequestCallback)
|
||||||
newChild.OnSelectionMotionRequest (
|
newChild.OnFocusMotionRequest (
|
||||||
element.childSelectionMotionRequestCallback)
|
element.childFocusMotionRequestCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: somehow inform the core that we do not in fact want to
|
// TODO: somehow inform the core that we do not in fact want to
|
||||||
@ -193,82 +193,80 @@ func (element *ScrollContainer) scrollChildBy (x, y int) {
|
|||||||
element.child.ScrollTo(scrollPoint)
|
element.child.ScrollTo(scrollPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) Selected () (selected bool) {
|
func (element *ScrollContainer) Focused () (focused bool) {
|
||||||
return element.selected
|
return element.focused
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) Select () {
|
func (element *ScrollContainer) Focus () {
|
||||||
if element.onSelectionRequest != nil {
|
if element.onFocusRequest != nil {
|
||||||
element.onSelectionRequest()
|
element.onFocusRequest()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) HandleSelection (
|
func (element *ScrollContainer) HandleFocus (
|
||||||
direction tomo.SelectionDirection,
|
direction tomo.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
accepted bool,
|
accepted bool,
|
||||||
) {
|
) {
|
||||||
if child, ok := element.child.(tomo.Selectable); ok {
|
if child, ok := element.child.(tomo.Focusable); ok {
|
||||||
element.selected = true
|
element.focused = true
|
||||||
return child.HandleSelection(direction)
|
return child.HandleFocus(direction)
|
||||||
} else {
|
} else {
|
||||||
element.selected = false
|
element.focused = false
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) HandleDeselection () {
|
func (element *ScrollContainer) HandleUnfocus () {
|
||||||
if child, ok := element.child.(tomo.Selectable); ok {
|
if child, ok := element.child.(tomo.Focusable); ok {
|
||||||
child.HandleDeselection()
|
child.HandleUnfocus()
|
||||||
}
|
}
|
||||||
element.selected = false
|
element.focused = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) OnSelectionRequest (callback func () (granted bool)) {
|
func (element *ScrollContainer) OnFocusRequest (callback func () (granted bool)) {
|
||||||
element.onSelectionRequest = callback
|
element.onFocusRequest = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) OnSelectionMotionRequest (
|
func (element *ScrollContainer) OnFocusMotionRequest (
|
||||||
callback func (direction tomo.SelectionDirection) (granted bool),
|
callback func (direction tomo.KeynavDirection) (granted bool),
|
||||||
) {
|
) {
|
||||||
element.onSelectionMotionRequest = callback
|
element.onFocusMotionRequest = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) childDamageCallback (region tomo.Canvas) {
|
func (element *ScrollContainer) childDamageCallback (region tomo.Canvas) {
|
||||||
element.core.DamageRegion(artist.Paste(element, region, image.Point { }))
|
element.core.DamageRegion(artist.Paste(element, region, image.Point { }))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) childSelectionRequestCallback () (granted bool) {
|
func (element *ScrollContainer) childFocusRequestCallback () (granted bool) {
|
||||||
child, ok := element.child.(tomo.Selectable)
|
child, ok := element.child.(tomo.Focusable)
|
||||||
if !ok { return false }
|
if !ok { return false }
|
||||||
if element.onSelectionRequest != nil && element.onSelectionRequest() {
|
if element.onFocusRequest != nil && element.onFocusRequest() {
|
||||||
child.HandleSelection(tomo.SelectionDirectionNeutral)
|
child.HandleFocus(tomo.KeynavDirectionNeutral)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) childSelectionMotionRequestCallback (
|
func (element *ScrollContainer) childFocusMotionRequestCallback (
|
||||||
direction tomo.SelectionDirection,
|
direction tomo.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
granted bool,
|
granted bool,
|
||||||
) {
|
) {
|
||||||
if element.onSelectionMotionRequest == nil {
|
if element.onFocusMotionRequest == nil { return }
|
||||||
return
|
return element.onFocusMotionRequest(direction)
|
||||||
}
|
|
||||||
return element.onSelectionMotionRequest(direction)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) clearChildEventHandlers (child tomo.Scrollable) {
|
func (element *ScrollContainer) clearChildEventHandlers (child tomo.Scrollable) {
|
||||||
child.OnDamage(nil)
|
child.OnDamage(nil)
|
||||||
child.OnMinimumSizeChange(nil)
|
child.OnMinimumSizeChange(nil)
|
||||||
child.OnScrollBoundsChange(nil)
|
child.OnScrollBoundsChange(nil)
|
||||||
if child0, ok := child.(tomo.Selectable); ok {
|
if child0, ok := child.(tomo.Focusable); ok {
|
||||||
child0.OnSelectionRequest(nil)
|
child0.OnFocusRequest(nil)
|
||||||
child0.OnSelectionMotionRequest(nil)
|
child0.OnFocusMotionRequest(nil)
|
||||||
if child0.Selected() {
|
if child0.Focused() {
|
||||||
child0.HandleDeselection()
|
child0.HandleUnfocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if child0, ok := child.(tomo.Flexible); ok {
|
if child0, ok := child.(tomo.Flexible); ok {
|
||||||
|
@ -12,9 +12,9 @@ var switchCase = theme.C("basic", "switch")
|
|||||||
// functionally identical to Checkbox, but plays a different semantic role.
|
// functionally identical to Checkbox, but plays a different semantic role.
|
||||||
type Switch struct {
|
type Switch struct {
|
||||||
*core.Core
|
*core.Core
|
||||||
*core.SelectableCore
|
*core.FocusableCore
|
||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
selectableControl core.SelectableCoreControl
|
focusableControl core.FocusableCoreControl
|
||||||
drawer artist.TextDrawer
|
drawer artist.TextDrawer
|
||||||
|
|
||||||
pressed bool
|
pressed bool
|
||||||
@ -28,8 +28,8 @@ type Switch struct {
|
|||||||
func NewSwitch (text string, on bool) (element *Switch) {
|
func NewSwitch (text string, on bool) (element *Switch) {
|
||||||
element = &Switch { checked: on, text: text }
|
element = &Switch { checked: on, text: text }
|
||||||
element.Core, element.core = core.NewCore(element)
|
element.Core, element.core = core.NewCore(element)
|
||||||
element.SelectableCore,
|
element.FocusableCore,
|
||||||
element.selectableControl = core.NewSelectableCore (func () {
|
element.focusableControl = core.NewFocusableCore (func () {
|
||||||
if element.core.HasImage () {
|
if element.core.HasImage () {
|
||||||
element.draw()
|
element.draw()
|
||||||
element.core.DamageAll()
|
element.core.DamageAll()
|
||||||
@ -49,7 +49,7 @@ func (element *Switch) Resize (width, height int) {
|
|||||||
|
|
||||||
func (element *Switch) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *Switch) HandleMouseDown (x, y int, button tomo.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
element.Select()
|
element.Focus()
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
element.draw()
|
element.draw()
|
||||||
@ -115,7 +115,7 @@ func (element *Switch) Value () (on bool) {
|
|||||||
|
|
||||||
// SetEnabled sets whether this switch can be flipped or not.
|
// SetEnabled sets whether this switch can be flipped or not.
|
||||||
func (element *Switch) SetEnabled (enabled bool) {
|
func (element *Switch) SetEnabled (enabled bool) {
|
||||||
element.selectableControl.SetEnabled(enabled)
|
element.focusableControl.SetEnabled(enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetText sets the checkbox's label text.
|
// SetText sets the checkbox's label text.
|
||||||
@ -171,7 +171,7 @@ func (element *Switch) draw () {
|
|||||||
gutterPattern, _ := theme.GutterPattern(theme.PatternState {
|
gutterPattern, _ := theme.GutterPattern(theme.PatternState {
|
||||||
Case: switchCase,
|
Case: switchCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Focused: element.Focused(),
|
||||||
Pressed: element.pressed,
|
Pressed: element.pressed,
|
||||||
})
|
})
|
||||||
artist.FillRectangle(element.core, gutterPattern, gutterBounds)
|
artist.FillRectangle(element.core, gutterPattern, gutterBounds)
|
||||||
@ -179,7 +179,7 @@ func (element *Switch) draw () {
|
|||||||
handlePattern, _ := theme.HandlePattern(theme.PatternState {
|
handlePattern, _ := theme.HandlePattern(theme.PatternState {
|
||||||
Case: switchCase,
|
Case: switchCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Focused: element.Focused(),
|
||||||
Pressed: element.pressed,
|
Pressed: element.pressed,
|
||||||
})
|
})
|
||||||
artist.FillRectangle(element.core, handlePattern, handleBounds)
|
artist.FillRectangle(element.core, handlePattern, handleBounds)
|
||||||
|
@ -12,9 +12,9 @@ var textBoxCase = theme.C("basic", "textBox")
|
|||||||
// TextBox is a single-line text input.
|
// TextBox is a single-line text input.
|
||||||
type TextBox struct {
|
type TextBox struct {
|
||||||
*core.Core
|
*core.Core
|
||||||
*core.SelectableCore
|
*core.FocusableCore
|
||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
selectableControl core.SelectableCoreControl
|
focusableControl core.FocusableCoreControl
|
||||||
|
|
||||||
cursor int
|
cursor int
|
||||||
scroll int
|
scroll int
|
||||||
@ -35,8 +35,8 @@ type TextBox struct {
|
|||||||
func NewTextBox (placeholder, value string) (element *TextBox) {
|
func NewTextBox (placeholder, value string) (element *TextBox) {
|
||||||
element = &TextBox { }
|
element = &TextBox { }
|
||||||
element.Core, element.core = core.NewCore(element)
|
element.Core, element.core = core.NewCore(element)
|
||||||
element.SelectableCore,
|
element.FocusableCore,
|
||||||
element.selectableControl = core.NewSelectableCore (func () {
|
element.focusableControl = core.NewFocusableCore (func () {
|
||||||
if element.core.HasImage () {
|
if element.core.HasImage () {
|
||||||
element.draw()
|
element.draw()
|
||||||
element.core.DamageAll()
|
element.core.DamageAll()
|
||||||
@ -61,8 +61,8 @@ func (element *TextBox) Resize (width, height int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *TextBox) HandleMouseDown (x, y int, button tomo.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
if !element.Selected() { element.Select() }
|
if !element.Focused() { element.Focus() }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) HandleMouseUp (x, y int, button tomo.Button) { }
|
func (element *TextBox) HandleMouseUp (x, y int, button tomo.Button) { }
|
||||||
@ -277,13 +277,13 @@ func (element *TextBox) draw () {
|
|||||||
|
|
||||||
// FIXME: take index into account
|
// FIXME: take index into account
|
||||||
pattern, inset := theme.InputPattern(theme.PatternState {
|
pattern, inset := theme.InputPattern(theme.PatternState {
|
||||||
Case: textBoxCase,
|
Case: textBoxCase,
|
||||||
Disabled: !element.Enabled(),
|
Disabled: !element.Enabled(),
|
||||||
Selected: element.Selected(),
|
Focused: element.Focused(),
|
||||||
})
|
})
|
||||||
artist.FillRectangle(element.core, pattern, bounds)
|
artist.FillRectangle(element.core, pattern, bounds)
|
||||||
|
|
||||||
if len(element.text) == 0 && !element.Selected() {
|
if len(element.text) == 0 && !element.Focused() {
|
||||||
// draw placeholder
|
// draw placeholder
|
||||||
textBounds := element.placeholderDrawer.LayoutBounds()
|
textBounds := element.placeholderDrawer.LayoutBounds()
|
||||||
offset := image.Point {
|
offset := image.Point {
|
||||||
@ -314,7 +314,7 @@ func (element *TextBox) draw () {
|
|||||||
foreground,
|
foreground,
|
||||||
offset.Sub(textBounds.Min))
|
offset.Sub(textBounds.Min))
|
||||||
|
|
||||||
if element.Selected() {
|
if element.Focused() {
|
||||||
// cursor
|
// cursor
|
||||||
cursorPosition := element.valueDrawer.PositionOf (
|
cursorPosition := element.valueDrawer.PositionOf (
|
||||||
element.cursor)
|
element.cursor)
|
||||||
|
@ -15,9 +15,6 @@ type Core struct {
|
|||||||
minimumHeight int
|
minimumHeight int
|
||||||
}
|
}
|
||||||
|
|
||||||
selectable bool
|
|
||||||
selected bool
|
|
||||||
|
|
||||||
onMinimumSizeChange func ()
|
onMinimumSizeChange func ()
|
||||||
onDamage func (region tomo.Canvas)
|
onDamage func (region tomo.Canvas)
|
||||||
}
|
}
|
||||||
|
@ -2,110 +2,110 @@ package core
|
|||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
|
|
||||||
// SelectableCore is a struct that can be embedded into objects to make them
|
// FocusableCore is a struct that can be embedded into objects to make them
|
||||||
// selectable, giving them the default selectability behavior.
|
// focusable, giving them the default keynav behavior.
|
||||||
type SelectableCore struct {
|
type FocusableCore struct {
|
||||||
selected bool
|
focused bool
|
||||||
enabled bool
|
enabled bool
|
||||||
drawSelectionChange func ()
|
drawFocusChange func ()
|
||||||
onSelectionRequest func () (granted bool)
|
onFocusRequest func () (granted bool)
|
||||||
onSelectionMotionRequest func(tomo.SelectionDirection) (granted bool)
|
onFocusMotionRequest func(tomo.KeynavDirection) (granted bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSelectableCore creates a new selectability core and its corresponding
|
// NewFocusableCore creates a new focusability core and its corresponding
|
||||||
// control. If your element needs to visually update itself when it's selection
|
// 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
|
// state changes (which it should), a callback to draw and push the update can
|
||||||
// be specified.
|
// be specified.
|
||||||
func NewSelectableCore (
|
func NewFocusableCore (
|
||||||
drawSelectionChange func (),
|
drawFocusChange func (),
|
||||||
) (
|
) (
|
||||||
core *SelectableCore,
|
core *FocusableCore,
|
||||||
control SelectableCoreControl,
|
control FocusableCoreControl,
|
||||||
) {
|
) {
|
||||||
core = &SelectableCore {
|
core = &FocusableCore {
|
||||||
drawSelectionChange: drawSelectionChange,
|
drawFocusChange: drawFocusChange,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
}
|
}
|
||||||
control = SelectableCoreControl { core: core }
|
control = FocusableCoreControl { core: core }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Selected returns whether or not this element is currently selected.
|
// Focused returns whether or not this element is currently focused.
|
||||||
func (core *SelectableCore) Selected () (selected bool) {
|
func (core *FocusableCore) Focused () (focused bool) {
|
||||||
return core.selected
|
return core.focused
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select selects this element, if its parent element grants the request.
|
// Focus focuses this element, if its parent element grants the request.
|
||||||
func (core *SelectableCore) Select () {
|
func (core *FocusableCore) Focus () {
|
||||||
if !core.enabled { return }
|
if !core.enabled { return }
|
||||||
if core.onSelectionRequest != nil {
|
if core.onFocusRequest != nil {
|
||||||
core.onSelectionRequest()
|
core.onFocusRequest()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleSelection causes this element to mark itself as selected, if it can
|
// HandleFocus causes this element to mark itself as focused, if it can
|
||||||
// currently be. Otherwise, it will return false and do nothing.
|
// currently be. Otherwise, it will return false and do nothing.
|
||||||
func (core *SelectableCore) HandleSelection (
|
func (core *FocusableCore) HandleFocus (
|
||||||
direction tomo.SelectionDirection,
|
direction tomo.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
accepted bool,
|
accepted bool,
|
||||||
) {
|
) {
|
||||||
direction = direction.Canon()
|
direction = direction.Canon()
|
||||||
if !core.enabled { return false }
|
if !core.enabled { return false }
|
||||||
if core.selected && direction != tomo.SelectionDirectionNeutral {
|
if core.focused && direction != tomo.KeynavDirectionNeutral {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
core.selected = true
|
core.focused = true
|
||||||
if core.drawSelectionChange != nil { core.drawSelectionChange() }
|
if core.drawFocusChange != nil { core.drawFocusChange() }
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleDeselection causes this element to mark itself as deselected.
|
// HandleUnfocus causes this element to mark itself as unfocused.
|
||||||
func (core *SelectableCore) HandleDeselection () {
|
func (core *FocusableCore) HandleUnfocus () {
|
||||||
core.selected = false
|
core.focused = false
|
||||||
if core.drawSelectionChange != nil { core.drawSelectionChange() }
|
if core.drawFocusChange != nil { core.drawFocusChange() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnSelectionRequest sets a function to be called when this element
|
// OnFocusRequest sets a function to be called when this element
|
||||||
// wants its parent element to select it. Parent elements should return
|
// wants its parent element to focus it. Parent elements should return
|
||||||
// true if the request was granted, and false if it was not.
|
// true if the request was granted, and false if it was not.
|
||||||
func (core *SelectableCore) OnSelectionRequest (callback func () (granted bool)) {
|
func (core *FocusableCore) OnFocusRequest (callback func () (granted bool)) {
|
||||||
core.onSelectionRequest = callback
|
core.onFocusRequest = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnSelectionMotionRequest sets a function to be called when this
|
// OnFocusMotionRequest sets a function to be called when this
|
||||||
// element wants its parent element to select the element behind or in
|
// element wants its parent element to focus the element behind or in
|
||||||
// front of it, depending on the specified direction. Parent elements
|
// front of it, depending on the specified direction. Parent elements
|
||||||
// should return true if the request was granted, and false if it was
|
// should return true if the request was granted, and false if it was
|
||||||
// not.
|
// not.
|
||||||
func (core *SelectableCore) OnSelectionMotionRequest (
|
func (core *FocusableCore) OnFocusMotionRequest (
|
||||||
callback func (direction tomo.SelectionDirection) (granted bool),
|
callback func (direction tomo.KeynavDirection) (granted bool),
|
||||||
) {
|
) {
|
||||||
core.onSelectionMotionRequest = callback
|
core.onFocusMotionRequest = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enabled returns whether or not the element is enabled.
|
// Enabled returns whether or not the element is enabled.
|
||||||
func (core *SelectableCore) Enabled () (enabled bool) {
|
func (core *FocusableCore) Enabled () (enabled bool) {
|
||||||
return core.enabled
|
return core.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectableCoreControl is a struct that can be used to exert control over a
|
// FocusableCoreControl is a struct that can be used to exert control over a
|
||||||
// selectability core. It must not be directly embedded into an element, but
|
// focusability core. It must not be directly embedded into an element, but
|
||||||
// instead kept as a private member. When a SelectableCore struct is created, a
|
// instead kept as a private member. When a FocusableCore struct is created, a
|
||||||
// corresponding SelectableCoreControl struct is linked to it and returned
|
// corresponding FocusableCoreControl struct is linked to it and returned
|
||||||
// alongside it.
|
// alongside it.
|
||||||
type SelectableCoreControl struct {
|
type FocusableCoreControl struct {
|
||||||
core *SelectableCore
|
core *FocusableCore
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEnabled sets whether the selectability core is enabled. If the state
|
// SetEnabled sets whether the focusability core is enabled. If the state
|
||||||
// changes, this will call drawSelectionChange.
|
// changes, this will call drawFocusChange.
|
||||||
func (control SelectableCoreControl) SetEnabled (enabled bool) {
|
func (control FocusableCoreControl) SetEnabled (enabled bool) {
|
||||||
if control.core.enabled == enabled { return }
|
if control.core.enabled == enabled { return }
|
||||||
control.core.enabled = enabled
|
control.core.enabled = enabled
|
||||||
if !enabled { control.core.selected = false }
|
if !enabled { control.core.focused = false }
|
||||||
if control.core.drawSelectionChange != nil {
|
if control.core.drawFocusChange != nil {
|
||||||
control.core.drawSelectionChange()
|
control.core.drawFocusChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,3 +26,9 @@ var listEntryPattern = artist.NewMultiBordered (
|
|||||||
|
|
||||||
var onListEntryPattern = artist.NewMultiBordered (
|
var onListEntryPattern = artist.NewMultiBordered (
|
||||||
artist.Stroke { Pattern: artist.NewUniform(hex(0x6e8079FF)) })
|
artist.Stroke { Pattern: artist.NewUniform(hex(0x6e8079FF)) })
|
||||||
|
|
||||||
|
var selectedListEntryPattern = artist.NewMultiBordered (
|
||||||
|
artist.Stroke { Pattern: artist.NewUniform(hex(0x999C99FF)) })
|
||||||
|
|
||||||
|
var selectedOnListEntryPattern = artist.NewMultiBordered (
|
||||||
|
artist.Stroke { Pattern: artist.NewUniform(hex(0x6e8079FF)) })
|
||||||
|
@ -31,9 +31,9 @@ type PatternState struct {
|
|||||||
// question is capable of being toggled.
|
// question is capable of being toggled.
|
||||||
On bool
|
On bool
|
||||||
|
|
||||||
// Selected should be set to true if the element that is using this
|
// Focused should be set to true if the element that is using this
|
||||||
// pattern is currently selected.
|
// pattern is currently focused.
|
||||||
Selected bool
|
Focused bool
|
||||||
|
|
||||||
// Pressed should be set to true if the element that is using this
|
// Pressed should be set to true if the element that is using this
|
||||||
// pattern is being pressed down by the mouse. This is only necessary if
|
// pattern is being pressed down by the mouse. This is only necessary if
|
||||||
@ -123,7 +123,7 @@ func InputPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|||||||
if state.Disabled {
|
if state.Disabled {
|
||||||
return disabledInputPattern, Inset { 1, 1, 1, 1 }
|
return disabledInputPattern, Inset { 1, 1, 1, 1 }
|
||||||
} else {
|
} else {
|
||||||
if state.Selected {
|
if state.Focused {
|
||||||
return selectedInputPattern, Inset { 1, 1, 1, 1 }
|
return selectedInputPattern, Inset { 1, 1, 1, 1 }
|
||||||
} else {
|
} else {
|
||||||
return inputPattern, Inset { 1, 1, 1, 1 }
|
return inputPattern, Inset { 1, 1, 1, 1 }
|
||||||
@ -133,7 +133,7 @@ func InputPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|||||||
|
|
||||||
// ListPattern returns a background pattern for a list of things.
|
// ListPattern returns a background pattern for a list of things.
|
||||||
func ListPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
func ListPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
||||||
if state.Selected {
|
if state.Focused {
|
||||||
return selectedListPattern, Inset { 4, 4, 4, 4 }
|
return selectedListPattern, Inset { 4, 4, 4, 4 }
|
||||||
} else {
|
} else {
|
||||||
return listPattern, Inset { 4, 4, 4, 4 }
|
return listPattern, Inset { 4, 4, 4, 4 }
|
||||||
@ -142,10 +142,18 @@ func ListPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|||||||
|
|
||||||
// ItemPattern returns a background pattern for a list item.
|
// ItemPattern returns a background pattern for a list item.
|
||||||
func ItemPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
func ItemPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
||||||
if state.On {
|
if state.Focused {
|
||||||
return onListEntryPattern, Inset { 4, 4, 4, 4 }
|
if state.On {
|
||||||
|
return selectedOnListEntryPattern, Inset { 4, 4, 4, 4 }
|
||||||
|
} else {
|
||||||
|
return selectedListEntryPattern, Inset { 4, 4, 4, 4 }
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return listEntryPattern, Inset { 4, 4, 4, 4 }
|
if state.On {
|
||||||
|
return onListEntryPattern, Inset { 4, 4, 4, 4 }
|
||||||
|
} else {
|
||||||
|
return listEntryPattern, Inset { 4, 4, 4, 4 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,14 +163,14 @@ func ButtonPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|||||||
return disabledButtonPattern, Inset { 1, 1, 1, 1 }
|
return disabledButtonPattern, Inset { 1, 1, 1, 1 }
|
||||||
} else {
|
} else {
|
||||||
if state.Pressed {
|
if state.Pressed {
|
||||||
if state.Selected {
|
if state.Focused {
|
||||||
return pressedSelectedButtonPattern, Inset {
|
return pressedSelectedButtonPattern, Inset {
|
||||||
2, 0, 0, 2 }
|
2, 0, 0, 2 }
|
||||||
} else {
|
} else {
|
||||||
return pressedButtonPattern, Inset { 2, 0, 0, 2 }
|
return pressedButtonPattern, Inset { 2, 0, 0, 2 }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if state.Selected {
|
if state.Focused {
|
||||||
return selectedButtonPattern, Inset { 1, 1, 1, 1 }
|
return selectedButtonPattern, Inset { 1, 1, 1, 1 }
|
||||||
} else {
|
} else {
|
||||||
return buttonPattern, Inset { 1, 1, 1, 1 }
|
return buttonPattern, Inset { 1, 1, 1, 1 }
|
||||||
@ -187,7 +195,7 @@ func HandlePattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|||||||
if state.Disabled {
|
if state.Disabled {
|
||||||
return disabledScrollBarPattern, Inset { 1, 1, 1, 1 }
|
return disabledScrollBarPattern, Inset { 1, 1, 1, 1 }
|
||||||
} else {
|
} else {
|
||||||
if state.Selected {
|
if state.Focused {
|
||||||
if state.Pressed {
|
if state.Pressed {
|
||||||
return pressedSelectedScrollBarPattern, Inset { 1, 1, 1, 1 }
|
return pressedSelectedScrollBarPattern, Inset { 1, 1, 1, 1 }
|
||||||
} else {
|
} else {
|
||||||
@ -212,7 +220,7 @@ func SunkenPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
|||||||
// RaisedPattern returns a general purpose pattern that is raised up out of the
|
// RaisedPattern returns a general purpose pattern that is raised up out of the
|
||||||
// background.
|
// background.
|
||||||
func RaisedPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
func RaisedPattern (state PatternState) (pattern artist.Pattern, inset Inset) {
|
||||||
if state.Selected {
|
if state.Focused {
|
||||||
return selectedRaisedPattern, Inset { 1, 1, 1, 1 }
|
return selectedRaisedPattern, Inset { 1, 1, 1, 1 }
|
||||||
} else {
|
} else {
|
||||||
return raisedPattern, Inset { 1, 1, 1, 1 }
|
return raisedPattern, Inset { 1, 1, 1, 1 }
|
||||||
|
Reference in New Issue
Block a user