2021-09-07 17:36:50 +03:00
|
|
|
package rui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ClipShape defines a View clipping area
|
|
|
|
type ClipShape interface {
|
|
|
|
Properties
|
|
|
|
fmt.Stringer
|
2022-05-22 12:54:02 +03:00
|
|
|
stringWriter
|
2021-09-07 17:36:50 +03:00
|
|
|
cssStyle(session Session) string
|
|
|
|
valid(session Session) bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type insetClip struct {
|
2024-11-13 12:56:39 +03:00
|
|
|
dataProperty
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type ellipseClip struct {
|
2024-11-13 12:56:39 +03:00
|
|
|
dataProperty
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
type circleClip struct {
|
2024-11-13 12:56:39 +03:00
|
|
|
dataProperty
|
2022-05-22 12:54:02 +03:00
|
|
|
}
|
|
|
|
|
2021-09-07 17:36:50 +03:00
|
|
|
type polygonClip struct {
|
2024-11-13 12:56:39 +03:00
|
|
|
dataProperty
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// InsetClip creates a rectangle View clipping area.
|
2021-11-04 21:13:34 +03:00
|
|
|
// top - offset from the top border of a View;
|
|
|
|
// right - offset from the right border of a View;
|
|
|
|
// bottom - offset from the bottom border of a View;
|
|
|
|
// left - offset from the left border of a View;
|
|
|
|
// radius - corner radius, pass nil if you don't need to round corners
|
2021-09-07 17:36:50 +03:00
|
|
|
func InsetClip(top, right, bottom, left SizeUnit, radius RadiusProperty) ClipShape {
|
|
|
|
clip := new(insetClip)
|
|
|
|
clip.init()
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.setRaw(Top, top)
|
|
|
|
clip.setRaw(Right, right)
|
|
|
|
clip.setRaw(Bottom, bottom)
|
|
|
|
clip.setRaw(Left, left)
|
2021-09-07 17:36:50 +03:00
|
|
|
if radius != nil {
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.setRaw(Radius, radius)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
return clip
|
|
|
|
}
|
|
|
|
|
|
|
|
// CircleClip creates a circle View clipping area.
|
|
|
|
func CircleClip(x, y, radius SizeUnit) ClipShape {
|
2022-05-22 12:54:02 +03:00
|
|
|
clip := new(circleClip)
|
2021-09-07 17:36:50 +03:00
|
|
|
clip.init()
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.setRaw(X, x)
|
|
|
|
clip.setRaw(Y, y)
|
|
|
|
clip.setRaw(Radius, radius)
|
2021-09-07 17:36:50 +03:00
|
|
|
return clip
|
|
|
|
}
|
|
|
|
|
|
|
|
// EllipseClip creates a ellipse View clipping area.
|
|
|
|
func EllipseClip(x, y, rx, ry SizeUnit) ClipShape {
|
|
|
|
clip := new(ellipseClip)
|
|
|
|
clip.init()
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.setRaw(X, x)
|
|
|
|
clip.setRaw(Y, y)
|
|
|
|
clip.setRaw(RadiusX, rx)
|
|
|
|
clip.setRaw(RadiusY, ry)
|
2021-09-07 17:36:50 +03:00
|
|
|
return clip
|
|
|
|
}
|
|
|
|
|
|
|
|
// PolygonClip creates a polygon View clipping area.
|
|
|
|
// The elements of the function argument can be or text constants,
|
|
|
|
// or the text representation of SizeUnit, or elements of SizeUnit type.
|
2022-07-26 18:36:00 +03:00
|
|
|
func PolygonClip(points []any) ClipShape {
|
2021-09-07 17:36:50 +03:00
|
|
|
clip := new(polygonClip)
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.init()
|
|
|
|
if polygonClipSet(clip, Points, points) != nil {
|
2021-09-07 17:36:50 +03:00
|
|
|
return clip
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PolygonPointsClip creates a polygon View clipping area.
|
|
|
|
func PolygonPointsClip(points []SizeUnit) ClipShape {
|
|
|
|
clip := new(polygonClip)
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.init()
|
|
|
|
if polygonClipSet(clip, Points, points) != nil {
|
2021-09-07 17:36:50 +03:00
|
|
|
return clip
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func (clip *insetClip) init() {
|
|
|
|
clip.dataProperty.init()
|
|
|
|
clip.set = insetClipSet
|
|
|
|
clip.supportedProperties = []PropertyName{
|
|
|
|
Top, Right, Bottom, Left, Radius,
|
|
|
|
RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
|
|
|
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
|
|
|
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
|
|
|
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func insetClipSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
|
|
|
switch tag {
|
2021-09-07 17:36:50 +03:00
|
|
|
case Top, Right, Bottom, Left:
|
2024-11-13 12:56:39 +03:00
|
|
|
return setSizeProperty(properties, tag, value)
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
case Radius:
|
2024-11-13 12:56:39 +03:00
|
|
|
return setRadiusProperty(properties, value)
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
|
|
|
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
|
|
|
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
|
|
|
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
2024-11-13 12:56:39 +03:00
|
|
|
if setRadiusPropertyElement(properties, tag, value) {
|
|
|
|
return []PropertyName{tag, Radius}
|
|
|
|
}
|
|
|
|
return nil
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ErrorLogF(`"%s" property is not supported by the inset clip shape`, tag)
|
2024-11-13 12:56:39 +03:00
|
|
|
return nil
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (clip *insetClip) String() string {
|
2022-05-22 12:54:02 +03:00
|
|
|
return runStringWriter(clip)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
func (clip *insetClip) writeString(buffer *strings.Builder, indent string) {
|
|
|
|
buffer.WriteString("inset { ")
|
|
|
|
comma := false
|
2024-11-13 12:56:39 +03:00
|
|
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius} {
|
2021-09-07 17:36:50 +03:00
|
|
|
if value, ok := clip.properties[tag]; ok {
|
2022-05-22 12:54:02 +03:00
|
|
|
if comma {
|
|
|
|
buffer.WriteString(", ")
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
2024-11-13 12:56:39 +03:00
|
|
|
buffer.WriteString(string(tag))
|
2022-05-22 12:54:02 +03:00
|
|
|
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 (clip *insetClip) cssStyle(session Session) string {
|
|
|
|
|
|
|
|
buffer := allocStringBuilder()
|
|
|
|
defer freeStringBuilder(buffer)
|
|
|
|
|
|
|
|
leadText := "inset("
|
2024-11-13 12:56:39 +03:00
|
|
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left} {
|
2021-09-07 17:36:50 +03:00
|
|
|
value, _ := sizeProperty(clip, tag, session)
|
|
|
|
buffer.WriteString(leadText)
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(value.cssString("0px", session))
|
2021-09-07 17:36:50 +03:00
|
|
|
leadText = " "
|
|
|
|
}
|
|
|
|
|
|
|
|
if radius := getRadiusProperty(clip); radius != nil {
|
|
|
|
buffer.WriteString(" round ")
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(radius.BoxRadius(session).cssString(session))
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
buffer.WriteRune(')')
|
|
|
|
return buffer.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (clip *insetClip) valid(session Session) bool {
|
2024-11-13 12:56:39 +03:00
|
|
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius, RadiusX, RadiusY} {
|
2021-09-07 17:36:50 +03:00
|
|
|
if value, ok := sizeProperty(clip, tag, session); ok && value.Type != Auto && value.Value != 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func (clip *circleClip) init() {
|
|
|
|
clip.dataProperty.init()
|
|
|
|
clip.set = circleClipSet
|
|
|
|
clip.supportedProperties = []PropertyName{X, Y, Radius}
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func circleClipSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
|
|
|
switch tag {
|
2022-05-22 12:54:02 +03:00
|
|
|
case X, Y, Radius:
|
2024-11-13 12:56:39 +03:00
|
|
|
return setSizeProperty(properties, tag, value)
|
2022-05-22 12:54:02 +03:00
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
ErrorLogF(`"%s" property is not supported by the circle clip shape`, tag)
|
2024-11-13 12:56:39 +03:00
|
|
|
return nil
|
2022-05-22 12:54:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (clip *circleClip) String() string {
|
|
|
|
return runStringWriter(clip)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (clip *circleClip) writeString(buffer *strings.Builder, indent string) {
|
|
|
|
buffer.WriteString("circle { ")
|
|
|
|
comma := false
|
2024-11-13 12:56:39 +03:00
|
|
|
for _, tag := range []PropertyName{Radius, X, Y} {
|
2022-05-22 12:54:02 +03:00
|
|
|
if value, ok := clip.properties[tag]; ok {
|
|
|
|
if comma {
|
|
|
|
buffer.WriteString(", ")
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
2024-11-13 12:56:39 +03:00
|
|
|
buffer.WriteString(string(tag))
|
2022-05-22 12:54:02 +03:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
func (clip *circleClip) cssStyle(session Session) string {
|
|
|
|
|
|
|
|
buffer := allocStringBuilder()
|
|
|
|
defer freeStringBuilder(buffer)
|
|
|
|
|
|
|
|
buffer.WriteString("circle(")
|
|
|
|
r, _ := sizeProperty(clip, Radius, session)
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(r.cssString("50%", session))
|
2022-05-22 12:54:02 +03:00
|
|
|
|
|
|
|
buffer.WriteString(" at ")
|
|
|
|
x, _ := sizeProperty(clip, X, session)
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(x.cssString("50%", session))
|
2022-05-22 12:54:02 +03:00
|
|
|
buffer.WriteRune(' ')
|
|
|
|
|
|
|
|
y, _ := sizeProperty(clip, Y, session)
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(y.cssString("50%", session))
|
2022-05-22 12:54:02 +03:00
|
|
|
buffer.WriteRune(')')
|
|
|
|
|
|
|
|
return buffer.String()
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
func (clip *circleClip) valid(session Session) bool {
|
|
|
|
if value, ok := sizeProperty(clip, Radius, session); ok && value.Value == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func (clip *ellipseClip) init() {
|
|
|
|
clip.dataProperty.init()
|
|
|
|
clip.set = ellipseClipSet
|
|
|
|
clip.supportedProperties = []PropertyName{X, Y, Radius, RadiusX, RadiusY}
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func ellipseClipSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
|
|
|
switch tag {
|
2022-05-22 12:54:02 +03:00
|
|
|
case X, Y, RadiusX, RadiusY:
|
2024-11-13 12:56:39 +03:00
|
|
|
return setSizeProperty(properties, tag, value)
|
2022-05-22 12:54:02 +03:00
|
|
|
|
|
|
|
case Radius:
|
2024-11-13 12:56:39 +03:00
|
|
|
if result := setSizeProperty(properties, RadiusX, value); result != nil {
|
|
|
|
properties.setRaw(RadiusY, properties.getRaw(RadiusX))
|
|
|
|
return append(result, RadiusY)
|
|
|
|
}
|
|
|
|
return nil
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
ErrorLogF(`"%s" property is not supported by the ellipse clip shape`, tag)
|
2024-11-13 12:56:39 +03:00
|
|
|
return nil
|
2022-05-22 12:54:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (clip *ellipseClip) String() string {
|
|
|
|
return runStringWriter(clip)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (clip *ellipseClip) writeString(buffer *strings.Builder, indent string) {
|
|
|
|
buffer.WriteString("ellipse { ")
|
|
|
|
comma := false
|
2024-11-13 12:56:39 +03:00
|
|
|
for _, tag := range []PropertyName{RadiusX, RadiusY, X, Y} {
|
2021-09-07 17:36:50 +03:00
|
|
|
if value, ok := clip.properties[tag]; ok {
|
2022-05-22 12:54:02 +03:00
|
|
|
if comma {
|
|
|
|
buffer.WriteString(", ")
|
|
|
|
}
|
2024-11-13 12:56:39 +03:00
|
|
|
buffer.WriteString(string(tag))
|
2022-05-22 12:54:02 +03:00
|
|
|
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 (clip *ellipseClip) cssStyle(session Session) string {
|
|
|
|
|
|
|
|
buffer := allocStringBuilder()
|
|
|
|
defer freeStringBuilder(buffer)
|
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
rx, _ := sizeProperty(clip, RadiusX, session)
|
|
|
|
ry, _ := sizeProperty(clip, RadiusX, session)
|
|
|
|
buffer.WriteString("ellipse(")
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(rx.cssString("50%", session))
|
2022-05-22 12:54:02 +03:00
|
|
|
buffer.WriteRune(' ')
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(ry.cssString("50%", session))
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
buffer.WriteString(" at ")
|
|
|
|
x, _ := sizeProperty(clip, X, session)
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(x.cssString("50%", session))
|
2021-09-07 17:36:50 +03:00
|
|
|
buffer.WriteRune(' ')
|
|
|
|
|
|
|
|
y, _ := sizeProperty(clip, Y, session)
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(y.cssString("50%", session))
|
2021-09-07 17:36:50 +03:00
|
|
|
buffer.WriteRune(')')
|
|
|
|
|
|
|
|
return buffer.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (clip *ellipseClip) valid(session Session) bool {
|
2022-05-22 12:54:02 +03:00
|
|
|
rx, _ := sizeProperty(clip, RadiusX, session)
|
|
|
|
ry, _ := sizeProperty(clip, RadiusY, session)
|
|
|
|
return rx.Value != 0 && ry.Value != 0
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func (clip *polygonClip) init() {
|
|
|
|
clip.dataProperty.init()
|
|
|
|
clip.set = polygonClipSet
|
|
|
|
clip.supportedProperties = []PropertyName{Points}
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func polygonClipSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
|
|
|
if Points == tag {
|
2021-09-07 17:36:50 +03:00
|
|
|
switch value := value.(type) {
|
2022-07-26 18:36:00 +03:00
|
|
|
case []any:
|
2024-11-13 12:56:39 +03:00
|
|
|
points := make([]any, len(value))
|
2021-09-07 17:36:50 +03:00
|
|
|
for i, val := range value {
|
|
|
|
switch val := val.(type) {
|
|
|
|
case string:
|
|
|
|
if isConstantName(val) {
|
2024-11-13 12:56:39 +03:00
|
|
|
points[i] = val
|
2021-09-07 17:36:50 +03:00
|
|
|
} else if size, ok := StringToSizeUnit(val); ok {
|
2024-11-13 12:56:39 +03:00
|
|
|
points[i] = size
|
2021-09-07 17:36:50 +03:00
|
|
|
} else {
|
|
|
|
notCompatibleType(tag, val)
|
2024-11-13 12:56:39 +03:00
|
|
|
return nil
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
case SizeUnit:
|
2024-11-13 12:56:39 +03:00
|
|
|
points[i] = val
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
default:
|
|
|
|
notCompatibleType(tag, val)
|
2024-11-13 12:56:39 +03:00
|
|
|
points[i] = AutoSize()
|
|
|
|
return nil
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
}
|
2024-11-13 12:56:39 +03:00
|
|
|
properties.setRaw(Points, points)
|
|
|
|
return []PropertyName{tag}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
case []SizeUnit:
|
2024-11-13 12:56:39 +03:00
|
|
|
points := make([]any, len(value))
|
2021-09-07 17:36:50 +03:00
|
|
|
for i, point := range value {
|
2024-11-13 12:56:39 +03:00
|
|
|
points[i] = point
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
2024-11-13 12:56:39 +03:00
|
|
|
properties.setRaw(Points, points)
|
|
|
|
return []PropertyName{tag}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
case string:
|
|
|
|
values := strings.Split(value, ",")
|
2024-11-13 12:56:39 +03:00
|
|
|
points := make([]any, len(values))
|
2021-09-07 17:36:50 +03:00
|
|
|
for i, val := range values {
|
|
|
|
val = strings.Trim(val, " \t\n\r")
|
|
|
|
if isConstantName(val) {
|
2024-11-13 12:56:39 +03:00
|
|
|
points[i] = val
|
2021-09-07 17:36:50 +03:00
|
|
|
} else if size, ok := StringToSizeUnit(val); ok {
|
2024-11-13 12:56:39 +03:00
|
|
|
points[i] = size
|
2021-09-07 17:36:50 +03:00
|
|
|
} else {
|
|
|
|
notCompatibleType(tag, val)
|
2024-11-13 12:56:39 +03:00
|
|
|
return nil
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
}
|
2024-11-13 12:56:39 +03:00
|
|
|
properties.setRaw(Points, points)
|
|
|
|
return []PropertyName{tag}
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
}
|
2024-11-13 12:56:39 +03:00
|
|
|
return nil
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func (clip *polygonClip) String() string {
|
|
|
|
return runStringWriter(clip)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func (clip *polygonClip) points() []any {
|
|
|
|
if value := clip.getRaw(Points); value != nil {
|
|
|
|
if points, ok := value.([]any); ok {
|
|
|
|
return points
|
|
|
|
}
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
2024-11-13 12:56:39 +03:00
|
|
|
return nil
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
func (clip *polygonClip) writeString(buffer *strings.Builder, indent string) {
|
2021-09-07 17:36:50 +03:00
|
|
|
|
2022-05-22 12:54:02 +03:00
|
|
|
buffer.WriteString("inset { ")
|
2021-09-07 17:36:50 +03:00
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
if points := clip.points(); points != nil {
|
|
|
|
buffer.WriteString(string(Points))
|
2022-05-22 12:54:02 +03:00
|
|
|
buffer.WriteString(` = "`)
|
2024-11-13 12:56:39 +03:00
|
|
|
for i, value := range points {
|
2021-09-07 17:36:50 +03:00
|
|
|
if i > 0 {
|
|
|
|
buffer.WriteString(", ")
|
|
|
|
}
|
2022-05-22 12:54:02 +03:00
|
|
|
writePropertyValue(buffer, "", value, indent)
|
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
|
|
|
}
|
2022-05-22 12:54:02 +03:00
|
|
|
buffer.WriteRune('}')
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (clip *polygonClip) cssStyle(session Session) string {
|
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
points := clip.points()
|
|
|
|
count := len(points)
|
2021-09-07 17:36:50 +03:00
|
|
|
if count < 2 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer := allocStringBuilder()
|
|
|
|
defer freeStringBuilder(buffer)
|
|
|
|
|
2022-07-26 18:36:00 +03:00
|
|
|
writePoint := func(value any) {
|
2021-09-07 17:36:50 +03:00
|
|
|
switch value := value.(type) {
|
|
|
|
case string:
|
|
|
|
if val, ok := session.resolveConstants(value); ok {
|
|
|
|
if size, ok := StringToSizeUnit(val); ok {
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(size.cssString("0px", session))
|
2021-09-07 17:36:50 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case SizeUnit:
|
2022-09-05 14:00:07 +03:00
|
|
|
buffer.WriteString(value.cssString("0px", session))
|
2021-09-07 17:36:50 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.WriteString("0px")
|
|
|
|
}
|
|
|
|
|
|
|
|
leadText := "polygon("
|
|
|
|
for i := 1; i < count; i += 2 {
|
|
|
|
buffer.WriteString(leadText)
|
2024-11-13 12:56:39 +03:00
|
|
|
writePoint(points[i-1])
|
2021-09-07 17:36:50 +03:00
|
|
|
buffer.WriteRune(' ')
|
2024-11-13 12:56:39 +03:00
|
|
|
writePoint(points[i])
|
2021-09-07 17:36:50 +03:00
|
|
|
leadText = ", "
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.WriteRune(')')
|
|
|
|
return buffer.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (clip *polygonClip) valid(session Session) bool {
|
2024-11-13 12:56:39 +03:00
|
|
|
return len(clip.points()) > 0
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func parseClipShape(obj DataObject) ClipShape {
|
|
|
|
switch obj.Tag() {
|
|
|
|
case "inset":
|
|
|
|
clip := new(insetClip)
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.init()
|
|
|
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius, RadiusX, RadiusY} {
|
|
|
|
if value, ok := obj.PropertyValue(string(tag)); ok {
|
|
|
|
insetClipSet(clip, tag, value)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return clip
|
|
|
|
|
|
|
|
case "circle":
|
|
|
|
clip := new(ellipseClip)
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.init()
|
|
|
|
for _, tag := range []PropertyName{X, Y, Radius} {
|
|
|
|
if value, ok := obj.PropertyValue(string(tag)); ok {
|
|
|
|
circleClipSet(clip, tag, value)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return clip
|
|
|
|
|
|
|
|
case "ellipse":
|
|
|
|
clip := new(ellipseClip)
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.init()
|
|
|
|
for _, tag := range []PropertyName{X, Y, RadiusX, RadiusY} {
|
|
|
|
if value, ok := obj.PropertyValue(string(tag)); ok {
|
|
|
|
ellipseClipSet(clip, tag, value)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return clip
|
|
|
|
|
|
|
|
case "polygon":
|
|
|
|
clip := new(ellipseClip)
|
2024-11-13 12:56:39 +03:00
|
|
|
clip.init()
|
|
|
|
if value, ok := obj.PropertyValue(string(Points)); ok {
|
|
|
|
polygonClipSet(clip, Points, value)
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
return clip
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func setClipShapeProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
2021-09-07 17:36:50 +03:00
|
|
|
switch value := value.(type) {
|
|
|
|
case ClipShape:
|
2024-11-13 12:56:39 +03:00
|
|
|
properties.setRaw(tag, value)
|
|
|
|
return []PropertyName{tag}
|
2021-09-07 17:36:50 +03:00
|
|
|
|
|
|
|
case string:
|
|
|
|
if isConstantName(value) {
|
2024-11-13 12:56:39 +03:00
|
|
|
properties.setRaw(tag, value)
|
|
|
|
return []PropertyName{tag}
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if obj := NewDataObject(value); obj == nil {
|
|
|
|
if clip := parseClipShape(obj); clip != nil {
|
2024-11-13 12:56:39 +03:00
|
|
|
properties.setRaw(tag, clip)
|
|
|
|
return []PropertyName{tag}
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case DataObject:
|
|
|
|
if clip := parseClipShape(value); clip != nil {
|
2024-11-13 12:56:39 +03:00
|
|
|
properties.setRaw(tag, clip)
|
|
|
|
return []PropertyName{tag}
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
case DataValue:
|
|
|
|
if value.IsObject() {
|
|
|
|
if clip := parseClipShape(value.Object()); clip != nil {
|
2024-11-13 12:56:39 +03:00
|
|
|
properties.setRaw(tag, clip)
|
|
|
|
return []PropertyName{tag}
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
notCompatibleType(tag, value)
|
2024-11-13 12:56:39 +03:00
|
|
|
return nil
|
2021-09-07 17:36:50 +03:00
|
|
|
}
|
|
|
|
|
2024-11-13 12:56:39 +03:00
|
|
|
func getClipShape(prop Properties, tag PropertyName, session Session) ClipShape {
|
2021-09-07 17:36:50 +03:00
|
|
|
if value := prop.getRaw(tag); value != nil {
|
|
|
|
switch value := value.(type) {
|
|
|
|
case ClipShape:
|
|
|
|
return value
|
|
|
|
|
|
|
|
case string:
|
|
|
|
if text, ok := session.resolveConstants(value); ok {
|
|
|
|
if obj := NewDataObject(text); obj == nil {
|
|
|
|
return parseClipShape(obj)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetClip returns a View clipping area.
|
2022-08-31 22:17:46 +03:00
|
|
|
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
|
|
|
func GetClip(view View, subviewID ...string) ClipShape {
|
2024-11-24 16:43:31 +03:00
|
|
|
if view = getSubview(view, subviewID); view != nil {
|
2021-09-07 17:36:50 +03:00
|
|
|
return getClipShape(view, Clip, view.Session())
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetShapeOutside returns a shape around which adjacent inline content.
|
2022-08-31 22:17:46 +03:00
|
|
|
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
|
|
|
func GetShapeOutside(view View, subviewID ...string) ClipShape {
|
2024-11-24 16:43:31 +03:00
|
|
|
if view = getSubview(view, subviewID); view != nil {
|
2021-09-07 17:36:50 +03:00
|
|
|
return getClipShape(view, ShapeOutside, view.Session())
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|