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 { enter event.FuncBroadcaster valueChange 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.SetLayout(layouts.Row { true, false, false }) box.increment.SetIcon(tomo.IconValueIncrement) box.decrement.SetIcon(tomo.IconValueDecrement) box.SetValue(value) box.CaptureScroll(true) box.CaptureKeyboard(true) box.OnScroll(box.handleScroll) box.OnKeyDown(box.handleKeyDown) box.input.OnEnter(box.handleEnter) 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) } // 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) } 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) { 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() }