2021-09-07 17:36:50 +03:00
package rui
import (
"fmt"
"strings"
)
2024-09-12 14:05:11 +03:00
// Constants for [RadiusProperty] specific properties
2021-09-07 17:36:50 +03:00
const (
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
Radius = "radius"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusX = "radius-x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusY = "radius-y"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusTopLeft = "radius-top-left"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusTopLeftX = "radius-top-left-x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusTopLeftY = "radius-top-left-y"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusTopRight = "radius-top-right"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusTopRightX = "radius-top-right-x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusTopRightY = "radius-top-right-y"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusBottomLeft = "radius-bottom-left"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusBottomLeftX = "radius-bottom-left-x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusBottomLeftY = "radius-bottom-left-y"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusBottomRight = "radius-bottom-right"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusBottomRightX = "radius-bottom-right-x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
RadiusBottomRightY = "radius-bottom-right-y"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
X = "x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
Y = "y"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
TopLeft = "top-left"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
TopLeftX = "top-left-x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
TopLeftY = "top-left-y"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
TopRight = "top-right"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
TopRightX = "top-right-x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
TopRightY = "top-right-y"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
BottomLeft = "bottom-left"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
BottomLeftX = "bottom-left-x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
BottomLeftY = "bottom-left-y"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
BottomRight = "bottom-right"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
BottomRightX = "bottom-right-x"
2024-09-18 13:50:06 +03:00
// 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.
2021-09-07 17:36:50 +03:00
BottomRightY = "bottom-right-y"
)
2024-09-12 14:05:11 +03:00
// RadiusProperty is a description of the [View] (shape) elliptical corner radius.
2021-09-07 17:36:50 +03:00
type RadiusProperty interface {
Properties
2022-05-22 12:54:02 +03:00
stringWriter
2021-09-07 17:36:50 +03:00
fmt . Stringer
2024-09-12 14:05:11 +03:00
// BoxRadius returns x and y radius of the corners of the element
2021-09-07 17:36:50 +03:00
BoxRadius ( session Session ) BoxRadius
}
type radiusPropertyData struct {
propertyList
}
// NewRadiusProperty creates the new RadiusProperty
func NewRadiusProperty ( params Params ) RadiusProperty {
result := new ( radiusPropertyData )
2022-07-26 18:36:00 +03:00
result . properties = map [ string ] any { }
2021-09-07 17:36:50 +03:00
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-" )
}
2022-05-22 12:54:02 +03:00
func ( radius * radiusPropertyData ) writeString ( buffer * strings . Builder , indent string ) {
buffer . WriteString ( "_{ " )
comma := false
2021-09-07 17:36:50 +03:00
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 {
2022-05-22 12:54:02 +03:00
if comma {
buffer . WriteString ( ", " )
}
buffer . WriteString ( tag )
buffer . WriteString ( " = " )
writePropertyValue ( buffer , tag , value , indent )
comma = true
2021-09-07 17:36:50 +03:00
}
}
2022-05-22 12:54:02 +03:00
buffer . WriteString ( " }" )
2021-09-07 17:36:50 +03:00
}
func ( radius * radiusPropertyData ) String ( ) string {
2022-05-22 12:54:02 +03:00
return runStringWriter ( radius )
2021-09-07 17:36:50 +03:00
}
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 )
}
}
}
2022-07-26 18:36:00 +03:00
equalValue := func ( value1 , value2 any ) bool {
2021-09-07 17:36:50 +03:00
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 )
}
}
2022-07-26 18:36:00 +03:00
func ( radius * radiusPropertyData ) Set ( tag string , value any ) bool {
2021-09-07 17:36:50 +03:00
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 {
2024-11-14 12:26:35 +03:00
xOK := radius . Set ( tag + "-x" , values [ 0 ] )
yOK := radius . Set ( tag + "-y" , values [ 1 ] )
2021-09-07 17:36:50 +03:00
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
}
2022-07-26 18:36:00 +03:00
func ( radius * radiusPropertyData ) Get ( tag string ) any {
2021-09-07 17:36:50 +03:00
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
}
}
2022-05-06 18:19:13 +03:00
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
}
}
2021-09-07 17:36:50 +03:00
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 ( )
}
2022-09-05 14:00:07 +03:00
func ( radius BoxRadius ) cssValue ( builder cssBuilder , session Session ) {
2021-09-07 17:36:50 +03:00
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 )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( radius . TopLeftX . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
if radius . AllAnglesIsEqual ( ) {
if ! radius . TopLeftX . Equal ( radius . TopLeftY ) {
buffer . WriteString ( " / " )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( radius . TopLeftY . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
}
} else {
buffer . WriteRune ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( radius . TopRightX . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( radius . BottomRightX . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( radius . BottomLeftX . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
if ! radius . TopLeftX . Equal ( radius . TopLeftY ) ||
! radius . TopRightX . Equal ( radius . TopRightY ) ||
! radius . BottomLeftX . Equal ( radius . BottomLeftY ) ||
! radius . BottomRightX . Equal ( radius . BottomRightY ) {
buffer . WriteString ( " / " )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( radius . TopLeftY . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( radius . TopRightY . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( radius . BottomRightY . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteRune ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( radius . BottomLeftY . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
}
}
builder . add ( "border-radius" , buffer . String ( ) )
}
2022-09-05 14:00:07 +03:00
func ( radius BoxRadius ) cssString ( session Session ) string {
2021-09-07 17:36:50 +03:00
var builder cssValueBuilder
2022-09-05 14:00:07 +03:00
radius . cssValue ( & builder , session )
2021-09-07 17:36:50 +03:00
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 )
}
2022-07-26 18:36:00 +03:00
func ( properties * propertyList ) setRadius ( value any ) bool {
2021-09-07 17:36:50 +03:00
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
2022-08-16 11:40:42 +03:00
case float32 :
return properties . setRadius ( Px ( float64 ( value ) ) )
case float64 :
return properties . setRadius ( Px ( value ) )
2021-09-07 17:36:50 +03:00
default :
2022-08-16 11:40:42 +03:00
if n , ok := isInt ( value ) ; ok {
return properties . setRadius ( Px ( float64 ( n ) ) )
}
2021-09-07 17:36:50 +03:00
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
}
}
}
2022-07-26 18:36:00 +03:00
func ( properties * propertyList ) setRadiusElement ( tag string , value any ) bool {
2021-09-07 17:36:50 +03:00
if value == nil {
properties . removeRadiusElement ( tag )
return true
}
radius := getRadiusProperty ( properties )
if radius . Set ( tag , value ) {
properties . properties [ Radius ] = radius
return true
}
return false
}
2022-07-26 18:36:00 +03:00
func getRadiusElement ( style Properties , tag string ) any {
2021-09-07 17:36:50 +03:00
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 { }
}