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/textdraw"
|
||||
|
||||
// Option specifies a ComboBox option. A blank option will display as "(None)".
|
||||
type Option 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 {
|
||||
entity tomo.FocusableEntity
|
||||
drawer textdraw.Drawer
|
||||
@ -35,7 +36,7 @@ type ComboBox struct {
|
||||
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) {
|
||||
if len(options) == 0 { options = []Option { "" } }
|
||||
element = &ComboBox { enabled: true, options: options }
|
||||
@ -98,15 +99,17 @@ func (element *ComboBox) Draw (destination canvas.Canvas) {
|
||||
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 ()) {
|
||||
element.onChange = callback
|
||||
}
|
||||
|
||||
// Value returns this element's value.
|
||||
func (element *ComboBox) Value () Option {
|
||||
return element.selected
|
||||
}
|
||||
|
||||
// Select sets this element's value.
|
||||
func (element *ComboBox) Select (option Option) {
|
||||
element.selected = option
|
||||
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 {
|
||||
return element.selected != ""
|
||||
}
|
||||
@ -126,12 +130,12 @@ func (element *ComboBox) 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 {
|
||||
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) {
|
||||
if element.enabled == enabled { return }
|
||||
element.enabled = enabled
|
||||
@ -180,6 +184,7 @@ func (element *ComboBox) HandleMouseUp (
|
||||
|
||||
func (element *ComboBox) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||
if !element.Enabled() { return }
|
||||
// TODO: use arrow keys to cycle options
|
||||
if key == input.KeyEnter {
|
||||
element.pressed = true
|
||||
element.entity.Invalidate()
|
||||
@ -200,18 +205,25 @@ func (element *ComboBox) dropDown () {
|
||||
menu, err := window.NewMenu(element.entity.Bounds())
|
||||
if err != nil { return }
|
||||
|
||||
cellToOption := make(map[tomo.Selectable] Option)
|
||||
|
||||
list := NewList()
|
||||
for _, option := range element.options {
|
||||
option := option
|
||||
cell := NewCell(NewLabel(option.Title()))
|
||||
cell.OnSelectionChange(func () {
|
||||
if cell.Selected() {
|
||||
element.Select(option)
|
||||
menu.Close()
|
||||
}
|
||||
})
|
||||
cellToOption[cell] = option
|
||||
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)
|
||||
list.Focus()
|
||||
|
@ -26,7 +26,8 @@ type List struct {
|
||||
forcedMinimumHeight int
|
||||
|
||||
theme theme.Wrapped
|
||||
|
||||
|
||||
onClick 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 {
|
||||
return element.enabled
|
||||
}
|
||||
@ -135,12 +152,7 @@ func (element *List) HandleChildMouseDown (
|
||||
if !element.enabled { return }
|
||||
element.Focus()
|
||||
if child, ok := child.(tomo.Selectable); ok {
|
||||
index := element.entity.IndexOf(child)
|
||||
if element.selected == index { return }
|
||||
element.selectNone()
|
||||
element.selected = index
|
||||
element.entity.SelectChild(index, true)
|
||||
element.scrollToSelected()
|
||||
element.Select(child)
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,7 +161,12 @@ func (element *List) HandleChildMouseUp (
|
||||
button input.Button,
|
||||
modifiers input.Modifiers,
|
||||
child tomo.Element,
|
||||
) { }
|
||||
) {
|
||||
if !position.In(child.Entity().Bounds()) { return }
|
||||
if element.onClick != nil {
|
||||
element.onClick()
|
||||
}
|
||||
}
|
||||
|
||||
func (element *List) HandleChildFlexibleHeightChange (child tomo.Flexible) {
|
||||
element.updateMinimumSize()
|
||||
@ -165,6 +182,10 @@ func (element *List) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||
index = element.selected - 1
|
||||
case input.KeyDown, input.KeyRight:
|
||||
index = element.selected + 1
|
||||
case input.KeyEnter:
|
||||
if element.onClick != nil {
|
||||
element.onClick()
|
||||
}
|
||||
}
|
||||
if index >= 0 && index < element.entity.CountChildren() {
|
||||
element.selectNone()
|
||||
@ -245,6 +266,10 @@ func (element *List) OnScrollBoundsChange (callback func ()) {
|
||||
element.onScrollBoundsChange = callback
|
||||
}
|
||||
|
||||
func (element *List) OnClick (callback func ()) {
|
||||
element.onClick = callback
|
||||
}
|
||||
|
||||
// ScrollAxes returns the supported axes for scrolling.
|
||||
func (element *List) ScrollAxes () (horizontal, vertical bool) {
|
||||
return false, true
|
||||
|
Reference in New Issue
Block a user