2021-09-07 17:36:50 +03:00
package rui
import (
"fmt"
"strings"
)
2024-12-03 10:25:55 +03:00
// Constants for [ShadowProperty] specific properties
2021-09-07 17:36:50 +03:00
const (
2024-09-18 13:50:06 +03:00
// ColorTag is the constant for "color" property tag.
//
2024-12-03 10:25:55 +03:00
// Used by `ColumnSeparatorProperty`, `BorderProperty`, `OutlineProperty`, `ShadowProperty`.
2024-09-18 13:50:06 +03:00
//
// 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.
//
2024-12-03 10:25:55 +03:00
// Usage in `ShadowProperty`:
2024-09-18 13:50:06 +03:00
// 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.
2024-11-13 12:56:39 +03:00
ColorTag PropertyName = "color"
2024-09-18 13:50:06 +03:00
// Inset is the constant for "inset" property tag.
//
2024-12-03 10:25:55 +03:00
// Used by `ShadowProperty`.
2024-10-21 18:37:35 +03:00
// Controls whether to draw shadow inside the frame or outside. Inset shadows are drawn inside the border(even transparent
2024-09-18 13:50:06 +03:00
// 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).
2024-11-13 12:56:39 +03:00
Inset PropertyName = "inset"
2024-09-18 13:50:06 +03:00
// XOffset is the constant for "x-offset" property tag.
//
2024-12-03 10:25:55 +03:00
// Used by `ShadowProperty`.
2024-09-18 13:50:06 +03:00
// 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.
2024-11-13 12:56:39 +03:00
XOffset PropertyName = "x-offset"
2024-09-18 13:50:06 +03:00
// YOffset is the constant for "y-offset" property tag.
//
2024-12-03 10:25:55 +03:00
// Used by `ShadowProperty`.
2024-09-18 13:50:06 +03:00
// 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.
2024-11-13 12:56:39 +03:00
YOffset PropertyName = "y-offset"
2024-09-18 13:50:06 +03:00
// BlurRadius is the constant for "blur" property tag.
//
2024-12-03 10:25:55 +03:00
// Used by `ShadowProperty`.
2024-10-21 18:37:35 +03:00
// Determines the radius of the blur effect. The larger this value, the bigger the blur, so the shadow becomes bigger and
2024-09-18 13:50:06 +03:00
// 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.
2024-11-13 12:56:39 +03:00
BlurRadius PropertyName = "blur"
2024-09-18 13:50:06 +03:00
// SpreadRadius is the constant for "spread-radius" property tag.
//
2024-12-03 10:25:55 +03:00
// Used by `ShadowProperty`.
2024-09-18 13:50:06 +03:00
// 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.
2024-11-13 12:56:39 +03:00
SpreadRadius PropertyName = "spread-radius"
2021-09-07 17:36:50 +03:00
)
2024-12-03 10:25:55 +03:00
// ShadowProperty contains attributes of the view shadow
type ShadowProperty interface {
2021-09-07 17:36:50 +03:00
Properties
fmt . Stringer
2022-05-22 12:54:02 +03:00
stringWriter
2021-09-07 17:36:50 +03:00
cssStyle ( buffer * strings . Builder , session Session , lead string ) bool
cssTextStyle ( buffer * strings . Builder , session Session , lead string ) bool
visible ( session Session ) bool
}
2024-12-03 10:25:55 +03:00
type shadowPropertyData struct {
2024-11-13 12:56:39 +03:00
dataProperty
2021-09-07 17:36:50 +03:00
}
2024-12-03 10:25:55 +03:00
// NewShadow create the new shadow property for a view. Arguments:
2024-10-21 18:37:35 +03:00
//
// 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.
2024-12-03 10:25:55 +03:00
func NewShadow [ xOffsetType SizeUnit | int | float64 , yOffsetType SizeUnit | int | float64 , blurType SizeUnit | int | float64 , spreadType SizeUnit | int | float64 ] (
xOffset xOffsetType , yOffset yOffsetType , blurRadius blurType , spreadRadius spreadType , color Color ) ShadowProperty {
return NewShadowProperty ( Params {
XOffset : xOffset ,
YOffset : yOffset ,
2021-10-04 18:05:57 +03:00
BlurRadius : blurRadius ,
SpreadRadius : spreadRadius ,
ColorTag : color ,
2021-09-07 17:36:50 +03:00
} )
}
2024-12-03 10:25:55 +03:00
// NewInsetShadow create the new inset shadow property for a view. Arguments:
2024-10-21 18:37:35 +03:00
//
// 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.
2024-12-03 10:25:55 +03:00
func NewInsetShadow [ xOffsetType SizeUnit | int | float64 , yOffsetType SizeUnit | int | float64 , blurType SizeUnit | int | float64 , spreadType SizeUnit | int | float64 ] (
xOffset xOffsetType , yOffset yOffsetType , blurRadius blurType , spreadRadius spreadType , color Color ) ShadowProperty {
return NewShadowProperty ( Params {
XOffset : xOffset ,
YOffset : yOffset ,
2021-10-04 18:05:57 +03:00
BlurRadius : blurRadius ,
SpreadRadius : spreadRadius ,
ColorTag : color ,
Inset : true ,
2021-09-07 17:36:50 +03:00
} )
}
2024-12-03 10:25:55 +03:00
// NewTextShadow create the new text shadow property. Arguments:
2024-10-21 18:37:35 +03:00
//
// 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.
2024-12-03 10:25:55 +03:00
func NewTextShadow [ xOffsetType SizeUnit | int | float64 , yOffsetType SizeUnit | int | float64 , blurType SizeUnit | int | float64 ] (
xOffset xOffsetType , yOffset yOffsetType , blurRadius blurType , color Color ) ShadowProperty {
return NewShadowProperty ( Params {
XOffset : xOffset ,
YOffset : yOffset ,
2021-10-04 18:05:57 +03:00
BlurRadius : blurRadius ,
ColorTag : color ,
2021-09-07 17:36:50 +03:00
} )
}
2024-12-03 10:25:55 +03:00
// NewShadowProperty create the new shadow property for a view.
2024-10-21 18:37:35 +03:00
// 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.
2024-12-03 10:25:55 +03:00
func NewShadowProperty ( params Params ) ShadowProperty {
shadow := new ( shadowPropertyData )
2024-11-13 12:56:39 +03:00
shadow . init ( )
2021-09-07 17:36:50 +03:00
if params != nil {
2024-11-13 12:56:39 +03:00
for _ , tag := range [ ] PropertyName { ColorTag , Inset , XOffset , YOffset , BlurRadius , SpreadRadius } {
2021-09-07 17:36:50 +03:00
if value , ok := params [ tag ] ; ok && value != nil {
2024-11-13 12:56:39 +03:00
shadow . set ( shadow , tag , value )
2021-09-07 17:36:50 +03:00
}
}
}
return shadow
}
2024-12-03 10:25:55 +03:00
// parseShadowProperty parse DataObject and create ShadowProperty object
func parseShadowProperty ( object DataObject ) ShadowProperty {
shadow := new ( shadowPropertyData )
2024-11-13 12:56:39 +03:00
shadow . init ( )
2021-09-07 17:36:50 +03:00
parseProperties ( shadow , object )
return shadow
}
2024-12-03 10:25:55 +03:00
func ( shadow * shadowPropertyData ) init ( ) {
2024-11-13 12:56:39 +03:00
shadow . dataProperty . init ( )
shadow . supportedProperties = [ ] PropertyName { ColorTag , Inset , XOffset , YOffset , BlurRadius , SpreadRadius }
2021-09-07 17:36:50 +03:00
}
2024-12-03 10:25:55 +03:00
func ( shadow * shadowPropertyData ) cssStyle ( buffer * strings . Builder , session Session , lead string ) bool {
2021-10-04 18:05:57 +03:00
color , _ := colorProperty ( shadow , ColorTag , session )
2021-09-07 17:36:50 +03:00
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 " )
}
2022-09-05 14:00:07 +03:00
buffer . WriteString ( offsetX . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteByte ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( offsetY . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteByte ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( blurRadius . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteByte ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( spreadRadius . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteByte ( ' ' )
buffer . WriteString ( color . cssString ( ) )
return true
}
2024-12-03 10:25:55 +03:00
func ( shadow * shadowPropertyData ) cssTextStyle ( buffer * strings . Builder , session Session , lead string ) bool {
2021-10-04 18:05:57 +03:00
color , _ := colorProperty ( shadow , ColorTag , session )
2021-09-07 17:36:50 +03:00
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 )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( offsetX . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteByte ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( offsetY . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteByte ( ' ' )
2022-09-05 14:00:07 +03:00
buffer . WriteString ( blurRadius . cssString ( "0" , session ) )
2021-09-07 17:36:50 +03:00
buffer . WriteByte ( ' ' )
buffer . WriteString ( color . cssString ( ) )
return true
}
2024-12-03 10:25:55 +03:00
func ( shadow * shadowPropertyData ) visible ( session Session ) bool {
2021-10-04 18:05:57 +03:00
color , _ := colorProperty ( shadow , ColorTag , session )
2021-09-07 17:36:50 +03:00
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
}
2024-12-03 10:25:55 +03:00
func ( shadow * shadowPropertyData ) String ( ) string {
2022-05-22 12:54:02 +03:00
return runStringWriter ( shadow )
2021-09-07 17:36:50 +03:00
}
2024-12-03 10:25:55 +03:00
func ( shadow * shadowPropertyData ) writeString ( buffer * strings . Builder , indent string ) {
2022-05-22 12:54:02 +03:00
buffer . WriteString ( "_{ " )
comma := false
2021-09-07 17:36:50 +03:00
for _ , tag := range shadow . AllTags ( ) {
2022-05-22 12:54:02 +03:00
if value , ok := shadow . properties [ tag ] ; ok {
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
}
2024-11-13 12:56:39 +03:00
func setShadowProperty ( properties Properties , tag PropertyName , value any ) bool {
2021-09-07 17:36:50 +03:00
if value == nil {
2024-11-13 12:56:39 +03:00
properties . setRaw ( tag , nil )
2021-09-07 17:36:50 +03:00
return true
}
switch value := value . ( type ) {
2024-12-03 10:25:55 +03:00
case ShadowProperty :
properties . setRaw ( tag , [ ] ShadowProperty { value } )
2021-09-07 17:36:50 +03:00
2024-12-03 10:25:55 +03:00
case [ ] ShadowProperty :
2021-09-07 17:36:50 +03:00
if len ( value ) == 0 {
2024-11-13 12:56:39 +03:00
properties . setRaw ( tag , nil )
2021-09-07 17:36:50 +03:00
} else {
2024-11-13 12:56:39 +03:00
properties . setRaw ( tag , value )
2021-09-07 17:36:50 +03:00
}
case DataValue :
if ! value . IsObject ( ) {
return false
}
2024-12-03 10:25:55 +03:00
properties . setRaw ( tag , [ ] ShadowProperty { parseShadowProperty ( value . Object ( ) ) } )
2021-09-07 17:36:50 +03:00
case [ ] DataValue :
2024-12-03 10:25:55 +03:00
shadows := [ ] ShadowProperty { }
2021-09-07 17:36:50 +03:00
for _ , data := range value {
if data . IsObject ( ) {
2024-12-03 10:25:55 +03:00
shadows = append ( shadows , parseShadowProperty ( data . Object ( ) ) )
2021-09-07 17:36:50 +03:00
}
}
if len ( shadows ) == 0 {
return false
}
2024-11-13 12:56:39 +03:00
properties . setRaw ( tag , shadows )
2021-09-07 17:36:50 +03:00
case string :
obj := NewDataObject ( value )
if obj == nil {
notCompatibleType ( tag , value )
return false
}
2024-12-03 10:25:55 +03:00
properties . setRaw ( tag , [ ] ShadowProperty { parseShadowProperty ( obj ) } )
2021-09-07 17:36:50 +03:00
default :
notCompatibleType ( tag , value )
return false
}
return true
}
2024-12-03 10:25:55 +03:00
func getShadows ( properties Properties , tag PropertyName ) [ ] ShadowProperty {
2021-09-07 17:36:50 +03:00
if value := properties . Get ( tag ) ; value != nil {
switch value := value . ( type ) {
2024-12-03 10:25:55 +03:00
case [ ] ShadowProperty :
2021-09-07 17:36:50 +03:00
return value
2024-12-03 10:25:55 +03:00
case ShadowProperty :
return [ ] ShadowProperty { value }
2021-09-07 17:36:50 +03:00
}
}
2024-12-03 10:25:55 +03:00
return [ ] ShadowProperty { }
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
func shadowCSS ( properties Properties , tag PropertyName , session Session ) string {
2021-09-07 17:36:50 +03:00
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 ( )
}