mirror of https://github.com/anoshenko/rui.git
358 lines
10 KiB
Go
358 lines
10 KiB
Go
package rui
|
|
|
|
import "strings"
|
|
|
|
type RadialGradientRadiusType int
|
|
|
|
// Constants related to view's background gradient description
|
|
const (
|
|
// EllipseGradient is value of the Shape property of a radial gradient background:
|
|
// the shape is an axis-aligned ellipse
|
|
EllipseGradient = 0
|
|
|
|
// CircleGradient is value of the Shape property of a radial gradient background:
|
|
// the gradient's shape is a circle with constant radius
|
|
CircleGradient = 1
|
|
|
|
// ClosestSideGradient is value of the Radius property of a radial gradient background:
|
|
// The gradient's ending shape meets the side of the box closest to its center (for circles)
|
|
// or meets both the vertical and horizontal sides closest to the center (for ellipses).
|
|
ClosestSideGradient RadialGradientRadiusType = 0
|
|
|
|
// ClosestCornerGradient is value of the Radius property of a radial gradient background:
|
|
// The gradient's ending shape is sized so that it exactly meets the closest corner
|
|
// of the box from its center.
|
|
ClosestCornerGradient RadialGradientRadiusType = 1
|
|
|
|
// FarthestSideGradient is value of the Radius property of a radial gradient background:
|
|
// Similar to closest-side, except the ending shape is sized to meet the side of the box
|
|
// farthest from its center (or vertical and horizontal sides).
|
|
FarthestSideGradient RadialGradientRadiusType = 2
|
|
|
|
// FarthestCornerGradient is value of the Radius property of a radial gradient background:
|
|
// The default value, the gradient's ending shape is sized so that it exactly meets
|
|
// the farthest corner of the box from its center.
|
|
FarthestCornerGradient RadialGradientRadiusType = 3
|
|
)
|
|
|
|
type backgroundRadialGradient struct {
|
|
backgroundGradient
|
|
}
|
|
|
|
// NewBackgroundRadialGradient creates the new background radial gradient.
|
|
//
|
|
// The following properties can be used:
|
|
// - "gradient" (Gradient) - Describes gradient stop points. This is a mandatory property while describing background gradients.
|
|
// - "center-x" (CenterX), "center-y" (CenterY) - Defines the gradient center point cooordinates.
|
|
// - "radial-gradient-radius" (RadialGradientRadius) - Defines radius of the radial gradient.
|
|
// - "radial-gradient-shape" (RadialGradientShape) - Defines shape of the radial gradient.
|
|
// - "repeating" (Repeating) - Defines whether stop points needs to be repeated after the last one.
|
|
func NewBackgroundRadialGradient(params Params) BackgroundElement {
|
|
result := new(backgroundRadialGradient)
|
|
result.init()
|
|
for tag, value := range params {
|
|
result.Set(tag, value)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// NewCircleRadialGradient creates the new background circle radial gradient.
|
|
func NewCircleRadialGradient[radiusType SizeUnit | RadialGradientRadiusType](xCenter, yCenter SizeUnit, radius radiusType, repeating bool, point1 GradientPoint, point2 GradientPoint, points ...GradientPoint) BackgroundElement {
|
|
params := Params{
|
|
RadialGradientShape: CircleGradient,
|
|
Gradient: append([]GradientPoint{point1, point2}, points...),
|
|
RadialGradientRadius: radius,
|
|
}
|
|
if xCenter.Type != Auto {
|
|
params[CenterX] = xCenter
|
|
}
|
|
if yCenter.Type != Auto {
|
|
params[CenterY] = yCenter
|
|
}
|
|
if repeating {
|
|
params[Repeating] = true
|
|
}
|
|
return NewBackgroundRadialGradient(params)
|
|
}
|
|
|
|
// NewEllipseRadialGradient creates the new background ellipse radial gradient.
|
|
func NewEllipseRadialGradient[radiusType []SizeUnit | RadialGradientRadiusType](xCenter, yCenter SizeUnit, radius radiusType, repeating bool, point1 GradientPoint, point2 GradientPoint, points ...GradientPoint) BackgroundElement {
|
|
params := Params{
|
|
RadialGradientShape: EllipseGradient,
|
|
Gradient: append([]GradientPoint{point1, point2}, points...),
|
|
RadialGradientRadius: radius,
|
|
}
|
|
if xCenter.Type != Auto {
|
|
params[CenterX] = xCenter
|
|
}
|
|
if yCenter.Type != Auto {
|
|
params[CenterY] = yCenter
|
|
}
|
|
if repeating {
|
|
params[Repeating] = true
|
|
}
|
|
return NewBackgroundRadialGradient(params)
|
|
}
|
|
|
|
func (gradient *backgroundRadialGradient) init() {
|
|
gradient.backgroundElement.init()
|
|
gradient.normalize = normalizeRadialGradientTag
|
|
gradient.set = backgroundRadialGradientSet
|
|
gradient.supportedProperties = []PropertyName{
|
|
RadialGradientRadius, RadialGradientShape, CenterX, CenterY, Gradient, Repeating,
|
|
}
|
|
}
|
|
|
|
func (gradient *backgroundRadialGradient) Tag() string {
|
|
return "radial-gradient"
|
|
}
|
|
|
|
func (image *backgroundRadialGradient) Clone() BackgroundElement {
|
|
result := NewBackgroundRadialGradient(nil)
|
|
for tag, value := range image.properties {
|
|
result.setRaw(tag, value)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func normalizeRadialGradientTag(tag PropertyName) PropertyName {
|
|
tag = defaultNormalize(tag)
|
|
switch tag {
|
|
case Radius:
|
|
tag = RadialGradientRadius
|
|
|
|
case Shape:
|
|
tag = RadialGradientShape
|
|
|
|
case "x-center":
|
|
tag = CenterX
|
|
|
|
case "y-center":
|
|
tag = CenterY
|
|
}
|
|
|
|
return tag
|
|
}
|
|
|
|
func backgroundRadialGradientSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
|
switch tag {
|
|
case RadialGradientRadius:
|
|
switch value := value.(type) {
|
|
case []SizeUnit:
|
|
switch len(value) {
|
|
case 0:
|
|
properties.setRaw(RadialGradientRadius, nil)
|
|
|
|
case 1:
|
|
if value[0].Type == Auto {
|
|
properties.setRaw(RadialGradientRadius, nil)
|
|
} else {
|
|
properties.setRaw(RadialGradientRadius, value[0])
|
|
}
|
|
|
|
default:
|
|
properties.setRaw(RadialGradientRadius, value)
|
|
}
|
|
return []PropertyName{tag}
|
|
|
|
case []any:
|
|
switch len(value) {
|
|
case 0:
|
|
properties.setRaw(RadialGradientRadius, nil)
|
|
return []PropertyName{tag}
|
|
|
|
case 1:
|
|
return backgroundRadialGradientSet(properties, RadialGradientRadius, value[0])
|
|
|
|
default:
|
|
properties.setRaw(RadialGradientRadius, value)
|
|
return []PropertyName{tag}
|
|
}
|
|
|
|
case string:
|
|
if setSimpleProperty(properties, RadialGradientRadius, value) {
|
|
return []PropertyName{tag}
|
|
}
|
|
if size, err := stringToSizeUnit(value); err == nil {
|
|
if size.Type == Auto {
|
|
properties.setRaw(RadialGradientRadius, nil)
|
|
} else {
|
|
properties.setRaw(RadialGradientRadius, size)
|
|
}
|
|
return []PropertyName{tag}
|
|
}
|
|
return setEnumProperty(properties, RadialGradientRadius, value, enumProperties[RadialGradientRadius].values)
|
|
|
|
case SizeUnit:
|
|
if value.Type == Auto {
|
|
properties.setRaw(RadialGradientRadius, nil)
|
|
} else {
|
|
properties.setRaw(RadialGradientRadius, value)
|
|
}
|
|
return []PropertyName{tag}
|
|
|
|
case RadialGradientRadiusType:
|
|
return setEnumProperty(properties, RadialGradientRadius, int(value), enumProperties[RadialGradientRadius].values)
|
|
|
|
case int:
|
|
return setEnumProperty(properties, RadialGradientRadius, value, enumProperties[RadialGradientRadius].values)
|
|
}
|
|
|
|
ErrorLogF(`Invalid value of "%s" property: %v`, tag, value)
|
|
return nil
|
|
|
|
case RadialGradientShape, CenterX, CenterY:
|
|
return propertiesSet(properties, tag, value)
|
|
}
|
|
|
|
return backgroundGradientSet(properties, tag, value)
|
|
}
|
|
|
|
func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
|
buffer := allocStringBuilder()
|
|
defer freeStringBuilder(buffer)
|
|
|
|
if repeating, _ := boolProperty(gradient, Repeating, session); repeating {
|
|
buffer.WriteString(`repeating-radial-gradient(`)
|
|
} else {
|
|
buffer.WriteString(`radial-gradient(`)
|
|
}
|
|
|
|
var shapeText string
|
|
if shape, ok := enumProperty(gradient, RadialGradientShape, session, EllipseGradient); ok && shape == CircleGradient {
|
|
shapeText = `circle `
|
|
} else {
|
|
shapeText = `ellipse `
|
|
}
|
|
|
|
if value, ok := gradient.properties[RadialGradientRadius]; ok {
|
|
switch value := value.(type) {
|
|
case string:
|
|
if text, ok := session.resolveConstants(value); ok {
|
|
values := enumProperties[RadialGradientRadius]
|
|
if n, ok := enumStringToInt(text, values.values, false); ok {
|
|
buffer.WriteString(shapeText)
|
|
shapeText = ""
|
|
buffer.WriteString(values.cssValues[n])
|
|
buffer.WriteString(" ")
|
|
} else {
|
|
if r, ok := StringToSizeUnit(text); ok && r.Type != Auto {
|
|
buffer.WriteString("ellipse ")
|
|
shapeText = ""
|
|
buffer.WriteString(r.cssString("", session))
|
|
buffer.WriteString(" ")
|
|
buffer.WriteString(r.cssString("", session))
|
|
buffer.WriteString(" ")
|
|
} else {
|
|
ErrorLog(`Invalid radial gradient radius: ` + text)
|
|
}
|
|
}
|
|
} else {
|
|
ErrorLog(`Invalid radial gradient radius: ` + value)
|
|
}
|
|
|
|
case int:
|
|
values := enumProperties[RadialGradientRadius].cssValues
|
|
if value >= 0 && value < len(values) {
|
|
buffer.WriteString(shapeText)
|
|
shapeText = ""
|
|
buffer.WriteString(values[value])
|
|
buffer.WriteString(" ")
|
|
} else {
|
|
ErrorLogF(`Invalid radial gradient radius: %d`, value)
|
|
}
|
|
|
|
case SizeUnit:
|
|
if value.Type != Auto {
|
|
buffer.WriteString("ellipse ")
|
|
shapeText = ""
|
|
buffer.WriteString(value.cssString("", session))
|
|
buffer.WriteString(" ")
|
|
buffer.WriteString(value.cssString("", session))
|
|
buffer.WriteString(" ")
|
|
}
|
|
|
|
case []SizeUnit:
|
|
count := len(value)
|
|
if count > 2 {
|
|
count = 2
|
|
}
|
|
buffer.WriteString("ellipse ")
|
|
shapeText = ""
|
|
for i := 0; i < count; i++ {
|
|
buffer.WriteString(value[i].cssString("50%", session))
|
|
buffer.WriteString(" ")
|
|
}
|
|
|
|
case []any:
|
|
count := len(value)
|
|
if count > 2 {
|
|
count = 2
|
|
}
|
|
buffer.WriteString("ellipse ")
|
|
shapeText = ""
|
|
for i := 0; i < count; i++ {
|
|
if value[i] != nil {
|
|
switch value := value[i].(type) {
|
|
case SizeUnit:
|
|
buffer.WriteString(value.cssString("50%", session))
|
|
buffer.WriteString(" ")
|
|
|
|
case string:
|
|
if text, ok := session.resolveConstants(value); ok {
|
|
if size, err := stringToSizeUnit(text); err == nil {
|
|
buffer.WriteString(size.cssString("50%", session))
|
|
buffer.WriteString(" ")
|
|
} else {
|
|
buffer.WriteString("50% ")
|
|
}
|
|
} else {
|
|
buffer.WriteString("50% ")
|
|
}
|
|
}
|
|
} else {
|
|
buffer.WriteString("50% ")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
x, _ := sizeProperty(gradient, CenterX, session)
|
|
y, _ := sizeProperty(gradient, CenterX, session)
|
|
if x.Type != Auto || y.Type != Auto {
|
|
if shapeText != "" {
|
|
buffer.WriteString(shapeText)
|
|
}
|
|
buffer.WriteString("at ")
|
|
buffer.WriteString(x.cssString("50%", session))
|
|
buffer.WriteString(" ")
|
|
buffer.WriteString(y.cssString("50%", session))
|
|
} else if shapeText != "" {
|
|
buffer.WriteString(shapeText)
|
|
}
|
|
|
|
buffer.WriteString(", ")
|
|
if !gradient.writeGradient(session, buffer) {
|
|
return ""
|
|
}
|
|
|
|
buffer.WriteString(") ")
|
|
|
|
return buffer.String()
|
|
}
|
|
|
|
func (gradient *backgroundRadialGradient) writeString(buffer *strings.Builder, indent string) {
|
|
gradient.writeToBuffer(buffer, indent, gradient.Tag(), []PropertyName{
|
|
Gradient,
|
|
CenterX,
|
|
CenterY,
|
|
Repeating,
|
|
RadialGradientShape,
|
|
RadialGradientRadius,
|
|
})
|
|
}
|
|
|
|
func (gradient *backgroundRadialGradient) String() string {
|
|
return runStringWriter(gradient)
|
|
}
|