mirror of https://github.com/anoshenko/rui.git
400 lines
12 KiB
Go
400 lines
12 KiB
Go
package rui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Constants for [ViewShadow] specific properties
|
|
const (
|
|
// ColorTag is the constant for "color" property tag.
|
|
//
|
|
// Used by `ColumnSeparatorProperty`, `BorderProperty`, `OutlineProperty`, `ViewShadow`.
|
|
//
|
|
// Usage in `ColumnSeparatorProperty`:
|
|
// Line color.
|
|
//
|
|
// Supported types: `Color`, `string`.
|
|
//
|
|
// Internal type is `Color`, other types converted to it during assignment.
|
|
// See `Color` description for more details.
|
|
//
|
|
// Usage in `BorderProperty`:
|
|
// Border line color.
|
|
//
|
|
// Supported types: `Color`, `string`.
|
|
//
|
|
// Internal type is `Color`, other types converted to it during assignment.
|
|
// See `Color` description for more details.
|
|
//
|
|
// Usage in `OutlineProperty`:
|
|
// Outline line color.
|
|
//
|
|
// Supported types: `Color`, `string`.
|
|
//
|
|
// Internal type is `Color`, other types converted to it during assignment.
|
|
// See `Color` description for more details.
|
|
//
|
|
// Usage in `ViewShadow`:
|
|
// Color property of the shadow.
|
|
//
|
|
// Supported types: `Color`, `string`.
|
|
//
|
|
// Internal type is `Color`, other types converted to it during assignment.
|
|
// See `Color` description for more details.
|
|
ColorTag PropertyName = "color"
|
|
|
|
// Inset is the constant for "inset" property tag.
|
|
//
|
|
// Used by `ViewShadow`.
|
|
// Controls whether to draw shadow inside the frame or outside. Inset shadows are drawn inside the border(even transparent
|
|
// ones), above the background, but below content.
|
|
//
|
|
// Supported types: `bool`, `int`, `string`.
|
|
//
|
|
// Values:
|
|
// `true` or `1` or "true", "yes", "on", "1" - Drop shadow inside the frame(as if the content was depressed inside the box).
|
|
// `false` or `0` or "false", "no", "off", "0" - Shadow is assumed to be a drop shadow(as if the box were raised above the content).
|
|
Inset PropertyName = "inset"
|
|
|
|
// XOffset is the constant for "x-offset" property tag.
|
|
//
|
|
// Used by `ViewShadow`.
|
|
// Determines the shadow horizontal offset. Negative values place the shadow to the left of the element.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
XOffset PropertyName = "x-offset"
|
|
|
|
// YOffset is the constant for "y-offset" property tag.
|
|
//
|
|
// Used by `ViewShadow`.
|
|
// Determines the shadow vertical offset. Negative values place the shadow above the element.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
YOffset PropertyName = "y-offset"
|
|
|
|
// BlurRadius is the constant for "blur" property tag.
|
|
//
|
|
// Used by `ViewShadow`.
|
|
// Determines the radius of the blur effect. The larger this value, the bigger the blur, so the shadow becomes bigger and
|
|
// lighter. Negative values are not allowed.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
BlurRadius PropertyName = "blur"
|
|
|
|
// SpreadRadius is the constant for "spread-radius" property tag.
|
|
//
|
|
// Used by `ViewShadow`.
|
|
// Positive values will cause the shadow to expand and grow bigger, negative values will cause the shadow to shrink.
|
|
//
|
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
//
|
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
// See `SizeUnit` description for more details.
|
|
SpreadRadius PropertyName = "spread-radius"
|
|
)
|
|
|
|
// ViewShadow contains attributes of the view shadow
|
|
type ViewShadow interface {
|
|
Properties
|
|
fmt.Stringer
|
|
stringWriter
|
|
cssStyle(buffer *strings.Builder, session Session, lead string) bool
|
|
cssTextStyle(buffer *strings.Builder, session Session, lead string) bool
|
|
visible(session Session) bool
|
|
}
|
|
|
|
type viewShadowData struct {
|
|
dataProperty
|
|
}
|
|
|
|
// NewViewShadow create the new shadow for a view. Arguments:
|
|
//
|
|
// offsetX, offsetY is x and y offset of the shadow;
|
|
//
|
|
// blurRadius is the blur radius of the shadow;
|
|
//
|
|
// spreadRadius is the spread radius of the shadow;
|
|
//
|
|
// color is the color of the shadow.
|
|
func NewViewShadow(offsetX, offsetY, blurRadius, spreadRadius SizeUnit, color Color) ViewShadow {
|
|
return NewShadowWithParams(Params{
|
|
XOffset: offsetX,
|
|
YOffset: offsetY,
|
|
BlurRadius: blurRadius,
|
|
SpreadRadius: spreadRadius,
|
|
ColorTag: color,
|
|
})
|
|
}
|
|
|
|
// NewInsetViewShadow create the new inset shadow for a view. Arguments:
|
|
//
|
|
// offsetX, offsetY is x and y offset of the shadow;
|
|
//
|
|
// blurRadius is the blur radius of the shadow;
|
|
//
|
|
// spreadRadius is the spread radius of the shadow;
|
|
//
|
|
// color is the color of the shadow.
|
|
func NewInsetViewShadow(offsetX, offsetY, blurRadius, spreadRadius SizeUnit, color Color) ViewShadow {
|
|
return NewShadowWithParams(Params{
|
|
XOffset: offsetX,
|
|
YOffset: offsetY,
|
|
BlurRadius: blurRadius,
|
|
SpreadRadius: spreadRadius,
|
|
ColorTag: color,
|
|
Inset: true,
|
|
})
|
|
}
|
|
|
|
// NewTextShadow create the new text shadow. Arguments:
|
|
//
|
|
// offsetX, offsetY is the x- and y-offset of the shadow;
|
|
//
|
|
// blurRadius is the blur radius of the shadow;
|
|
//
|
|
// color is the color of the shadow.
|
|
func NewTextShadow(offsetX, offsetY, blurRadius SizeUnit, color Color) ViewShadow {
|
|
return NewShadowWithParams(Params{
|
|
XOffset: offsetX,
|
|
YOffset: offsetY,
|
|
BlurRadius: blurRadius,
|
|
ColorTag: color,
|
|
})
|
|
}
|
|
|
|
// NewShadowWithParams create the new shadow for a view.
|
|
// The following properties can be used:
|
|
//
|
|
// "color" (ColorTag). Determines the color of the shadow (Color);
|
|
//
|
|
// "x-offset" (XOffset). Determines the shadow horizontal offset (SizeUnit);
|
|
//
|
|
// "y-offset" (YOffset). Determines the shadow vertical offset (SizeUnit);
|
|
//
|
|
// "blur" (BlurRadius). Determines the radius of the blur effect (SizeUnit);
|
|
//
|
|
// "spread-radius" (SpreadRadius). Positive values (SizeUnit) will cause the shadow to expand and grow bigger, negative values will cause the shadow to shrink;
|
|
//
|
|
// "inset" (Inset). Controls (bool) whether to draw shadow inside the frame or outside.
|
|
func NewShadowWithParams(params Params) ViewShadow {
|
|
shadow := new(viewShadowData)
|
|
shadow.init()
|
|
|
|
if params != nil {
|
|
for _, tag := range []PropertyName{ColorTag, Inset, XOffset, YOffset, BlurRadius, SpreadRadius} {
|
|
if value, ok := params[tag]; ok && value != nil {
|
|
shadow.set(shadow, tag, value)
|
|
}
|
|
}
|
|
}
|
|
return shadow
|
|
}
|
|
|
|
// parseViewShadow parse DataObject and create ViewShadow object
|
|
func parseViewShadow(object DataObject) ViewShadow {
|
|
shadow := new(viewShadowData)
|
|
shadow.init()
|
|
parseProperties(shadow, object)
|
|
return shadow
|
|
}
|
|
|
|
func (shadow *viewShadowData) init() {
|
|
shadow.dataProperty.init()
|
|
shadow.supportedProperties = []PropertyName{ColorTag, Inset, XOffset, YOffset, BlurRadius, SpreadRadius}
|
|
}
|
|
|
|
func (shadow *viewShadowData) cssStyle(buffer *strings.Builder, session Session, lead string) bool {
|
|
color, _ := colorProperty(shadow, ColorTag, session)
|
|
offsetX, _ := sizeProperty(shadow, XOffset, session)
|
|
offsetY, _ := sizeProperty(shadow, YOffset, session)
|
|
blurRadius, _ := sizeProperty(shadow, BlurRadius, session)
|
|
spreadRadius, _ := sizeProperty(shadow, SpreadRadius, session)
|
|
|
|
if color.Alpha() == 0 ||
|
|
((offsetX.Type == Auto || offsetX.Value == 0) &&
|
|
(offsetY.Type == Auto || offsetY.Value == 0) &&
|
|
(blurRadius.Type == Auto || blurRadius.Value == 0) &&
|
|
(spreadRadius.Type == Auto || spreadRadius.Value == 0)) {
|
|
return false
|
|
}
|
|
|
|
buffer.WriteString(lead)
|
|
if inset, _ := boolProperty(shadow, Inset, session); inset {
|
|
buffer.WriteString("inset ")
|
|
}
|
|
|
|
buffer.WriteString(offsetX.cssString("0", session))
|
|
buffer.WriteByte(' ')
|
|
buffer.WriteString(offsetY.cssString("0", session))
|
|
buffer.WriteByte(' ')
|
|
buffer.WriteString(blurRadius.cssString("0", session))
|
|
buffer.WriteByte(' ')
|
|
buffer.WriteString(spreadRadius.cssString("0", session))
|
|
buffer.WriteByte(' ')
|
|
buffer.WriteString(color.cssString())
|
|
return true
|
|
}
|
|
|
|
func (shadow *viewShadowData) cssTextStyle(buffer *strings.Builder, session Session, lead string) bool {
|
|
color, _ := colorProperty(shadow, ColorTag, session)
|
|
offsetX, _ := sizeProperty(shadow, XOffset, session)
|
|
offsetY, _ := sizeProperty(shadow, YOffset, session)
|
|
blurRadius, _ := sizeProperty(shadow, BlurRadius, session)
|
|
|
|
if color.Alpha() == 0 ||
|
|
((offsetX.Type == Auto || offsetX.Value == 0) &&
|
|
(offsetY.Type == Auto || offsetY.Value == 0) &&
|
|
(blurRadius.Type == Auto || blurRadius.Value == 0)) {
|
|
return false
|
|
}
|
|
|
|
buffer.WriteString(lead)
|
|
buffer.WriteString(offsetX.cssString("0", session))
|
|
buffer.WriteByte(' ')
|
|
buffer.WriteString(offsetY.cssString("0", session))
|
|
buffer.WriteByte(' ')
|
|
buffer.WriteString(blurRadius.cssString("0", session))
|
|
buffer.WriteByte(' ')
|
|
buffer.WriteString(color.cssString())
|
|
return true
|
|
}
|
|
|
|
func (shadow *viewShadowData) visible(session Session) bool {
|
|
color, _ := colorProperty(shadow, ColorTag, session)
|
|
offsetX, _ := sizeProperty(shadow, XOffset, session)
|
|
offsetY, _ := sizeProperty(shadow, YOffset, session)
|
|
blurRadius, _ := sizeProperty(shadow, BlurRadius, session)
|
|
spreadRadius, _ := sizeProperty(shadow, SpreadRadius, session)
|
|
|
|
if color.Alpha() == 0 ||
|
|
((offsetX.Type == Auto || offsetX.Value == 0) &&
|
|
(offsetY.Type == Auto || offsetY.Value == 0) &&
|
|
(blurRadius.Type == Auto || blurRadius.Value == 0) &&
|
|
(spreadRadius.Type == Auto || spreadRadius.Value == 0)) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (shadow *viewShadowData) String() string {
|
|
return runStringWriter(shadow)
|
|
}
|
|
|
|
func (shadow *viewShadowData) writeString(buffer *strings.Builder, indent string) {
|
|
buffer.WriteString("_{ ")
|
|
comma := false
|
|
for _, tag := range shadow.AllTags() {
|
|
if value, ok := shadow.properties[tag]; ok {
|
|
if comma {
|
|
buffer.WriteString(", ")
|
|
}
|
|
buffer.WriteString(string(tag))
|
|
buffer.WriteString(" = ")
|
|
writePropertyValue(buffer, tag, value, indent)
|
|
comma = true
|
|
}
|
|
}
|
|
buffer.WriteString(" }")
|
|
}
|
|
|
|
func setShadowProperty(properties Properties, tag PropertyName, value any) bool {
|
|
|
|
if value == nil {
|
|
properties.setRaw(tag, nil)
|
|
return true
|
|
}
|
|
|
|
switch value := value.(type) {
|
|
case ViewShadow:
|
|
properties.setRaw(tag, []ViewShadow{value})
|
|
|
|
case []ViewShadow:
|
|
if len(value) == 0 {
|
|
properties.setRaw(tag, nil)
|
|
} else {
|
|
properties.setRaw(tag, value)
|
|
}
|
|
|
|
case DataValue:
|
|
if !value.IsObject() {
|
|
return false
|
|
}
|
|
properties.setRaw(tag, []ViewShadow{parseViewShadow(value.Object())})
|
|
|
|
case []DataValue:
|
|
shadows := []ViewShadow{}
|
|
for _, data := range value {
|
|
if data.IsObject() {
|
|
shadows = append(shadows, parseViewShadow(data.Object()))
|
|
}
|
|
}
|
|
if len(shadows) == 0 {
|
|
return false
|
|
}
|
|
properties.setRaw(tag, shadows)
|
|
|
|
case string:
|
|
obj := NewDataObject(value)
|
|
if obj == nil {
|
|
notCompatibleType(tag, value)
|
|
return false
|
|
}
|
|
properties.setRaw(tag, []ViewShadow{parseViewShadow(obj)})
|
|
|
|
default:
|
|
notCompatibleType(tag, value)
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func getShadows(properties Properties, tag PropertyName) []ViewShadow {
|
|
if value := properties.Get(tag); value != nil {
|
|
switch value := value.(type) {
|
|
case []ViewShadow:
|
|
return value
|
|
|
|
case ViewShadow:
|
|
return []ViewShadow{value}
|
|
}
|
|
}
|
|
return []ViewShadow{}
|
|
}
|
|
|
|
func shadowCSS(properties Properties, tag PropertyName, session Session) string {
|
|
shadows := getShadows(properties, tag)
|
|
if len(shadows) == 0 {
|
|
return ""
|
|
}
|
|
|
|
buffer := allocStringBuilder()
|
|
defer freeStringBuilder(buffer)
|
|
|
|
lead := ""
|
|
if tag == Shadow {
|
|
for _, shadow := range shadows {
|
|
if shadow.cssStyle(buffer, session, lead) {
|
|
lead = ", "
|
|
}
|
|
}
|
|
} else {
|
|
for _, shadow := range shadows {
|
|
if shadow.cssTextStyle(buffer, session, lead) {
|
|
lead = ", "
|
|
}
|
|
}
|
|
}
|
|
return buffer.String()
|
|
}
|