From 3c3c09b043efc7e43addb05a080eff721d014a35 Mon Sep 17 00:00:00 2001 From: Alexei Anoshenko <2277098+anoshenko@users.noreply.github.com> Date: Tue, 17 Jun 2025 21:08:16 +0300 Subject: [PATCH] Added binding support --- animation.go | 6 +- animationEvents.go | 202 +++++++++--------- animationRun.go | 26 +-- background.go | 18 +- checkbox.go | 59 +++--- colorPicker.go | 8 +- columnLayout.go | 8 +- customView.go | 7 + dataList.go | 4 +- datePicker.go | 20 +- detailsView.go | 12 +- dragAndDrop.go | 114 +++++++--- dropDownList.go | 16 +- editView.go | 28 ++- events.go | 510 +++++++++++++++++++++++++++++++++------------ events1arg.go | 266 +++++++++++++++++++++++ filePicker.go | 27 ++- focusEvents.go | 8 +- gridLayout.go | 28 ++- keyEvents.go | 44 ++-- listLayout.go | 24 ++- listView.go | 109 +++++++--- mouseEvents.go | 122 ++++++++--- numberPicker.go | 24 ++- pointerEvents.go | 92 ++++++-- popup.go | 2 +- progressBar.go | 8 +- propertyNames.go | 2 + resizeEvent.go | 23 +- scrollEvent.go | 35 +++- stackLayout.go | 18 +- tableView.go | 73 +------ tableViewUtils.go | 74 +++++-- tabsLayout.go | 168 ++------------- textView.go | 4 +- timePicker.go | 20 +- touchEvents.go | 62 ++++-- transform.go | 36 +++- view.go | 46 ++-- viewUtils.go | 112 +++++++--- 40 files changed, 1674 insertions(+), 791 deletions(-) create mode 100644 events1arg.go diff --git a/animation.go b/animation.go index 122692b..2adece7 100644 --- a/animation.go +++ b/animation.go @@ -209,7 +209,7 @@ type animationData struct { usageCounter int view View listener func(view View, animation AnimationProperty, event PropertyName) - oldListeners map[PropertyName][]func(View, PropertyName) + oldListeners map[PropertyName][]oneArgListener[View, PropertyName] oldAnimation []AnimationProperty } @@ -1083,7 +1083,9 @@ func SetAnimated(rootView View, viewID string, tag PropertyName, value any, anim } // IsAnimationPaused returns "true" if an animation of the subview is paused, "false" otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsAnimationPaused(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, AnimationPaused, false) } diff --git a/animationEvents.go b/animationEvents.go index e785007..a5f00ac 100644 --- a/animationEvents.go +++ b/animationEvents.go @@ -156,45 +156,6 @@ const ( AnimationIterationEvent PropertyName = "animation-iteration-event" ) -/* -func setTransitionListener(properties Properties, tag PropertyName, value any) bool { - if listeners, ok := valueToOneArgEventListeners[View, string](value); ok { - if len(listeners) == 0 { - properties.setRaw(tag, nil) - } else { - properties.setRaw(tag, listeners) - } - return true - } - notCompatibleType(tag, value) - return false -} - -func (view *viewData) removeTransitionListener(tag PropertyName) { - delete(view.properties, tag) - if view.created { - if js, ok := eventJsFunc[tag]; ok { - view.session.removeProperty(view.htmlID(), js.jsEvent) - } - } -} - -func transitionEventsHtml(view View, buffer *strings.Builder) { - for _, tag := range []PropertyName{TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent} { - if value := view.getRaw(tag); value != nil { - if js, ok := eventJsFunc[tag]; ok { - if listeners, ok := value.([]func(View, string)); ok && len(listeners) > 0 { - buffer.WriteString(js.jsEvent) - buffer.WriteString(`="`) - buffer.WriteString(js.jsFunc) - buffer.WriteString(`(this, event)" `) - } - } - } - } -} -*/ - func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject) { if propertyName, ok := data.PropertyValue("property"); ok { property := PropertyName(propertyName) @@ -208,50 +169,11 @@ func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject) } for _, listener := range getOneArgEventListeners[View, PropertyName](view, nil, tag) { - listener(view, property) + listener.Run(view, property) } } } -/* - func setAnimationListener(properties Properties, tag PropertyName, value any) bool { - if listeners, ok := valueToOneArgEventListeners[View, string](value); ok { - if len(listeners) == 0 { - properties.setRaw(tag, nil) - } else { - properties.setRaw(tag, listeners) - } - return true - } - notCompatibleType(tag, value) - return false - } - -func (view *viewData) removeAnimationListener(tag PropertyName) { - delete(view.properties, tag) - if view.created { - if js, ok := eventJsFunc[tag]; ok { - view.session.removeProperty(view.htmlID(), js.jsEvent) - } - } -} - -func animationEventsHtml(view View, buffer *strings.Builder) { - for _, tag := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent} { - if value := view.getRaw(tag); value != nil { - if js, ok := eventJsFunc[tag]; ok { - if listeners, ok := value.([]func(View, string)); ok && len(listeners) > 0 { - buffer.WriteString(js.jsEvent) - buffer.WriteString(`="`) - buffer.WriteString(js.jsFunc) - buffer.WriteString(`(this, event)" `) - } - } - } - } -} -*/ - func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) { if listeners := getOneArgEventListeners[View, string](view, nil, tag); len(listeners) > 0 { id := "" @@ -263,63 +185,135 @@ func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) { } } for _, listener := range listeners { - listener(view, id) + listener.Run(view, id) } } } // GetTransitionRunListeners returns the "transition-run-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 GetTransitionRunListeners(view View, subviewID ...string) []func(View, string) { - return getOneArgEventListeners[View, string](view, subviewID, TransitionRunEvent) +// +// Result elements can be of the following types: +// - func(rui.View, string), +// - func(rui.View), +// - func(string), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTransitionRunListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, string](view, subviewID, TransitionStartEvent) +// +// Result elements can be of the following types: +// - func(rui.View, string), +// - func(rui.View), +// - func(string), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTransitionStartListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, string](view, subviewID, TransitionEndEvent) +// +// Result elements can be of the following types: +// - func(rui.View, string), +// - func(rui.View), +// - func(string), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTransitionEndListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, string](view, subviewID, TransitionCancelEvent) +// +// Result elements can be of the following types: +// - func(rui.View, string), +// - func(rui.View), +// - func(string), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTransitionCancelListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, string](view, subviewID, AnimationStartEvent) +// +// Result elements can be of the following types: +// - func(rui.View, string), +// - func(rui.View), +// - func(string), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetAnimationStartListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, string](view, subviewID, AnimationEndEvent) +// +// Result elements can be of the following types: +// - func(rui.View, string), +// - func(rui.View), +// - func(string), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetAnimationEndListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, string](view, subviewID, AnimationCancelEvent) +// +// Result elements can be of the following types: +// - func(rui.View, string), +// - func(rui.View), +// - func(string), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetAnimationCancelListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, string](view, subviewID, AnimationIterationEvent) +// +// Result elements can be of the following types: +// - func(rui.View, string), +// - func(rui.View), +// - func(string), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetAnimationIterationListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, string](view, subviewID, AnimationIterationEvent) } diff --git a/animationRun.go b/animationRun.go index e9f1eeb..64c3c3d 100644 --- a/animationRun.go +++ b/animationRun.go @@ -1,5 +1,7 @@ package rui +import "slices" + func (animation *animationData) Start(view View, listener func(view View, animation AnimationProperty, event PropertyName)) bool { if view == nil { ErrorLog("nil View in animation.Start() function") @@ -13,28 +15,22 @@ func (animation *animationData) Start(view View, listener func(view View, animat animation.listener = listener animation.oldAnimation = nil + + //if getOneArgEventListeners[View, PropertyName](view, nil, Animation) if value := view.Get(Animation); value != nil { if oldAnimation, ok := value.([]AnimationProperty); ok && len(oldAnimation) > 0 { animation.oldAnimation = oldAnimation } } - animation.oldListeners = map[PropertyName][]func(View, PropertyName){} + animation.oldListeners = map[PropertyName][]oneArgListener[View, PropertyName]{} setListeners := func(event PropertyName, listener func(View, PropertyName)) { - var listeners []func(View, PropertyName) = nil - if value := view.Get(event); value != nil { - if oldListeners, ok := value.([]func(View, PropertyName)); ok && len(oldListeners) > 0 { - listeners = oldListeners - } - } - - if listeners == nil { - view.Set(event, listener) - } else { - animation.oldListeners[event] = listeners - view.Set(event, append(listeners, listener)) + listeners := getOneArgEventListeners[View, PropertyName](view, nil, event) + if len(listeners) > 0 { + animation.oldListeners[event] = slices.Clone(listeners) } + view.Set(event, append(listeners, newOneArgListenerVE(listener))) } setListeners(AnimationStartEvent, animation.onAnimationStart) @@ -49,7 +45,7 @@ func (animation *animationData) Start(view View, listener func(view View, animat func (animation *animationData) finish() { if animation.view != nil { for _, event := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationCancelEvent, AnimationIterationEvent} { - if listeners, ok := animation.oldListeners[event]; ok { + if listeners, ok := animation.oldListeners[event]; ok && len(listeners) > 0 { animation.view.Set(event, listeners) } else { animation.view.Remove(event) @@ -63,7 +59,7 @@ func (animation *animationData) finish() { animation.view.Set(Animation, "") } - animation.oldListeners = map[PropertyName][]func(View, PropertyName){} + animation.oldListeners = map[PropertyName][]oneArgListener[View, PropertyName]{} animation.view = nil animation.listener = nil diff --git a/background.go b/background.go index 79a4c2f..d55d12d 100644 --- a/background.go +++ b/background.go @@ -268,14 +268,16 @@ func backgroundStyledPropery(view View, subviewID []string, tag PropertyName) [] // GetBackground returns the view background. // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetBackground(view View, subviewID ...string) []BackgroundElement { return backgroundStyledPropery(view, subviewID, Background) } // GetMask returns the view mask. // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetMask(view View, subviewID ...string) []BackgroundElement { return backgroundStyledPropery(view, subviewID, Mask) } @@ -284,7 +286,8 @@ func GetMask(view View, subviewID ...string) []BackgroundElement { // // BorderBox (0), PaddingBox (1), ContentBox (2) // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetBackgroundClip(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, BackgroundClip, 0, false) } @@ -293,7 +296,8 @@ func GetBackgroundClip(view View, subviewID ...string) int { // // BorderBox (0), PaddingBox (1), ContentBox (2) // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetBackgroundOrigin(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, BackgroundOrigin, 0, false) } @@ -302,7 +306,8 @@ func GetBackgroundOrigin(view View, subviewID ...string) int { // // BorderBox (0), PaddingBox (1), ContentBox (2) // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetMaskClip(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, MaskClip, 0, false) } @@ -311,7 +316,8 @@ func GetMaskClip(view View, subviewID ...string) int { // // BorderBox (0), PaddingBox (1), ContentBox (2) // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetMaskOrigin(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, MaskOrigin, 0, false) } diff --git a/checkbox.go b/checkbox.go index ce13e1d..2909158 100644 --- a/checkbox.go +++ b/checkbox.go @@ -53,8 +53,8 @@ func (button *checkboxData) init(session Session) { button.remove = button.removeFunc button.changed = button.propertyChanged - button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener}) - button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener}) + button.setRaw(ClickEvent, []oneArgListener[View, MouseEvent]{newOneArgListenerVE(checkboxClickListener)}) + button.setRaw(KeyDownEvent, []oneArgListener[View, KeyEvent]{newOneArgListenerVE(checkboxKeyListener)}) } func (button *checkboxData) Focusable() bool { @@ -67,9 +67,9 @@ func (button *checkboxData) propertyChanged(tag PropertyName) { case Checked: session := button.Session() checked := IsCheckboxChecked(button) - if listeners := GetCheckboxChangedListeners(button); len(listeners) > 0 { + if listeners := getOneArgEventListeners[Checkbox, bool](button, nil, CheckboxChangedEvent); len(listeners) > 0 { for _, listener := range listeners { - listener(button, checked) + listener.Run(button, checked) } } @@ -103,7 +103,7 @@ func (button *checkboxData) setFunc(tag PropertyName, value any) []PropertyName switch tag { case ClickEvent: if listeners, ok := valueToOneArgEventListeners[View, MouseEvent](value); ok && listeners != nil { - listeners = append(listeners, checkboxClickListener) + listeners = append(listeners, newOneArgListenerVE(checkboxClickListener)) button.setRaw(tag, listeners) return []PropertyName{tag} } @@ -111,7 +111,7 @@ func (button *checkboxData) setFunc(tag PropertyName, value any) []PropertyName case KeyDownEvent: if listeners, ok := valueToOneArgEventListeners[View, KeyEvent](value); ok && listeners != nil { - listeners = append(listeners, checkboxKeyListener) + listeners = append(listeners, newOneArgListenerVE(checkboxKeyListener)) button.setRaw(tag, listeners) return []PropertyName{tag} } @@ -134,31 +134,17 @@ func (button *checkboxData) setFunc(tag PropertyName, value any) []PropertyName func (button *checkboxData) removeFunc(tag PropertyName) []PropertyName { switch tag { case ClickEvent: - button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener}) + button.setRaw(ClickEvent, []oneArgListener[View, MouseEvent]{newOneArgListenerVE(checkboxClickListener)}) return []PropertyName{ClickEvent} case KeyDownEvent: - button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener}) + button.setRaw(KeyDownEvent, []oneArgListener[View, KeyEvent]{newOneArgListenerVE(checkboxKeyListener)}) return []PropertyName{ClickEvent} } return button.viewsContainerData.removeFunc(tag) } -/* -func (button *checkboxData) changedCheckboxState(state bool) { - for _, listener := range GetCheckboxChangedListeners(button) { - listener(button, state) - } - - buffer := allocStringBuilder() - defer freeStringBuilder(buffer) - - button.htmlCheckbox(buffer, state) - button.Session().updateInnerHTML(button.htmlID()+"checkbox", buffer.String()) -} -*/ - func checkboxClickListener(view View, _ MouseEvent) { view.Set(Checked, !IsCheckboxChecked(view)) BlurView(view) @@ -302,26 +288,41 @@ func checkboxVerticalAlignCSS(view View) string { } // IsCheckboxChecked returns true if the Checkbox is checked, false otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsCheckboxChecked(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, Checked, false) } // GetCheckboxVerticalAlign return the vertical align of a Checkbox subview: TopAlign (0), BottomAlign (1), CenterAlign (2) -// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetCheckboxVerticalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, LeftAlign, false) } // GetCheckboxHorizontalAlign return the vertical align of a Checkbox subview: LeftAlign (0), RightAlign (1), CenterAlign (2) -// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetCheckboxHorizontalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, TopAlign, false) } // GetCheckboxChangedListeners returns the CheckboxChangedListener list of an Checkbox subview. -// If there are no listeners then the empty list is returned -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. -func GetCheckboxChangedListeners(view View, subviewID ...string) []func(Checkbox, bool) { - return getOneArgEventListeners[Checkbox, bool](view, subviewID, CheckboxChangedEvent) +// If there are no listeners then the empty list is returned. +// +// Result elements can be of the following types: +// - func(Checkbox, bool), +// - func(Checkbox), +// - func(bool), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetCheckboxChangedListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[Checkbox, bool](view, subviewID, CheckboxChangedEvent) } diff --git a/colorPicker.go b/colorPicker.go index b1016f5..f205094 100644 --- a/colorPicker.go +++ b/colorPicker.go @@ -172,7 +172,9 @@ func (picker *colorPickerData) handleCommand(self View, command PropertyName, da } // GetColorPickerValue returns the value of ColorPicker subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetColorPickerValue(view View, subviewID ...string) Color { if view = getSubview(view, subviewID); view != nil { if value, ok := colorProperty(view, ColorPickerValue, view.Session()); ok { @@ -191,7 +193,9 @@ func GetColorPickerValue(view View, subviewID ...string) Color { // GetColorChangedListeners returns the ColorChangedListener list of an ColorPicker subview. // If there are no listeners then the empty list is returned -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetColorChangedListeners(view View, subviewID ...string) []func(ColorPicker, Color, Color) { return getTwoArgEventListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent) } diff --git a/columnLayout.go b/columnLayout.go index 2a0a64a..9cfad54 100644 --- a/columnLayout.go +++ b/columnLayout.go @@ -249,13 +249,17 @@ func GetColumnSeparatorColor(view View, subviewID ...string) Color { // GetColumnFill returns a "column-fill" property value of the subview. // Returns one of next values: ColumnFillBalance (0) or ColumnFillAuto (1) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetColumnFill(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, ColumnFill, ColumnFillBalance, true) } // IsColumnSpanAll returns a "column-span-all" property value of the subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsColumnSpanAll(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, ColumnSpanAll, false) } diff --git a/customView.go b/customView.go index 5523e8a..35411d6 100644 --- a/customView.go +++ b/customView.go @@ -352,3 +352,10 @@ func (customView *CustomViewData) LoadFile(file FileInfo, result func(FileInfo, customView.superView.LoadFile(file, result) } } + +func (customView *CustomViewData) binding() any { + if customView.superView != nil { + return customView.superView.binding() + } + return nil +} diff --git a/dataList.go b/dataList.go index 2c1bb11..0efdd56 100644 --- a/dataList.go +++ b/dataList.go @@ -312,7 +312,9 @@ func dataListHtmlProperties(view View, buffer *strings.Builder) { } // GetDataList returns the data list of an editor. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDataList(view View, subviewID ...string) []string { if view = getSubview(view, subviewID); view != nil { return getDataListProperty(view) diff --git a/datePicker.go b/datePicker.go index bff18c6..54da1c4 100644 --- a/datePicker.go +++ b/datePicker.go @@ -400,7 +400,9 @@ func getDateProperty(view View, mainTag, shortTag PropertyName) (time.Time, bool // GetDatePickerMin returns the min date of DatePicker subview and "true" as the second value if the min date is set, // "false" as the second value otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDatePickerMin(view View, subviewID ...string) (time.Time, bool) { if view = getSubview(view, subviewID); view != nil { return getDateProperty(view, DatePickerMin, Min) @@ -410,7 +412,9 @@ func GetDatePickerMin(view View, subviewID ...string) (time.Time, bool) { // GetDatePickerMax returns the max date of DatePicker subview and "true" as the second value if the min date is set, // "false" as the second value otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDatePickerMax(view View, subviewID ...string) (time.Time, bool) { if view = getSubview(view, subviewID); view != nil { return getDateProperty(view, DatePickerMax, Max) @@ -419,13 +423,17 @@ func GetDatePickerMax(view View, subviewID ...string) (time.Time, bool) { } // GetDatePickerStep returns the date changing step in days of DatePicker subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDatePickerStep(view View, subviewID ...string) int { return intStyledProperty(view, subviewID, DatePickerStep, 0) } // GetDatePickerValue returns the date of DatePicker subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDatePickerValue(view View, subviewID ...string) time.Time { if view = getSubview(view, subviewID); view == nil { return time.Now() @@ -436,7 +444,9 @@ func GetDatePickerValue(view View, subviewID ...string) time.Time { // GetDateChangedListeners returns the DateChangedListener list of an DatePicker subview. // If there are no listeners then the empty list is returned -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDateChangedListeners(view View, subviewID ...string) []func(DatePicker, time.Time, time.Time) { return getTwoArgEventListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent) } diff --git a/detailsView.go b/detailsView.go index c4b9401..2296083 100644 --- a/detailsView.go +++ b/detailsView.go @@ -202,7 +202,9 @@ func (detailsView *detailsViewData) handleCommand(self View, command PropertyNam } // GetDetailsSummary returns a value of the Summary property of DetailsView. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDetailsSummary(view View, subviewID ...string) View { if view = getSubview(view, subviewID); view != nil { if value := view.Get(Summary); value != nil { @@ -219,13 +221,17 @@ func GetDetailsSummary(view View, subviewID ...string) View { } // IsDetailsExpanded returns a value of the Expanded property of DetailsView. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsDetailsExpanded(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, Expanded, false) } // IsDetailsExpanded returns a value of the HideSummaryMarker property of DetailsView. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsSummaryMarkerHidden(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, HideSummaryMarker, false) } diff --git a/dragAndDrop.go b/dragAndDrop.go index 92e2af6..f0fa70e 100644 --- a/dragAndDrop.go +++ b/dragAndDrop.go @@ -336,7 +336,7 @@ func handleDragAndDropEvents(view View, tag PropertyName, data DataObject) { event.init(view.Session(), data) for _, listener := range listeners { - listener(view, event) + listener.Run(view, event) } } } @@ -434,41 +434,99 @@ func (view *viewData) LoadFile(file FileInfo, result func(FileInfo, []byte)) { } // GetDragStartEventListeners returns the "drag-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 GetDragStartEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) { - return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragStartEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.DragAndDropEvent), +// - func(rui.View), +// - func(rui.DragAndDropEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetDragStartEventListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragStartEvent) } // GetDragEndEventListeners returns the "drag-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 GetDragEndEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) { - return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragEndEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.DragAndDropEvent), +// - func(rui.View), +// - func(rui.DragAndDropEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetDragEndEventListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragEndEvent) } // GetDragEnterEventListeners returns the "drag-enter-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 GetDragEnterEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) { - return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragEnterEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.DragAndDropEvent), +// - func(rui.View), +// - func(rui.DragAndDropEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetDragEnterEventListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragEnterEvent) } // GetDragLeaveEventListeners returns the "drag-leave-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 GetDragLeaveEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) { - return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragLeaveEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.DragAndDropEvent), +// - func(rui.View), +// - func(rui.DragAndDropEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetDragLeaveEventListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragLeaveEvent) } // GetDragOverEventListeners returns the "drag-over-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 GetDragOverEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) { - return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragOverEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.DragAndDropEvent), +// - func(rui.View), +// - func(rui.DragAndDropEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetDragOverEventListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragOverEvent) } // GetDropEventListeners returns the "drag-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 GetDropEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) { - return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DropEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.DragAndDropEvent), +// - func(rui.View), +// - func(rui.DragAndDropEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetDropEventListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DropEvent) } +// GetDropEventListeners returns the "drag-data" data. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDragData(view View, subviewID ...string) map[string]string { result := map[string]string{} if view = getSubview(view, subviewID); view != nil { @@ -483,7 +541,9 @@ func GetDragData(view View, subviewID ...string) map[string]string { } // GetDragImage returns the drag feedback image. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDragImage(view View, subviewID ...string) string { if view = getSubview(view, subviewID); view != nil { value := view.getRaw(DragImage) @@ -508,13 +568,17 @@ func GetDragImage(view View, subviewID ...string) string { } // GetDragImageXOffset returns the horizontal offset in pixels within the drag feedback image. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDragImageXOffset(view View, subviewID ...string) float64 { return floatStyledProperty(view, subviewID, DragImageXOffset, 0) } // GetDragImageYOffset returns the vertical offset in pixels within the drag feedback image. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDragImageYOffset(view View, subviewID ...string) float64 { return floatStyledProperty(view, subviewID, DragImageYOffset, 0) } @@ -529,7 +593,8 @@ func GetDragImageYOffset(view View, subviewID ...string) float64 { // - 2 (DropEffectMove) - An item may be moved to a new location. // - 4 (DropEffectLink) - A link may be established to the source at the new location. // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDropEffect(view View, subviewID ...string) int { if view = getSubview(view, subviewID); view != nil { value := view.getRaw(DropEffect) @@ -573,7 +638,8 @@ func GetDropEffect(view View, subviewID ...string) int { // - 6 (DropEffectLinkMove) - A link or move operation is permitted. // - 7 (DropEffectAll) - All operations are permitted. // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDropEffectAllowed(view View, subviewID ...string) int { if view = getSubview(view, subviewID); view != nil { value := view.getRaw(DropEffectAllowed) diff --git a/dropDownList.go b/dropDownList.go index f7fd3e6..830a655 100644 --- a/dropDownList.go +++ b/dropDownList.go @@ -264,13 +264,17 @@ 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. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDropDownListeners(view View, subviewID ...string) []func(DropDownList, int, int) { return getTwoArgEventListeners[DropDownList, int](view, subviewID, DropDownEvent) } // GetDropDownItems return the DropDownList items list. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDropDownItems(view View, subviewID ...string) []string { if view = getSubview(view, subviewID); view != nil { if value := view.Get(Items); value != nil { @@ -313,14 +317,18 @@ func getIndicesArray(view View, tag PropertyName) []int { } // GetDropDownDisabledItems return an array of disabled(non selectable) items indices of DropDownList. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDropDownDisabledItems(view View, subviewID ...string) []int { view = getSubview(view, subviewID) return getIndicesArray(view, DisabledItems) } // GetDropDownItemSeparators return an array of indices of DropDownList items after which a separator should be added. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetDropDownItemSeparators(view View, subviewID ...string) []int { view = getSubview(view, subviewID) return getIndicesArray(view, ItemSeparators) diff --git a/editView.go b/editView.go index c65a783..ece94fe 100644 --- a/editView.go +++ b/editView.go @@ -451,26 +451,34 @@ func IsReadOnly(view View, subviewID ...string) bool { } // IsSpellcheck returns a value of the Spellcheck property of EditView. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsSpellcheck(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, Spellcheck, false) } // GetTextChangedListeners returns the TextChangedListener list of an EditView or MultiLineEditView subview. // If there are no listeners then the empty list is returned -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextChangedListeners(view View, subviewID ...string) []func(EditView, string, string) { return getTwoArgEventListeners[EditView, string](view, subviewID, EditTextChangedEvent) } // GetEditViewType returns a value of the Type property of EditView. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetEditViewType(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, EditViewType, SingleLineText, false) } // GetEditViewPattern returns a value of the Pattern property of EditView. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetEditViewPattern(view View, subviewID ...string) string { if view = getSubview(view, subviewID); view != nil { if pattern, ok := stringProperty(view, EditViewPattern, view.Session()); ok { @@ -488,13 +496,17 @@ func GetEditViewPattern(view View, subviewID ...string) string { } // IsEditViewWrap returns a value of the EditWrap property of MultiLineEditView. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsEditViewWrap(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, EditWrap, false) } // AppendEditText appends the text to the EditView content. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func AppendEditText(view View, subviewID string, text string) { if subviewID != "" { if edit := EditViewByID(view, subviewID); edit != nil { @@ -509,7 +521,9 @@ func AppendEditText(view View, subviewID string, text string) { } // GetCaretColor returns the color of the text input caret. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetCaretColor(view View, subviewID ...string) Color { return colorStyledProperty(view, subviewID, CaretColor, false) } diff --git a/events.go b/events.go index 84c344b..f663c47 100644 --- a/events.go +++ b/events.go @@ -1,6 +1,9 @@ package rui -import "strings" +import ( + "reflect" + "strings" +) var eventJsFunc = map[PropertyName]struct{ jsEvent, jsFunc string }{ FocusEvent: {jsEvent: "onfocus", jsFunc: "focusEvent"}, @@ -38,12 +41,203 @@ var eventJsFunc = map[PropertyName]struct{ jsEvent, jsFunc string }{ DragLeaveEvent: {jsEvent: "ondragleave", jsFunc: "dragLeaveEvent"}, } -func valueToNoArgEventListeners[V any](value any) ([]func(V), bool) { +/* +type oneArgListener[V View, E any] interface { + call(V, E) + listener() func(V, E) + rawListener() any +} + +type oneArgListener0[V View, E any] struct { + fn func() +} + +type oneArgListenerV[V View, E any] struct { + fn func(V) +} + +type oneArgListenerE[V View, E any] struct { + fn func(E) +} + +type oneArgListenerVE[V View, E any] struct { + fn func(V, E) +} + +type oneArgListenerBinding[V View, E any] struct { + name string +} + +func newOneArgListener0[V View, E any](fn func()) oneArgListener[V, E] { + obj := new(oneArgListener0[V, E]) + obj.fn = fn + return obj +} + +func (data *oneArgListener0[V, E]) call(_ V, _ E) { + data.fn() +} + +func (data *oneArgListener0[V, E]) listener() func(V, E) { + return data.call +} + +func (data *oneArgListener0[V, E]) rawListener() any { + return data.fn +} + +func newOneArgListenerV[V View, E any](fn func(V)) oneArgListener[V, E] { + obj := new(oneArgListenerV[V, E]) + obj.fn = fn + return obj +} + +func (data *oneArgListenerV[V, E]) call(view V, _ E) { + data.fn(view) +} + +func (data *oneArgListenerV[V, E]) listener() func(V, E) { + return data.call +} + +func (data *oneArgListenerV[V, E]) rawListener() any { + return data.fn +} + +func newOneArgListenerE[V View, E any](fn func(E)) oneArgListener[V, E] { + obj := new(oneArgListenerE[V, E]) + obj.fn = fn + return obj +} + +func (data *oneArgListenerE[V, E]) call(_ V, event E) { + data.fn(event) +} + +func (data *oneArgListenerE[V, E]) listener() func(V, E) { + return data.call +} + +func (data *oneArgListenerE[V, E]) rawListener() any { + return data.fn +} + +func newOneArgListenerVE[V View, E any](fn func(V, E)) oneArgListener[V, E] { + obj := new(oneArgListenerVE[V, E]) + obj.fn = fn + return obj +} + +func (data *oneArgListenerVE[V, E]) call(view V, arg E) { + data.fn(view, arg) +} + +func (data *oneArgListenerVE[V, E]) listener() func(V, E) { + return data.fn +} + +func (data *oneArgListenerVE[V, E]) rawListener() any { + return data.fn +} + +func newOneArgListenerBinding[V View, E any](name string) oneArgListener[V, E] { + obj := new(oneArgListenerBinding[V, E]) + obj.name = name + return obj +} + +func (data *oneArgListenerBinding[V, E]) call(view V, event E) { + bind := view.binding() + if bind == nil { + ErrorLogF(`There is no a binding object for call "%s"`, data.name) + return + } + + val := reflect.ValueOf(bind) + method := val.MethodByName(data.name) + if !method.IsValid() { + ErrorLogF(`The "%s" method is not valid`, data.name) + return + } + + methodType := method.Type() + var args []reflect.Value = nil + switch methodType.NumIn() { + case 0: + args = []reflect.Value{} + + case 1: + inType := methodType.In(0) + if inType == reflect.TypeOf(view) { + args = []reflect.Value{reflect.ValueOf(view)} + } else if inType == reflect.TypeOf(event) { + args = []reflect.Value{reflect.ValueOf(event)} + } + + case 2: + if methodType.In(0) == reflect.TypeOf(view) && methodType.In(1) == reflect.TypeOf(event) { + args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(event)} + } + } + + if args != nil { + method.Call(args) + } else { + ErrorLogF(`Unsupported prototype of "%s" method`, data.name) + } +} + +func (data *oneArgListenerBinding[V, E]) listener() func(V, E) { + return data.call +} + +func (data *oneArgListenerBinding[V, E]) rawListener() any { + return data.name +} +*/ + +func valueToNoArgEventListeners[V any](view View, value any) ([]func(V), bool) { if value == nil { return nil, true } switch value := value.(type) { + case string: + fn := func(arg V) { + bind := view.binding() + if bind == nil { + ErrorLogF(`There is no a binding object for call "%s"`, value) + return + } + + val := reflect.ValueOf(bind) + method := val.MethodByName(value) + if !method.IsValid() { + ErrorLogF(`The "%s" method is not valid`, value) + return + } + + methodType := method.Type() + var args []reflect.Value = nil + switch methodType.NumIn() { + case 0: + args = []reflect.Value{} + + case 1: + inType := methodType.In(0) + if inType == reflect.TypeOf(arg) { + args = []reflect.Value{reflect.ValueOf(arg)} + } + } + + if args != nil { + method.Call(args) + } else { + ErrorLogF(`Unsupported prototype of "%s" method`, value) + } + } + return []func(V){fn}, true + case func(V): return []func(V){value}, true @@ -109,137 +303,153 @@ func valueToNoArgEventListeners[V any](value any) ([]func(V), bool) { return nil, false } -func valueToOneArgEventListeners[V View, E any](value any) ([]func(V, E), bool) { +/* + func valueToOneArgEventListeners[V View, E any](view View, value any) ([]oneArgListener[V, E], bool) { + if value == nil { + return nil, true + } + + switch value := value.(type) { + case string: + return []oneArgListener[V, E]{newOneArgListenerBinding[V, E](value)}, true + + case func(V, E): + return []oneArgListener[V, E]{newOneArgListenerVE[V, E](value)}, true + + case func(V): + return []oneArgListener[V, E]{newOneArgListenerV[V, E](value)}, true + + case func(E): + return []oneArgListener[V, E]{newOneArgListenerE[V, E](value)}, true + + case func(): + return []oneArgListener[V, E]{newOneArgListener0[V, E](value)}, true + + case []func(V, E): + result := make([]oneArgListener[V, E], 0, len(value)) + for _, fn := range value { + if fn != nil { + result = append(result, newOneArgListenerVE[V, E](fn)) + } + } + return result, len(result) > 0 + + case []func(E): + result := make([]oneArgListener[V, E], 0, len(value)) + for _, fn := range value { + if fn != nil { + result = append(result, newOneArgListenerE[V, E](fn)) + } + } + return result, len(result) > 0 + + case []func(V): + result := make([]oneArgListener[V, E], 0, len(value)) + for _, fn := range value { + if fn != nil { + result = append(result, newOneArgListenerV[V, E](fn)) + } + } + return result, len(result) > 0 + + case []func(): + result := make([]oneArgListener[V, E], 0, len(value)) + for _, fn := range value { + if fn != nil { + result = append(result, newOneArgListener0[V, E](fn)) + } + } + return result, len(result) > 0 + + case []any: + result := make([]oneArgListener[V, E], 0, len(value)) + for _, v := range value { + if v != nil { + switch v := v.(type) { + case func(V, E): + result = append(result, newOneArgListenerVE[V, E](v)) + + case func(E): + result = append(result, newOneArgListenerE[V, E](v)) + + case func(V): + result = append(result, newOneArgListenerV[V, E](v)) + + case func(): + result = append(result, newOneArgListener0[V, E](v)) + + case string: + result = append(result, newOneArgListenerBinding[V, E](v)) + + default: + return nil, false + } + } + } + return result, len(result) > 0 + } + + return nil, false + } +*/ +func valueToTwoArgEventListeners[V View, E any](view View, value any) ([]func(V, E, E), bool) { if value == nil { return nil, true } switch value := value.(type) { - case func(V, E): - return []func(V, E){value}, true - - case func(E): - fn := func(_ V, event E) { - value(event) - } - return []func(V, E){fn}, true - - case func(V): - fn := func(view V, _ E) { - value(view) - } - return []func(V, E){fn}, true - - case func(): - fn := func(V, E) { - value() - } - return []func(V, E){fn}, true - - case []func(V, E): - if len(value) == 0 { - return nil, true - } - for _, fn := range value { - if fn == nil { - return nil, false + case string: + fn := func(view V, val1 E, val2 E) { + bind := view.binding() + if bind == nil { + ErrorLogF(`There is no a binding object for call "%s"`, value) + return } - } - return value, true - case []func(E): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(V, E), count) - for i, v := range value { - if v == nil { - return nil, false + val := reflect.ValueOf(bind) + method := val.MethodByName(value) + if !method.IsValid() { + ErrorLogF(`The "%s" method is not valid`, value) + return } - listeners[i] = func(_ V, event E) { - v(event) - } - } - return listeners, true - case []func(V): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(V, E), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(view V, _ E) { - v(view) - } - } - return listeners, true + methodType := method.Type() + var args []reflect.Value = nil + switch methodType.NumIn() { + case 0: + args = []reflect.Value{} - case []func(): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(V, E), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(V, E) { - v() - } - } - return listeners, true - - case []any: - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(V, E), count) - for i, v := range value { - if v == nil { - return nil, false - } - switch v := v.(type) { - case func(V, E): - listeners[i] = v - - case func(E): - listeners[i] = func(_ V, event E) { - v(event) + case 1: + inType := methodType.In(0) + if inType == reflect.TypeOf(view) { + args = []reflect.Value{reflect.ValueOf(view)} + } else if inType == reflect.TypeOf(val1) { + args = []reflect.Value{reflect.ValueOf(val1)} } - case func(V): - listeners[i] = func(view V, _ E) { - v(view) + case 2: + valType := reflect.TypeOf(val1) + if methodType.In(0) == reflect.TypeOf(view) && methodType.In(1) == valType { + args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(val1)} + } else if methodType.In(0) == valType && methodType.In(1) == valType { + args = []reflect.Value{reflect.ValueOf(val1), reflect.ValueOf(val2)} } - case func(): - listeners[i] = func(V, E) { - v() + case 3: + valType := reflect.TypeOf(val1) + if methodType.In(0) == reflect.TypeOf(view) && methodType.In(1) == valType && methodType.In(2) == valType { + args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(val1), reflect.ValueOf(val2)} } + } - default: - return nil, false + if args != nil { + method.Call(args) + } else { + ErrorLogF(`Unsupported prototype of "%s" method`, value) } } - return listeners, true - } + return []func(V, E, E){fn}, true - return nil, false -} - -func valueToTwoArgEventListeners[V View, E any](value any) ([]func(V, E, E), bool) { - if value == nil { - return nil, true - } - - switch value := value.(type) { case func(V, E, E): return []func(V, E, E){value}, true @@ -424,17 +634,27 @@ func getNoArgEventListeners[V View](view View, subviewID []string, tag PropertyN return []func(V){} } -func getOneArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E) { - if view = getSubview(view, subviewID); view != nil { - if value := view.Get(tag); value != nil { - if result, ok := value.([]func(V, E)); ok { - return result +/* + func getOneArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []oneArgListener[V, E] { + if view = getSubview(view, subviewID); view != nil { + if value := view.Get(tag); value != nil { + if result, ok := value.([]oneArgListener[V, E]); ok { + return result + } } } + return []oneArgListener[V, E]{} } - return []func(V, E){} -} + func getOneArgEventRawListeners[V View, E any](view View, subviewID []string, tag PropertyName) []any { + listeners := getOneArgEventListeners[V, E](view, subviewID, tag) + result := make([]any, len(listeners)) + for i, l := range listeners { + result[i] = l.rawListener() + } + return result + } +*/ func getTwoArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E, E) { if view = getSubview(view, subviewID); view != nil { if value := view.Get(tag); value != nil { @@ -446,12 +666,12 @@ func getTwoArgEventListeners[V View, E any](view View, subviewID []string, tag P return []func(V, E, E){} } -func setNoArgEventListener[V View](properties Properties, tag PropertyName, value any) []PropertyName { - if listeners, ok := valueToNoArgEventListeners[V](value); ok { +func setNoArgEventListener[V View](view View, tag PropertyName, value any) []PropertyName { + if listeners, ok := valueToNoArgEventListeners[V](view, value); ok { if len(listeners) > 0 { - properties.setRaw(tag, listeners) - } else if properties.getRaw(tag) != nil { - properties.setRaw(tag, nil) + view.setRaw(tag, listeners) + } else if view.getRaw(tag) != nil { + view.setRaw(tag, nil) } else { return []PropertyName{} } @@ -461,12 +681,13 @@ func setNoArgEventListener[V View](properties Properties, tag PropertyName, valu return nil } -func setOneArgEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName { - if listeners, ok := valueToOneArgEventListeners[V, T](value); ok { +/* +func setOneArgEventListener[V View, T any](view View, tag PropertyName, value any) []PropertyName { + if listeners, ok := valueToOneArgEventListeners[V, T](view, value); ok { if len(listeners) > 0 { - properties.setRaw(tag, listeners) - } else if properties.getRaw(tag) != nil { - properties.setRaw(tag, nil) + view.setRaw(tag, listeners) + } else if view.getRaw(tag) != nil { + view.setRaw(tag, nil) } else { return []PropertyName{} } @@ -475,16 +696,18 @@ func setOneArgEventListener[V View, T any](properties Properties, tag PropertyNa notCompatibleType(tag, value) return nil } +*/ -func setTwoArgEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName { - listeners, ok := valueToTwoArgEventListeners[V, T](value) +func setTwoArgEventListener[V View, T any](view View, tag PropertyName, value any) []PropertyName { + listeners, ok := valueToTwoArgEventListeners[V, T](view, value) if !ok { notCompatibleType(tag, value) return nil - } else if len(listeners) > 0 { - properties.setRaw(tag, listeners) - } else if properties.getRaw(tag) != nil { - properties.setRaw(tag, nil) + } + if len(listeners) > 0 { + view.setRaw(tag, listeners) + } else if view.getRaw(tag) != nil { + view.setRaw(tag, nil) } else { return []PropertyName{} } @@ -493,9 +716,17 @@ func setTwoArgEventListener[V View, T any](properties Properties, tag PropertyNa func viewEventsHtml[T any](view View, events []PropertyName, buffer *strings.Builder) { for _, tag := range events { - if value := view.getRaw(tag); value != nil { + if js, ok := eventJsFunc[tag]; ok { + if value := getOneArgEventListeners[View, T](view, nil, tag); len(value) > 0 { + buffer.WriteString(js.jsEvent) + buffer.WriteString(`="`) + buffer.WriteString(js.jsFunc) + buffer.WriteString(`(this, event)" `) + } + } + /*if value := view.getRaw(tag); value != nil { if js, ok := eventJsFunc[tag]; ok { - if listeners, ok := value.([]func(View, T)); ok && len(listeners) > 0 { + if listeners, ok := value.([] func(View, T)); ok && len(listeners) > 0 { buffer.WriteString(js.jsEvent) buffer.WriteString(`="`) buffer.WriteString(js.jsFunc) @@ -503,6 +734,7 @@ func viewEventsHtml[T any](view View, events []PropertyName, buffer *strings.Bui } } } + */ } } diff --git a/events1arg.go b/events1arg.go new file mode 100644 index 0000000..77004b3 --- /dev/null +++ b/events1arg.go @@ -0,0 +1,266 @@ +package rui + +import ( + "reflect" +) + +type oneArgListener[V View, E any] interface { + Run(V, E) + rawListener() any +} + +type oneArgListener0[V View, E any] struct { + fn func() +} + +type oneArgListenerV[V View, E any] struct { + fn func(V) +} + +type oneArgListenerE[V View, E any] struct { + fn func(E) +} + +type oneArgListenerVE[V View, E any] struct { + fn func(V, E) +} + +type oneArgListenerBinding[V View, E any] struct { + name string +} + +func newOneArgListener0[V View, E any](fn func()) oneArgListener[V, E] { + obj := new(oneArgListener0[V, E]) + obj.fn = fn + return obj +} + +func (data *oneArgListener0[V, E]) Run(_ V, _ E) { + data.fn() +} + +func (data *oneArgListener0[V, E]) rawListener() any { + return data.fn +} + +func newOneArgListenerV[V View, E any](fn func(V)) oneArgListener[V, E] { + obj := new(oneArgListenerV[V, E]) + obj.fn = fn + return obj +} + +func (data *oneArgListenerV[V, E]) Run(view V, _ E) { + data.fn(view) +} + +func (data *oneArgListenerV[V, E]) rawListener() any { + return data.fn +} + +func newOneArgListenerE[V View, E any](fn func(E)) oneArgListener[V, E] { + obj := new(oneArgListenerE[V, E]) + obj.fn = fn + return obj +} + +func (data *oneArgListenerE[V, E]) Run(_ V, event E) { + data.fn(event) +} + +func (data *oneArgListenerE[V, E]) rawListener() any { + return data.fn +} + +func newOneArgListenerVE[V View, E any](fn func(V, E)) oneArgListener[V, E] { + obj := new(oneArgListenerVE[V, E]) + obj.fn = fn + return obj +} + +func (data *oneArgListenerVE[V, E]) Run(view V, arg E) { + data.fn(view, arg) +} + +func (data *oneArgListenerVE[V, E]) rawListener() any { + return data.fn +} + +func newOneArgListenerBinding[V View, E any](name string) oneArgListener[V, E] { + obj := new(oneArgListenerBinding[V, E]) + obj.name = name + return obj +} + +func (data *oneArgListenerBinding[V, E]) Run(view V, event E) { + bind := view.binding() + if bind == nil { + ErrorLogF(`There is no a binding object for call "%s"`, data.name) + return + } + + val := reflect.ValueOf(bind) + method := val.MethodByName(data.name) + if !method.IsValid() { + ErrorLogF(`The "%s" method is not valid`, data.name) + return + } + + methodType := method.Type() + var args []reflect.Value = nil + switch methodType.NumIn() { + case 0: + args = []reflect.Value{} + + case 1: + inType := methodType.In(0) + if inType == reflect.TypeOf(view) { + args = []reflect.Value{reflect.ValueOf(view)} + } else if inType == reflect.TypeOf(event) { + args = []reflect.Value{reflect.ValueOf(event)} + } + + case 2: + if methodType.In(0) == reflect.TypeOf(view) && methodType.In(1) == reflect.TypeOf(event) { + args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(event)} + } + } + + if args != nil { + method.Call(args) + } else { + ErrorLogF(`Unsupported prototype of "%s" method`, data.name) + } +} + +func (data *oneArgListenerBinding[V, E]) rawListener() any { + return data.name +} + +func valueToOneArgEventListeners[V View, E any](value any) ([]oneArgListener[V, E], bool) { + if value == nil { + return nil, true + } + + switch value := value.(type) { + case []oneArgListener[V, E]: + return value, true + + case oneArgListener[V, E]: + return []oneArgListener[V, E]{value}, true + + case string: + return []oneArgListener[V, E]{newOneArgListenerBinding[V, E](value)}, true + + case func(V, E): + return []oneArgListener[V, E]{newOneArgListenerVE(value)}, true + + case func(V): + return []oneArgListener[V, E]{newOneArgListenerV[V, E](value)}, true + + case func(E): + return []oneArgListener[V, E]{newOneArgListenerE[V](value)}, true + + case func(): + return []oneArgListener[V, E]{newOneArgListener0[V, E](value)}, true + + case []func(V, E): + result := make([]oneArgListener[V, E], 0, len(value)) + for _, fn := range value { + if fn != nil { + result = append(result, newOneArgListenerVE(fn)) + } + } + return result, len(result) > 0 + + case []func(E): + result := make([]oneArgListener[V, E], 0, len(value)) + for _, fn := range value { + if fn != nil { + result = append(result, newOneArgListenerE[V](fn)) + } + } + return result, len(result) > 0 + + case []func(V): + result := make([]oneArgListener[V, E], 0, len(value)) + for _, fn := range value { + if fn != nil { + result = append(result, newOneArgListenerV[V, E](fn)) + } + } + return result, len(result) > 0 + + case []func(): + result := make([]oneArgListener[V, E], 0, len(value)) + for _, fn := range value { + if fn != nil { + result = append(result, newOneArgListener0[V, E](fn)) + } + } + return result, len(result) > 0 + + case []any: + result := make([]oneArgListener[V, E], 0, len(value)) + for _, v := range value { + if v != nil { + switch v := v.(type) { + case func(V, E): + result = append(result, newOneArgListenerVE(v)) + + case func(E): + result = append(result, newOneArgListenerE[V](v)) + + case func(V): + result = append(result, newOneArgListenerV[V, E](v)) + + case func(): + result = append(result, newOneArgListener0[V, E](v)) + + case string: + result = append(result, newOneArgListenerBinding[V, E](v)) + + default: + return nil, false + } + } + } + return result, len(result) > 0 + } + + return nil, false +} + +func setOneArgEventListener[V View, T any](view View, tag PropertyName, value any) []PropertyName { + if listeners, ok := valueToOneArgEventListeners[V, T](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} + } + notCompatibleType(tag, value) + return nil +} + +func getOneArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []oneArgListener[V, E] { + if view = getSubview(view, subviewID); view != nil { + if value := view.Get(tag); value != nil { + if result, ok := value.([]oneArgListener[V, E]); ok { + return result + } + } + } + return []oneArgListener[V, E]{} +} + +func getOneArgEventRawListeners[V View, E any](view View, subviewID []string, tag PropertyName) []any { + listeners := getOneArgEventListeners[V, E](view, subviewID, tag) + result := make([]any, len(listeners)) + for i, l := range listeners { + result[i] = l.rawListener() + } + return result +} diff --git a/filePicker.go b/filePicker.go index 8c8b0b6..9735497 100644 --- a/filePicker.go +++ b/filePicker.go @@ -282,8 +282,8 @@ func (picker *filePickerData) handleCommand(self View, command PropertyName, dat case "fileSelected": if files := parseFilesTag(data); files != nil { picker.files = files - for _, listener := range GetFileSelectedListeners(picker) { - listener(picker, files) + for _, listener := range getOneArgEventListeners[FilePicker, []FileInfo](picker, nil, FileSelectedEvent) { + listener.Run(picker, files) } } return true @@ -317,13 +317,17 @@ func LoadFilePickerFile(view View, subviewID string, file FileInfo, result func( } // IsMultipleFilePicker returns "true" if multiple files can be selected in the FilePicker, "false" otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsMultipleFilePicker(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, Multiple, false) } // GetFilePickerAccept returns sets the list of allowed file extensions or MIME types. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetFilePickerAccept(view View, subviewID ...string) []string { if view = getSubview(view, subviewID); view != nil { accept, ok := stringProperty(view, Accept, view.Session()) @@ -345,7 +349,16 @@ func GetFilePickerAccept(view View, subviewID ...string) []string { // GetFileSelectedListeners returns the "file-selected-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 GetFileSelectedListeners(view View, subviewID ...string) []func(FilePicker, []FileInfo) { - return getOneArgEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent) +// +// Result elements can be of the following types: +// - func(rui.View, []rui.FileInfo), +// - func(rui.View), +// - func([]rui.FileInfo), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetFileSelectedListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent) } diff --git a/focusEvents.go b/focusEvents.go index 281e128..e091cbc 100644 --- a/focusEvents.go +++ b/focusEvents.go @@ -49,13 +49,17 @@ 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. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetFocusListeners(view View, subviewID ...string) []func(View) { 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. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetLostFocusListeners(view View, subviewID ...string) []func(View) { return getNoArgEventListeners[View](view, subviewID, LostFocusEvent) } diff --git a/gridLayout.go b/gridLayout.go index ff1474c..619d416 100644 --- a/gridLayout.go +++ b/gridLayout.go @@ -506,26 +506,34 @@ func gridCellSizes(properties Properties, tag PropertyName, session Session) []S } // GetCellVerticalAlign returns the vertical align of a GridLayout cell content: TopAlign (0), BottomAlign (1), CenterAlign (2), StretchAlign (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetCellVerticalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, CellVerticalAlign, StretchAlign, false) } // GetCellHorizontalAlign returns the vertical align of a GridLayout cell content: LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetCellHorizontalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, CellHorizontalAlign, StretchAlign, false) } // GetGridAutoFlow returns the value of the "grid-auto-flow" property -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetGridAutoFlow(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, GridAutoFlow, 0, false) } // GetCellWidth returns the width of a GridLayout cell. If the result is an empty array, then the width is not set. // If the result is a single value array, then the width of all cell is equal. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetCellWidth(view View, subviewID ...string) []SizeUnit { if view = getSubview(view, subviewID); view != nil { return gridCellSizes(view, CellWidth, view.Session()) @@ -535,7 +543,9 @@ func GetCellWidth(view View, subviewID ...string) []SizeUnit { // GetCellHeight returns the height of a GridLayout cell. If the result is an empty array, then the height is not set. // If the result is a single value array, then the height of all cell is equal. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetCellHeight(view View, subviewID ...string) []SizeUnit { if view = getSubview(view, subviewID); view != nil { return gridCellSizes(view, CellHeight, view.Session()) @@ -544,13 +554,17 @@ func GetCellHeight(view View, subviewID ...string) []SizeUnit { } // GetGridRowGap returns the gap between GridLayout rows. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetGridRowGap(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, GridRowGap, false) } // GetGridColumnGap returns the gap between GridLayout columns. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetGridColumnGap(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, GridColumnGap, false) } diff --git a/keyEvents.go b/keyEvents.go index a26419f..22f7621 100644 --- a/keyEvents.go +++ b/keyEvents.go @@ -434,15 +434,13 @@ func (event *KeyEvent) init(data DataObject) { } func keyEventsHtml(view View, buffer *strings.Builder) { - if len(getOneArgEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 { + if len(getOneArgEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 || + (view.Focusable() && len(getOneArgEventListeners[View, MouseEvent](view, nil, ClickEvent)) > 0) { + buffer.WriteString(`onkeydown="keyDownEvent(this, event)" `) - } else if view.Focusable() { - if len(getOneArgEventListeners[View, MouseEvent](view, nil, ClickEvent)) > 0 { - buffer.WriteString(`onkeydown="keyDownEvent(this, event)" `) - } } - if listeners := getOneArgEventListeners[View, KeyEvent](view, nil, KeyUpEvent); len(listeners) > 0 { + if len(getOneArgEventListeners[View, KeyEvent](view, nil, KeyUpEvent)) > 0 { buffer.WriteString(`onkeyup="keyUpEvent(this, event)" `) } } @@ -454,7 +452,7 @@ func handleKeyEvents(view View, tag PropertyName, data DataObject) { if len(listeners) > 0 { for _, listener := range listeners { - listener(view, event) + listener.Run(view, event) } return } @@ -477,20 +475,38 @@ func handleKeyEvents(view View, tag PropertyName, data DataObject) { ScreenY: view.Frame().Top + view.Frame().Height/2, } for _, listener := range listeners { - listener(view, clickEvent) + listener.Run(view, clickEvent) } } } } // 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 getOneArgEventListeners[View, KeyEvent](view, subviewID, KeyDownEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.KeyEvent), +// - func(rui.View), +// - func(rui.KeyEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetKeyDownListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.KeyEvent), +// - func(rui.View), +// - func(rui.KeyEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetKeyUpListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, KeyEvent](view, subviewID, KeyUpEvent) } diff --git a/listLayout.go b/listLayout.go index 55acf8a..48366e8 100644 --- a/listLayout.go +++ b/listLayout.go @@ -205,21 +205,27 @@ func (listLayout *listLayoutData) UpdateContent() { // GetListVerticalAlign returns the vertical align of a ListLayout or ListView sibview: // TopAlign (0), BottomAlign (1), CenterAlign (2), or StretchAlign (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListVerticalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, VerticalAlign, TopAlign, false) } // GetListHorizontalAlign returns the vertical align of a ListLayout or ListView subview: // LeftAlign (0), RightAlign (1), CenterAlign (2), or StretchAlign (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListHorizontalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, HorizontalAlign, LeftAlign, false) } // GetListOrientation returns the orientation of a ListLayout or ListView subview: // TopDownOrientation (0), StartToEndOrientation (1), BottomUpOrientation (2), or EndToStartOrientation (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListOrientation(view View, subviewID ...string) int { if view = getSubview(view, subviewID); view != nil { if orientation, ok := valueToOrientation(view.Get(Orientation), view.Session()); ok { @@ -238,19 +244,25 @@ func GetListOrientation(view View, subviewID ...string) int { // GetListWrap returns the wrap type of a ListLayout or ListView subview: // ListWrapOff (0), ListWrapOn (1), or ListWrapReverse (2) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListWrap(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, ListWrap, ListWrapOff, false) } // GetListRowGap returns the gap between ListLayout or ListView rows. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListRowGap(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, ListRowGap, false) } // GetListColumnGap returns the gap between ListLayout or ListView columns. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListColumnGap(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, ListColumnGap, false) } diff --git a/listView.go b/listView.go index c90b392..e55d4a3 100644 --- a/listView.go +++ b/listView.go @@ -122,19 +122,13 @@ type ListView interface { // ReloadListViewData updates ListView content ReloadListViewData() - //getCheckedItems() []int getItemFrames() []Frame } type listViewData struct { viewData - //adapter ListAdapter - //clickedListeners []func(ListView, int) - //selectedListeners []func(ListView, int) - //checkedListeners []func(ListView, []int) items []View itemFrame []Frame - //checkedItem []int } // NewListView creates the new list view @@ -279,7 +273,7 @@ func (listView *listViewData) propertyChanged(tag PropertyName) { if listeners := getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent); len(listeners) > 0 { current := GetCurrent(listView) for _, listener := range listeners { - listener(listView, current) + listener.Run(listView, current) } } @@ -288,7 +282,7 @@ func (listView *listViewData) propertyChanged(tag PropertyName) { if listeners := getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent); len(listeners) > 0 { checked := GetListViewCheckedItems(listView) for _, listener := range listeners { - listener(listView, checked) + listener.Run(listView, checked) } } @@ -966,7 +960,7 @@ func (listView *listViewData) handleCommand(self View, command PropertyName, dat func (listView *listViewData) handleCurrent(number int) { listView.properties[Current] = number for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) { - listener(listView, number) + listener.Run(listView, number) } if listener, ok := listView.changeListener[Current]; ok { listener(listView, Current) @@ -1032,12 +1026,12 @@ func (listView *listViewData) onItemClick(number int) { } for _, listener := range getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) { - listener(listView, checkedItem) + listener.Run(listView, checkedItem) } } for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemClickedEvent) { - listener(listView, number) + listener.Run(listView, number) } } @@ -1054,58 +1048,97 @@ func (listView *listViewData) onItemResize(self View, index string, x, y, width, } // GetVerticalAlign return the vertical align of a list: TopAlign (0), BottomAlign (1), CenterAlign (2), StretchAlign (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetVerticalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, VerticalAlign, TopAlign, false) } // GetHorizontalAlign return the vertical align of a list/checkbox: LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetHorizontalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, HorizontalAlign, LeftAlign, false) } // GetListItemClickedListeners returns a ListItemClickedListener 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 GetListItemClickedListeners(view View, subviewID ...string) []func(ListView, int) { - return getOneArgEventListeners[ListView, int](view, subviewID, ListItemClickedEvent) +// +// Result elements can be of the following types: +// - func(rui.ListView, int), +// - func(rui.ListView), +// - func(int), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetListItemClickedListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[ListView, int](view, subviewID, ListItemSelectedEvent) +// +// Result elements can be of the following types: +// - func(rui.ListView, int), +// - func(rui.ListView), +// - func(int), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetListItemSelectedListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[ListView, []int](view, subviewID, ListItemCheckedEvent) +// +// Result elements can be of the following types: +// - func(rui.ListView, []int), +// - func(rui.ListView), +// - func([]int), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetListItemCheckedListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[ListView, []int](view, subviewID, ListItemCheckedEvent) } // GetListItemWidth returns the width of a ListView item. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListItemWidth(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, ItemWidth, false) } // GetListItemHeight returns the height of a ListView item. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListItemHeight(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, ItemHeight, false) } // GetListViewCheckbox returns the ListView checkbox type: NoneCheckbox (0), SingleCheckbox (1), or MultipleCheckbox (2). -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListViewCheckbox(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, ItemCheckbox, 0, false) } // GetListViewCheckedItems returns the array of ListView checked items. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListViewCheckedItems(view View, subviewID ...string) []int { if view = getSubview(view, subviewID); view != nil { if value := view.getRaw(Checked); value != nil { @@ -1138,34 +1171,44 @@ func IsListViewCheckedItem(view View, subviewID string, index int) bool { // GetListViewCheckboxVerticalAlign returns the vertical align of the ListView checkbox: // TopAlign (0), BottomAlign (1), CenterAlign (2) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListViewCheckboxVerticalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, TopAlign, false) } // GetListViewCheckboxHorizontalAlign returns the horizontal align of the ListView checkbox: // LeftAlign (0), RightAlign (1), CenterAlign (2) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListViewCheckboxHorizontalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, LeftAlign, false) } // GetListItemVerticalAlign returns the vertical align of the ListView item content: // TopAlign (0), BottomAlign (1), CenterAlign (2) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListItemVerticalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, ItemVerticalAlign, TopAlign, false) } // ItemHorizontalAlign returns the horizontal align of the ListView item content: // LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListItemHorizontalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, ItemHorizontalAlign, LeftAlign, false) } // GetListItemFrame - returns the location and size of the ListView item in pixels. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListItemFrame(view View, subviewID string, index int) Frame { if subviewID != "" { view = ViewByID(view, subviewID) @@ -1182,7 +1225,9 @@ func GetListItemFrame(view View, subviewID string, index int) Frame { } // GetListViewAdapter - returns the ListView adapter. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetListViewAdapter(view View, subviewID ...string) ListAdapter { if view = getSubview(view, subviewID); view != nil { if value := view.Get(Items); value != nil { diff --git a/mouseEvents.go b/mouseEvents.go index a184483..6d53e42 100644 --- a/mouseEvents.go +++ b/mouseEvents.go @@ -280,56 +280,128 @@ func handleMouseEvents(view View, tag PropertyName, data DataObject) { event.init(data) for _, listener := range listeners { - listener(view, event) + listener.Run(view, event) } } } // 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 getOneArgEventListeners[View, MouseEvent](view, subviewID, ClickEvent) +// +// Result elements can be of the following types: +// - func(View, MouseEvent), +// - func(View), +// - func(MouseEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetClickListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, MouseEvent](view, subviewID, DoubleClickEvent) +// +// Result elements can be of the following types: +// - func(View, MouseEvent), +// - func(View), +// - func(MouseEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetDoubleClickListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, MouseEvent](view, subviewID, ContextMenuEvent) +// +// Result elements can be of the following types: +// - func(View, MouseEvent), +// - func(View), +// - func(MouseEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetContextMenuListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseDown) +// +// Result elements can be of the following types: +// - func(View, MouseEvent), +// - func(View), +// - func(MouseEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetMouseDownListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseUp) +// +// Result elements can be of the following types: +// - func(View, MouseEvent), +// - func(View), +// - func(MouseEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetMouseUpListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseMove) +// +// Result elements can be of the following types: +// - func(View, MouseEvent), +// - func(View), +// - func(MouseEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetMouseMoveListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseOver) +// +// Result elements can be of the following types: +// - func(View, MouseEvent), +// - func(View), +// - func(MouseEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetMouseOverListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseOut) +// +// Result elements can be of the following types: +// - func(View, MouseEvent), +// - func(View), +// - func(MouseEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetMouseOutListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, MouseEvent](view, subviewID, MouseOut) } diff --git a/numberPicker.go b/numberPicker.go index c664bc0..17963b0 100644 --- a/numberPicker.go +++ b/numberPicker.go @@ -298,13 +298,17 @@ func (picker *numberPickerData) handleCommand(self View, command PropertyName, d // GetNumberPickerType returns the type of NumberPicker subview. Valid values: // NumberEditor (0) - NumberPicker is presented by editor (default type); // NumberSlider (1) - NumberPicker is presented by slider. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetNumberPickerType(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, NumberPickerType, NumberEditor, false) } // GetNumberPickerMinMax returns the min and max value of NumberPicker subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetNumberPickerMinMax(view View, subviewID ...string) (float64, float64) { view = getSubview(view, subviewID) pickerType := GetNumberPickerType(view) @@ -328,7 +332,9 @@ func GetNumberPickerMinMax(view View, subviewID ...string) (float64, float64) { } // GetNumberPickerStep returns the value changing step of NumberPicker subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetNumberPickerStep(view View, subviewID ...string) float64 { view = getSubview(view, subviewID) _, max := GetNumberPickerMinMax(view) @@ -341,7 +347,9 @@ func GetNumberPickerStep(view View, subviewID ...string) float64 { } // GetNumberPickerValue returns the value of NumberPicker subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetNumberPickerValue(view View, subviewID ...string) float64 { view = getSubview(view, subviewID) min, _ := GetNumberPickerMinMax(view) @@ -350,13 +358,17 @@ func GetNumberPickerValue(view View, subviewID ...string) float64 { // GetNumberChangedListeners returns the NumberChangedListener list of an NumberPicker subview. // If there are no listeners then the empty list is returned -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetNumberChangedListeners(view View, subviewID ...string) []func(NumberPicker, float64, float64) { 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. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified 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 57d226b..1621f8f 100644 --- a/pointerEvents.go +++ b/pointerEvents.go @@ -192,42 +192,96 @@ func handlePointerEvents(view View, tag PropertyName, data DataObject) { event.init(data) for _, listener := range listeners { - listener(view, event) + listener.Run(view, event) } } // 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 getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerDown) +// +// Result elements can be of the following types: +// - func(View, PointerEvent), +// - func(View), +// - func(PointerEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetPointerDownListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerUp) +// +// Result elements can be of the following types: +// - func(View, PointerEvent), +// - func(View), +// - func(PointerEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetPointerUpListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerMove) +// +// Result elements can be of the following types: +// - func(View, PointerEvent), +// - func(View), +// - func(PointerEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetPointerMoveListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerCancel) +// +// Result elements can be of the following types: +// - func(View, PointerEvent), +// - func(View), +// - func(PointerEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetPointerCancelListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerOver) +// +// Result elements can be of the following types: +// - func(View, PointerEvent), +// - func(View), +// - func(PointerEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetPointerOverListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerOut) +// +// Result elements can be of the following types: +// - func(View, PointerEvent), +// - func(View), +// - func(PointerEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetPointerOutListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, PointerEvent](view, subviewID, PointerOut) } diff --git a/popup.go b/popup.go index 93ad67b..cc77b41 100644 --- a/popup.go +++ b/popup.go @@ -649,7 +649,7 @@ func (popup *popupData) init(view View, popupParams Params) { } case DismissEvent: - if listeners, ok := valueToNoArgEventListeners[Popup](value); ok { + if listeners, ok := valueToNoArgEventListeners[Popup](popup.contentView, value); ok { if listeners != nil { popup.dismissListener = listeners } diff --git a/progressBar.go b/progressBar.go index d37b23c..723b583 100644 --- a/progressBar.go +++ b/progressBar.go @@ -101,13 +101,17 @@ func (progress *progressBarData) htmlProperties(self View, buffer *strings.Build } // GetProgressBarMax returns the max value of ProgressBar subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetProgressBarMax(view View, subviewID ...string) float64 { return floatStyledProperty(view, subviewID, ProgressBarMax, 1) } // GetProgressBarValue returns the value of ProgressBar subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetProgressBarValue(view View, subviewID ...string) float64 { return floatStyledProperty(view, subviewID, ProgressBarValue, 0) } diff --git a/propertyNames.go b/propertyNames.go index b2259d9..b327ca2 100644 --- a/propertyNames.go +++ b/propertyNames.go @@ -2723,4 +2723,6 @@ const ( // // Supported types: string. Tooltip PropertyName = "tooltip" + + Binding PropertyName = "binding" ) diff --git a/resizeEvent.go b/resizeEvent.go index bae4fbc..f102b84 100644 --- a/resizeEvent.go +++ b/resizeEvent.go @@ -25,8 +25,8 @@ func (view *viewData) onResize(self View, x, y, width, height float64) { view.frame.Top = y view.frame.Width = width view.frame.Height = height - for _, listener := range GetResizeListeners(view) { - listener(self, view.frame) + for _, listener := range getOneArgEventListeners[View, Frame](view, nil, ResizeEvent) { + listener.Run(self, view.frame) } } @@ -73,7 +73,9 @@ func (view *viewData) Frame() Frame { } // GetViewFrame returns the size and location of view's viewport. -// If the second argument (subviewID) is not specified or it is "" then the value of the first argument (view) is returned +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetViewFrame(view View, subviewID ...string) Frame { view = getSubview(view, subviewID) if view == nil { @@ -83,7 +85,16 @@ 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 getOneArgEventListeners[View, Frame](view, subviewID, ResizeEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.Frame), +// - func(rui.View), +// - func(rui.Frame), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetResizeListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, Frame](view, subviewID, ResizeEvent) } diff --git a/scrollEvent.go b/scrollEvent.go index 294538e..2b457ee 100644 --- a/scrollEvent.go +++ b/scrollEvent.go @@ -25,8 +25,8 @@ func (view *viewData) onScroll(self View, x, y, width, height float64) { view.scroll.Top = y view.scroll.Width = width view.scroll.Height = height - for _, listener := range GetScrollListeners(view) { - listener(self, view.scroll) + for _, listener := range getOneArgEventListeners[View, Frame](view, nil, ScrollEvent) { + listener.Run(self, view.scroll) } } @@ -42,7 +42,9 @@ func (view *viewData) setScroll(x, y, width, height float64) { } // GetViewScroll returns ... -// If the second argument (subviewID) is not specified or it is "" then a value of the first argument (view) is returned +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetViewScroll(view View, subviewID ...string) Frame { view = getSubview(view, subviewID) if view == nil { @@ -52,13 +54,24 @@ 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 getOneArgEventListeners[View, Frame](view, subviewID, ResizeEvent) +// +// Result elements can be of the following types: +// - func(rui.View, rui.Frame), +// - func(rui.View), +// - func(rui.Frame), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetScrollListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, Frame](view, subviewID, ScrollEvent) } // ScrollTo scrolls the view's content to the given position. -// If the second argument (subviewID) is "" then the first argument (view) is used +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func ScrollViewTo(view View, subviewID string, x, y float64) { if subviewID != "" { view = ViewByID(view, subviewID) @@ -69,7 +82,9 @@ func ScrollViewTo(view View, subviewID string, x, y float64) { } // ScrollViewToEnd scrolls the view's content to the start of view. -// If the second argument (subviewID) is not specified or it is "" then the first argument (view) is used +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func ScrollViewToStart(view View, subviewID ...string) { if view = getSubview(view, subviewID); view != nil { view.Session().callFunc("scrollToStart", view.htmlID()) @@ -77,7 +92,9 @@ func ScrollViewToStart(view View, subviewID ...string) { } // ScrollViewToEnd scrolls the view's content to the end of view. -// If the second argument (subviewID) is not specified or it is "" then the first argument (view) is used +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func ScrollViewToEnd(view View, subviewID ...string) { if view = getSubview(view, subviewID); view != nil { view.Session().callFunc("scrollToEnd", view.htmlID()) diff --git a/stackLayout.go b/stackLayout.go index ef9a238..327bc5c 100644 --- a/stackLayout.go +++ b/stackLayout.go @@ -334,7 +334,9 @@ func (layout *stackLayoutData) init(session Session) { layout.remove = layout.removeFunc layout.changed = layout.propertyChanged - layout.setRaw(TransitionEndEvent, []func(View, PropertyName){layout.transitionFinished}) + layout.setRaw(TransitionEndEvent, []oneArgListener[View, PropertyName]{ + newOneArgListenerVE(layout.transitionFinished), + }) if session.TextDirection() == RightToLeftDirection { layout.setRaw(PushTransform, NewTransformProperty(Params{TranslateX: Percent(-100)})) } else { @@ -434,7 +436,7 @@ func (layout *stackLayoutData) setFunc(tag PropertyName, value any) []PropertyNa // TODO listeners, ok := valueToOneArgEventListeners[View, PropertyName](value) if ok && listeners != nil { - listeners = append(listeners, layout.transitionFinished) + listeners = append(listeners, newOneArgListenerVE(layout.transitionFinished)) layout.setRaw(TransitionEndEvent, listeners) return []PropertyName{tag} } @@ -464,7 +466,9 @@ func (layout *stackLayoutData) propertyChanged(tag PropertyName) { func (layout *stackLayoutData) removeFunc(tag PropertyName) []PropertyName { switch tag { case TransitionEndEvent: - layout.setRaw(TransitionEndEvent, []func(View, PropertyName){layout.transitionFinished}) + layout.setRaw(TransitionEndEvent, []oneArgListener[View, PropertyName]{ + newOneArgListenerVE(layout.transitionFinished), + }) return []PropertyName{tag} } return layout.viewsContainerData.removeFunc(tag) @@ -914,7 +918,9 @@ func (layout *stackLayoutData) htmlSubviews(self View, buffer *strings.Builder) } // IsMoveToFrontAnimation returns "true" if an animation is used when calling the MoveToFront/MoveToFrontByID method of StackLayout interface. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsMoveToFrontAnimation(view View, subviewID ...string) bool { if view = getSubview(view, subviewID); view != nil { if value, ok := boolProperty(view, MoveToFrontAnimation, view.Session()); ok { @@ -950,7 +956,9 @@ func GetPushTiming(view View, subviewID ...string) string { // GetPushTransform returns the start transform (translation, scale and rotation over x, y and z axes as well as a distortion) // for an animated pushing of a child view. // The default value is nil (no transform). -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetPushTransform(view View, subviewID ...string) TransformProperty { return transformStyledProperty(view, subviewID, PushTransform) } diff --git a/tableView.go b/tableView.go index 6ce13d4..0bd784b 100644 --- a/tableView.go +++ b/tableView.go @@ -592,14 +592,6 @@ func (table *tableViewData) init(session Session) { table.tag = "TableView" table.cellViews = []View{} table.cellFrame = []Frame{} - /* - table.cellSelectedListener = []func(TableView, int, int){} - table.cellClickedListener = []func(TableView, int, int){} - table.rowSelectedListener = []func(TableView, int){} - table.rowClickedListener = []func(TableView, int){} - table.current.Row = -1 - table.current.Column = -1 - */ table.normalize = normalizeTableViewTag table.set = table.setFunc table.changed = table.propertyChanged @@ -955,63 +947,6 @@ func tableViewCurrentInactiveStyle(view View) string { return "ruiCurrentTableCell" } -/* -func (table *tableViewData) valueToCellListeners(value any) []func(TableView, int, int) { - if value == nil { - return []func(TableView, int, int){} - } - - switch value := value.(type) { - case func(TableView, int, int): - return []func(TableView, int, int){value} - - case func(int, int): - fn := func(_ TableView, row, column int) { - value(row, column) - } - return []func(TableView, int, int){fn} - - case []func(TableView, int, int): - return value - - case []func(int, int): - listeners := make([]func(TableView, int, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - listeners[i] = func(_ TableView, row, column int) { - val(row, column) - } - } - return listeners - - case []any: - listeners := make([]func(TableView, int, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - switch val := val.(type) { - case func(TableView, int, int): - listeners[i] = val - - case func(int, int): - listeners[i] = func(_ TableView, row, column int) { - val(row, column) - } - - default: - return nil - } - } - return listeners - } - - return nil -} -*/ - func (table *tableViewData) htmlTag() string { return "table" } @@ -1735,8 +1670,8 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data listener(table, Current) } - for _, listener := range GetTableRowSelectedListeners(table) { - listener(table, row) + for _, listener := range getOneArgEventListeners[TableView, int](table, nil, TableRowSelectedEvent) { + listener.Run(table, row) } } @@ -1761,8 +1696,8 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data case "rowClick": if row, ok := dataIntProperty(data, "row"); ok { - for _, listener := range GetTableRowClickedListeners(table) { - listener(table, row) + for _, listener := range getOneArgEventListeners[TableView, int](table, nil, TableRowClickedEvent) { + listener.Run(table, row) } } diff --git a/tableViewUtils.go b/tableViewUtils.go index 152a8e6..69b77e9 100644 --- a/tableViewUtils.go +++ b/tableViewUtils.go @@ -26,7 +26,9 @@ func (cell *tableCellView) cssStyle(self View, builder cssBuilder) { } // GetTableContent returns a TableAdapter which defines the TableView content. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableContent(view View, subviewID ...string) TableAdapter { if view = getSubview(view, subviewID); view != nil { if content := view.getRaw(Content); content != nil { @@ -40,7 +42,9 @@ func GetTableContent(view View, subviewID ...string) TableAdapter { } // GetTableRowStyle returns a TableRowStyle which defines styles of TableView rows. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableRowStyle(view View, subviewID ...string) TableRowStyle { if view = getSubview(view, subviewID); view != nil { for _, tag := range []PropertyName{RowStyle, Content} { @@ -56,7 +60,9 @@ func GetTableRowStyle(view View, subviewID ...string) TableRowStyle { } // GetTableColumnStyle returns a TableColumnStyle which defines styles of TableView columns. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableColumnStyle(view View, subviewID ...string) TableColumnStyle { if view = getSubview(view, subviewID); view != nil { for _, tag := range []PropertyName{ColumnStyle, Content} { @@ -72,7 +78,9 @@ func GetTableColumnStyle(view View, subviewID ...string) TableColumnStyle { } // GetTableCellStyle returns a TableCellStyle which defines styles of TableView cells. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableCellStyle(view View, subviewID ...string) TableCellStyle { if view = getSubview(view, subviewID); view != nil { for _, tag := range []PropertyName{CellStyle, Content} { @@ -90,26 +98,34 @@ func GetTableCellStyle(view View, subviewID ...string) TableCellStyle { // GetTableSelectionMode returns the mode of the TableView elements selection. // Valid values are NoneSelection (0), CellSelection (1), and RowSelection (2). -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableSelectionMode(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, SelectionMode, NoneSelection, false) } // GetTableVerticalAlign returns a vertical align in a TableView cell. Returns one of next values: // TopAlign (0), BottomAlign (1), CenterAlign (2), and BaselineAlign (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableVerticalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, TableVerticalAlign, TopAlign, false) } // GetTableHeadHeight returns the number of rows in the table header. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableHeadHeight(view View, subviewID ...string) int { return intStyledProperty(view, subviewID, HeadHeight, 0) } // GetTableFootHeight returns the number of rows in the table footer. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableFootHeight(view View, subviewID ...string) int { return intStyledProperty(view, subviewID, FootHeight, 0) } @@ -118,7 +134,9 @@ func GetTableFootHeight(view View, subviewID ...string) int { // If there is no selected cell/row or the selection mode is NoneSelection (0), // then a value of the row and column index less than 0 is returned. // If the selection mode is RowSelection (2) then the returned column index is less than 0. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableCurrent(view View, subviewID ...string) CellIndex { if view = getSubview(view, subviewID); view != nil { if selectionMode := GetTableSelectionMode(view); selectionMode != NoneSelection { @@ -130,30 +148,52 @@ func GetTableCurrent(view View, subviewID ...string) CellIndex { // GetTableCellClickedListeners returns listeners of event which occurs when the user clicks on a table cell. // 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. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableCellClickedListeners(view View, subviewID ...string) []func(TableView, int, int) { 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. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTableCellSelectedListeners(view View, subviewID ...string) []func(TableView, int, int) { 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 getOneArgEventListeners[TableView, int](view, subviewID, TableRowClickedEvent) +// +// Result elements can be of the following types: +// - func(rui.TableView, int), +// - func(rui.TableView), +// - func(int), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTableRowClickedListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[TableView, int](view, subviewID, TableRowSelectedEvent) +// +// Result elements can be of the following types: +// - func(rui.TableView, int), +// - func(rui.TableView), +// - func(int), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTableRowSelectedListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[TableView, int](view, subviewID, TableRowSelectedEvent) } // ReloadTableViewData updates TableView diff --git a/tabsLayout.go b/tabsLayout.go index 7a2ee21..5fb6b40 100644 --- a/tabsLayout.go +++ b/tabsLayout.go @@ -238,155 +238,6 @@ func (tabsLayout *tabsLayoutData) propertyChanged(tag PropertyName) { } } -/* - func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayout, int, int) { - if value == nil { - return []func(TabsLayout, int, int){} - } - - switch value := value.(type) { - case func(TabsLayout, int, int): - return []func(TabsLayout, int, int){value} - - case func(TabsLayout, int): - fn := func(view TabsLayout, current, _ int) { - value(view, current) - } - return []func(TabsLayout, int, int){fn} - - case func(TabsLayout): - fn := func(view TabsLayout, _, _ int) { - value(view) - } - return []func(TabsLayout, int, int){fn} - - case func(int, int): - fn := func(_ TabsLayout, current, old int) { - value(current, old) - } - return []func(TabsLayout, int, int){fn} - - case func(int): - fn := func(_ TabsLayout, current, _ int) { - value(current) - } - return []func(TabsLayout, int, int){fn} - - case func(): - fn := func(TabsLayout, int, int) { - value() - } - return []func(TabsLayout, int, int){fn} - - case []func(TabsLayout, int, int): - return value - - case []func(TabsLayout, int): - listeners := make([]func(TabsLayout, int, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - listeners[i] = func(view TabsLayout, current, _ int) { - val(view, current) - } - } - return listeners - - case []func(TabsLayout): - listeners := make([]func(TabsLayout, int, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - listeners[i] = func(view TabsLayout, _, _ int) { - val(view) - } - } - return listeners - - case []func(int, int): - listeners := make([]func(TabsLayout, int, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - listeners[i] = func(_ TabsLayout, current, old int) { - val(current, old) - } - } - return listeners - - case []func(int): - listeners := make([]func(TabsLayout, int, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - listeners[i] = func(_ TabsLayout, current, _ int) { - val(current) - } - } - return listeners - - case []func(): - listeners := make([]func(TabsLayout, int, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - listeners[i] = func(TabsLayout, int, int) { - val() - } - } - return listeners - - case []any: - listeners := make([]func(TabsLayout, int, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - switch val := val.(type) { - case func(TabsLayout, int, int): - listeners[i] = val - - case func(TabsLayout, int): - listeners[i] = func(view TabsLayout, current, _ int) { - val(view, current) - } - - case func(TabsLayout): - listeners[i] = func(view TabsLayout, _, _ int) { - val(view) - } - - case func(int, int): - listeners[i] = func(_ TabsLayout, current, old int) { - val(current, old) - } - - case func(int): - listeners[i] = func(_ TabsLayout, current, _ int) { - val(current) - } - - case func(): - listeners[i] = func(TabsLayout, int, int) { - val() - } - - default: - return nil - } - } - return listeners - } - - return nil - } -*/ - func (tabsLayout *tabsLayoutData) tabsLocation() int { tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0) return tabs @@ -504,7 +355,7 @@ func (tabsLayout *tabsLayoutData) ListItem(index int, session Session) View { Content: "✕", ClickEvent: func() { for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) { - listener(tabsLayout, index) + listener.Run(tabsLayout, index) } }, })) @@ -892,7 +743,7 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName, if numberText, ok := data.PropertyValue("number"); ok { if number, err := strconv.Atoi(numberText); err == nil { for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) { - listener(tabsLayout, number) + listener.Run(tabsLayout, number) } } } @@ -900,3 +751,18 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName, } return tabsLayout.viewsContainerData.handleCommand(self, command, data) } + +// GetTabCloseEventListeners returns the "tab-close-event" listener list. If there are no listeners then the empty list is returned. +// +// Result elements can be of the following types: +// - func(rui.TabsLayout, int), +// - func(rui.TabsLayout), +// - func(int), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTabCloseEventListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[TabsLayout, int](view, subviewID, TabCloseEvent) +} diff --git a/textView.go b/textView.go index a21413f..efcab65 100644 --- a/textView.go +++ b/textView.go @@ -111,7 +111,9 @@ func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) { // GetTextOverflow returns a value of the "text-overflow" property: // TextOverflowClip (0) or TextOverflowEllipsis (1). -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextOverflow(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, TextOverflow, SingleLineText, false) } diff --git a/timePicker.go b/timePicker.go index a85ad18..9d8dea2 100644 --- a/timePicker.go +++ b/timePicker.go @@ -373,7 +373,9 @@ func getTimeProperty(view View, mainTag, shortTag PropertyName) (time.Time, bool // GetTimePickerMin returns the min time of TimePicker subview and "true" as the second value if the min time is set, // "false" as the second value otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTimePickerMin(view View, subviewID ...string) (time.Time, bool) { if view = getSubview(view, subviewID); view != nil { return getTimeProperty(view, TimePickerMin, Min) @@ -383,7 +385,9 @@ func GetTimePickerMin(view View, subviewID ...string) (time.Time, bool) { // GetTimePickerMax returns the max time of TimePicker subview and "true" as the second value if the min time is set, // "false" as the second value otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTimePickerMax(view View, subviewID ...string) (time.Time, bool) { if view = getSubview(view, subviewID); view != nil { return getTimeProperty(view, TimePickerMax, Max) @@ -392,13 +396,17 @@ func GetTimePickerMax(view View, subviewID ...string) (time.Time, bool) { } // GetTimePickerStep returns the time changing step in seconds of TimePicker subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTimePickerStep(view View, subviewID ...string) int { return intStyledProperty(view, subviewID, TimePickerStep, 60) } // GetTimePickerValue returns the time of TimePicker subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTimePickerValue(view View, subviewID ...string) time.Time { if view = getSubview(view, subviewID); view == nil { return time.Now() @@ -409,7 +417,9 @@ func GetTimePickerValue(view View, subviewID ...string) time.Time { // GetTimeChangedListeners returns the TimeChangedListener list of an TimePicker subview. // If there are no listeners then the empty list is returned -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTimeChangedListeners(view View, subviewID ...string) []func(TimePicker, time.Time, time.Time) { return getTwoArgEventListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent) } diff --git a/touchEvents.go b/touchEvents.go index 68d0d50..4a1a73e 100644 --- a/touchEvents.go +++ b/touchEvents.go @@ -193,30 +193,66 @@ func handleTouchEvents(view View, tag PropertyName, data DataObject) { event.init(data) for _, listener := range listeners { - listener(view, event) + listener.Run(view, event) } } // 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 getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchStart) +// +// Result elements can be of the following types: +// - func(rui.View, rui.TouchEvent), +// - func(rui.View), +// - func(rui.TouchEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTouchStartListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchEnd) +// +// Result elements can be of the following types: +// - func(rui.View, rui.TouchEvent), +// - func(rui.View), +// - func(rui.TouchEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTouchEndListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchMove) +// +// Result elements can be of the following types: +// - func(rui.View, rui.TouchEvent), +// - func(rui.View), +// - func(rui.TouchEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTouchMoveListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[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 getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchCancel) +// +// Result elements can be of the following types: +// - func(rui.View, rui.TouchEvent), +// - func(rui.View), +// - func(rui.TouchEvent), +// - func(), +// - string. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. +func GetTouchCancelListeners(view View, subviewID ...string) []any { + return getOneArgEventRawListeners[View, TouchEvent](view, subviewID, TouchCancel) } diff --git a/transform.go b/transform.go index e52cfda..6a0c600 100644 --- a/transform.go +++ b/transform.go @@ -647,7 +647,9 @@ func transformOriginCSS(x, y, z SizeUnit, session Session) string { // GetTransform returns a view transform: translation, scale and rotation over x, y and z axes as well as a distortion of a view along x and y axes. // The default value is nil (no transform) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTransform(view View, subviewID ...string) TransformProperty { return transformStyledProperty(view, subviewID, Transform) } @@ -655,14 +657,18 @@ func GetTransform(view View, subviewID ...string) TransformProperty { // GetPerspective returns a distance between the z = 0 plane and the user in order to give a 3D-positioned // element some perspective. Each 3D element with z > 0 becomes larger; each 3D-element with z < 0 becomes smaller. // The default value is 0 (no 3D effects). -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetPerspective(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, Perspective, false) } // GetPerspectiveOrigin returns a x- and y-coordinate of the position at which the viewer is looking. // It is used as the vanishing point by the Perspective property. The default value is (50%, 50%). -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetPerspectiveOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit) { view = getSubview(view, subviewID) if view == nil { @@ -675,14 +681,18 @@ func GetPerspectiveOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit) { // visible when turned towards the user. Values: // true - the back face is visible when turned towards the user (default value). // false - the back face is hidden, effectively making the element invisible when turned away from the user. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetBackfaceVisible(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, BackfaceVisible, false) } // 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. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTransformOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) { view = getSubview(view, subviewID) if view == nil { @@ -692,7 +702,9 @@ func GetTransformOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit, Siz } // GetTranslate returns a x-, y-, and z-axis translation value of a 2D/3D translation -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTranslate(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) { if transform := GetTransform(view, subviewID...); transform != nil { return transform.getTranslate(view.Session()) @@ -702,7 +714,9 @@ func GetTranslate(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) // GetSkew returns a angles to use to distort the element along the abscissa (x-axis) // and the ordinate (y-axis). The default value is 0. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetSkew(view View, subviewID ...string) (AngleUnit, AngleUnit) { if transform := GetTransform(view, subviewID...); transform != nil { x, y, _ := transform.getSkew(view.Session()) @@ -712,7 +726,9 @@ func GetSkew(view View, subviewID ...string) (AngleUnit, AngleUnit) { } // GetScale returns a x-, y-, and z-axis scaling value of a 2D/3D scale. The default value is 1. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetScale(view View, subviewID ...string) (float64, float64, float64) { if transform := GetTransform(view, subviewID...); transform != nil { session := view.Session() @@ -725,7 +741,9 @@ func GetScale(view View, subviewID ...string) (float64, float64, float64) { } // GetRotate returns a x-, y, z-coordinate of the vector denoting the axis of rotation, and the angle of the view rotation -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetRotate(view View, subviewID ...string) (float64, float64, float64, AngleUnit) { if transform := GetTransform(view, subviewID...); transform != nil { session := view.Session() diff --git a/view.go b/view.go index 72fc4a8..2b2ab01 100644 --- a/view.go +++ b/view.go @@ -92,6 +92,7 @@ type View interface { addToCSSStyle(addCSS map[string]string) exscludeTags() []PropertyName htmlDisabledProperty() bool + binding() any onResize(self View, x, y, width, height float64) onItemResize(self View, index string, x, y, width, height float64) @@ -195,6 +196,18 @@ func (view *viewData) ID() string { return view.viewID } +func (view *viewData) binding() any { + if result := view.getRaw(Binding); result != nil { + return result + } + + if parent := view.Parent(); parent != nil { + return parent.binding() + } + + return nil +} + func (view *viewData) ViewByID(id string) View { if id == view.ID() { if v := view.session.viewByHTMLID(view.htmlID()); v != nil { @@ -304,6 +317,14 @@ func (view *viewData) removeFunc(tag PropertyName) []PropertyName { changedTags = []PropertyName{} } + case Binding: + if view.getRaw(Binding) != nil { + view.setRaw(Binding, nil) + changedTags = []PropertyName{Binding} + } else { + changedTags = []PropertyName{} + } + case Animation: if val := view.getRaw(Animation); val != nil { if animations, ok := val.([]AnimationProperty); ok { @@ -336,6 +357,10 @@ func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName { notCompatibleType(ID, value) return nil + case Binding: + view.setRaw(Binding, value) + return []PropertyName{Binding} + case Animation: oldAnimations := []AnimationProperty{} if val := view.getRaw(Animation); val != nil { @@ -386,20 +411,15 @@ func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName { 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 + if listeners, ok := valueToOneArgEventListeners[View, string](view); ok && len(listeners) > 0 { + newListeners := make([]oneArgListener[View, PropertyName], len(listeners)) + for i, listener := range listeners { + newListeners[i] = newOneArgListenerVE(func(view View, name PropertyName) { + listener.Run(view, string(name)) + }) } - view.setRaw(tag, nil) - return nil + view.setRaw(tag, newListeners) + result = []PropertyName{tag} } } return result diff --git a/viewUtils.go b/viewUtils.go index 3f5f921..42cc6b0 100644 --- a/viewUtils.go +++ b/viewUtils.go @@ -355,31 +355,41 @@ func GetTextShadows(view View, subviewID ...string) []ShadowProperty { } // GetBackgroundColor returns a background color of the subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetBackgroundColor(view View, subviewID ...string) Color { return colorStyledProperty(view, subviewID, BackgroundColor, false) } // GetAccentColor returns the accent color for UI controls generated by some elements. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetAccentColor(view View, subviewID ...string) Color { return colorStyledProperty(view, subviewID, AccentColor, false) } // GetFontName returns the subview font. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetFontName(view View, subviewID ...string) string { return stringStyledProperty(view, nil, FontName, true) } // GetTextColor returns a text color of the subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextColor(view View, subviewID ...string) Color { return colorStyledProperty(view, subviewID, TextColor, true) } // GetTextSize returns a text size of the subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextSize(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, TextSize, true) } @@ -392,7 +402,9 @@ func GetTabSize(view View, subviewID ...string) int { // GetTextWeight returns a text weight of the subview. Returns one of next values: // 1, 2, 3, 4 (normal text), 5, 6, 7 (bold text), 8 and 9 -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextWeight(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, TextWeight, NormalFont, true) } @@ -401,7 +413,8 @@ func GetTextWeight(view View, subviewID ...string) int { // // LeftAlign = 0, RightAlign = 1, CenterAlign = 2, JustifyAlign = 3 // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, TextAlign, LeftAlign, true) } @@ -410,89 +423,116 @@ func GetTextAlign(view View, subviewID ...string) int { // // TextWrapOn = 0, TextWrapOff = 1, TextWrapBalance = 3 // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextWrap(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, TextWrap, TextWrapOn, true) } // GetTextIndent returns a text indent of the subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextIndent(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, TextIndent, true) } // GetLetterSpacing returns a letter spacing of the subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetLetterSpacing(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, LetterSpacing, true) } // GetWordSpacing returns a word spacing of the subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetWordSpacing(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, WordSpacing, true) } // GetLineHeight returns a height of a text line of the subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetLineHeight(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, LineHeight, true) } // IsItalic returns "true" if a text font of the subview is displayed in italics, "false" otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsItalic(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, Italic, true) } // IsSmallCaps returns "true" if a text font of the subview is displayed in small caps, "false" otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsSmallCaps(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, SmallCaps, true) } // IsStrikethrough returns "true" if a text font of the subview is displayed strikethrough, "false" otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsStrikethrough(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, Strikethrough, true) } // IsOverline returns "true" if a text font of the subview is displayed overlined, "false" otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsOverline(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, Overline, true) } // IsUnderline returns "true" if a text font of the subview is displayed underlined, "false" otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsUnderline(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, Underline, true) } // GetTextLineThickness returns the stroke thickness of the decoration line that // is used on text in an element, such as a line-through, underline, or overline. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextLineThickness(view View, subviewID ...string) SizeUnit { return sizeStyledProperty(view, subviewID, TextLineThickness, true) } // GetTextLineStyle returns the stroke style of the decoration line that // is used on text in an element, such as a line-through, underline, or overline. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextLineStyle(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, TextLineStyle, SolidLine, true) } // GetTextLineColor returns the stroke color of the decoration line that // is used on text in an element, such as a line-through, underline, or overline. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextLineColor(view View, subviewID ...string) Color { return colorStyledProperty(view, subviewID, TextLineColor, true) } // GetTextTransform returns a text transform of the subview. Return one of next values: // NoneTextTransform (0), CapitalizeTextTransform (1), LowerCaseTextTransform (2) or UpperCaseTextTransform (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextTransform(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, TextTransform, NoneTextTransform, true) } @@ -500,14 +540,18 @@ func GetTextTransform(view View, subviewID ...string) int { // GetWritingMode returns whether lines of text are laid out horizontally or vertically, as well as // the direction in which blocks progress. Valid values are HorizontalTopToBottom (0), // HorizontalBottomToTop (1), VerticalRightToLeft (2) and VerticalLeftToRight (3) -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetWritingMode(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, WritingMode, HorizontalTopToBottom, true) } // GetTextDirection - returns a direction of text, table columns, and horizontal overflow. // Valid values are SystemTextDirection (0), LeftToRightDirection (1), and RightToLeftDirection (2). -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTextDirection(view View, subviewID ...string) int { if view == nil { return SystemTextDirection @@ -519,7 +563,9 @@ func GetTextDirection(view View, subviewID ...string) int { // GetVerticalTextOrientation returns a orientation of the text characters in a line. It only affects text // in vertical mode (when "writing-mode" is "vertical-right-to-left" or "vertical-left-to-right"). // Valid values are MixedTextOrientation (0), UprightTextOrientation (1), and SidewaysTextOrientation (2). -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetVerticalTextOrientation(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, VerticalTextOrientation, MixedTextOrientation, true) } @@ -761,7 +807,9 @@ func BlurViewByID(viewID string, session Session) { } // GetCurrent returns the index of the selected item (<0 if there is no a selected item) or the current view index (StackLayout, TabsLayout). -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetCurrent(view View, subviewID ...string) int { defaultValue := -1 if view = getSubview(view, subviewID); view != nil { @@ -775,7 +823,9 @@ func GetCurrent(view View, subviewID ...string) int { } // IsUserSelect returns "true" if the user can select text, "false" otherwise. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func IsUserSelect(view View, subviewID ...string) bool { if view = getSubview(view, subviewID); view != nil { value, _ := isUserSelect(view) @@ -821,7 +871,8 @@ func isUserSelect(view View) (bool, bool) { // BlendSoftLight (9), BlendDifference (10), BlendExclusion (11), BlendHue (12), // BlendSaturation (13), BlendColor (14), BlendLuminosity (15) // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetMixBlendMode(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, MixBlendMode, BlendNormal, true) } @@ -833,13 +884,16 @@ func GetMixBlendMode(view View, subviewID ...string) int { // BlendSoftLight (9), BlendDifference (10), BlendExclusion (11), BlendHue (12), // BlendSaturation (13), BlendColor (14), BlendLuminosity (15) // -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetBackgroundBlendMode(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, BackgroundBlendMode, BlendNormal, true) } // GetTooltip returns a tooltip text of the subview. -// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. +// +// The second argument (subviewID) specifies the path to the child element whose value needs to be returned. +// If it is not specified then a value from the first argument (view) is returned. func GetTooltip(view View, subviewID ...string) string { if view = getSubview(view, subviewID); view != nil { if value := view.Get(Tooltip); value != nil {