mirror of https://github.com/anoshenko/rui.git
1091 lines
33 KiB
Go
1091 lines
33 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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 {
|
|
propertyList
|
|
}
|
|
|
|
// NewRadiusProperty creates the new RadiusProperty
|
|
func NewRadiusProperty(params Params) RadiusProperty {
|
|
result := new(radiusPropertyData)
|
|
result.properties = map[string]any{}
|
|
if params != nil {
|
|
for _, tag := range []string{X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
|
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY} {
|
|
if value, ok := params[tag]; ok {
|
|
result.Set(tag, value)
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (radius *radiusPropertyData) normalizeTag(tag string) string {
|
|
return strings.TrimPrefix(strings.ToLower(tag), "radius-")
|
|
}
|
|
|
|
func (radius *radiusPropertyData) writeString(buffer *strings.Builder, indent string) {
|
|
buffer.WriteString("_{ ")
|
|
comma := false
|
|
for _, tag := range []string{X, Y, TopLeft, TopLeftX, TopLeftY, TopRight, TopRightX, TopRightY,
|
|
BottomLeft, BottomLeftX, BottomLeftY, BottomRight, BottomRightX, BottomRightY} {
|
|
if value, ok := radius.properties[tag]; ok {
|
|
if comma {
|
|
buffer.WriteString(", ")
|
|
}
|
|
buffer.WriteString(tag)
|
|
buffer.WriteString(" = ")
|
|
writePropertyValue(buffer, tag, value, indent)
|
|
comma = true
|
|
}
|
|
}
|
|
|
|
buffer.WriteString(" }")
|
|
}
|
|
|
|
func (radius *radiusPropertyData) String() string {
|
|
return runStringWriter(radius)
|
|
}
|
|
|
|
func (radius *radiusPropertyData) delete(tags []string) {
|
|
for _, tag := range tags {
|
|
delete(radius.properties, tag)
|
|
}
|
|
}
|
|
|
|
func (radius *radiusPropertyData) deleteUnusedTags() {
|
|
for _, tag := range []string{X, Y} {
|
|
if _, ok := radius.properties[tag]; ok {
|
|
unused := true
|
|
for _, t := range []string{TopLeft, TopRight, BottomLeft, BottomRight} {
|
|
if _, ok := radius.properties[t+"-"+tag]; !ok {
|
|
if _, ok := radius.properties[t]; !ok {
|
|
unused = false
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if unused {
|
|
delete(radius.properties, 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 []string{TopLeft, TopRight, BottomLeft, BottomRight} {
|
|
tagX := tag + "-x"
|
|
tagY := tag + "-y"
|
|
valueX, okX := radius.properties[tagX]
|
|
valueY, okY := radius.properties[tagY]
|
|
|
|
if value, ok := radius.properties[tag]; ok {
|
|
if okX && okY {
|
|
delete(radius.properties, tag)
|
|
} else if okX && !okY {
|
|
if equalValue(value, valueX) {
|
|
delete(radius.properties, tagX)
|
|
} else {
|
|
radius.properties[tagY] = value
|
|
delete(radius.properties, tag)
|
|
}
|
|
} else if !okX && okY {
|
|
if equalValue(value, valueY) {
|
|
delete(radius.properties, tagY)
|
|
} else {
|
|
radius.properties[tagX] = value
|
|
delete(radius.properties, tag)
|
|
}
|
|
}
|
|
} else if okX && okY && equalValue(valueX, valueY) {
|
|
radius.properties[tag] = valueX
|
|
delete(radius.properties, tagX)
|
|
delete(radius.properties, tagY)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (radius *radiusPropertyData) Remove(tag string) {
|
|
tag = radius.normalizeTag(tag)
|
|
|
|
switch tag {
|
|
case X, Y:
|
|
if _, ok := radius.properties[tag]; ok {
|
|
radius.Set(tag, AutoSize())
|
|
delete(radius.properties, tag)
|
|
}
|
|
|
|
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
|
delete(radius.properties, tag)
|
|
|
|
case TopLeft, TopRight, BottomLeft, BottomRight:
|
|
radius.delete([]string{tag, tag + "-x", tag + "-y"})
|
|
|
|
default:
|
|
ErrorLogF(`"%s" property is not compatible with the RadiusProperty`, tag)
|
|
}
|
|
|
|
}
|
|
|
|
func (radius *radiusPropertyData) Set(tag string, value any) bool {
|
|
if value == nil {
|
|
radius.Remove(tag)
|
|
return true
|
|
}
|
|
|
|
tag = radius.normalizeTag(tag)
|
|
switch tag {
|
|
case X:
|
|
if radius.setSizeProperty(tag, value) {
|
|
radius.delete([]string{TopLeftX, TopRightX, BottomLeftX, BottomRightX})
|
|
for _, t := range []string{TopLeft, TopRight, BottomLeft, BottomRight} {
|
|
if val, ok := radius.properties[t]; ok {
|
|
if _, ok := radius.properties[t+"-y"]; !ok {
|
|
radius.properties[t+"-y"] = val
|
|
}
|
|
delete(radius.properties, t)
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
case Y:
|
|
if radius.setSizeProperty(tag, value) {
|
|
radius.delete([]string{TopLeftY, TopRightY, BottomLeftY, BottomRightY})
|
|
for _, t := range []string{TopLeft, TopRight, BottomLeft, BottomRight} {
|
|
if val, ok := radius.properties[t]; ok {
|
|
if _, ok := radius.properties[t+"-x"]; !ok {
|
|
radius.properties[t+"-x"] = val
|
|
}
|
|
delete(radius.properties, t)
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
|
if radius.setSizeProperty(tag, value) {
|
|
radius.deleteUnusedTags()
|
|
return true
|
|
}
|
|
|
|
case TopLeft, TopRight, BottomLeft, BottomRight:
|
|
switch value := value.(type) {
|
|
case SizeUnit:
|
|
radius.properties[tag] = value
|
|
radius.delete([]string{tag + "-x", tag + "-y"})
|
|
radius.deleteUnusedTags()
|
|
return true
|
|
|
|
case string:
|
|
if strings.Contains(value, "/") {
|
|
if values := strings.Split(value, "/"); len(values) == 2 {
|
|
xOK := radius.Set(tag+"-x", value[0])
|
|
yOK := radius.Set(tag+"-y", value[1])
|
|
return xOK && yOK
|
|
} else {
|
|
notCompatibleType(tag, value)
|
|
}
|
|
} else {
|
|
if radius.setSizeProperty(tag, value) {
|
|
radius.delete([]string{tag + "-x", tag + "-y"})
|
|
radius.deleteUnusedTags()
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
default:
|
|
ErrorLogF(`"%s" property is not compatible with the RadiusProperty`, tag)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (radius *radiusPropertyData) Get(tag string) any {
|
|
tag = radius.normalizeTag(tag)
|
|
if value, ok := radius.properties[tag]; ok {
|
|
return value
|
|
}
|
|
|
|
switch tag {
|
|
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
|
tagLen := len(tag)
|
|
if value, ok := radius.properties[tag[:tagLen-2]]; ok {
|
|
return value
|
|
}
|
|
if value, ok := radius.properties[tag[tagLen-1:]]; ok {
|
|
return value
|
|
}
|
|
}
|
|
|
|
switch tag {
|
|
case TopLeftX, TopRightX, BottomLeftX, BottomRightX:
|
|
if value, ok := radius.properties[X]; ok {
|
|
return value
|
|
}
|
|
case TopLeftY, TopRightY, BottomLeftY, BottomRightY:
|
|
if value, ok := radius.properties[Y]; ok {
|
|
return value
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (radius *radiusPropertyData) BoxRadius(session Session) BoxRadius {
|
|
x, _ := sizeProperty(radius, X, session)
|
|
y, _ := sizeProperty(radius, Y, session)
|
|
|
|
getRadius := func(tag string) (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 (properties *propertyList) setRadius(value any) bool {
|
|
|
|
if value == nil {
|
|
delete(properties.properties, Radius)
|
|
return true
|
|
}
|
|
|
|
switch value := value.(type) {
|
|
case RadiusProperty:
|
|
properties.properties[Radius] = value
|
|
return true
|
|
|
|
case SizeUnit:
|
|
properties.properties[Radius] = value
|
|
return true
|
|
|
|
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.properties[Radius] = radius
|
|
return true
|
|
|
|
case string:
|
|
if strings.Contains(value, "/") {
|
|
values := strings.Split(value, "/")
|
|
if len(values) == 2 {
|
|
okX := properties.setRadiusElement(RadiusX, values[0])
|
|
okY := properties.setRadiusElement(RadiusY, values[1])
|
|
return okX && okY
|
|
} else {
|
|
notCompatibleType(Radius, value)
|
|
}
|
|
} else {
|
|
return properties.setSizeProperty(Radius, value)
|
|
}
|
|
|
|
case DataObject:
|
|
radius := NewRadiusProperty(nil)
|
|
for _, tag := range []string{X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
|
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY} {
|
|
if value, ok := value.PropertyValue(tag); ok {
|
|
radius.Set(tag, value)
|
|
}
|
|
}
|
|
properties.properties[Radius] = radius
|
|
return true
|
|
|
|
case float32:
|
|
return properties.setRadius(Px(float64(value)))
|
|
|
|
case float64:
|
|
return properties.setRadius(Px(value))
|
|
|
|
default:
|
|
if n, ok := isInt(value); ok {
|
|
return properties.setRadius(Px(float64(n)))
|
|
}
|
|
notCompatibleType(Radius, value)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (properties *propertyList) removeRadiusElement(tag string) {
|
|
if value, ok := properties.properties[Radius]; ok && value != nil {
|
|
radius := getRadiusProperty(properties)
|
|
radius.Remove(tag)
|
|
if len(radius.AllTags()) == 0 {
|
|
delete(properties.properties, Radius)
|
|
} else {
|
|
properties.properties[Radius] = radius
|
|
}
|
|
}
|
|
}
|
|
|
|
func (properties *propertyList) setRadiusElement(tag string, value any) bool {
|
|
if value == nil {
|
|
properties.removeRadiusElement(tag)
|
|
return true
|
|
}
|
|
|
|
radius := getRadiusProperty(properties)
|
|
if radius.Set(tag, value) {
|
|
properties.properties[Radius] = radius
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func getRadiusElement(style Properties, tag string) 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{}
|
|
}
|