Fixed background radial gradient

This commit is contained in:
Alexei Anoshenko 2022-05-01 13:27:04 +03:00
parent 26abd1f632
commit 61ee6c03f2
7 changed files with 181 additions and 62 deletions

View File

@ -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

View File

@ -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(" ")

View File

@ -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 + `"`)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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