mirror of https://github.com/anoshenko/rui.git
1128 lines
35 KiB
Go
1128 lines
35 KiB
Go
package rui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Constants for [RadiusProperty] specific properties
|
|
const (
|
|
// Radius is the constant for "radius" property tag.
|
|
//
|
|
// Used by `View`, `BackgroundElement`, `ClipShape`.
|
|
//
|
|
// Usage in `View`:
|
|
// Specifies the corners rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `RadiusProperty`, `SizeUnit`, `SizeFunc`, `BoxRadius`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is either `RadiusProperty` or `SizeUnit`, other types converted to them during assignment.
|
|
// See `RadiusProperty`, `SizeUnit`, `SizeFunc` and `BoxRadius` description for more details.
|
|
//
|
|
// Conversion rules:
|
|
// `RadiusProperty` - stored as is, no conversion performed.
|
|
// `SizeUnit` - stored as is and set all corners to have the same value.
|
|
// `BoxRadius` - a new `RadiusProperty` will be created and all corresponding elliptical radius values will be set.
|
|
// `string` - if one value will be provided then it will be set as a radius for all corners. If two values will be provided divided by (`/`) then x and y radius will be set for all corners. Examples: "1em", "1em/0.5em", "2/4". Values which doesn't have size prefix will use size in pixels by default.
|
|
// `float` - values of this type will set radius for all corners in pixels.
|
|
// `int` - values of this type will set radius for all corners in pixels.
|
|
//
|
|
// Usage in `BackgroundElement`:
|
|
// Same as "radial-gradient-radius".
|
|
//
|
|
// Usage in `ClipShape`:
|
|
// Specifies the radius of the corners or the radius of the cropping area.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
Radius PropertyName = "radius"
|
|
|
|
// RadiusX is the constant for "radius-x" property tag.
|
|
//
|
|
// Used by `View`, `ClipShape`.
|
|
//
|
|
// Usage in `View`:
|
|
// Specifies the x-axis corners elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
//
|
|
// Usage in `ClipShape`:
|
|
// Specifies the x-axis corners elliptic rounding radius of the elliptic clip shape.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusX PropertyName = "radius-x"
|
|
|
|
// RadiusY is the constant for "radius-y" property tag.
|
|
//
|
|
// Used by `View`, `ClipShape`.
|
|
//
|
|
// Usage in `View`:
|
|
// Specifies the y-axis corners elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
//
|
|
// Usage in `ClipShape`:
|
|
// Specifies the y-axis corners elliptic rounding radius of of the elliptic clip shape.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusY PropertyName = "radius-y"
|
|
|
|
// RadiusTopLeft is the constant for "radius-top-left" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the top-left corner rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusTopLeft PropertyName = "radius-top-left"
|
|
|
|
// RadiusTopLeftX is the constant for "radius-top-left-x" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the x-axis top-left corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusTopLeftX PropertyName = "radius-top-left-x"
|
|
|
|
// RadiusTopLeftY is the constant for "radius-top-left-y" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the y-axis top-left corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusTopLeftY PropertyName = "radius-top-left-y"
|
|
|
|
// RadiusTopRight is the constant for "radius-top-right" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the top-right corner rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusTopRight PropertyName = "radius-top-right"
|
|
|
|
// RadiusTopRightX is the constant for "radius-top-right-x" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the x-axis top-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusTopRightX PropertyName = "radius-top-right-x"
|
|
|
|
// RadiusTopRightY is the constant for "radius-top-right-y" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the y-axis top-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusTopRightY PropertyName = "radius-top-right-y"
|
|
|
|
// RadiusBottomLeft is the constant for "radius-bottom-left" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the bottom-left corner rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusBottomLeft PropertyName = "radius-bottom-left"
|
|
|
|
// RadiusBottomLeftX is the constant for "radius-bottom-left-x" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the x-axis bottom-left corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusBottomLeftX PropertyName = "radius-bottom-left-x"
|
|
|
|
// RadiusBottomLeftY is the constant for "radius-bottom-left-y" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the y-axis bottom-left corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusBottomLeftY PropertyName = "radius-bottom-left-y"
|
|
|
|
// RadiusBottomRight is the constant for "radius-bottom-right" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the bottom-right corner rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusBottomRight PropertyName = "radius-bottom-right"
|
|
|
|
// RadiusBottomRightX is the constant for "radius-bottom-right-x" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the x-axis bottom-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusBottomRightX PropertyName = "radius-bottom-right-x"
|
|
|
|
// RadiusBottomRightY is the constant for "radius-bottom-right-y" property tag.
|
|
//
|
|
// Used by `View`.
|
|
// Specifies the y-axis bottom-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
RadiusBottomRightY PropertyName = "radius-bottom-right-y"
|
|
|
|
// X is the constant for "x" property tag.
|
|
//
|
|
// Used by `ClipShape`, `RadiusProperty`.
|
|
//
|
|
// Usage in `ClipShape`:
|
|
// Specifies x-axis position of the clip shape.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
//
|
|
// Usage in `RadiusProperty`:
|
|
// Determines the x-axis top-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
X PropertyName = "x"
|
|
|
|
// Y is the constant for "y" property tag.
|
|
//
|
|
// Used by `ClipShape`, `RadiusProperty`.
|
|
//
|
|
// Usage in `ClipShape`:
|
|
// Specifies y-axis position of the clip shape.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
//
|
|
// Usage in `RadiusProperty`:
|
|
// Determines the y-axis top-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
Y PropertyName = "y"
|
|
|
|
// TopLeft is the constant for "top-left" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the top-left corner rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
TopLeft PropertyName = "top-left"
|
|
|
|
// TopLeftX is the constant for "top-left-x" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the x-axis top-left corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
TopLeftX PropertyName = "top-left-x"
|
|
|
|
// TopLeftY is the constant for "top-left-y" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the y-axis top-left corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
TopLeftY PropertyName = "top-left-y"
|
|
|
|
// TopRight is the constant for "top-right" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the top-right corner rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
TopRight PropertyName = "top-right"
|
|
|
|
// TopRightX is the constant for "top-right-x" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the x-axis top-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
TopRightX PropertyName = "top-right-x"
|
|
|
|
// TopRightY is the constant for "top-right-y" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the y-axis top-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
TopRightY PropertyName = "top-right-y"
|
|
|
|
// BottomLeft is the constant for "bottom-left" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the bottom-left corner rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
BottomLeft PropertyName = "bottom-left"
|
|
|
|
// BottomLeftX is the constant for "bottom-left-x" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the x-axis bottom-left corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
BottomLeftX PropertyName = "bottom-left-x"
|
|
|
|
// BottomLeftY is the constant for "bottom-left-y" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the y-axis bottom-left corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
BottomLeftY PropertyName = "bottom-left-y"
|
|
|
|
// BottomRight is the constant for "bottom-right" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the bottom-right corner rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
BottomRight PropertyName = "bottom-right"
|
|
|
|
// BottomRightX is the constant for "bottom-right-x" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the x-axis bottom-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
BottomRightX PropertyName = "bottom-right-x"
|
|
|
|
// BottomRightY is the constant for "bottom-right-y" property tag.
|
|
//
|
|
// Used by `RadiusProperty`.
|
|
// Determines the y-axis bottom-right corner elliptic rounding radius of an element's outer border edge.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
BottomRightY PropertyName = "bottom-right-y"
|
|
)
|
|
|
|
// RadiusProperty is a description of the [View] (shape) elliptical corner radius.
|
|
type RadiusProperty interface {
|
|
Properties
|
|
stringWriter
|
|
fmt.Stringer
|
|
|
|
// BoxRadius returns x and y radius of the corners of the element
|
|
BoxRadius(session Session) BoxRadius
|
|
}
|
|
|
|
type radiusPropertyData struct {
|
|
dataProperty
|
|
}
|
|
|
|
// NewRadiusProperty creates the new RadiusProperty
|
|
func NewRadiusProperty(params Params) RadiusProperty {
|
|
result := new(radiusPropertyData)
|
|
result.dataProperty.init()
|
|
result.normalize = radiusPropertyNormalize
|
|
result.get = radiusPropertyGet
|
|
result.remove = radiusPropertyRemove
|
|
result.set = radiusPropertySet
|
|
result.supportedProperties = []PropertyName{
|
|
X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
|
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY,
|
|
}
|
|
|
|
if params != nil {
|
|
for _, tag := range result.supportedProperties {
|
|
if value, ok := params[tag]; ok {
|
|
radiusPropertySet(result, tag, value)
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func radiusPropertyNormalize(tag PropertyName) PropertyName {
|
|
name := strings.TrimPrefix(strings.ToLower(string(tag)), "radius-")
|
|
return PropertyName(name)
|
|
}
|
|
|
|
func (radius *radiusPropertyData) writeString(buffer *strings.Builder, indent string) {
|
|
buffer.WriteString("_{ ")
|
|
comma := false
|
|
for _, tag := range radius.supportedProperties {
|
|
if value, ok := radius.properties[tag]; ok {
|
|
if comma {
|
|
buffer.WriteString(", ")
|
|
}
|
|
buffer.WriteString(string(tag))
|
|
buffer.WriteString(" = ")
|
|
writePropertyValue(buffer, tag, value, indent)
|
|
comma = true
|
|
}
|
|
}
|
|
|
|
buffer.WriteString(" }")
|
|
}
|
|
|
|
func (radius *radiusPropertyData) String() string {
|
|
return runStringWriter(radius)
|
|
}
|
|
|
|
func radiusPropertyRemove(properties Properties, tag PropertyName) []PropertyName {
|
|
result := []PropertyName{}
|
|
removeTag := func(tag PropertyName) {
|
|
if properties.getRaw(tag) != nil {
|
|
properties.setRaw(tag, nil)
|
|
result = append(result, tag)
|
|
}
|
|
}
|
|
|
|
switch tag {
|
|
case X, Y:
|
|
if properties.getRaw(tag) == nil {
|
|
for _, prefix := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
|
removeTag(prefix + "-" + tag)
|
|
}
|
|
} else {
|
|
removeTag(tag)
|
|
}
|
|
|
|
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
|
removeTag(tag)
|
|
|
|
case TopLeft, TopRight, BottomLeft, BottomRight:
|
|
for _, tag := range []PropertyName{tag, tag + "-x", tag + "-y"} {
|
|
removeTag(tag)
|
|
}
|
|
|
|
default:
|
|
ErrorLogF(`"%s" property is not compatible with the RadiusProperty`, tag)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func deleteRadiusUnusedTags(radius Properties, result []PropertyName) {
|
|
|
|
for _, tag := range []PropertyName{X, Y} {
|
|
if radius.getRaw(tag) != nil {
|
|
unused := true
|
|
for _, t := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
|
if radius.getRaw(t+"-"+tag) == nil && radius.getRaw(t) == nil {
|
|
unused = false
|
|
break
|
|
}
|
|
}
|
|
if unused {
|
|
radius.setRaw(tag, nil)
|
|
result = append(result, tag)
|
|
}
|
|
}
|
|
}
|
|
|
|
equalValue := func(value1, value2 any) bool {
|
|
switch value1 := value1.(type) {
|
|
case string:
|
|
switch value2 := value2.(type) {
|
|
case string:
|
|
return value1 == value2
|
|
}
|
|
|
|
case SizeUnit:
|
|
switch value2 := value2.(type) {
|
|
case SizeUnit:
|
|
return value1.Equal(value2)
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
for _, tag := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
|
tagX := tag + "-x"
|
|
tagY := tag + "-y"
|
|
valueX := radius.getRaw(tagX)
|
|
valueY := radius.getRaw(tagY)
|
|
|
|
if value := radius.getRaw(tag); value != nil {
|
|
if valueX != nil && valueY != nil {
|
|
radius.setRaw(tag, nil)
|
|
result = append(result, tag)
|
|
} else if valueX != nil && valueY == nil {
|
|
if equalValue(value, valueX) {
|
|
radius.setRaw(tagX, nil)
|
|
result = append(result, tagX)
|
|
} else {
|
|
radius.setRaw(tagY, value)
|
|
result = append(result, tagY)
|
|
radius.setRaw(tag, nil)
|
|
result = append(result, tag)
|
|
}
|
|
} else if valueX == nil && valueY != nil {
|
|
if equalValue(value, valueY) {
|
|
radius.setRaw(tagY, nil)
|
|
result = append(result, tagY)
|
|
} else {
|
|
radius.setRaw(tagX, value)
|
|
result = append(result, tagX)
|
|
radius.setRaw(tag, nil)
|
|
result = append(result, tag)
|
|
}
|
|
}
|
|
} else if valueX != nil && valueY != nil && equalValue(valueX, valueY) {
|
|
radius.setRaw(tag, valueX)
|
|
result = append(result, tag)
|
|
radius.setRaw(tagX, nil)
|
|
result = append(result, tagX)
|
|
radius.setRaw(tagY, nil)
|
|
result = append(result, tagY)
|
|
}
|
|
}
|
|
}
|
|
|
|
func radiusPropertySet(radius Properties, tag PropertyName, value any) []PropertyName {
|
|
var result []PropertyName = nil
|
|
|
|
deleteTags := func(tags []PropertyName) {
|
|
for _, tag := range tags {
|
|
if radius.getRaw(tag) != nil {
|
|
radius.setRaw(tag, nil)
|
|
result = append(result, tag)
|
|
}
|
|
}
|
|
}
|
|
|
|
switch tag {
|
|
case X:
|
|
if result = setSizeProperty(radius, tag, value); result != nil {
|
|
deleteTags([]PropertyName{TopLeftX, TopRightX, BottomLeftX, BottomRightX})
|
|
for _, t := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
|
if val := radius.getRaw(t); val != nil {
|
|
t2 := t + "-y"
|
|
if radius.getRaw(t2) != nil {
|
|
radius.setRaw(t2, val)
|
|
result = append(result, t2)
|
|
}
|
|
radius.setRaw(t, nil)
|
|
result = append(result, t)
|
|
}
|
|
}
|
|
}
|
|
|
|
case Y:
|
|
if result = setSizeProperty(radius, tag, value); result != nil {
|
|
deleteTags([]PropertyName{TopLeftY, TopRightY, BottomLeftY, BottomRightY})
|
|
for _, t := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
|
if val := radius.getRaw(t); val != nil {
|
|
t2 := t + "-x"
|
|
if radius.getRaw(t2) != nil {
|
|
radius.setRaw(t2, val)
|
|
result = append(result, t2)
|
|
}
|
|
radius.setRaw(t, nil)
|
|
result = append(result, t)
|
|
}
|
|
}
|
|
}
|
|
|
|
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
|
if result = setSizeProperty(radius, tag, value); result != nil {
|
|
deleteRadiusUnusedTags(radius, result)
|
|
}
|
|
|
|
case TopLeft, TopRight, BottomLeft, BottomRight:
|
|
switch value := value.(type) {
|
|
case SizeUnit:
|
|
radius.setRaw(tag, value)
|
|
result = []PropertyName{tag}
|
|
deleteTags([]PropertyName{tag + "-x", tag + "-y"})
|
|
deleteRadiusUnusedTags(radius, result)
|
|
|
|
case string:
|
|
if strings.Contains(value, "/") {
|
|
if values := strings.Split(value, "/"); len(values) == 2 {
|
|
if result = radiusPropertySet(radius, tag+"-x", values[0]); result != nil {
|
|
if resultY := radiusPropertySet(radius, tag+"-y", values[1]); resultY != nil {
|
|
result = append(result, resultY...)
|
|
}
|
|
|
|
}
|
|
} else {
|
|
notCompatibleType(tag, value)
|
|
}
|
|
} else {
|
|
if result = setSizeProperty(radius, tag, value); result != nil {
|
|
deleteTags([]PropertyName{tag + "-x", tag + "-y"})
|
|
deleteRadiusUnusedTags(radius, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
default:
|
|
ErrorLogF(`"%s" property is not compatible with the RadiusProperty`, tag)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func radiusPropertyGet(properties Properties, tag PropertyName) any {
|
|
if value := properties.getRaw(tag); value != nil {
|
|
return value
|
|
}
|
|
|
|
switch tag {
|
|
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
|
tagLen := len(tag)
|
|
if value := properties.getRaw(tag[:tagLen-2]); value != nil {
|
|
return value
|
|
}
|
|
if value := properties.getRaw(tag[tagLen-1:]); value != nil {
|
|
return value
|
|
}
|
|
}
|
|
|
|
switch tag {
|
|
case TopLeftX, TopRightX, BottomLeftX, BottomRightX:
|
|
if value := properties.getRaw(X); value != nil {
|
|
return value
|
|
}
|
|
case TopLeftY, TopRightY, BottomLeftY, BottomRightY:
|
|
if value := properties.getRaw(Y); value != nil {
|
|
return value
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (radius *radiusPropertyData) BoxRadius(session Session) BoxRadius {
|
|
x, _ := sizeProperty(radius, X, session)
|
|
y, _ := sizeProperty(radius, Y, session)
|
|
|
|
getRadius := func(tag PropertyName) (SizeUnit, SizeUnit) {
|
|
rx := x
|
|
ry := y
|
|
if r, ok := sizeProperty(radius, tag, session); ok {
|
|
rx = r
|
|
ry = r
|
|
}
|
|
if r, ok := sizeProperty(radius, tag+"-x", session); ok {
|
|
rx = r
|
|
}
|
|
if r, ok := sizeProperty(radius, tag+"-y", session); ok {
|
|
ry = r
|
|
}
|
|
|
|
return rx, ry
|
|
}
|
|
|
|
var result BoxRadius
|
|
|
|
result.TopLeftX, result.TopLeftY = getRadius(TopLeft)
|
|
result.TopRightX, result.TopRightY = getRadius(TopRight)
|
|
result.BottomLeftX, result.BottomLeftY = getRadius(BottomLeft)
|
|
result.BottomRightX, result.BottomRightY = getRadius(BottomRight)
|
|
|
|
return result
|
|
}
|
|
|
|
// BoxRadius defines radii of rounds the corners of an element's outer border edge
|
|
type BoxRadius struct {
|
|
TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY SizeUnit
|
|
}
|
|
|
|
// AllAnglesIsEqual returns 'true' if all angles is equal, 'false' otherwise
|
|
func (radius BoxRadius) AllAnglesIsEqual() bool {
|
|
return radius.TopLeftX.Equal(radius.TopRightX) &&
|
|
radius.TopLeftY.Equal(radius.TopRightY) &&
|
|
radius.TopLeftX.Equal(radius.BottomLeftX) &&
|
|
radius.TopLeftY.Equal(radius.BottomLeftY) &&
|
|
radius.TopLeftX.Equal(radius.BottomRightX) &&
|
|
radius.TopLeftY.Equal(radius.BottomRightY)
|
|
}
|
|
|
|
// String returns a string representation of a BoxRadius struct
|
|
func (radius BoxRadius) String() string {
|
|
|
|
if radius.AllAnglesIsEqual() {
|
|
if radius.TopLeftX.Equal(radius.TopLeftY) {
|
|
return radius.TopLeftX.String()
|
|
} else {
|
|
return fmt.Sprintf("_{ x = %s, y = %s }", radius.TopLeftX.String(), radius.TopLeftY.String())
|
|
}
|
|
}
|
|
|
|
buffer := allocStringBuilder()
|
|
defer freeStringBuilder(buffer)
|
|
|
|
buffer.WriteString("_{ ")
|
|
|
|
if radius.TopLeftX.Equal(radius.TopLeftY) {
|
|
buffer.WriteString("top-left = ")
|
|
buffer.WriteString(radius.TopLeftX.String())
|
|
} else {
|
|
buffer.WriteString("top-left-x = ")
|
|
buffer.WriteString(radius.TopLeftX.String())
|
|
buffer.WriteString("top-left-y = ")
|
|
buffer.WriteString(radius.TopLeftY.String())
|
|
}
|
|
|
|
if radius.TopRightX.Equal(radius.TopRightY) {
|
|
buffer.WriteString(", top-right = ")
|
|
buffer.WriteString(radius.TopRightX.String())
|
|
} else {
|
|
buffer.WriteString(", top-right-x = ")
|
|
buffer.WriteString(radius.TopRightX.String())
|
|
buffer.WriteString(", top-right-y = ")
|
|
buffer.WriteString(radius.TopRightY.String())
|
|
}
|
|
|
|
if radius.BottomLeftX.Equal(radius.BottomLeftY) {
|
|
buffer.WriteString(", bottom-left = ")
|
|
buffer.WriteString(radius.BottomLeftX.String())
|
|
} else {
|
|
buffer.WriteString(", bottom-left-x = ")
|
|
buffer.WriteString(radius.BottomLeftX.String())
|
|
buffer.WriteString(", bottom-left-y = ")
|
|
buffer.WriteString(radius.BottomLeftY.String())
|
|
}
|
|
|
|
if radius.BottomRightX.Equal(radius.BottomRightY) {
|
|
buffer.WriteString(", bottom-right = ")
|
|
buffer.WriteString(radius.BottomRightX.String())
|
|
} else {
|
|
buffer.WriteString(", bottom-right-x = ")
|
|
buffer.WriteString(radius.BottomRightX.String())
|
|
buffer.WriteString(", bottom-right-y = ")
|
|
buffer.WriteString(radius.BottomRightY.String())
|
|
}
|
|
|
|
buffer.WriteString(" }")
|
|
return buffer.String()
|
|
}
|
|
|
|
func (radius BoxRadius) cssValue(builder cssBuilder, session Session) {
|
|
|
|
if (radius.TopLeftX.Type == Auto || radius.TopLeftX.Value == 0) &&
|
|
(radius.TopLeftY.Type == Auto || radius.TopLeftY.Value == 0) &&
|
|
(radius.TopRightX.Type == Auto || radius.TopRightX.Value == 0) &&
|
|
(radius.TopRightY.Type == Auto || radius.TopRightY.Value == 0) &&
|
|
(radius.BottomRightX.Type == Auto || radius.BottomRightX.Value == 0) &&
|
|
(radius.BottomRightY.Type == Auto || radius.BottomRightY.Value == 0) &&
|
|
(radius.BottomLeftX.Type == Auto || radius.BottomLeftX.Value == 0) &&
|
|
(radius.BottomLeftY.Type == Auto || radius.BottomLeftY.Value == 0) {
|
|
return
|
|
}
|
|
|
|
buffer := allocStringBuilder()
|
|
defer freeStringBuilder(buffer)
|
|
|
|
buffer.WriteString(radius.TopLeftX.cssString("0", session))
|
|
|
|
if radius.AllAnglesIsEqual() {
|
|
|
|
if !radius.TopLeftX.Equal(radius.TopLeftY) {
|
|
buffer.WriteString(" / ")
|
|
buffer.WriteString(radius.TopLeftY.cssString("0", session))
|
|
}
|
|
|
|
} else {
|
|
|
|
buffer.WriteRune(' ')
|
|
buffer.WriteString(radius.TopRightX.cssString("0", session))
|
|
buffer.WriteRune(' ')
|
|
buffer.WriteString(radius.BottomRightX.cssString("0", session))
|
|
buffer.WriteRune(' ')
|
|
buffer.WriteString(radius.BottomLeftX.cssString("0", session))
|
|
|
|
if !radius.TopLeftX.Equal(radius.TopLeftY) ||
|
|
!radius.TopRightX.Equal(radius.TopRightY) ||
|
|
!radius.BottomLeftX.Equal(radius.BottomLeftY) ||
|
|
!radius.BottomRightX.Equal(radius.BottomRightY) {
|
|
|
|
buffer.WriteString(" / ")
|
|
buffer.WriteString(radius.TopLeftY.cssString("0", session))
|
|
buffer.WriteRune(' ')
|
|
buffer.WriteString(radius.TopRightY.cssString("0", session))
|
|
buffer.WriteRune(' ')
|
|
buffer.WriteString(radius.BottomRightY.cssString("0", session))
|
|
buffer.WriteRune(' ')
|
|
buffer.WriteString(radius.BottomLeftY.cssString("0", session))
|
|
}
|
|
}
|
|
|
|
builder.add("border-radius", buffer.String())
|
|
}
|
|
|
|
func (radius BoxRadius) cssString(session Session) string {
|
|
var builder cssValueBuilder
|
|
radius.cssValue(&builder, session)
|
|
return builder.finish()
|
|
}
|
|
|
|
func getRadiusProperty(style Properties) RadiusProperty {
|
|
if value := style.Get(Radius); value != nil {
|
|
switch value := value.(type) {
|
|
case RadiusProperty:
|
|
return value
|
|
|
|
case BoxRadius:
|
|
result := NewRadiusProperty(nil)
|
|
if value.AllAnglesIsEqual() {
|
|
result.Set(X, value.TopLeftX)
|
|
result.Set(Y, value.TopLeftY)
|
|
} else {
|
|
if value.TopLeftX.Equal(value.TopLeftY) {
|
|
result.Set(TopLeft, value.TopLeftX)
|
|
} else {
|
|
result.Set(TopLeftX, value.TopLeftX)
|
|
result.Set(TopLeftY, value.TopLeftY)
|
|
}
|
|
if value.TopRightX.Equal(value.TopRightY) {
|
|
result.Set(TopRight, value.TopRightX)
|
|
} else {
|
|
result.Set(TopRightX, value.TopRightX)
|
|
result.Set(TopRightY, value.TopRightY)
|
|
}
|
|
if value.BottomLeftX.Equal(value.BottomLeftY) {
|
|
result.Set(BottomLeft, value.BottomLeftX)
|
|
} else {
|
|
result.Set(BottomLeftX, value.BottomLeftX)
|
|
result.Set(BottomLeftY, value.BottomLeftY)
|
|
}
|
|
if value.BottomRightX.Equal(value.BottomRightY) {
|
|
result.Set(BottomRight, value.BottomRightX)
|
|
} else {
|
|
result.Set(BottomRightX, value.BottomRightX)
|
|
result.Set(BottomRightY, value.BottomRightY)
|
|
}
|
|
}
|
|
return result
|
|
|
|
case SizeUnit:
|
|
return NewRadiusProperty(Params{
|
|
X: value,
|
|
Y: value,
|
|
})
|
|
|
|
case string:
|
|
return NewRadiusProperty(Params{
|
|
X: value,
|
|
Y: value,
|
|
})
|
|
}
|
|
}
|
|
|
|
return NewRadiusProperty(nil)
|
|
}
|
|
|
|
func setRadiusProperty(properties Properties, value any) []PropertyName {
|
|
|
|
if value == nil {
|
|
return propertiesRemove(properties, Radius)
|
|
}
|
|
|
|
switch value := value.(type) {
|
|
case RadiusProperty:
|
|
properties.setRaw(Radius, value)
|
|
|
|
case SizeUnit:
|
|
properties.setRaw(Radius, value)
|
|
|
|
case BoxRadius:
|
|
radius := NewRadiusProperty(nil)
|
|
if value.AllAnglesIsEqual() {
|
|
radius.Set(X, value.TopLeftX)
|
|
radius.Set(Y, value.TopLeftY)
|
|
} else {
|
|
if value.TopLeftX.Equal(value.TopLeftY) {
|
|
radius.Set(TopLeft, value.TopLeftX)
|
|
} else {
|
|
radius.Set(TopLeftX, value.TopLeftX)
|
|
radius.Set(TopLeftY, value.TopLeftY)
|
|
}
|
|
if value.TopRightX.Equal(value.TopRightY) {
|
|
radius.Set(TopRight, value.TopRightX)
|
|
} else {
|
|
radius.Set(TopRightX, value.TopRightX)
|
|
radius.Set(TopRightY, value.TopRightY)
|
|
}
|
|
if value.BottomLeftX.Equal(value.BottomLeftY) {
|
|
radius.Set(BottomLeft, value.BottomLeftX)
|
|
} else {
|
|
radius.Set(BottomLeftX, value.BottomLeftX)
|
|
radius.Set(BottomLeftY, value.BottomLeftY)
|
|
}
|
|
if value.BottomRightX.Equal(value.BottomRightY) {
|
|
radius.Set(BottomRight, value.BottomRightX)
|
|
} else {
|
|
radius.Set(BottomRightX, value.BottomRightX)
|
|
radius.Set(BottomRightY, value.BottomRightY)
|
|
}
|
|
}
|
|
properties.setRaw(Radius, radius)
|
|
|
|
case string:
|
|
if strings.Contains(value, "/") {
|
|
values := strings.Split(value, "/")
|
|
if len(values) == 2 {
|
|
if setRadiusPropertyElement(properties, RadiusX, values[0]) {
|
|
result := []PropertyName{Radius, RadiusX}
|
|
if setRadiusPropertyElement(properties, RadiusY, values[1]) {
|
|
result = append(result, RadiusY)
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
notCompatibleType(Radius, value)
|
|
return nil
|
|
|
|
} else {
|
|
return setSizeProperty(properties, Radius, value)
|
|
}
|
|
|
|
case DataObject:
|
|
radius := NewRadiusProperty(nil)
|
|
for _, tag := range []PropertyName{X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
|
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY} {
|
|
if value, ok := value.PropertyValue(string(tag)); ok {
|
|
radius.Set(tag, value)
|
|
}
|
|
}
|
|
properties.setRaw(Radius, radius)
|
|
|
|
case float32:
|
|
properties.setRaw(Radius, Px(float64(value)))
|
|
|
|
case float64:
|
|
properties.setRaw(Radius, Px(value))
|
|
|
|
default:
|
|
if n, ok := isInt(value); ok {
|
|
properties.setRaw(Radius, Px(float64(n)))
|
|
} else {
|
|
notCompatibleType(Radius, value)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return []PropertyName{Radius}
|
|
}
|
|
|
|
func removeRadiusPropertyElement(properties Properties, tag PropertyName) bool {
|
|
if value := properties.getRaw(Radius); value != nil {
|
|
radius := getRadiusProperty(properties)
|
|
radius.Remove(tag)
|
|
if radius.empty() {
|
|
properties.setRaw(Radius, nil)
|
|
} else {
|
|
properties.setRaw(Radius, radius)
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func setRadiusPropertyElement(properties Properties, tag PropertyName, value any) bool {
|
|
if value == nil {
|
|
removeRadiusPropertyElement(properties, tag)
|
|
return true
|
|
}
|
|
|
|
radius := getRadiusProperty(properties)
|
|
if radius.Set(tag, value) {
|
|
properties.setRaw(Radius, radius)
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func getRadiusElement(style Properties, tag PropertyName) any {
|
|
value := style.Get(Radius)
|
|
if value != nil {
|
|
switch value := value.(type) {
|
|
case string:
|
|
return value
|
|
|
|
case SizeUnit:
|
|
return value
|
|
|
|
case RadiusProperty:
|
|
return value.Get(tag)
|
|
|
|
case BoxRadius:
|
|
switch tag {
|
|
case RadiusX:
|
|
if value.TopLeftX.Equal(value.TopRightX) &&
|
|
value.TopLeftX.Equal(value.BottomLeftX) &&
|
|
value.TopLeftX.Equal(value.BottomRightX) {
|
|
return value.TopLeftX
|
|
}
|
|
|
|
case RadiusY:
|
|
if value.TopLeftY.Equal(value.TopRightY) &&
|
|
value.TopLeftY.Equal(value.BottomLeftY) &&
|
|
value.TopLeftY.Equal(value.BottomRightY) {
|
|
return value.TopLeftY
|
|
}
|
|
|
|
case RadiusTopLeft:
|
|
if value.TopLeftX.Equal(value.TopLeftY) {
|
|
return value.TopLeftY
|
|
}
|
|
|
|
case RadiusTopRight:
|
|
if value.TopRightX.Equal(value.TopRightY) {
|
|
return value.TopRightY
|
|
}
|
|
|
|
case RadiusBottomLeft:
|
|
if value.BottomLeftX.Equal(value.BottomLeftY) {
|
|
return value.BottomLeftY
|
|
}
|
|
|
|
case RadiusBottomRight:
|
|
if value.BottomRightX.Equal(value.BottomRightY) {
|
|
return value.BottomRightY
|
|
}
|
|
|
|
case RadiusTopLeftX:
|
|
return value.TopLeftX
|
|
|
|
case RadiusTopLeftY:
|
|
return value.TopLeftY
|
|
|
|
case RadiusTopRightX:
|
|
return value.TopRightX
|
|
|
|
case RadiusTopRightY:
|
|
return value.TopRightY
|
|
|
|
case RadiusBottomLeftX:
|
|
return value.BottomLeftX
|
|
|
|
case RadiusBottomLeftY:
|
|
return value.BottomLeftY
|
|
|
|
case RadiusBottomRightX:
|
|
return value.BottomRightX
|
|
|
|
case RadiusBottomRightY:
|
|
return value.BottomRightY
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getRadius(properties Properties, session Session) BoxRadius {
|
|
if value := properties.Get(Radius); value != nil {
|
|
switch value := value.(type) {
|
|
case BoxRadius:
|
|
return value
|
|
|
|
case RadiusProperty:
|
|
return value.BoxRadius(session)
|
|
|
|
case SizeUnit:
|
|
return BoxRadius{TopLeftX: value, TopLeftY: value, TopRightX: value, TopRightY: value,
|
|
BottomLeftX: value, BottomLeftY: value, BottomRightX: value, BottomRightY: value}
|
|
|
|
case string:
|
|
if text, ok := session.resolveConstants(value); ok {
|
|
if size, ok := StringToSizeUnit(text); ok {
|
|
return BoxRadius{TopLeftX: size, TopLeftY: size, TopRightX: size, TopRightY: size,
|
|
BottomLeftX: size, BottomLeftY: size, BottomRightX: size, BottomRightY: size}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return BoxRadius{}
|
|
}
|