Optimisation

This commit is contained in:
Alexei Anoshenko 2026-05-22 15:54:35 -04:00
parent 167fbd2fd8
commit ca68b80b38
13 changed files with 439 additions and 401 deletions

View File

@ -4,6 +4,7 @@
* Added GoogleFonts field to AppParams
* Added functions: GetWhiteSpace, GetWordBreak, ScrollIntoViewIfNeeded
* Added PopupShowAnimation and SetPopupShowAnimation methods to Session interface
* Added ToBoundsProperty method to Bounds struct
# v0.20.0

View File

@ -423,11 +423,9 @@ func animationSet(properties Properties, tag PropertyName, value any) []Property
if text, ok := value.(string); ok {
text = strings.Trim(text, " \t\n\r")
if text == "" {
properties.setRaw(tag, nil)
} else {
properties.setRaw(tag, text)
return removeProperty(properties, tag)
}
return []PropertyName{tag}
return setPropertyValue(properties, tag, text)
}
notCompatibleType(tag, value)
return nil
@ -571,8 +569,7 @@ func animationSet(properties Properties, tag PropertyName, value any) []Property
case TimingFunction:
if text, ok := value.(string); ok {
properties.setRaw(tag, text)
return []PropertyName{tag}
return setPropertyValue(properties, tag, text)
}
case IterationCount:

View File

@ -178,14 +178,11 @@ func setBackgroundProperty(properties Properties, tag PropertyName, value any) [
return nil
}
if len(background) > 0 {
properties.setRaw(tag, background)
} else if properties.getRaw(tag) != nil {
properties.setRaw(tag, nil)
} else {
return []PropertyName{}
if len(background) == 0 {
return removeProperty(properties, tag)
}
properties.setRaw(tag, background)
return []PropertyName{tag}
}

View File

@ -167,8 +167,7 @@ func backgroundConicGradientSet(properties Properties, tag PropertyName, value a
return []PropertyName{tag}
}
} else if ok, _ := isConstantName(value); ok {
properties.setRaw(Gradient, value)
return []PropertyName{tag}
return setPropertyValue(properties, Gradient, value)
}
ErrorLogF(`Invalid conic gradient: "%s"`, value)

View File

@ -104,8 +104,7 @@ func backgroundGradientSet(properties Properties, tag PropertyName, value any) [
switch value := value.(type) {
case string:
if ok, _ := isConstantName(value); ok {
properties.setRaw(Gradient, value)
return []PropertyName{tag}
return setPropertyValue(properties, tag, value)
}
if strings.ContainsAny(value, " ,") {
@ -319,16 +318,14 @@ func backgroundLinearGradientSet(properties Properties, tag PropertyName, value
if tag == Direction {
switch value := value.(type) {
case AngleUnit:
properties.setRaw(Direction, value)
return []PropertyName{tag}
return setPropertyValue(properties, tag, value)
case string:
if setSimpleProperty(properties, tag, value) {
return []PropertyName{tag}
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
if angle, ok := StringToAngleUnit(value); ok {
properties.setRaw(Direction, angle)
return []PropertyName{tag}
return setPropertyValue(properties, tag, angle)
}
case LinearGradientDirectionType:

View File

@ -141,25 +141,23 @@ func backgroundRadialGradientSet(properties Properties, tag PropertyName, value
case []SizeUnit:
switch len(value) {
case 0:
properties.setRaw(RadialGradientRadius, nil)
return removeProperty(properties, tag)
case 1:
if value[0].Type == Auto {
properties.setRaw(RadialGradientRadius, nil)
} else {
properties.setRaw(RadialGradientRadius, value[0])
return removeProperty(properties, tag)
}
return setPropertyValue(properties, tag, value[0])
default:
properties.setRaw(RadialGradientRadius, value)
}
return []PropertyName{tag}
}
case []any:
switch len(value) {
case 0:
properties.setRaw(RadialGradientRadius, nil)
return []PropertyName{tag}
return removeProperty(properties, tag)
case 1:
return backgroundRadialGradientSet(properties, RadialGradientRadius, value[0])
@ -170,26 +168,24 @@ func backgroundRadialGradientSet(properties Properties, tag PropertyName, value
}
case string:
if setSimpleProperty(properties, RadialGradientRadius, value) {
return []PropertyName{tag}
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
if size, err := stringToSizeUnit(value); err == nil {
if size.Type == Auto {
properties.setRaw(RadialGradientRadius, nil)
return removeProperty(properties, tag)
} else {
properties.setRaw(RadialGradientRadius, size)
return setPropertyValue(properties, tag, size)
}
return []PropertyName{tag}
}
return setEnumProperty(properties, RadialGradientRadius, value, enumProperties[RadialGradientRadius].values)
case SizeUnit:
if value.Type == Auto {
properties.setRaw(RadialGradientRadius, nil)
return removeProperty(properties, tag)
} else {
properties.setRaw(RadialGradientRadius, value)
return setPropertyValue(properties, tag, value)
}
return []PropertyName{tag}
case RadialGradientRadiusType:
return setEnumProperty(properties, RadialGradientRadius, int(value), enumProperties[RadialGradientRadius].values)

View File

@ -107,6 +107,26 @@ func DefaultBounds() Bounds {
}
}
// ToBoundsProperty() convert Bounds to BoundsProperty.
// The fields with Auto value will not be set in the result BoundsProperty.
func (bounds *Bounds) ToBoundsProperty() BoundsProperty {
result := NewBoundsProperty(nil)
if bounds.Top.Type != Auto {
result.setRaw(Top, bounds.Top)
}
if bounds.Right.Type != Auto {
result.setRaw(Right, bounds.Right)
}
if bounds.Bottom.Type != Auto {
result.setRaw(Bottom, bounds.Bottom)
}
if bounds.Left.Type != Auto {
result.setRaw(Left, bounds.Left)
}
return result
}
// SetAll set the Top, Right, Bottom and Left field to the equal value
func (bounds *Bounds) SetAll(value SizeUnit) {
bounds.Top = value
@ -179,15 +199,25 @@ func (bounds *Bounds) cssString(session Session) string {
}
func setBoundsProperty(properties Properties, tag PropertyName, value any) []PropertyName {
if !setSimpleProperty(properties, tag, value) {
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
switch value := value.(type) {
case string:
if strings.ContainsRune(value, ',') {
values := split4Values(value)
count := len(values)
switch count {
switch count := len(values); count {
case 1:
value = values[0]
return setSizeProperty(properties, tag, value[0])
case 5:
text := strings.Trim(values[4], " \t\n\r")
if text != "" {
notCompatibleType(tag, value)
return nil
}
fallthrough
case 4:
bounds := NewBoundsProperty(nil)
@ -196,6 +226,10 @@ func setBoundsProperty(properties Properties, tag PropertyName, value any) []Pro
return nil
}
}
if bounds.IsEmpty() {
return removeProperty(properties, tag)
}
properties.setRaw(tag, bounds)
return []PropertyName{tag}
@ -207,31 +241,25 @@ func setBoundsProperty(properties Properties, tag PropertyName, value any) []Pro
return setSizeProperty(properties, tag, value)
case SizeUnit:
properties.setRaw(tag, value)
return setPropertyValue(properties, tag, value)
case float32:
properties.setRaw(tag, Px(float64(value)))
return setPropertyValue(properties, tag, Px(float64(value)))
case float64:
properties.setRaw(tag, Px(value))
return setPropertyValue(properties, tag, Px(value))
case Bounds:
bounds := NewBoundsProperty(nil)
if value.Top.Type != Auto {
bounds.setRaw(Top, value.Top)
}
if value.Right.Type != Auto {
bounds.setRaw(Right, value.Right)
}
if value.Bottom.Type != Auto {
bounds.setRaw(Bottom, value.Bottom)
}
if value.Left.Type != Auto {
bounds.setRaw(Left, value.Left)
bounds := value.ToBoundsProperty()
if bounds.IsEmpty() {
return removeProperty(properties, tag)
}
properties.setRaw(tag, bounds)
case BoundsProperty:
if value.IsEmpty() {
return removeProperty(properties, tag)
}
properties.setRaw(tag, value)
case DataObject:
@ -244,17 +272,19 @@ func setBoundsProperty(properties Properties, tag PropertyName, value any) []Pro
}
}
}
if bounds.IsEmpty() {
return removeProperty(properties, tag)
}
properties.setRaw(tag, bounds)
default:
if n, ok := isInt(value); ok {
properties.setRaw(tag, Px(float64(n)))
return setPropertyValue(properties, tag, Px(float64(n)))
} else {
notCompatibleType(tag, value)
return nil
}
}
}
return []PropertyName{tag}
}

View File

@ -635,8 +635,7 @@ func setClipShapePropertyProperty(properties Properties, tag PropertyName, value
case string:
if ok, _ := isConstantName(value); ok {
properties.setRaw(tag, value)
return []PropertyName{tag}
return setPropertyValue(properties, tag, value)
}
if obj := NewDataObject(value); obj == nil {

View File

@ -214,18 +214,15 @@ func (picker *datePickerData) setFunc(tag PropertyName, value any) []PropertyNam
setDateValue := func(tag PropertyName) []PropertyName {
switch value := value.(type) {
case time.Time:
picker.setRaw(tag, value)
return []PropertyName{tag}
return setPropertyValue(picker, tag, value)
case string:
if ok, _ := isConstantName(value); ok {
picker.setRaw(tag, value)
return []PropertyName{tag}
return setPropertyValue(picker, tag, value)
}
if date, ok := stringToDate(value); ok {
picker.setRaw(tag, date)
return []PropertyName{tag}
return setPropertyValue(picker, tag, date)
}
}

View File

@ -285,33 +285,21 @@ func stringToDropEffect(text string) (int, bool) {
}
func (view *viewData) setDropEffect(value any) []PropertyName {
if !setSimpleProperty(view, DropEffect, value) {
if result := setSimpleProperty(view, DropEffect, value); result != nil {
return result
}
var newValue int
if text, ok := value.(string); ok {
if n, ok := stringToDropEffect(text); ok {
if n == DropEffectUndefined {
view.setRaw(DropEffect, nil)
} else {
view.setRaw(DropEffect, n)
}
} else {
if newValue, ok = stringToDropEffect(text); !ok {
invalidPropertyValue(DropEffect, value)
return nil
}
} else if i, ok := isInt(value); ok {
switch i {
case DropEffectUndefined:
view.setRaw(DropEffect, nil)
case DropEffectCopy, DropEffectMove, DropEffectLink:
view.setRaw(DropEffect, i)
default:
invalidPropertyValue(DropEffect, value)
return nil
}
newValue = i
} else {
@ -319,9 +307,17 @@ func (view *viewData) setDropEffect(value any) []PropertyName {
return nil
}
}
switch newValue {
case DropEffectUndefined:
return removeProperty(view, DropEffect)
return []PropertyName{DropEffect}
case DropEffectCopy, DropEffectMove, DropEffectLink:
return setPropertyValue(view, DropEffect, newValue)
default:
invalidPropertyValue(DropEffect, value)
return nil
}
}
func stringToDropEffectAllowed(text string) (int, bool) {
@ -348,39 +344,35 @@ func stringToDropEffectAllowed(text string) (int, bool) {
}
func (view *viewData) setDropEffectAllowed(value any) []PropertyName {
if !setSimpleProperty(view, DropEffectAllowed, value) {
if text, ok := value.(string); ok {
if n, ok := stringToDropEffectAllowed(text); ok {
if n == DropEffectUndefined {
view.setRaw(DropEffectAllowed, nil)
} else {
view.setRaw(DropEffectAllowed, n)
if result := setSimpleProperty(view, DropEffectAllowed, value); result != nil {
return result
}
} else {
var newValue int
if text, ok := value.(string); ok {
if newValue, ok = stringToDropEffectAllowed(text); !ok {
invalidPropertyValue(DropEffectAllowed, value)
return nil
}
} else {
n, ok := isInt(value)
if !ok {
notCompatibleType(DropEffectAllowed, value)
return nil
}
if n == DropEffectUndefined {
view.setRaw(DropEffectAllowed, nil)
} else if n > DropEffectUndefined && n <= DropEffectAll {
view.setRaw(DropEffectAllowed, n)
} else {
var ok bool
if newValue, ok = isInt(value); !ok {
notCompatibleType(DropEffectAllowed, value)
return nil
}
}
if newValue == DropEffectUndefined {
return removeProperty(view, DropEffectAllowed)
}
return []PropertyName{DropEffectAllowed}
if newValue < DropEffectUndefined || newValue > DropEffectAll {
notCompatibleType(DropEffectAllowed, value)
return nil
}
return setPropertyValue(view, DropEffectAllowed, newValue)
}
func handleDragAndDropEvents(view View, tag PropertyName, data DataObject) {

View File

@ -166,6 +166,9 @@ func (edit *editViewData) setFunc(tag PropertyName, value any) []PropertyName {
old := ""
if val := edit.getRaw(Text); val != nil {
if txt, ok := val.(string); ok {
if txt == text {
return []PropertyName{}
}
old = txt
}
}

View File

@ -561,48 +561,79 @@ func isInt(value any) (int, bool) {
return n, true
}
func setSimpleProperty(properties Properties, tag PropertyName, value any) bool {
if value == nil {
properties.setRaw(tag, nil)
return true
} else if text, ok := value.(string); ok {
text = strings.Trim(text, " \t\n\r")
if text == "" {
properties.setRaw(tag, nil)
return true
}
if ok, _ := isConstantName(text); ok {
properties.setRaw(tag, text)
return true
}
}
return false
}
func setStringPropertyValue(properties Properties, tag PropertyName, text any) []PropertyName {
if text != "" {
properties.setRaw(tag, text)
} else if properties.getRaw(tag) != nil {
properties.setRaw(tag, nil)
} else {
func setPropertyValue[T comparable](properties Properties, tag PropertyName, value T) []PropertyName {
if oldValue := properties.getRaw(tag); oldValue != nil {
if oldTypedValue, ok := oldValue.(T); ok && oldTypedValue == value {
return []PropertyName{}
}
}
properties.setRaw(tag, value)
return []PropertyName{tag}
}
func setArrayPropertyValue[T any](properties Properties, tag PropertyName, value []T) []PropertyName {
if len(value) > 0 {
properties.setRaw(tag, value)
} else if properties.getRaw(tag) != nil {
func removeProperty(properties Properties, tag PropertyName) []PropertyName {
if properties.getRaw(tag) != nil {
properties.setRaw(tag, nil)
} else {
return []PropertyName{tag}
}
return []PropertyName{}
}
func setSimpleProperty(properties Properties, tag PropertyName, value any) []PropertyName {
if value == nil {
return removeProperty(properties, tag)
}
if text, ok := value.(string); ok {
text = strings.Trim(text, " \t\n\r")
if text == "" {
return removeProperty(properties, tag)
}
if oldValue := properties.getRaw(tag); oldValue != nil {
if oldText, ok := oldValue.(string); ok && oldText == text {
return []PropertyName{}
}
}
if ok, _ := isConstantName(text); ok {
properties.setRaw(tag, text)
return []PropertyName{tag}
}
}
return nil
}
func setStringPropertyValue(properties Properties, tag PropertyName, text string) []PropertyName {
if text == "" {
return removeProperty(properties, tag)
}
return setPropertyValue(properties, tag, text)
}
func setArrayPropertyValue[T any](properties Properties, tag PropertyName, value []T) []PropertyName {
if len(value) == 0 {
return removeProperty(properties, tag)
}
/*
oldValue := properties.getRaw(tag)
if oldValue != nil {
if oldArray, ok := oldValue.([]T); ok && slices.Equal(oldArray, value) {
return []PropertyName{}
}
}
*/
properties.setRaw(tag, value)
return []PropertyName{tag}
}
func setSizeProperty(properties Properties, tag PropertyName, value any) []PropertyName {
if !setSimpleProperty(properties, tag, value) {
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
var size SizeUnit
switch value := value.(type) {
case string:
@ -640,17 +671,16 @@ func setSizeProperty(properties Properties, tag PropertyName, value any) []Prope
}
if size.Type == Auto {
properties.setRaw(tag, nil)
} else {
properties.setRaw(tag, size)
return removeProperty(properties, tag)
}
}
return []PropertyName{tag}
return setPropertyValue(properties, tag, size)
}
func setAngleProperty(properties Properties, tag PropertyName, value any) []PropertyName {
if !setSimpleProperty(properties, tag, value) {
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
var angle AngleUnit
switch value := value.(type) {
case string:
@ -676,14 +706,15 @@ func setAngleProperty(properties Properties, tag PropertyName, value any) []Prop
return nil
}
}
properties.setRaw(tag, angle)
}
return []PropertyName{tag}
return setPropertyValue(properties, tag, angle)
}
func setColorProperty(properties Properties, tag PropertyName, value any) []PropertyName {
if !setSimpleProperty(properties, tag, value) {
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
var result Color
switch value := value.(type) {
case string:
@ -704,14 +735,14 @@ func setColorProperty(properties Properties, tag PropertyName, value any) []Prop
}
}
properties.setRaw(tag, result)
}
return []PropertyName{tag}
return setPropertyValue(properties, tag, result)
}
func setEnumProperty(properties Properties, tag PropertyName, value any, values []string) []PropertyName {
if !setSimpleProperty(properties, tag, value) {
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
var n int
if text, ok := value.(string); ok {
if n, ok = enumStringToInt(text, values, false); !ok {
@ -729,21 +760,22 @@ func setEnumProperty(properties Properties, tag PropertyName, value any, values
return nil
}
properties.setRaw(tag, n)
}
return []PropertyName{tag}
return setPropertyValue(properties, tag, n)
}
func setBoolProperty(properties Properties, tag PropertyName, value any) []PropertyName {
if !setSimpleProperty(properties, tag, value) {
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
var flag bool
if text, ok := value.(string); ok {
switch strings.ToLower(strings.Trim(text, " \t")) {
case "true", "yes", "on", "1":
properties.setRaw(tag, true)
flag = true
case "false", "no", "off", "0":
properties.setRaw(tag, false)
flag = false
default:
invalidPropertyValue(tag, value)
@ -752,28 +784,31 @@ func setBoolProperty(properties Properties, tag PropertyName, value any) []Prope
} else if n, ok := isInt(value); ok {
switch n {
case 1:
properties.setRaw(tag, true)
flag = true
case 0:
properties.setRaw(tag, false)
flag = false
default:
invalidPropertyValue(tag, value)
return nil
}
} else if b, ok := value.(bool); ok {
properties.setRaw(tag, b)
flag = b
} else {
notCompatibleType(tag, value)
return nil
}
}
return []PropertyName{tag}
return setPropertyValue(properties, tag, flag)
}
func setIntProperty(properties Properties, tag PropertyName, value any) []PropertyName {
if !setSimpleProperty(properties, tag, value) {
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
var result int
if text, ok := value.(string); ok {
n, err := strconv.Atoi(strings.Trim(text, " \t"))
if err != nil {
@ -781,60 +816,54 @@ func setIntProperty(properties Properties, tag PropertyName, value any) []Proper
ErrorLog(err.Error())
return nil
}
properties.setRaw(tag, n)
result = n
} else if n, ok := isInt(value); ok {
properties.setRaw(tag, n)
result = n
} else {
notCompatibleType(tag, value)
return nil
}
}
return []PropertyName{tag}
return setPropertyValue(properties, tag, result)
}
func setFloatProperty(properties Properties, tag PropertyName, value any, min, max float64) []PropertyName {
if !setSimpleProperty(properties, tag, value) {
f := float64(0)
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
var result float64
switch value := value.(type) {
case string:
var err error
if f, err = strconv.ParseFloat(strings.Trim(value, " \t"), 64); err != nil {
f, err := strconv.ParseFloat(strings.Trim(value, " \t"), 64)
if err != nil {
invalidPropertyValue(tag, value)
ErrorLog(err.Error())
return nil
}
if f < min || f > max {
ErrorLogF(`"%T" out of range of "%s" property`, value, tag)
return nil
}
properties.setRaw(tag, value)
return nil
result = f
case float32:
f = float64(value)
result = float64(value)
case float64:
f = value
result = value
default:
if n, ok := isInt(value); ok {
f = float64(n)
result = float64(n)
} else {
notCompatibleType(tag, value)
return nil
}
}
if f >= min && f <= max {
properties.setRaw(tag, f)
} else {
if result < min || result > max {
ErrorLogF(`"%T" out of range of "%s" property`, value, tag)
return nil
}
}
return []PropertyName{tag}
return setPropertyValue(properties, tag, result)
}
func propertiesSet(properties Properties, tag PropertyName, value any) []PropertyName {

View File

@ -47,29 +47,30 @@ func (r *Range) setValue(value string) bool {
}
func setRangeProperty(properties Properties, tag PropertyName, value any) []PropertyName {
switch value := value.(type) {
case string:
if setSimpleProperty(properties, tag, value) {
return []PropertyName{tag}
if result := setSimpleProperty(properties, tag, value); result != nil {
return result
}
var r Range
switch value := value.(type) {
case string:
if !r.setValue(value) {
invalidPropertyValue(tag, value)
return nil
}
properties.setRaw(tag, r)
case Range:
properties.setRaw(tag, value)
r = value
default:
if n, ok := isInt(value); ok {
properties.setRaw(tag, Range{First: n, Last: n})
r.First = n
r.Last = n
} else {
notCompatibleType(tag, value)
return nil
}
}
return []PropertyName{tag}
return setPropertyValue(properties, tag, r)
}