Optimisation

This commit is contained in:
Alexei Anoshenko 2025-07-06 11:20:37 +03:00
parent 8066fb92ba
commit 73cc26b54e
27 changed files with 117 additions and 154 deletions

View File

@ -1,6 +1,7 @@
package rui package rui
import ( import (
"errors"
"fmt" "fmt"
"math" "math"
"strconv" "strconv"
@ -86,6 +87,10 @@ func StringToAngleUnit(value string) (AngleUnit, bool) {
func stringToAngleUnit(value string) (AngleUnit, error) { func stringToAngleUnit(value string) (AngleUnit, error) {
value = strings.ToLower(strings.Trim(value, " \t\n\r")) value = strings.ToLower(strings.Trim(value, " \t\n\r"))
if value == "" {
return AngleUnit{}, errors.New(`invalid AngleUnit value: ""`)
}
setValue := func(suffix string, unitType AngleUnitType) (AngleUnit, error) { setValue := func(suffix string, unitType AngleUnitType) (AngleUnit, error) {
val, err := strconv.ParseFloat(value[:len(value)-len(suffix)], 64) val, err := strconv.ParseFloat(value[:len(value)-len(suffix)], 64)
if err != nil { if err != nil {

View File

@ -65,17 +65,13 @@ func (point *BackgroundGradientAngle) color(session Session) (Color, bool) {
if point.Color != nil { if point.Color != nil {
switch color := point.Color.(type) { switch color := point.Color.(type) {
case string: case string:
if color != "" { if ok, constName := isConstantName(color); ok {
if color[0] == '@' { if clr, ok := session.Color(constName); ok {
if clr, ok := session.Color(color[1:]); ok {
return clr, true return clr, true
} }
} else { } else if clr, ok := StringToColor(color); ok {
if clr, ok := StringToColor(color); ok {
return clr, true return clr, true
} }
}
}
case Color: case Color:
return color, true return color, true
@ -104,11 +100,8 @@ func (point *BackgroundGradientAngle) cssString(session Session, buffer *strings
if point.Angle != nil { if point.Angle != nil {
switch value := point.Angle.(type) { switch value := point.Angle.(type) {
case string: case string:
if value != "" { if ok, constName := isConstantName(value); ok {
if value[0] == '@' { if value, ok = session.Constant(constName); !ok {
if val, ok := session.Constant(value[1:]); ok {
value = val
} else {
return return
} }
} }
@ -117,7 +110,6 @@ func (point *BackgroundGradientAngle) cssString(session Session, buffer *strings
buffer.WriteRune(' ') buffer.WriteRune(' ')
buffer.WriteString(angle.cssString()) buffer.WriteString(angle.cssString())
} }
}
case AngleUnit: case AngleUnit:
buffer.WriteRune(' ') buffer.WriteRune(' ')
@ -174,7 +166,7 @@ func backgroundConicGradientSet(properties Properties, tag PropertyName, value a
properties.setRaw(Gradient, vector) properties.setRaw(Gradient, vector)
return []PropertyName{tag} return []PropertyName{tag}
} }
} else if isConstantName(value) { } else if ok, _ := isConstantName(value); ok {
properties.setRaw(Gradient, value) properties.setRaw(Gradient, value)
return []PropertyName{tag} return []PropertyName{tag}
} }
@ -206,15 +198,6 @@ func backgroundConicGradientSet(properties Properties, tag PropertyName, value a
return propertiesSet(properties, tag, value) return propertiesSet(properties, tag, value)
} }
func (gradient *backgroundConicGradient) stringToAngle(text string) (any, bool) {
if text == "" {
return nil, false
} else if text[0] == '@' {
return text, true
}
return StringToAngleUnit(text)
}
func (gradient *backgroundConicGradient) stringToGradientPoint(text string) (BackgroundGradientAngle, bool) { func (gradient *backgroundConicGradient) stringToGradientPoint(text string) (BackgroundGradientAngle, bool) {
var result BackgroundGradientAngle var result BackgroundGradientAngle
colorText := "" colorText := ""
@ -231,7 +214,7 @@ func (gradient *backgroundConicGradient) stringToGradientPoint(text string) (Bac
return result, false return result, false
} }
if colorText[0] == '@' { if ok, _ := isConstantName(colorText); ok {
result.Color = colorText result.Color = colorText
} else if color, ok := StringToColor(colorText); ok { } else if color, ok := StringToColor(colorText); ok {
result.Color = color result.Color = color
@ -240,7 +223,9 @@ func (gradient *backgroundConicGradient) stringToGradientPoint(text string) (Bac
} }
if pointText != "" { if pointText != "" {
if angle, ok := gradient.stringToAngle(pointText); ok { if ok, _ := isConstantName(pointText); ok {
result.Angle = pointText
} else if angle, ok := StringToAngleUnit(text); ok {
result.Angle = angle result.Angle = angle
} else { } else {
return result, false return result, false

View File

@ -103,14 +103,14 @@ func backgroundGradientSet(properties Properties, tag PropertyName, value any) [
case Gradient: case Gradient:
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if value != "" { if ok, _ := isConstantName(value); ok {
if strings.Contains(value, " ") || strings.Contains(value, ",") { properties.setRaw(Gradient, value)
if points := parseGradientText(value); len(points) >= 2 {
properties.setRaw(Gradient, points)
return []PropertyName{tag} return []PropertyName{tag}
} }
} else if value[0] == '@' {
properties.setRaw(Gradient, value) if strings.ContainsAny(value, " ,") {
if points := parseGradientText(value); len(points) >= 2 {
properties.setRaw(Gradient, points)
return []PropertyName{tag} return []PropertyName{tag}
} }
} }
@ -168,7 +168,7 @@ func (point *BackgroundGradientPoint) setValue(text string) bool {
return false return false
} }
if colorText[0] == '@' { if ok, _ := isConstantName(colorText); ok {
point.Color = colorText point.Color = colorText
} else if color, ok := StringToColor(colorText); ok { } else if color, ok := StringToColor(colorText); ok {
point.Color = color point.Color = color
@ -178,7 +178,7 @@ func (point *BackgroundGradientPoint) setValue(text string) bool {
if pointText == "" { if pointText == "" {
point.Pos = nil point.Pos = nil
} else if pointText[0] == '@' { } else if ok, _ := isConstantName(pointText); ok {
point.Pos = pointText point.Pos = pointText
} else if pos, ok := StringToSizeUnit(pointText); ok { } else if pos, ok := StringToSizeUnit(pointText); ok {
point.Pos = pos point.Pos = pos
@ -193,17 +193,10 @@ func (point *BackgroundGradientPoint) color(session Session) (Color, bool) {
if point.Color != nil { if point.Color != nil {
switch color := point.Color.(type) { switch color := point.Color.(type) {
case string: case string:
if color != "" { if ok, constName := isConstantName(color); ok {
if color[0] == '@' { return session.Color(constName)
if clr, ok := session.Color(color[1:]); ok {
return clr, true
}
} else {
if clr, ok := StringToColor(color); ok {
return clr, true
}
}
} }
return StringToColor(color)
case Color: case Color:
return color, true return color, true
@ -256,8 +249,8 @@ func (gradient *backgroundGradient) writeGradient(session Session, buffer *strin
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if value != "" && value[0] == '@' { if ok, constName := isConstantName(value); ok {
if text, ok := session.Constant(value[1:]); ok { if text, ok := session.Constant(constName); ok {
points = parseGradientText(text) points = parseGradientText(text)
} }
} }

View File

@ -450,7 +450,7 @@ func polygonClipDataSet(properties Properties, tag PropertyName, value any) []Pr
for i, val := range value { for i, val := range value {
switch val := val.(type) { switch val := val.(type) {
case string: case string:
if isConstantName(val) { if ok, _ := isConstantName(val); ok {
points[i] = val points[i] = val
} else if size, ok := StringToSizeUnit(val); ok { } else if size, ok := StringToSizeUnit(val); ok {
points[i] = size points[i] = size
@ -484,7 +484,7 @@ func polygonClipDataSet(properties Properties, tag PropertyName, value any) []Pr
points := make([]any, len(values)) points := make([]any, len(values))
for i, val := range values { for i, val := range values {
val = strings.Trim(val, " \t\n\r") val = strings.Trim(val, " \t\n\r")
if isConstantName(val) { if ok, _ := isConstantName(val); ok {
points[i] = val points[i] = val
} else if size, ok := StringToSizeUnit(val); ok { } else if size, ok := StringToSizeUnit(val); ok {
points[i] = size points[i] = size
@ -634,7 +634,7 @@ func setClipShapePropertyProperty(properties Properties, tag PropertyName, value
return []PropertyName{tag} return []PropertyName{tag}
case string: case string:
if isConstantName(value) { if ok, _ := isConstantName(value); ok {
properties.setRaw(tag, value) properties.setRaw(tag, value)
return []PropertyName{tag} return []PropertyName{tag}
} }

View File

@ -159,9 +159,7 @@ func (picker *colorPickerData) handleCommand(self View, command PropertyName, da
for _, listener := range getTwoArgEventListeners[ColorPicker, Color](picker, nil, ColorChangedEvent) { for _, listener := range getTwoArgEventListeners[ColorPicker, Color](picker, nil, ColorChangedEvent) {
listener.Run(picker, color, oldColor) listener.Run(picker, color, oldColor)
} }
if listener, ok := picker.changeListener[ColorPickerValue]; ok { picker.runChangeListener(ColorPickerValue)
listener.Run(picker, ColorPickerValue)
}
} }
} }
} }

View File

@ -207,7 +207,7 @@ func (picker *datePickerData) setFunc(tag PropertyName, value any) []PropertyNam
return []PropertyName{tag} return []PropertyName{tag}
case string: case string:
if isConstantName(value) { if ok, _ := isConstantName(value); ok {
picker.setRaw(tag, value) picker.setRaw(tag, value)
return []PropertyName{tag} return []PropertyName{tag}
} }
@ -351,9 +351,7 @@ func (picker *datePickerData) handleCommand(self View, command PropertyName, dat
for _, listener := range getTwoArgEventListeners[DatePicker, time.Time](picker, nil, DateChangedEvent) { for _, listener := range getTwoArgEventListeners[DatePicker, time.Time](picker, nil, DateChangedEvent) {
listener.Run(picker, value, oldValue) listener.Run(picker, value, oldValue)
} }
if listener, ok := picker.changeListener[DatePickerValue]; ok { picker.runChangeListener(DatePickerValue)
listener.Run(picker, DatePickerValue)
}
} }
} }
} }

View File

@ -192,9 +192,7 @@ func (detailsView *detailsViewData) handleCommand(self View, command PropertyNam
if command == "details-open" { if command == "details-open" {
if n, ok := dataIntProperty(data, "open"); ok { if n, ok := dataIntProperty(data, "open"); ok {
detailsView.properties[Expanded] = (n != 0) detailsView.properties[Expanded] = (n != 0)
if listener, ok := detailsView.changeListener[Expanded]; ok { detailsView.runChangeListener(Expanded)
listener.Run(detailsView, Expanded)
}
} }
return true return true
} }

View File

@ -608,8 +608,8 @@ func GetDragImage(view View, subviewID ...string) string {
if value != nil { if value != nil {
if img, ok := value.(string); ok { if img, ok := value.(string); ok {
img = strings.Trim(img, " \t") img = strings.Trim(img, " \t")
if img != "" && img[0] == '@' { if ok, constName := isConstantName(img); ok {
if img, ok = view.Session().ImageConstant(img[1:]); ok { if img, ok = view.Session().ImageConstant(constName); ok {
return img return img
} }
} else { } else {

View File

@ -139,7 +139,7 @@ func parseIndicesArray(value any) ([]any, bool) {
if val != nil { if val != nil {
switch val := val.(type) { switch val := val.(type) {
case string: case string:
if isConstantName(val) { if ok, _ := isConstantName(val); ok {
items = append(items, val) items = append(items, val)
} else if n, err := strconv.Atoi(val); err == nil { } else if n, err := strconv.Atoi(val); err == nil {
items = append(items, n) items = append(items, n)
@ -162,7 +162,7 @@ func parseIndicesArray(value any) ([]any, bool) {
items := make([]any, 0, len(value)) items := make([]any, 0, len(value))
for _, str := range value { for _, str := range value {
if str = strings.Trim(str, " \t"); str != "" { if str = strings.Trim(str, " \t"); str != "" {
if isConstantName(str) { if ok, _ := isConstantName(str); ok {
items = append(items, str) items = append(items, str)
} else if n, err := strconv.Atoi(str); err == nil { } else if n, err := strconv.Atoi(str); err == nil {
items = append(items, n) items = append(items, n)
@ -248,9 +248,7 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat
for _, listener := range getTwoArgEventListeners[DropDownList, int](list, nil, DropDownEvent) { for _, listener := range getTwoArgEventListeners[DropDownList, int](list, nil, DropDownEvent) {
listener.Run(list, number, old) listener.Run(list, number, old)
} }
if listener, ok := list.changeListener[Current]; ok { list.runChangeListener(Current)
listener.Run(list, Current)
}
} }
} else { } else {
ErrorLog(err.Error()) ErrorLog(err.Error())
@ -308,8 +306,8 @@ func getIndicesArray(view View, tag PropertyName) []int {
result = append(result, value) result = append(result, value)
case string: case string:
if value != "" && value[0] == '@' { if ok, constName := isConstantName(value); ok {
if val, ok := view.Session().Constant(value[1:]); ok { if val, ok := view.Session().Constant(constName); ok {
if n, err := strconv.Atoi(val); err == nil { if n, err := strconv.Atoi(val); err == nil {
result = append(result, n) result = append(result, n)
} }

View File

@ -271,9 +271,7 @@ func (edit *editViewData) textChanged(newText, oldText string) {
for _, listener := range getTwoArgEventListeners[EditView, string](edit, nil, EditTextChangedEvent) { for _, listener := range getTwoArgEventListeners[EditView, string](edit, nil, EditTextChangedEvent) {
listener.Run(edit, newText, oldText) listener.Run(edit, newText, oldText)
} }
if listener, ok := edit.changeListener[Text]; ok { edit.runChangeListener(Text)
listener.Run(edit, Text)
}
} }
func (edit *editViewData) htmlTag() string { func (edit *editViewData) htmlTag() string {

View File

@ -150,7 +150,7 @@ func setGridCellSize(properties Properties, tag PropertyName, value any) []Prope
sizes := make([]any, count) sizes := make([]any, count)
for i, val := range values { for i, val := range values {
val = strings.Trim(val, " \t\n\r") val = strings.Trim(val, " \t\n\r")
if isConstantName(val) { if ok, _ := isConstantName(val); ok {
sizes[i] = val sizes[i] = val
} else if fn := parseSizeFunc(val); fn != nil { } else if fn := parseSizeFunc(val); fn != nil {
sizes[i] = SizeUnit{Type: SizeFunction, Function: fn} sizes[i] = SizeUnit{Type: SizeFunction, Function: fn}
@ -162,7 +162,7 @@ func setGridCellSize(properties Properties, tag PropertyName, value any) []Prope
} }
} }
properties.setRaw(tag, sizes) properties.setRaw(tag, sizes)
} else if isConstantName(values[0]) { } else if ok, _ := isConstantName(values[0]); ok {
properties.setRaw(tag, values[0]) properties.setRaw(tag, values[0])
} else if size, err := stringToSizeUnit(values[0]); err == nil { } else if size, err := stringToSizeUnit(values[0]); err == nil {
properties.setRaw(tag, size) properties.setRaw(tag, size)
@ -220,7 +220,7 @@ func setGridCellSize(properties Properties, tag PropertyName, value any) []Prope
sizes[i] = val sizes[i] = val
case string: case string:
if isConstantName(val) { if ok, _ := isConstantName(val); ok {
sizes[i] = val sizes[i] = val
} else if size, err := stringToSizeUnit(val); err == nil { } else if size, err := stringToSizeUnit(val); err == nil {
sizes[i] = size sizes[i] = size
@ -458,7 +458,7 @@ func (gridLayout *gridLayoutData) UpdateGridContent() {
if gridLayout.created { if gridLayout.created {
updateInnerHTML(gridLayout.htmlID(), gridLayout.session) updateInnerHTML(gridLayout.htmlID(), gridLayout.session)
} }
gridLayout.contentChanged() gridLayout.runChangeListener(Content)
} }
} }

View File

@ -143,8 +143,8 @@ func (manager *imageManager) imageLoadError(obj DataObject) {
// LoadImage starts the async image loading by url // LoadImage starts the async image loading by url
func LoadImage(url string, onLoaded func(Image), session Session) Image { func LoadImage(url string, onLoaded func(Image), session Session) Image {
if url != "" && url[0] == '@' { if ok, constName := isConstantName(url); ok {
if image, ok := session.ImageConstant(url[1:]); ok { if image, ok := session.ImageConstant(constName); ok {
url = image url = image
} }
} }

View File

@ -217,11 +217,11 @@ func (imageView *imageViewData) htmlTag() string {
} }
func imageViewSrc(view View, src string) (string, string) { func imageViewSrc(view View, src string) (string, string) {
if src != "" && src[0] == '@' { if ok, constName := isConstantName(src); ok {
if image, ok := view.Session().ImageConstant(src[1:]); ok { if image, ok := view.Session().ImageConstant(constName); ok {
src = image src = image
} else { } else {
src = "" return "", ""
} }
} }

View File

@ -196,7 +196,7 @@ func (listLayout *listLayoutData) UpdateContent() {
if listLayout.created { if listLayout.created {
updateInnerHTML(listLayout.htmlID(), listLayout.session) updateInnerHTML(listLayout.htmlID(), listLayout.session)
} }
listLayout.contentChanged() listLayout.runChangeListener(Content)
} }
} }

View File

@ -962,9 +962,7 @@ func (listView *listViewData) handleCurrent(number int) {
for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) { for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) {
listener.Run(listView, number) listener.Run(listView, number)
} }
if listener, ok := listView.changeListener[Current]; ok { listView.runChangeListener(Current)
listener.Run(listView, Current)
}
} }
func (listView *listViewData) onItemClick(number int) { func (listView *listViewData) onItemClick(number int) {
@ -1021,9 +1019,7 @@ func (listView *listViewData) onItemClick(number int) {
} }
setArrayPropertyValue(listView, Checked, checkedItem) setArrayPropertyValue(listView, Checked, checkedItem)
if listener, ok := listView.changeListener[Checked]; ok { listView.runChangeListener(Checked)
listener.Run(listView, Checked)
}
for _, listener := range getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) { for _, listener := range getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) {
listener.Run(listView, checkedItem) listener.Run(listView, checkedItem)

View File

@ -283,9 +283,7 @@ func (picker *numberPickerData) handleCommand(self View, command PropertyName, d
for _, listener := range getTwoArgEventListeners[NumberPicker, float64](picker, nil, NumberChangedEvent) { for _, listener := range getTwoArgEventListeners[NumberPicker, float64](picker, nil, NumberChangedEvent) {
listener.Run(picker, value, oldValue) listener.Run(picker, value, oldValue)
} }
if listener, ok := picker.changeListener[NumberPickerValue]; ok { picker.runChangeListener(NumberPickerValue)
listener.Run(picker, NumberPickerValue)
}
} }
} }
} }

View File

@ -615,8 +615,8 @@ func (popup *popupData) Set(tag PropertyName, value any) bool {
popup.setRaw(Content, popup.contentView) popup.setRaw(Content, popup.contentView)
case string: case string:
if len(value) > 0 && value[0] == '@' { if ok, constName := isConstantName(value); ok {
view := CreateViewFromResources(popup.session, value[1:]) view := CreateViewFromResources(popup.session, constName)
if view != nil { if view != nil {
popup.contentView = view popup.contentView = view
break break
@ -1107,8 +1107,8 @@ func (popup *popupData) createTitleView() GridLayout {
if value := popup.getRaw(Title); value != nil { if value := popup.getRaw(Title); value != nil {
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if len(value) > 0 && value[0] == '@' { if ok, constName := isConstantName(value); ok {
title = CreateViewFromResources(session, value[1:]) title = CreateViewFromResources(session, constName)
if title != nil { if title != nil {
break break
} }

View File

@ -18,8 +18,8 @@ func stringProperty(properties Properties, tag PropertyName, session Session) (s
func imageProperty(properties Properties, tag PropertyName, session Session) (string, bool) { func imageProperty(properties Properties, tag PropertyName, session Session) (string, bool) {
if value := properties.getRaw(tag); value != nil { if value := properties.getRaw(tag); value != nil {
if text, ok := value.(string); ok { if text, ok := value.(string); ok {
if text != "" && text[0] == '@' { if ok, constName := isConstantName(text); ok {
if image, ok := session.ImageConstant(text[1:]); ok { if image, ok := session.ImageConstant(constName); ok {
return image, true return image, true
} else { } else {
return "", false return "", false
@ -88,8 +88,8 @@ func valueToColor(value any, session Session) (Color, bool) {
return value, true return value, true
case string: case string:
if len(value) > 1 && value[0] == '@' { if ok, constName := isConstantName(value); ok {
return session.Color(value[1:]) return session.Color(constName)
} }
return StringToColor(value) return StringToColor(value)
} }

View File

@ -511,10 +511,10 @@ func invalidPropertyValue(tag PropertyName, value any) {
ErrorLogF(`Invalid value "%v" of "%s" property`, value, string(tag)) ErrorLogF(`Invalid value "%v" of "%s" property`, value, string(tag))
} }
func isConstantName(text string) bool { func isConstantName(text string) (bool, string) {
len := len(text) len := len(text)
if len <= 1 || text[0] != '@' { if len <= 1 || text[0] != '@' {
return false return false, ""
} }
if len > 2 { if len > 2 {
@ -522,11 +522,14 @@ func isConstantName(text string) bool {
if (text[1] == '`' && text[last] == '`') || if (text[1] == '`' && text[last] == '`') ||
(text[1] == '"' && text[last] == '"') || (text[1] == '"' && text[last] == '"') ||
(text[1] == '\'' && text[last] == '\'') { (text[1] == '\'' && text[last] == '\'') {
return true return true, text[2:last]
} }
} }
return !strings.ContainsAny(text, ",;|\"'`+(){}[]<>/\\*&%! \t\n\r") if strings.ContainsAny(text, ",;|\"'`+(){}[]<>/\\*&%! \t\n\r") {
return false, ""
}
return true, text[1:]
} }
func isInt(value any) (int, bool) { func isInt(value any) (int, bool) {
@ -579,7 +582,7 @@ func setSimpleProperty(properties Properties, tag PropertyName, value any) bool
properties.setRaw(tag, nil) properties.setRaw(tag, nil)
return true return true
} }
if isConstantName(text) { if ok, _ := isConstantName(text); ok {
properties.setRaw(tag, text) properties.setRaw(tag, text)
return true return true
} }

View File

@ -234,7 +234,7 @@ func resizableSetSide(properties Properties, value any) []PropertyName {
val := strings.Trim(val, " \t\r\n") val := strings.Trim(val, " \t\r\n")
values[i] = val values[i] = val
if val[0] == '@' { if ok, _ := isConstantName(val); ok {
hasConst = true hasConst = true
} else if n, err := strconv.Atoi(val); err == nil { } else if n, err := strconv.Atoi(val); err == nil {
if n < 1 || n > AllSides { if n < 1 || n > AllSides {
@ -262,7 +262,7 @@ func resizableSetSide(properties Properties, value any) []PropertyName {
return []PropertyName{Side} return []PropertyName{Side}
} }
} else if value[0] == '@' { } else if ok, _ := isConstantName(value); ok {
properties.setRaw(Side, value) properties.setRaw(Side, value)
return []PropertyName{Side} return []PropertyName{Side}
} else if n, ok := validValues[value]; ok { } else if n, ok := validValues[value]; ok {

View File

@ -130,7 +130,7 @@ func (data *sizeFuncData) parseArgs(args []any, allowNumber bool) bool {
return false return false
} }
if arg[0] == '@' { if ok, _ := isConstantName(arg); ok {
data.args = append(data.args, arg) data.args = append(data.args, arg)
} else if val, err := strconv.ParseFloat(arg, 64); err == nil { } else if val, err := strconv.ParseFloat(arg, 64); err == nil {
return numberArg(i, val) return numberArg(i, val)

View File

@ -377,7 +377,7 @@ func (layout *stackLayoutData) transitionFinished(view View, tag PropertyName) {
} }
} }
delete(layout.onPushFinished, viewID) delete(layout.onPushFinished, viewID)
layout.contentChanged() layout.runChangeListener(Content)
} }
case "pop": case "pop":
@ -416,7 +416,7 @@ func (layout *stackLayoutData) transitionFinished(view View, tag PropertyName) {
session.removeProperty(pageID, "ontransitionend") session.removeProperty(pageID, "ontransitionend")
session.removeProperty(pageID, "ontransitioncancel") session.removeProperty(pageID, "ontransitioncancel")
session.finishUpdateScript(pageID) session.finishUpdateScript(pageID)
layout.contentChanged() layout.runChangeListener(Content)
if finished, ok := layout.onMoveFinished[viewID]; ok { if finished, ok := layout.onMoveFinished[viewID]; ok {
for _, listener := range finished.listener { for _, listener := range finished.listener {
@ -566,7 +566,7 @@ func (layout *stackLayoutData) moveToFrontByIndex(index int, onShow []func(View)
if transform == nil { if transform == nil {
session.updateCSSProperty(peekPageID, "visibility", "hidden") session.updateCSSProperty(peekPageID, "visibility", "hidden")
session.updateCSSProperty(pageID, "visibility", "visible") session.updateCSSProperty(pageID, "visibility", "visible")
layout.contentChanged() layout.runChangeListener(Content)
for _, listener := range onShow { for _, listener := range onShow {
if listener != nil { if listener != nil {
listener(view) listener(view)
@ -677,7 +677,7 @@ func (layout *stackLayoutData) Append(view View) {
} }
session.appendToInnerHTML(stackID, buffer.String()) session.appendToInnerHTML(stackID, buffer.String())
layout.contentChanged() layout.runChangeListener(Content)
} }
} }
@ -713,7 +713,7 @@ func (layout *stackLayoutData) Insert(view View, index int) {
session := layout.Session() session := layout.Session()
session.appendToInnerHTML(stackID, buffer.String()) session.appendToInnerHTML(stackID, buffer.String())
layout.contentChanged() layout.runChangeListener(Content)
} }
// Remove removes view from list and return it // Remove removes view from list and return it
@ -744,7 +744,7 @@ func (layout *stackLayoutData) RemoveView(index int) View {
} }
layout.Session().callFunc("removeView", view.htmlID()+"page") layout.Session().callFunc("removeView", view.htmlID()+"page")
layout.contentChanged() layout.runChangeListener(Content)
return view return view
} }
@ -839,7 +839,7 @@ func (layout *stackLayoutData) Pop(onPopFinished ...func(View)) bool {
view.setParentID("") view.setParentID("")
layout.views = layout.views[:peek] layout.views = layout.views[:peek]
layout.contentChanged() layout.runChangeListener(Content)
layout.onPopFinished[view.htmlID()] = popFinished{ layout.onPopFinished[view.htmlID()] = popFinished{
view: view, view: view,

View File

@ -695,7 +695,7 @@ func (table *tableViewData) setFunc(tag PropertyName, value any) []PropertyName
case HeadHeight, FootHeight: case HeadHeight, FootHeight:
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if isConstantName(value) { if ok, _ := isConstantName(value); ok {
table.setRaw(tag, value) table.setRaw(tag, value)
} else if n, err := strconv.Atoi(value); err == nil { } else if n, err := strconv.Atoi(value); err == nil {
table.setRaw(tag, n) table.setRaw(tag, n)
@ -1675,13 +1675,10 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data
if row, ok := dataIntProperty(data, "row"); ok && row != current.Row { if row, ok := dataIntProperty(data, "row"); ok && row != current.Row {
current.Row = row current.Row = row
table.setRaw(Current, current.Row) table.setRaw(Current, current.Row)
if listener, ok := table.changeListener[Current]; ok {
listener.Run(table, Current)
}
for _, listener := range getOneArgEventListeners[TableView, int](table, nil, TableRowSelectedEvent) { for _, listener := range getOneArgEventListeners[TableView, int](table, nil, TableRowSelectedEvent) {
listener.Run(table, row) listener.Run(table, row)
} }
table.runChangeListener(Current)
} }
case "currentCell": case "currentCell":
@ -1692,13 +1689,11 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data
current.Row = row current.Row = row
current.Column = column current.Column = column
table.setRaw(Current, current.Row) table.setRaw(Current, current.Row)
if listener, ok := table.changeListener[Current]; ok {
listener.Run(table, Current)
}
for _, listener := range getTwoArgEventListeners[TableView, int](table, nil, TableCellSelectedEvent) { for _, listener := range getTwoArgEventListeners[TableView, int](table, nil, TableCellSelectedEvent) {
listener.Run(table, row, column) listener.Run(table, row, column)
} }
table.runChangeListener(Current)
} }
} }
} }

View File

@ -403,7 +403,7 @@ func (tabsLayout *tabsLayoutData) Append(view View) {
view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton) view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton)
if tabsLayout.created { if tabsLayout.created {
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session()) updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
tabsLayout.contentChanged() tabsLayout.runChangeListener(Content)
tabsLayout.Set(Current, len(tabsLayout.views)-1) tabsLayout.Set(Current, len(tabsLayout.views)-1)
} }
} }
@ -427,7 +427,7 @@ func (tabsLayout *tabsLayoutData) currentChanged(newCurrent, oldCurrent int) {
for _, listener := range getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) { for _, listener := range getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) {
listener.Run(tabsLayout, newCurrent, oldCurrent) listener.Run(tabsLayout, newCurrent, oldCurrent)
} }
tabsLayout.contentChanged() tabsLayout.runChangeListener(Current)
} }
// Remove removes view from list and return it // Remove removes view from list and return it
@ -453,7 +453,7 @@ func (tabsLayout *tabsLayoutData) RemoveView(index int) View {
tabsLayout.Set(Current, newCurrent) tabsLayout.Set(Current, newCurrent)
} }
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session()) updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
tabsLayout.contentChanged() tabsLayout.runChangeListener(Content)
} else if newCurrent != oldCurrent { } else if newCurrent != oldCurrent {
tabsLayout.setRaw(Current, newCurrent) tabsLayout.setRaw(Current, newCurrent)
} }

View File

@ -176,7 +176,7 @@ func (picker *timePickerData) setFunc(tag PropertyName, value any) []PropertyNam
return []PropertyName{tag} return []PropertyName{tag}
case string: case string:
if isConstantName(value) { if ok, _ := isConstantName(value); ok {
picker.setRaw(tag, value) picker.setRaw(tag, value)
return []PropertyName{tag} return []PropertyName{tag}
} }
@ -323,10 +323,7 @@ func (picker *timePickerData) handleCommand(self View, command PropertyName, dat
for _, listener := range getTwoArgEventListeners[TimePicker, time.Time](picker, nil, TimeChangedEvent) { for _, listener := range getTwoArgEventListeners[TimePicker, time.Time](picker, nil, TimeChangedEvent) {
listener.Run(picker, value, oldValue) listener.Run(picker, value, oldValue)
} }
if listener, ok := picker.changeListener[TimePickerValue]; ok { picker.runChangeListener(TimePickerValue)
listener.Run(picker, TimePickerValue)
}
} }
} }
} }

18
view.go
View File

@ -246,15 +246,19 @@ func (view *viewData) Focusable() bool {
return false return false
} }
func (view *viewData) runChangeListener(tag PropertyName) {
if listener, ok := view.changeListener[tag]; ok {
listener.Run(view, tag)
}
}
func (view *viewData) Remove(tag PropertyName) { func (view *viewData) Remove(tag PropertyName) {
changedTags := view.removeFunc(view.normalize(tag)) changedTags := view.removeFunc(view.normalize(tag))
if view.created && len(changedTags) > 0 { if view.created && len(changedTags) > 0 {
for _, tag := range changedTags { for _, tag := range changedTags {
view.changed(tag) view.changed(tag)
if listener, ok := view.changeListener[tag]; ok { view.runChangeListener(tag)
listener.Run(view, tag)
}
} }
} }
} }
@ -280,9 +284,7 @@ func (view *viewData) Set(tag PropertyName, value any) bool {
if view.created && len(changedTags) > 0 { if view.created && len(changedTags) > 0 {
for _, tag := range changedTags { for _, tag := range changedTags {
view.changed(tag) view.changed(tag)
if listener, ok := view.changeListener[tag]; ok { view.runChangeListener(tag)
listener.Run(view, tag)
}
} }
} }
@ -910,8 +912,8 @@ func (view *viewData) propertyChanged(tag PropertyName) {
case DragImage: case DragImage:
if img, ok := stringProperty(view, DragImage, session); ok && img != "" { if img, ok := stringProperty(view, DragImage, session); ok && img != "" {
img = strings.Trim(img, " \t") img = strings.Trim(img, " \t")
if img[0] == '@' { if ok, constName := isConstantName(img); ok {
img, ok = session.ImageConstant(img[1:]) img, ok = session.ImageConstant(constName)
if !ok { if !ok {
session.removeProperty(htmlID, "data-drag-image") session.removeProperty(htmlID, "data-drag-image")
return return

View File

@ -88,13 +88,7 @@ func (container *viewsContainerData) Append(view View) {
viewHTML(view, buffer, "") viewHTML(view, buffer, "")
container.Session().appendToInnerHTML(container.htmlID(), buffer.String()) container.Session().appendToInnerHTML(container.htmlID(), buffer.String())
container.contentChanged() container.runChangeListener(Content)
}
}
func (container *viewsContainerData) contentChanged() {
if listener, ok := container.changeListener[Content]; ok {
listener.Run(container, Content)
} }
} }
@ -119,7 +113,7 @@ func (container *viewsContainerData) insert(view View, index int) bool {
func (container *viewsContainerData) Insert(view View, index int) { func (container *viewsContainerData) Insert(view View, index int) {
if container.insert(view, index) && container.created { if container.insert(view, index) && container.created {
updateInnerHTML(container.htmlID(), container.Session()) updateInnerHTML(container.htmlID(), container.Session())
container.contentChanged() container.runChangeListener(Content)
} }
} }
@ -153,7 +147,7 @@ func (container *viewsContainerData) RemoveView(index int) View {
view := container.removeView(index) view := container.removeView(index)
if view != nil && container.created { if view != nil && container.created {
container.Session().callFunc("removeView", view.htmlID()) container.Session().callFunc("removeView", view.htmlID())
container.contentChanged() container.runChangeListener(Content)
} }
return view return view
} }
@ -190,6 +184,11 @@ func viewFromTextValue(text string, session Session) View {
return view return view
} }
} }
if ok, constName := isConstantName(text); ok {
if view := CreateViewFromResources(session, constName); view != nil {
return view
}
}
return NewTextView(session, Params{Text: text}) return NewTextView(session, Params{Text: text})
} }