From e23ad83b6cb7f0b1951f7c45da707560d36a4497 Mon Sep 17 00:00:00 2001 From: Alexei Anoshenko Date: Wed, 27 Jul 2022 20:31:57 +0300 Subject: [PATCH] Refactoring and optimisation --- animationEvents.go | 163 +++--------------------------------- colorPicker.go | 69 ++-------------- datePicker.go | 69 ++-------------- dropDownList.go | 69 +++------------- editView.go | 76 +++-------------- filePicker.go | 69 ++-------------- focusEvents.go | 24 +++--- imageView.go | 79 ++---------------- keyEvents.go | 117 +++++++++++++------------- listView.go | 129 ++++------------------------- mediaPlayer.go | 200 +-------------------------------------------- mouseEvents.go | 173 ++++----------------------------------- numberPicker.go | 64 ++------------- pointerEvents.go | 155 ++--------------------------------- popup.go | 11 ++- resizeEvent.go | 156 ++--------------------------------- scrollEvent.go | 14 +--- session.go | 2 +- stackLayout.go | 4 +- tableView.go | 69 ++-------------- tabsLayout.go | 61 +------------- timePicker.go | 69 ++-------------- touchEvents.go | 151 ++-------------------------------- 23 files changed, 228 insertions(+), 1765 deletions(-) diff --git a/animationEvents.go b/animationEvents.go index 4bb45e1..fc774c0 100644 --- a/animationEvents.go +++ b/animationEvents.go @@ -51,131 +51,6 @@ const ( AnimationIterationEvent = "animation-iteration-event" ) -func valueToAnimationListeners(value any) ([]func(View, string), bool) { - if value == nil { - return nil, true - } - - switch value := value.(type) { - case func(View, string): - return []func(View, string){value}, true - - case func(string): - fn := func(_ View, event string) { - value(event) - } - return []func(View, string){fn}, true - - case func(View): - fn := func(view View, _ string) { - value(view) - } - return []func(View, string){fn}, true - - case func(): - fn := func(View, string) { - value() - } - return []func(View, string){fn}, true - - case []func(View, string): - if len(value) == 0 { - return nil, true - } - for _, fn := range value { - if fn == nil { - return nil, false - } - } - return value, true - - case []func(string): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, string), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(_ View, event string) { - v(event) - } - } - return listeners, true - - case []func(View): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, string), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(view View, _ string) { - v(view) - } - } - return listeners, true - - case []func(): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, string), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(View, string) { - v() - } - } - return listeners, true - - case []any: - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, string), count) - for i, v := range value { - if v == nil { - return nil, false - } - switch v := v.(type) { - case func(View, string): - listeners[i] = v - - case func(string): - listeners[i] = func(_ View, event string) { - v(event) - } - - case func(View): - listeners[i] = func(view View, _ string) { - v(view) - } - - case func(): - listeners[i] = func(View, string) { - v() - } - - default: - return nil, false - } - } - return listeners, true - } - - return nil, false -} - var transitionEvents = map[string]struct{ jsEvent, jsFunc string }{ TransitionRunEvent: {jsEvent: "ontransitionrun", jsFunc: "transitionRunEvent"}, TransitionStartEvent: {jsEvent: "ontransitionstart", jsFunc: "transitionStartEvent"}, @@ -184,7 +59,7 @@ var transitionEvents = map[string]struct{ jsEvent, jsFunc string }{ } func (view *viewData) setTransitionListener(tag string, value any) bool { - listeners, ok := valueToAnimationListeners(value) + listeners, ok := valueToEventListeners[View, string](value) if !ok { notCompatibleType(tag, value) return false @@ -212,20 +87,6 @@ func (view *viewData) removeTransitionListener(tag string) { } } -func getAnimationListeners(view View, subviewID string, tag string) []func(View, string) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(tag); value != nil { - if result, ok := value.([]func(View, string)); ok { - return result - } - } - } - return []func(View, string){} -} - func transitionEventsHtml(view View, buffer *strings.Builder) { for tag, js := range transitionEvents { if value := view.getRaw(tag); value != nil { @@ -250,7 +111,7 @@ func (view *viewData) handleTransitionEvents(tag string, data DataObject) { } } - for _, listener := range getAnimationListeners(view, "", tag) { + for _, listener := range getEventListeners[View, string](view, "", tag) { listener(view, property) } } @@ -264,7 +125,7 @@ var animationEvents = map[string]struct{ jsEvent, jsFunc string }{ } func (view *viewData) setAnimationListener(tag string, value any) bool { - listeners, ok := valueToAnimationListeners(value) + listeners, ok := valueToEventListeners[View, string](value) if !ok { notCompatibleType(tag, value) return false @@ -303,7 +164,7 @@ func animationEventsHtml(view View, buffer *strings.Builder) { } func (view *viewData) handleAnimationEvents(tag string, data DataObject) { - if listeners := getAnimationListeners(view, "", tag); len(listeners) > 0 { + if listeners := getEventListeners[View, string](view, "", tag); len(listeners) > 0 { id := "" if name, ok := data.PropertyValue("name"); ok { for _, animation := range GetAnimation(view, "") { @@ -322,54 +183,54 @@ func (view *viewData) handleAnimationEvents(tag string, data DataObject) { // If there are no listeners then the empty list is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetTransitionRunListeners(view View, subviewID string) []func(View, string) { - return getAnimationListeners(view, subviewID, TransitionRunEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetTransitionStartListeners(view View, subviewID string) []func(View, string) { - return getAnimationListeners(view, subviewID, TransitionStartEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetTransitionEndListeners(view View, subviewID string) []func(View, string) { - return getAnimationListeners(view, subviewID, TransitionEndEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetTransitionCancelListeners(view View, subviewID string) []func(View, string) { - return getAnimationListeners(view, subviewID, TransitionCancelEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetAnimationStartListeners(view View, subviewID string) []func(View, string) { - return getAnimationListeners(view, subviewID, AnimationStartEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetAnimationEndListeners(view View, subviewID string) []func(View, string) { - return getAnimationListeners(view, subviewID, AnimationEndEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetAnimationCancelListeners(view View, subviewID string) []func(View, string) { - return getAnimationListeners(view, subviewID, AnimationCancelEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetAnimationIterationListeners(view View, subviewID string) []func(View, string) { - return getAnimationListeners(view, subviewID, AnimationIterationEvent) + return getEventListeners[View, string](view, subviewID, AnimationIterationEvent) } diff --git a/colorPicker.go b/colorPicker.go index 130a4f8..9719674 100644 --- a/colorPicker.go +++ b/colorPicker.go @@ -87,57 +87,14 @@ func (picker *colorPickerData) set(tag string, value any) bool { switch tag { case ColorChangedEvent: - switch value := value.(type) { - case func(ColorPicker, Color): - picker.colorChangedListeners = []func(ColorPicker, Color){value} - - case func(Color): - fn := func(_ ColorPicker, date Color) { - value(date) - } - picker.colorChangedListeners = []func(ColorPicker, Color){fn} - - case []func(ColorPicker, Color): - picker.colorChangedListeners = value - - case []func(Color): - listeners := make([]func(ColorPicker, Color), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - listeners[i] = func(_ ColorPicker, date Color) { - val(date) - } - } - picker.colorChangedListeners = listeners - - case []any: - listeners := make([]func(ColorPicker, Color), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - switch val := val.(type) { - case func(ColorPicker, Color): - listeners[i] = val - - case func(Color): - listeners[i] = func(_ ColorPicker, date Color) { - val(date) - } - - default: - notCompatibleType(tag, val) - return false - } - } - picker.colorChangedListeners = listeners + listeners, ok := valueToEventListeners[ColorPicker, Color](value) + if !ok { + notCompatibleType(tag, value) + return false + } else if listeners == nil { + listeners = []func(ColorPicker, Color){} } + picker.colorChangedListeners = listeners picker.propertyChangedEvent(tag) return true @@ -249,15 +206,5 @@ func GetColorPickerValue(view View, subviewID string) Color { // If there are no listeners then the empty list is returned // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetColorChangedListeners(view View, subviewID string) []func(ColorPicker, Color) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(ColorChangedEvent); value != nil { - if listeners, ok := value.([]func(ColorPicker, Color)); ok { - return listeners - } - } - } - return []func(ColorPicker, Color){} + return getEventListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent) } diff --git a/datePicker.go b/datePicker.go index edd8c15..a9033d1 100644 --- a/datePicker.go +++ b/datePicker.go @@ -235,57 +235,14 @@ func (picker *datePickerData) set(tag string, value any) bool { } case DateChangedEvent: - switch value := value.(type) { - case func(DatePicker, time.Time): - picker.dateChangedListeners = []func(DatePicker, time.Time){value} - - case func(time.Time): - fn := func(_ DatePicker, date time.Time) { - value(date) - } - picker.dateChangedListeners = []func(DatePicker, time.Time){fn} - - case []func(DatePicker, time.Time): - picker.dateChangedListeners = value - - case []func(time.Time): - listeners := make([]func(DatePicker, time.Time), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - listeners[i] = func(_ DatePicker, date time.Time) { - val(date) - } - } - picker.dateChangedListeners = listeners - - case []any: - listeners := make([]func(DatePicker, time.Time), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - switch val := val.(type) { - case func(DatePicker, time.Time): - listeners[i] = val - - case func(time.Time): - listeners[i] = func(_ DatePicker, date time.Time) { - val(date) - } - - default: - notCompatibleType(tag, val) - return false - } - } - picker.dateChangedListeners = listeners + listeners, ok := valueToEventListeners[DatePicker, time.Time](value) + if !ok { + notCompatibleType(tag, value) + return false + } else if listeners == nil { + listeners = []func(DatePicker, time.Time){} } + picker.dateChangedListeners = listeners picker.propertyChangedEvent(tag) return true @@ -463,15 +420,5 @@ func GetDatePickerValue(view View, subviewID string) time.Time { // If there are no listeners then the empty list is returned // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetDateChangedListeners(view View, subviewID string) []func(DatePicker, time.Time) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(DateChangedEvent); value != nil { - if listeners, ok := value.([]func(DatePicker, time.Time)); ok { - return listeners - } - } - } - return []func(DatePicker, time.Time){} + return getEventListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent) } diff --git a/dropDownList.go b/dropDownList.go index 470e749..c770b39 100644 --- a/dropDownList.go +++ b/dropDownList.go @@ -113,7 +113,16 @@ func (list *dropDownListData) set(tag string, value any) bool { return list.setDisabledItems(value) case DropDownEvent: - return list.setDropDownListener(value) + listeners, ok := valueToEventListeners[DropDownList, int](value) + if !ok { + notCompatibleType(tag, value) + return false + } else if listeners == nil { + listeners = []func(DropDownList, int){} + } + list.dropDownListener = listeners + list.propertyChangedEvent(tag) + return true case Current: oldCurrent := GetCurrent(list, "") @@ -291,64 +300,6 @@ func (list *dropDownListData) setDisabledItems(value any) bool { } -func (list *dropDownListData) setDropDownListener(value any) bool { - switch value := value.(type) { - case func(DropDownList, int): - list.dropDownListener = []func(DropDownList, int){value} - - case func(int): - list.dropDownListener = []func(DropDownList, int){func(_ DropDownList, index int) { - value(index) - }} - - case []func(DropDownList, int): - list.dropDownListener = value - - case []func(int): - listeners := make([]func(DropDownList, int), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(DropDownEvent, value) - return false - } - listeners[i] = func(_ DropDownList, index int) { - val(index) - } - } - list.dropDownListener = listeners - - case []any: - listeners := make([]func(DropDownList, int), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(DropDownEvent, value) - return false - } - switch val := val.(type) { - case func(DropDownList, int): - listeners[i] = val - - case func(int): - listeners[i] = func(_ DropDownList, index int) { - val(index) - } - - default: - notCompatibleType(DropDownEvent, value) - return false - } - } - list.dropDownListener = listeners - - default: - notCompatibleType(DropDownEvent, value) - return false - } - - list.propertyChangedEvent(DropDownEvent) - return true -} - func (list *dropDownListData) Get(tag string) any { return list.get(strings.ToLower(tag)) } diff --git a/editView.go b/editView.go index a33678c..945dda0 100644 --- a/editView.go +++ b/editView.go @@ -333,75 +333,29 @@ func (edit *editViewData) set(tag string, value any) bool { return false case EditTextChangedEvent: - ok := edit.setChangeListeners(value) + listeners, ok := valueToEventListeners[EditView, string](value) if !ok { notCompatibleType(tag, value) + return false + } else if listeners == nil { + listeners = []func(EditView, string){} } + edit.textChangeListeners = listeners edit.propertyChangedEvent(tag) - return ok + return true } return edit.viewData.set(tag, value) } -func (edit *editViewData) setChangeListeners(value any) bool { - switch value := value.(type) { - case func(EditView, string): - edit.textChangeListeners = []func(EditView, string){value} - - case func(string): - fn := func(_ EditView, text string) { - value(text) - } - edit.textChangeListeners = []func(EditView, string){fn} - - case []func(EditView, string): - edit.textChangeListeners = value - - case []func(string): - listeners := make([]func(EditView, string), len(value)) - for i, v := range value { - if v == nil { - return false - } - listeners[i] = func(_ EditView, text string) { - v(text) - } - } - edit.textChangeListeners = listeners - - case []any: - listeners := make([]func(EditView, string), len(value)) - for i, v := range value { - if v == nil { - return false - } - switch v := v.(type) { - case func(EditView, string): - listeners[i] = v - - case func(string): - listeners[i] = func(_ EditView, text string) { - v(text) - } - - default: - return false - } - } - edit.textChangeListeners = listeners - - default: - return false - } - return true -} - func (edit *editViewData) Get(tag string) any { return edit.get(edit.normalizeTag(tag)) } func (edit *editViewData) get(tag string) any { + if tag == EditTextChangedEvent { + return edit.textChangeListeners + } return edit.viewData.get(tag) } @@ -635,17 +589,7 @@ func IsSpellcheck(view View, subviewID string) bool { // If there are no listeners then the empty list is returned // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetTextChangedListeners(view View, subviewID string) []func(EditView, string) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(EditTextChangedEvent); value != nil { - if result, ok := value.([]func(EditView, string)); ok { - return result - } - } - } - return []func(EditView, string){} + return getEventListeners[EditView, string](view, subviewID, EditTextChangedEvent) } // GetEditViewType returns a value of the Type property of EditView. diff --git a/filePicker.go b/filePicker.go index 97fea43..75819f7 100644 --- a/filePicker.go +++ b/filePicker.go @@ -151,57 +151,14 @@ func (picker *filePickerData) set(tag string, value any) bool { switch tag { case FileSelectedEvent: - switch value := value.(type) { - case func(FilePicker, []FileInfo): - picker.fileSelectedListeners = []func(FilePicker, []FileInfo){value} - - case func([]FileInfo): - fn := func(_ FilePicker, files []FileInfo) { - value(files) - } - picker.fileSelectedListeners = []func(FilePicker, []FileInfo){fn} - - case []func(FilePicker, []FileInfo): - picker.fileSelectedListeners = value - - case []func([]FileInfo): - listeners := make([]func(FilePicker, []FileInfo), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - listeners[i] = func(_ FilePicker, files []FileInfo) { - val(files) - } - } - picker.fileSelectedListeners = listeners - - case []any: - listeners := make([]func(FilePicker, []FileInfo), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - switch val := val.(type) { - case func(FilePicker, []FileInfo): - listeners[i] = val - - case func([]FileInfo): - listeners[i] = func(_ FilePicker, files []FileInfo) { - val(files) - } - - default: - notCompatibleType(tag, val) - return false - } - } - picker.fileSelectedListeners = listeners + listeners, ok := valueToEventListeners[FilePicker, []FileInfo](value) + if !ok { + notCompatibleType(tag, value) + return false + } else if listeners == nil { + listeners = []func(FilePicker, []FileInfo){} } + picker.fileSelectedListeners = listeners picker.propertyChangedEvent(tag) return true @@ -436,15 +393,5 @@ func GetFilePickerAccept(view View, subviewID string) []string { // If there are no listeners then the empty list is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetFileSelectedListeners(view View, subviewID string) []func(FilePicker, []FileInfo) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(FileSelectedEvent); value != nil { - if result, ok := value.([]func(FilePicker, []FileInfo)); ok { - return result - } - } - } - return []func(FilePicker, []FileInfo){} + return getEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent) } diff --git a/focusEvents.go b/focusEvents.go index c40f7a6..db3b146 100644 --- a/focusEvents.go +++ b/focusEvents.go @@ -20,22 +20,22 @@ const ( LostFocusEvent = "lost-focus-event" ) -func valueToFocusListeners(value any) ([]func(View), bool) { +func valueToNoParamListeners[V View](value any) ([]func(V), bool) { if value == nil { return nil, true } switch value := value.(type) { - case func(View): - return []func(View){value}, true + case func(V): + return []func(V){value}, true case func(): - fn := func(View) { + fn := func(V) { value() } - return []func(View){fn}, true + return []func(V){fn}, true - case []func(View): + case []func(V): if len(value) == 0 { return nil, true } @@ -51,12 +51,12 @@ func valueToFocusListeners(value any) ([]func(View), bool) { if count == 0 { return nil, true } - listeners := make([]func(View), count) + listeners := make([]func(V), count) for i, v := range value { if v == nil { return nil, false } - listeners[i] = func(View) { + listeners[i] = func(V) { v() } } @@ -67,17 +67,17 @@ func valueToFocusListeners(value any) ([]func(View), bool) { if count == 0 { return nil, true } - listeners := make([]func(View), count) + listeners := make([]func(V), count) for i, v := range value { if v == nil { return nil, false } switch v := v.(type) { - case func(View): + case func(V): listeners[i] = v case func(): - listeners[i] = func(View) { + listeners[i] = func(V) { v() } @@ -97,7 +97,7 @@ var focusEvents = map[string]struct{ jsEvent, jsFunc string }{ } func (view *viewData) setFocusListener(tag string, value any) bool { - listeners, ok := valueToFocusListeners(value) + listeners, ok := valueToNoParamListeners[View](value) if !ok { notCompatibleType(tag, value) return false diff --git a/imageView.go b/imageView.go index 4d63e57..636c1f7 100644 --- a/imageView.go +++ b/imageView.go @@ -118,77 +118,6 @@ func (imageView *imageViewData) Set(tag string, value any) bool { return imageView.set(imageView.normalizeTag(tag), value) } -func valueToImageListeners(value any) ([]func(ImageView), bool) { - if value == nil { - return nil, true - } - - switch value := value.(type) { - case func(ImageView): - return []func(ImageView){value}, true - - case func(): - fn := func(ImageView) { - value() - } - return []func(ImageView){fn}, true - - case []func(ImageView): - if len(value) == 0 { - return nil, true - } - for _, fn := range value { - if fn == nil { - return nil, false - } - } - return value, true - - case []func(): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(ImageView), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(ImageView) { - v() - } - } - return listeners, true - - case []any: - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(ImageView), count) - for i, v := range value { - if v == nil { - return nil, false - } - switch v := v.(type) { - case func(ImageView): - listeners[i] = v - - case func(): - listeners[i] = func(ImageView) { - v() - } - - default: - return nil, false - } - } - return listeners, true - } - - return nil, false -} - func (imageView *imageViewData) set(tag string, value any) bool { if value == nil { imageView.remove(tag) @@ -228,8 +157,12 @@ func (imageView *imageViewData) set(tag string, value any) bool { notCompatibleType(tag, value) case LoadedEvent, ErrorEvent: - if listeners, ok := valueToImageListeners(value); ok { - imageView.properties[tag] = listeners + if listeners, ok := valueToNoParamListeners[ImageView](value); ok { + if listeners == nil { + delete(imageView.properties, tag) + } else { + imageView.properties[tag] = listeners + } return true } diff --git a/keyEvents.go b/keyEvents.go index acf2602..35a1789 100644 --- a/keyEvents.go +++ b/keyEvents.go @@ -50,34 +50,52 @@ type KeyEvent struct { MetaKey bool } -func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) { +func (event *KeyEvent) init(data DataObject) { + getBool := func(tag string) bool { + if value, ok := data.PropertyValue(tag); ok && value == "1" { + return true + } + return false + } + + event.Key, _ = data.PropertyValue("key") + event.Code, _ = data.PropertyValue("code") + event.TimeStamp = getTimeStamp(data) + event.Repeat = getBool("repeat") + event.CtrlKey = getBool("ctrlKey") + event.ShiftKey = getBool("shiftKey") + event.AltKey = getBool("altKey") + event.MetaKey = getBool("metaKey") +} + +func valueToEventListeners[V View, E any](value any) ([]func(V, E), bool) { if value == nil { return nil, true } switch value := value.(type) { - case func(View, KeyEvent): - return []func(View, KeyEvent){value}, true + case func(V, E): + return []func(V, E){value}, true - case func(KeyEvent): - fn := func(_ View, event KeyEvent) { + case func(E): + fn := func(_ V, event E) { value(event) } - return []func(View, KeyEvent){fn}, true + return []func(V, E){fn}, true - case func(View): - fn := func(view View, _ KeyEvent) { + case func(V): + fn := func(view V, _ E) { value(view) } - return []func(View, KeyEvent){fn}, true + return []func(V, E){fn}, true case func(): - fn := func(View, KeyEvent) { + fn := func(V, E) { value() } - return []func(View, KeyEvent){fn}, true + return []func(V, E){fn}, true - case []func(View, KeyEvent): + case []func(V, E): if len(value) == 0 { return nil, true } @@ -88,33 +106,33 @@ func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) { } return value, true - case []func(KeyEvent): + case []func(E): count := len(value) if count == 0 { return nil, true } - listeners := make([]func(View, KeyEvent), count) + listeners := make([]func(V, E), count) for i, v := range value { if v == nil { return nil, false } - listeners[i] = func(_ View, event KeyEvent) { + listeners[i] = func(_ V, event E) { v(event) } } return listeners, true - case []func(View): + case []func(V): count := len(value) if count == 0 { return nil, true } - listeners := make([]func(View, KeyEvent), count) + listeners := make([]func(V, E), count) for i, v := range value { if v == nil { return nil, false } - listeners[i] = func(view View, _ KeyEvent) { + listeners[i] = func(view V, _ E) { v(view) } } @@ -125,12 +143,12 @@ func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) { if count == 0 { return nil, true } - listeners := make([]func(View, KeyEvent), count) + listeners := make([]func(V, E), count) for i, v := range value { if v == nil { return nil, false } - listeners[i] = func(View, KeyEvent) { + listeners[i] = func(V, E) { v() } } @@ -141,27 +159,27 @@ func valueToKeyListeners(value any) ([]func(View, KeyEvent), bool) { if count == 0 { return nil, true } - listeners := make([]func(View, KeyEvent), count) + listeners := make([]func(V, E), count) for i, v := range value { if v == nil { return nil, false } switch v := v.(type) { - case func(View, KeyEvent): + case func(V, E): listeners[i] = v - case func(KeyEvent): - listeners[i] = func(_ View, event KeyEvent) { + case func(E): + listeners[i] = func(_ V, event E) { v(event) } - case func(View): - listeners[i] = func(view View, _ KeyEvent) { + case func(V): + listeners[i] = func(view V, _ E) { v(view) } case func(): - listeners[i] = func(View, KeyEvent) { + listeners[i] = func(V, E) { v() } @@ -181,7 +199,7 @@ var keyEvents = map[string]struct{ jsEvent, jsFunc string }{ } func (view *viewData) setKeyListener(tag string, value any) bool { - listeners, ok := valueToKeyListeners(value) + listeners, ok := valueToEventListeners[View, KeyEvent](value) if !ok { notCompatibleType(tag, value) return false @@ -209,67 +227,48 @@ func (view *viewData) removeKeyListener(tag string) { } } -func getKeyListeners(view View, subviewID string, tag string) []func(View, KeyEvent) { +func getEventListeners[V View, E any](view View, subviewID string, tag string) []func(V, E) { if subviewID != "" { view = ViewByID(view, subviewID) } if view != nil { if value := view.Get(tag); value != nil { - if result, ok := value.([]func(View, KeyEvent)); ok { + if result, ok := value.([]func(V, E)); ok { return result } } } - return []func(View, KeyEvent){} + return []func(V, E){} } func keyEventsHtml(view View, buffer *strings.Builder) { for tag, js := range keyEvents { - if listeners := getKeyListeners(view, "", tag); len(listeners) > 0 { + if listeners := getEventListeners[View, KeyEvent](view, "", tag); len(listeners) > 0 { buffer.WriteString(js.jsEvent + `="` + js.jsFunc + `(this, event)" `) } } } func handleKeyEvents(view View, tag string, data DataObject) { - listeners := getKeyListeners(view, "", tag) - if len(listeners) == 0 { - return - } + listeners := getEventListeners[View, KeyEvent](view, "", tag) + if len(listeners) > 0 { + var event KeyEvent + event.init(data) - getBool := func(tag string) bool { - if value, ok := data.PropertyValue(tag); ok && value == "1" { - return true + for _, listener := range listeners { + listener(view, event) } - return false - } - - key, _ := data.PropertyValue("key") - code, _ := data.PropertyValue("code") - event := KeyEvent{ - TimeStamp: getTimeStamp(data), - Key: key, - Code: code, - Repeat: getBool("repeat"), - CtrlKey: getBool("ctrlKey"), - ShiftKey: getBool("shiftKey"), - AltKey: getBool("altKey"), - MetaKey: getBool("metaKey"), - } - - for _, listener := range listeners { - listener(view, event) } } // 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 "" then a value from the first argument (view) is returned. func GetKeyDownListeners(view View, subviewID string) []func(View, KeyEvent) { - return getKeyListeners(view, subviewID, KeyDownEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetKeyUpListeners(view View, subviewID string) []func(View, KeyEvent) { - return getKeyListeners(view, subviewID, KeyUpEvent) + return getEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent) } diff --git a/listView.go b/listView.go index 3ad0d24..10cb7e5 100644 --- a/listView.go +++ b/listView.go @@ -205,29 +205,38 @@ func (listView *listViewData) set(tag string, value any) bool { switch tag { case ListItemClickedEvent: - listeners := listView.valueToItemListeners(value) - if listeners == nil { + listeners, ok := valueToEventListeners[ListView, int](value) + if !ok { notCompatibleType(tag, value) return false + } else if listeners == nil { + listeners = []func(ListView, int){} } listView.clickedListeners = listeners listView.propertyChangedEvent(tag) return true case ListItemSelectedEvent: - listeners := listView.valueToItemListeners(value) - if listeners == nil { + listeners, ok := valueToEventListeners[ListView, int](value) + if !ok { notCompatibleType(tag, value) return false + } else if listeners == nil { + listeners = []func(ListView, int){} } listView.selectedListeners = listeners listView.propertyChangedEvent(tag) return true case ListItemCheckedEvent: - if !listView.setItemCheckedEvent(value) { + listeners, ok := valueToEventListeners[ListView, []int](value) + if !ok { + notCompatibleType(tag, value) return false + } else if listeners == nil { + listeners = []func(ListView, []int){} } + listView.checkedListeners = listeners listView.propertyChangedEvent(tag) return true @@ -288,61 +297,6 @@ func (listView *listViewData) set(tag string, value any) bool { return true } -func (listView *listViewData) setItemCheckedEvent(value any) bool { - switch value := value.(type) { - case func(ListView, []int): - listView.checkedListeners = []func(ListView, []int){value} - - case func([]int): - fn := func(_ ListView, date []int) { - value(date) - } - listView.checkedListeners = []func(ListView, []int){fn} - - case []func(ListView, []int): - listView.checkedListeners = value - - case []func([]int): - listeners := make([]func(ListView, []int), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(ListItemCheckedEvent, val) - return false - } - - listeners[i] = func(_ ListView, date []int) { - val(date) - } - } - listView.checkedListeners = listeners - - case []any: - listeners := make([]func(ListView, []int), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(ListItemCheckedEvent, val) - return false - } - - switch val := val.(type) { - case func(ListView, []int): - listeners[i] = val - - case func([]int): - listeners[i] = func(_ ListView, checked []int) { - val(checked) - } - - default: - notCompatibleType(ListItemCheckedEvent, val) - return false - } - } - listView.checkedListeners = listeners - } - return true -} - func (listView *listViewData) Get(tag string) any { return listView.get(listView.normalizeTag(tag)) } @@ -460,61 +414,6 @@ func (listView *listViewData) setItems(value any) bool { return true } -func (listView *listViewData) valueToItemListeners(value any) []func(ListView, int) { - if value == nil { - return []func(ListView, int){} - } - - switch value := value.(type) { - case func(ListView, int): - return []func(ListView, int){value} - - case func(int): - fn := func(_ ListView, index int) { - value(index) - } - return []func(ListView, int){fn} - - case []func(ListView, int): - return value - - case []func(int): - listeners := make([]func(ListView, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - listeners[i] = func(_ ListView, index int) { - val(index) - } - } - return listeners - - case []any: - listeners := make([]func(ListView, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - switch val := val.(type) { - case func(ListView, int): - listeners[i] = val - - case func(int): - listeners[i] = func(_ ListView, index int) { - val(index) - } - - default: - return nil - } - } - return listeners - } - - return nil -} - func (listView *listViewData) setChecked(value any) bool { var checked []int if value == nil { diff --git a/mediaPlayer.go b/mediaPlayer.go index 2b84d75..22a5d54 100644 --- a/mediaPlayer.go +++ b/mediaPlayer.go @@ -205,7 +205,7 @@ func (player *mediaPlayerData) set(tag string, value any) bool { case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, LoadStartEvent, EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent: - if listeners, ok := valueToPlayerListeners(value); ok { + if listeners, ok := valueToNoParamListeners[MediaPlayer](value); ok { if listeners == nil { delete(player.properties, tag) } else { @@ -218,7 +218,7 @@ func (player *mediaPlayerData) set(tag string, value any) bool { notCompatibleType(tag, value) case DurationChangedEvent, RateChangedEvent, TimeUpdateEvent, VolumeChangedEvent: - if listeners, ok := valueToPlayerTimeListeners(value); ok { + if listeners, ok := valueToEventListeners[MediaPlayer, float64](value); ok { if listeners == nil { delete(player.properties, tag) } else { @@ -311,202 +311,6 @@ func (player *mediaPlayerData) setSource(value any) bool { return true } -func valueToPlayerListeners(value any) ([]func(MediaPlayer), bool) { - if value == nil { - return nil, true - } - - switch value := value.(type) { - case func(MediaPlayer): - return []func(MediaPlayer){value}, true - - case func(): - fn := func(MediaPlayer) { - value() - } - return []func(MediaPlayer){fn}, true - - case []func(MediaPlayer): - if len(value) == 0 { - return nil, true - } - for _, fn := range value { - if fn == nil { - return nil, false - } - } - return value, true - - case []func(): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(MediaPlayer), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(MediaPlayer) { - v() - } - } - return listeners, true - - case []any: - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(MediaPlayer), count) - for i, v := range value { - if v == nil { - return nil, false - } - switch v := v.(type) { - case func(MediaPlayer): - listeners[i] = v - - case func(): - listeners[i] = func(MediaPlayer) { - v() - } - - default: - return nil, false - } - } - return listeners, true - } - - return nil, false -} - -func valueToPlayerTimeListeners(value any) ([]func(MediaPlayer, float64), bool) { - if value == nil { - return nil, true - } - - switch value := value.(type) { - case func(MediaPlayer, float64): - return []func(MediaPlayer, float64){value}, true - - case func(float64): - fn := func(_ MediaPlayer, time float64) { - value(time) - } - return []func(MediaPlayer, float64){fn}, true - - case func(MediaPlayer): - fn := func(player MediaPlayer, _ float64) { - value(player) - } - return []func(MediaPlayer, float64){fn}, true - - case func(): - fn := func(MediaPlayer, float64) { - value() - } - return []func(MediaPlayer, float64){fn}, true - - case []func(MediaPlayer, float64): - if len(value) == 0 { - return nil, true - } - for _, fn := range value { - if fn == nil { - return nil, false - } - } - return value, true - - case []func(float64): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(MediaPlayer, float64), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(_ MediaPlayer, time float64) { - v(time) - } - } - return listeners, true - - case []func(MediaPlayer): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(MediaPlayer, float64), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(player MediaPlayer, _ float64) { - v(player) - } - } - return listeners, true - - case []func(): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(MediaPlayer, float64), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(MediaPlayer, float64) { - v() - } - } - return listeners, true - - case []any: - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(MediaPlayer, float64), count) - for i, v := range value { - if v == nil { - return nil, false - } - switch v := v.(type) { - case func(MediaPlayer, float64): - listeners[i] = v - - case func(float64): - listeners[i] = func(_ MediaPlayer, time float64) { - v(time) - } - - case func(MediaPlayer): - listeners[i] = func(player MediaPlayer, _ float64) { - v(player) - } - - case func(): - listeners[i] = func(MediaPlayer, float64) { - v() - } - - default: - return nil, false - } - } - return listeners, true - } - - return nil, false -} - func valueToPlayerErrorListeners(value any) ([]func(MediaPlayer, int, string), bool) { if value == nil { return nil, true diff --git a/mouseEvents.go b/mouseEvents.go index a4905fb..daa547e 100644 --- a/mouseEvents.go +++ b/mouseEvents.go @@ -144,131 +144,6 @@ type MouseEvent struct { MetaKey bool } -func valueToMouseListeners(value any) ([]func(View, MouseEvent), bool) { - if value == nil { - return nil, true - } - - switch value := value.(type) { - case func(View, MouseEvent): - return []func(View, MouseEvent){value}, true - - case func(MouseEvent): - fn := func(_ View, event MouseEvent) { - value(event) - } - return []func(View, MouseEvent){fn}, true - - case func(View): - fn := func(view View, _ MouseEvent) { - value(view) - } - return []func(View, MouseEvent){fn}, true - - case func(): - fn := func(View, MouseEvent) { - value() - } - return []func(View, MouseEvent){fn}, true - - case []func(View, MouseEvent): - if len(value) == 0 { - return nil, true - } - for _, fn := range value { - if fn == nil { - return nil, false - } - } - return value, true - - case []func(MouseEvent): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, MouseEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(_ View, event MouseEvent) { - v(event) - } - } - return listeners, true - - case []func(View): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, MouseEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(view View, _ MouseEvent) { - v(view) - } - } - return listeners, true - - case []func(): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, MouseEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(View, MouseEvent) { - v() - } - } - return listeners, true - - case []any: - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, MouseEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - switch v := v.(type) { - case func(View, MouseEvent): - listeners[i] = v - - case func(MouseEvent): - listeners[i] = func(_ View, event MouseEvent) { - v(event) - } - - case func(View): - listeners[i] = func(view View, _ MouseEvent) { - v(view) - } - - case func(): - listeners[i] = func(View, MouseEvent) { - v() - } - - default: - return nil, false - } - } - return listeners, true - } - - return nil, false -} - var mouseEvents = map[string]struct{ jsEvent, jsFunc string }{ ClickEvent: {jsEvent: "onclick", jsFunc: "clickEvent"}, DoubleClickEvent: {jsEvent: "ondblclick", jsFunc: "doubleClickEvent"}, @@ -281,7 +156,7 @@ var mouseEvents = map[string]struct{ jsEvent, jsFunc string }{ } func (view *viewData) setMouseListener(tag string, value any) bool { - listeners, ok := valueToMouseListeners(value) + listeners, ok := valueToEventListeners[View, MouseEvent](value) if !ok { notCompatibleType(tag, value) return false @@ -309,20 +184,6 @@ func (view *viewData) removeMouseListener(tag string) { } } -func getMouseListeners(view View, subviewID string, tag string) []func(View, MouseEvent) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(tag); value != nil { - if result, ok := value.([]func(View, MouseEvent)); ok { - return result - } - } - } - return []func(View, MouseEvent){} -} - func mouseEventsHtml(view View, buffer *strings.Builder) { for tag, js := range mouseEvents { if value := view.getRaw(tag); value != nil { @@ -363,64 +224,62 @@ func (event *MouseEvent) init(data DataObject) { } func handleMouseEvents(view View, tag string, data DataObject) { - listeners := getMouseListeners(view, "", tag) - if len(listeners) == 0 { - return - } + listeners := getEventListeners[View, MouseEvent](view, "", tag) + if len(listeners) > 0 { + var event MouseEvent + event.init(data) - var event MouseEvent - event.init(data) - - for _, listener := range listeners { - listener(view, event) + for _, listener := range listeners { + listener(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 "" then a value from the first argument (view) is returned. func GetClickListeners(view View, subviewID string) []func(View, MouseEvent) { - return getMouseListeners(view, subviewID, ClickEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetDoubleClickListeners(view View, subviewID string) []func(View, MouseEvent) { - return getMouseListeners(view, subviewID, DoubleClickEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetContextMenuListeners(view View, subviewID string) []func(View, MouseEvent) { - return getMouseListeners(view, subviewID, ContextMenuEvent) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetMouseDownListeners(view View, subviewID string) []func(View, MouseEvent) { - return getMouseListeners(view, subviewID, MouseDown) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetMouseUpListeners(view View, subviewID string) []func(View, MouseEvent) { - return getMouseListeners(view, subviewID, MouseUp) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetMouseMoveListeners(view View, subviewID string) []func(View, MouseEvent) { - return getMouseListeners(view, subviewID, MouseMove) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetMouseOverListeners(view View, subviewID string) []func(View, MouseEvent) { - return getMouseListeners(view, subviewID, MouseOver) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetMouseOutListeners(view View, subviewID string) []func(View, MouseEvent) { - return getMouseListeners(view, subviewID, MouseOut) + return getEventListeners[View, MouseEvent](view, subviewID, MouseOut) } diff --git a/numberPicker.go b/numberPicker.go index 6b47a3f..a9c8067 100644 --- a/numberPicker.go +++ b/numberPicker.go @@ -99,52 +99,14 @@ func (picker *numberPickerData) set(tag string, value any) bool { switch tag { case NumberChangedEvent: - switch value := value.(type) { - case func(NumberPicker, float64): - picker.numberChangedListeners = []func(NumberPicker, float64){value} - - case func(float64): - fn := func(_ NumberPicker, newValue float64) { - value(newValue) - } - picker.numberChangedListeners = []func(NumberPicker, float64){fn} - - case []func(NumberPicker, float64): - picker.numberChangedListeners = value - - case []func(float64): - listeners := make([]func(NumberPicker, float64), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - listeners[i] = func(_ NumberPicker, newValue float64) { - val(newValue) - } - } - picker.numberChangedListeners = listeners - - case []any: - listeners := make([]func(NumberPicker, float64), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - switch val := val.(type) { - case func(NumberPicker, float64): - listeners[i] = val - - default: - notCompatibleType(tag, val) - return false - } - } - picker.numberChangedListeners = listeners + listeners, ok := valueToEventListeners[NumberPicker, float64](value) + if !ok { + notCompatibleType(tag, value) + return false + } else if listeners == nil { + listeners = []func(NumberPicker, float64){} } + picker.numberChangedListeners = listeners picker.propertyChangedEvent(tag) return true @@ -386,15 +348,5 @@ func GetNumberPickerValue(view View, subviewID string) float64 { // If there are no listeners then the empty list is returned // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetNumberChangedListeners(view View, subviewID string) []func(NumberPicker, float64) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(NumberChangedEvent); value != nil { - if listeners, ok := value.([]func(NumberPicker, float64)); ok { - return listeners - } - } - } - return []func(NumberPicker, float64){} + return getEventListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent) } diff --git a/pointerEvents.go b/pointerEvents.go index 6d84909..d7cd051 100644 --- a/pointerEvents.go +++ b/pointerEvents.go @@ -87,131 +87,6 @@ type PointerEvent struct { IsPrimary bool } -func valueToPointerListeners(value any) ([]func(View, PointerEvent), bool) { - if value == nil { - return nil, true - } - - switch value := value.(type) { - case func(View, PointerEvent): - return []func(View, PointerEvent){value}, true - - case func(PointerEvent): - fn := func(_ View, event PointerEvent) { - value(event) - } - return []func(View, PointerEvent){fn}, true - - case func(View): - fn := func(view View, _ PointerEvent) { - value(view) - } - return []func(View, PointerEvent){fn}, true - - case func(): - fn := func(View, PointerEvent) { - value() - } - return []func(View, PointerEvent){fn}, true - - case []func(View, PointerEvent): - if len(value) == 0 { - return nil, true - } - for _, fn := range value { - if fn == nil { - return nil, false - } - } - return value, true - - case []func(PointerEvent): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, PointerEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(_ View, event PointerEvent) { - v(event) - } - } - return listeners, true - - case []func(View): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, PointerEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(view View, _ PointerEvent) { - v(view) - } - } - return listeners, true - - case []func(): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, PointerEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(View, PointerEvent) { - v() - } - } - return listeners, true - - case []any: - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, PointerEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - switch v := v.(type) { - case func(View, PointerEvent): - listeners[i] = v - - case func(PointerEvent): - listeners[i] = func(_ View, event PointerEvent) { - v(event) - } - - case func(View): - listeners[i] = func(view View, _ PointerEvent) { - v(view) - } - - case func(): - listeners[i] = func(View, PointerEvent) { - v() - } - - default: - return nil, false - } - } - return listeners, true - } - - return nil, false -} - var pointerEvents = map[string]struct{ jsEvent, jsFunc string }{ PointerDown: {jsEvent: "onpointerdown", jsFunc: "pointerDownEvent"}, PointerUp: {jsEvent: "onpointerup", jsFunc: "pointerUpEvent"}, @@ -222,7 +97,7 @@ var pointerEvents = map[string]struct{ jsEvent, jsFunc string }{ } func (view *viewData) setPointerListener(tag string, value any) bool { - listeners, ok := valueToPointerListeners(value) + listeners, ok := valueToEventListeners[View, PointerEvent](value) if !ok { notCompatibleType(tag, value) return false @@ -250,20 +125,6 @@ func (view *viewData) removePointerListener(tag string) { } } -func getPointerListeners(view View, subviewID string, tag string) []func(View, PointerEvent) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(tag); value != nil { - if result, ok := value.([]func(View, PointerEvent)); ok { - return result - } - } - } - return []func(View, PointerEvent){} -} - func pointerEventsHtml(view View, buffer *strings.Builder) { for tag, js := range pointerEvents { if value := view.getRaw(tag); value != nil { @@ -291,7 +152,7 @@ func (event *PointerEvent) init(data DataObject) { } func handlePointerEvents(view View, tag string, data DataObject) { - listeners := getPointerListeners(view, "", tag) + listeners := getEventListeners[View, PointerEvent](view, "", tag) if len(listeners) == 0 { return } @@ -307,35 +168,35 @@ func handlePointerEvents(view View, tag string, data DataObject) { // GetPointerDownListeners returns the "pointer-down" listener list. If there are no listeners then the empty list is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetPointerDownListeners(view View, subviewID string) []func(View, PointerEvent) { - return getPointerListeners(view, subviewID, PointerDown) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetPointerUpListeners(view View, subviewID string) []func(View, PointerEvent) { - return getPointerListeners(view, subviewID, PointerUp) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetPointerMoveListeners(view View, subviewID string) []func(View, PointerEvent) { - return getPointerListeners(view, subviewID, PointerMove) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetPointerCancelListeners(view View, subviewID string) []func(View, PointerEvent) { - return getPointerListeners(view, subviewID, PointerCancel) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetPointerOverListeners(view View, subviewID string) []func(View, PointerEvent) { - return getPointerListeners(view, subviewID, PointerOver) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetPointerOutListeners(view View, subviewID string) []func(View, PointerEvent) { - return getPointerListeners(view, subviewID, PointerOut) + return getEventListeners[View, PointerEvent](view, subviewID, PointerOut) } diff --git a/popup.go b/popup.go index d177d34..1565aae 100644 --- a/popup.go +++ b/popup.go @@ -36,6 +36,10 @@ const ( // It occurs after the Popup disappears from the screen. // The main listener for this event has the following format: func(Popup) DismissEvent = "dismiss-event" + + // PopupArrow is the constant for the "popup-arrow" property tag. + // Using the "popup-arrow" property you can add ... + PopupArrow = "popup-arrow" ) // PopupButton describes a button that will be placed at the bottom of the window. @@ -181,11 +185,10 @@ func (popup *popupData) init(view View, params Params) { viewRow := 0 if title != nil || closeButton { viewRow = 1 - titleHeight, _ := sizeConstant(popup.Session(), "ruiPopupTitleHeight") titleView := NewGridLayout(session, Params{ Row: 0, Style: titleStyle, - CellWidth: []SizeUnit{Fr(1), titleHeight}, + CellWidth: []any{Fr(1), "@ruiPopupTitleHeight"}, CellVerticalAlign: CenterAlign, PaddingLeft: Px(12), }) @@ -195,8 +198,8 @@ func (popup *popupData) init(view View, params Params) { if closeButton { titleView.Append(NewGridLayout(session, Params{ Column: 1, - Height: titleHeight, - Width: titleHeight, + Height: "@ruiPopupTitleHeight", + Width: "@ruiPopupTitleHeight", CellHorizontalAlign: CenterAlign, CellVerticalAlign: CenterAlign, TextSize: Px(20), diff --git a/resizeEvent.go b/resizeEvent.go index 5427afb..c8b9c56 100644 --- a/resizeEvent.go +++ b/resizeEvent.go @@ -22,146 +22,18 @@ func (view *viewData) onItemResize(self View, index string, x, y, width, height } func (view *viewData) setFrameListener(tag string, value any) bool { - if value == nil { - delete(view.properties, tag) - return true - } - - switch value := value.(type) { - case func(View, Frame): - view.properties[tag] = []func(View, Frame){value} - - case []func(View, Frame): - if len(value) > 0 { - view.properties[tag] = value - } else { - delete(view.properties, tag) - return true - } - - case func(Frame): - fn := func(_ View, frame Frame) { - value(frame) - } - view.properties[tag] = []func(View, Frame){fn} - - case []func(Frame): - count := len(value) - if count == 0 { - delete(view.properties, tag) - return true - } - - listeners := make([]func(View, Frame), count) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - listeners[i] = func(_ View, frame Frame) { - val(frame) - } - } - view.properties[tag] = listeners - - case func(View): - fn := func(view View, _ Frame) { - value(view) - } - view.properties[tag] = []func(View, Frame){fn} - - case []func(View): - count := len(value) - if count == 0 { - delete(view.properties, tag) - return true - } - - listeners := make([]func(View, Frame), count) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - listeners[i] = func(view View, _ Frame) { - val(view) - } - } - view.properties[tag] = listeners - - case func(): - fn := func(View, Frame) { - value() - } - view.properties[tag] = []func(View, Frame){fn} - - case []func(): - count := len(value) - if count == 0 { - delete(view.properties, tag) - return true - } - - listeners := make([]func(View, Frame), count) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - listeners[i] = func(View, Frame) { - val() - } - } - view.properties[tag] = listeners - - case []any: - count := len(value) - if count == 0 { - delete(view.properties, tag) - return true - } - - listeners := make([]func(View, Frame), count) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - switch val := val.(type) { - case func(View, Frame): - listeners[i] = val - - case func(Frame): - listeners[i] = func(_ View, frame Frame) { - val(frame) - } - - case func(View): - listeners[i] = func(view View, _ Frame) { - val(view) - } - - case func(): - listeners[i] = func(View, Frame) { - val() - } - - default: - notCompatibleType(tag, val) - return false - } - } - view.properties[tag] = listeners - - default: + listeners, ok := valueToEventListeners[FilePicker, []FileInfo](value) + if !ok { notCompatibleType(tag, value) return false } + if listeners == nil { + delete(view.properties, tag) + } else { + view.properties[tag] = listeners + } + view.propertyChangedEvent(tag) return true } @@ -204,15 +76,5 @@ func GetViewFrame(view View, subviewID string) Frame { // GetResizeListeners returns the list of "resize-event" listeners. If there are no listeners then the empty list is returned // If the second argument (subviewID) is "" then the listeners list of the first argument (view) is returned func GetResizeListeners(view View, subviewID string) []func(View, Frame) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(ResizeEvent); value != nil { - if result, ok := value.([]func(View, Frame)); ok { - return result - } - } - } - return []func(View, Frame){} + return getEventListeners[View, Frame](view, subviewID, ResizeEvent) } diff --git a/scrollEvent.go b/scrollEvent.go index 134bdea..ac5a185 100644 --- a/scrollEvent.go +++ b/scrollEvent.go @@ -3,7 +3,7 @@ package rui import "fmt" // ScrollEvent is the constant for "scroll-event" property tag. -// The "resize-event" is fired when the content of the view is scrolled. +// The "scroll-event" is fired when the content of the view is scrolled. // The main listener format: // func(View, Frame). // The additional listener formats: @@ -46,17 +46,7 @@ func GetViewScroll(view View, subviewID string) Frame { // GetScrollListeners returns the list of "scroll-event" listeners. If there are no listeners then the empty list is returned // If the second argument (subviewID) is "" then the listeners list of the first argument (view) is returned func GetScrollListeners(view View, subviewID string) []func(View, Frame) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(ScrollEvent); value != nil { - if result, ok := value.([]func(View, Frame)); ok { - return result - } - } - } - return []func(View, Frame){} + return getEventListeners[View, Frame](view, subviewID, ResizeEvent) } // ScrollTo scrolls the view's content to the given position. diff --git a/session.go b/session.go index 5ec95e5..ed8b90b 100644 --- a/session.go +++ b/session.go @@ -431,7 +431,7 @@ func (session *sessionData) handleViewEvent(command string, data DataObject) { if view := session.viewByHTMLID(viewID); view != nil { view.handleCommand(view, command, data) } - } else { + } else if command != "clickOutsidePopup" { ErrorLog(`"id" property not found. Event: ` + command) } } diff --git a/stackLayout.go b/stackLayout.go index 4e1274a..ec10fd9 100644 --- a/stackLayout.go +++ b/stackLayout.go @@ -109,8 +109,8 @@ func (layout *stackLayoutData) set(tag string, value any) bool { switch tag { case TransitionEndEvent: - listeners, ok := valueToAnimationListeners(value) - if ok { + listeners, ok := valueToEventListeners[View, string](value) + if ok && listeners != nil { listeners = append(listeners, layout.pushFinished) listeners = append(listeners, layout.popFinished) layout.properties[TransitionEndEvent] = listeners diff --git a/tableView.go b/tableView.go index b121e21..e57105d 100644 --- a/tableView.go +++ b/tableView.go @@ -384,20 +384,24 @@ func (table *tableViewData) set(tag string, value any) bool { table.cellSelectedListener = listeners case TableRowClickedEvent: - listeners := table.valueToRowListeners(value) - if listeners == nil { + listeners, ok := valueToEventListeners[TableView, int](value) + if !ok { notCompatibleType(tag, value) return false + } else if listeners == nil { + listeners = []func(TableView, int){} } table.rowClickedListener = listeners case TableRowSelectedEvent: - listeners := table.valueToRowListeners(value) - if listeners == nil { + listeners, ok := valueToEventListeners[TableView, int](value) + if !ok { notCompatibleType(tag, value) return false + } else if listeners == nil { + listeners = []func(TableView, int){} } - table.rowSelectedListener = []func(TableView, int){} + table.rowSelectedListener = listeners case CellStyle: if style, ok := value.(TableCellStyle); ok { @@ -731,61 +735,6 @@ func (table *tableViewData) valueToCellListeners(value any) []func(TableView, in return nil } -func (table *tableViewData) valueToRowListeners(value any) []func(TableView, int) { - if value == nil { - return []func(TableView, int){} - } - - switch value := value.(type) { - case func(TableView, int): - return []func(TableView, int){value} - - case func(int): - fn := func(_ TableView, index int) { - value(index) - } - return []func(TableView, int){fn} - - case []func(TableView, int): - return value - - case []func(int): - listeners := make([]func(TableView, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - listeners[i] = func(_ TableView, index int) { - val(index) - } - } - return listeners - - case []any: - listeners := make([]func(TableView, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - switch val := val.(type) { - case func(TableView, int): - listeners[i] = val - - case func(int): - listeners[i] = func(_ TableView, index int) { - val(index) - } - - default: - return nil - } - } - return listeners - } - - return nil -} - func (table *tableViewData) htmlTag() string { return "table" } diff --git a/tabsLayout.go b/tabsLayout.go index b5a1ff2..05647d4 100644 --- a/tabsLayout.go +++ b/tabsLayout.go @@ -210,10 +210,12 @@ func (tabsLayout *tabsLayoutData) set(tag string, value any) bool { tabsLayout.tabListener = listeners case TabCloseEvent: - listeners := tabsLayout.valueToCloseListeners(value) - if listeners == nil { + listeners, ok := valueToEventListeners[TabsLayout, int](value) + if !ok { notCompatibleType(tag, value) return false + } else if listeners == nil { + listeners = []func(TabsLayout, int){} } tabsLayout.tabCloseListener = listeners @@ -433,61 +435,6 @@ func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayo return nil } -func (tabsLayout *tabsLayoutData) valueToCloseListeners(value any) []func(TabsLayout, int) { - if value == nil { - return []func(TabsLayout, int){} - } - - switch value := value.(type) { - case func(TabsLayout, int): - return []func(TabsLayout, int){value} - - case func(int): - fn := func(_ TabsLayout, index int) { - value(index) - } - return []func(TabsLayout, int){fn} - - case []func(TabsLayout, int): - return value - - case []func(int): - listeners := make([]func(TabsLayout, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - listeners[i] = func(_ TabsLayout, index int) { - val(index) - } - } - return listeners - - case []any: - listeners := make([]func(TabsLayout, int), len(value)) - for i, val := range value { - if val == nil { - return nil - } - switch val := val.(type) { - case func(TabsLayout, int): - listeners[i] = val - - case func(int): - listeners[i] = func(_ TabsLayout, index int) { - val(index) - } - - default: - return nil - } - } - return listeners - } - - return nil -} - func (tabsLayout *tabsLayoutData) tabsLocation() int { tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0) return tabs diff --git a/timePicker.go b/timePicker.go index 5edf71e..8d2543e 100644 --- a/timePicker.go +++ b/timePicker.go @@ -223,57 +223,14 @@ func (picker *timePickerData) set(tag string, value any) bool { } case TimeChangedEvent: - switch value := value.(type) { - case func(TimePicker, time.Time): - picker.timeChangedListeners = []func(TimePicker, time.Time){value} - - case func(time.Time): - fn := func(_ TimePicker, time time.Time) { - value(time) - } - picker.timeChangedListeners = []func(TimePicker, time.Time){fn} - - case []func(TimePicker, time.Time): - picker.timeChangedListeners = value - - case []func(time.Time): - listeners := make([]func(TimePicker, time.Time), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - listeners[i] = func(_ TimePicker, time time.Time) { - val(time) - } - } - picker.timeChangedListeners = listeners - - case []any: - listeners := make([]func(TimePicker, time.Time), len(value)) - for i, val := range value { - if val == nil { - notCompatibleType(tag, val) - return false - } - - switch val := val.(type) { - case func(TimePicker, time.Time): - listeners[i] = val - - case func(time.Time): - listeners[i] = func(_ TimePicker, time time.Time) { - val(time) - } - - default: - notCompatibleType(tag, val) - return false - } - } - picker.timeChangedListeners = listeners + listeners, ok := valueToEventListeners[TimePicker, time.Time](value) + if !ok { + notCompatibleType(tag, value) + return false + } else if listeners == nil { + listeners = []func(TimePicker, time.Time){} } + picker.timeChangedListeners = listeners picker.propertyChangedEvent(tag) return true @@ -458,15 +415,5 @@ func GetTimePickerValue(view View, subviewID string) time.Time { // If there are no listeners then the empty list is returned // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetTimeChangedListeners(view View, subviewID string) []func(TimePicker, time.Time) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(TimeChangedEvent); value != nil { - if listeners, ok := value.([]func(TimePicker, time.Time)); ok { - return listeners - } - } - } - return []func(TimePicker, time.Time){} + return getEventListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent) } diff --git a/touchEvents.go b/touchEvents.go index db5c76d..ac8a410 100644 --- a/touchEvents.go +++ b/touchEvents.go @@ -90,131 +90,6 @@ type TouchEvent struct { MetaKey bool } -func valueToTouchListeners(value any) ([]func(View, TouchEvent), bool) { - if value == nil { - return nil, true - } - - switch value := value.(type) { - case func(View, TouchEvent): - return []func(View, TouchEvent){value}, true - - case func(TouchEvent): - fn := func(_ View, event TouchEvent) { - value(event) - } - return []func(View, TouchEvent){fn}, true - - case func(View): - fn := func(view View, _ TouchEvent) { - value(view) - } - return []func(View, TouchEvent){fn}, true - - case func(): - fn := func(View, TouchEvent) { - value() - } - return []func(View, TouchEvent){fn}, true - - case []func(View, TouchEvent): - if len(value) == 0 { - return nil, true - } - for _, fn := range value { - if fn == nil { - return nil, false - } - } - return value, true - - case []func(TouchEvent): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, TouchEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(_ View, event TouchEvent) { - v(event) - } - } - return listeners, true - - case []func(View): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, TouchEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(view View, _ TouchEvent) { - v(view) - } - } - return listeners, true - - case []func(): - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, TouchEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - listeners[i] = func(View, TouchEvent) { - v() - } - } - return listeners, true - - case []any: - count := len(value) - if count == 0 { - return nil, true - } - listeners := make([]func(View, TouchEvent), count) - for i, v := range value { - if v == nil { - return nil, false - } - switch v := v.(type) { - case func(View, TouchEvent): - listeners[i] = v - - case func(TouchEvent): - listeners[i] = func(_ View, event TouchEvent) { - v(event) - } - - case func(View): - listeners[i] = func(view View, _ TouchEvent) { - v(view) - } - - case func(): - listeners[i] = func(View, TouchEvent) { - v() - } - - default: - return nil, false - } - } - return listeners, true - } - - return nil, false -} - var touchEvents = map[string]struct{ jsEvent, jsFunc string }{ TouchStart: {jsEvent: "ontouchstart", jsFunc: "touchStartEvent"}, TouchEnd: {jsEvent: "ontouchend", jsFunc: "touchEndEvent"}, @@ -223,7 +98,7 @@ var touchEvents = map[string]struct{ jsEvent, jsFunc string }{ } func (view *viewData) setTouchListener(tag string, value any) bool { - listeners, ok := valueToTouchListeners(value) + listeners, ok := valueToEventListeners[View, TouchEvent](value) if !ok { notCompatibleType(tag, value) return false @@ -251,20 +126,6 @@ func (view *viewData) removeTouchListener(tag string) { } } -func getTouchListeners(view View, subviewID string, tag string) []func(View, TouchEvent) { - if subviewID != "" { - view = ViewByID(view, subviewID) - } - if view != nil { - if value := view.Get(tag); value != nil { - if result, ok := value.([]func(View, TouchEvent)); ok { - return result - } - } - } - return []func(View, TouchEvent){} -} - func touchEventsHtml(view View, buffer *strings.Builder) { for tag, js := range touchEvents { if value := view.getRaw(tag); value != nil { @@ -309,7 +170,7 @@ func (event *TouchEvent) init(data DataObject) { } func handleTouchEvents(view View, tag string, data DataObject) { - listeners := getTouchListeners(view, "", tag) + listeners := getEventListeners[View, TouchEvent](view, "", tag) if len(listeners) == 0 { return } @@ -325,23 +186,23 @@ func handleTouchEvents(view View, tag string, data DataObject) { // GetTouchStartListeners returns the "touch-start" listener list. If there are no listeners then the empty list is returned. // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetTouchStartListeners(view View, subviewID string) []func(View, TouchEvent) { - return getTouchListeners(view, subviewID, TouchStart) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetTouchEndListeners(view View, subviewID string) []func(View, TouchEvent) { - return getTouchListeners(view, subviewID, TouchEnd) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetTouchMoveListeners(view View, subviewID string) []func(View, TouchEvent) { - return getTouchListeners(view, subviewID, TouchMove) + return getEventListeners[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 "" then a value from the first argument (view) is returned. func GetTouchCancelListeners(view View, subviewID string) []func(View, TouchEvent) { - return getTouchListeners(view, subviewID, TouchCancel) + return getEventListeners[View, TouchEvent](view, subviewID, TouchCancel) }