Bug fixing

This commit is contained in:
Alexei Anoshenko 2026-08-15 11:33:22 +03:00
parent 20f7cab725
commit 6ca2de5c6c
21 changed files with 61 additions and 49 deletions

View File

@ -593,7 +593,7 @@ func (animation *animationData) String() string {
for _, tag := range animation.AllTags() { for _, tag := range animation.AllTags() {
if tag != PropertyTag { if tag != PropertyTag {
if value, ok := animation.properties[tag]; ok && value != nil { if value := animation.getRaw(tag); value != nil {
text := propertyValueToString(tag, value, "\t") text := propertyValueToString(tag, value, "\t")
if text != "" { if text != "" {
buffer.WriteString("\n\t") buffer.WriteString("\n\t")

View File

@ -93,7 +93,7 @@ func (animation *animationData) onAnimationEnd(view View, _ PropertyName) {
animationView := animation.view animationView := animation.view
listener := animation.listener listener := animation.listener
if value, ok := animation.properties[PropertyTag]; ok { if value := animation.getRaw(PropertyTag); value != nil {
if props, ok := value.([]AnimatedProperty); ok { if props, ok := value.([]AnimatedProperty); ok {
for _, prop := range props { for _, prop := range props {
animationView.setRaw(prop.Tag, prop.To) animationView.setRaw(prop.Tag, prop.To)
@ -119,7 +119,7 @@ func (animation *animationData) onAnimationCancel(view View, _ PropertyName) {
animationView := animation.view animationView := animation.view
listener := animation.listener listener := animation.listener
if value, ok := animation.properties[PropertyTag]; ok { if value := animation.getRaw(PropertyTag); value != nil {
if props, ok := value.([]AnimatedProperty); ok { if props, ok := value.([]AnimatedProperty); ok {
for _, prop := range props { for _, prop := range props {
animationView.Set(prop.Tag, prop.To) animationView.Set(prop.Tag, prop.To)

View File

@ -141,9 +141,9 @@ func (gradient *backgroundConicGradient) Tag() string {
func (image *backgroundConicGradient) Clone() BackgroundElement { func (image *backgroundConicGradient) Clone() BackgroundElement {
result := NewBackgroundConicGradient(nil) result := NewBackgroundConicGradient(nil)
for tag, value := range image.properties { image.mutex.Lock()
result.setRaw(tag, value) result.setAll(image.properties)
} image.mutex.Unlock()
return result return result
} }
@ -268,7 +268,7 @@ func (gradient *backgroundConicGradient) parseGradientText(value string) []Backg
func (gradient *backgroundConicGradient) cssStyle(session Session) string { func (gradient *backgroundConicGradient) cssStyle(session Session) string {
points := []BackgroundGradientAngle{} points := []BackgroundGradientAngle{}
if value, ok := gradient.properties[Gradient]; ok { if value := gradient.getRaw(Gradient); value != nil {
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if text, ok := session.resolveConstants(value); ok && text != "" { if text, ok := session.resolveConstants(value); ok && text != "" {

View File

@ -105,9 +105,9 @@ func (image *backgroundImage) Tag() string {
func (image *backgroundImage) Clone() BackgroundElement { func (image *backgroundImage) Clone() BackgroundElement {
result := NewBackgroundImage(nil) result := NewBackgroundImage(nil)
for tag, value := range image.properties { image.mutex.Lock()
result.setRaw(tag, value) result.setAll(image.properties)
} image.mutex.Unlock()
return result return result
} }

View File

@ -253,8 +253,8 @@ func (point *BackgroundGradientPoint) String() string {
func (gradient *backgroundGradient) writeGradient(session Session, buffer *strings.Builder) bool { func (gradient *backgroundGradient) writeGradient(session Session, buffer *strings.Builder) bool {
value, ok := gradient.properties[Gradient] value := gradient.getRaw(Gradient)
if !ok { if value == nil {
return false return false
} }
@ -322,9 +322,9 @@ func (gradient *backgroundLinearGradient) Tag() string {
func (image *backgroundLinearGradient) Clone() BackgroundElement { func (image *backgroundLinearGradient) Clone() BackgroundElement {
result := NewBackgroundLinearGradient(nil) result := NewBackgroundLinearGradient(nil)
for tag, value := range image.properties { image.mutex.Lock()
result.setRaw(tag, value) result.setAll(image.properties)
} image.mutex.Unlock()
return result return result
} }
@ -361,7 +361,7 @@ func (gradient *backgroundLinearGradient) cssStyle(session Session) string {
buffer.WriteString(`linear-gradient(`) buffer.WriteString(`linear-gradient(`)
} }
if value, ok := gradient.properties[Direction]; ok { if value := gradient.getRaw(Direction); value != nil {
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if text, ok := session.resolveConstants(value); ok { if text, ok := session.resolveConstants(value); ok {

View File

@ -109,9 +109,9 @@ func (gradient *backgroundRadialGradient) Tag() string {
func (image *backgroundRadialGradient) Clone() BackgroundElement { func (image *backgroundRadialGradient) Clone() BackgroundElement {
result := NewBackgroundRadialGradient(nil) result := NewBackgroundRadialGradient(nil)
for tag, value := range image.properties { image.mutex.Lock()
result.setRaw(tag, value) result.setAll(image.properties)
} image.mutex.Unlock()
return result return result
} }
@ -221,7 +221,7 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
shapeText = `ellipse ` shapeText = `ellipse `
} }
if value, ok := gradient.properties[RadialGradientRadius]; ok { if value := gradient.getRaw(RadialGradientRadius); value != nil {
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if text, ok := session.resolveConstants(value); ok { if text, ok := session.resolveConstants(value); ok {

View File

@ -393,6 +393,9 @@ func (border *borderProperty) writeString(buffer *strings.Builder, indent string
} }
} }
border.mutex.Lock()
defer border.mutex.Unlock()
for _, tag := range []PropertyName{Style, Width, ColorTag} { for _, tag := range []PropertyName{Style, Width, ColorTag} {
if value, ok := border.properties[tag]; ok { if value, ok := border.properties[tag]; ok {
write(tag, value) write(tag, value)
@ -722,7 +725,7 @@ func (border *borderProperty) deleteTag(tag PropertyName) bool {
case Left, Right, Top, Bottom: case Left, Right, Top, Bottom:
if border.Get(Style) != nil { if border.Get(Style) != nil {
border.properties[tag+"-"+Style] = 0 border.setRaw(tag+"-"+Style, 0)
result = true result = true
removeTags([]PropertyName{tag + "-" + ColorTag, tag + "-" + Width}) removeTags([]PropertyName{tag + "-" + ColorTag, tag + "-" + Width})
} else { } else {
@ -732,7 +735,7 @@ func (border *borderProperty) deleteTag(tag PropertyName) bool {
case LeftStyle, RightStyle, TopStyle, BottomStyle: case LeftStyle, RightStyle, TopStyle, BottomStyle:
if border.getRaw(tag) != nil { if border.getRaw(tag) != nil {
if border.Get(Style) != nil { if border.Get(Style) != nil {
border.properties[tag] = 0 border.setRaw(tag, 0)
result = true result = true
} else { } else {
removeTags([]PropertyName{tag}) removeTags([]PropertyName{tag})
@ -742,7 +745,7 @@ func (border *borderProperty) deleteTag(tag PropertyName) bool {
case LeftWidth, RightWidth, TopWidth, BottomWidth: case LeftWidth, RightWidth, TopWidth, BottomWidth:
if border.getRaw(tag) != nil { if border.getRaw(tag) != nil {
if border.Get(Width) != nil { if border.Get(Width) != nil {
border.properties[tag] = AutoSize() border.setRaw(tag, AutoSize())
result = true result = true
} else { } else {
removeTags([]PropertyName{tag}) removeTags([]PropertyName{tag})
@ -752,7 +755,7 @@ func (border *borderProperty) deleteTag(tag PropertyName) bool {
case LeftColor, RightColor, TopColor, BottomColor: case LeftColor, RightColor, TopColor, BottomColor:
if border.getRaw(tag) != nil { if border.getRaw(tag) != nil {
if border.Get(ColorTag) != nil { if border.Get(ColorTag) != nil {
border.properties[tag] = 0 border.setRaw(tag, 0)
result = true result = true
} else { } else {
removeTags([]PropertyName{tag}) removeTags([]PropertyName{tag})

View File

@ -243,7 +243,7 @@ func (clip *insetClipData) writeString(buffer *strings.Builder, indent string) {
buffer.WriteString("inset { ") buffer.WriteString("inset { ")
comma := false comma := false
for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius} { for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius} {
if value, ok := clip.properties[tag]; ok { if value := clip.getRaw(tag); value != nil {
text := propertyValueToString(tag, value, indent) text := propertyValueToString(tag, value, indent)
if text != "" { if text != "" {
if comma { if comma {
@ -319,7 +319,7 @@ func (clip *circleClipData) writeString(buffer *strings.Builder, indent string)
buffer.WriteString("circle { ") buffer.WriteString("circle { ")
comma := false comma := false
for _, tag := range []PropertyName{Radius, X, Y} { for _, tag := range []PropertyName{Radius, X, Y} {
if value, ok := clip.properties[tag]; ok { if value := clip.getRaw(tag); value != nil {
text := propertyValueToString(tag, value, indent) text := propertyValueToString(tag, value, indent)
if text != "" { if text != "" {
if comma { if comma {
@ -399,7 +399,7 @@ func (clip *ellipseClipData) writeString(buffer *strings.Builder, indent string)
buffer.WriteString("ellipse { ") buffer.WriteString("ellipse { ")
comma := false comma := false
for _, tag := range []PropertyName{RadiusX, RadiusY, X, Y} { for _, tag := range []PropertyName{RadiusX, RadiusY, X, Y} {
if value, ok := clip.properties[tag]; ok { if value := clip.getRaw(tag); value != nil {
text := propertyValueToString(tag, value, indent) text := propertyValueToString(tag, value, indent)
if text != "" { if text != "" {
if comma { if comma {

View File

@ -165,7 +165,7 @@ func (picker *colorPickerData) handleCommand(self View, command PropertyName, da
if text, ok := data.PropertyValue("text"); ok { if text, ok := data.PropertyValue("text"); ok {
if color, ok := StringToColor(text); ok { if color, ok := StringToColor(text); ok {
oldColor := GetColorPickerValue(picker) oldColor := GetColorPickerValue(picker)
picker.properties[ColorPickerValue] = color picker.setRaw(ColorPickerValue, color)
if color != oldColor { if color != oldColor {
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)

View File

@ -75,11 +75,8 @@ func (customView *CustomViewData) setRaw(tag PropertyName, value any) {
customView.superView.setRaw(tag, value) customView.superView.setRaw(tag, value)
} }
func (customView *CustomViewData) setContent(value any) bool { func (customView *CustomViewData) setAll(props map[PropertyName]any) {
if container, ok := customView.superView.(ViewsContainer); ok { customView.superView.setAll(props)
return container.setContent(value)
}
return false
} }
// Set sets the value (second argument) of the property with name defined by the first argument. // Set sets the value (second argument) of the property with name defined by the first argument.

View File

@ -354,7 +354,7 @@ func (picker *datePickerData) handleCommand(self View, command PropertyName, dat
if text, ok := data.PropertyValue("text"); ok { if text, ok := data.PropertyValue("text"); ok {
if value, err := time.Parse(dateFormat, text); err == nil { if value, err := time.Parse(dateFormat, text); err == nil {
oldValue := GetDatePickerValue(picker) oldValue := GetDatePickerValue(picker)
picker.properties[DatePickerValue] = value picker.setRaw(DatePickerValue, value)
if value != oldValue { if value != oldValue {
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)

View File

@ -171,7 +171,7 @@ func (detailsView *detailsViewData) htmlSubviews(self View, buffer *strings.Buil
summary := false summary := false
hidden := IsSummaryMarkerHidden(detailsView) hidden := IsSummaryMarkerHidden(detailsView)
if value, ok := detailsView.properties[Summary]; ok { if value := detailsView.getRaw(Summary); value != nil {
switch value := value.(type) { switch value := value.(type) {
case string: case string:
@ -217,7 +217,7 @@ func (detailsView *detailsViewData) htmlSubviews(self View, buffer *strings.Buil
func (detailsView *detailsViewData) handleCommand(self View, command PropertyName, data DataObject) bool { func (detailsView *detailsViewData) handleCommand(self View, command PropertyName, data DataObject) bool {
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.setRaw(Expanded, n != 0)
detailsView.runChangeListener(Expanded) detailsView.runChangeListener(Expanded)
} }
return true return true

View File

@ -255,7 +255,7 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat
items := GetDropDownItems(list) items := GetDropDownItems(list)
if GetCurrent(list) != number && number >= 0 && number < len(items) { if GetCurrent(list) != number && number >= 0 && number < len(items) {
old := GetCurrent(list) old := GetCurrent(list)
list.properties[Current] = number list.setRaw(Current, number)
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)
} }

View File

@ -268,7 +268,7 @@ func (edit *editViewData) AppendText(text string) {
if textValue, ok := value.(string); ok { if textValue, ok := value.(string); ok {
oldText := textValue oldText := textValue
textValue += text textValue += text
edit.properties[Text] = textValue edit.setRaw(Text, textValue)
edit.session.callFunc("appendToInnerHTML", edit.htmlID(), text) edit.session.callFunc("appendToInnerHTML", edit.htmlID(), text)
edit.session.callFunc("appendToInputValue", edit.htmlID(), text) edit.session.callFunc("appendToInputValue", edit.htmlID(), text)
edit.textChanged(textValue, oldText) edit.textChanged(textValue, oldText)

View File

@ -189,7 +189,7 @@ func newFilterProperty(obj DataObject) FilterProperty {
} }
} }
if len(filter.properties) > 0 { if !filter.IsEmpty() {
return filter return filter
} }
ErrorLog("Empty view filter") ErrorLog("Empty view filter")

View File

@ -986,7 +986,7 @@ func (listView *listViewData) handleCommand(self View, command PropertyName, dat
} }
case "itemUnselected": case "itemUnselected":
if _, ok := listView.properties[Current]; ok { if listView.getRaw(Current) != nil {
listView.handleCurrent(-1) listView.handleCurrent(-1)
} }
@ -1003,7 +1003,7 @@ func (listView *listViewData) handleCommand(self View, command PropertyName, dat
} }
func (listView *listViewData) handleCurrent(number int) { func (listView *listViewData) handleCurrent(number int) {
listView.properties[Current] = number listView.setRaw(Current, number)
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)
} }

View File

@ -289,7 +289,7 @@ func (picker *numberPickerData) handleCommand(self View, command PropertyName, d
if text, ok := data.PropertyValue("text"); ok { if text, ok := data.PropertyValue("text"); ok {
if value, err := strconv.ParseFloat(text, 32); err == nil { if value, err := strconv.ParseFloat(text, 32); err == nil {
oldValue := GetNumberPickerValue(picker) oldValue := GetNumberPickerValue(picker)
picker.properties[NumberPickerValue] = text picker.setRaw(NumberPickerValue, text)
if value != oldValue { if value != oldValue {
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)

View File

@ -1428,11 +1428,13 @@ func (popup *popupData) createLayerView() GridLayout {
CellHorizontalAlign, CellHorizontalAlign,
} }
popup.mutex.Lock()
for tag, value := range popup.properties { for tag, value := range popup.properties {
if !slices.Contains(popupProperties, tag) { if !slices.Contains(popupProperties, tag) {
params[tag] = value params[tag] = value
} }
} }
popup.mutex.Unlock()
views := make([]View, 0, 3) views := make([]View, 0, 3)
if title := popup.createTitleView(); title != nil { if title := popup.createTitleView(); title != nil {
@ -1507,9 +1509,9 @@ func NewPopup(view View, param Params) Popup {
} }
popup := new(popupData) popup := new(popupData)
popup.init()
popup.session = view.Session() popup.session = view.Session()
popup.contentView = view popup.contentView = view
popup.properties = map[PropertyName]any{}
popup.hotkeys = map[string]func(Popup){} popup.hotkeys = map[string]func(Popup){}
for tag, value := range popup.session.PopupDefaultsSeq() { for tag, value := range popup.session.PopupDefaultsSeq() {
@ -1547,8 +1549,8 @@ func CreatePopupFromObject(session Session, object DataObject, binding any) Popu
} }
popup := new(popupData) popup := new(popupData)
popup.init()
popup.session = session popup.session = session
popup.properties = map[PropertyName]any{}
popup.hotkeys = map[string]func(Popup){} popup.hotkeys = map[string]func(Popup){}
for key, value := range object.ToParams() { for key, value := range object.ToParams() {

View File

@ -2,6 +2,7 @@ package rui
import ( import (
"iter" "iter"
"maps"
"slices" "slices"
"strings" "strings"
"sync" "sync"
@ -19,6 +20,7 @@ type Properties interface {
// a description of the error is written to the log // a description of the error is written to the log
Set(tag PropertyName, value any) bool Set(tag PropertyName, value any) bool
setRaw(tag PropertyName, value any) setRaw(tag PropertyName, value any)
setAll(properties map[PropertyName]any)
// Remove removes the property with name defined by the argument // Remove removes the property with name defined by the argument
Remove(tag PropertyName) Remove(tag PropertyName)
@ -56,9 +58,6 @@ func defaultNormalize(tag PropertyName) PropertyName {
func (properties *propertyList) init() { func (properties *propertyList) init() {
properties.properties = map[PropertyName]any{} properties.properties = map[PropertyName]any{}
properties.normalize = defaultNormalize properties.normalize = defaultNormalize
//properties.getFunc = properties.getRaw
//properties.set = propertiesSet
//properties.remove = propertiesRemove
} }
func (properties *propertyList) IsEmpty() bool { func (properties *propertyList) IsEmpty() bool {
@ -87,6 +86,12 @@ func (properties *propertyList) setRaw(tag PropertyName, value any) {
properties.mutex.Unlock() properties.mutex.Unlock()
} }
func (properties *propertyList) setAll(props map[PropertyName]any) {
properties.mutex.Lock()
maps.Copy(properties.properties, props)
properties.mutex.Unlock()
}
/* /*
func (properties *propertyList) Remove(tag PropertyName) { func (properties *propertyList) Remove(tag PropertyName) {
properties.remove(properties, properties.normalize(tag)) properties.remove(properties, properties.normalize(tag))
@ -100,6 +105,8 @@ func (properties *propertyList) Clear() {
} }
func (properties *propertyList) All() iter.Seq2[PropertyName, any] { func (properties *propertyList) All() iter.Seq2[PropertyName, any] {
properties.mutex.Lock()
defer properties.mutex.Unlock()
return func(yield func(PropertyName, any) bool) { return func(yield func(PropertyName, any) bool) {
for tag, value := range properties.properties { for tag, value := range properties.properties {
if !yield(tag, value) { if !yield(tag, value) {
@ -204,6 +211,9 @@ func (data *dataProperty) Remove(tag PropertyName) {
} }
func (data *dataProperty) writeToBuffer(buffer *strings.Builder, indent string, objectName string, tags []PropertyName) { func (data *dataProperty) writeToBuffer(buffer *strings.Builder, indent string, objectName string, tags []PropertyName) {
data.mutex.Lock()
defer data.mutex.Unlock()
buffer.WriteString(objectName) buffer.WriteString(objectName)
buffer.WriteString("{ ") buffer.WriteString("{ ")
comma := false comma := false

View File

@ -1201,7 +1201,7 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
} }
} }
if len(view.properties) > 0 { if !view.IsEmpty() {
view.cssStyle(view, &cssBuilder) view.cssStyle(view, &cssBuilder)
} }

View File

@ -329,7 +329,7 @@ func (picker *timePickerData) handleCommand(self View, command PropertyName, dat
if text, ok := data.PropertyValue("text"); ok { if text, ok := data.PropertyValue("text"); ok {
if value, ok := stringToTime(text); ok { if value, ok := stringToTime(text); ok {
oldValue := GetTimePickerValue(picker) oldValue := GetTimePickerValue(picker)
picker.properties[TimePickerValue] = value picker.setRaw(TimePickerValue, value)
if value != oldValue { if value != oldValue {
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)