package objects import "math" import "strconv" import "git.tebibyte.media/tomo/tomo" 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 { valueChange event.FuncBroadcaster confirm 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(""), } box.SetRole(tomo.R("objects", "NumberInput")) box.Add(box.input) box.Add(box.decrement) box.Add(box.increment) box.SetAttr(tomo.ALayout(layouts.Row { true, false, false })) box.increment.SetIcon(tomo.IconValueIncrement) box.decrement.SetIcon(tomo.IconValueDecrement) box.SetValue(value) box.OnScroll(box.handleScroll) box.OnKeyDown(box.handleKeyDown) box.OnKeyUp(box.handleKeyUp) box.input.OnConfirm(box.handleConfirm) box.input.OnValueChange(box.on.valueChange.Broadcast) box.increment.OnClick(func () { box.shift(1) }) box.decrement.OnClick(func () { box.shift(-1) }) return box } // Value returns the value of the input. func (this *NumberInput) Value () float64 { value, _ := strconv.ParseFloat(this.input.Text(), 64) return value } // SetValue sets the value of the input. func (this *NumberInput) SetValue (value float64) { this.input.SetText(strconv.FormatFloat(value, 'g', -1, 64)) } // OnValueChange specifies a function to be called when the user edits the input // value. func (this *NumberInput) OnValueChange (callback func ()) event.Cookie { return this.on.valueChange.Connect(callback) } // OnConfirm specifies a function to be called when the user presses enter within // the number input. func (this *NumberInput) OnConfirm (callback func ()) event.Cookie { return this.on.confirm.Connect(callback) } func (this *NumberInput) shift (by int) { this.SetValue(this.Value() + float64(by)) this.on.valueChange.Broadcast() } func (this *NumberInput) handleKeyDown (key input.Key, numpad bool) bool { switch key { case input.KeyUp: this.shift(1) return true case input.KeyDown: this.shift(-1) return true } return false } func (this *NumberInput) handleKeyUp (key input.Key, numpad bool) bool { switch key { case input.KeyUp: return true case input.KeyDown: return true } return false } func (this *NumberInput) handleScroll (x, y float64) bool { if x == 0 { this.shift(-int(math.Round(y))) return true } return false } func (this *NumberInput) handleConfirm () { this.SetValue(this.Value()) this.on.confirm.Broadcast() }