diff --git a/CHANGELOG.md b/CHANGELOG.md index 0712373..6a4b01c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # v0.18.0 + +* OriginX, OriginY, and OriginZ properties renamed to TransformOriginX, TransformOriginY, and TransformOriginZ +* GetOrigin function renamed to GetTransformOrigin * Added LineJoin type. Type of constants MiterJoin, RoundJoin, and BevelJoin changed to LineJoin. Type of Canvas.SetLineJoin function argument changed to LineJoin. * Added LineCap type. Type of constants ButtCap, RoundCap, and SquareCap changed to LineCap. Type of Canvas.SetLineCap function argument changed to LineCap. diff --git a/animationEvents.go b/animationEvents.go index 0d5bb7c..f666de6 100644 --- a/animationEvents.go +++ b/animationEvents.go @@ -157,7 +157,7 @@ const ( /* func setTransitionListener(properties Properties, tag PropertyName, value any) bool { - if listeners, ok := valueToEventListeners[View, string](value); ok { + if listeners, ok := valueToOneArgEventListeners[View, string](value); ok { if len(listeners) == 0 { properties.setRaw(tag, nil) } else { @@ -206,7 +206,7 @@ func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject) } } - for _, listener := range getEventListeners[View, PropertyName](view, nil, tag) { + for _, listener := range getOneArgEventListeners[View, PropertyName](view, nil, tag) { listener(view, property) } } @@ -214,7 +214,7 @@ func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject) /* func setAnimationListener(properties Properties, tag PropertyName, value any) bool { - if listeners, ok := valueToEventListeners[View, string](value); ok { + if listeners, ok := valueToOneArgEventListeners[View, string](value); ok { if len(listeners) == 0 { properties.setRaw(tag, nil) } else { @@ -252,7 +252,7 @@ func animationEventsHtml(view View, buffer *strings.Builder) { */ func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) { - if listeners := getEventListeners[View, string](view, nil, tag); len(listeners) > 0 { + if listeners := getOneArgEventListeners[View, string](view, nil, tag); len(listeners) > 0 { id := "" if name, ok := data.PropertyValue("name"); ok { for _, animation := range GetAnimation(view) { @@ -271,54 +271,54 @@ func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) { // 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. func GetTransitionRunListeners(view View, subviewID ...string) []func(View, string) { - return getEventListeners[View, string](view, subviewID, TransitionRunEvent) + return getOneArgEventListeners[View, string](view, subviewID, TransitionRunEvent) } // GetTransitionStartListeners returns the "transition-start-event" listener list. // 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. func GetTransitionStartListeners(view View, subviewID ...string) []func(View, string) { - return getEventListeners[View, string](view, subviewID, TransitionStartEvent) + return getOneArgEventListeners[View, string](view, subviewID, TransitionStartEvent) } // GetTransitionEndListeners returns the "transition-end-event" listener list. // 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. func GetTransitionEndListeners(view View, subviewID ...string) []func(View, string) { - return getEventListeners[View, string](view, subviewID, TransitionEndEvent) + return getOneArgEventListeners[View, string](view, subviewID, TransitionEndEvent) } // GetTransitionCancelListeners returns the "transition-cancel-event" listener list. // 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. func GetTransitionCancelListeners(view View, subviewID ...string) []func(View, string) { - return getEventListeners[View, string](view, subviewID, TransitionCancelEvent) + return getOneArgEventListeners[View, string](view, subviewID, TransitionCancelEvent) } // GetAnimationStartListeners returns the "animation-start-event" listener list. // 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. func GetAnimationStartListeners(view View, subviewID ...string) []func(View, string) { - return getEventListeners[View, string](view, subviewID, AnimationStartEvent) + return getOneArgEventListeners[View, string](view, subviewID, AnimationStartEvent) } // GetAnimationEndListeners returns the "animation-end-event" listener list. // 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. func GetAnimationEndListeners(view View, subviewID ...string) []func(View, string) { - return getEventListeners[View, string](view, subviewID, AnimationEndEvent) + return getOneArgEventListeners[View, string](view, subviewID, AnimationEndEvent) } // GetAnimationCancelListeners returns the "animation-cancel-event" listener list. // 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. func GetAnimationCancelListeners(view View, subviewID ...string) []func(View, string) { - return getEventListeners[View, string](view, subviewID, AnimationCancelEvent) + return getOneArgEventListeners[View, string](view, subviewID, AnimationCancelEvent) } // GetAnimationIterationListeners returns the "animation-iteration-event" listener list. // 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. func GetAnimationIterationListeners(view View, subviewID ...string) []func(View, string) { - return getEventListeners[View, string](view, subviewID, AnimationIterationEvent) + return getOneArgEventListeners[View, string](view, subviewID, AnimationIterationEvent) } diff --git a/app_scripts.js b/app_scripts.js index 872c3a4..8c40e74 100644 --- a/app_scripts.js +++ b/app_scripts.js @@ -623,21 +623,10 @@ function listItemClickEvent(element, event) { return } - let selected = false; - if (element.classList) { - const focusStyle = getListFocusedItemStyle(element); - const blurStyle = getListSelectedItemStyle(element); - selected = (element.classList.contains(focusStyle) || element.classList.contains(blurStyle)); - } - const list = element.parentNode.parentNode if (list) { - if (!selected) { - selectListItem(list, element, true) - } - - const message = "itemClick{session=" + sessionID + ",id=" + list.id + "}" - sendMessage(message); + const number = getListItemNumber(element.id) + sendMessage("itemClick{session=" + sessionID + ",id=" + list.id + ",number=" + number + "}"); } } @@ -664,7 +653,7 @@ function getListSelectedItemStyle(element) { return getStyleAttribute(element, "data-bluritemstyle", "ruiListItemSelected"); } -function selectListItem(element, item, needSendMessage) { +function selectListItem(element, item) { const currentId = element.getAttribute("data-current"); let message; const focusStyle = getListFocusedItemStyle(element); @@ -676,9 +665,7 @@ function selectListItem(element, item, needSendMessage) { if (current.classList) { current.classList.remove(focusStyle, blurStyle); } - if (sendMessage) { - message = "itemUnselected{session=" + sessionID + ",id=" + element.id + "}"; - } + message = "itemUnselected{session=" + sessionID + ",id=" + element.id + "}"; } } @@ -693,42 +680,21 @@ function selectListItem(element, item, needSendMessage) { } } - element.setAttribute("data-current", item.id); - if (sendMessage) { - const number = getListItemNumber(item.id) - if (number != undefined) { - message = "itemSelected{session=" + sessionID + ",id=" + element.id + ",number=" + number + "}"; - } + element.setAttribute("data-current", item.id); + const number = getListItemNumber(item.id) + if (number != undefined) { + message = "itemSelected{session=" + sessionID + ",id=" + element.id + ",number=" + number + "}"; } + if (item.scrollIntoViewIfNeeded) { item.scrollIntoViewIfNeeded() } else { item.scrollIntoView({block: "nearest", inline: "nearest"}); } - /* - let left = item.offsetLeft - element.offsetLeft; - if (left < element.scrollLeft) { - element.scrollLeft = left; - } - - let top = item.offsetTop - element.offsetTop; - if (top < element.scrollTop) { - element.scrollTop = top; - } - - let right = left + item.offsetWidth; - if (right > element.scrollLeft + element.clientWidth) { - element.scrollLeft = right - element.clientWidth; - } - - let bottom = top + item.offsetHeight - if (bottom > element.scrollTop + element.clientHeight) { - element.scrollTop = bottom - element.clientHeight; - }*/ } - if (needSendMessage && message != undefined) { + if (message != undefined) { sendMessage(message); } scanElementsSize(); @@ -857,7 +823,7 @@ function listViewKeyDownEvent(element, event) { switch (key) { case " ": case "Enter": - const message = "itemClick{session=" + sessionID + ",id=" + element.id + "}"; + const message = "itemClick{session=" + sessionID + ",id=" + element.id + ",number=" + getListItemNumber(currentId) + "}"; sendMessage(message); break; @@ -897,7 +863,7 @@ function listViewKeyDownEvent(element, event) { return; } if (item && item !== current) { - selectListItem(element, item, true); + selectListItem(element, item); } } else { switch (key) { @@ -916,7 +882,7 @@ function listViewKeyDownEvent(element, event) { if (item.getAttribute("data-disabled") == "1") { continue; } - selectListItem(element, item, true); + selectListItem(element, item); return; } break; diff --git a/canvasView.go b/canvasView.go index b9adab2..daa2f5d 100644 --- a/canvasView.go +++ b/canvasView.go @@ -37,8 +37,8 @@ func (canvasView *canvasViewData) init(session Session) { canvasView.viewData.init(session) canvasView.tag = "CanvasView" canvasView.normalize = normalizeCanvasViewTag - canvasView.set = canvasViewSet - canvasView.remove = canvasViewRemove + canvasView.set = canvasView.setFunc + canvasView.remove = canvasView.removeFunc } @@ -51,36 +51,32 @@ func normalizeCanvasViewTag(tag PropertyName) PropertyName { return tag } -func canvasViewRemove(view View, tag PropertyName) []PropertyName { +func (canvasView *canvasViewData) removeFunc(tag PropertyName) []PropertyName { if tag == DrawFunction { - if view.getRaw(DrawFunction) != nil { - view.setRaw(DrawFunction, nil) - if canvasView, ok := view.(CanvasView); ok { - canvasView.Redraw() - } + if canvasView.getRaw(DrawFunction) != nil { + canvasView.setRaw(DrawFunction, nil) + canvasView.Redraw() return []PropertyName{DrawFunction} } return []PropertyName{} } - return viewRemove(view, tag) + return canvasView.viewData.removeFunc(tag) } -func canvasViewSet(view View, tag PropertyName, value any) []PropertyName { +func (canvasView *canvasViewData) setFunc(tag PropertyName, value any) []PropertyName { if tag == DrawFunction { if fn, ok := value.(func(Canvas)); ok { - view.setRaw(DrawFunction, fn) + canvasView.setRaw(DrawFunction, fn) } else { notCompatibleType(tag, value) return nil } - if canvasView, ok := view.(CanvasView); ok { - canvasView.Redraw() - } + canvasView.Redraw() return []PropertyName{DrawFunction} } - return viewSet(view, tag, value) + return canvasView.viewData.setFunc(tag, value) } func (canvasView *canvasViewData) htmlTag() string { diff --git a/checkbox.go b/checkbox.go index 85d4372..cdce746 100644 --- a/checkbox.go +++ b/checkbox.go @@ -49,117 +49,98 @@ func (button *checkboxData) init(session Session) { button.systemClass = "ruiGridLayout ruiCheckbox" button.set = button.setFunc button.remove = button.removeFunc - button.changed = checkboxPropertyChanged + button.changed = button.propertyChanged - button.setRaw(ClickEvent, checkboxClickListener) - button.setRaw(KeyDownEvent, checkboxKeyListener) + button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener}) + button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener}) } func (button *checkboxData) Focusable() bool { return true } -func checkboxPropertyChanged(view View, tag PropertyName) { +func (button *checkboxData) propertyChanged(tag PropertyName) { switch tag { case Checked: - session := view.Session() - checked := IsCheckboxChecked(view) - if listeners := GetCheckboxChangedListeners(view); len(listeners) > 0 { - if checkbox, ok := view.(Checkbox); ok { - for _, listener := range listeners { - listener(checkbox, checked) - } + session := button.Session() + checked := IsCheckboxChecked(button) + if listeners := GetCheckboxChangedListeners(button); len(listeners) > 0 { + for _, listener := range listeners { + listener(button, checked) } } buffer := allocStringBuilder() defer freeStringBuilder(buffer) - checkboxHtml(view, buffer, checked) - session.updateInnerHTML(view.htmlID()+"checkbox", buffer.String()) + checkboxHtml(button, buffer, checked) + session.updateInnerHTML(button.htmlID()+"checkbox", buffer.String()) case CheckboxHorizontalAlign, CheckboxVerticalAlign: - htmlID := view.htmlID() - session := view.Session() + htmlID := button.htmlID() + session := button.Session() updateCSSStyle(htmlID, session) updateInnerHTML(htmlID, session) case VerticalAlign: - view.Session().updateCSSProperty(view.htmlID()+"content", "align-items", checkboxVerticalAlignCSS(view)) + button.Session().updateCSSProperty(button.htmlID()+"content", "align-items", checkboxVerticalAlignCSS(button)) case HorizontalAlign: - view.Session().updateCSSProperty(view.htmlID()+"content", "justify-items", checkboxHorizontalAlignCSS(view)) + button.Session().updateCSSProperty(button.htmlID()+"content", "justify-items", checkboxHorizontalAlignCSS(button)) case AccentColor: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(button.htmlID(), button.Session()) default: - viewsContainerPropertyChanged(view, tag) + button.viewsContainerData.propertyChanged(tag) } } -func (button *checkboxData) setFunc(view View, tag PropertyName, value any) []PropertyName { +func (button *checkboxData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case ClickEvent: - if button.viewsContainerData.setFunc(view, ClickEvent, value) != nil { - if value := view.getRaw(ClickEvent); value != nil { - if listeners, ok := value.([]func(View, MouseEvent)); ok { - listeners = append(listeners, checkboxClickListener) - view.setRaw(ClickEvent, listeners) - return []PropertyName{ClickEvent} - } - } - - return button.viewsContainerData.setFunc(view, ClickEvent, checkboxClickListener) + if listeners, ok := valueToOneArgEventListeners[View, MouseEvent](value); ok && listeners != nil { + listeners = append(listeners, checkboxClickListener) + button.setRaw(tag, listeners) + return []PropertyName{tag} } return nil case KeyDownEvent: - if button.viewsContainerData.setFunc(view, KeyDownEvent, value) != nil { - if value := view.getRaw(KeyDownEvent); value != nil { - if listeners, ok := value.([]func(View, KeyEvent)); ok { - listeners = append(listeners, checkboxKeyListener) - view.setRaw(KeyDownEvent, listeners) - return []PropertyName{KeyDownEvent} - } - } - - return button.viewsContainerData.setFunc(view, KeyDownEvent, checkboxKeyListener) + if listeners, ok := valueToOneArgEventListeners[View, KeyEvent](value); ok && listeners != nil { + listeners = append(listeners, checkboxKeyListener) + button.setRaw(tag, listeners) + return []PropertyName{tag} } return nil case CheckboxChangedEvent: - return setViewEventListener[Checkbox, bool](view, tag, value) + return setOneArgEventListener[Checkbox, bool](button, tag, value) case Checked: - return setBoolProperty(view, Checked, value) + return setBoolProperty(button, Checked, value) case CellVerticalAlign, CellHorizontalAlign, CellWidth, CellHeight: ErrorLogF(`"%s" property is not compatible with the BoundsProperty`, string(tag)) return nil } - return button.viewsContainerData.setFunc(view, tag, value) + return button.viewsContainerData.setFunc(tag, value) } -func (button *checkboxData) removeFunc(view View, tag PropertyName) []PropertyName { +func (button *checkboxData) removeFunc(tag PropertyName) []PropertyName { switch tag { case ClickEvent: - button.setRaw(ClickEvent, checkboxClickListener) + button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener}) return []PropertyName{ClickEvent} case KeyDownEvent: - button.setRaw(KeyDownEvent, checkboxKeyListener) + button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener}) return []PropertyName{ClickEvent} } - return button.viewsContainerData.removeFunc(view, tag) -} - -func (button *checkboxData) checked() bool { - checked, _ := boolProperty(button, Checked, button.Session()) - return checked + return button.viewsContainerData.removeFunc(tag) } /* @@ -340,5 +321,5 @@ func GetCheckboxHorizontalAlign(view View, subviewID ...string) int { // 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. func GetCheckboxChangedListeners(view View, subviewID ...string) []func(Checkbox, bool) { - return getEventListeners[Checkbox, bool](view, subviewID, CheckboxChangedEvent) + return getOneArgEventListeners[Checkbox, bool](view, subviewID, CheckboxChangedEvent) } diff --git a/colorPicker.go b/colorPicker.go index 705beb1..3561547 100644 --- a/colorPicker.go +++ b/colorPicker.go @@ -66,8 +66,8 @@ func (picker *colorPickerData) init(session Session) { picker.hasHtmlDisabled = true picker.properties[Padding] = Px(0) picker.normalize = normalizeColorPickerTag - picker.set = colorPickerSet - picker.changed = colorPickerPropertyChanged + picker.set = picker.setFunc + picker.changed = picker.propertyChanged } func normalizeColorPickerTag(tag PropertyName) PropertyName { @@ -80,44 +80,44 @@ func normalizeColorPickerTag(tag PropertyName) PropertyName { return normalizeDataListTag(tag) } -func colorPickerSet(view View, tag PropertyName, value any) []PropertyName { +func (picker *colorPickerData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case ColorChangedEvent: - return setEventWithOldListener[ColorPicker, Color](view, tag, value) + return setTwoArgEventListener[ColorPicker, Color](picker, tag, value) case ColorPickerValue: - oldColor := GetColorPickerValue(view) - result := setColorProperty(view, ColorPickerValue, value) + oldColor := GetColorPickerValue(picker) + result := setColorProperty(picker, ColorPickerValue, value) if result != nil { - view.setRaw("old-color", oldColor) + picker.setRaw("old-color", oldColor) } return result case DataList: - return setDataList(view, value, "") + return setDataList(picker, value, "") } - return viewSet(view, tag, value) + return picker.viewData.setFunc(tag, value) } -func colorPickerPropertyChanged(view View, tag PropertyName) { +func (picker *colorPickerData) propertyChanged(tag PropertyName) { switch tag { case ColorPickerValue: - color := GetColorPickerValue(view) - view.Session().callFunc("setInputValue", view.htmlID(), color.rgbString()) + color := GetColorPickerValue(picker) + picker.Session().callFunc("setInputValue", picker.htmlID(), color.rgbString()) - if listeners := GetColorChangedListeners(view); len(listeners) > 0 { + if listeners := GetColorChangedListeners(picker); len(listeners) > 0 { oldColor := Color(0) - if value := view.getRaw("old-color"); value != nil { + if value := picker.getRaw("old-color"); value != nil { oldColor = value.(Color) } for _, listener := range listeners { - listener(view, color, oldColor) + listener(picker, color, oldColor) } } default: - viewPropertyChanged(view, tag) + picker.viewData.propertyChanged(tag) } } @@ -196,5 +196,5 @@ func GetColorPickerValue(view View, subviewID ...string) Color { // 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. func GetColorChangedListeners(view View, subviewID ...string) []func(ColorPicker, Color, Color) { - return getEventWithOldListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent) + return getTwoArgEventListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent) } diff --git a/columnLayout.go b/columnLayout.go index 1119f22..9468167 100644 --- a/columnLayout.go +++ b/columnLayout.go @@ -141,7 +141,7 @@ func (columnLayout *columnLayoutData) init(session Session) { columnLayout.viewsContainerData.init(session) columnLayout.tag = "ColumnLayout" columnLayout.normalize = normalizeColumnLayoutTag - columnLayout.changed = columnLayoutPropertyChanged + columnLayout.changed = columnLayout.propertyChanged //columnLayout.systemClass = "ruiColumnLayout" } @@ -154,27 +154,27 @@ func normalizeColumnLayoutTag(tag PropertyName) PropertyName { return tag } -func columnLayoutPropertyChanged(view View, tag PropertyName) { +func (columnLayout *columnLayoutData) propertyChanged(tag PropertyName) { switch tag { case ColumnSeparator: css := "" - session := view.Session() - if value := view.getRaw(ColumnSeparator); value != nil { + session := columnLayout.Session() + if value := columnLayout.getRaw(ColumnSeparator); value != nil { separator := value.(ColumnSeparatorProperty) - css = separator.cssValue(view.Session()) + css = separator.cssValue(session) } - session.updateCSSProperty(view.htmlID(), "column-rule", css) + session.updateCSSProperty(columnLayout.htmlID(), "column-rule", css) case ColumnCount: - session := view.Session() - if count, ok := intProperty(view, tag, session, 0); ok && count > 0 { - session.updateCSSProperty(view.htmlID(), string(ColumnCount), strconv.Itoa(count)) + session := columnLayout.Session() + if count := GetColumnCount(columnLayout); count > 0 { + session.updateCSSProperty(columnLayout.htmlID(), string(ColumnCount), strconv.Itoa(count)) } else { - session.updateCSSProperty(view.htmlID(), string(ColumnCount), "auto") + session.updateCSSProperty(columnLayout.htmlID(), string(ColumnCount), "auto") } default: - viewsContainerPropertyChanged(view, tag) + columnLayout.viewsContainerData.propertyChanged(tag) } } diff --git a/columnSeparator.go b/columnSeparator.go index be30b18..323f858 100644 --- a/columnSeparator.go +++ b/columnSeparator.go @@ -82,6 +82,7 @@ func NewColumnSeparator(params Params) ColumnSeparatorProperty { func (separator *columnSeparatorProperty) init() { separator.dataProperty.init() separator.normalize = normalizeVolumnSeparatorTag + separator.set = columnSeparatorSet separator.supportedProperties = []PropertyName{Style, Width, ColorTag} } @@ -171,3 +172,10 @@ func (separator *columnSeparatorProperty) cssValue(session Session) string { return buffer.String() } + +func columnSeparatorSet(properties Properties, tag PropertyName, value any) []PropertyName { + if tag == Style { + return setEnumProperty(properties, Style, value, enumProperties[BorderStyle].values) + } + return propertiesSet(properties, tag, value) +} diff --git a/dataList.go b/dataList.go index f595cb1..a4fa535 100644 --- a/dataList.go +++ b/dataList.go @@ -120,7 +120,7 @@ func normalizeDataListTag(tag PropertyName) PropertyName { } func setDataList(properties Properties, value any, dateTimeFormat string) []PropertyName { - if items, ok := anyToStringArray(value, timeFormat); ok { + if items, ok := anyToStringArray(value, dateTimeFormat); ok { properties.setRaw(DataList, items) return []PropertyName{DataList} } diff --git a/datePicker.go b/datePicker.go index bf1ec65..dded25f 100644 --- a/datePicker.go +++ b/datePicker.go @@ -138,8 +138,8 @@ func (picker *datePickerData) init(session Session) { picker.tag = "DatePicker" picker.hasHtmlDisabled = true picker.normalize = normalizeDatePickerTag - picker.set = datePickerSet - picker.changed = datePickerPropertyChanged + picker.set = picker.setFunc + picker.changed = picker.propertyChanged } func (picker *datePickerData) Focusable() bool { @@ -198,22 +198,22 @@ func stringToDate(value string) (time.Time, bool) { return time.Now(), false } -func datePickerSet(view View, tag PropertyName, value any) []PropertyName { +func (picker *datePickerData) setFunc(tag PropertyName, value any) []PropertyName { setDateValue := func(tag PropertyName) []PropertyName { switch value := value.(type) { case time.Time: - view.setRaw(tag, value) + picker.setRaw(tag, value) return []PropertyName{tag} case string: if isConstantName(value) { - view.setRaw(tag, value) + picker.setRaw(tag, value) return []PropertyName{tag} } if date, ok := stringToDate(value); ok { - view.setRaw(tag, date) + picker.setRaw(tag, date) return []PropertyName{tag} } } @@ -227,67 +227,67 @@ func datePickerSet(view View, tag PropertyName, value any) []PropertyName { return setDateValue(tag) case DatePickerStep: - return setIntProperty(view, DatePickerStep, value) + return setIntProperty(picker, DatePickerStep, value) case DatePickerValue: - view.setRaw("old-date", GetDatePickerValue(view)) + picker.setRaw("old-date", GetDatePickerValue(picker)) return setDateValue(tag) case DateChangedEvent: - return setEventWithOldListener[DatePicker, time.Time](view, tag, value) + return setTwoArgEventListener[DatePicker, time.Time](picker, tag, value) case DataList: - return setDataList(view, value, dateFormat) + return setDataList(picker, value, dateFormat) } - return viewSet(view, tag, value) + return picker.viewData.setFunc(tag, value) } -func datePickerPropertyChanged(view View, tag PropertyName) { +func (picker *datePickerData) propertyChanged(tag PropertyName) { - session := view.Session() + session := picker.Session() switch tag { case DatePickerMin: - if date, ok := GetDatePickerMin(view); ok { - session.updateProperty(view.htmlID(), "min", date.Format(dateFormat)) + if date, ok := GetDatePickerMin(picker); ok { + session.updateProperty(picker.htmlID(), "min", date.Format(dateFormat)) } else { - session.removeProperty(view.htmlID(), "min") + session.removeProperty(picker.htmlID(), "min") } case DatePickerMax: - if date, ok := GetDatePickerMax(view); ok { - session.updateProperty(view.htmlID(), "max", date.Format(dateFormat)) + if date, ok := GetDatePickerMax(picker); ok { + session.updateProperty(picker.htmlID(), "max", date.Format(dateFormat)) } else { - session.removeProperty(view.htmlID(), "max") + session.removeProperty(picker.htmlID(), "max") } case DatePickerStep: - if step := GetDatePickerStep(view); step > 0 { - session.updateProperty(view.htmlID(), "step", strconv.Itoa(step)) + if step := GetDatePickerStep(picker); step > 0 { + session.updateProperty(picker.htmlID(), "step", strconv.Itoa(step)) } else { - session.removeProperty(view.htmlID(), "step") + session.removeProperty(picker.htmlID(), "step") } case DatePickerValue: - date := GetDatePickerValue(view) - session.callFunc("setInputValue", view.htmlID(), date.Format(dateFormat)) + date := GetDatePickerValue(picker) + session.callFunc("setInputValue", picker.htmlID(), date.Format(dateFormat)) - if listeners := GetDateChangedListeners(view); len(listeners) > 0 { + if listeners := GetDateChangedListeners(picker); len(listeners) > 0 { oldDate := time.Now() - if value := view.getRaw("old-date"); value != nil { + if value := picker.getRaw("old-date"); value != nil { if date, ok := value.(time.Time); ok { oldDate = date } } for _, listener := range listeners { - listener(view, date, oldDate) + listener(picker, date, oldDate) } } default: - viewPropertyChanged(view, tag) + picker.viewData.propertyChanged(tag) } } @@ -447,5 +447,5 @@ func GetDatePickerValue(view View, subviewID ...string) time.Time { // 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. func GetDateChangedListeners(view View, subviewID ...string) []func(DatePicker, time.Time, time.Time) { - return getEventWithOldListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent) + return getTwoArgEventListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent) } diff --git a/detailsView.go b/detailsView.go index 3c4ea42..cb6529f 100644 --- a/detailsView.go +++ b/detailsView.go @@ -54,7 +54,7 @@ func (detailsView *detailsViewData) init(session Session) { detailsView.viewsContainerData.init(session) detailsView.tag = "DetailsView" detailsView.set = detailsView.setFunc - detailsView.changed = detailsViewPropertyChanged + detailsView.changed = detailsView.propertyChanged //detailsView.systemClass = "ruiDetailsView" } @@ -69,7 +69,7 @@ func (detailsView *detailsViewData) Views() []View { return views } -func (detailsView *detailsViewData) setFunc(self View, tag PropertyName, value any) []PropertyName { +func (detailsView *detailsViewData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Summary: switch value := value.(type) { @@ -95,26 +95,26 @@ func (detailsView *detailsViewData) setFunc(self View, tag PropertyName, value a return []PropertyName{tag} } - return detailsView.viewsContainerData.setFunc(detailsView, tag, value) + return detailsView.viewsContainerData.setFunc(tag, value) } -func detailsViewPropertyChanged(view View, tag PropertyName) { +func (detailsView *detailsViewData) propertyChanged(tag PropertyName) { switch tag { case Summary: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(detailsView.htmlID(), detailsView.Session()) case Expanded: - if IsDetailsExpanded(view) { - view.Session().updateProperty(view.htmlID(), "open", "") + if IsDetailsExpanded(detailsView) { + detailsView.Session().updateProperty(detailsView.htmlID(), "open", "") } else { - view.Session().removeProperty(view.htmlID(), "open") + detailsView.Session().removeProperty(detailsView.htmlID(), "open") } case NotTranslate: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(detailsView.htmlID(), detailsView.Session()) default: - viewsContainerPropertyChanged(view, tag) + detailsView.viewsContainerData.propertyChanged(tag) } } @@ -155,8 +155,8 @@ func (detailsView *detailsViewData) handleCommand(self View, command PropertyNam if command == "details-open" { if n, ok := dataIntProperty(data, "open"); ok { detailsView.properties[Expanded] = (n != 0) - if listener, ok := detailsView.changeListener[Current]; ok { - listener(detailsView, Current) + if listener, ok := detailsView.changeListener[Expanded]; ok { + listener(detailsView, Expanded) } } return true diff --git a/dropDownList.go b/dropDownList.go index ec6d46d..1b9f739 100644 --- a/dropDownList.go +++ b/dropDownList.go @@ -46,8 +46,8 @@ func (list *dropDownListData) init(session Session) { list.tag = "DropDownList" list.hasHtmlDisabled = true list.normalize = normalizeDropDownListTag - list.set = dropDownListSet - list.changed = dropDownListPropertyChanged + list.set = list.setFunc + list.changed = list.propertyChanged } func (list *dropDownListData) Focusable() bool { @@ -62,59 +62,49 @@ func normalizeDropDownListTag(tag PropertyName) PropertyName { return tag } -func dropDownListSet(view View, tag PropertyName, value any) []PropertyName { +func (list *dropDownListData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Items: if items, ok := anyToStringArray(value, ""); ok { - return setArrayPropertyValue(view, tag, items) + return setArrayPropertyValue(list, tag, items) } notCompatibleType(Items, value) return nil case DisabledItems, ItemSeparators: if items, ok := parseIndicesArray(value); ok { - return setArrayPropertyValue(view, tag, items) + return setArrayPropertyValue(list, tag, items) } notCompatibleType(tag, value) return nil case DropDownEvent: - return setEventWithOldListener[DropDownList, int](view, tag, value) + return setTwoArgEventListener[DropDownList, int](list, tag, value) case Current: - if view, ok := view.(View); ok { - view.setRaw("old-current", GetCurrent(view)) - } - return setIntProperty(view, Current, value) + list.setRaw("old-current", GetCurrent(list)) + return setIntProperty(list, Current, value) } - return viewSet(view, tag, value) + return list.viewData.setFunc(tag, value) } -func dropDownListPropertyChanged(view View, tag PropertyName) { +func (list *dropDownListData) propertyChanged(tag PropertyName) { switch tag { case Items, DisabledItems, ItemSeparators: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(list.htmlID(), list.Session()) case Current: - current := GetCurrent(view) - view.Session().callFunc("selectDropDownListItem", view.htmlID(), current) + current := GetCurrent(list) + list.Session().callFunc("selectDropDownListItem", list.htmlID(), current) - if list, ok := view.(DropDownList); ok { - oldCurrent := -1 - if value := view.getRaw("old-current"); value != nil { - if n, ok := value.(int); ok { - oldCurrent = n - } - } - - for _, listener := range GetDropDownListeners(view) { - listener(list, current, oldCurrent) - } + oldCurrent, _ := intProperty(list, "old-current", list.Session(), -1) + for _, listener := range GetDropDownListeners(list) { + listener(list, current, oldCurrent) } default: - viewPropertyChanged(view, tag) + list.viewData.propertyChanged(tag) } } @@ -253,6 +243,9 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat for _, listener := range GetDropDownListeners(list) { listener(list, number, old) } + if listener, ok := list.changeListener[Current]; ok { + listener(list, Current) + } } } else { ErrorLog(err.Error()) @@ -268,7 +261,7 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat // GetDropDownListeners returns the "drop-down-event" listener list. 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. func GetDropDownListeners(view View, subviewID ...string) []func(DropDownList, int, int) { - return getEventWithOldListeners[DropDownList, int](view, subviewID, DropDownEvent) + return getTwoArgEventListeners[DropDownList, int](view, subviewID, DropDownEvent) } // GetDropDownItems return the DropDownList items list. diff --git a/editView.go b/editView.go index a6c08ea..4056ddf 100644 --- a/editView.go +++ b/editView.go @@ -121,8 +121,8 @@ func (edit *editViewData) init(session Session) { edit.hasHtmlDisabled = true edit.tag = "EditView" edit.normalize = normalizeEditViewTag - edit.set = editViewSet - edit.changed = editViewPropertyChanged + edit.set = edit.setFunc + edit.changed = edit.propertyChanged } func (edit *editViewData) Focusable() bool { @@ -148,18 +148,18 @@ func normalizeEditViewTag(tag PropertyName) PropertyName { return normalizeDataListTag(tag) } -func editViewSet(view View, tag PropertyName, value any) []PropertyName { +func (edit *editViewData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Text: if text, ok := value.(string); ok { old := "" - if val := view.getRaw(Text); val != nil { + if val := edit.getRaw(Text); val != nil { if txt, ok := val.(string); ok { old = txt } } - view.setRaw("old-text", old) - view.setRaw(tag, text) + edit.setRaw("old-text", old) + edit.setRaw(tag, text) return []PropertyName{tag} } @@ -168,85 +168,83 @@ func editViewSet(view View, tag PropertyName, value any) []PropertyName { case Hint: if text, ok := value.(string); ok { - return setStringPropertyValue(view, tag, strings.Trim(text, " \t\n")) + return setStringPropertyValue(edit, tag, strings.Trim(text, " \t\n")) } notCompatibleType(tag, value) return nil case DataList: - setDataList(view, value, "") + setDataList(edit, value, "") case EditTextChangedEvent: - return setEventWithOldListener[EditView, string](view, tag, value) + return setTwoArgEventListener[EditView, string](edit, tag, value) } - return viewSet(view, tag, value) + return edit.viewData.setFunc(tag, value) } -func editViewPropertyChanged(view View, tag PropertyName) { - session := view.Session() +func (edit *editViewData) propertyChanged(tag PropertyName) { + session := edit.Session() switch tag { case Text: - text := GetText(view) - session.callFunc("setInputValue", view.htmlID(), text) + text := GetText(edit) + session.callFunc("setInputValue", edit.htmlID(), text) - if edit, ok := view.(EditView); ok { - old := "" - if val := view.getRaw("old-text"); val != nil { - if txt, ok := val.(string); ok { - old = txt - } + old := "" + if val := edit.getRaw("old-text"); val != nil { + if txt, ok := val.(string); ok { + old = txt } - edit.textChanged(text, old) } + edit.textChanged(text, old) case Hint: - if text := GetHint(view); text != "" { - session.updateProperty(view.htmlID(), "placeholder", text) + if text := GetHint(edit); text != "" { + session.updateProperty(edit.htmlID(), "placeholder", text) } else { - session.removeProperty(view.htmlID(), "placeholder") + session.removeProperty(edit.htmlID(), "placeholder") } case MaxLength: - if maxLength := GetMaxLength(view); maxLength > 0 { - session.updateProperty(view.htmlID(), "maxlength", strconv.Itoa(maxLength)) + if maxLength := GetMaxLength(edit); maxLength > 0 { + session.updateProperty(edit.htmlID(), "maxlength", strconv.Itoa(maxLength)) } else { - session.removeProperty(view.htmlID(), "maxlength") + session.removeProperty(edit.htmlID(), "maxlength") } case ReadOnly: - if IsReadOnly(view) { - session.updateProperty(view.htmlID(), "readonly", "") + if IsReadOnly(edit) { + session.updateProperty(edit.htmlID(), "readonly", "") } else { - session.removeProperty(view.htmlID(), "readonly") + session.removeProperty(edit.htmlID(), "readonly") } case Spellcheck: - session.updateProperty(view.htmlID(), "spellcheck", IsSpellcheck(view)) + session.updateProperty(edit.htmlID(), "spellcheck", IsSpellcheck(edit)) case EditViewPattern: - if text := GetEditViewPattern(view); text != "" { - session.updateProperty(view.htmlID(), "pattern", text) + if text := GetEditViewPattern(edit); text != "" { + session.updateProperty(edit.htmlID(), "pattern", text) } else { - session.removeProperty(view.htmlID(), "pattern") + session.removeProperty(edit.htmlID(), "pattern") } case EditViewType: - updateInnerHTML(view.parentHTMLID(), session) + updateInnerHTML(edit.parentHTMLID(), session) case EditWrap: - if wrap := IsEditViewWrap(view); wrap { - session.updateProperty(view.htmlID(), "wrap", "soft") + if wrap := IsEditViewWrap(edit); wrap { + session.updateProperty(edit.htmlID(), "wrap", "soft") } else { - session.updateProperty(view.htmlID(), "wrap", "off") + session.updateProperty(edit.htmlID(), "wrap", "off") } case DataList: - updateInnerHTML(view.htmlID(), session) + updateInnerHTML(edit.htmlID(), session) default: - viewPropertyChanged(view, tag) + edit.viewData.propertyChanged(tag) } } @@ -467,7 +465,7 @@ func IsSpellcheck(view View, subviewID ...string) bool { // 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. func GetTextChangedListeners(view View, subviewID ...string) []func(EditView, string, string) { - return getEventWithOldListeners[EditView, string](view, subviewID, EditTextChangedEvent) + return getTwoArgEventListeners[EditView, string](view, subviewID, EditTextChangedEvent) } // GetEditViewType returns a value of the Type property of EditView. diff --git a/events.go b/events.go index bb6eab9..55d8772 100644 --- a/events.go +++ b/events.go @@ -35,7 +35,7 @@ var eventJsFunc = map[PropertyName]struct{ jsEvent, jsFunc string }{ AnimationCancelEvent: {jsEvent: "onanimationcancel", jsFunc: "animationCancelEvent"}, } -func valueToNoParamListeners[V any](value any) ([]func(V), bool) { +func valueToNoArgEventListeners[V any](value any) ([]func(V), bool) { if value == nil { return nil, true } @@ -106,7 +106,7 @@ func valueToNoParamListeners[V any](value any) ([]func(V), bool) { return nil, false } -func valueToEventListeners[V View, E any](value any) ([]func(V, E), bool) { +func valueToOneArgEventListeners[V View, E any](value any) ([]func(V, E), bool) { if value == nil { return nil, true } @@ -231,7 +231,7 @@ func valueToEventListeners[V View, E any](value any) ([]func(V, E), bool) { return nil, false } -func valueToEventWithOldListeners[V View, E any](value any) ([]func(V, E, E), bool) { +func valueToTwoArgEventListeners[V View, E any](value any) ([]func(V, E, E), bool) { if value == nil { return nil, true } @@ -410,7 +410,7 @@ func valueToEventWithOldListeners[V View, E any](value any) ([]func(V, E, E), bo return nil, false } -func getNoParamEventListeners[V View](view View, subviewID []string, tag PropertyName) []func(V) { +func getNoArgEventListeners[V View](view View, subviewID []string, tag PropertyName) []func(V) { if len(subviewID) > 0 && subviewID[0] != "" { view = ViewByID(view, subviewID[0]) } @@ -424,7 +424,7 @@ func getNoParamEventListeners[V View](view View, subviewID []string, tag Propert return []func(V){} } -func getEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E) { +func getOneArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E) { if len(subviewID) > 0 && subviewID[0] != "" { view = ViewByID(view, subviewID[0]) } @@ -438,7 +438,7 @@ func getEventListeners[V View, E any](view View, subviewID []string, tag Propert return []func(V, E){} } -func getEventWithOldListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E, E) { +func getTwoArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E, E) { if len(subviewID) > 0 && subviewID[0] != "" { view = ViewByID(view, subviewID[0]) } @@ -452,8 +452,8 @@ func getEventWithOldListeners[V View, E any](view View, subviewID []string, tag return []func(V, E, E){} } -func setNoParamEventListener[V View](properties Properties, tag PropertyName, value any) []PropertyName { - if listeners, ok := valueToNoParamListeners[V](value); ok { +func setNoArgEventListener[V View](properties Properties, tag PropertyName, value any) []PropertyName { + if listeners, ok := valueToNoArgEventListeners[V](value); ok { if len(listeners) > 0 { properties.setRaw(tag, listeners) } else if properties.getRaw(tag) != nil { @@ -467,8 +467,8 @@ func setNoParamEventListener[V View](properties Properties, tag PropertyName, va return nil } -func setViewEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName { - if listeners, ok := valueToEventListeners[V, T](value); ok { +func setOneArgEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName { + if listeners, ok := valueToOneArgEventListeners[V, T](value); ok { if len(listeners) > 0 { properties.setRaw(tag, listeners) } else if properties.getRaw(tag) != nil { @@ -482,8 +482,8 @@ func setViewEventListener[V View, T any](properties Properties, tag PropertyName return nil } -func setEventWithOldListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName { - listeners, ok := valueToEventWithOldListeners[V, T](value) +func setTwoArgEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName { + listeners, ok := valueToTwoArgEventListeners[V, T](value) if !ok { notCompatibleType(tag, value) return nil @@ -498,7 +498,7 @@ func setEventWithOldListener[V View, T any](properties Properties, tag PropertyN } func viewEventsHtml[T any](view View, events []PropertyName, buffer *strings.Builder) { - for _, tag := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent} { + for _, tag := range events { if value := view.getRaw(tag); value != nil { if js, ok := eventJsFunc[tag]; ok { if listeners, ok := value.([]func(View, T)); ok && len(listeners) > 0 { diff --git a/filePicker.go b/filePicker.go index 4923e17..72e86ab 100644 --- a/filePicker.go +++ b/filePicker.go @@ -123,8 +123,8 @@ func (picker *filePickerData) init(session Session) { picker.hasHtmlDisabled = true picker.files = []FileInfo{} picker.loader = map[int]func(FileInfo, []byte){} - picker.set = filePickerSet - picker.changed = filePickerPropertyChanged + picker.set = picker.setFunc + picker.changed = picker.propertyChanged } @@ -150,27 +150,16 @@ func (picker *filePickerData) LoadFile(file FileInfo, result func(FileInfo, []by } } -func filePickerSet(view View, tag PropertyName, value any) []PropertyName { - - setAccept := func(value string) []PropertyName { - if value != "" { - view.setRaw(tag, value) - } else if view.getRaw(tag) != nil { - view.setRaw(tag, nil) - } else { - return []PropertyName{} - } - return []PropertyName{Accept} - } +func (picker *filePickerData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case FileSelectedEvent: - return setViewEventListener[FilePicker, []FileInfo](view, tag, value) + return setOneArgEventListener[FilePicker, []FileInfo](picker, tag, value) case Accept: switch value := value.(type) { case string: - return setAccept(strings.Trim(value, " \t\n")) + return setStringPropertyValue(picker, Accept, strings.Trim(value, " \t\n")) case []string: buffer := allocStringBuilder() @@ -184,27 +173,27 @@ func filePickerSet(view View, tag PropertyName, value any) []PropertyName { buffer.WriteString(val) } } - return setAccept(buffer.String()) + return setStringPropertyValue(picker, Accept, buffer.String()) } notCompatibleType(tag, value) return nil } - return viewSet(view, tag, value) + return picker.viewData.setFunc(tag, value) } -func filePickerPropertyChanged(view View, tag PropertyName) { +func (picker *filePickerData) propertyChanged(tag PropertyName) { switch tag { case Accept: - session := view.Session() - if css := acceptPropertyCSS(view); css != "" { - session.updateProperty(view.htmlID(), "accept", css) + session := picker.Session() + if css := acceptPropertyCSS(picker); css != "" { + session.updateProperty(picker.htmlID(), "accept", css) } else { - session.removeProperty(view.htmlID(), "accept") + session.removeProperty(picker.htmlID(), "accept") } default: - viewPropertyChanged(view, tag) + picker.viewData.propertyChanged(tag) } } @@ -381,5 +370,5 @@ func GetFilePickerAccept(view View, subviewID ...string) []string { // 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. func GetFileSelectedListeners(view View, subviewID ...string) []func(FilePicker, []FileInfo) { - return getEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent) + return getOneArgEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent) } diff --git a/focusEvents.go b/focusEvents.go index 4c1f7f5..425c599 100644 --- a/focusEvents.go +++ b/focusEvents.go @@ -51,11 +51,11 @@ func focusEventsHtml(view View, buffer *strings.Builder) { // GetFocusListeners returns a FocusListener list. 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. func GetFocusListeners(view View, subviewID ...string) []func(View) { - return getNoParamEventListeners[View](view, subviewID, FocusEvent) + return getNoArgEventListeners[View](view, subviewID, FocusEvent) } // GetLostFocusListeners returns a LostFocusListener list. 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. func GetLostFocusListeners(view View, subviewID ...string) []func(View) { - return getNoParamEventListeners[View](view, subviewID, LostFocusEvent) + return getNoArgEventListeners[View](view, subviewID, LostFocusEvent) } diff --git a/gridLayout.go b/gridLayout.go index 1122d21..39d8a7f 100644 --- a/gridLayout.go +++ b/gridLayout.go @@ -137,10 +137,10 @@ func (gridLayout *gridLayoutData) init(session Session) { gridLayout.systemClass = "ruiGridLayout" gridLayout.adapter = nil gridLayout.normalize = normalizeGridLayoutTag - gridLayout.getFunc = gridLayout.get + gridLayout.get = gridLayout.getFunc gridLayout.set = gridLayout.setFunc gridLayout.remove = gridLayout.removeFunc - + gridLayout.changed = gridLayout.propertyChanged } func setGridCellSize(properties Properties, tag PropertyName, value any) []PropertyName { @@ -303,7 +303,7 @@ func normalizeGridLayoutTag(tag PropertyName) PropertyName { return tag } -func (gridLayout *gridLayoutData) get(self View, tag PropertyName) any { +func (gridLayout *gridLayoutData) getFunc(tag PropertyName) any { switch tag { case Gap: rowGap := GetGridRowGap(gridLayout) @@ -319,10 +319,10 @@ func (gridLayout *gridLayoutData) get(self View, tag PropertyName) any { } } - return gridLayout.viewsContainerData.get(gridLayout, tag) + return gridLayout.viewsContainerData.getFunc(tag) } -func (gridLayout *gridLayoutData) removeFunc(self View, tag PropertyName) []PropertyName { +func (gridLayout *gridLayoutData) removeFunc(tag PropertyName) []PropertyName { switch tag { case Gap: result := []PropertyName{} @@ -343,13 +343,13 @@ func (gridLayout *gridLayoutData) removeFunc(self View, tag PropertyName) []Prop return []PropertyName{} } - return gridLayout.viewsContainerData.removeFunc(gridLayout, tag) + return gridLayout.viewsContainerData.removeFunc(tag) } -func (gridLayout *gridLayoutData) setFunc(self View, tag PropertyName, value any) []PropertyName { +func (gridLayout *gridLayoutData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Gap: - result := gridLayout.setFunc(gridLayout, GridRowGap, value) + result := gridLayout.setFunc(GridRowGap, value) if result != nil { if gap := gridLayout.getRaw(GridRowGap); gap != nil { gridLayout.setRaw(GridColumnGap, gap) @@ -370,21 +370,23 @@ func (gridLayout *gridLayoutData) setFunc(self View, tag PropertyName, value any return []PropertyName{Content} } - return gridLayout.viewsContainerData.setFunc(gridLayout, tag, value) + return gridLayout.viewsContainerData.setFunc(tag, value) } -func gridLayoutPropertyChanged(view View, tag PropertyName) { +func (gridLayout *gridLayoutData) propertyChanged(tag PropertyName) { switch tag { case CellWidth: - view.Session().updateCSSProperty(view.htmlID(), `grid-template-columns`, - gridCellSizesCSS(view, CellWidth, view.Session())) + session := gridLayout.Session() + session.updateCSSProperty(gridLayout.htmlID(), `grid-template-columns`, + gridCellSizesCSS(gridLayout, CellWidth, session)) case CellHeight: - view.Session().updateCSSProperty(view.htmlID(), `grid-template-rows`, - gridCellSizesCSS(view, CellHeight, view.Session())) + session := gridLayout.Session() + session.updateCSSProperty(gridLayout.htmlID(), `grid-template-rows`, + gridCellSizesCSS(gridLayout, CellHeight, session)) default: - viewsContainerPropertyChanged(view, tag) + gridLayout.viewsContainerData.propertyChanged(tag) } } diff --git a/imageView.go b/imageView.go index 1e0b9c8..b837456 100644 --- a/imageView.go +++ b/imageView.go @@ -97,8 +97,8 @@ func (imageView *imageViewData) init(session Session) { imageView.tag = "ImageView" imageView.systemClass = "ruiImageView" imageView.normalize = normalizeImageViewTag - imageView.set = imageViewSet - imageView.changed = imageViewPropertyChanged + imageView.set = imageView.setFunc + imageView.changed = imageView.propertyChanged } func normalizeImageViewTag(tag PropertyName) PropertyName { @@ -122,30 +122,30 @@ func normalizeImageViewTag(tag PropertyName) PropertyName { return tag } -func imageViewSet(view View, tag PropertyName, value any) []PropertyName { +func (imageView *imageViewData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Source, SrcSet, AltText: if text, ok := value.(string); ok { - return setStringPropertyValue(view, tag, text) + return setStringPropertyValue(imageView, tag, text) } notCompatibleType(tag, value) return nil case LoadedEvent, ErrorEvent: - return setNoParamEventListener[ImageView](view, tag, value) + return setNoArgEventListener[ImageView](imageView, tag, value) } - return viewSet(view, tag, value) + return imageView.viewData.setFunc(tag, value) } -func imageViewPropertyChanged(view View, tag PropertyName) { - session := view.Session() - htmlID := view.htmlID() +func (imageView *imageViewData) propertyChanged(tag PropertyName) { + session := imageView.Session() + htmlID := imageView.htmlID() switch tag { case Source: - src, srcset := imageViewSrc(view, GetImageViewSource(view)) + src, srcset := imageViewSrc(imageView, GetImageViewSource(imageView)) session.updateProperty(htmlID, "src", src) if srcset != "" { session.updateProperty(htmlID, "srcset", srcset) @@ -154,7 +154,7 @@ func imageViewPropertyChanged(view View, tag PropertyName) { } case SrcSet: - _, srcset := imageViewSrc(view, GetImageViewSource(view)) + _, srcset := imageViewSrc(imageView, GetImageViewSource(imageView)) if srcset != "" { session.updateProperty(htmlID, "srcset", srcset) } else { @@ -168,7 +168,7 @@ func imageViewPropertyChanged(view View, tag PropertyName) { updateCSSStyle(htmlID, session) default: - viewPropertyChanged(view, tag) + imageView.viewData.propertyChanged(tag) } } @@ -256,7 +256,7 @@ func (imageView *imageViewData) htmlProperties(self View, buffer *strings.Builde buffer.WriteString(` onload="imageLoaded(this, event)"`) - if len(getNoParamEventListeners[ImageView](imageView, nil, ErrorEvent)) > 0 { + if len(getNoArgEventListeners[ImageView](imageView, nil, ErrorEvent)) > 0 { buffer.WriteString(` onerror="imageError(this, event)"`) } } @@ -299,7 +299,7 @@ func (imageView *imageViewData) cssStyle(self View, builder cssBuilder) { func (imageView *imageViewData) handleCommand(self View, command PropertyName, data DataObject) bool { switch command { case "imageViewError": - for _, listener := range getNoParamEventListeners[ImageView](imageView, nil, ErrorEvent) { + for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, ErrorEvent) { listener(imageView) } @@ -308,7 +308,7 @@ func (imageView *imageViewData) handleCommand(self View, command PropertyName, d imageView.naturalHeight = dataFloatProperty(data, "natural-height") imageView.currentSrc, _ = data.PropertyValue("current-src") - for _, listener := range getNoParamEventListeners[ImageView](imageView, nil, LoadedEvent) { + for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, LoadedEvent) { listener(imageView) } diff --git a/keyEvents.go b/keyEvents.go index bfbd52b..5f1e810 100644 --- a/keyEvents.go +++ b/keyEvents.go @@ -431,7 +431,7 @@ func (event *KeyEvent) init(data DataObject) { /* func setKeyListener(properties Properties, tag PropertyName, value any) bool { - if listeners, ok := valueToEventListeners[View, KeyEvent](value); ok { + if listeners, ok := valueToOneArgEventListeners[View, KeyEvent](value); ok { if len(listeners) == 0 { properties.setRaw(tag, nil) } else { @@ -460,15 +460,15 @@ func (view *viewData) removeKeyListener(tag PropertyName) { */ func keyEventsHtml(view View, buffer *strings.Builder) { - if len(getEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 { + if len(getOneArgEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 { buffer.WriteString(`onkeydown="keyDownEvent(this, event)" `) } else if view.Focusable() { - if len(getEventListeners[View, MouseEvent](view, nil, ClickEvent)) > 0 { + if len(getOneArgEventListeners[View, MouseEvent](view, nil, ClickEvent)) > 0 { buffer.WriteString(`onkeydown="keyDownEvent(this, event)" `) } } - if listeners := getEventListeners[View, KeyEvent](view, nil, KeyUpEvent); len(listeners) > 0 { + if listeners := getOneArgEventListeners[View, KeyEvent](view, nil, KeyUpEvent); len(listeners) > 0 { buffer.WriteString(`onkeyup="keyUpEvent(this, event)" `) } } @@ -476,7 +476,7 @@ func keyEventsHtml(view View, buffer *strings.Builder) { func handleKeyEvents(view View, tag PropertyName, data DataObject) { var event KeyEvent event.init(data) - listeners := getEventListeners[View, KeyEvent](view, nil, tag) + listeners := getOneArgEventListeners[View, KeyEvent](view, nil, tag) if len(listeners) > 0 { for _, listener := range listeners { @@ -486,7 +486,7 @@ func handleKeyEvents(view View, tag PropertyName, data DataObject) { } if tag == KeyDownEvent && view.Focusable() && (event.Key == " " || event.Key == "Enter") && !IsDisabled(view) { - if listeners := getEventListeners[View, MouseEvent](view, nil, ClickEvent); len(listeners) > 0 { + if listeners := getOneArgEventListeners[View, MouseEvent](view, nil, ClickEvent); len(listeners) > 0 { clickEvent := MouseEvent{ TimeStamp: event.TimeStamp, Button: PrimaryMouseButton, @@ -512,11 +512,11 @@ func handleKeyEvents(view View, tag PropertyName, data DataObject) { // GetKeyDownListeners returns the "key-down-event" listener list. 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. func GetKeyDownListeners(view View, subviewID ...string) []func(View, KeyEvent) { - return getEventListeners[View, KeyEvent](view, subviewID, KeyDownEvent) + return getOneArgEventListeners[View, KeyEvent](view, subviewID, KeyDownEvent) } // GetKeyUpListeners returns the "key-up-event" listener list. 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. func GetKeyUpListeners(view View, subviewID ...string) []func(View, KeyEvent) { - return getEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent) + return getOneArgEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent) } diff --git a/listLayout.go b/listLayout.go index cc68a92..0a479f3 100644 --- a/listLayout.go +++ b/listLayout.go @@ -64,10 +64,10 @@ func (listLayout *listLayoutData) init(session Session) { listLayout.tag = "ListLayout" listLayout.systemClass = "ruiListLayout" listLayout.normalize = normalizeListLayoutTag - listLayout.getFunc = listLayout.get + listLayout.get = listLayout.getFunc listLayout.set = listLayout.setFunc listLayout.remove = listLayout.removeFunc - listLayout.changed = listLayoutPropertyChanged + listLayout.changed = listLayout.propertyChanged } @@ -86,7 +86,7 @@ func normalizeListLayoutTag(tag PropertyName) PropertyName { return tag } -func (listLayout *listLayoutData) get(self View, tag PropertyName) any { +func (listLayout *listLayoutData) getFunc(tag PropertyName) any { switch tag { case Gap: if rowGap := GetListRowGap(listLayout); rowGap.Equal(GetListColumnGap(listLayout)) { @@ -100,10 +100,10 @@ func (listLayout *listLayoutData) get(self View, tag PropertyName) any { } } - return listLayout.viewsContainerData.get(listLayout, tag) + return listLayout.viewsContainerData.getFunc(tag) } -func (listLayout *listLayoutData) removeFunc(self View, tag PropertyName) []PropertyName { +func (listLayout *listLayoutData) removeFunc(tag PropertyName) []PropertyName { switch tag { case Gap: result := []PropertyName{} @@ -116,18 +116,18 @@ func (listLayout *listLayoutData) removeFunc(self View, tag PropertyName) []Prop return result case Content: - listLayout.viewsContainerData.removeFunc(listLayout, Content) + listLayout.viewsContainerData.removeFunc(Content) listLayout.adapter = nil return []PropertyName{Content} } - return listLayout.viewsContainerData.removeFunc(listLayout, tag) + return listLayout.viewsContainerData.removeFunc(tag) } -func (listLayout *listLayoutData) setFunc(self View, tag PropertyName, value any) []PropertyName { +func (listLayout *listLayoutData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Gap: - result := listLayout.setFunc(listLayout, ListRowGap, value) + result := listLayout.setFunc(ListRowGap, value) if result != nil { if gap := listLayout.getRaw(ListRowGap); gap != nil { listLayout.setRaw(ListColumnGap, gap) @@ -147,16 +147,16 @@ func (listLayout *listLayoutData) setFunc(self View, tag PropertyName, value any } return []PropertyName{Content} } - return listLayout.viewsContainerData.setFunc(listLayout, tag, value) + return listLayout.viewsContainerData.setFunc(tag, value) } -func listLayoutPropertyChanged(view View, tag PropertyName) { +func (listLayout *listLayoutData) propertyChanged(tag PropertyName) { switch tag { case Orientation, ListWrap, HorizontalAlign, VerticalAlign: - updateCSSStyle(view.htmlID(), view.Session()) + updateCSSStyle(listLayout.htmlID(), listLayout.Session()) default: - viewsContainerPropertyChanged(view, tag) + listLayout.viewsContainerData.propertyChanged(tag) } } diff --git a/listView.go b/listView.go index ffaae1c..d1804e9 100644 --- a/listView.go +++ b/listView.go @@ -148,11 +148,10 @@ func (listView *listViewData) init(session Session) { listView.items = []View{} listView.itemFrame = []Frame{} listView.normalize = normalizeListViewTag - listView.getFunc = listView.get - listView.set = listViewSet - listView.changed = listViewPropertyChanged - listView.remove = listViewRemove - + listView.get = listView.getFunc + listView.set = listView.setFunc + listView.remove = listView.removeFunc + listView.changed = listView.propertyChanged } func (listView *listViewData) Views() []View { @@ -183,36 +182,36 @@ func normalizeListViewTag(tag PropertyName) PropertyName { return tag } -func listViewRemove(view View, tag PropertyName) []PropertyName { +func (listView *listViewData) removeFunc(tag PropertyName) []PropertyName { switch tag { case Gap: - result := viewRemove(view, ListRowGap) + result := listView.removeFunc(ListRowGap) if result != nil { - if result2 := viewRemove(view, ListColumnGap); result2 != nil { + if result2 := listView.removeFunc(ListColumnGap); result2 != nil { result = append(result, result2...) } } return result } - return viewRemove(view, tag) + return listView.viewData.removeFunc(tag) } -func listViewSet(view View, tag PropertyName, value any) []PropertyName { +func (listView *listViewData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Gap: - result := listViewSet(view, ListRowGap, value) + result := listView.setFunc(ListRowGap, value) if result != nil { - if result2 := listViewSet(view, ListColumnGap, value); result2 != nil { + if result2 := listView.setFunc(ListColumnGap, value); result2 != nil { result = append(result, result2...) } } return result case ListItemClickedEvent, ListItemSelectedEvent: - return setViewEventListener[ListView, int](view, tag, value) + return setOneArgEventListener[ListView, int](listView, tag, value) case ListItemCheckedEvent: - return setViewEventListener[ListView, []int](view, tag, value) + return setOneArgEventListener[ListView, []int](listView, tag, value) case Checked: var checked []int @@ -243,69 +242,65 @@ func listViewSet(view View, tag PropertyName, value any) []PropertyName { return nil } - return setArrayPropertyValue(view, Checked, checked) + return setArrayPropertyValue(listView, Checked, checked) case Items: - return listViewSetItems(view, value) + return listView.setItems(value) case ListItemStyle, CurrentStyle, CurrentInactiveStyle: if text, ok := value.(string); ok { - return setStringPropertyValue(view, tag, text) + return setStringPropertyValue(listView, tag, text) } notCompatibleType(tag, value) return nil case Current: - return setIntProperty(view, Current, value) + return setIntProperty(listView, Current, value) } - return viewSet(view, tag, value) + return listView.viewData.setFunc(tag, value) } -func listViewPropertyChanged(view View, tag PropertyName) { +func (listView *listViewData) propertyChanged(tag PropertyName) { switch tag { case Current: - updateInnerHTML(view.htmlID(), view.Session()) - if listeners := getEventListeners[ListView, int](view, nil, ListItemSelectedEvent); len(listeners) > 0 { - if listView, ok := view.(ListView); ok { - current := GetCurrent(view) - for _, listener := range listeners { - listener(listView, current) - } + updateInnerHTML(listView.htmlID(), listView.Session()) + if listeners := getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent); len(listeners) > 0 { + current := GetCurrent(listView) + for _, listener := range listeners { + listener(listView, current) } } case Checked: - updateInnerHTML(view.htmlID(), view.Session()) - if listeners := getEventListeners[ListView, []int](view, nil, ListItemCheckedEvent); len(listeners) > 0 { - if listView, ok := view.(ListView); ok { - checked := GetListViewCheckedItems(view) - for _, listener := range listeners { - listener(listView, checked) - } + updateInnerHTML(listView.htmlID(), listView.Session()) + if listeners := getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent); len(listeners) > 0 { + checked := GetListViewCheckedItems(listView) + for _, listener := range listeners { + listener(listView, checked) } } case Items, Orientation, ListWrap, ListRowGap, ListColumnGap, VerticalAlign, HorizontalAlign, Style, StyleDisabled, ItemWidth, ItemHeight, ItemHorizontalAlign, ItemVerticalAlign, ItemCheckbox, CheckboxHorizontalAlign, CheckboxVerticalAlign, ListItemStyle, AccentColor: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(listView.htmlID(), listView.Session()) case CurrentStyle: - view.Session().updateProperty(view.htmlID(), "data-focusitemstyle", listViewCurrentStyle(view)) - updateInnerHTML(view.htmlID(), view.Session()) + listView.Session().updateProperty(listView.htmlID(), "data-focusitemstyle", listViewCurrentStyle(listView)) + updateInnerHTML(listView.htmlID(), listView.Session()) case CurrentInactiveStyle: - view.Session().updateProperty(view.htmlID(), "data-bluritemstyle", listViewCurrentInactiveStyle(view)) - updateInnerHTML(view.htmlID(), view.Session()) + listView.Session().updateProperty(listView.htmlID(), "data-bluritemstyle", listViewCurrentInactiveStyle(listView)) + updateInnerHTML(listView.htmlID(), listView.Session()) default: - viewPropertyChanged(view, tag) + listView.viewData.propertyChanged(tag) } } -func (listView *listViewData) get(self View, tag PropertyName) any { +func (listView *listViewData) getFunc(tag PropertyName) any { switch tag { case Gap: if rowGap := GetListRowGap(listView); rowGap.Equal(GetListColumnGap(listView)) { @@ -313,16 +308,13 @@ func (listView *listViewData) get(self View, tag PropertyName) any { } return AutoSize() } - return viewGet(self, tag) + return listView.viewData.getFunc(tag) } -func listViewSetItems(properties Properties, value any) []PropertyName { +func (listView *listViewData) setItems(value any) []PropertyName { var adapter ListAdapter = nil - var session Session = nil - if view, ok := properties.(View); ok { - session = view.Session() - } + session := listView.session switch value := value.(type) { case []string: @@ -400,7 +392,7 @@ func listViewSetItems(properties Properties, value any) []PropertyName { return nil } - properties.setRaw(Items, adapter) + listView.setRaw(Items, adapter) return []PropertyName{Items} } @@ -951,7 +943,9 @@ func (listView *listViewData) handleCommand(self View, command PropertyName, dat } case "itemClick": - listView.onItemClick() + if number, ok := dataIntProperty(data, `number`); ok { + listView.onItemClick(number) + } default: return listView.viewData.handleCommand(self, command, data) @@ -962,7 +956,7 @@ func (listView *listViewData) handleCommand(self View, command PropertyName, dat func (listView *listViewData) handleCurrent(number int) { listView.properties[Current] = number - for _, listener := range getEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) { + for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) { listener(listView, number) } if listener, ok := listView.changeListener[Current]; ok { @@ -970,33 +964,37 @@ func (listView *listViewData) handleCurrent(number int) { } } -func (listView *listViewData) onItemClick() { - checkbox := GetListViewCheckbox(listView) - if checkbox == NoneCheckbox { +func (listView *listViewData) onItemClick(number int) { + + if IsDisabled(listView) { return } - if current := GetCurrent(listView); current >= 0 && !IsDisabled(listView) { + if current := GetCurrent(listView); current != number { + listView.Set(Current, number) + } + + if checkbox := GetListViewCheckbox(listView); checkbox != NoneCheckbox { checkedItem := GetListViewCheckedItems(listView) switch checkbox { case SingleCheckbox: if len(checkedItem) == 0 { - checkedItem = []int{current} - listView.updateCheckboxItem(current, true) - } else if checkedItem[0] != current { + checkedItem = []int{number} + listView.updateCheckboxItem(number, true) + } else if checkedItem[0] != number { listView.updateCheckboxItem(checkedItem[0], false) - checkedItem = []int{current} - listView.updateCheckboxItem(current, true) + checkedItem = []int{number} + listView.updateCheckboxItem(number, true) } else { checkedItem = []int{} - listView.updateCheckboxItem(current, false) + listView.updateCheckboxItem(number, false) } case MultipleCheckbox: uncheck := false for i, index := range checkedItem { - if index == current { + if index == number { uncheck = true listView.updateCheckboxItem(index, false) count := len(checkedItem) @@ -1014,8 +1012,8 @@ func (listView *listViewData) onItemClick() { } if !uncheck { - listView.updateCheckboxItem(current, true) - checkedItem = append(checkedItem, current) + listView.updateCheckboxItem(number, true) + checkedItem = append(checkedItem, number) } } @@ -1024,10 +1022,15 @@ func (listView *listViewData) onItemClick() { listener(listView, Checked) } - for _, listener := range getEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) { + for _, listener := range getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) { listener(listView, checkedItem) } } + + for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemClickedEvent) { + listener(listView, number) + } + } func (listView *listViewData) onItemResize(self View, index string, x, y, width, height float64) { @@ -1057,21 +1060,21 @@ func GetHorizontalAlign(view View, subviewID ...string) int { // 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. func GetListItemClickedListeners(view View, subviewID ...string) []func(ListView, int) { - return getEventListeners[ListView, int](view, subviewID, ListItemClickedEvent) + return getOneArgEventListeners[ListView, int](view, subviewID, ListItemClickedEvent) } // GetListItemSelectedListeners returns a ListItemSelectedListener of the ListView. // 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. func GetListItemSelectedListeners(view View, subviewID ...string) []func(ListView, int) { - return getEventListeners[ListView, int](view, subviewID, ListItemSelectedEvent) + return getOneArgEventListeners[ListView, int](view, subviewID, ListItemSelectedEvent) } // GetListItemCheckedListeners returns a ListItemCheckedListener of the ListView. // 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. func GetListItemCheckedListeners(view View, subviewID ...string) []func(ListView, []int) { - return getEventListeners[ListView, []int](view, subviewID, ListItemCheckedEvent) + return getOneArgEventListeners[ListView, []int](view, subviewID, ListItemCheckedEvent) } // GetListItemWidth returns the width of a ListView item. diff --git a/mediaPlayer.go b/mediaPlayer.go index 31f0d07..518b7a5 100644 --- a/mediaPlayer.go +++ b/mediaPlayer.go @@ -907,46 +907,39 @@ type MediaSource struct { func (player *mediaPlayerData) init(session Session) { player.viewData.init(session) player.tag = "MediaPlayer" - player.set = mediaPlayerSet - player.changed = mediaPlayerPropertyChanged + player.set = player.setFunc + player.changed = player.propertyChanged } func (player *mediaPlayerData) Focusable() bool { return true } -func mediaPlayerSet(view View, tag PropertyName, value any) []PropertyName { +func (player *mediaPlayerData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, LoadStartEvent, EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent: - return setNoParamEventListener[MediaPlayer](view, tag, value) + return setNoArgEventListener[MediaPlayer](player, tag, value) case DurationChangedEvent, RateChangedEvent, TimeUpdateEvent, VolumeChangedEvent: - return setViewEventListener[MediaPlayer, float64](view, tag, value) + return setOneArgEventListener[MediaPlayer, float64](player, tag, value) case PlayerErrorEvent: if listeners, ok := valueToPlayerErrorListeners(value); ok { - if len(listeners) > 0 { - view.setRaw(tag, listeners) - } else if view.getRaw(tag) != nil { - view.setRaw(tag, nil) - } else { - return []PropertyName{} - } - return []PropertyName{tag} + return setArrayPropertyValue(player, tag, listeners) } notCompatibleType(tag, value) return nil case Source: - return setMediaPlayerSource(view, value) + return setMediaPlayerSource(player, value) } - return viewSet(view, tag, value) + return player.viewData.setFunc(tag, value) } func setMediaPlayerSource(properties Properties, value any) []PropertyName { @@ -1151,26 +1144,26 @@ func mediaPlayerEvents() map[PropertyName]string { } } -func mediaPlayerPropertyChanged(view View, tag PropertyName) { - session := view.Session() +func (player *mediaPlayerData) propertyChanged(tag PropertyName) { + session := player.Session() switch tag { case Controls, Loop: - value, _ := boolProperty(view, tag, session) + value, _ := boolProperty(player, tag, session) if value { - session.updateProperty(view.htmlID(), string(tag), value) + session.updateProperty(player.htmlID(), string(tag), value) } else { - session.removeProperty(view.htmlID(), string(tag)) + session.removeProperty(player.htmlID(), string(tag)) } case Muted: - value, _ := boolProperty(view, Muted, session) - session.callFunc("setMediaMuted", view.htmlID(), value) + value, _ := boolProperty(player, Muted, session) + session.callFunc("setMediaMuted", player.htmlID(), value) case Preload: - value, _ := enumProperty(view, Preload, session, 0) + value, _ := enumProperty(player, Preload, session, 0) values := enumProperties[Preload].values - session.updateProperty(view.htmlID(), string(Preload), values[value]) + session.updateProperty(player.htmlID(), string(Preload), values[value]) case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, ProgressEvent, @@ -1178,54 +1171,54 @@ func mediaPlayerPropertyChanged(view View, tag PropertyName) { if cssTag, ok := mediaPlayerEvents()[tag]; ok { fn := "" - if value := view.getRaw(tag); value != nil { + if value := player.getRaw(tag); value != nil { if listeners, ok := value.([]func(MediaPlayer)); ok && len(listeners) > 0 { fn = fmt.Sprintf(`viewEvent(this, "%s")`, string(tag)) } } - session.updateProperty(view.htmlID(), cssTag, fn) + session.updateProperty(player.htmlID(), cssTag, fn) } case TimeUpdateEvent: - if value := view.getRaw(tag); value != nil { - session.updateProperty(view.htmlID(), "ontimeupdate", "viewTimeUpdatedEvent(this)") + if value := player.getRaw(tag); value != nil { + session.updateProperty(player.htmlID(), "ontimeupdate", "viewTimeUpdatedEvent(this)") } else { - session.updateProperty(view.htmlID(), "ontimeupdate", "") + session.updateProperty(player.htmlID(), "ontimeupdate", "") } case VolumeChangedEvent: - if value := view.getRaw(tag); value != nil { - session.updateProperty(view.htmlID(), "onvolumechange", "viewVolumeChangedEvent(this)") + if value := player.getRaw(tag); value != nil { + session.updateProperty(player.htmlID(), "onvolumechange", "viewVolumeChangedEvent(this)") } else { - session.updateProperty(view.htmlID(), "onvolumechange", "") + session.updateProperty(player.htmlID(), "onvolumechange", "") } case DurationChangedEvent: - if value := view.getRaw(tag); value != nil { - session.updateProperty(view.htmlID(), "ondurationchange", "viewDurationChangedEvent(this)") + if value := player.getRaw(tag); value != nil { + session.updateProperty(player.htmlID(), "ondurationchange", "viewDurationChangedEvent(this)") } else { - session.updateProperty(view.htmlID(), "ondurationchange", "") + session.updateProperty(player.htmlID(), "ondurationchange", "") } case RateChangedEvent: - if value := view.getRaw(tag); value != nil { - session.updateProperty(view.htmlID(), "onratechange", "viewRateChangedEvent(this)") + if value := player.getRaw(tag); value != nil { + session.updateProperty(player.htmlID(), "onratechange", "viewRateChangedEvent(this)") } else { - session.updateProperty(view.htmlID(), "onratechange", "") + session.updateProperty(player.htmlID(), "onratechange", "") } case PlayerErrorEvent: - if value := view.getRaw(tag); value != nil { - session.updateProperty(view.htmlID(), "onerror", "viewErrorEvent(this)") + if value := player.getRaw(tag); value != nil { + session.updateProperty(player.htmlID(), "onerror", "viewErrorEvent(this)") } else { - session.updateProperty(view.htmlID(), "onerror", "") + session.updateProperty(player.htmlID(), "onerror", "") } case Source: - updateInnerHTML(view.htmlID(), session) + updateInnerHTML(player.htmlID(), session) default: - viewPropertyChanged(view, tag) + player.viewData.propertyChanged(tag) } } diff --git a/mouseEvents.go b/mouseEvents.go index d65df31..836e5c7 100644 --- a/mouseEvents.go +++ b/mouseEvents.go @@ -230,7 +230,7 @@ type MouseEvent struct { /* func setMouseListener(properties Properties, tag PropertyName, value any) bool { - if listeners, ok := valueToEventListeners[View, MouseEvent](value); ok { + if listeners, ok := valueToOneArgEventListeners[View, MouseEvent](value); ok { if len(listeners) == 0 { properties.setRaw(tag, nil) } else { @@ -302,7 +302,7 @@ func (event *MouseEvent) init(data DataObject) { } func handleMouseEvents(view View, tag PropertyName, data DataObject) { - listeners := getEventListeners[View, MouseEvent](view, nil, tag) + listeners := getOneArgEventListeners[View, MouseEvent](view, nil, tag) if len(listeners) > 0 { var event MouseEvent event.init(data) @@ -316,48 +316,48 @@ func handleMouseEvents(view View, tag PropertyName, data DataObject) { // GetClickListeners returns the "click-event" listener list. 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. func GetClickListeners(view View, subviewID ...string) []func(View, MouseEvent) { - return getEventListeners[View, MouseEvent](view, subviewID, ClickEvent) + return getOneArgEventListeners[View, MouseEvent](view, subviewID, ClickEvent) } // GetDoubleClickListeners returns the "double-click-event" listener list. 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. func GetDoubleClickListeners(view View, subviewID ...string) []func(View, MouseEvent) { - return getEventListeners[View, MouseEvent](view, subviewID, DoubleClickEvent) + return getOneArgEventListeners[View, MouseEvent](view, subviewID, DoubleClickEvent) } // GetContextMenuListeners returns the "context-menu" listener list. // 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. func GetContextMenuListeners(view View, subviewID ...string) []func(View, MouseEvent) { - return getEventListeners[View, MouseEvent](view, subviewID, ContextMenuEvent) + return getOneArgEventListeners[View, MouseEvent](view, subviewID, ContextMenuEvent) } // GetMouseDownListeners returns the "mouse-down" listener list. 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. func GetMouseDownListeners(view View, subviewID ...string) []func(View, MouseEvent) { - return getEventListeners[View, MouseEvent](view, subviewID, MouseDown) + return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseDown) } // GetMouseUpListeners returns the "mouse-up" listener list. 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. func GetMouseUpListeners(view View, subviewID ...string) []func(View, MouseEvent) { - return getEventListeners[View, MouseEvent](view, subviewID, MouseUp) + return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseUp) } // GetMouseMoveListeners returns the "mouse-move" listener list. 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. func GetMouseMoveListeners(view View, subviewID ...string) []func(View, MouseEvent) { - return getEventListeners[View, MouseEvent](view, subviewID, MouseMove) + return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseMove) } // GetMouseOverListeners returns the "mouse-over" listener list. 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. func GetMouseOverListeners(view View, subviewID ...string) []func(View, MouseEvent) { - return getEventListeners[View, MouseEvent](view, subviewID, MouseOver) + return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseOver) } // GetMouseOutListeners returns the "mouse-out" listener list. 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. func GetMouseOutListeners(view View, subviewID ...string) []func(View, MouseEvent) { - return getEventListeners[View, MouseEvent](view, subviewID, MouseOut) + return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseOut) } diff --git a/numberPicker.go b/numberPicker.go index c4b5db0..501a207 100644 --- a/numberPicker.go +++ b/numberPicker.go @@ -1,6 +1,7 @@ package rui import ( + "fmt" "math" "strconv" "strings" @@ -79,6 +80,16 @@ const ( // // Internal type is `float`, other types converted to it during assignment. NumberPickerValue PropertyName = "number-picker-value" + + // NumberPickerValue is the constant for "number-picker-value" property tag. + // + // Used by `NumberPicker`. + // Precision of displaying fractional part in editor. The default value is 0 (not used). + // + // Supported types: `int`, `int8`...`int64`, `uint`, `uint8`...`uint64`, `string`. + // + // Internal type is `float`, other types converted to it during assignment. + NumberPickerPrecision PropertyName = "number-picker-precision" ) // Constants which describe values of the "number-picker-type" property of a [NumberPicker] @@ -116,8 +127,8 @@ func (picker *numberPickerData) init(session Session) { picker.tag = "NumberPicker" picker.hasHtmlDisabled = true picker.normalize = normalizeNumberPickerTag - picker.set = numberPickerSet - picker.changed = numberPickerPropertyChanged + picker.set = picker.setFunc + picker.changed = picker.propertyChanged } func (picker *numberPickerData) Focusable() bool { @@ -127,73 +138,83 @@ func (picker *numberPickerData) Focusable() bool { func normalizeNumberPickerTag(tag PropertyName) PropertyName { tag = defaultNormalize(tag) switch tag { - case Type, Min, Max, Step, Value: + case Type, Min, Max, Step, Value, "precision": return "number-picker-" + tag } return normalizeDataListTag(tag) } -func numberPickerSet(view View, tag PropertyName, value any) []PropertyName { +func (picker *numberPickerData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case NumberChangedEvent: - return setEventWithOldListener[NumberPicker, float64](view, tag, value) + return setTwoArgEventListener[NumberPicker, float64](picker, tag, value) case NumberPickerValue: - view.setRaw("old-number", GetNumberPickerValue(view)) - min, max := GetNumberPickerMinMax(view) + picker.setRaw("old-number", GetNumberPickerValue(picker)) + min, max := GetNumberPickerMinMax(picker) - return setFloatProperty(view, NumberPickerValue, value, min, max) + return setFloatProperty(picker, NumberPickerValue, value, min, max) case DataList: - return setDataList(view, value, "") + return setDataList(picker, value, "") } - return viewSet(view, tag, value) + return picker.viewData.setFunc(tag, value) } -func numberPickerPropertyChanged(view View, tag PropertyName) { +func (picker *numberPickerData) numberFormat() string { + if precission := GetNumberPickerPrecision(picker); precission > 0 { + return fmt.Sprintf("%%.%df", precission) + } + return "%g" +} + +func (picker *numberPickerData) propertyChanged(tag PropertyName) { switch tag { case NumberPickerType: - if GetNumberPickerType(view) == NumberSlider { - view.Session().updateProperty(view.htmlID(), "type", "range") + if GetNumberPickerType(picker) == NumberSlider { + picker.Session().updateProperty(picker.htmlID(), "type", "range") } else { - view.Session().updateProperty(view.htmlID(), "type", "number") + picker.Session().updateProperty(picker.htmlID(), "type", "number") } case NumberPickerMin: - min, _ := GetNumberPickerMinMax(view) - view.Session().updateProperty(view.htmlID(), "min", strconv.FormatFloat(min, 'f', -1, 32)) + min, _ := GetNumberPickerMinMax(picker) + picker.Session().updateProperty(picker.htmlID(), "min", fmt.Sprintf(picker.numberFormat(), min)) case NumberPickerMax: - _, max := GetNumberPickerMinMax(view) - view.Session().updateProperty(view.htmlID(), "max", strconv.FormatFloat(max, 'f', -1, 32)) + _, max := GetNumberPickerMinMax(picker) + picker.Session().updateProperty(picker.htmlID(), "max", fmt.Sprintf(picker.numberFormat(), max)) case NumberPickerStep: - if step := GetNumberPickerStep(view); step > 0 { - view.Session().updateProperty(view.htmlID(), "step", strconv.FormatFloat(step, 'f', -1, 32)) + if step := GetNumberPickerStep(picker); step > 0 { + picker.Session().updateProperty(picker.htmlID(), "step", fmt.Sprintf(picker.numberFormat(), step)) } else { - view.Session().updateProperty(view.htmlID(), "step", "any") + picker.Session().updateProperty(picker.htmlID(), "step", "any") } - case TimePickerValue: - value := GetNumberPickerValue(view) - view.Session().callFunc("setInputValue", view.htmlID(), value) + case NumberPickerValue: + value := GetNumberPickerValue(picker) + format := picker.numberFormat() + picker.Session().callFunc("setInputValue", picker.htmlID(), fmt.Sprintf(format, value)) - if listeners := GetNumberChangedListeners(view); len(listeners) > 0 { + if listeners := GetNumberChangedListeners(picker); len(listeners) > 0 { old := 0.0 - if val := view.getRaw("old-number"); val != nil { + if val := picker.getRaw("old-number"); val != nil { if n, ok := val.(float64); ok { old = n } } - for _, listener := range listeners { - listener(view, value, old) + if old != value { + for _, listener := range listeners { + listener(picker, value, old) + } } } default: - viewPropertyChanged(view, tag) + picker.viewData.propertyChanged(tag) } } @@ -217,30 +238,31 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde buffer.WriteString(` type="number"`) } + format := picker.numberFormat() min, max := GetNumberPickerMinMax(picker) if min != math.Inf(-1) { buffer.WriteString(` min="`) - buffer.WriteString(strconv.FormatFloat(min, 'f', -1, 64)) + buffer.WriteString(fmt.Sprintf(format, min)) buffer.WriteByte('"') } if max != math.Inf(1) { buffer.WriteString(` max="`) - buffer.WriteString(strconv.FormatFloat(max, 'f', -1, 64)) + buffer.WriteString(fmt.Sprintf(format, max)) buffer.WriteByte('"') } step := GetNumberPickerStep(picker) if step != 0 { buffer.WriteString(` step="`) - buffer.WriteString(strconv.FormatFloat(step, 'f', -1, 64)) + buffer.WriteString(fmt.Sprintf(format, step)) buffer.WriteByte('"') } else { buffer.WriteString(` step="any"`) } buffer.WriteString(` value="`) - buffer.WriteString(strconv.FormatFloat(GetNumberPickerValue(picker), 'f', -1, 64)) + buffer.WriteString(fmt.Sprintf(format, GetNumberPickerValue(picker))) buffer.WriteByte('"') buffer.WriteString(` oninput="editViewInputEvent(this)"`) @@ -342,5 +364,11 @@ func GetNumberPickerValue(view View, subviewID ...string) float64 { // 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. func GetNumberChangedListeners(view View, subviewID ...string) []func(NumberPicker, float64, float64) { - return getEventWithOldListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent) + return getTwoArgEventListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent) +} + +// GetNumberPickerPrecision returns the precision of displaying fractional part in editor 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 GetNumberPickerPrecision(view View, subviewID ...string) int { + return intStyledProperty(view, subviewID, NumberPickerPrecision, 0) } diff --git a/pointerEvents.go b/pointerEvents.go index 30cb1c7..c4d33a3 100644 --- a/pointerEvents.go +++ b/pointerEvents.go @@ -156,7 +156,7 @@ type PointerEvent struct { /* func setPointerListener(properties Properties, tag PropertyName, value any) bool { - if listeners, ok := valueToEventListeners[View, PointerEvent](value); ok { + if listeners, ok := valueToOneArgEventListeners[View, PointerEvent](value); ok { if len(listeners) == 0 { properties.setRaw(tag, nil) } else { @@ -210,7 +210,7 @@ func (event *PointerEvent) init(data DataObject) { } func handlePointerEvents(view View, tag PropertyName, data DataObject) { - listeners := getEventListeners[View, PointerEvent](view, nil, tag) + listeners := getOneArgEventListeners[View, PointerEvent](view, nil, tag) if len(listeners) == 0 { return } @@ -226,35 +226,35 @@ func handlePointerEvents(view View, tag PropertyName, data DataObject) { // GetPointerDownListeners returns the "pointer-down" listener list. 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. func GetPointerDownListeners(view View, subviewID ...string) []func(View, PointerEvent) { - return getEventListeners[View, PointerEvent](view, subviewID, PointerDown) + return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerDown) } // GetPointerUpListeners returns the "pointer-up" listener list. 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. func GetPointerUpListeners(view View, subviewID ...string) []func(View, PointerEvent) { - return getEventListeners[View, PointerEvent](view, subviewID, PointerUp) + return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerUp) } // GetPointerMoveListeners returns the "pointer-move" listener list. 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. func GetPointerMoveListeners(view View, subviewID ...string) []func(View, PointerEvent) { - return getEventListeners[View, PointerEvent](view, subviewID, PointerMove) + return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerMove) } // GetPointerCancelListeners returns the "pointer-cancel" listener list. 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. func GetPointerCancelListeners(view View, subviewID ...string) []func(View, PointerEvent) { - return getEventListeners[View, PointerEvent](view, subviewID, PointerCancel) + return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerCancel) } // GetPointerOverListeners returns the "pointer-over" listener list. 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. func GetPointerOverListeners(view View, subviewID ...string) []func(View, PointerEvent) { - return getEventListeners[View, PointerEvent](view, subviewID, PointerOver) + return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerOver) } // GetPointerOutListeners returns the "pointer-out" listener list. 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. func GetPointerOutListeners(view View, subviewID ...string) []func(View, PointerEvent) { - return getEventListeners[View, PointerEvent](view, subviewID, PointerOut) + return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerOut) } diff --git a/popup.go b/popup.go index c35a219..24af20a 100644 --- a/popup.go +++ b/popup.go @@ -560,7 +560,7 @@ func (popup *popupData) init(view View, popupParams Params) { } case DismissEvent: - if listeners, ok := valueToNoParamListeners[Popup](value); ok { + if listeners, ok := valueToNoArgEventListeners[Popup](value); ok { if listeners != nil { popup.dismissListener = listeners } diff --git a/progressBar.go b/progressBar.go index b3009fc..04b3027 100644 --- a/progressBar.go +++ b/progressBar.go @@ -53,7 +53,7 @@ func (progress *progressBarData) init(session Session) { progress.viewData.init(session) progress.tag = "ProgressBar" progress.normalize = normalizeProgressBarTag - progress.changed = progressBarPropertyChanged + progress.changed = progress.propertyChanged } func normalizeProgressBarTag(tag PropertyName) PropertyName { @@ -68,19 +68,19 @@ func normalizeProgressBarTag(tag PropertyName) PropertyName { return tag } -func progressBarPropertyChanged(view View, tag PropertyName) { +func (progress *progressBarData) propertyChanged(tag PropertyName) { switch tag { case ProgressBarMax: - view.Session().updateProperty(view.htmlID(), "max", - strconv.FormatFloat(GetProgressBarMax(view), 'f', -1, 32)) + progress.Session().updateProperty(progress.htmlID(), "max", + strconv.FormatFloat(GetProgressBarMax(progress), 'f', -1, 32)) case ProgressBarValue: - view.Session().updateProperty(view.htmlID(), "value", - strconv.FormatFloat(GetProgressBarValue(view), 'f', -1, 32)) + progress.Session().updateProperty(progress.htmlID(), "value", + strconv.FormatFloat(GetProgressBarValue(progress), 'f', -1, 32)) default: - viewPropertyChanged(view, tag) + progress.viewData.propertyChanged(tag) } } diff --git a/propertySet.go b/propertySet.go index be89100..7b18683 100644 --- a/propertySet.go +++ b/propertySet.go @@ -19,6 +19,7 @@ var colorProperties = []PropertyName{ OutlineColor, TextLineColor, ColorPickerValue, + AccentColor, } func isPropertyInList(tag PropertyName, list []PropertyName) bool { @@ -74,6 +75,7 @@ var intProperties = []PropertyName{ Order, TabIndex, MaxLength, + NumberPickerPrecision, } var floatProperties = map[PropertyName]struct{ min, max float64 }{ @@ -136,9 +138,9 @@ var sizeProperties = map[PropertyName]string{ Perspective: string(Perspective), PerspectiveOriginX: string(PerspectiveOriginX), PerspectiveOriginY: string(PerspectiveOriginY), - OriginX: string(OriginX), - OriginY: string(OriginY), - OriginZ: string(OriginZ), + TransformOriginX: string(TransformOriginX), + TransformOriginY: string(TransformOriginY), + TransformOriginZ: string(TransformOriginZ), Radius: string(Radius), RadiusX: string(RadiusX), RadiusY: string(RadiusY), diff --git a/resizable.go b/resizable.go index 9767908..f9815cb 100644 --- a/resizable.go +++ b/resizable.go @@ -80,8 +80,8 @@ func (resizable *resizableData) init(session Session) { resizable.viewData.init(session) resizable.tag = "Resizable" resizable.systemClass = "ruiGridLayout" - resizable.set = resizableSet - resizable.changed = resizablePropertyChanged + resizable.set = resizable.setFunc + resizable.changed = resizable.propertyChanged } func (resizable *resizableData) Views() []View { @@ -100,25 +100,25 @@ func (resizable *resizableData) content() View { return nil } -func resizableSet(view View, tag PropertyName, value any) []PropertyName { +func (resizable *resizableData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Side: - return resizableSetSide(view, value) + return resizableSetSide(resizable, value) case ResizeBorderWidth: - return setSizeProperty(view, tag, value) + return setSizeProperty(resizable, tag, value) case Content: var newContent View = nil switch value := value.(type) { case string: - newContent = NewTextView(view.Session(), Params{Text: value}) + newContent = NewTextView(resizable.Session(), Params{Text: value}) case View: newContent = value case DataObject: - if newContent = CreateViewFromObject(view.Session(), value); newContent == nil { + if newContent = CreateViewFromObject(resizable.Session(), value); newContent == nil { return nil } @@ -127,7 +127,7 @@ func resizableSet(view View, tag PropertyName, value any) []PropertyName { return nil } - view.setRaw(Content, newContent) + resizable.setRaw(Content, newContent) return []PropertyName{} case CellWidth, CellHeight, GridRowGap, GridColumnGap, CellVerticalAlign, CellHorizontalAlign: @@ -135,28 +135,28 @@ func resizableSet(view View, tag PropertyName, value any) []PropertyName { return nil } - return viewSet(view, tag, value) + return resizable.viewData.setFunc(tag, value) } -func resizablePropertyChanged(view View, tag PropertyName) { +func (resizable *resizableData) propertyChanged(tag PropertyName) { switch tag { case Side: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(resizable.htmlID(), resizable.Session()) fallthrough case ResizeBorderWidth: - htmlID := view.htmlID() - session := view.Session() - column, row := resizableCellSizeCSS(view) + htmlID := resizable.htmlID() + session := resizable.Session() + column, row := resizableCellSizeCSS(resizable) session.updateCSSProperty(htmlID, "grid-template-columns", column) session.updateCSSProperty(htmlID, "grid-template-rows", row) case Content: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(resizable.htmlID(), resizable.Session()) default: - viewPropertyChanged(view, tag) + resizable.viewData.propertyChanged(tag) } } diff --git a/resizeEvent.go b/resizeEvent.go index ec39ee0..3096105 100644 --- a/resizeEvent.go +++ b/resizeEvent.go @@ -33,7 +33,7 @@ func (view *viewData) onItemResize(self View, index string, x, y, width, height /* func setFrameListener(properties Properties, tag PropertyName, value any) bool { - if listeners, ok := valueToEventListeners[View, Frame](value); ok { + if listeners, ok := valueToOneArgEventListeners[View, Frame](value); ok { if len(listeners) == 0 { properties.setRaw(tag, nil) } else { @@ -85,5 +85,5 @@ func GetViewFrame(view View, subviewID ...string) Frame { // GetResizeListeners returns the list of "resize-event" listeners. If there are no listeners then the empty list is returned // If the second argument (subviewID) is not specified or it is "" then the listeners list of the first argument (view) is returned func GetResizeListeners(view View, subviewID ...string) []func(View, Frame) { - return getEventListeners[View, Frame](view, subviewID, ResizeEvent) + return getOneArgEventListeners[View, Frame](view, subviewID, ResizeEvent) } diff --git a/scrollEvent.go b/scrollEvent.go index 6c66d57..f6c276d 100644 --- a/scrollEvent.go +++ b/scrollEvent.go @@ -54,7 +54,7 @@ func GetViewScroll(view View, subviewID ...string) Frame { // GetScrollListeners returns the list of "scroll-event" listeners. If there are no listeners then the empty list is returned // If the second argument (subviewID) is not specified or it is "" then the listeners list of the first argument (view) is returned func GetScrollListeners(view View, subviewID ...string) []func(View, Frame) { - return getEventListeners[View, Frame](view, subviewID, ResizeEvent) + return getOneArgEventListeners[View, Frame](view, subviewID, ResizeEvent) } // ScrollTo scrolls the view's content to the given position. diff --git a/stackLayout.go b/stackLayout.go index e4fcb78..020b9b1 100644 --- a/stackLayout.go +++ b/stackLayout.go @@ -81,9 +81,10 @@ func (layout *stackLayoutData) init(session Session) { layout.tag = "StackLayout" layout.systemClass = "ruiStackLayout" layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished} - layout.getFunc = layout.get + layout.get = layout.getFunc layout.set = layout.setFunc layout.remove = layout.removeFunc + layout.changed = layout.propertyChanged } func (layout *stackLayoutData) pushFinished(view View, tag string) { @@ -121,14 +122,14 @@ func (layout *stackLayoutData) popFinished(view View, tag string) { } } -func (layout *stackLayoutData) setFunc(view View, tag PropertyName, value any) []PropertyName { +func (layout *stackLayoutData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case TransitionEndEvent: - listeners, ok := valueToEventListeners[View, string](value) + listeners, ok := valueToOneArgEventListeners[View, string](value) if ok && listeners != nil { listeners = append(listeners, layout.pushFinished) listeners = append(listeners, layout.popFinished) - view.setRaw(TransitionEndEvent, listeners) + layout.setRaw(TransitionEndEvent, listeners) return []PropertyName{tag} } return nil @@ -170,42 +171,42 @@ func (layout *stackLayoutData) setFunc(view View, tag PropertyName, value any) [ layout.peek = newCurrent return []PropertyName{tag} } - return layout.viewsContainerData.setFunc(view, tag, value) + return layout.viewsContainerData.setFunc(tag, value) } -func (layout *stackLayoutData) propertyChanged(view View, tag PropertyName) { +func (layout *stackLayoutData) propertyChanged(tag PropertyName) { switch tag { case Current: if layout.prevPeek != layout.peek { if layout.prevPeek < len(layout.views) { layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(layout.prevPeek), "visibility", "hidden") } - layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(layout.prevPeek), "visibility", "visible") + layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(layout.peek), "visibility", "visible") layout.prevPeek = layout.peek } default: - viewsContainerPropertyChanged(view, tag) + layout.viewsContainerData.propertyChanged(tag) } } -func (layout *stackLayoutData) removeFunc(view View, tag PropertyName) []PropertyName { +func (layout *stackLayoutData) removeFunc(tag PropertyName) []PropertyName { switch tag { case TransitionEndEvent: - view.setRaw(TransitionEndEvent, []func(View, string){layout.pushFinished, layout.popFinished}) + layout.setRaw(TransitionEndEvent, []func(View, string){layout.pushFinished, layout.popFinished}) return []PropertyName{tag} case Current: - view.setRaw(Current, 0) + layout.setRaw(Current, 0) return []PropertyName{tag} } - return layout.viewsContainerData.removeFunc(view, tag) + return layout.viewsContainerData.removeFunc(tag) } -func (layout *stackLayoutData) get(view View, tag PropertyName) any { +func (layout *stackLayoutData) getFunc(tag PropertyName) any { if tag == Current { return layout.peek } - return layout.viewsContainerData.get(view, tag) + return layout.viewsContainerData.getFunc(tag) } func (layout *stackLayoutData) Peek() View { diff --git a/svgImageView.go b/svgImageView.go index 96132ae..8b650a4 100644 --- a/svgImageView.go +++ b/svgImageView.go @@ -34,8 +34,8 @@ func (imageView *svgImageViewData) init(session Session) { imageView.tag = "SvgImageView" imageView.systemClass = "ruiSvgImageView" imageView.normalize = normalizeSvgImageViewTag - imageView.set = svgImageViewSet - imageView.changed = svgImageViewPropertyChanged + imageView.set = imageView.setFunc + imageView.changed = imageView.propertyChanged } @@ -54,28 +54,28 @@ func normalizeSvgImageViewTag(tag PropertyName) PropertyName { return tag } -func svgImageViewSet(view View, tag PropertyName, value any) []PropertyName { +func (imageView *svgImageViewData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Content: if text, ok := value.(string); ok { - view.setRaw(Content, text) + imageView.setRaw(Content, text) return []PropertyName{tag} } notCompatibleType(Source, value) return nil default: - return viewSet(view, tag, value) + return imageView.viewData.setFunc(tag, value) } } -func svgImageViewPropertyChanged(view View, tag PropertyName) { +func (imageView *svgImageViewData) propertyChanged(tag PropertyName) { switch tag { case Content: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(imageView.htmlID(), imageView.Session()) default: - viewPropertyChanged(view, tag) + imageView.viewData.propertyChanged(tag) } } diff --git a/tableView.go b/tableView.go index a1ef62d..b9eed8f 100644 --- a/tableView.go +++ b/tableView.go @@ -593,8 +593,8 @@ func (table *tableViewData) init(session Session) { table.current.Column = -1 */ table.normalize = normalizeTableViewTag - table.set = tableViewSet - table.changed = tableViewPropertyChanged + table.set = table.setFunc + table.changed = table.propertyChanged } func normalizeTableViewTag(tag PropertyName) PropertyName { @@ -618,7 +618,7 @@ func (table *tableViewData) Focusable() bool { return GetTableSelectionMode(table) != NoneSelection } -func tableViewSet(view View, tag PropertyName, value any) []PropertyName { +func (table *tableViewData) setFunc(tag PropertyName, value any) []PropertyName { setLineStyle := func() []PropertyName { params := []Params{} @@ -637,9 +637,9 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { if len(params) > 0 { style := new(simpleTableLineStyle) style.params = params - view.setRaw(tag, style) - } else if view.getRaw(tag) != nil { - view.setRaw(tag, nil) + table.setRaw(tag, style) + } else if table.getRaw(tag) != nil { + table.setRaw(tag, nil) } else { return []PropertyName{} } @@ -650,13 +650,13 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { case Content: switch val := value.(type) { case TableAdapter: - view.setRaw(Content, value) + table.setRaw(Content, value) case [][]any: - view.setRaw(Content, NewSimpleTableAdapter(val)) + table.setRaw(Content, NewSimpleTableAdapter(val)) case [][]string: - view.setRaw(Content, NewTextTableAdapter(val)) + table.setRaw(Content, NewTextTableAdapter(val)) default: notCompatibleType(tag, value) @@ -665,14 +665,14 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { return []PropertyName{tag} case TableCellClickedEvent, TableCellSelectedEvent: - return setEventWithOldListener[TableView, int](view, tag, value) + return setTwoArgEventListener[TableView, int](table, tag, value) case TableRowClickedEvent, TableRowSelectedEvent: - return setViewEventListener[TableView, int](view, tag, value) + return setOneArgEventListener[TableView, int](table, tag, value) case CellStyle: if style, ok := value.(TableCellStyle); ok { - view.setRaw(tag, style) + table.setRaw(tag, style) return []PropertyName{tag} } notCompatibleType(tag, value) @@ -680,14 +680,14 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { case RowStyle: if style, ok := value.(TableRowStyle); ok { - view.setRaw(tag, style) + table.setRaw(tag, style) return []PropertyName{tag} } return setLineStyle() case ColumnStyle: if style, ok := value.(TableColumnStyle); ok { - view.setRaw(tag, style) + table.setRaw(tag, style) return []PropertyName{tag} } return setLineStyle() @@ -696,9 +696,9 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { switch value := value.(type) { case string: if isConstantName(value) { - view.setRaw(tag, value) + table.setRaw(tag, value) } else if n, err := strconv.Atoi(value); err == nil { - view.setRaw(tag, n) + table.setRaw(tag, n) } else { ErrorLog(err.Error()) notCompatibleType(tag, value) @@ -707,7 +707,7 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { default: if n, ok := isInt(value); ok { - view.setRaw(tag, n) + table.setRaw(tag, n) } else { notCompatibleType(tag, value) return nil @@ -718,13 +718,13 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { case HeadStyle, FootStyle: switch value := value.(type) { case string: - view.setRaw(tag, value) + table.setRaw(tag, value) case Params: if len(value) > 0 { - view.setRaw(tag, value) - } else if view.getRaw(tag) != nil { - view.setRaw(tag, nil) + table.setRaw(tag, value) + } else if table.getRaw(tag) != nil { + table.setRaw(tag, nil) } else { return []PropertyName{} } @@ -736,15 +736,15 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { params[PropertyName(prop.Tag())] = prop.Text() } } - return tableViewSet(view, tag, params) + return table.setFunc(tag, params) case DataNode: switch value.Type() { case ObjectNode: - return tableViewSet(view, tag, value.Object()) + return table.setFunc(tag, value.Object()) case TextNode: - view.setRaw(tag, value.Text()) + table.setRaw(tag, value.Text()) default: notCompatibleType(tag, value) @@ -760,10 +760,10 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { case AllowSelection: switch value.(type) { case TableAllowCellSelection: - view.setRaw(tag, value) + table.setRaw(tag, value) case TableAllowRowSelection: - view.setRaw(tag, value) + table.setRaw(tag, value) default: notCompatibleType(tag, value) @@ -819,17 +819,17 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName { return nil } } - view.setRaw(Current, current) + table.setRaw(Current, current) return []PropertyName{tag} } - return viewSet(view, tag, value) + return table.viewData.setFunc(tag, value) } -func tableViewPropertyChanged(view View, tag PropertyName) { +func (table *tableViewData) propertyChanged(tag PropertyName) { - htmlID := view.htmlID() - session := view.Session() + htmlID := table.htmlID() + session := table.Session() switch tag { case Content, TableVerticalAlign, RowStyle, ColumnStyle, CellStyle, CellPadding, @@ -837,20 +837,20 @@ func tableViewPropertyChanged(view View, tag PropertyName) { CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft, TableCellClickedEvent, TableCellSelectedEvent, TableRowClickedEvent, TableRowSelectedEvent, AllowSelection, AccentColor: - ReloadTableViewData(view) + ReloadTableViewData(table) case Current: - switch GetTableSelectionMode(view) { + switch GetTableSelectionMode(table) { case CellSelection: - current := tableViewCurrent(view) + current := tableViewCurrent(table) session.callFunc("setTableCellCursorByID", htmlID, current.Row, current.Column) case RowSelection: - session.callFunc("setTableRowCursorByID", htmlID, tableViewCurrent(view).Row) + session.callFunc("setTableRowCursorByID", htmlID, tableViewCurrent(table).Row) } case Gap: - gap, ok := sizeProperty(view, Gap, session) + gap, ok := sizeProperty(table, Gap, session) if !ok || gap.Type == Auto || gap.Value <= 0 { session.updateCSSProperty(htmlID, "border-spacing", "0") session.updateCSSProperty(htmlID, "border-collapse", "collapse") @@ -860,43 +860,43 @@ func tableViewPropertyChanged(view View, tag PropertyName) { } case SelectionMode: - switch GetTableSelectionMode(view) { + switch GetTableSelectionMode(table) { case CellSelection: - tabIndex, _ := intProperty(view, TabIndex, session, 0) + tabIndex, _ := intProperty(table, TabIndex, session, 0) session.updateProperty(htmlID, "tabindex", tabIndex) session.updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)") session.updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)") session.updateProperty(htmlID, "data-selection", "cell") - session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(view)) - session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(view)) + session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(table)) + session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(table)) - current := tableViewCurrent(view) + current := tableViewCurrent(table) if current.Row >= 0 && current.Column >= 0 { - session.updateProperty(htmlID, "data-current", tableViewCellID(view, current.Row, current.Column)) + session.updateProperty(htmlID, "data-current", tableViewCellID(table, current.Row, current.Column)) } else { session.removeProperty(htmlID, "data-current") } session.updateProperty(htmlID, "onkeydown", "tableViewCellKeyDownEvent(this, event)") case RowSelection: - tabIndex, _ := intProperty(view, TabIndex, session, 0) + tabIndex, _ := intProperty(table, TabIndex, session, 0) session.updateProperty(htmlID, "tabindex", tabIndex) session.updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)") session.updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)") session.updateProperty(htmlID, "data-selection", "row") - session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(view)) - session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(view)) + session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(table)) + session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(table)) - current := tableViewCurrent(view) + current := tableViewCurrent(table) if current.Row >= 0 { - session.updateProperty(htmlID, "data-current", tableViewRowID(view, current.Row)) + session.updateProperty(htmlID, "data-current", tableViewRowID(table, current.Row)) } else { session.removeProperty(htmlID, "data-current") } session.updateProperty(htmlID, "onkeydown", "tableViewRowKeyDownEvent(this, event)") default: // NoneSelection - if tabIndex, ok := intProperty(view, TabIndex, session, -1); !ok || tabIndex < 0 { + if tabIndex, ok := intProperty(table, TabIndex, session, -1); !ok || tabIndex < 0 { session.removeProperty(htmlID, "tabindex") } @@ -907,7 +907,7 @@ func tableViewPropertyChanged(view View, tag PropertyName) { updateInnerHTML(htmlID, session) default: - viewPropertyChanged(view, tag) + table.viewData.propertyChanged(tag) } } diff --git a/tableViewUtils.go b/tableViewUtils.go index 09509bc..9e707d1 100644 --- a/tableViewUtils.go +++ b/tableViewUtils.go @@ -152,28 +152,28 @@ func GetTableCurrent(view View, subviewID ...string) CellIndex { // 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. func GetTableCellClickedListeners(view View, subviewID ...string) []func(TableView, int, int) { - return getEventWithOldListeners[TableView, int](view, subviewID, TableCellClickedEvent) + return getTwoArgEventListeners[TableView, int](view, subviewID, TableCellClickedEvent) } // GetTableCellSelectedListeners returns listeners of event which occurs when a table cell becomes selected. // 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. func GetTableCellSelectedListeners(view View, subviewID ...string) []func(TableView, int, int) { - return getEventWithOldListeners[TableView, int](view, subviewID, TableCellSelectedEvent) + return getTwoArgEventListeners[TableView, int](view, subviewID, TableCellSelectedEvent) } // GetTableRowClickedListeners returns listeners of event which occurs when the user clicks on a table row. // 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. func GetTableRowClickedListeners(view View, subviewID ...string) []func(TableView, int) { - return getEventListeners[TableView, int](view, subviewID, TableRowClickedEvent) + return getOneArgEventListeners[TableView, int](view, subviewID, TableRowClickedEvent) } // GetTableRowSelectedListeners returns listeners of event which occurs when a table row becomes selected. // 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. func GetTableRowSelectedListeners(view View, subviewID ...string) []func(TableView, int) { - return getEventListeners[TableView, int](view, subviewID, TableRowSelectedEvent) + return getOneArgEventListeners[TableView, int](view, subviewID, TableRowSelectedEvent) } // ReloadTableViewData updates TableView diff --git a/tabsLayout.go b/tabsLayout.go index 28bc7e6..c59f76c 100644 --- a/tabsLayout.go +++ b/tabsLayout.go @@ -168,69 +168,69 @@ func tabsLayoutCurrent(view View, defaultValue int) int { return result } -func (tabsLayout *tabsLayoutData) setFunc(view View, tag PropertyName, value any) []PropertyName { +func (tabsLayout *tabsLayoutData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case CurrentTabChangedEvent: - return setEventWithOldListener[TabsLayout, int](view, tag, value) + return setTwoArgEventListener[TabsLayout, int](tabsLayout, tag, value) case TabCloseEvent: - return setViewEventListener[TabsLayout, int](view, tag, value) + return setOneArgEventListener[TabsLayout, int](tabsLayout, tag, value) case Current: - view.setRaw("old-current", tabsLayoutCurrent(view, -1)) + tabsLayout.setRaw("old-current", tabsLayoutCurrent(tabsLayout, -1)) if current, ok := value.(int); ok && current < 0 { - view.setRaw(Current, nil) + tabsLayout.setRaw(Current, nil) return []PropertyName{tag} } - return setIntProperty(view, Current, value) + return setIntProperty(tabsLayout, Current, value) case TabStyle, CurrentTabStyle, TabBarStyle: if text, ok := value.(string); ok { - return setStringPropertyValue(view, tag, text) + return setStringPropertyValue(tabsLayout, tag, text) } notCompatibleType(tag, value) return nil } - return tabsLayout.viewsContainerData.setFunc(tabsLayout, tag, value) + return tabsLayout.viewsContainerData.setFunc(tag, value) } -func (tabsLayout *tabsLayoutData) propertyChanged(view View, tag PropertyName) { +func (tabsLayout *tabsLayoutData) propertyChanged(tag PropertyName) { switch tag { case Current: - session := view.Session() - current := GetCurrent(view) - session.callFunc("activateTab", view.htmlID(), current) + session := tabsLayout.Session() + current := GetCurrent(tabsLayout) + session.callFunc("activateTab", tabsLayout.htmlID(), current) - if listeners := getEventWithOldListeners[TabsLayout, int](view, nil, CurrentTabChangedEvent); len(listeners) > 0 { - oldCurrent, _ := intProperty(view, "old-current", session, -1) + if listeners := getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent); len(listeners) > 0 { + oldCurrent, _ := intProperty(tabsLayout, "old-current", session, -1) for _, listener := range listeners { listener(tabsLayout, current, oldCurrent) } } case Tabs: - htmlID := view.htmlID() - session := view.Session() - session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(view)) - session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(view)) + htmlID := tabsLayout.htmlID() + session := tabsLayout.Session() + session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(tabsLayout)) + session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(tabsLayout)) updateCSSStyle(htmlID, session) updateInnerHTML(htmlID, session) case TabStyle, CurrentTabStyle, TabBarStyle: - htmlID := view.htmlID() - session := view.Session() - session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(view)) - session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(view)) + htmlID := tabsLayout.htmlID() + session := tabsLayout.Session() + session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(tabsLayout)) + session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(tabsLayout)) updateInnerHTML(htmlID, session) case TabCloseButton: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session()) default: - viewsContainerPropertyChanged(view, tag) + tabsLayout.viewsContainerData.propertyChanged(tag) } } @@ -499,7 +499,7 @@ func (tabsLayout *tabsLayoutData) ListItem(index int, session Session) View { Column: 2, Content: "✕", ClickEvent: func() { - for _, listener := range getEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) { + for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) { listener(tabsLayout, index) } }, @@ -565,7 +565,7 @@ func (tabsLayout *tabsLayoutData) Insert(view View, index int) { if view != nil { if current := GetCurrent(tabsLayout); current >= index { tabsLayout.setRaw(Current, current+1) - defer tabsLayout.currentChanged() + defer tabsLayout.currentChanged(current+1, current) } tabsLayout.viewsContainerData.Insert(view, index) view.SetChangeListener(Title, tabsLayout.updateTitle) @@ -574,7 +574,10 @@ func (tabsLayout *tabsLayoutData) Insert(view View, index int) { } } -func (tabsLayout *tabsLayoutData) currentChanged() { +func (tabsLayout *tabsLayoutData) currentChanged(newCurrent, oldCurrent int) { + for _, listener := range getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) { + listener(tabsLayout, newCurrent, oldCurrent) + } if listener, ok := tabsLayout.changeListener[Current]; ok { listener(tabsLayout, Current) } @@ -600,7 +603,7 @@ func (tabsLayout *tabsLayoutData) RemoveView(index int) View { if newCurrent != oldCurrent { tabsLayout.setRaw(Current, newCurrent) - tabsLayout.currentChanged() + tabsLayout.currentChanged(newCurrent, oldCurrent) } } return nil @@ -871,10 +874,8 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName, current := GetCurrent(tabsLayout) if current != number { tabsLayout.setRaw(Current, number) - for _, listener := range getEventWithOldListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) { - listener(tabsLayout, number, current) - } - tabsLayout.currentChanged() + + tabsLayout.currentChanged(number, current) } } } @@ -883,7 +884,7 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName, case "tabCloseClick": if numberText, ok := data.PropertyValue("number"); ok { if number, err := strconv.Atoi(numberText); err == nil { - for _, listener := range getEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) { + for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) { listener(tabsLayout, number) } } diff --git a/textView.go b/textView.go index 374d46a..a21413f 100644 --- a/textView.go +++ b/textView.go @@ -30,63 +30,63 @@ func newTextView(session Session) View { func (textView *textViewData) init(session Session) { textView.viewData.init(session) textView.tag = "TextView" - textView.set = textViewSet - textView.changed = textViewPropertyChanged + textView.set = textView.setFunc + textView.changed = textView.propertyChanged } -func textViewPropertyChanged(view View, tag PropertyName) { +func (textView *textViewData) propertyChanged(tag PropertyName) { switch tag { case Text: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(textView.htmlID(), textView.Session()) case TextOverflow: - session := view.Session() - if n, ok := enumProperty(view, TextOverflow, session, 0); ok { + session := textView.Session() + if n, ok := enumProperty(textView, TextOverflow, session, 0); ok { values := enumProperties[TextOverflow].cssValues if n >= 0 && n < len(values) { - session.updateCSSProperty(view.htmlID(), string(TextOverflow), values[n]) + session.updateCSSProperty(textView.htmlID(), string(TextOverflow), values[n]) return } } - session.updateCSSProperty(view.htmlID(), string(TextOverflow), "") + session.updateCSSProperty(textView.htmlID(), string(TextOverflow), "") case NotTranslate: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(textView.htmlID(), textView.Session()) default: - viewPropertyChanged(view, tag) + textView.viewData.propertyChanged(tag) } } -func textViewSet(view View, tag PropertyName, value any) []PropertyName { +func (textView *textViewData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Text: switch value := value.(type) { case string: - view.setRaw(Text, value) + textView.setRaw(Text, value) case fmt.Stringer: - view.setRaw(Text, value.String()) + textView.setRaw(Text, value.String()) case float32: - view.setRaw(Text, fmt.Sprintf("%g", float64(value))) + textView.setRaw(Text, fmt.Sprintf("%g", float64(value))) case float64: - view.setRaw(Text, fmt.Sprintf("%g", value)) + textView.setRaw(Text, fmt.Sprintf("%g", value)) case []rune: - view.setRaw(Text, string(value)) + textView.setRaw(Text, string(value)) case bool: if value { - view.setRaw(Text, "true") + textView.setRaw(Text, "true") } else { - view.setRaw(Text, "false") + textView.setRaw(Text, "false") } default: if n, ok := isInt(value); ok { - view.setRaw(Text, fmt.Sprintf("%d", n)) + textView.setRaw(Text, fmt.Sprintf("%d", n)) } else { notCompatibleType(tag, value) return nil @@ -95,7 +95,7 @@ func textViewSet(view View, tag PropertyName, value any) []PropertyName { return []PropertyName{Text} } - return viewSet(view, tag, value) + return textView.viewData.setFunc(tag, value) } func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) { diff --git a/timePicker.go b/timePicker.go index 340b859..1e2956a 100644 --- a/timePicker.go +++ b/timePicker.go @@ -120,8 +120,8 @@ func (picker *timePickerData) init(session Session) { picker.tag = "TimePicker" picker.hasHtmlDisabled = true picker.normalize = normalizeTimePickerTag - picker.set = timePickerSet - picker.changed = timePickerPropertyChanged + picker.set = picker.setFunc + picker.changed = picker.propertyChanged } func (picker *timePickerData) Focusable() bool { @@ -167,22 +167,22 @@ func stringToTime(value string) (time.Time, bool) { return result, true } -func timePickerSet(view View, tag PropertyName, value any) []PropertyName { +func (picker *timePickerData) setFunc(tag PropertyName, value any) []PropertyName { setTimeValue := func(tag PropertyName) []PropertyName { switch value := value.(type) { case time.Time: - view.setRaw(tag, value) + picker.setRaw(tag, value) return []PropertyName{tag} case string: if isConstantName(value) { - view.setRaw(tag, value) + picker.setRaw(tag, value) return []PropertyName{tag} } if time, ok := stringToTime(value); ok { - view.setRaw(tag, time) + picker.setRaw(tag, time) return []PropertyName{tag} } } @@ -199,67 +199,67 @@ func timePickerSet(view View, tag PropertyName, value any) []PropertyName { return setTimeValue(TimePickerMax) case TimePickerStep: - return setIntProperty(view, TimePickerStep, value) + return setIntProperty(picker, TimePickerStep, value) case TimePickerValue: - view.setRaw("old-time", GetTimePickerValue(view)) + picker.setRaw("old-time", GetTimePickerValue(picker)) return setTimeValue(tag) case TimeChangedEvent: - return setEventWithOldListener[TimePicker, time.Time](view, tag, value) + return setTwoArgEventListener[TimePicker, time.Time](picker, tag, value) case DataList: - return setDataList(view, value, timeFormat) + return setDataList(picker, value, timeFormat) } - return viewSet(view, tag, value) + return picker.viewData.setFunc(tag, value) } -func timePickerPropertyChanged(view View, tag PropertyName) { +func (picker *timePickerData) propertyChanged(tag PropertyName) { - session := view.Session() + session := picker.Session() switch tag { case TimePickerMin: - if time, ok := GetTimePickerMin(view); ok { - session.updateProperty(view.htmlID(), "min", time.Format(timeFormat)) + if time, ok := GetTimePickerMin(picker); ok { + session.updateProperty(picker.htmlID(), "min", time.Format(timeFormat)) } else { - session.removeProperty(view.htmlID(), "min") + session.removeProperty(picker.htmlID(), "min") } case TimePickerMax: - if time, ok := GetTimePickerMax(view); ok { - session.updateProperty(view.htmlID(), "max", time.Format(timeFormat)) + if time, ok := GetTimePickerMax(picker); ok { + session.updateProperty(picker.htmlID(), "max", time.Format(timeFormat)) } else { - session.removeProperty(view.htmlID(), "max") + session.removeProperty(picker.htmlID(), "max") } case TimePickerStep: - if step := GetTimePickerStep(view); step > 0 { - session.updateProperty(view.htmlID(), "step", strconv.Itoa(step)) + if step := GetTimePickerStep(picker); step > 0 { + session.updateProperty(picker.htmlID(), "step", strconv.Itoa(step)) } else { - session.removeProperty(view.htmlID(), "step") + session.removeProperty(picker.htmlID(), "step") } case TimePickerValue: - value := GetTimePickerValue(view) - session.callFunc("setInputValue", view.htmlID(), value.Format(timeFormat)) + value := GetTimePickerValue(picker) + session.callFunc("setInputValue", picker.htmlID(), value.Format(timeFormat)) - if listeners := GetTimeChangedListeners(view); len(listeners) > 0 { + if listeners := GetTimeChangedListeners(picker); len(listeners) > 0 { oldTime := time.Now() - if val := view.getRaw("old-time"); val != nil { + if val := picker.getRaw("old-time"); val != nil { if time, ok := val.(time.Time); ok { oldTime = time } } for _, listener := range listeners { - listener(view, value, oldTime) + listener(picker, value, oldTime) } } default: - viewPropertyChanged(view, tag) + picker.viewData.propertyChanged(tag) } } @@ -420,5 +420,5 @@ func GetTimePickerValue(view View, subviewID ...string) time.Time { // 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. func GetTimeChangedListeners(view View, subviewID ...string) []func(TimePicker, time.Time, time.Time) { - return getEventWithOldListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent) + return getTwoArgEventListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent) } diff --git a/touchEvents.go b/touchEvents.go index f42f531..1b55ea0 100644 --- a/touchEvents.go +++ b/touchEvents.go @@ -144,7 +144,7 @@ type TouchEvent struct { /* func setTouchListener(properties Properties, tag PropertyName, value any) bool { - if listeners, ok := valueToEventListeners[View, TouchEvent](value); ok { + if listeners, ok := valueToOneArgEventListeners[View, TouchEvent](value); ok { if len(listeners) == 0 { properties.setRaw(tag, nil) } else { @@ -215,7 +215,7 @@ func (event *TouchEvent) init(data DataObject) { } func handleTouchEvents(view View, tag PropertyName, data DataObject) { - listeners := getEventListeners[View, TouchEvent](view, nil, tag) + listeners := getOneArgEventListeners[View, TouchEvent](view, nil, tag) if len(listeners) == 0 { return } @@ -231,23 +231,23 @@ func handleTouchEvents(view View, tag PropertyName, data DataObject) { // GetTouchStartListeners returns the "touch-start" listener list. 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. func GetTouchStartListeners(view View, subviewID ...string) []func(View, TouchEvent) { - return getEventListeners[View, TouchEvent](view, subviewID, TouchStart) + return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchStart) } // GetTouchEndListeners returns the "touch-end" listener list. 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. func GetTouchEndListeners(view View, subviewID ...string) []func(View, TouchEvent) { - return getEventListeners[View, TouchEvent](view, subviewID, TouchEnd) + return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchEnd) } // GetTouchMoveListeners returns the "touch-move" listener list. 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. func GetTouchMoveListeners(view View, subviewID ...string) []func(View, TouchEvent) { - return getEventListeners[View, TouchEvent](view, subviewID, TouchMove) + return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchMove) } // GetTouchCancelListeners returns the "touch-cancel" listener list. 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. func GetTouchCancelListeners(view View, subviewID ...string) []func(View, TouchEvent) { - return getEventListeners[View, TouchEvent](view, subviewID, TouchCancel) + return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchCancel) } diff --git a/videoPlayer.go b/videoPlayer.go index 97c828c..f78acdc 100644 --- a/videoPlayer.go +++ b/videoPlayer.go @@ -61,22 +61,22 @@ func newVideoPlayer(session Session) View { func (player *videoPlayerData) init(session Session) { player.mediaPlayerData.init(session) player.tag = "VideoPlayer" - player.changed = videoPlayerPropertyChanged + player.changed = player.propertyChanged } func (player *videoPlayerData) htmlTag() string { return "video" } -func videoPlayerPropertyChanged(view View, tag PropertyName) { +func (player *videoPlayerData) propertyChanged(tag PropertyName) { - session := view.Session() + session := player.Session() updateSize := func(cssTag string) { - if size, ok := floatTextProperty(view, tag, session, 0); ok { + if size, ok := floatTextProperty(player, tag, session, 0); ok { if size != "0" { - session.updateProperty(view.htmlID(), cssTag, size) + session.updateProperty(player.htmlID(), cssTag, size) } else { - session.removeProperty(view.htmlID(), cssTag) + session.removeProperty(player.htmlID(), cssTag) } } } @@ -89,14 +89,14 @@ func videoPlayerPropertyChanged(view View, tag PropertyName) { updateSize("height") case Poster: - if url, ok := stringProperty(view, Poster, session); ok { - session.updateProperty(view.htmlID(), string(Poster), url) + if url, ok := stringProperty(player, Poster, session); ok { + session.updateProperty(player.htmlID(), string(Poster), url) } else { - session.removeProperty(view.htmlID(), string(Poster)) + session.removeProperty(player.htmlID(), string(Poster)) } default: - mediaPlayerPropertyChanged(view, tag) + player.mediaPlayerData.propertyChanged(tag) } } diff --git a/view.go b/view.go index 9df8d37..655e10c 100644 --- a/view.go +++ b/view.go @@ -110,10 +110,10 @@ type viewData struct { created bool hasFocus bool hasHtmlDisabled bool - getFunc func(view View, tag PropertyName) any - set func(view View, tag PropertyName, value any) []PropertyName - remove func(view View, tag PropertyName) []PropertyName - changed func(view View, tag PropertyName) + get func(tag PropertyName) any + set func(tag PropertyName, value any) []PropertyName + remove func(tag PropertyName) []PropertyName + changed func(tag PropertyName) } func newView(session Session) View { @@ -145,10 +145,11 @@ func setInitParams(view View, params Params) { func (view *viewData) init(session Session) { view.viewStyle.init() - view.getFunc = viewGet - view.set = viewSet + view.get = view.getFunc + view.set = view.setFunc + view.remove = view.removeFunc view.normalize = normalizeViewTag - view.changed = viewPropertyChanged + view.changed = view.propertyChanged view.tag = "View" view.session = session view.changeListener = map[PropertyName]func(View, PropertyName){} @@ -213,35 +214,11 @@ func (view *viewData) Focusable() bool { } func (view *viewData) Remove(tag PropertyName) { - tag = view.normalize(tag) - var changedTags []PropertyName = nil - - switch tag { - case ID: - if view.viewID != "" { - view.viewID = "" - changedTags = []PropertyName{ID} - } - - case AnimationTag: - if val := view.getRaw(AnimationTag); val != nil { - if animations, ok := val.([]Animation); ok { - for _, animation := range animations { - animation.unused(view.session) - } - } - - view.setRaw(AnimationTag, nil) - changedTags = []PropertyName{AnimationTag} - } - - default: - changedTags = view.remove(view, tag) - } + changedTags := view.removeFunc(view.normalize(tag)) if view.created && len(changedTags) > 0 { for _, tag := range changedTags { - view.changed(view, tag) + view.changed(tag) } for _, tag := range changedTags { @@ -252,6 +229,15 @@ func (view *viewData) Remove(tag PropertyName) { } } +func (view *viewData) Get(tag PropertyName) any { + switch tag { + case ID: + return view.ID() + } + return view.get(view.normalize(tag)) + +} + func (view *viewData) Set(tag PropertyName, value any) bool { if value == nil { view.Remove(tag) @@ -259,42 +245,11 @@ func (view *viewData) Set(tag PropertyName, value any) bool { } tag = view.normalize(tag) - var changedTags []PropertyName = nil - - switch tag { - case ID: - text, ok := value.(string) - if !ok { - notCompatibleType(ID, value) - return false - } - view.viewID = text - changedTags = []PropertyName{ID} - - case AnimationTag: - oldAnimations := []Animation{} - if val := view.getRaw(AnimationTag); val != nil { - if animation, ok := val.([]Animation); ok { - oldAnimations = animation - } - } - - if !setAnimationProperty(view, tag, value) { - return false - } - - for _, animation := range oldAnimations { - animation.unused(view.session) - } - changedTags = []PropertyName{AnimationTag} - - default: - changedTags = viewSet(view, tag, value) - } + changedTags := view.set(tag, value) if view.created && len(changedTags) > 0 { for _, tag := range changedTags { - view.changed(view, tag) + view.changed(tag) } for _, tag := range changedTags { @@ -316,67 +271,78 @@ func normalizeViewTag(tag PropertyName) PropertyName { return tag } -/* -func (view *viewData) propertyChangedEvent(tag PropertyName) { - if listener, ok := view.changeListener[tag]; ok { - listener(view, tag) +func (view *viewData) getFunc(tag PropertyName) any { + if tag == ID { + if id := view.ID(); id != "" { + return id + } else { + return nil + } } + return viewStyleGet(view, tag) +} + +func (view *viewData) removeFunc(tag PropertyName) []PropertyName { + var changedTags []PropertyName = nil switch tag { - case BorderLeft, BorderRight, BorderTop, BorderBottom, - BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle, - BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor, - BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth: - tag = Border + case ID: + if view.viewID != "" { + view.viewID = "" + changedTags = []PropertyName{ID} + } else { + changedTags = []PropertyName{} + } - case CellBorderStyle, CellBorderColor, CellBorderWidth, - CellBorderLeft, CellBorderLeftStyle, CellBorderLeftColor, CellBorderLeftWidth, - CellBorderRight, CellBorderRightStyle, CellBorderRightColor, CellBorderRightWidth, - CellBorderTop, CellBorderTopStyle, CellBorderTopColor, CellBorderTopWidth, - CellBorderBottom, CellBorderBottomStyle, CellBorderBottomColor, CellBorderBottomWidth: - tag = CellBorder + case AnimationTag: + if val := view.getRaw(AnimationTag); val != nil { + if animations, ok := val.([]Animation); ok { + for _, animation := range animations { + animation.unused(view.session) + } + } - case OutlineColor, OutlineStyle, OutlineWidth: - tag = Outline - - case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY, - RadiusTopRight, RadiusTopRightX, RadiusTopRightY, - RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY, - RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY: - tag = Radius - - case MarginTop, MarginRight, MarginBottom, MarginLeft, - "top-margin", "right-margin", "bottom-margin", "left-margin": - tag = Margin - - case PaddingTop, PaddingRight, PaddingBottom, PaddingLeft, - "top-padding", "right-padding", "bottom-padding", "left-padding": - tag = Padding - - case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft: - tag = CellPadding - - case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor: - tag = ColumnSeparator + view.setRaw(AnimationTag, nil) + changedTags = []PropertyName{AnimationTag} + } default: - return + changedTags = viewStyleRemove(view, tag) } - if listener, ok := view.changeListener[tag]; ok { - listener(view, tag) - } -} -*/ - -func viewRemove(properties Properties, tag PropertyName) []PropertyName { - return viewStyleRemove(properties, tag) + return changedTags } -func viewSet(view View, tag PropertyName, value any) []PropertyName { +func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { + case ID: + if text, ok := value.(string); ok { + view.viewID = text + view.setRaw(ID, text) + return []PropertyName{ID} + } + notCompatibleType(ID, value) + return nil + + case AnimationTag: + oldAnimations := []Animation{} + if val := view.getRaw(AnimationTag); val != nil { + if animation, ok := val.([]Animation); ok { + oldAnimations = animation + } + } + + if !setAnimationProperty(view, tag, value) { + return nil + } + + for _, animation := range oldAnimations { + animation.unused(view.session) + } + return []PropertyName{AnimationTag} + case TabIndex, "tab-index": return setIntProperty(view, TabIndex, value) @@ -393,29 +359,46 @@ func viewSet(view View, tag PropertyName, value any) []PropertyName { return nil case FocusEvent, LostFocusEvent: - return setNoParamEventListener[View](view, tag, value) + return setNoArgEventListener[View](view, tag, value) case KeyDownEvent, KeyUpEvent: - return setViewEventListener[View, KeyEvent](view, tag, value) + return setOneArgEventListener[View, KeyEvent](view, tag, value) case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent: - return setViewEventListener[View, MouseEvent](view, tag, value) + return setOneArgEventListener[View, MouseEvent](view, tag, value) case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel: - return setViewEventListener[View, PointerEvent](view, tag, value) + return setOneArgEventListener[View, PointerEvent](view, tag, value) case TouchStart, TouchEnd, TouchMove, TouchCancel: - return setViewEventListener[View, TouchEvent](view, tag, value) + return setOneArgEventListener[View, TouchEvent](view, tag, value) - case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent, - AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent: - return setViewEventListener[View, string](view, tag, value) - //return setTransitionListener(view, tag, value), tag - //return setAnimationListener(view, tag, value), tag + case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent: + result := setOneArgEventListener[View, PropertyName](view, tag, value) + if result == nil { + result = setOneArgEventListener[View, string](view, tag, value) + if result != nil { + if listeners, ok := view.getRaw(tag).([]func(View, string)); ok { + newListeners := make([]func(View, PropertyName), len(listeners)) + for i, listener := range listeners { + newListeners[i] = func(view View, name PropertyName) { + listener(view, string(name)) + } + } + view.setRaw(tag, newListeners) + return result + } + view.setRaw(tag, nil) + return nil + } + } + return result + + case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent: + return setOneArgEventListener[View, string](view, tag, value) case ResizeEvent, ScrollEvent: - return setViewEventListener[View, Frame](view, tag, value) - //return setFrameListener(view, tag, value), tag + return setOneArgEventListener[View, Frame](view, tag, value) } return viewStyleSet(view, tag, value) @@ -439,12 +422,7 @@ func (view *viewData) SetParams(params Params) bool { return result } -func viewPropertyChanged(view View, tag PropertyName) { - /* - if view.updateTransformProperty(tag) { - return - } - */ +func (view *viewData) propertyChanged(tag PropertyName) { htmlID := view.htmlID() session := view.Session() @@ -645,9 +623,11 @@ func viewPropertyChanged(view View, tag PropertyName) { case Strikethrough, Overline, Underline: session.updateCSSProperty(htmlID, "text-decoration", textDecorationCSS(view, session)) - for _, tag2 := range []PropertyName{TextLineColor, TextLineStyle, TextLineThickness} { - viewPropertyChanged(view, tag2) - } + /* + for _, tag2 := range []PropertyName{TextLineColor, TextLineStyle, TextLineThickness} { + view.propertyChanged(tag2) + } + */ case Transition: session.updateCSSProperty(htmlID, "transition", transitionCSS(view, session)) @@ -711,34 +691,19 @@ func viewPropertyChanged(view View, tag PropertyName) { } case PerspectiveOriginX, PerspectiveOriginY: - if getTransform3D(view, session) { - x, y := GetPerspectiveOrigin(view) - value := "" - if x.Type != Auto || y.Type != Auto { - value = x.cssString("50%", session) + " " + y.cssString("50%", session) - } - session.updateCSSProperty(htmlID, "perspective-origin", value) - } + x, y := GetPerspectiveOrigin(view) + session.updateCSSProperty(htmlID, "perspective-origin", transformOriginCSS(x, y, AutoSize(), view.Session())) case BackfaceVisible: - if getTransform3D(view, session) { - if GetBackfaceVisible(view) { - session.updateCSSProperty(htmlID, string(BackfaceVisible), "visible") - } else { - session.updateCSSProperty(htmlID, string(BackfaceVisible), "hidden") - } + if GetBackfaceVisible(view) { + session.updateCSSProperty(htmlID, string(BackfaceVisible), "visible") + } else { + session.updateCSSProperty(htmlID, string(BackfaceVisible), "hidden") } - case OriginX, OriginY, OriginZ: - x, y, z := getOrigin(view, session) - value := "" - - if z.Type != Auto { - value = x.cssString("50%", session) + " " + y.cssString("50%", session) + " " + z.cssString("50%", session) - } else if x.Type != Auto || y.Type != Auto { - value = x.cssString("50%", session) + " " + y.cssString("50%", session) - } - session.updateCSSProperty(htmlID, "transform-origin", value) + case TransformOriginX, TransformOriginY, TransformOriginZ: + x, y, z := getTransformOrigin(view, session) + session.updateCSSProperty(htmlID, "transform-origin", transformOriginCSS(x, y, z, view.Session())) case TransformTag, Perspective, SkewX, SkewY, TranslateX, TranslateY, TranslateZ, ScaleX, ScaleY, ScaleZ, Rotate, RotateX, RotateY, RotateZ: @@ -803,17 +768,6 @@ func viewPropertyChanged(view View, tag PropertyName) { } } -func viewGet(view View, tag PropertyName) any { - if tag == ID { - if id := view.ID(); id != "" { - return id - } else { - return nil - } - } - return viewStyleGet(view, tag) -} - func (view *viewData) htmlTag() string { if semantics := GetSemantics(view); semantics > DefaultSemantics { values := enumProperties[Semantics].cssValues @@ -999,13 +953,13 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb case FocusEvent: view.hasFocus = true - for _, listener := range getNoParamEventListeners[View](view, nil, command) { + for _, listener := range getNoArgEventListeners[View](view, nil, command) { listener(self) } case LostFocusEvent: view.hasFocus = false - for _, listener := range getNoParamEventListeners[View](view, nil, command) { + for _, listener := range getNoArgEventListeners[View](view, nil, command) { listener(self) } diff --git a/viewStyle.go b/viewStyle.go index 18a7f3f..28b9afa 100644 --- a/viewStyle.go +++ b/viewStyle.go @@ -497,6 +497,16 @@ func normalizeViewStyleTag(tag PropertyName) PropertyName { case "left-padding": return PaddingLeft + + case "origin-x": + return TransformOriginX + + case "origin-y": + return TransformOriginY + + case "origin-z": + return TransformOriginZ + } return tag } @@ -868,7 +878,8 @@ func writeViewStyle(name string, view Properties, buffer *strings.Builder, inden } finalTags := []PropertyName{ - Perspective, PerspectiveOriginX, PerspectiveOriginY, BackfaceVisible, OriginX, OriginY, OriginZ, + PerspectiveOriginX, PerspectiveOriginY, BackfaceVisible, + TransformOriginX, TransformOriginY, TransformOriginZ, TransformTag, Clip, Filter, BackdropFilter, Summary, Content, Transition} for _, tag := range finalTags { removeTag(tag) diff --git a/viewTransform.go b/viewTransform.go index b19771f..5f6700c 100644 --- a/viewTransform.go +++ b/viewTransform.go @@ -79,7 +79,7 @@ const ( // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. - OriginX PropertyName = "origin-x" + TransformOriginX PropertyName = "transform-origin-x" // OriginY is the constant for "origin-y" property tag. // @@ -90,7 +90,7 @@ const ( // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. - OriginY PropertyName = "origin-y" + TransformOriginY PropertyName = "transform-origin-y" // OriginZ is the constant for "origin-z" property tag. // @@ -101,7 +101,7 @@ const ( // // Internal type is `SizeUnit`, other types converted to it during assignment. // See `SizeUnit` description for more details. - OriginZ PropertyName = "origin-z" + TransformOriginZ PropertyName = "transform-origin-z" // TranslateX is the constant for "translate-x" property tag. // @@ -527,29 +527,31 @@ func getTransformProperty(properties Properties) Transform { func setTransformPropertyElement(properties Properties, tag PropertyName, value any) []PropertyName { switch tag { case Perspective, RotateX, RotateY, RotateZ, Rotate, SkewX, SkewY, ScaleX, ScaleY, ScaleZ, TranslateX, TranslateY, TranslateZ: + var result []PropertyName = nil if transform := getTransformProperty(properties); transform != nil { - if result := transformSet(transform, tag, value); result != nil { + if result = transformSet(transform, tag, value); result != nil { result = append(result, TransformTag) } } else { transform := NewTransform(nil) - if result := transformSet(transform, tag, value); result != nil { + if result = transformSet(transform, tag, value); result != nil { properties.setRaw(TransformTag, transform) result = append(result, TransformTag) } } - - default: - ErrorLogF(`"Transform" interface does not support the "%s" property`, tag) + return result } + ErrorLogF(`"Transform" interface does not support the "%s" property`, tag) return nil } +/* func getTransform3D(style Properties, session Session) bool { perspective, ok := sizeProperty(style, Perspective, session) return ok && perspective.Type != Auto && perspective.Value != 0 } +*/ func getPerspectiveOrigin(style Properties, session Session) (SizeUnit, SizeUnit) { x, _ := sizeProperty(style, PerspectiveOriginX, session) @@ -557,10 +559,10 @@ func getPerspectiveOrigin(style Properties, session Session) (SizeUnit, SizeUnit return x, y } -func getOrigin(style Properties, session Session) (SizeUnit, SizeUnit, SizeUnit) { - x, _ := sizeProperty(style, OriginX, session) - y, _ := sizeProperty(style, OriginY, session) - z, _ := sizeProperty(style, OriginZ, session) +func getTransformOrigin(style Properties, session Session) (SizeUnit, SizeUnit, SizeUnit) { + x, _ := sizeProperty(style, TransformOriginX, session) + y, _ := sizeProperty(style, TransformOriginY, session) + z, _ := sizeProperty(style, TransformOriginZ, session) return x, y, z } @@ -674,8 +676,9 @@ func (transform *transformData) transformCSS(session Session) string { func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Session) { x, y := getPerspectiveOrigin(style, session) - if x.Type != Auto || y.Type != Auto { - builder.addValues(`perspective-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session)) + z := AutoSize() + if css := transformOriginCSS(x, y, z, session); css != "" { + builder.add(`perspective-origin`, css) } if backfaceVisible, ok := boolProperty(style, BackfaceVisible, session); ok { @@ -686,11 +689,9 @@ func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Sessio } } - x, y, z := getOrigin(style, session) - if z.Type != Auto && z.Value != 0 { - builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session), z.cssString("0", session)) - } else if x.Type != Auto || y.Type != Auto { - builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session)) + x, y, z = getTransformOrigin(style, session) + if css := transformOriginCSS(x, y, z, session); css != "" { + builder.add(`transform-origin`, css) } if transform := getTransformProperty(style); transform != nil { @@ -698,6 +699,56 @@ func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Sessio } } +func transformOriginCSS(x, y, z SizeUnit, session Session) string { + if z.Type == Auto && x.Type == Auto && y.Type == Auto { + return "" + } + + buffer := allocStringBuilder() + defer freeStringBuilder(buffer) + + if x.Type == SizeInPercent { + switch x.Value { + case 0: + buffer.WriteString("left") + case 50: + buffer.WriteString("center") + case 100: + buffer.WriteString("right") + + default: + buffer.WriteString(x.cssString("center", session)) + } + } else { + buffer.WriteString(x.cssString("center", session)) + } + + buffer.WriteRune(' ') + + if y.Type == SizeInPercent { + switch y.Value { + case 0: + buffer.WriteString("top") + case 50: + buffer.WriteString("center") + case 100: + buffer.WriteString("bottom") + + default: + buffer.WriteString(y.cssString("center", session)) + } + } else { + buffer.WriteString(y.cssString("center", session)) + } + + if z.Type != Auto && z.Value != 0 { + buffer.WriteRune(' ') + buffer.WriteString(z.cssString("0", session)) + } + + return buffer.String() +} + /* func (view *viewData) updateTransformProperty(tag PropertyName) bool { htmlID := view.htmlID() diff --git a/viewUtils.go b/viewUtils.go index 8b90076..da7a26a 100644 --- a/viewUtils.go +++ b/viewUtils.go @@ -613,17 +613,17 @@ func GetBackfaceVisible(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, BackfaceVisible, false) } -// GetOrigin returns a x-, y-, and z-coordinate of the point around which a view transformation is applied. +// GetTransformOrigin returns a x-, y-, and z-coordinate of the point around which a view transformation is applied. // The default value is (50%, 50%, 50%). // If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. -func GetOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) { +func GetTransformOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) { if len(subviewID) > 0 && subviewID[0] != "" { view = ViewByID(view, subviewID[0]) } if view == nil { return AutoSize(), AutoSize(), AutoSize() } - return getOrigin(view, view.Session()) + return getTransformOrigin(view, view.Session()) } // GetTranslate returns a x-, y-, and z-axis translation value of a 2D/3D translation diff --git a/viewsContainer.go b/viewsContainer.go index f16290e..c1dcd3b 100644 --- a/viewsContainer.go +++ b/viewsContainer.go @@ -38,10 +38,10 @@ func (container *viewsContainerData) init(session Session) { container.viewData.init(session) container.tag = "ViewsContainer" container.views = []View{} - container.getFunc = container.get + container.get = container.getFunc container.set = container.setFunc container.remove = container.removeFunc - container.changed = viewsContainerPropertyChanged + container.changed = container.propertyChanged } func (container *viewsContainerData) setParentID(parentID string) { @@ -163,7 +163,7 @@ func viewFromTextValue(text string, session Session) View { return NewTextView(session, Params{Text: text}) } -func (container *viewsContainerData) removeFunc(view View, tag PropertyName) []PropertyName { +func (container *viewsContainerData) removeFunc(tag PropertyName) []PropertyName { switch tag { case Content: if len(container.views) > 0 { @@ -173,18 +173,18 @@ func (container *viewsContainerData) removeFunc(view View, tag PropertyName) []P return []PropertyName{} case Disabled: - if view.getRaw(Disabled) != nil { - view.setRaw(Disabled, nil) + if container.getRaw(Disabled) != nil { + container.setRaw(Disabled, nil) for _, view := range container.views { view.Remove(Disabled) } return []PropertyName{tag} } } - return viewRemove(view, tag) + return container.viewData.removeFunc(tag) } -func (container *viewsContainerData) setFunc(self View, tag PropertyName, value any) []PropertyName { +func (container *viewsContainerData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case Content: if container.setContent(value) { @@ -194,7 +194,7 @@ func (container *viewsContainerData) setFunc(self View, tag PropertyName, value case Disabled: oldDisabled := IsDisabled(container) - result := viewSet(self, Disabled, value) + result := container.viewData.setFunc(Disabled, value) if result != nil { disabled := IsDisabled(container) if oldDisabled != disabled { @@ -206,16 +206,16 @@ func (container *viewsContainerData) setFunc(self View, tag PropertyName, value return result } - return viewSet(self, tag, value) + return container.viewData.setFunc(tag, value) } -func viewsContainerPropertyChanged(view View, tag PropertyName) { +func (container *viewsContainerData) propertyChanged(tag PropertyName) { switch tag { case Content: - updateInnerHTML(view.htmlID(), view.Session()) + updateInnerHTML(container.htmlID(), container.Session()) default: - viewPropertyChanged(view, tag) + container.viewData.propertyChanged(tag) } } @@ -292,13 +292,13 @@ func (container *viewsContainerData) setContent(value any) bool { return true } -func (container *viewsContainerData) get(view View, tag PropertyName) any { +func (container *viewsContainerData) getFunc(tag PropertyName) any { switch tag { case Content: return container.views default: - return viewGet(view, tag) + return container.viewData.getFunc(tag) } }