From 61ee6c03f2feca3faeacef6e783d9a520332b019 Mon Sep 17 00:00:00 2001 From: Alexei Anoshenko Date: Sun, 1 May 2022 13:27:04 +0300 Subject: [PATCH] Fixed background radial gradient --- angleUnit.go | 33 +++++------ backgroundGradient.go | 133 ++++++++++++++++++++++++++++++++++++++---- color.go | 36 +++++++----- gridLayout.go | 10 ++-- propertySet.go | 4 +- sessionTheme.go | 6 +- sizeUnit.go | 21 ++++--- 7 files changed, 181 insertions(+), 62 deletions(-) diff --git a/angleUnit.go b/angleUnit.go index c2de20a..7be546c 100644 --- a/angleUnit.go +++ b/angleUnit.go @@ -67,31 +67,27 @@ func angleUnitSuffixes() map[AngleUnitType]string { // StringToAngleUnit converts the string argument to AngleUnit func StringToAngleUnit(value string) (AngleUnit, bool) { - var angle AngleUnit - ok, err := angle.setValue(value) - if !ok { - ErrorLog(err) + angle, err := stringToAngleUnit(value) + if err != nil { + ErrorLog(err.Error()) + return angle, false } - return angle, ok + return angle, true } -func (angle *AngleUnit) setValue(value string) (bool, string) { +func stringToAngleUnit(value string) (AngleUnit, error) { value = strings.ToLower(strings.Trim(value, " \t\n\r")) - setValue := func(suffix string, unitType AngleUnitType) (bool, string) { + setValue := func(suffix string, unitType AngleUnitType) (AngleUnit, error) { val, err := strconv.ParseFloat(value[:len(value)-len(suffix)], 64) if err != nil { - return false, `AngleUnit.SetValue("` + value + `") error: ` + err.Error() + return AngleUnit{}, err } - angle.Value = val - angle.Type = unitType - return true, "" + return AngleUnit{Value: val, Type: unitType}, nil } if value == "π" { - angle.Value = 1 - angle.Type = PiRadian - return true, "" + return AngleUnit{Value: 1, Type: PiRadian}, nil } if strings.HasSuffix(value, "π") { @@ -108,13 +104,12 @@ func (angle *AngleUnit) setValue(value string) (bool, string) { } } - if val, err := strconv.ParseFloat(value, 64); err == nil { - angle.Value = val - angle.Type = Radian - return true, "" + val, err := strconv.ParseFloat(value, 64) + if err != nil { + return AngleUnit{}, err } - return false, `AngleUnit.SetValue("` + value + `") error: invalid argument` + return AngleUnit{Value: val, Type: Radian}, nil } // String - convert AngleUnit to string diff --git a/backgroundGradient.go b/backgroundGradient.go index 00afeff..08a8328 100644 --- a/backgroundGradient.go +++ b/backgroundGradient.go @@ -161,7 +161,8 @@ func (gradient *backgroundGradient) Set(tag string, value interface{}) bool { return false } - return gradient.backgroundElement.Set(tag, value) + ErrorLogF("Property %s is not supported by a background gradient", tag) + return false } func (point *BackgroundGradientPoint) setValue(text string) bool { @@ -303,8 +304,10 @@ func (gradient *backgroundLinearGradient) Set(tag string, value interface{}) boo return true case string: - var angle AngleUnit - if ok, _ := angle.setValue(value); ok { + if gradient.setSimpleProperty(tag, value) { + return true + } + if angle, ok := StringToAngleUnit(value); ok { gradient.properties[Direction] = angle return true } @@ -404,8 +407,60 @@ func (gradient *backgroundRadialGradient) Set(tag string, value interface{}) boo switch tag { case RadialGradientRadius: switch value := value.(type) { - case string, SizeUnit: - return gradient.propertyList.Set(RadialGradientRadius, value) + case []SizeUnit: + switch len(value) { + case 0: + delete(gradient.properties, RadialGradientRadius) + return true + + case 1: + if value[0].Type == Auto { + delete(gradient.properties, RadialGradientRadius) + } else { + gradient.properties[RadialGradientRadius] = value[0] + } + return true + + default: + gradient.properties[RadialGradientRadius] = value + return true + } + + case []interface{}: + switch len(value) { + case 0: + delete(gradient.properties, RadialGradientRadius) + return true + + case 1: + return gradient.Set(RadialGradientRadius, value[0]) + + default: + gradient.properties[RadialGradientRadius] = value + return true + } + + case string: + if gradient.setSimpleProperty(RadialGradientRadius, value) { + return true + } + if size, err := stringToSizeUnit(value); err == nil { + if size.Type == Auto { + delete(gradient.properties, RadialGradientRadius) + } else { + gradient.properties[RadialGradientRadius] = size + } + return true + } + return gradient.setEnumProperty(RadialGradientRadius, value, enumProperties[RadialGradientRadius].values) + + case SizeUnit: + if value.Type == Auto { + delete(gradient.properties, RadialGradientRadius) + } else { + gradient.properties[RadialGradientRadius] = value + } + return true case int: n := value @@ -415,10 +470,7 @@ func (gradient *backgroundRadialGradient) Set(tag string, value interface{}) boo } ErrorLogF(`Invalid value of "%s" property: %v`, tag, value) - case RadialGradientShape: - return gradient.propertyList.Set(RadialGradientShape, value) - - case CenterX, CenterY: + case RadialGradientShape, CenterX, CenterY: return gradient.propertyList.Set(tag, value) } @@ -439,10 +491,11 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string { buffer.WriteString(`radial-gradient(`) } + var shapeText string if shape, ok := enumProperty(gradient, RadialGradientShape, session, EllipseGradient); ok && shape == CircleGradient { - buffer.WriteString(`circle `) + shapeText = `circle ` } else { - buffer.WriteString(`ellipse `) + shapeText = `ellipse ` } if value, ok := gradient.properties[RadialGradientRadius]; ok { @@ -451,10 +504,16 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string { if text, ok := session.resolveConstants(value); ok { values := enumProperties[RadialGradientRadius] if n, ok := enumStringToInt(text, values.values, false); ok { + buffer.WriteString(shapeText) + shapeText = "" buffer.WriteString(values.cssValues[n]) buffer.WriteString(" ") } else { if r, ok := StringToSizeUnit(text); ok && r.Type != Auto { + buffer.WriteString("ellipse ") + shapeText = "" + buffer.WriteString(r.cssString("")) + buffer.WriteString(" ") buffer.WriteString(r.cssString("")) buffer.WriteString(" ") } else { @@ -468,6 +527,8 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string { case int: values := enumProperties[RadialGradientRadius].cssValues if value >= 0 && value < len(values) { + buffer.WriteString(shapeText) + shapeText = "" buffer.WriteString(values[value]) buffer.WriteString(" ") } else { @@ -476,8 +537,55 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string { case SizeUnit: if value.Type != Auto { + buffer.WriteString("ellipse ") + shapeText = "" buffer.WriteString(value.cssString("")) buffer.WriteString(" ") + buffer.WriteString(value.cssString("")) + buffer.WriteString(" ") + } + + case []SizeUnit: + count := len(value) + if count > 2 { + count = 2 + } + buffer.WriteString("ellipse ") + shapeText = "" + for i := 0; i < count; i++ { + buffer.WriteString(value[i].cssString("50%")) + buffer.WriteString(" ") + } + + case []interface{}: + count := len(value) + if count > 2 { + count = 2 + } + buffer.WriteString("ellipse ") + shapeText = "" + for i := 0; i < count; i++ { + if value[i] != nil { + switch value := value[i].(type) { + case SizeUnit: + buffer.WriteString(value.cssString("50%")) + buffer.WriteString(" ") + + case string: + if text, ok := session.resolveConstants(value); ok { + if size, err := stringToSizeUnit(text); err == nil { + buffer.WriteString(size.cssString("50%")) + buffer.WriteString(" ") + } else { + buffer.WriteString("50% ") + } + } else { + buffer.WriteString("50% ") + } + } + } else { + buffer.WriteString("50% ") + } } } } @@ -485,6 +593,9 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string { x, _ := sizeProperty(gradient, CenterX, session) y, _ := sizeProperty(gradient, CenterX, session) if x.Type != Auto || y.Type != Auto { + if shapeText != "" { + buffer.WriteString(shapeText) + } buffer.WriteString("at ") buffer.WriteString(x.cssString("50%")) buffer.WriteString(" ") diff --git a/color.go b/color.go index adea3a8..5ce76cc 100644 --- a/color.go +++ b/color.go @@ -2,6 +2,7 @@ package rui import ( "bytes" + "errors" "fmt" "strconv" "strings" @@ -71,43 +72,49 @@ func (color Color) cssString() string { // StringToColor converts the string argument to Color value func StringToColor(text string) (Color, bool) { + color, err := stringToColor(text) + if err != nil { + ErrorLog(err.Error()) + return color, false + } + return color, true +} + +func stringToColor(text string) (Color, error) { text = strings.Trim(text, " \t\r\n") if text == "" { - ErrorLog(`Invalid color value: ""`) - return 0, false + return 0, errors.New(`Invalid color value: ""`) } if text[0] == '#' { c, err := strconv.ParseUint(text[1:], 16, 32) if err != nil { - ErrorLog("Set color value error: " + err.Error()) - return 0, false + return 0, errors.New("Set color value error: " + err.Error()) } switch len(text) - 1 { case 8: - return Color(c), true + return Color(c), nil case 6: - return Color(c | 0xFF000000), true + return Color(c | 0xFF000000), nil case 4: a := (c >> 12) & 0xF r := (c >> 8) & 0xF g := (c >> 4) & 0xF b := c & 0xF - return Color((a << 28) | (a << 24) | (r << 20) | (r << 16) | (g << 12) | (g << 8) | (b << 4) | b), true + return Color((a << 28) | (a << 24) | (r << 20) | (r << 16) | (g << 12) | (g << 8) | (b << 4) | b), nil case 3: r := (c >> 8) & 0xF g := (c >> 4) & 0xF b := c & 0xF - return Color(0xFF000000 | (r << 20) | (r << 16) | (g << 12) | (g << 8) | (b << 4) | b), true + return Color(0xFF000000 | (r << 20) | (r << 16) | (g << 12) | (g << 8) | (b << 4) | b), nil } - ErrorLog(`Invalid color format: "` + text + `". Valid formats: #AARRGGBB, #RRGGBB, #ARGB, #RGB`) - return 0, false + return 0, errors.New(`Invalid color format: "` + text + `". Valid formats: #AARRGGBB, #RRGGBB, #ARGB, #RGB`) } parseRGB := func(args string) []int { @@ -155,23 +162,22 @@ func StringToColor(text string) (Color, bool) { if strings.HasPrefix(text, "rgba") { args := parseRGB(text[4:]) if len(args) == 4 { - return Color((args[3] << 24) | (args[0] << 16) | (args[1] << 8) | args[2]), true + return Color((args[3] << 24) | (args[0] << 16) | (args[1] << 8) | args[2]), nil } } if strings.HasPrefix(text, "rgb") { args := parseRGB(text[3:]) if len(args) == 3 { - return Color(0xFF000000 | (args[0] << 16) | (args[1] << 8) | args[2]), true + return Color(0xFF000000 | (args[0] << 16) | (args[1] << 8) | args[2]), nil } } // TODO hsl(360,100%,50%), hsla(360,100%,50%,.5) if color, ok := colorConstants[text]; ok { - return color, true + return color, nil } - ErrorLog(`Invalid color format: "` + text + `"`) - return 0, false + return 0, errors.New(`Invalid color format: "` + text + `"`) } diff --git a/gridLayout.go b/gridLayout.go index c26ebbe..9dbfdbf 100644 --- a/gridLayout.go +++ b/gridLayout.go @@ -42,7 +42,7 @@ func (style *viewStyle) setGridCellSize(tag string, value interface{}) bool { val = strings.Trim(val, " \t\n\r") if isConstantName(val) { sizes[i] = val - } else if size, ok := StringToSizeUnit(val); ok { + } else if size, err := stringToSizeUnit(val); err == nil { sizes[i] = size } else { invalidPropertyValue(tag, value) @@ -52,7 +52,7 @@ func (style *viewStyle) setGridCellSize(tag string, value interface{}) bool { style.properties[tag] = sizes } else if isConstantName(values[0]) { style.properties[tag] = values[0] - } else if size, ok := StringToSizeUnit(values[0]); ok { + } else if size, err := stringToSizeUnit(values[0]); err == nil { style.properties[tag] = size } else { invalidPropertyValue(tag, value) @@ -110,7 +110,7 @@ func (style *viewStyle) setGridCellSize(tag string, value interface{}) bool { case string: if isConstantName(val) { sizes[i] = val - } else if size, ok := StringToSizeUnit(val); ok { + } else if size, err := stringToSizeUnit(val); err == nil { sizes[i] = size } else { invalidPropertyValue(tag, value) @@ -291,7 +291,7 @@ func gridCellSizes(properties Properties, tag string, session Session) []SizeUni case string: if text, ok := session.resolveConstants(val); ok { - result[i], _ = StringToSizeUnit(text) + result[i], _ = stringToSizeUnit(text) } } } @@ -302,7 +302,7 @@ func gridCellSizes(properties Properties, tag string, session Session) []SizeUni values := strings.Split(text, ",") result := make([]SizeUnit, len(values)) for i, val := range values { - result[i], _ = StringToSizeUnit(val) + result[i], _ = stringToSizeUnit(val) } return result } diff --git a/propertySet.go b/propertySet.go index ef98002..dd4d0cf 100644 --- a/propertySet.go +++ b/propertySet.go @@ -586,8 +586,8 @@ func (properties *propertyList) setColorProperty(tag string, value interface{}) var result Color switch value := value.(type) { case string: - var ok bool - if result, ok = StringToColor(value); !ok { + var err error + if result, err = stringToColor(value); err != nil { invalidPropertyValue(tag, value) return false } diff --git a/sessionTheme.go b/sessionTheme.go index 8279021..91d67d5 100644 --- a/sessionTheme.go +++ b/sessionTheme.go @@ -166,9 +166,9 @@ func (session *sessionData) Color(tag string) (Color, bool) { } if len(result) == 0 || result[0] != '@' { - color, ok := StringToColor(result) - if !ok { - ErrorLogF(`invalid value "%v" of "%v" color constant`, result, tag) + color, err := stringToColor(result) + if err != nil { + ErrorLogF(`invalid value "%v" of "%v" color constant (%s)`, result, tag, err.Error()) return 0, false } return color, true diff --git a/sizeUnit.go b/sizeUnit.go index 159201e..07b7973 100644 --- a/sizeUnit.go +++ b/sizeUnit.go @@ -1,6 +1,7 @@ package rui import ( + "errors" "fmt" "strconv" "strings" @@ -120,15 +121,23 @@ func sizeUnitSuffixes() map[SizeUnitType]string { // StringToSizeUnit converts the string argument to SizeUnit func StringToSizeUnit(value string) (SizeUnit, bool) { + size, err := stringToSizeUnit(value) + if err != nil { + ErrorLog(err.Error()) + return size, false + } + return size, true +} +func stringToSizeUnit(value string) (SizeUnit, error) { value = strings.Trim(value, " \t\n\r") switch value { case "auto", "none", "": - return SizeUnit{Type: Auto, Value: 0}, true + return SizeUnit{Type: Auto, Value: 0}, nil case "0": - return SizeUnit{Type: SizeInPixel, Value: 0}, true + return SizeUnit{Type: SizeInPixel, Value: 0}, nil } suffixes := sizeUnitSuffixes() @@ -137,15 +146,13 @@ func StringToSizeUnit(value string) (SizeUnit, bool) { var err error var val float64 if val, err = strconv.ParseFloat(value[:len(value)-len(suffix)], 64); err != nil { - ErrorLog(err.Error()) - return SizeUnit{Type: Auto, Value: 0}, false + return SizeUnit{Type: Auto, Value: 0}, err } - return SizeUnit{Type: unitType, Value: val}, true + return SizeUnit{Type: unitType, Value: val}, nil } } - ErrorLog(`Invalid SizeUnit value: "` + value + `"`) - return SizeUnit{Type: Auto, Value: 0}, false + return SizeUnit{Type: Auto, Value: 0}, errors.New(`Invalid SizeUnit value: "` + value + `"`) } // String - convert SizeUnit to string