Refined the combo box a bit
This commit is contained in:
parent
cc14151a14
commit
1c0dee1b95
@ -8,6 +8,7 @@ import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
|||||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
|
||||||
|
|
||||||
|
// Option specifies a ComboBox option. A blank option will display as "(None)".
|
||||||
type Option string
|
type Option string
|
||||||
|
|
||||||
func (option Option) Title () string {
|
func (option Option) Title () string {
|
||||||
@ -18,7 +19,7 @@ func (option Option) Title () string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Button is a clickable button.
|
// ComboBox is an input that can be one of several predetermined values.
|
||||||
type ComboBox struct {
|
type ComboBox struct {
|
||||||
entity tomo.FocusableEntity
|
entity tomo.FocusableEntity
|
||||||
drawer textdraw.Drawer
|
drawer textdraw.Drawer
|
||||||
@ -35,7 +36,7 @@ type ComboBox struct {
|
|||||||
onChange func ()
|
onChange func ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewButton creates a new button with the specified label text.
|
// NewComboBox creates a new ComboBox with the specifed options.
|
||||||
func NewComboBox (options ...Option) (element *ComboBox) {
|
func NewComboBox (options ...Option) (element *ComboBox) {
|
||||||
if len(options) == 0 { options = []Option { "" } }
|
if len(options) == 0 { options = []Option { "" } }
|
||||||
element = &ComboBox { enabled: true, options: options }
|
element = &ComboBox { enabled: true, options: options }
|
||||||
@ -98,15 +99,17 @@ func (element *ComboBox) Draw (destination canvas.Canvas) {
|
|||||||
element.drawer.Draw(destination, foreground, offset)
|
element.drawer.Draw(destination, foreground, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnClick sets the function to be called when the button is clicked.
|
// OnChange sets the function to be called when this element's value is changed.
|
||||||
func (element *ComboBox) OnChange (callback func ()) {
|
func (element *ComboBox) OnChange (callback func ()) {
|
||||||
element.onChange = callback
|
element.onChange = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Value returns this element's value.
|
||||||
func (element *ComboBox) Value () Option {
|
func (element *ComboBox) Value () Option {
|
||||||
return element.selected
|
return element.selected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select sets this element's value.
|
||||||
func (element *ComboBox) Select (option Option) {
|
func (element *ComboBox) Select (option Option) {
|
||||||
element.selected = option
|
element.selected = option
|
||||||
element.drawer.SetText([]rune(option.Title()))
|
element.drawer.SetText([]rune(option.Title()))
|
||||||
@ -117,6 +120,7 @@ func (element *ComboBox) Select (option Option) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filled returns whether this element has a value other than (None).
|
||||||
func (element *ComboBox) Filled () bool {
|
func (element *ComboBox) Filled () bool {
|
||||||
return element.selected != ""
|
return element.selected != ""
|
||||||
}
|
}
|
||||||
@ -126,12 +130,12 @@ func (element *ComboBox) Focus () {
|
|||||||
if !element.entity.Focused() { element.entity.Focus() }
|
if !element.entity.Focused() { element.entity.Focus() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enabled returns whether this button is enabled or not.
|
// Enabled returns whether this element is enabled or not.
|
||||||
func (element *ComboBox) Enabled () bool {
|
func (element *ComboBox) Enabled () bool {
|
||||||
return element.enabled
|
return element.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEnabled sets whether this button can be clicked or not.
|
// SetEnabled sets whether this element is enabled or not.
|
||||||
func (element *ComboBox) SetEnabled (enabled bool) {
|
func (element *ComboBox) SetEnabled (enabled bool) {
|
||||||
if element.enabled == enabled { return }
|
if element.enabled == enabled { return }
|
||||||
element.enabled = enabled
|
element.enabled = enabled
|
||||||
@ -180,6 +184,7 @@ func (element *ComboBox) HandleMouseUp (
|
|||||||
|
|
||||||
func (element *ComboBox) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
func (element *ComboBox) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
|
// TODO: use arrow keys to cycle options
|
||||||
if key == input.KeyEnter {
|
if key == input.KeyEnter {
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
element.entity.Invalidate()
|
element.entity.Invalidate()
|
||||||
@ -200,18 +205,25 @@ func (element *ComboBox) dropDown () {
|
|||||||
menu, err := window.NewMenu(element.entity.Bounds())
|
menu, err := window.NewMenu(element.entity.Bounds())
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
|
|
||||||
|
cellToOption := make(map[tomo.Selectable] Option)
|
||||||
|
|
||||||
list := NewList()
|
list := NewList()
|
||||||
for _, option := range element.options {
|
for _, option := range element.options {
|
||||||
option := option
|
option := option
|
||||||
cell := NewCell(NewLabel(option.Title()))
|
cell := NewCell(NewLabel(option.Title()))
|
||||||
cell.OnSelectionChange(func () {
|
cellToOption[cell] = option
|
||||||
if cell.Selected() {
|
|
||||||
element.Select(option)
|
|
||||||
menu.Close()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
list.Adopt(cell)
|
list.Adopt(cell)
|
||||||
|
|
||||||
|
if option == element.selected {
|
||||||
|
list.Select(cell)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
list.OnClick(func () {
|
||||||
|
selected := list.Selected()
|
||||||
|
if selected == nil { return }
|
||||||
|
element.Select(cellToOption[selected])
|
||||||
|
menu.Close()
|
||||||
|
})
|
||||||
|
|
||||||
menu.Adopt(list)
|
menu.Adopt(list)
|
||||||
list.Focus()
|
list.Focus()
|
||||||
|
@ -27,6 +27,7 @@ type List struct {
|
|||||||
|
|
||||||
theme theme.Wrapped
|
theme theme.Wrapped
|
||||||
|
|
||||||
|
onClick func ()
|
||||||
onScrollBoundsChange func ()
|
onScrollBoundsChange func ()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +93,22 @@ func (element *List) Layout () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (element *List) Selected () tomo.Selectable {
|
||||||
|
if element.selected == -1 { return nil }
|
||||||
|
child, ok := element.entity.Child(element.selected).(tomo.Selectable)
|
||||||
|
if !ok { return nil }
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
|
||||||
|
func (element *List) Select (child tomo.Selectable) {
|
||||||
|
index := element.entity.IndexOf(child)
|
||||||
|
if element.selected == index { return }
|
||||||
|
element.selectNone()
|
||||||
|
element.selected = index
|
||||||
|
element.entity.SelectChild(index, true)
|
||||||
|
element.scrollToSelected()
|
||||||
|
}
|
||||||
|
|
||||||
func (element *List) Enabled () bool {
|
func (element *List) Enabled () bool {
|
||||||
return element.enabled
|
return element.enabled
|
||||||
}
|
}
|
||||||
@ -135,12 +152,7 @@ func (element *List) HandleChildMouseDown (
|
|||||||
if !element.enabled { return }
|
if !element.enabled { return }
|
||||||
element.Focus()
|
element.Focus()
|
||||||
if child, ok := child.(tomo.Selectable); ok {
|
if child, ok := child.(tomo.Selectable); ok {
|
||||||
index := element.entity.IndexOf(child)
|
element.Select(child)
|
||||||
if element.selected == index { return }
|
|
||||||
element.selectNone()
|
|
||||||
element.selected = index
|
|
||||||
element.entity.SelectChild(index, true)
|
|
||||||
element.scrollToSelected()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +161,12 @@ func (element *List) HandleChildMouseUp (
|
|||||||
button input.Button,
|
button input.Button,
|
||||||
modifiers input.Modifiers,
|
modifiers input.Modifiers,
|
||||||
child tomo.Element,
|
child tomo.Element,
|
||||||
) { }
|
) {
|
||||||
|
if !position.In(child.Entity().Bounds()) { return }
|
||||||
|
if element.onClick != nil {
|
||||||
|
element.onClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (element *List) HandleChildFlexibleHeightChange (child tomo.Flexible) {
|
func (element *List) HandleChildFlexibleHeightChange (child tomo.Flexible) {
|
||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
@ -165,6 +182,10 @@ func (element *List) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
|||||||
index = element.selected - 1
|
index = element.selected - 1
|
||||||
case input.KeyDown, input.KeyRight:
|
case input.KeyDown, input.KeyRight:
|
||||||
index = element.selected + 1
|
index = element.selected + 1
|
||||||
|
case input.KeyEnter:
|
||||||
|
if element.onClick != nil {
|
||||||
|
element.onClick()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if index >= 0 && index < element.entity.CountChildren() {
|
if index >= 0 && index < element.entity.CountChildren() {
|
||||||
element.selectNone()
|
element.selectNone()
|
||||||
@ -245,6 +266,10 @@ func (element *List) OnScrollBoundsChange (callback func ()) {
|
|||||||
element.onScrollBoundsChange = callback
|
element.onScrollBoundsChange = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (element *List) OnClick (callback func ()) {
|
||||||
|
element.onClick = callback
|
||||||
|
}
|
||||||
|
|
||||||
// ScrollAxes returns the supported axes for scrolling.
|
// ScrollAxes returns the supported axes for scrolling.
|
||||||
func (element *List) ScrollAxes () (horizontal, vertical bool) {
|
func (element *List) ScrollAxes () (horizontal, vertical bool) {
|
||||||
return false, true
|
return false, true
|
||||||
|
Reference in New Issue
Block a user