2021-09-07 17:36:50 +03:00
package rui
import (
"fmt"
"strings"
)
2024-09-12 14:05:11 +03:00
// Constants for [ViewShadow] 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.
//
// 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.
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.
//
// Used by `ViewShadow`.
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.
//
// 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.
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.
//
// 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.
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.
//
// Used by `ViewShadow`.
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.
//
// 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.
2024-11-13 12:56:39 +03:00
SpreadRadius PropertyName = "spread-radius"
2021-09-07 17:36:50 +03:00
)
// ViewShadow contains attributes of the view shadow
type ViewShadow interface {
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
}
type viewShadowData struct {
2024-11-13 12:56:39 +03:00
dataProperty
2021-09-07 17:36:50 +03:00
}
// NewViewShadow create the new shadow 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.
2021-09-07 17:36:50 +03:00
func NewViewShadow ( offsetX , offsetY , blurRadius , spreadRadius SizeUnit , color Color ) ViewShadow {
return NewShadowWithParams ( Params {
2021-10-04 18:05:57 +03:00
XOffset : offsetX ,
YOffset : offsetY ,
BlurRadius : blurRadius ,
SpreadRadius : spreadRadius ,
ColorTag : color ,
2021-09-07 17:36:50 +03:00
} )
}
// NewInsetViewShadow create the new inset shadow 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.
2021-09-07 17:36:50 +03:00
func NewInsetViewShadow ( offsetX , offsetY , blurRadius , spreadRadius SizeUnit , color Color ) ViewShadow {
return NewShadowWithParams ( Params {
2021-10-04 18:05:57 +03:00
XOffset : offsetX ,
YOffset : offsetY ,
BlurRadius : blurRadius ,
SpreadRadius : spreadRadius ,
ColorTag : color ,
Inset : true ,
2021-09-07 17:36:50 +03:00
} )
}
// NewTextShadow create the new text shadow. 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.
2021-09-07 17:36:50 +03:00
func NewTextShadow ( offsetX , offsetY , blurRadius SizeUnit , color Color ) ViewShadow {
return NewShadowWithParams ( Params {
2021-10-04 18:05:57 +03:00
XOffset : offsetX ,
YOffset : offsetY ,
BlurRadius : blurRadius ,
ColorTag : color ,
2021-09-07 17:36:50 +03:00
} )
}
// NewShadowWithParams create the new shadow 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.
2021-09-07 17:36:50 +03:00
func NewShadowWithParams ( params Params ) ViewShadow {
shadow := new ( viewShadowData )
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
}
// parseViewShadow parse DataObject and create ViewShadow object
func parseViewShadow ( object DataObject ) ViewShadow {
shadow := new ( viewShadowData )
2024-11-13 12:56:39 +03:00
shadow . init ( )
2021-09-07 17:36:50 +03:00
parseProperties ( shadow , object )
return shadow
}
2024-11-13 12:56:39 +03:00
func ( shadow * viewShadowData ) init ( ) {
shadow . dataProperty . init ( )
shadow . supportedProperties = [ ] PropertyName { ColorTag , Inset , XOffset , YOffset , BlurRadius , SpreadRadius }
2021-09-07 17:36:50 +03:00
}
func ( shadow * viewShadowData ) 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
}
func ( shadow * viewShadowData ) 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
}
func ( shadow * viewShadowData ) 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
}
func ( shadow * viewShadowData ) String ( ) string {
2022-05-22 12:54:02 +03:00
return runStringWriter ( shadow )
2021-09-07 17:36:50 +03:00
}
2022-05-22 12:54:02 +03:00
func ( shadow * viewShadowData ) writeString ( buffer * strings . Builder , indent string ) {
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 ) {
case ViewShadow :
2024-11-13 12:56:39 +03:00
properties . setRaw ( tag , [ ] ViewShadow { value } )
2021-09-07 17:36:50 +03:00
case [ ] ViewShadow :
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-11-13 12:56:39 +03:00
properties . setRaw ( tag , [ ] ViewShadow { parseViewShadow ( value . Object ( ) ) } )
2021-09-07 17:36:50 +03:00
case [ ] DataValue :
shadows := [ ] ViewShadow { }
for _ , data := range value {
if data . IsObject ( ) {
shadows = append ( shadows , parseViewShadow ( data . Object ( ) ) )
}
}
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-11-13 12:56:39 +03:00
properties . setRaw ( tag , [ ] ViewShadow { parseViewShadow ( obj ) } )
2021-09-07 17:36:50 +03:00
default :
notCompatibleType ( tag , value )
return false
}
return true
}
2024-11-13 12:56:39 +03:00
func getShadows ( properties Properties , tag PropertyName ) [ ] ViewShadow {
2021-09-07 17:36:50 +03:00
if value := properties . Get ( tag ) ; value != nil {
switch value := value . ( type ) {
case [ ] ViewShadow :
return value
case ViewShadow :
return [ ] ViewShadow { value }
}
}
return [ ] ViewShadow { }
}
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 ( )
}