mirror of https://github.com/anoshenko/rui.git
Improved binding for no args listeners
This commit is contained in:
parent
4b00299878
commit
f2fb948325
178
events.go
178
events.go
|
@ -67,6 +67,96 @@ func updateEventListenerHtml(view View, tag PropertyName) {
|
|||
}
|
||||
}
|
||||
|
||||
type noArgListener[V View] interface {
|
||||
Run(V)
|
||||
rawListener() any
|
||||
}
|
||||
|
||||
type noArgListener0[V View] struct {
|
||||
fn func()
|
||||
}
|
||||
|
||||
type noArgListenerV[V View] struct {
|
||||
fn func(V)
|
||||
}
|
||||
|
||||
type noArgListenerBinding[V View] struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func newNoArgListener0[V View](fn func()) noArgListener[V] {
|
||||
obj := new(noArgListener0[V])
|
||||
obj.fn = fn
|
||||
return obj
|
||||
}
|
||||
|
||||
func (data *noArgListener0[V]) Run(_ V) {
|
||||
data.fn()
|
||||
}
|
||||
|
||||
func (data *noArgListener0[V]) rawListener() any {
|
||||
return data.fn
|
||||
}
|
||||
|
||||
func newNoArgListenerV[V View](fn func(V)) noArgListener[V] {
|
||||
obj := new(noArgListenerV[V])
|
||||
obj.fn = fn
|
||||
return obj
|
||||
}
|
||||
|
||||
func (data *noArgListenerV[V]) Run(view V) {
|
||||
data.fn(view)
|
||||
}
|
||||
|
||||
func (data *noArgListenerV[V]) rawListener() any {
|
||||
return data.fn
|
||||
}
|
||||
|
||||
func newNoArgListenerBinding[V View](name string) noArgListener[V] {
|
||||
obj := new(noArgListenerBinding[V])
|
||||
obj.name = name
|
||||
return obj
|
||||
}
|
||||
|
||||
func (data *noArgListenerBinding[V]) Run(view V) {
|
||||
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)}
|
||||
}
|
||||
}
|
||||
|
||||
if args != nil {
|
||||
method.Call(args)
|
||||
} else {
|
||||
ErrorLogF(`Unsupported prototype of "%s" method`, data.name)
|
||||
}
|
||||
}
|
||||
|
||||
func (data *noArgListenerBinding[V]) rawListener() any {
|
||||
return data.name
|
||||
}
|
||||
|
||||
/*
|
||||
func valueToNoArgEventListeners[V any](view View, value any) ([]func(V), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
|
@ -173,20 +263,74 @@ func valueToNoArgEventListeners[V any](view View, value any) ([]func(V), bool) {
|
|||
|
||||
return nil, false
|
||||
}
|
||||
*/
|
||||
|
||||
func getNoArgEventListeners[V View](view View, subviewID []string, tag PropertyName) []func(V) {
|
||||
if view = getSubview(view, subviewID); view != nil {
|
||||
if value := view.Get(tag); value != nil {
|
||||
if result, ok := value.([]func(V)); ok {
|
||||
return result
|
||||
func valueToNoArgEventListeners[V View](value any) ([]noArgListener[V], bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case []noArgListener[V]:
|
||||
return value, true
|
||||
|
||||
case noArgListener[V]:
|
||||
return []noArgListener[V]{value}, true
|
||||
|
||||
case string:
|
||||
return []noArgListener[V]{newNoArgListenerBinding[V](value)}, true
|
||||
|
||||
case func(V):
|
||||
return []noArgListener[V]{newNoArgListenerV(value)}, true
|
||||
|
||||
case func():
|
||||
return []noArgListener[V]{newNoArgListener0[V](value)}, true
|
||||
|
||||
case []func(V):
|
||||
result := make([]noArgListener[V], 0, len(value))
|
||||
for _, fn := range value {
|
||||
if fn != nil {
|
||||
result = append(result, newNoArgListenerV(fn))
|
||||
}
|
||||
}
|
||||
return result, len(result) > 0
|
||||
|
||||
case []func():
|
||||
result := make([]noArgListener[V], 0, len(value))
|
||||
for _, fn := range value {
|
||||
if fn != nil {
|
||||
result = append(result, newNoArgListener0[V](fn))
|
||||
}
|
||||
}
|
||||
return result, len(result) > 0
|
||||
|
||||
case []any:
|
||||
result := make([]noArgListener[V], 0, len(value))
|
||||
for _, v := range value {
|
||||
if v != nil {
|
||||
switch v := v.(type) {
|
||||
case func(V):
|
||||
result = append(result, newNoArgListenerV(v))
|
||||
|
||||
case func():
|
||||
result = append(result, newNoArgListener0[V](v))
|
||||
|
||||
case string:
|
||||
result = append(result, newNoArgListenerBinding[V](v))
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, len(result) > 0
|
||||
}
|
||||
return []func(V){}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func setNoArgEventListener[V View](view View, tag PropertyName, value any) []PropertyName {
|
||||
if listeners, ok := valueToNoArgEventListeners[V](view, value); ok {
|
||||
if listeners, ok := valueToNoArgEventListeners[V](value); ok {
|
||||
if len(listeners) > 0 {
|
||||
view.setRaw(tag, listeners)
|
||||
} else if view.getRaw(tag) != nil {
|
||||
|
@ -199,3 +343,23 @@ func setNoArgEventListener[V View](view View, tag PropertyName, value any) []Pro
|
|||
notCompatibleType(tag, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNoArgEventListeners[V View](view View, subviewID []string, tag PropertyName) []noArgListener[V] {
|
||||
if view = getSubview(view, subviewID); view != nil {
|
||||
if value := view.Get(tag); value != nil {
|
||||
if result, ok := value.([]noArgListener[V]); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []noArgListener[V]{}
|
||||
}
|
||||
|
||||
func getNoArgEventRawListeners[V View](view View, subviewID []string, tag PropertyName) []any {
|
||||
listeners := getNoArgEventListeners[V](view, subviewID, tag)
|
||||
result := make([]any, len(listeners))
|
||||
for i, l := range listeners {
|
||||
result[i] = l.rawListener()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -50,16 +50,26 @@ func focusEventsHtml(view View, buffer *strings.Builder) {
|
|||
|
||||
// GetFocusListeners returns a FocusListener list. If there are no listeners then the empty list is returned
|
||||
//
|
||||
// Result elements can be of the following types:
|
||||
// - func(rui.View),
|
||||
// - 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 GetFocusListeners(view View, subviewID ...string) []func(View) {
|
||||
return getNoArgEventListeners[View](view, subviewID, FocusEvent)
|
||||
func GetFocusListeners(view View, subviewID ...string) []any {
|
||||
return getNoArgEventRawListeners[View](view, subviewID, FocusEvent)
|
||||
}
|
||||
|
||||
// GetLostFocusListeners returns a LostFocusListener list. If there are no listeners then the empty list is returned
|
||||
//
|
||||
// Result elements can be of the following types:
|
||||
// - func(rui.View),
|
||||
// - 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 GetLostFocusListeners(view View, subviewID ...string) []func(View) {
|
||||
return getNoArgEventListeners[View](view, subviewID, LostFocusEvent)
|
||||
func GetLostFocusListeners(view View, subviewID ...string) []any {
|
||||
return getNoArgEventRawListeners[View](view, subviewID, LostFocusEvent)
|
||||
}
|
||||
|
|
32
imageView.go
32
imageView.go
|
@ -300,7 +300,7 @@ func (imageView *imageViewData) handleCommand(self View, command PropertyName, d
|
|||
switch command {
|
||||
case "imageViewError":
|
||||
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, ErrorEvent) {
|
||||
listener(imageView)
|
||||
listener.Run(imageView)
|
||||
}
|
||||
|
||||
case "imageViewLoaded":
|
||||
|
@ -309,7 +309,7 @@ func (imageView *imageViewData) handleCommand(self View, command PropertyName, d
|
|||
imageView.currentSrc, _ = data.PropertyValue("current-src")
|
||||
|
||||
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, LoadedEvent) {
|
||||
listener(imageView)
|
||||
listener.Run(imageView)
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -370,3 +370,31 @@ func GetImageViewVerticalAlign(view View, subviewID ...string) int {
|
|||
func GetImageViewHorizontalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, ImageHorizontalAlign, LeftAlign, false)
|
||||
}
|
||||
|
||||
// GetImageViewErrorEventListeners returns the list of "error-event" event listeners.
|
||||
// If there are no listeners then the empty list is returned
|
||||
//
|
||||
// Result elements can be of the following types:
|
||||
// - func(rui.ImageView)
|
||||
// - 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 GetImageViewErrorEventListeners(view View, subviewID ...string) []any {
|
||||
return getNoArgEventRawListeners[View](view, subviewID, ErrorEvent)
|
||||
}
|
||||
|
||||
// GetImageViewLoadedEventListeners returns the list of "loaded-event" event listeners.
|
||||
// If there are no listeners then the empty list is returned
|
||||
//
|
||||
// Result elements can be of the following types:
|
||||
// - func(rui.ImageView)
|
||||
// - 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 GetImageViewLoadedEventListeners(view View, subviewID ...string) []any {
|
||||
return getNoArgEventRawListeners[View](view, subviewID, LoadedEvent)
|
||||
}
|
||||
|
|
160
popup.go
160
popup.go
|
@ -2,6 +2,7 @@ package rui
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -281,13 +282,30 @@ type Popup interface {
|
|||
dissmissAnimation(listener func(PropertyName)) bool
|
||||
}
|
||||
|
||||
type popupListener interface {
|
||||
Run(Popup)
|
||||
rawListener() any
|
||||
}
|
||||
|
||||
type popupListener0 struct {
|
||||
fn func()
|
||||
}
|
||||
|
||||
type popupListener1 struct {
|
||||
fn func(Popup)
|
||||
}
|
||||
|
||||
type popupListenerBinding struct {
|
||||
name string
|
||||
}
|
||||
|
||||
type popupData struct {
|
||||
layerView GridLayout
|
||||
popupView GridLayout
|
||||
contentView View
|
||||
buttons []PopupButton
|
||||
cancelable bool
|
||||
dismissListener []func(Popup)
|
||||
dismissListener []popupListener
|
||||
showTransform TransformProperty
|
||||
showOpacity float64
|
||||
showDuration float64
|
||||
|
@ -649,7 +667,7 @@ func (popup *popupData) init(view View, popupParams Params) {
|
|||
}
|
||||
|
||||
case DismissEvent:
|
||||
if listeners, ok := valueToNoArgEventListeners[Popup](popup.contentView, value); ok {
|
||||
if listeners, ok := valueToPopupEventListeners(value); ok {
|
||||
if listeners != nil {
|
||||
popup.dismissListener = listeners
|
||||
}
|
||||
|
@ -887,7 +905,7 @@ func (popup *popupData) onDismiss() {
|
|||
popup.Session().callFunc("removeView", popup.layerView.htmlID())
|
||||
|
||||
for _, listener := range popup.dismissListener {
|
||||
listener(popup)
|
||||
listener.Run(popup)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1014,3 +1032,139 @@ func (manager *popupManager) dismissPopup(popup Popup) {
|
|||
listener("")
|
||||
}
|
||||
}
|
||||
|
||||
func newPopupListener0(fn func()) popupListener {
|
||||
obj := new(popupListener0)
|
||||
obj.fn = fn
|
||||
return obj
|
||||
}
|
||||
|
||||
func (data *popupListener0) Run(_ Popup) {
|
||||
data.fn()
|
||||
}
|
||||
|
||||
func (data *popupListener0) rawListener() any {
|
||||
return data.fn
|
||||
}
|
||||
|
||||
func newPopupListener1(fn func(Popup)) popupListener {
|
||||
obj := new(popupListener1)
|
||||
obj.fn = fn
|
||||
return obj
|
||||
}
|
||||
|
||||
func (data *popupListener1) Run(popup Popup) {
|
||||
data.fn(popup)
|
||||
}
|
||||
|
||||
func (data *popupListener1) rawListener() any {
|
||||
return data.fn
|
||||
}
|
||||
|
||||
func newPopupListenerBinding(name string) popupListener {
|
||||
obj := new(popupListenerBinding)
|
||||
obj.name = name
|
||||
return obj
|
||||
}
|
||||
|
||||
func (data *popupListenerBinding) Run(popup Popup) {
|
||||
bind := popup.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(popup) {
|
||||
args = []reflect.Value{reflect.ValueOf(popup)}
|
||||
}
|
||||
}
|
||||
|
||||
if args != nil {
|
||||
method.Call(args)
|
||||
} else {
|
||||
ErrorLogF(`Unsupported prototype of "%s" method`, data.name)
|
||||
}
|
||||
}
|
||||
|
||||
func (data *popupListenerBinding) rawListener() any {
|
||||
return data.name
|
||||
}
|
||||
|
||||
func valueToPopupEventListeners(value any) ([]popupListener, bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case []popupListener:
|
||||
return value, true
|
||||
|
||||
case popupListener:
|
||||
return []popupListener{value}, true
|
||||
|
||||
case string:
|
||||
return []popupListener{newPopupListenerBinding(value)}, true
|
||||
|
||||
case func(Popup):
|
||||
return []popupListener{newPopupListener1(value)}, true
|
||||
|
||||
case func():
|
||||
return []popupListener{newPopupListener0(value)}, true
|
||||
|
||||
case []func(Popup):
|
||||
result := make([]popupListener, 0, len(value))
|
||||
for _, fn := range value {
|
||||
if fn != nil {
|
||||
result = append(result, newPopupListener1(fn))
|
||||
}
|
||||
}
|
||||
return result, len(result) > 0
|
||||
|
||||
case []func():
|
||||
result := make([]popupListener, 0, len(value))
|
||||
for _, fn := range value {
|
||||
if fn != nil {
|
||||
result = append(result, newPopupListener0(fn))
|
||||
}
|
||||
}
|
||||
return result, len(result) > 0
|
||||
|
||||
case []any:
|
||||
result := make([]popupListener, 0, len(value))
|
||||
for _, v := range value {
|
||||
if v != nil {
|
||||
switch v := v.(type) {
|
||||
case func(Popup):
|
||||
result = append(result, newPopupListener1(v))
|
||||
|
||||
case func():
|
||||
result = append(result, newPopupListener0(v))
|
||||
|
||||
case string:
|
||||
result = append(result, newPopupListenerBinding(v))
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, len(result) > 0
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
|
4
view.go
4
view.go
|
@ -1162,13 +1162,13 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb
|
|||
case FocusEvent:
|
||||
view.hasFocus = true
|
||||
for _, listener := range getNoArgEventListeners[View](view, nil, command) {
|
||||
listener(self)
|
||||
listener.Run(self)
|
||||
}
|
||||
|
||||
case LostFocusEvent:
|
||||
view.hasFocus = false
|
||||
for _, listener := range getNoArgEventListeners[View](view, nil, command) {
|
||||
listener(self)
|
||||
listener.Run(self)
|
||||
}
|
||||
|
||||
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
|
||||
|
|
Loading…
Reference in New Issue