diff --git a/numberinput.go b/numberinput.go new file mode 100644 index 0000000..d7e3dcc --- /dev/null +++ b/numberinput.go @@ -0,0 +1,100 @@ +package objects + +import "math" +import "strconv" +import "git.tebibyte.media/tomo/tomo" +import "git.tebibyte.media/tomo/tomo/theme" +import "git.tebibyte.media/tomo/tomo/input" +import "git.tebibyte.media/tomo/tomo/event" +import "git.tebibyte.media/tomo/objects/layouts" + +// NumberInput is an editable text box which accepts only numbers, and has +// controls to increment and decrement its value. +type NumberInput struct { + tomo.ContainerBox + input *TextInput + increment *Button + decrement *Button + on struct { + enter event.FuncBroadcaster + edit event.FuncBroadcaster + } +} + +// NewNumberInput creates a new number input with the specified value. +func NewNumberInput (value float64) *NumberInput { + box := &NumberInput { + ContainerBox: tomo.NewContainerBox(), + input: NewTextInput(""), + increment: NewButton(""), + decrement: NewButton(""), + } + theme.Apply(box, theme.R("objects", "NumberInput", "")) + box.Add(box.input) + box.Add(box.increment) + box.Add(box.decrement) + box.SetLayout(layouts.NewGrid([]bool { true, false, false }, []bool { true })) + box.increment.SetIcon(theme.IconActionIncrement) + box.decrement.SetIcon(theme.IconActionDecrement) + + box.SetValue(value) + + box.CaptureScroll(true) + box.CaptureKeyboard(true) + + box.OnScroll(box.handleScroll) + box.OnKeyDown(box.handleKeyDown) + box.input.OnEnter(box.handleEnter) + box.input.OnEdit(box.on.edit.Broadcast) + box.increment.OnClick(func () { box.shift(1) }) + box.decrement.OnClick(func () { box.shift(-1) }) + return box +} + +// SetValue sets the value of the input. +func (this *NumberInput) SetValue (value float64) { + this.input.SetText(strconv.FormatFloat(value, 'g', -1, 64)) +} + +// Value returns the value of the input. +func (this *NumberInput) Value () float64 { + value, _ := strconv.ParseFloat(this.input.Text(), 64) + return value +} + +// OnEnter specifies a function to be called when the user presses enter within +// the text input. +func (this *NumberInput) OnEnter (callback func ()) event.Cookie { + return this.on.enter.Connect(callback) +} + +// OnEdit specifies a function to be called when the user edits the input value. +func (this *NumberInput) OnEdit (callback func ()) event.Cookie { + return this.on.edit.Connect(callback) +} + +func (this *NumberInput) shift (by int) { + this.SetValue(this.Value() + float64(by)) + this.on.edit.Broadcast() +} + +func (this *NumberInput) handleKeyDown (key input.Key, numpad bool) { + switch key { + case input.KeyUp: this.shift(1) + case input.KeyDown: this.shift(-1) + default: this.input.handleKeyDown(key, numpad) + } +} + +func (this *NumberInput) handleScroll (x, y float64) { + if x == 0 { + this.shift(-int(math.Round(y))) + } else { + this.input.handleScroll(x, y) + } +} + +func (this *NumberInput) handleEnter () { + this.SetValue(this.Value()) + this.on.enter.Broadcast() +}