package objects import "math" import "strconv" import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/tomo/text" import "git.tebibyte.media/tomo/tomo/input" import "git.tebibyte.media/tomo/tomo/event" import "git.tebibyte.media/tomo/objects/layouts" var _ tomo.Object = new(NumberInput) // NumberInput is an editable text box which accepts only numbers, and has // controls to increment and decrement its value. type NumberInput struct { box 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 { numberInput := &NumberInput { box: tomo.NewContainerBox(), input: NewTextInput(""), increment: NewButton(""), decrement: NewButton(""), } numberInput.box.SetRole(tomo.R("objects", "NumberInput")) numberInput.box.Add(numberInput.input) numberInput.box.Add(numberInput.decrement) numberInput.box.Add(numberInput.increment) numberInput.box.SetAttr(tomo.ALayout(layouts.Row { true, false, false })) numberInput.increment.SetIcon(tomo.IconValueIncrement) numberInput.decrement.SetIcon(tomo.IconValueDecrement) numberInput.SetValue(value) numberInput.box.OnScroll(numberInput.handleScroll) numberInput.box.OnKeyDown(numberInput.handleKeyDown) numberInput.box.OnKeyUp(numberInput.handleKeyUp) numberInput.input.OnConfirm(numberInput.handleConfirm) numberInput.input.OnValueChange(numberInput.on.valueChange.Broadcast) numberInput.increment.OnClick(func () { numberInput.shift( 1) }) numberInput.decrement.OnClick(func () { numberInput.shift(-1) }) return numberInput } // GetBox returns the underlying box. func (this *NumberInput) GetBox () tomo.Box { return this.box } // SetFocused sets whether or not this number input has keyboard focus. If set // to true, this method will steal focus away from whichever object currently // has focus. func (this *NumberInput) SetFocused (focused bool) { this.input.SetFocused(focused) } // Select sets the text cursor or selection. func (this *NumberInput) Select (dot text.Dot) { this.input.Select(dot) } // Dot returns the text cursor or selection. func (this *NumberInput) Dot () text.Dot { return this.input.Dot() } // Value returns the value of the input. func (this *NumberInput) Value () float64 { value, _ := strconv.ParseFloat(this.input.Value(), 64) return value } // SetValue sets the value of the input. func (this *NumberInput) SetValue (value float64) { this.input.SetValue(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() }