rui_orig/numberPicker.go

368 lines
11 KiB
Go
Raw Permalink Normal View History

2021-09-07 17:36:50 +03:00
package rui
import (
2022-05-03 12:12:57 +03:00
"math"
2021-09-07 17:36:50 +03:00
"strconv"
"strings"
)
const (
2024-04-23 19:34:36 +03:00
// NumberChangedEvent is the constant for the "" property tag.
// The "number-changed" property sets listener(s) that track the change in the entered value.
2021-09-07 17:36:50 +03:00
NumberChangedEvent = "number-changed"
2024-04-23 19:34:36 +03:00
// NumberPickerType is the constant for the "number-picker-type" property tag.
// The "number-picker-type" int property sets the mode of NumberPicker. It can take the following values:
// * NumberEditor (0) - NumberPicker is presented by editor. Default value;
// * NumberSlider (1) - NumberPicker is presented by slider. |
NumberPickerType = "number-picker-type"
// NumberPickerMin is the constant for the "number-picker-min" property tag.
// The "number-picker-min" int property sets the minimum value of NumberPicker. The default value is 0.
NumberPickerMin = "number-picker-min"
// NumberPickerMax is the constant for the "number-picker-max" property tag.
// The "number-picker-max" int property sets the maximum value of NumberPicker. The default value is 1.
NumberPickerMax = "number-picker-max"
// NumberPickerStep is the constant for the "number-picker-step" property tag.
// The "number-picker-step" int property sets the value change step of NumberPicker
NumberPickerStep = "number-picker-step"
// NumberPickerValue is the constant for the "number-picker-value" property tag.
// The "number-picker-value" int property sets the current value of NumberPicker. The default value is 0.
NumberPickerValue = "number-picker-value"
2021-09-07 17:36:50 +03:00
)
const (
// NumberEditor - type of NumberPicker. NumberPicker is presented by editor
NumberEditor = 0
2024-04-23 19:34:36 +03:00
2021-09-07 17:36:50 +03:00
// NumberSlider - type of NumberPicker. NumberPicker is presented by slider
NumberSlider = 1
)
// NumberPicker - NumberPicker view
type NumberPicker interface {
View
}
type numberPickerData struct {
viewData
2024-05-18 18:57:41 +03:00
dataList
2023-04-23 18:39:25 +03:00
numberChangedListeners []func(NumberPicker, float64, float64)
2021-09-07 17:36:50 +03:00
}
// NewNumberPicker create new NumberPicker object and return it
func NewNumberPicker(session Session, params Params) NumberPicker {
view := new(numberPickerData)
view.init(session)
2021-09-07 17:36:50 +03:00
setInitParams(view, params)
return view
}
func newNumberPicker(session Session) View {
return NewNumberPicker(session, nil)
}
func (picker *numberPickerData) init(session Session) {
picker.viewData.init(session)
2021-09-07 17:36:50 +03:00
picker.tag = "NumberPicker"
2024-04-23 18:24:51 +03:00
picker.hasHtmlDisabled = true
2023-04-23 18:39:25 +03:00
picker.numberChangedListeners = []func(NumberPicker, float64, float64){}
2024-05-18 18:57:41 +03:00
picker.dataListInit()
2021-09-07 17:36:50 +03:00
}
2022-05-22 12:54:02 +03:00
func (picker *numberPickerData) String() string {
return getViewString(picker, nil)
2022-05-22 12:54:02 +03:00
}
func (picker *numberPickerData) Focusable() bool {
return true
}
2021-09-07 17:36:50 +03:00
func (picker *numberPickerData) normalizeTag(tag string) string {
tag = strings.ToLower(tag)
switch tag {
case Type, Min, Max, Step, Value:
return "number-picker-" + tag
}
2024-05-18 18:57:41 +03:00
return picker.normalizeDataListTag(tag)
2021-09-07 17:36:50 +03:00
}
func (picker *numberPickerData) Remove(tag string) {
picker.remove(picker.normalizeTag(tag))
}
func (picker *numberPickerData) remove(tag string) {
switch tag {
case NumberChangedEvent:
if len(picker.numberChangedListeners) > 0 {
2023-04-23 18:39:25 +03:00
picker.numberChangedListeners = []func(NumberPicker, float64, float64){}
picker.propertyChangedEvent(tag)
}
case NumberPickerValue:
oldValue := GetNumberPickerValue(picker)
picker.viewData.remove(tag)
if oldValue != 0 {
if picker.created {
picker.session.callFunc("setInputValue", picker.htmlID(), 0)
}
for _, listener := range picker.numberChangedListeners {
listener(picker, 0, oldValue)
}
picker.propertyChangedEvent(tag)
2021-09-07 17:36:50 +03:00
}
2024-05-18 18:57:41 +03:00
case DataList:
if len(picker.dataList.dataList) > 0 {
picker.setDataList(picker, []string{}, true)
}
2021-09-07 17:36:50 +03:00
default:
picker.viewData.remove(tag)
picker.propertyChanged(tag)
}
}
2022-07-26 18:36:00 +03:00
func (picker *numberPickerData) Set(tag string, value any) bool {
2021-09-07 17:36:50 +03:00
return picker.set(picker.normalizeTag(tag), value)
}
2022-07-26 18:36:00 +03:00
func (picker *numberPickerData) set(tag string, value any) bool {
2021-09-07 17:36:50 +03:00
if value == nil {
picker.remove(tag)
return true
}
switch tag {
case NumberChangedEvent:
2023-04-23 18:39:25 +03:00
listeners, ok := valueToEventWithOldListeners[NumberPicker, float64](value)
2022-07-27 20:31:57 +03:00
if !ok {
notCompatibleType(tag, value)
return false
} else if listeners == nil {
2023-04-23 18:39:25 +03:00
listeners = []func(NumberPicker, float64, float64){}
2021-09-07 17:36:50 +03:00
}
2022-07-27 20:31:57 +03:00
picker.numberChangedListeners = listeners
picker.propertyChangedEvent(tag)
2021-09-07 17:36:50 +03:00
return true
case NumberPickerValue:
oldValue := GetNumberPickerValue(picker)
min, max := GetNumberPickerMinMax(picker)
2021-09-07 17:36:50 +03:00
if picker.setFloatProperty(NumberPickerValue, value, min, max) {
2022-08-18 18:18:36 +03:00
if f, ok := floatProperty(picker, NumberPickerValue, picker.Session(), min); ok && f != oldValue {
newValue, _ := floatTextProperty(picker, NumberPickerValue, picker.Session(), min)
if picker.created {
2022-11-02 20:10:19 +03:00
picker.session.callFunc("setInputValue", picker.htmlID(), newValue)
}
2021-09-07 17:36:50 +03:00
for _, listener := range picker.numberChangedListeners {
2023-04-23 18:39:25 +03:00
listener(picker, f, oldValue)
2021-09-07 17:36:50 +03:00
}
picker.propertyChangedEvent(tag)
2021-09-07 17:36:50 +03:00
}
return true
}
2024-05-18 18:57:41 +03:00
case DataList:
return picker.setDataList(picker, value, picker.created)
2021-09-07 17:36:50 +03:00
default:
if picker.viewData.set(tag, value) {
picker.propertyChanged(tag)
return true
}
}
return false
}
func (picker *numberPickerData) propertyChanged(tag string) {
if picker.created {
switch tag {
case NumberPickerType:
if GetNumberPickerType(picker) == NumberSlider {
2022-10-30 17:22:33 +03:00
picker.session.updateProperty(picker.htmlID(), "type", "range")
} else {
2022-10-30 17:22:33 +03:00
picker.session.updateProperty(picker.htmlID(), "type", "number")
}
2021-09-07 17:36:50 +03:00
case NumberPickerMin:
min, _ := GetNumberPickerMinMax(picker)
2022-10-30 17:22:33 +03:00
picker.session.updateProperty(picker.htmlID(), Min, strconv.FormatFloat(min, 'f', -1, 32))
2021-09-07 17:36:50 +03:00
case NumberPickerMax:
_, max := GetNumberPickerMinMax(picker)
2022-10-30 17:22:33 +03:00
picker.session.updateProperty(picker.htmlID(), Max, strconv.FormatFloat(max, 'f', -1, 32))
2021-09-07 17:36:50 +03:00
case NumberPickerStep:
if step := GetNumberPickerStep(picker); step > 0 {
2022-10-30 17:22:33 +03:00
picker.session.updateProperty(picker.htmlID(), Step, strconv.FormatFloat(step, 'f', -1, 32))
} else {
2022-10-30 17:22:33 +03:00
picker.session.updateProperty(picker.htmlID(), Step, "any")
}
2021-09-07 17:36:50 +03:00
}
}
}
2022-07-26 18:36:00 +03:00
func (picker *numberPickerData) Get(tag string) any {
2021-09-07 17:36:50 +03:00
return picker.get(picker.normalizeTag(tag))
}
2022-07-26 18:36:00 +03:00
func (picker *numberPickerData) get(tag string) any {
2021-09-07 17:36:50 +03:00
switch tag {
case NumberChangedEvent:
return picker.numberChangedListeners
2024-05-18 18:57:41 +03:00
case DataList:
return picker.dataList.dataList
2021-09-07 17:36:50 +03:00
default:
return picker.viewData.get(tag)
}
}
func (picker *numberPickerData) htmlTag() string {
return "input"
}
2024-05-18 18:57:41 +03:00
func (picker *numberPickerData) htmlSubviews(self View, buffer *strings.Builder) {
picker.dataListHtmlSubviews(self, buffer)
}
2021-09-07 17:36:50 +03:00
func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builder) {
picker.viewData.htmlProperties(self, buffer)
if GetNumberPickerType(picker) == NumberSlider {
2021-09-07 17:36:50 +03:00
buffer.WriteString(` type="range"`)
} else {
buffer.WriteString(` type="number"`)
}
min, max := GetNumberPickerMinMax(picker)
2022-05-03 12:12:57 +03:00
if min != math.Inf(-1) {
buffer.WriteString(` min="`)
buffer.WriteString(strconv.FormatFloat(min, 'f', -1, 64))
buffer.WriteByte('"')
}
2021-09-07 17:36:50 +03:00
2022-05-03 12:12:57 +03:00
if max != math.Inf(1) {
buffer.WriteString(` max="`)
buffer.WriteString(strconv.FormatFloat(max, 'f', -1, 64))
buffer.WriteByte('"')
}
2021-09-07 17:36:50 +03:00
step := GetNumberPickerStep(picker)
2021-09-07 17:36:50 +03:00
if step != 0 {
buffer.WriteString(` step="`)
buffer.WriteString(strconv.FormatFloat(step, 'f', -1, 64))
buffer.WriteByte('"')
} else {
buffer.WriteString(` step="any"`)
}
buffer.WriteString(` value="`)
buffer.WriteString(strconv.FormatFloat(GetNumberPickerValue(picker), 'f', -1, 64))
2021-09-07 17:36:50 +03:00
buffer.WriteByte('"')
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
2024-05-18 18:57:41 +03:00
2024-05-29 15:31:58 +03:00
picker.dataListHtmlProperties(picker, buffer)
2021-09-07 17:36:50 +03:00
}
func (picker *numberPickerData) handleCommand(self View, command string, data DataObject) bool {
switch command {
case "textChanged":
if text, ok := data.PropertyValue("text"); ok {
if value, err := strconv.ParseFloat(text, 32); err == nil {
oldValue := GetNumberPickerValue(picker)
2022-08-18 18:18:36 +03:00
picker.properties[NumberPickerValue] = text
2021-09-07 17:36:50 +03:00
if value != oldValue {
for _, listener := range picker.numberChangedListeners {
2023-04-23 18:39:25 +03:00
listener(picker, value, oldValue)
2021-09-07 17:36:50 +03:00
}
}
}
}
return true
}
return picker.viewData.handleCommand(self, command, data)
}
// GetNumberPickerType returns the type of NumberPicker subview. Valid values:
2021-11-04 21:13:34 +03:00
// NumberEditor (0) - NumberPicker is presented by editor (default type);
// NumberSlider (1) - NumberPicker is presented by slider.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetNumberPickerType(view View, subviewID ...string) int {
2022-07-28 12:41:50 +03:00
return enumStyledProperty(view, subviewID, NumberPickerType, NumberEditor, false)
2021-09-07 17:36:50 +03:00
}
// GetNumberPickerMinMax returns the min and max value of NumberPicker subview.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetNumberPickerMinMax(view View, subviewID ...string) (float64, float64) {
var pickerType int
if len(subviewID) > 0 && subviewID[0] != "" {
pickerType = GetNumberPickerType(view, subviewID[0])
} else {
pickerType = GetNumberPickerType(view)
}
2022-07-28 12:11:27 +03:00
var defMin, defMax float64
if pickerType == NumberSlider {
2022-07-28 12:11:27 +03:00
defMin = 0
defMax = 1
} else {
defMin = math.Inf(-1)
defMax = math.Inf(1)
2021-09-07 17:36:50 +03:00
}
2022-07-28 12:11:27 +03:00
min := floatStyledProperty(view, subviewID, NumberPickerMin, defMin)
max := floatStyledProperty(view, subviewID, NumberPickerMax, defMax)
2021-09-07 17:36:50 +03:00
2022-07-28 12:11:27 +03:00
if min > max {
return max, min
2021-09-07 17:36:50 +03:00
}
2022-07-28 12:11:27 +03:00
return min, max
2021-09-07 17:36:50 +03:00
}
// GetNumberPickerStep returns the value changing step of NumberPicker subview.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetNumberPickerStep(view View, subviewID ...string) float64 {
var max float64
if len(subviewID) > 0 && subviewID[0] != "" {
_, max = GetNumberPickerMinMax(view, subviewID[0])
} else {
_, max = GetNumberPickerMinMax(view)
}
2022-07-28 12:11:27 +03:00
result := floatStyledProperty(view, subviewID, NumberPickerStep, 0)
2021-09-07 17:36:50 +03:00
if result > max {
return max
}
return result
}
// GetNumberPickerValue returns the value of NumberPicker subview.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetNumberPickerValue(view View, subviewID ...string) float64 {
var min float64
if len(subviewID) > 0 && subviewID[0] != "" {
min, _ = GetNumberPickerMinMax(view, subviewID[0])
} else {
min, _ = GetNumberPickerMinMax(view)
}
2022-07-28 12:11:27 +03:00
result := floatStyledProperty(view, subviewID, NumberPickerValue, min)
2021-09-07 17:36:50 +03:00
return result
}
// GetNumberChangedListeners returns the NumberChangedListener list of an NumberPicker subview.
// If there are no listeners then the empty list is returned
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
2023-04-23 18:39:25 +03:00
func GetNumberChangedListeners(view View, subviewID ...string) []func(NumberPicker, float64, float64) {
return getEventWithOldListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent)
2021-09-07 17:36:50 +03:00
}