rui_orig/bounds.go

383 lines
9.7 KiB
Go
Raw Normal View History

2021-09-07 17:36:50 +03:00
package rui
import (
"fmt"
"strings"
)
// BorderProperty is an interface of a bounds property data
2021-09-07 17:36:50 +03:00
type BoundsProperty interface {
Properties
fmt.Stringer
2022-05-22 12:54:02 +03:00
stringWriter
// Bounds returns top, right, bottom and left size of the bounds
2021-09-07 17:36:50 +03:00
Bounds(session Session) Bounds
}
type boundsPropertyData struct {
2024-11-13 12:56:39 +03:00
dataProperty
2021-09-07 17:36:50 +03:00
}
2024-10-21 18:37:35 +03:00
// NewBoundsProperty creates the new BoundsProperty object.
// The following SizeUnit properties can be used: "left" (Left), "right" (Right), "top" (Top), and "bottom" (Bottom).
2021-09-07 17:36:50 +03:00
func NewBoundsProperty(params Params) BoundsProperty {
bounds := new(boundsPropertyData)
2024-11-13 12:56:39 +03:00
bounds.init()
2021-09-07 17:36:50 +03:00
if params != nil {
2024-11-13 12:56:39 +03:00
for _, tag := range bounds.supportedProperties {
if value, ok := params[tag]; ok && value != nil {
bounds.set(bounds, tag, value)
2021-09-07 17:36:50 +03:00
}
}
}
return bounds
}
2024-11-13 12:56:39 +03:00
func (bounds *boundsPropertyData) init() {
bounds.dataProperty.init()
bounds.normalize = normalizeBoundsTag
bounds.supportedProperties = []PropertyName{Top, Right, Bottom, Left}
}
func normalizeBoundsTag(tag PropertyName) PropertyName {
tag = defaultNormalize(tag)
2021-09-07 17:36:50 +03:00
switch tag {
case MarginTop, PaddingTop, CellPaddingTop,
"top-margin", "top-padding", "top-cell-padding":
tag = Top
case MarginRight, PaddingRight, CellPaddingRight,
"right-margin", "right-padding", "right-cell-padding":
tag = Right
case MarginBottom, PaddingBottom, CellPaddingBottom,
"bottom-margin", "bottom-padding", "bottom-cell-padding":
tag = Bottom
case MarginLeft, PaddingLeft, CellPaddingLeft,
"left-margin", "left-padding", "left-cell-padding":
tag = Left
}
return tag
}
2022-05-22 12:54:02 +03:00
func (bounds *boundsPropertyData) String() string {
return runStringWriter(bounds)
}
2021-09-07 17:36:50 +03:00
2022-05-22 12:54:02 +03:00
func (bounds *boundsPropertyData) writeString(buffer *strings.Builder, indent string) {
buffer.WriteString("_{ ")
comma := false
2024-11-13 12:56:39 +03:00
for _, tag := range []PropertyName{Top, Right, Bottom, Left} {
2021-09-07 17:36:50 +03:00
if value, ok := bounds.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 (bounds *boundsPropertyData) Bounds(session Session) Bounds {
top, _ := sizeProperty(bounds, Top, session)
right, _ := sizeProperty(bounds, Right, session)
bottom, _ := sizeProperty(bounds, Bottom, session)
left, _ := sizeProperty(bounds, Left, session)
return Bounds{Top: top, Right: right, Bottom: bottom, Left: left}
}
// Bounds describe bounds of rectangle.
type Bounds struct {
Top, Right, Bottom, Left SizeUnit
}
// DefaultBounds return bounds with Top, Right, Bottom and Left fields set to Auto
func DefaultBounds() Bounds {
return Bounds{
Top: SizeUnit{Type: Auto, Value: 0},
Right: SizeUnit{Type: Auto, Value: 0},
Bottom: SizeUnit{Type: Auto, Value: 0},
Left: SizeUnit{Type: Auto, Value: 0},
}
}
// SetAll set the Top, Right, Bottom and Left field to the equal value
func (bounds *Bounds) SetAll(value SizeUnit) {
bounds.Top = value
bounds.Right = value
bounds.Bottom = value
bounds.Left = value
}
2024-11-13 12:56:39 +03:00
func (bounds *Bounds) setFromProperties(tag, topTag, rightTag, bottomTag, leftTag PropertyName, properties Properties, session Session) {
2021-09-07 17:36:50 +03:00
bounds.Top = AutoSize()
if size, ok := sizeProperty(properties, tag, session); ok {
bounds.Top = size
}
bounds.Right = bounds.Top
bounds.Bottom = bounds.Top
bounds.Left = bounds.Top
if size, ok := sizeProperty(properties, topTag, session); ok {
bounds.Top = size
}
if size, ok := sizeProperty(properties, rightTag, session); ok {
bounds.Right = size
}
if size, ok := sizeProperty(properties, bottomTag, session); ok {
bounds.Bottom = size
}
if size, ok := sizeProperty(properties, leftTag, session); ok {
bounds.Left = size
}
}
2022-05-22 12:54:02 +03:00
/*
2021-09-07 17:36:50 +03:00
func (bounds *Bounds) allFieldsAuto() bool {
return bounds.Left.Type == Auto &&
bounds.Top.Type == Auto &&
bounds.Right.Type == Auto &&
bounds.Bottom.Type == Auto
}
func (bounds *Bounds) allFieldsZero() bool {
return (bounds.Left.Type == Auto || bounds.Left.Value == 0) &&
(bounds.Top.Type == Auto || bounds.Top.Value == 0) &&
(bounds.Right.Type == Auto || bounds.Right.Value == 0) &&
(bounds.Bottom.Type == Auto || bounds.Bottom.Value == 0)
}
*/
func (bounds *Bounds) allFieldsEqual() bool {
if bounds.Left.Type == bounds.Top.Type &&
bounds.Left.Type == bounds.Right.Type &&
bounds.Left.Type == bounds.Bottom.Type {
return bounds.Left.Type == Auto ||
(bounds.Left.Value == bounds.Top.Value &&
bounds.Left.Value == bounds.Right.Value &&
bounds.Left.Value == bounds.Bottom.Value)
}
return false
}
2022-05-22 12:54:02 +03:00
/*
2021-09-07 17:36:50 +03:00
func (bounds Bounds) writeCSSString(buffer *strings.Builder, textForAuto string) {
buffer.WriteString(bounds.Top.cssString(textForAuto))
if !bounds.allFieldsEqual() {
buffer.WriteRune(' ')
buffer.WriteString(bounds.Right.cssString(textForAuto))
buffer.WriteRune(' ')
buffer.WriteString(bounds.Bottom.cssString(textForAuto))
buffer.WriteRune(' ')
buffer.WriteString(bounds.Left.cssString(textForAuto))
}
}
2022-05-22 12:54:02 +03:00
*/
2021-09-07 17:36:50 +03:00
// String convert Bounds to string
func (bounds *Bounds) String() string {
if bounds.allFieldsEqual() {
return bounds.Top.String()
}
return bounds.Top.String() + "," + bounds.Right.String() + "," +
bounds.Bottom.String() + "," + bounds.Left.String()
}
2024-11-13 12:56:39 +03:00
func (bounds *Bounds) cssValue(tag PropertyName, builder cssBuilder, session Session) {
2021-09-07 17:36:50 +03:00
if bounds.allFieldsEqual() {
2024-11-13 12:56:39 +03:00
builder.add(string(tag), bounds.Top.cssString("0", session))
2021-09-07 17:36:50 +03:00
} else {
2024-11-13 12:56:39 +03:00
builder.addValues(string(tag), " ",
bounds.Top.cssString("0", session),
bounds.Right.cssString("0", session),
bounds.Bottom.cssString("0", session),
bounds.Left.cssString("0", session))
2021-09-07 17:36:50 +03:00
}
}
func (bounds *Bounds) cssString(session Session) string {
2021-09-07 17:36:50 +03:00
var builder cssValueBuilder
bounds.cssValue("", &builder, session)
2021-09-07 17:36:50 +03:00
return builder.finish()
}
2024-11-13 12:56:39 +03:00
func setBoundsProperty(properties Properties, tag PropertyName, value any) []PropertyName {
if !setSimpleProperty(properties, tag, value) {
2021-09-07 17:36:50 +03:00
switch value := value.(type) {
case string:
if strings.Contains(value, ",") {
values := split4Values(value)
count := len(values)
switch count {
case 1:
value = values[0]
case 4:
bounds := NewBoundsProperty(nil)
2024-11-13 12:56:39 +03:00
for i, tag := range []PropertyName{Top, Right, Bottom, Left} {
2021-09-07 17:36:50 +03:00
if !bounds.Set(tag, values[i]) {
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(tag, bounds)
return []PropertyName{tag}
2021-09-07 17:36:50 +03:00
default:
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
return setSizeProperty(properties, tag, value)
2021-09-07 17:36:50 +03:00
case SizeUnit:
2024-11-13 12:56:39 +03:00
properties.setRaw(tag, value)
2021-09-07 17:36:50 +03:00
2022-08-16 11:40:42 +03:00
case float32:
2024-11-13 12:56:39 +03:00
properties.setRaw(tag, Px(float64(value)))
2022-08-16 11:40:42 +03:00
case float64:
2024-11-13 12:56:39 +03:00
properties.setRaw(tag, Px(value))
2022-08-16 11:40:42 +03:00
2021-09-07 17:36:50 +03:00
case Bounds:
2022-05-23 15:22:14 +03:00
bounds := NewBoundsProperty(nil)
if value.Top.Type != Auto {
2024-11-13 12:56:39 +03:00
bounds.setRaw(Top, value.Top)
2022-05-23 15:22:14 +03:00
}
if value.Right.Type != Auto {
2024-11-13 12:56:39 +03:00
bounds.setRaw(Right, value.Right)
2022-05-23 15:22:14 +03:00
}
if value.Bottom.Type != Auto {
2024-11-13 12:56:39 +03:00
bounds.setRaw(Bottom, value.Bottom)
2022-05-23 15:22:14 +03:00
}
if value.Left.Type != Auto {
2024-11-13 12:56:39 +03:00
bounds.setRaw(Left, value.Left)
2022-05-23 15:22:14 +03:00
}
2024-11-13 12:56:39 +03:00
properties.setRaw(tag, bounds)
2021-09-07 17:36:50 +03:00
case BoundsProperty:
2024-11-13 12:56:39 +03:00
properties.setRaw(tag, value)
2021-09-07 17:36:50 +03:00
case DataObject:
bounds := NewBoundsProperty(nil)
2024-11-13 12:56:39 +03:00
for _, tag := range []PropertyName{Top, Right, Bottom, Left} {
if text, ok := value.PropertyValue(string(tag)); ok {
2021-09-07 17:36:50 +03:00
if !bounds.Set(tag, text) {
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
properties.setRaw(tag, bounds)
2021-09-07 17:36:50 +03:00
default:
2022-08-16 11:40:42 +03:00
if n, ok := isInt(value); ok {
2024-11-13 12:56:39 +03:00
properties.setRaw(tag, Px(float64(n)))
2022-08-16 11:40:42 +03:00
} else {
notCompatibleType(tag, value)
2024-11-13 12:56:39 +03:00
return nil
}
}
}
return []PropertyName{tag}
}
func removeBoundsPropertySide(properties Properties, mainTag, sideTag PropertyName) []PropertyName {
if bounds := getBoundsProperty(properties, mainTag); bounds != nil {
if bounds.getRaw(sideTag) != nil {
bounds.Remove(sideTag)
if bounds.empty() {
bounds = nil
2022-08-16 11:40:42 +03:00
}
2024-11-13 12:56:39 +03:00
properties.setRaw(mainTag, bounds)
return []PropertyName{mainTag, sideTag}
2021-09-07 17:36:50 +03:00
}
}
2024-11-13 12:56:39 +03:00
return []PropertyName{}
}
func setBoundsPropertySide(properties Properties, mainTag, sideTag PropertyName, value any) []PropertyName {
if value == nil {
return removeBoundsPropertySide(properties, mainTag, sideTag)
}
bounds := getBoundsProperty(properties, mainTag)
if bounds == nil {
bounds = NewBoundsProperty(nil)
}
if bounds.Set(sideTag, value) {
properties.setRaw(mainTag, bounds)
return []PropertyName{mainTag, sideTag}
}
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
notCompatibleType(sideTag, value)
return nil
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
func getBoundsProperty(properties Properties, tag PropertyName) BoundsProperty {
if value := properties.getRaw(tag); value != nil {
2021-09-07 17:36:50 +03:00
switch value := value.(type) {
case string:
bounds := NewBoundsProperty(nil)
2024-11-13 12:56:39 +03:00
for _, t := range []PropertyName{Top, Right, Bottom, Left} {
2021-09-07 17:36:50 +03:00
bounds.Set(t, value)
}
return bounds
case SizeUnit:
bounds := NewBoundsProperty(nil)
2024-11-13 12:56:39 +03:00
for _, t := range []PropertyName{Top, Right, Bottom, Left} {
2021-09-07 17:36:50 +03:00
bounds.Set(t, value)
}
return bounds
case BoundsProperty:
return value
case Bounds:
return NewBoundsProperty(Params{
Top: value.Top,
Right: value.Right,
Bottom: value.Bottom,
Left: value.Left})
}
}
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 getBounds(properties Properties, tag PropertyName, session Session) (Bounds, bool) {
2021-09-07 17:36:50 +03:00
if value := properties.Get(tag); value != nil {
switch value := value.(type) {
case string:
if text, ok := session.resolveConstants(value); ok {
if size, ok := StringToSizeUnit(text); ok {
return Bounds{Left: size, Top: size, Right: size, Bottom: size}, true
}
}
case SizeUnit:
return Bounds{Left: value, Top: value, Right: value, Bottom: value}, true
case Bounds:
return value, true
case BoundsProperty:
return value.Bounds(session), true
default:
notCompatibleType(tag, value)
}
}
return DefaultBounds(), false
}