Added binding to View.String()

This commit is contained in:
Alexei Anoshenko 2025-06-19 17:31:39 +03:00
parent 24aeeb515b
commit 2f07584b37
6 changed files with 286 additions and 133 deletions

View File

@ -84,7 +84,16 @@ const (
// Fired when the user starts dragging an element or text selection. // Fired when the user starts dragging an element or text selection.
// //
// General listener format: // General listener format:
// func(view rui.View, event rui.DragAndDropEvent).
// //
// where:
// - view - Interface of a view which generated this event,
// - event - event parameters.
//
// Allowed listener formats:
// func(view rui.View)
// func(rui.DragAndDropEvent)
// func()
DragStartEvent PropertyName = "drag-start-event" DragStartEvent PropertyName = "drag-start-event"
// DragEndEvent is the constant for "drag-end-event" property tag. // DragEndEvent is the constant for "drag-end-event" property tag.
@ -93,7 +102,16 @@ const (
// Fired when a drag operation ends (by releasing a mouse button or hitting the escape key). // Fired when a drag operation ends (by releasing a mouse button or hitting the escape key).
// //
// General listener format: // General listener format:
// func(view rui.View, event rui.DragAndDropEvent).
// //
// where:
// - view - Interface of a view which generated this event,
// - event - event parameters.
//
// Allowed listener formats:
// func(view rui.View)
// func(rui.DragAndDropEvent)
// func()
DragEndEvent PropertyName = "drag-end-event" DragEndEvent PropertyName = "drag-end-event"
// DragEnterEvent is the constant for "drag-enter-event" property tag. // DragEnterEvent is the constant for "drag-enter-event" property tag.
@ -102,7 +120,16 @@ const (
// Fired when a dragged element or text selection enters a valid drop target. // Fired when a dragged element or text selection enters a valid drop target.
// //
// General listener format: // General listener format:
// func(view rui.View, event rui.DragAndDropEvent).
// //
// where:
// - view - Interface of a view which generated this event,
// - event - event parameters.
//
// Allowed listener formats:
// func(view rui.View)
// func(rui.DragAndDropEvent)
// func()
DragEnterEvent PropertyName = "drag-enter-event" DragEnterEvent PropertyName = "drag-enter-event"
// DragLeaveEvent is the constant for "drag-leave-event" property tag. // DragLeaveEvent is the constant for "drag-leave-event" property tag.
@ -111,7 +138,16 @@ const (
// Fired when a dragged element or text selection leaves a valid drop target. // Fired when a dragged element or text selection leaves a valid drop target.
// //
// General listener format: // General listener format:
// func(view rui.View, event rui.DragAndDropEvent).
// //
// where:
// - view - Interface of a view which generated this event,
// - event - event parameters.
//
// Allowed listener formats:
// func(view rui.View)
// func(rui.DragAndDropEvent)
// func()
DragLeaveEvent PropertyName = "drag-leave-event" DragLeaveEvent PropertyName = "drag-leave-event"
// DragOverEvent is the constant for "drag-over-event" property tag. // DragOverEvent is the constant for "drag-over-event" property tag.
@ -120,7 +156,16 @@ const (
// Fired when an element or text selection is being dragged over a valid drop target (every few hundred milliseconds). // Fired when an element or text selection is being dragged over a valid drop target (every few hundred milliseconds).
// //
// General listener format: // General listener format:
// func(view rui.View, event rui.DragAndDropEvent).
// //
// where:
// - view - Interface of a view which generated this event,
// - event - event parameters.
//
// Allowed listener formats:
// func(view rui.View)
// func(rui.DragAndDropEvent)
// func()
DragOverEvent PropertyName = "drag-over-event" DragOverEvent PropertyName = "drag-over-event"
// DropEvent is the constant for "drop-event" property tag. // DropEvent is the constant for "drop-event" property tag.
@ -129,7 +174,16 @@ const (
// Fired when an element or text selection is dropped on a valid drop target. // Fired when an element or text selection is dropped on a valid drop target.
// //
// General listener format: // General listener format:
// func(view rui.View, event rui.DragAndDropEvent).
// //
// where:
// - view - Interface of a view which generated this event,
// - event - event parameters.
//
// Allowed listener formats:
// func(view rui.View)
// func(rui.DragAndDropEvent)
// func()
DropEvent PropertyName = "drop-event" DropEvent PropertyName = "drop-event"
// DropEffectUndefined - the value of the "drop-effect" and "drop-effect-allowed" properties: the value is not defined (default value). // DropEffectUndefined - the value of the "drop-effect" and "drop-effect-allowed" properties: the value is not defined (default value).

119
events.go
View File

@ -156,115 +156,6 @@ func (data *noArgListenerBinding[V]) rawListener() any {
return data.name return data.name
} }
/*
func valueToNoArgEventListeners[V any](view View, value any) ([]func(V), bool) {
if value == nil {
return nil, true
}
switch value := value.(type) {
case string:
fn := func(arg V) {
bind := view.binding()
if bind == nil {
ErrorLogF(`There is no a binding object for call "%s"`, value)
return
}
val := reflect.ValueOf(bind)
method := val.MethodByName(value)
if !method.IsValid() {
ErrorLogF(`The "%s" method is not valid`, value)
return
}
methodType := method.Type()
var args []reflect.Value = nil
switch methodType.NumIn() {
case 0:
args = []reflect.Value{}
case 1:
inType := methodType.In(0)
if inType == reflect.TypeOf(arg) {
args = []reflect.Value{reflect.ValueOf(arg)}
}
}
if args != nil {
method.Call(args)
} else {
ErrorLogF(`Unsupported prototype of "%s" method`, value)
}
}
return []func(V){fn}, true
case func(V):
return []func(V){value}, true
case func():
fn := func(V) {
value()
}
return []func(V){fn}, true
case []func(V):
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(V), count)
for i, v := range value {
if v == nil {
return nil, false
}
listeners[i] = func(V) {
v()
}
}
return listeners, true
case []any:
count := len(value)
if count == 0 {
return nil, true
}
listeners := make([]func(V), count)
for i, v := range value {
if v == nil {
return nil, false
}
switch v := v.(type) {
case func(V):
listeners[i] = v
case func():
listeners[i] = func(V) {
v()
}
default:
return nil, false
}
}
return listeners, true
}
return nil, false
}
*/
func valueToNoArgEventListeners[V View](value any) ([]noArgListener[V], bool) { func valueToNoArgEventListeners[V View](value any) ([]noArgListener[V], bool) {
if value == nil { if value == nil {
return nil, true return nil, true
@ -356,3 +247,13 @@ func getNoArgEventRawListeners[V View](view View, subviewID []string, tag Proper
} }
return result return result
} }
func getNoArgBinding[V View](listeners []noArgListener[V]) string {
for _, listener := range listeners {
raw := listener.rawListener()
if text, ok := raw.(string); ok && text != "" {
return text
}
}
return ""
}

View File

@ -257,3 +257,13 @@ func getOneArgEventRawListeners[V View, E any](view View, subviewID []string, ta
} }
return result return result
} }
func getOneArgBinding[V View, E any](listeners []oneArgListener[V, E]) string {
for _, listener := range listeners {
raw := listener.rawListener()
if text, ok := raw.(string); ok && text != "" {
return text
}
}
return ""
}

View File

@ -330,3 +330,13 @@ func getTwoArgEventRawListeners[V View, E any](view View, subviewID []string, ta
} }
return result return result
} }
func getTwoArgBinding[V View, E any](listeners []twoArgListener[V, E]) string {
for _, listener := range listeners {
raw := listener.rawListener()
if text, ok := raw.(string); ok && text != "" {
return text
}
}
return ""
}

View File

@ -1628,3 +1628,13 @@ func valueToMediaPlayerErrorListeners(value any) ([]mediaPlayerErrorListener, bo
return nil, false return nil, false
} }
func getMediaPlayerErrorListenerBinding(listeners []mediaPlayerErrorListener) string {
for _, listener := range listeners {
raw := listener.rawListener()
if text, ok := raw.(string); ok && text != "" {
return text
}
}
return ""
}

View File

@ -2,9 +2,10 @@ package rui
import ( import (
"fmt" "fmt"
"sort" "slices"
"strconv" "strconv"
"strings" "strings"
"time"
) )
// ViewStyle interface of the style of view // ViewStyle interface of the style of view
@ -551,26 +552,118 @@ func viewStyleGet(style Properties, tag PropertyName) any {
} }
func supportedPropertyValue(value any) bool { func supportedPropertyValue(value any) bool {
switch value.(type) { switch value := value.(type) {
case string: case string, bool, float32, float64, int, stringWriter, fmt.Stringer:
return true
case []string: case []string:
case bool: return len(value) > 0
case float32:
case float64:
case int:
case stringWriter:
case fmt.Stringer:
case []ShadowProperty: case []ShadowProperty:
return len(value) > 0
case []View: case []View:
return len(value) > 0
case []any: case []any:
return len(value) > 0
case []BackgroundElement: case []BackgroundElement:
return len(value) > 0
case []BackgroundGradientPoint: case []BackgroundGradientPoint:
return len(value) > 0
case []BackgroundGradientAngle: case []BackgroundGradientAngle:
return len(value) > 0
case map[PropertyName]AnimationProperty: case map[PropertyName]AnimationProperty:
return len(value) > 0
case []noArgListener[View]:
return getNoArgBinding(value) != ""
case []noArgListener[ImageView]:
return getNoArgBinding(value) != ""
case []noArgListener[MediaPlayer]:
return getNoArgBinding(value) != ""
case []oneArgListener[View, KeyEvent]:
return getOneArgBinding(value) != ""
case []oneArgListener[View, MouseEvent]:
return getOneArgBinding(value) != ""
case []oneArgListener[View, TouchEvent]:
return getOneArgBinding(value) != ""
case []oneArgListener[View, PointerEvent]:
return getOneArgBinding(value) != ""
case []oneArgListener[View, PropertyName]:
return getOneArgBinding(value) != ""
case []oneArgListener[View, string]:
return getOneArgBinding(value) != ""
case []oneArgListener[View, Frame]:
return getOneArgBinding(value) != ""
case []oneArgListener[View, DragAndDropEvent]:
return getOneArgBinding(value) != ""
case []oneArgListener[Checkbox, bool]:
return getOneArgBinding(value) != ""
case []oneArgListener[FilePicker, []FileInfo]:
return getOneArgBinding(value) != ""
case []oneArgListener[ListView, int]:
return getOneArgBinding(value) != ""
case []oneArgListener[ListView, []int]:
return getOneArgBinding(value) != ""
case []oneArgListener[MediaPlayer, float64]:
return getOneArgBinding(value) != ""
case []oneArgListener[TableView, int]:
return getOneArgBinding(value) != ""
case []oneArgListener[TabsLayout, int]:
return getOneArgBinding(value) != ""
case []twoArgListener[ColorPicker, Color]:
return getTwoArgBinding(value) != ""
case []twoArgListener[DatePicker, time.Time]:
return getTwoArgBinding(value) != ""
case []twoArgListener[TimePicker, time.Time]:
return getTwoArgBinding(value) != ""
case []twoArgListener[DropDownList, int]:
return getTwoArgBinding(value) != ""
case []twoArgListener[EditView, string]:
return getTwoArgBinding(value) != ""
case []twoArgListener[NumberPicker, float64]:
return getTwoArgBinding(value) != ""
case []twoArgListener[TableView, int]:
return getTwoArgBinding(value) != ""
case []twoArgListener[TabsLayout, int]:
return getTwoArgBinding(value) != ""
case []mediaPlayerErrorListener:
return getMediaPlayerErrorListenerBinding(value) != ""
default: default:
return false return false
} }
return true
} }
func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, indent string) { func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, indent string) {
@ -791,9 +884,7 @@ func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, in
for tag := range value { for tag := range value {
tags = append(tags, tag) tags = append(tags, tag)
} }
sort.Slice(tags, func(i, j int) bool { slices.Sort(tags)
return tags[i] < tags[j]
})
buffer.WriteString("[\n") buffer.WriteString("[\n")
indent2 := indent + "\t" indent2 := indent + "\t"
for _, tag := range tags { for _, tag := range tags {
@ -806,6 +897,87 @@ func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, in
buffer.WriteString(indent) buffer.WriteString(indent)
buffer.WriteRune(']') buffer.WriteRune(']')
} }
case []noArgListener[View]:
buffer.WriteString(getNoArgBinding(value))
case []noArgListener[ImageView]:
buffer.WriteString(getNoArgBinding(value))
case []noArgListener[MediaPlayer]:
buffer.WriteString(getNoArgBinding(value))
case []oneArgListener[View, KeyEvent]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[View, MouseEvent]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[View, TouchEvent]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[View, PointerEvent]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[View, PropertyName]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[View, string]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[View, Frame]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[View, DragAndDropEvent]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[Checkbox, bool]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[FilePicker, []FileInfo]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[ListView, int]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[ListView, []int]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[MediaPlayer, float64]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[TableView, int]:
buffer.WriteString(getOneArgBinding(value))
case []oneArgListener[TabsLayout, int]:
buffer.WriteString(getOneArgBinding(value))
case []twoArgListener[ColorPicker, Color]:
buffer.WriteString(getTwoArgBinding(value))
case []twoArgListener[DatePicker, time.Time]:
buffer.WriteString(getTwoArgBinding(value))
case []twoArgListener[TimePicker, time.Time]:
buffer.WriteString(getTwoArgBinding(value))
case []twoArgListener[DropDownList, int]:
buffer.WriteString(getTwoArgBinding(value))
case []twoArgListener[EditView, string]:
buffer.WriteString(getTwoArgBinding(value))
case []twoArgListener[NumberPicker, float64]:
buffer.WriteString(getTwoArgBinding(value))
case []twoArgListener[TableView, int]:
buffer.WriteString(getTwoArgBinding(value))
case []twoArgListener[TabsLayout, int]:
buffer.WriteString(getTwoArgBinding(value))
case []mediaPlayerErrorListener:
buffer.WriteString(getMediaPlayerErrorListenerBinding(value))
} }
} }
@ -815,12 +987,7 @@ func writeViewStyle(name string, view Properties, buffer *strings.Builder, inden
indent += "\t" indent += "\t"
writeProperty := func(tag PropertyName, value any) { writeProperty := func(tag PropertyName, value any) {
for _, exclude := range excludeTags { if !slices.Contains(excludeTags, tag) {
if exclude == tag {
return
}
}
if supportedPropertyValue(value) { if supportedPropertyValue(value) {
buffer.WriteString(indent) buffer.WriteString(indent)
buffer.WriteString(string(tag)) buffer.WriteString(string(tag))
@ -829,6 +996,7 @@ func writeViewStyle(name string, view Properties, buffer *strings.Builder, inden
buffer.WriteString(",\n") buffer.WriteString(",\n")
} }
} }
}
tags := view.AllTags() tags := view.AllTags()
removeTag := func(tag PropertyName) { removeTag := func(tag PropertyName) {