mirror of https://github.com/anoshenko/rui.git
Added PropertyName type
This commit is contained in:
parent
8fcc52de63
commit
e2775d52f2
|
@ -425,7 +425,7 @@ View имеет ряд свойств, таких как высота, шири
|
||||||
(View реализует данный интерфейс):
|
(View реализует данный интерфейс):
|
||||||
|
|
||||||
type Properties interface {
|
type Properties interface {
|
||||||
Get(tag string) any
|
Get(tag PropertyName) any
|
||||||
Set(tag string, value any) bool
|
Set(tag string, value any) bool
|
||||||
Remove(tag string)
|
Remove(tag string)
|
||||||
Clear()
|
Clear()
|
||||||
|
|
|
@ -429,7 +429,7 @@ View has a number of properties like height, width, color, text parameters, etc.
|
||||||
The Properties interface is used to read and write the property value (View implements this interface):
|
The Properties interface is used to read and write the property value (View implements this interface):
|
||||||
|
|
||||||
type Properties interface {
|
type Properties interface {
|
||||||
Get(tag string) any
|
Get(tag PropertyName) any
|
||||||
Set(tag string, value any) bool
|
Set(tag string, value any) bool
|
||||||
Remove(tag string)
|
Remove(tag string)
|
||||||
Clear()
|
Clear()
|
||||||
|
|
|
@ -20,7 +20,8 @@ func NewAbsoluteLayout(session Session, params Params) AbsoluteLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAbsoluteLayout(session Session) View {
|
func newAbsoluteLayout(session Session) View {
|
||||||
return NewAbsoluteLayout(session, nil)
|
//return NewAbsoluteLayout(session, nil)
|
||||||
|
return new(absoluteLayoutData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of ViewsContainer by default values
|
// Init initialize fields of ViewsContainer by default values
|
||||||
|
|
272
animation.go
272
animation.go
|
@ -18,7 +18,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `[]Animation`, other types converted to it during assignment.
|
// Internal type is `[]Animation`, other types converted to it during assignment.
|
||||||
// See `Animation` description for more details.
|
// See `Animation` description for more details.
|
||||||
AnimationTag = "animation"
|
AnimationTag PropertyName = "animation"
|
||||||
|
|
||||||
// AnimationPaused is the constant for "animation-paused" property tag.
|
// AnimationPaused is the constant for "animation-paused" property tag.
|
||||||
//
|
//
|
||||||
|
@ -30,7 +30,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Animation is paused.
|
// `true` or `1` or "true", "yes", "on", "1" - Animation is paused.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - Animation is playing.
|
// `false` or `0` or "false", "no", "off", "0" - Animation is playing.
|
||||||
AnimationPaused = "animation-paused"
|
AnimationPaused PropertyName = "animation-paused"
|
||||||
|
|
||||||
// Transition is the constant for "transition" property tag.
|
// Transition is the constant for "transition" property tag.
|
||||||
//
|
//
|
||||||
|
@ -44,7 +44,7 @@ const (
|
||||||
// Supported types: `Params`.
|
// Supported types: `Params`.
|
||||||
//
|
//
|
||||||
// See `Params` description for more details.
|
// See `Params` description for more details.
|
||||||
Transition = "transition"
|
Transition PropertyName = "transition"
|
||||||
|
|
||||||
// PropertyTag is the constant for "property" property tag.
|
// PropertyTag is the constant for "property" property tag.
|
||||||
//
|
//
|
||||||
|
@ -55,7 +55,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `[]AnimatedProperty`, other types converted to it during assignment.
|
// Internal type is `[]AnimatedProperty`, other types converted to it during assignment.
|
||||||
// See `AnimatedProperty` description for more details.
|
// See `AnimatedProperty` description for more details.
|
||||||
PropertyTag = "property"
|
PropertyTag PropertyName = "property"
|
||||||
|
|
||||||
// Duration is the constant for "duration" property tag.
|
// Duration is the constant for "duration" property tag.
|
||||||
//
|
//
|
||||||
|
@ -65,7 +65,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
Duration = "duration"
|
Duration PropertyName = "duration"
|
||||||
|
|
||||||
// Delay is the constant for "delay" property tag.
|
// Delay is the constant for "delay" property tag.
|
||||||
//
|
//
|
||||||
|
@ -77,7 +77,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
Delay = "delay"
|
Delay PropertyName = "delay"
|
||||||
|
|
||||||
// TimingFunction is the constant for "timing-function" property tag.
|
// TimingFunction is the constant for "timing-function" property tag.
|
||||||
//
|
//
|
||||||
|
@ -92,7 +92,7 @@ const (
|
||||||
// "ease-out"(`EaseOutTiming`) - Speed is fast at first, but decreases in the end.
|
// "ease-out"(`EaseOutTiming`) - Speed is fast at first, but decreases in the end.
|
||||||
// "ease-in-out"(`EaseInOutTiming`) - Speed is slow at first, but quickly increases and at the end it decreases again.
|
// "ease-in-out"(`EaseInOutTiming`) - Speed is slow at first, but quickly increases and at the end it decreases again.
|
||||||
// "linear"(`LinearTiming`) - Constant speed.
|
// "linear"(`LinearTiming`) - Constant speed.
|
||||||
TimingFunction = "timing-function"
|
TimingFunction PropertyName = "timing-function"
|
||||||
|
|
||||||
// IterationCount is the constant for "iteration-count" property tag.
|
// IterationCount is the constant for "iteration-count" property tag.
|
||||||
//
|
//
|
||||||
|
@ -102,7 +102,7 @@ const (
|
||||||
// Supported types: `int`, `string`.
|
// Supported types: `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `int`, other types converted to it during assignment.
|
// Internal type is `int`, other types converted to it during assignment.
|
||||||
IterationCount = "iteration-count"
|
IterationCount PropertyName = "iteration-count"
|
||||||
|
|
||||||
// AnimationDirection is the constant for "animation-direction" property tag.
|
// AnimationDirection is the constant for "animation-direction" property tag.
|
||||||
//
|
//
|
||||||
|
@ -117,7 +117,7 @@ const (
|
||||||
// `1`(`ReverseAnimation`) or "reverse" - The animation plays backwards, from the last position to the first, and then resets to the final position and plays again.
|
// `1`(`ReverseAnimation`) or "reverse" - The animation plays backwards, from the last position to the first, and then resets to the final position and plays again.
|
||||||
// `2`(`AlternateAnimation`) or "alternate" - The animation changes direction in each cycle, that is, in the first cycle, it starts from the start position, reaches the end position, and in the second cycle, it continues from the end position and reaches the start position, and so on.
|
// `2`(`AlternateAnimation`) or "alternate" - The animation changes direction in each cycle, that is, in the first cycle, it starts from the start position, reaches the end position, and in the second cycle, it continues from the end position and reaches the start position, and so on.
|
||||||
// `3`(`AlternateReverseAnimation`) or "alternate-reverse" - The animation starts playing from the end position and reaches the start position, and in the next cycle, continuing from the start position, it goes to the end position.
|
// `3`(`AlternateReverseAnimation`) or "alternate-reverse" - The animation starts playing from the end position and reaches the start position, and in the next cycle, continuing from the start position, it goes to the end position.
|
||||||
AnimationDirection = "animation-direction"
|
AnimationDirection PropertyName = "animation-direction"
|
||||||
|
|
||||||
// NormalAnimation is value of the "animation-direction" property.
|
// NormalAnimation is value of the "animation-direction" property.
|
||||||
// The animation plays forwards each cycle. In other words, each time the animation cycles,
|
// The animation plays forwards each cycle. In other words, each time the animation cycles,
|
||||||
|
@ -180,7 +180,7 @@ func CubicBezierTiming(x1, y1, x2, y2 float64) string {
|
||||||
// AnimatedProperty describes the change script of one property
|
// AnimatedProperty describes the change script of one property
|
||||||
type AnimatedProperty struct {
|
type AnimatedProperty struct {
|
||||||
// Tag is the name of the property
|
// Tag is the name of the property
|
||||||
Tag string
|
Tag PropertyName
|
||||||
// From is the initial value of the property
|
// From is the initial value of the property
|
||||||
From any
|
From any
|
||||||
// To is the final value of the property
|
// To is the final value of the property
|
||||||
|
@ -190,12 +190,12 @@ type AnimatedProperty struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type animationData struct {
|
type animationData struct {
|
||||||
propertyList
|
dataProperty
|
||||||
keyFramesName string
|
keyFramesName string
|
||||||
usageCounter int
|
usageCounter int
|
||||||
view View
|
view View
|
||||||
listener func(view View, animation Animation, event string)
|
listener func(view View, animation Animation, event PropertyName)
|
||||||
oldListeners map[string][]func(View, string)
|
oldListeners map[PropertyName][]func(View, PropertyName)
|
||||||
oldAnimation []Animation
|
oldAnimation []Animation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ type Animation interface {
|
||||||
|
|
||||||
// Start starts the animation for the view specified by the first argument.
|
// Start starts the animation for the view specified by the first argument.
|
||||||
// The second argument specifies the animation event listener (can be nil)
|
// The second argument specifies the animation event listener (can be nil)
|
||||||
Start(view View, listener func(view View, animation Animation, event string)) bool
|
Start(view View, listener func(view View, animation Animation, event PropertyName)) bool
|
||||||
// Stop stops the animation
|
// Stop stops the animation
|
||||||
Stop()
|
Stop()
|
||||||
// Pause pauses the animation
|
// Pause pauses the animation
|
||||||
|
@ -215,7 +215,7 @@ type Animation interface {
|
||||||
// Resume resumes an animation that was stopped using the Pause method
|
// Resume resumes an animation that was stopped using the Pause method
|
||||||
Resume()
|
Resume()
|
||||||
|
|
||||||
writeTransitionString(tag string, buffer *strings.Builder)
|
writeTransitionString(tag PropertyName, buffer *strings.Builder)
|
||||||
animationCSS(session Session) string
|
animationCSS(session Session) string
|
||||||
transitionCSS(buffer *strings.Builder, session Session)
|
transitionCSS(buffer *strings.Builder, session Session)
|
||||||
hasAnimatedProperty() bool
|
hasAnimatedProperty() bool
|
||||||
|
@ -230,10 +230,11 @@ func parseAnimation(obj DataObject) Animation {
|
||||||
|
|
||||||
for i := 0; i < obj.PropertyCount(); i++ {
|
for i := 0; i < obj.PropertyCount(); i++ {
|
||||||
if node := obj.Property(i); node != nil {
|
if node := obj.Property(i); node != nil {
|
||||||
|
tag := PropertyName(node.Tag())
|
||||||
if node.Type() == TextNode {
|
if node.Type() == TextNode {
|
||||||
animation.Set(node.Tag(), node.Text())
|
animation.Set(tag, node.Text())
|
||||||
} else {
|
} else {
|
||||||
animation.Set(node.Tag(), node)
|
animation.Set(tag, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,6 +252,13 @@ func NewAnimation(params Params) Animation {
|
||||||
return animation
|
return animation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (animation *animationData) init() {
|
||||||
|
animation.dataProperty.init()
|
||||||
|
animation.normalize = normalizeAnimationTag
|
||||||
|
animation.set = animationSet
|
||||||
|
animation.supportedProperties = []PropertyName{ID, PropertyTag, Duration, Delay, TimingFunction, IterationCount, AnimationDirection}
|
||||||
|
}
|
||||||
|
|
||||||
func (animation *animationData) animatedProperties() []AnimatedProperty {
|
func (animation *animationData) animatedProperties() []AnimatedProperty {
|
||||||
value := animation.getRaw(PropertyTag)
|
value := animation.getRaw(PropertyTag)
|
||||||
if value == nil {
|
if value == nil {
|
||||||
|
@ -291,33 +299,28 @@ func (animation *animationData) unused(session Session) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (animation *animationData) normalizeTag(tag string) string {
|
func normalizeAnimationTag(tag PropertyName) PropertyName {
|
||||||
tag = strings.ToLower(tag)
|
tag = defaultNormalize(tag)
|
||||||
if tag == Direction {
|
if tag == Direction {
|
||||||
return AnimationDirection
|
return AnimationDirection
|
||||||
}
|
}
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (animation *animationData) Set(tag string, value any) bool {
|
func animationSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
if value == nil {
|
switch tag {
|
||||||
animation.Remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag = animation.normalizeTag(tag); tag {
|
|
||||||
case ID:
|
case ID:
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
text = strings.Trim(text, " \t\n\r")
|
text = strings.Trim(text, " \t\n\r")
|
||||||
if text == "" {
|
if text == "" {
|
||||||
delete(animation.properties, tag)
|
properties.setRaw(tag, nil)
|
||||||
} else {
|
} else {
|
||||||
animation.properties[tag] = text
|
properties.setRaw(tag, text)
|
||||||
}
|
}
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
|
|
||||||
case PropertyTag:
|
case PropertyTag:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
@ -340,8 +343,8 @@ func (animation *animationData) Set(tag string, value any) bool {
|
||||||
} else if value.To == nil {
|
} else if value.To == nil {
|
||||||
ErrorLog("AnimatedProperty.To is nil")
|
ErrorLog("AnimatedProperty.To is nil")
|
||||||
} else {
|
} else {
|
||||||
animation.properties[tag] = []AnimatedProperty{value}
|
properties.setRaw(tag, []AnimatedProperty{value})
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case []AnimatedProperty:
|
case []AnimatedProperty:
|
||||||
|
@ -369,8 +372,8 @@ func (animation *animationData) Set(tag string, value any) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(props) > 0 {
|
if len(props) > 0 {
|
||||||
animation.properties[tag] = props
|
properties.setRaw(tag, props)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
} else {
|
} else {
|
||||||
ErrorLog("[]AnimatedProperty is empty")
|
ErrorLog("[]AnimatedProperty is empty")
|
||||||
}
|
}
|
||||||
|
@ -417,8 +420,8 @@ func (animation *animationData) Set(tag string, value any) bool {
|
||||||
switch value.Type() {
|
switch value.Type() {
|
||||||
case ObjectNode:
|
case ObjectNode:
|
||||||
if prop, ok := parseObject(value.Object()); ok {
|
if prop, ok := parseObject(value.Object()); ok {
|
||||||
animation.properties[tag] = []AnimatedProperty{prop}
|
properties.setRaw(tag, []AnimatedProperty{prop})
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case ArrayNode:
|
case ArrayNode:
|
||||||
|
@ -433,8 +436,8 @@ func (animation *animationData) Set(tag string, value any) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(props) > 0 {
|
if len(props) > 0 {
|
||||||
animation.properties[tag] = props
|
properties.setRaw(tag, props)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -446,36 +449,28 @@ func (animation *animationData) Set(tag string, value any) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Duration:
|
case Duration:
|
||||||
return animation.setFloatProperty(tag, value, 0, math.MaxFloat64)
|
return setFloatProperty(properties, tag, value, 0, math.MaxFloat64)
|
||||||
|
|
||||||
case Delay:
|
case Delay:
|
||||||
return animation.setFloatProperty(tag, value, -math.MaxFloat64, math.MaxFloat64)
|
return setFloatProperty(properties, tag, value, -math.MaxFloat64, math.MaxFloat64)
|
||||||
|
|
||||||
case TimingFunction:
|
case TimingFunction:
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
animation.properties[tag] = text
|
properties.setRaw(tag, text)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case IterationCount:
|
case IterationCount:
|
||||||
return animation.setIntProperty(tag, value)
|
return setIntProperty(properties, tag, value)
|
||||||
|
|
||||||
case AnimationDirection:
|
case AnimationDirection:
|
||||||
return animation.setEnumProperty(AnimationDirection, value, enumProperties[AnimationDirection].values)
|
return setEnumProperty(properties, AnimationDirection, value, enumProperties[AnimationDirection].values)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ErrorLogF(`The "%s" property is not supported by Animation`, tag)
|
ErrorLogF(`The "%s" property is not supported by Animation`, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
func (animation *animationData) Remove(tag string) {
|
|
||||||
delete(animation.properties, animation.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (animation *animationData) Get(tag string) any {
|
|
||||||
return animation.getRaw(animation.normalizeTag(tag))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (animation *animationData) String() string {
|
func (animation *animationData) String() string {
|
||||||
|
@ -488,7 +483,7 @@ func (animation *animationData) String() string {
|
||||||
if tag != PropertyTag {
|
if tag != PropertyTag {
|
||||||
if value, ok := animation.properties[tag]; ok && value != nil {
|
if value, ok := animation.properties[tag]; ok && value != nil {
|
||||||
buffer.WriteString("\n\t")
|
buffer.WriteString("\n\t")
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, "\t")
|
writePropertyValue(buffer, tag, value, "\t")
|
||||||
buffer.WriteRune(',')
|
buffer.WriteRune(',')
|
||||||
|
@ -497,7 +492,7 @@ func (animation *animationData) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
writeProperty := func(prop AnimatedProperty, indent string) {
|
writeProperty := func(prop AnimatedProperty, indent string) {
|
||||||
buffer.WriteString(prop.Tag)
|
buffer.WriteString(string(prop.Tag))
|
||||||
buffer.WriteString("{\n")
|
buffer.WriteString("{\n")
|
||||||
buffer.WriteString(indent)
|
buffer.WriteString(indent)
|
||||||
buffer.WriteString("from = ")
|
buffer.WriteString("from = ")
|
||||||
|
@ -512,7 +507,7 @@ func (animation *animationData) String() string {
|
||||||
tag := strconv.Itoa(key) + "%"
|
tag := strconv.Itoa(key) + "%"
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(tag)
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
writePropertyValue(buffer, PropertyName(tag), value, indent)
|
||||||
}
|
}
|
||||||
buffer.WriteString("\n")
|
buffer.WriteString("\n")
|
||||||
buffer.WriteString(indent[1:])
|
buffer.WriteString(indent[1:])
|
||||||
|
@ -522,7 +517,7 @@ func (animation *animationData) String() string {
|
||||||
if props := animation.animatedProperties(); len(props) > 0 {
|
if props := animation.animatedProperties(); len(props) > 0 {
|
||||||
|
|
||||||
buffer.WriteString("\n\t")
|
buffer.WriteString("\n\t")
|
||||||
buffer.WriteString(PropertyTag)
|
buffer.WriteString(string(PropertyTag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
if len(props) > 1 {
|
if len(props) > 1 {
|
||||||
buffer.WriteString("[\n")
|
buffer.WriteString("[\n")
|
||||||
|
@ -606,15 +601,15 @@ func (animation *animationData) transitionCSS(buffer *strings.Builder, session S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (animation *animationData) writeTransitionString(tag string, buffer *strings.Builder) {
|
func (animation *animationData) writeTransitionString(tag PropertyName, buffer *strings.Builder) {
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString("{")
|
buffer.WriteString("{")
|
||||||
lead := " "
|
lead := " "
|
||||||
|
|
||||||
writeFloatProperty := func(name string) bool {
|
writeFloatProperty := func(name PropertyName) bool {
|
||||||
if value := animation.getRaw(name); value != nil {
|
if value := animation.getRaw(name); value != nil {
|
||||||
buffer.WriteString(lead)
|
buffer.WriteString(lead)
|
||||||
buffer.WriteString(name)
|
buffer.WriteString(string(name))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, name, value, "")
|
writePropertyValue(buffer, name, value, "")
|
||||||
lead = ", "
|
lead = ", "
|
||||||
|
@ -633,7 +628,7 @@ func (animation *animationData) writeTransitionString(tag string, buffer *string
|
||||||
if value := animation.getRaw(TimingFunction); value != nil {
|
if value := animation.getRaw(TimingFunction); value != nil {
|
||||||
if timingFunction, ok := value.(string); ok && timingFunction != "" {
|
if timingFunction, ok := value.(string); ok && timingFunction != "" {
|
||||||
buffer.WriteString(lead)
|
buffer.WriteString(lead)
|
||||||
buffer.WriteString(TimingFunction)
|
buffer.WriteString(string(TimingFunction))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
if strings.ContainsAny(timingFunction, " ,()") {
|
if strings.ContainsAny(timingFunction, " ,()") {
|
||||||
buffer.WriteRune('"')
|
buffer.WriteRune('"')
|
||||||
|
@ -767,7 +762,7 @@ func (session *sessionData) registerAnimation(props []AnimatedProperty) string {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) SetAnimated(tag string, value any, animation Animation) bool {
|
func (view *viewData) SetAnimated(tag PropertyName, value any, animation Animation) bool {
|
||||||
if animation == nil {
|
if animation == nil {
|
||||||
return view.Set(tag, value)
|
return view.Set(tag, value)
|
||||||
}
|
}
|
||||||
|
@ -779,27 +774,30 @@ func (view *viewData) SetAnimated(tag string, value any, animation Animation) bo
|
||||||
session.updateProperty(htmlID, "ontransitionend", "transitionEndEvent(this, event)")
|
session.updateProperty(htmlID, "ontransitionend", "transitionEndEvent(this, event)")
|
||||||
session.updateProperty(htmlID, "ontransitioncancel", "transitionCancelEvent(this, event)")
|
session.updateProperty(htmlID, "ontransitioncancel", "transitionCancelEvent(this, event)")
|
||||||
|
|
||||||
if prevAnimation, ok := view.transitions[tag]; ok {
|
transitions := getTransitionProperty(view)
|
||||||
view.singleTransition[tag] = prevAnimation
|
var prevAnimation Animation = nil
|
||||||
} else {
|
if transitions != nil {
|
||||||
view.singleTransition[tag] = nil
|
if prev, ok := transitions[tag]; ok {
|
||||||
|
prevAnimation = prev
|
||||||
}
|
}
|
||||||
view.transitions[tag] = animation
|
}
|
||||||
view.updateTransitionCSS()
|
view.singleTransition[tag] = prevAnimation
|
||||||
|
setTransition(view, tag, animation)
|
||||||
|
view.session.updateCSSProperty(view.htmlID(), "transition", transitionCSS(view, view.session))
|
||||||
|
|
||||||
session.finishUpdateScript(htmlID)
|
session.finishUpdateScript(htmlID)
|
||||||
|
|
||||||
result := view.Set(tag, value)
|
result := view.Set(tag, value)
|
||||||
if !result {
|
if !result {
|
||||||
delete(view.singleTransition, tag)
|
delete(view.singleTransition, tag)
|
||||||
view.updateTransitionCSS()
|
view.session.updateCSSProperty(view.htmlID(), "transition", transitionCSS(view, view.session))
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) animationCSS(session Session) string {
|
func animationCSS(properties Properties, session Session) string {
|
||||||
if value := style.getRaw(AnimationTag); value != nil {
|
if value := properties.getRaw(AnimationTag); value != nil {
|
||||||
if animations, ok := value.([]Animation); ok {
|
if animations, ok := value.([]Animation); ok {
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
@ -820,11 +818,12 @@ func (style *viewStyle) animationCSS(session Session) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) transitionCSS(session Session) string {
|
func transitionCSS(properties Properties, session Session) string {
|
||||||
|
if transitions := getTransitionProperty(properties); len(transitions) > 0 {
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
convert := map[string]string{
|
convert := map[PropertyName]string{
|
||||||
CellHeight: "grid-template-rows",
|
CellHeight: "grid-template-rows",
|
||||||
CellWidth: "grid-template-columns",
|
CellWidth: "grid-template-columns",
|
||||||
Row: "grid-row",
|
Row: "grid-row",
|
||||||
|
@ -837,7 +836,7 @@ func (style *viewStyle) transitionCSS(session Session) string {
|
||||||
TextLineThickness: "text-decoration-thickness",
|
TextLineThickness: "text-decoration-thickness",
|
||||||
}
|
}
|
||||||
|
|
||||||
for tag, animation := range style.transitions {
|
for tag, animation := range transitions {
|
||||||
if buffer.Len() > 0 {
|
if buffer.Len() > 0 {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
|
@ -845,53 +844,128 @@ func (style *viewStyle) transitionCSS(session Session) string {
|
||||||
if cssTag, ok := convert[tag]; ok {
|
if cssTag, ok := convert[tag]; ok {
|
||||||
buffer.WriteString(cssTag)
|
buffer.WriteString(cssTag)
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
}
|
}
|
||||||
animation.transitionCSS(buffer, session)
|
animation.transitionCSS(buffer, session)
|
||||||
}
|
}
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
return ""
|
||||||
func (view *viewData) updateTransitionCSS() {
|
|
||||||
view.session.updateCSSProperty(view.htmlID(), "transition", view.transitionCSS(view.session))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) Transition(tag string) Animation {
|
/*
|
||||||
if style.transitions != nil {
|
func (view *viewData) updateTransitionCSS() {
|
||||||
if anim, ok := style.transitions[tag]; ok {
|
view.session.updateCSSProperty(view.htmlID(), "transition", transitionCSS(view, view.session))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (style *viewStyle) Transition(tag PropertyName) Animation {
|
||||||
|
if transitions := getTransitionProperty(style); transitions != nil {
|
||||||
|
if anim, ok := transitions[tag]; ok {
|
||||||
return anim
|
return anim
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) Transitions() map[string]Animation {
|
func (style *viewStyle) Transitions() map[PropertyName]Animation {
|
||||||
result := map[string]Animation{}
|
result := map[PropertyName]Animation{}
|
||||||
for tag, animation := range style.transitions {
|
for tag, animation := range getTransitionProperty(style) {
|
||||||
result[tag] = animation
|
result[tag] = animation
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) SetTransition(tag string, animation Animation) {
|
func (style *viewStyle) SetTransition(tag PropertyName, animation Animation) {
|
||||||
if animation == nil {
|
setTransition(style, style.normalize(tag), animation)
|
||||||
delete(style.transitions, tag)
|
}
|
||||||
} else {
|
|
||||||
style.transitions[tag] = animation
|
func (view *viewData) SetTransition(tag PropertyName, animation Animation) {
|
||||||
|
setTransition(view, view.normalize(tag), animation)
|
||||||
|
if view.created {
|
||||||
|
view.session.updateCSSProperty(view.htmlID(), "transition", transitionCSS(view, view.session))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) SetTransition(tag string, animation Animation) {
|
func setTransition(properties Properties, tag PropertyName, animation Animation) {
|
||||||
view.viewStyle.SetTransition(tag, animation)
|
transitions := getTransitionProperty(properties)
|
||||||
if view.created {
|
|
||||||
view.session.updateCSSProperty(view.htmlID(), "transition", view.transitionCSS(view.session))
|
if animation == nil {
|
||||||
|
if transitions != nil {
|
||||||
|
delete(transitions, tag)
|
||||||
|
if len(transitions) == 0 {
|
||||||
|
properties.setRaw(Transition, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if transitions != nil {
|
||||||
|
transitions[tag] = animation
|
||||||
|
} else {
|
||||||
|
properties.setRaw(Transition, map[PropertyName]Animation{tag: animation})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTransitionProperty(properties Properties) map[PropertyName]Animation {
|
||||||
|
if value := properties.getRaw(Transition); value != nil {
|
||||||
|
if transitions, ok := value.(map[PropertyName]Animation); ok {
|
||||||
|
return transitions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAnimationProperty(properties Properties, tag PropertyName, value any) bool {
|
||||||
|
|
||||||
|
set := func(animations []Animation) {
|
||||||
|
properties.setRaw(tag, animations)
|
||||||
|
for _, animation := range animations {
|
||||||
|
animation.used()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case Animation:
|
||||||
|
set([]Animation{value})
|
||||||
|
return true
|
||||||
|
|
||||||
|
case []Animation:
|
||||||
|
set(value)
|
||||||
|
return true
|
||||||
|
|
||||||
|
case DataObject:
|
||||||
|
if animation := parseAnimation(value); animation.hasAnimatedProperty() {
|
||||||
|
set([]Animation{animation})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
case DataNode:
|
||||||
|
animations := []Animation{}
|
||||||
|
result := true
|
||||||
|
for i := 0; i < value.ArraySize(); i++ {
|
||||||
|
if obj := value.ArrayElement(i).Object(); obj != nil {
|
||||||
|
if anim := parseAnimation(obj); anim.hasAnimatedProperty() {
|
||||||
|
animations = append(animations, anim)
|
||||||
|
} else {
|
||||||
|
result = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notCompatibleType(tag, value.ArrayElement(i))
|
||||||
|
result = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if result && len(animations) > 0 {
|
||||||
|
set(animations)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// SetAnimated sets the property with name "tag" of the "rootView" subview with "viewID" id by value. Result:
|
// SetAnimated sets the property with name "tag" of the "rootView" subview with "viewID" id by value. Result:
|
||||||
// true - success,
|
// true - success,
|
||||||
// false - error (incompatible type or invalid format of a string value, see AppLog).
|
// false - error (incompatible type or invalid format of a string value, see AppLog).
|
||||||
func SetAnimated(rootView View, viewID, tag string, value any, animation Animation) bool {
|
func SetAnimated(rootView View, viewID string, tag PropertyName, value any, animation Animation) bool {
|
||||||
if view := ViewByID(rootView, viewID); view != nil {
|
if view := ViewByID(rootView, viewID); view != nil {
|
||||||
return view.SetAnimated(tag, value, animation)
|
return view.SetAnimated(tag, value, animation)
|
||||||
}
|
}
|
||||||
|
@ -906,7 +980,7 @@ func IsAnimationPaused(view View, subviewID ...string) bool {
|
||||||
|
|
||||||
// GetTransitions returns the subview transitions. The result is always non-nil.
|
// GetTransitions returns the subview transitions. The result is always non-nil.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then transitions of the first argument (view) is returned
|
// If the second argument (subviewID) is not specified or it is "" then transitions of the first argument (view) is returned
|
||||||
func GetTransitions(view View, subviewID ...string) map[string]Animation {
|
func GetTransitions(view View, subviewID ...string) map[PropertyName]Animation {
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
|
@ -915,12 +989,12 @@ func GetTransitions(view View, subviewID ...string) map[string]Animation {
|
||||||
return view.Transitions()
|
return view.Transitions()
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[string]Animation{}
|
return map[PropertyName]Animation{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransition returns the subview property transition. If there is no transition for the given property then nil is returned.
|
// GetTransition returns the subview property transition. If there is no transition for the given property then nil is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then transitions of the first argument (view) is returned
|
// If the second argument (subviewID) is not specified or it is "" then transitions of the first argument (view) is returned
|
||||||
func GetTransition(view View, subviewID, tag string) Animation {
|
func GetTransition(view View, subviewID string, tag PropertyName) Animation {
|
||||||
if subviewID != "" {
|
if subviewID != "" {
|
||||||
view = ViewByID(view, subviewID)
|
view = ViewByID(view, subviewID)
|
||||||
}
|
}
|
||||||
|
@ -934,7 +1008,7 @@ func GetTransition(view View, subviewID, tag string) Animation {
|
||||||
|
|
||||||
// AddTransition adds the transition for the subview property.
|
// AddTransition adds the transition for the subview property.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then the transition is added to the first argument (view)
|
// If the second argument (subviewID) is not specified or it is "" then the transition is added to the first argument (view)
|
||||||
func AddTransition(view View, subviewID, tag string, animation Animation) bool {
|
func AddTransition(view View, subviewID string, tag PropertyName, animation Animation) bool {
|
||||||
if tag != "" {
|
if tag != "" {
|
||||||
if subviewID != "" {
|
if subviewID != "" {
|
||||||
view = ViewByID(view, subviewID)
|
view = ViewByID(view, subviewID)
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// Constants which describe values for view's animation events properties
|
// Constants which describe values for view's animation events properties
|
||||||
const (
|
const (
|
||||||
// TransitionRunEvent is the constant for "transition-run-event" property tag.
|
// TransitionRunEvent is the constant for "transition-run-event" property tag.
|
||||||
|
@ -20,7 +18,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(propertyName string)`,
|
// `func(propertyName string)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TransitionRunEvent = "transition-run-event"
|
TransitionRunEvent PropertyName = "transition-run-event"
|
||||||
|
|
||||||
// TransitionStartEvent is the constant for "transition-start-event" property tag.
|
// TransitionStartEvent is the constant for "transition-start-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -38,7 +36,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(propertyName string)`,
|
// `func(propertyName string)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TransitionStartEvent = "transition-start-event"
|
TransitionStartEvent PropertyName = "transition-start-event"
|
||||||
|
|
||||||
// TransitionEndEvent is the constant for "transition-end-event" property tag.
|
// TransitionEndEvent is the constant for "transition-end-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -56,7 +54,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(propertyName string)`,
|
// `func(propertyName string)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TransitionEndEvent = "transition-end-event"
|
TransitionEndEvent PropertyName = "transition-end-event"
|
||||||
|
|
||||||
// TransitionCancelEvent is the constant for "transition-cancel-event" property tag.
|
// TransitionCancelEvent is the constant for "transition-cancel-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -76,7 +74,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(propertyName string)`,
|
// `func(propertyName string)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TransitionCancelEvent = "transition-cancel-event"
|
TransitionCancelEvent PropertyName = "transition-cancel-event"
|
||||||
|
|
||||||
// AnimationStartEvent is the constant for "animation-start-event" property tag.
|
// AnimationStartEvent is the constant for "animation-start-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -95,7 +93,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(animationId string)`,
|
// `func(animationId string)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
AnimationStartEvent = "animation-start-event"
|
AnimationStartEvent PropertyName = "animation-start-event"
|
||||||
|
|
||||||
// AnimationEndEvent is the constant for "animation-end-event" property tag.
|
// AnimationEndEvent is the constant for "animation-end-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -114,7 +112,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(animationId string)`,
|
// `func(animationId string)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
AnimationEndEvent = "animation-end-event"
|
AnimationEndEvent PropertyName = "animation-end-event"
|
||||||
|
|
||||||
// AnimationCancelEvent is the constant for "animation-cancel-event" property tag.
|
// AnimationCancelEvent is the constant for "animation-cancel-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -135,7 +133,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(animationId string)`,
|
// `func(animationId string)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
AnimationCancelEvent = "animation-cancel-event"
|
AnimationCancelEvent PropertyName = "animation-cancel-event"
|
||||||
|
|
||||||
// AnimationIterationEvent is the constant for "animation-iteration-event" property tag.
|
// AnimationIterationEvent is the constant for "animation-iteration-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -154,48 +152,36 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(animationId string)`,
|
// `func(animationId string)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
AnimationIterationEvent = "animation-iteration-event"
|
AnimationIterationEvent PropertyName = "animation-iteration-event"
|
||||||
)
|
)
|
||||||
|
|
||||||
var transitionEvents = map[string]struct{ jsEvent, jsFunc string }{
|
/*
|
||||||
TransitionRunEvent: {jsEvent: "ontransitionrun", jsFunc: "transitionRunEvent"},
|
func setTransitionListener(properties Properties, tag PropertyName, value any) bool {
|
||||||
TransitionStartEvent: {jsEvent: "ontransitionstart", jsFunc: "transitionStartEvent"},
|
if listeners, ok := valueToEventListeners[View, string](value); ok {
|
||||||
TransitionEndEvent: {jsEvent: "ontransitionend", jsFunc: "transitionEndEvent"},
|
if len(listeners) == 0 {
|
||||||
TransitionCancelEvent: {jsEvent: "ontransitioncancel", jsFunc: "transitionCancelEvent"},
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
properties.setRaw(tag, listeners)
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) setTransitionListener(tag string, value any) bool {
|
|
||||||
listeners, ok := valueToEventListeners[View, string](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if listeners == nil {
|
func (view *viewData) removeTransitionListener(tag PropertyName) {
|
||||||
view.removeTransitionListener(tag)
|
|
||||||
} else if js, ok := transitionEvents[tag]; ok {
|
|
||||||
view.properties[tag] = listeners
|
|
||||||
if view.created {
|
|
||||||
view.session.updateProperty(view.htmlID(), js.jsEvent, js.jsFunc+"(this, event)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) removeTransitionListener(tag string) {
|
|
||||||
delete(view.properties, tag)
|
delete(view.properties, tag)
|
||||||
if view.created {
|
if view.created {
|
||||||
if js, ok := transitionEvents[tag]; ok {
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func transitionEventsHtml(view View, buffer *strings.Builder) {
|
func transitionEventsHtml(view View, buffer *strings.Builder) {
|
||||||
for tag, js := range transitionEvents {
|
for _, tag := range []PropertyName{TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent} {
|
||||||
if value := view.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
if listeners, ok := value.([]func(View, string)); ok && len(listeners) > 0 {
|
if listeners, ok := value.([]func(View, string)); ok && len(listeners) > 0 {
|
||||||
buffer.WriteString(js.jsEvent)
|
buffer.WriteString(js.jsEvent)
|
||||||
buffer.WriteString(`="`)
|
buffer.WriteString(`="`)
|
||||||
|
@ -205,67 +191,55 @@ func transitionEventsHtml(view View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (view *viewData) handleTransitionEvents(tag string, data DataObject) {
|
func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject) {
|
||||||
if property, ok := data.PropertyValue("property"); ok {
|
if propertyName, ok := data.PropertyValue("property"); ok {
|
||||||
|
property := PropertyName(propertyName)
|
||||||
if tag == TransitionEndEvent || tag == TransitionCancelEvent {
|
if tag == TransitionEndEvent || tag == TransitionCancelEvent {
|
||||||
if animation, ok := view.singleTransition[property]; ok {
|
if animation, ok := view.singleTransition[property]; ok {
|
||||||
delete(view.singleTransition, property)
|
delete(view.singleTransition, property)
|
||||||
if animation != nil {
|
setTransition(view, tag, animation)
|
||||||
view.transitions[property] = animation
|
session := view.session
|
||||||
} else {
|
session.updateCSSProperty(view.htmlID(), "transition", transitionCSS(view, session))
|
||||||
delete(view.transitions, property)
|
|
||||||
}
|
|
||||||
view.updateTransitionCSS()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, listener := range getEventListeners[View, string](view, nil, tag) {
|
for _, listener := range getEventListeners[View, PropertyName](view, nil, tag) {
|
||||||
listener(view, property)
|
listener(view, property)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var animationEvents = map[string]struct{ jsEvent, jsFunc string }{
|
/*
|
||||||
AnimationStartEvent: {jsEvent: "onanimationstart", jsFunc: "animationStartEvent"},
|
func setAnimationListener(properties Properties, tag PropertyName, value any) bool {
|
||||||
AnimationEndEvent: {jsEvent: "onanimationend", jsFunc: "animationEndEvent"},
|
if listeners, ok := valueToEventListeners[View, string](value); ok {
|
||||||
AnimationIterationEvent: {jsEvent: "onanimationiteration", jsFunc: "animationIterationEvent"},
|
if len(listeners) == 0 {
|
||||||
AnimationCancelEvent: {jsEvent: "onanimationcancel", jsFunc: "animationCancelEvent"},
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
properties.setRaw(tag, listeners)
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) setAnimationListener(tag string, value any) bool {
|
|
||||||
listeners, ok := valueToEventListeners[View, string](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if listeners == nil {
|
func (view *viewData) removeAnimationListener(tag PropertyName) {
|
||||||
view.removeAnimationListener(tag)
|
|
||||||
} else if js, ok := animationEvents[tag]; ok {
|
|
||||||
view.properties[tag] = listeners
|
|
||||||
if view.created {
|
|
||||||
view.session.updateProperty(view.htmlID(), js.jsEvent, js.jsFunc+"(this, event)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) removeAnimationListener(tag string) {
|
|
||||||
delete(view.properties, tag)
|
delete(view.properties, tag)
|
||||||
if view.created {
|
if view.created {
|
||||||
if js, ok := animationEvents[tag]; ok {
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func animationEventsHtml(view View, buffer *strings.Builder) {
|
func animationEventsHtml(view View, buffer *strings.Builder) {
|
||||||
for tag, js := range animationEvents {
|
for _, tag := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent} {
|
||||||
if value := view.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
if listeners, ok := value.([]func(View)); ok && len(listeners) > 0 {
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
|
if listeners, ok := value.([]func(View, string)); ok && len(listeners) > 0 {
|
||||||
buffer.WriteString(js.jsEvent)
|
buffer.WriteString(js.jsEvent)
|
||||||
buffer.WriteString(`="`)
|
buffer.WriteString(`="`)
|
||||||
buffer.WriteString(js.jsFunc)
|
buffer.WriteString(js.jsFunc)
|
||||||
|
@ -274,8 +248,10 @@ func animationEventsHtml(view View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (view *viewData) handleAnimationEvents(tag string, data DataObject) {
|
func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) {
|
||||||
if listeners := getEventListeners[View, string](view, nil, tag); len(listeners) > 0 {
|
if listeners := getEventListeners[View, string](view, nil, tag); len(listeners) > 0 {
|
||||||
id := ""
|
id := ""
|
||||||
if name, ok := data.PropertyValue("name"); ok {
|
if name, ok := data.PropertyValue("name"); ok {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
func (animation *animationData) Start(view View, listener func(view View, animation Animation, event string)) bool {
|
func (animation *animationData) Start(view View, listener func(view View, animation Animation, event PropertyName)) bool {
|
||||||
if view == nil {
|
if view == nil {
|
||||||
ErrorLog("nil View in animation.Start() function")
|
ErrorLog("nil View in animation.Start() function")
|
||||||
return false
|
return false
|
||||||
|
@ -19,12 +19,12 @@ func (animation *animationData) Start(view View, listener func(view View, animat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
animation.oldListeners = map[string][]func(View, string){}
|
animation.oldListeners = map[PropertyName][]func(View, PropertyName){}
|
||||||
|
|
||||||
setListeners := func(event string, listener func(View, string)) {
|
setListeners := func(event PropertyName, listener func(View, PropertyName)) {
|
||||||
var listeners []func(View, string) = nil
|
var listeners []func(View, PropertyName) = nil
|
||||||
if value := view.Get(event); value != nil {
|
if value := view.Get(event); value != nil {
|
||||||
if oldListeners, ok := value.([]func(View, string)); ok && len(oldListeners) > 0 {
|
if oldListeners, ok := value.([]func(View, PropertyName)); ok && len(oldListeners) > 0 {
|
||||||
listeners = oldListeners
|
listeners = oldListeners
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ func (animation *animationData) Start(view View, listener func(view View, animat
|
||||||
|
|
||||||
func (animation *animationData) finish() {
|
func (animation *animationData) finish() {
|
||||||
if animation.view != nil {
|
if animation.view != nil {
|
||||||
for _, event := range []string{AnimationStartEvent, AnimationEndEvent, AnimationCancelEvent, AnimationIterationEvent} {
|
for _, event := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationCancelEvent, AnimationIterationEvent} {
|
||||||
if listeners, ok := animation.oldListeners[event]; ok {
|
if listeners, ok := animation.oldListeners[event]; ok {
|
||||||
animation.view.Set(event, listeners)
|
animation.view.Set(event, listeners)
|
||||||
} else {
|
} else {
|
||||||
|
@ -63,7 +63,7 @@ func (animation *animationData) finish() {
|
||||||
animation.view.Set(AnimationTag, "")
|
animation.view.Set(AnimationTag, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
animation.oldListeners = map[string][]func(View, string){}
|
animation.oldListeners = map[PropertyName][]func(View, PropertyName){}
|
||||||
|
|
||||||
animation.view = nil
|
animation.view = nil
|
||||||
animation.listener = nil
|
animation.listener = nil
|
||||||
|
@ -86,13 +86,13 @@ func (animation *animationData) Resume() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (animation *animationData) onAnimationStart(view View, _ string) {
|
func (animation *animationData) onAnimationStart(view View, _ PropertyName) {
|
||||||
if animation.view != nil && animation.listener != nil {
|
if animation.view != nil && animation.listener != nil {
|
||||||
animation.listener(animation.view, animation, AnimationStartEvent)
|
animation.listener(animation.view, animation, AnimationStartEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (animation *animationData) onAnimationEnd(view View, _ string) {
|
func (animation *animationData) onAnimationEnd(view View, _ PropertyName) {
|
||||||
if animation.view != nil {
|
if animation.view != nil {
|
||||||
animationView := animation.view
|
animationView := animation.view
|
||||||
listener := animation.listener
|
listener := animation.listener
|
||||||
|
@ -112,13 +112,13 @@ func (animation *animationData) onAnimationEnd(view View, _ string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (animation *animationData) onAnimationIteration(view View, _ string) {
|
func (animation *animationData) onAnimationIteration(view View, _ PropertyName) {
|
||||||
if animation.view != nil && animation.listener != nil {
|
if animation.view != nil && animation.listener != nil {
|
||||||
animation.listener(animation.view, animation, AnimationIterationEvent)
|
animation.listener(animation.view, animation, AnimationIterationEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (animation *animationData) onAnimationCancel(view View, _ string) {
|
func (animation *animationData) onAnimationCancel(view View, _ PropertyName) {
|
||||||
if animation.view != nil {
|
if animation.view != nil {
|
||||||
animationView := animation.view
|
animationView := animation.view
|
||||||
listener := animation.listener
|
listener := animation.listener
|
||||||
|
|
|
@ -215,6 +215,14 @@ function appendToInnerHTML(elementId, content) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appendToInputValue(elementId, content) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.value += content;
|
||||||
|
scanElementsSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setDisabled(elementId, disabled) {
|
function setDisabled(elementId, disabled) {
|
||||||
const element = document.getElementById(elementId);
|
const element = document.getElementById(elementId);
|
||||||
if (element) {
|
if (element) {
|
||||||
|
|
|
@ -13,13 +13,12 @@ type audioPlayerData struct {
|
||||||
func NewAudioPlayer(session Session, params Params) AudioPlayer {
|
func NewAudioPlayer(session Session, params Params) AudioPlayer {
|
||||||
view := new(audioPlayerData)
|
view := new(audioPlayerData)
|
||||||
view.init(session)
|
view.init(session)
|
||||||
view.tag = "AudioPlayer"
|
|
||||||
setInitParams(view, params)
|
setInitParams(view, params)
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAudioPlayer(session Session) View {
|
func newAudioPlayer(session Session) View {
|
||||||
return NewAudioPlayer(session, nil)
|
return new(audioPlayerData) // NewAudioPlayer(session, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *audioPlayerData) init(session Session) {
|
func (player *audioPlayerData) init(session Session) {
|
||||||
|
@ -27,10 +26,6 @@ func (player *audioPlayerData) init(session Session) {
|
||||||
player.tag = "AudioPlayer"
|
player.tag = "AudioPlayer"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *audioPlayerData) String() string {
|
|
||||||
return getViewString(player, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *audioPlayerData) htmlTag() string {
|
func (player *audioPlayerData) htmlTag() string {
|
||||||
return "audio"
|
return "audio"
|
||||||
}
|
}
|
||||||
|
|
124
background.go
124
background.go
|
@ -78,7 +78,7 @@ type BackgroundElement interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type backgroundElement struct {
|
type backgroundElement struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
type backgroundImage struct {
|
type backgroundImage struct {
|
||||||
|
@ -91,24 +91,16 @@ func createBackground(obj DataObject) BackgroundElement {
|
||||||
|
|
||||||
switch obj.Tag() {
|
switch obj.Tag() {
|
||||||
case "image":
|
case "image":
|
||||||
image := new(backgroundImage)
|
result = NewBackgroundImage(nil)
|
||||||
image.properties = map[string]any{}
|
|
||||||
result = image
|
|
||||||
|
|
||||||
case "linear-gradient":
|
case "linear-gradient":
|
||||||
gradient := new(backgroundLinearGradient)
|
result = NewBackgroundLinearGradient(nil)
|
||||||
gradient.properties = map[string]any{}
|
|
||||||
result = gradient
|
|
||||||
|
|
||||||
case "radial-gradient":
|
case "radial-gradient":
|
||||||
gradient := new(backgroundRadialGradient)
|
result = NewBackgroundRadialGradient(nil)
|
||||||
gradient.properties = map[string]any{}
|
|
||||||
result = gradient
|
|
||||||
|
|
||||||
case "conic-gradient":
|
case "conic-gradient":
|
||||||
gradient := new(backgroundConicGradient)
|
result = NewBackgroundConicGradient(nil)
|
||||||
gradient.properties = map[string]any{}
|
|
||||||
result = gradient
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
|
@ -118,7 +110,7 @@ func createBackground(obj DataObject) BackgroundElement {
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
if node := obj.Property(i); node.Type() == TextNode {
|
if node := obj.Property(i); node.Type() == TextNode {
|
||||||
if value := node.Text(); value != "" {
|
if value := node.Text(); value != "" {
|
||||||
result.Set(node.Tag(), value)
|
result.Set(PropertyName(node.Tag()), value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,13 +121,21 @@ func createBackground(obj DataObject) BackgroundElement {
|
||||||
// NewBackgroundImage creates the new background image
|
// NewBackgroundImage creates the new background image
|
||||||
func NewBackgroundImage(params Params) BackgroundElement {
|
func NewBackgroundImage(params Params) BackgroundElement {
|
||||||
result := new(backgroundImage)
|
result := new(backgroundImage)
|
||||||
result.properties = map[string]any{}
|
result.init()
|
||||||
for tag, value := range params {
|
for tag, value := range params {
|
||||||
result.Set(tag, value)
|
result.Set(tag, value)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (image *backgroundImage) init() {
|
||||||
|
image.backgroundElement.init()
|
||||||
|
image.normalize = normalizeBackgroundImageTag
|
||||||
|
image.supportedProperties = []PropertyName{
|
||||||
|
Attachment, Width, Height, Repeat, ImageHorizontalAlign, ImageVerticalAlign, backgroundFit, Source,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (image *backgroundImage) Tag() string {
|
func (image *backgroundImage) Tag() string {
|
||||||
return "image"
|
return "image"
|
||||||
}
|
}
|
||||||
|
@ -148,8 +148,8 @@ func (image *backgroundImage) Clone() BackgroundElement {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (image *backgroundImage) normalizeTag(tag string) string {
|
func normalizeBackgroundImageTag(tag PropertyName) PropertyName {
|
||||||
tag = strings.ToLower(tag)
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case "source":
|
case "source":
|
||||||
tag = Source
|
tag = Source
|
||||||
|
@ -167,21 +167,6 @@ func (image *backgroundImage) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (image *backgroundImage) Set(tag string, value any) bool {
|
|
||||||
tag = image.normalizeTag(tag)
|
|
||||||
switch tag {
|
|
||||||
case Attachment, Width, Height, Repeat, ImageHorizontalAlign, ImageVerticalAlign,
|
|
||||||
backgroundFit, Source:
|
|
||||||
return image.backgroundElement.Set(tag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (image *backgroundImage) Get(tag string) any {
|
|
||||||
return image.backgroundElement.Get(image.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (image *backgroundImage) cssStyle(session Session) string {
|
func (image *backgroundImage) cssStyle(session Session) string {
|
||||||
if src, ok := imageProperty(image, Source, session); ok && src != "" {
|
if src, ok := imageProperty(image, Source, session); ok && src != "" {
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
|
@ -252,7 +237,7 @@ func (image *backgroundImage) cssStyle(session Session) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (image *backgroundImage) writeString(buffer *strings.Builder, indent string) {
|
func (image *backgroundImage) writeString(buffer *strings.Builder, indent string) {
|
||||||
image.writeToBuffer(buffer, indent, image.Tag(), []string{
|
image.writeToBuffer(buffer, indent, image.Tag(), []PropertyName{
|
||||||
Source,
|
Source,
|
||||||
Width,
|
Width,
|
||||||
Height,
|
Height,
|
||||||
|
@ -267,3 +252,76 @@ func (image *backgroundImage) writeString(buffer *strings.Builder, indent string
|
||||||
func (image *backgroundImage) String() string {
|
func (image *backgroundImage) String() string {
|
||||||
return runStringWriter(image)
|
return runStringWriter(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setBackgroundProperty(properties Properties, value any) []PropertyName {
|
||||||
|
background := []BackgroundElement{}
|
||||||
|
|
||||||
|
error := func() []PropertyName {
|
||||||
|
notCompatibleType(Background, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case BackgroundElement:
|
||||||
|
background = []BackgroundElement{value}
|
||||||
|
|
||||||
|
case []BackgroundElement:
|
||||||
|
background = value
|
||||||
|
|
||||||
|
case []DataValue:
|
||||||
|
for _, el := range value {
|
||||||
|
if el.IsObject() {
|
||||||
|
if element := createBackground(el.Object()); element != nil {
|
||||||
|
background = append(background, element)
|
||||||
|
} else {
|
||||||
|
return error()
|
||||||
|
}
|
||||||
|
} else if obj := ParseDataText(el.Value()); obj != nil {
|
||||||
|
if element := createBackground(obj); element != nil {
|
||||||
|
background = append(background, element)
|
||||||
|
} else {
|
||||||
|
return error()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case DataObject:
|
||||||
|
if element := createBackground(value); element != nil {
|
||||||
|
background = []BackgroundElement{element}
|
||||||
|
} else {
|
||||||
|
return error()
|
||||||
|
}
|
||||||
|
|
||||||
|
case []DataObject:
|
||||||
|
for _, obj := range value {
|
||||||
|
if element := createBackground(obj); element != nil {
|
||||||
|
background = append(background, element)
|
||||||
|
} else {
|
||||||
|
return error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case string:
|
||||||
|
if obj := ParseDataText(value); obj != nil {
|
||||||
|
if element := createBackground(obj); element != nil {
|
||||||
|
background = []BackgroundElement{element}
|
||||||
|
} else {
|
||||||
|
return error()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(background) > 0 {
|
||||||
|
properties.setRaw(Background, background)
|
||||||
|
} else if properties.getRaw(Background) != nil {
|
||||||
|
properties.setRaw(Background, nil)
|
||||||
|
} else {
|
||||||
|
return []PropertyName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return []PropertyName{Background}
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ type BackgroundGradientAngle struct {
|
||||||
// NewBackgroundConicGradient creates the new background conic gradient
|
// NewBackgroundConicGradient creates the new background conic gradient
|
||||||
func NewBackgroundConicGradient(params Params) BackgroundElement {
|
func NewBackgroundConicGradient(params Params) BackgroundElement {
|
||||||
result := new(backgroundConicGradient)
|
result := new(backgroundConicGradient)
|
||||||
result.properties = map[string]any{}
|
result.init()
|
||||||
for tag, value := range params {
|
for tag, value := range params {
|
||||||
result.Set(tag, value)
|
result.Set(tag, value)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ func (point *BackgroundGradientAngle) String() string {
|
||||||
|
|
||||||
case AngleUnit:
|
case AngleUnit:
|
||||||
result += " " + value.String()
|
result += " " + value.String()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +114,15 @@ func (point *BackgroundGradientAngle) cssString(session Session, buffer *strings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gradient *backgroundConicGradient) init() {
|
||||||
|
gradient.backgroundElement.init()
|
||||||
|
gradient.normalize = normalizeConicGradientTag
|
||||||
|
gradient.set = backgroundConicGradientSet
|
||||||
|
gradient.supportedProperties = []PropertyName{
|
||||||
|
CenterX, CenterY, Repeating, From, Gradient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (gradient *backgroundConicGradient) Tag() string {
|
func (gradient *backgroundConicGradient) Tag() string {
|
||||||
return "conic-gradient"
|
return "conic-gradient"
|
||||||
}
|
}
|
||||||
|
@ -127,8 +135,8 @@ func (image *backgroundConicGradient) Clone() BackgroundElement {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundConicGradient) normalizeTag(tag string) string {
|
func normalizeConicGradientTag(tag PropertyName) PropertyName {
|
||||||
tag = strings.ToLower(tag)
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case "x-center":
|
case "x-center":
|
||||||
tag = CenterX
|
tag = CenterX
|
||||||
|
@ -140,18 +148,50 @@ func (gradient *backgroundConicGradient) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundConicGradient) Set(tag string, value any) bool {
|
func backgroundConicGradientSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
tag = gradient.normalizeTag(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case CenterX, CenterY, Repeating, From:
|
|
||||||
return gradient.propertyList.Set(tag, value)
|
|
||||||
|
|
||||||
case Gradient:
|
case Gradient:
|
||||||
return gradient.setGradient(value)
|
switch value := value.(type) {
|
||||||
|
case string:
|
||||||
|
if value == "" {
|
||||||
|
return propertiesRemove(properties, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLogF(`"%s" property is not supported by BackgroundConicGradient`, tag)
|
if strings.Contains(value, ",") || strings.Contains(value, " ") {
|
||||||
return false
|
if vector := parseGradientText(value); vector != nil {
|
||||||
|
properties.setRaw(Gradient, vector)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
} else if isConstantName(value) {
|
||||||
|
properties.setRaw(Gradient, value)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorLogF(`Invalid conic gradient: "%s"`, value)
|
||||||
|
|
||||||
|
case []BackgroundGradientAngle:
|
||||||
|
count := len(value)
|
||||||
|
if count < 2 {
|
||||||
|
ErrorLog("The gradient must contain at least 2 points")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, point := range value {
|
||||||
|
if point.Color == nil {
|
||||||
|
ErrorLogF("Invalid %d element of the conic gradient: Color is nil", i)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
properties.setRaw(Gradient, value)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
|
||||||
|
default:
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return propertiesSet(properties, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundConicGradient) stringToAngle(text string) (any, bool) {
|
func (gradient *backgroundConicGradient) stringToAngle(text string) (any, bool) {
|
||||||
|
@ -216,57 +256,6 @@ func (gradient *backgroundConicGradient) parseGradientText(value string) []Backg
|
||||||
}
|
}
|
||||||
return vector
|
return vector
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundConicGradient) setGradient(value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
delete(gradient.properties, Gradient)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case string:
|
|
||||||
if value == "" {
|
|
||||||
delete(gradient.properties, Gradient)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(value, ",") || strings.Contains(value, " ") {
|
|
||||||
if vector := gradient.parseGradientText(value); vector != nil {
|
|
||||||
gradient.properties[Gradient] = vector
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
} else if value[0] == '@' {
|
|
||||||
gradient.properties[Gradient] = value
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorLogF(`Invalid conic gradient: "%s"`, value)
|
|
||||||
return false
|
|
||||||
|
|
||||||
case []BackgroundGradientAngle:
|
|
||||||
count := len(value)
|
|
||||||
if count < 2 {
|
|
||||||
ErrorLog("The gradient must contain at least 2 points")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, point := range value {
|
|
||||||
if point.Color == nil {
|
|
||||||
ErrorLogF("Invalid %d element of the conic gradient: Color is nil", i)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gradient.properties[Gradient] = value
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gradient *backgroundConicGradient) Get(tag string) any {
|
|
||||||
return gradient.backgroundElement.Get(gradient.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gradient *backgroundConicGradient) cssStyle(session Session) string {
|
func (gradient *backgroundConicGradient) cssStyle(session Session) string {
|
||||||
|
|
||||||
points := []BackgroundGradientAngle{}
|
points := []BackgroundGradientAngle{}
|
||||||
|
@ -339,7 +328,7 @@ func (gradient *backgroundConicGradient) cssStyle(session Session) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundConicGradient) writeString(buffer *strings.Builder, indent string) {
|
func (gradient *backgroundConicGradient) writeString(buffer *strings.Builder, indent string) {
|
||||||
gradient.writeToBuffer(buffer, indent, gradient.Tag(), []string{
|
gradient.writeToBuffer(buffer, indent, gradient.Tag(), []PropertyName{
|
||||||
Gradient,
|
Gradient,
|
||||||
CenterX,
|
CenterX,
|
||||||
CenterY,
|
CenterY,
|
||||||
|
|
|
@ -72,7 +72,7 @@ type backgroundRadialGradient struct {
|
||||||
// NewBackgroundLinearGradient creates the new background linear gradient
|
// NewBackgroundLinearGradient creates the new background linear gradient
|
||||||
func NewBackgroundLinearGradient(params Params) BackgroundElement {
|
func NewBackgroundLinearGradient(params Params) BackgroundElement {
|
||||||
result := new(backgroundLinearGradient)
|
result := new(backgroundLinearGradient)
|
||||||
result.properties = map[string]any{}
|
result.init()
|
||||||
for tag, value := range params {
|
for tag, value := range params {
|
||||||
result.Set(tag, value)
|
result.Set(tag, value)
|
||||||
}
|
}
|
||||||
|
@ -82,14 +82,14 @@ func NewBackgroundLinearGradient(params Params) BackgroundElement {
|
||||||
// NewBackgroundRadialGradient creates the new background radial gradient
|
// NewBackgroundRadialGradient creates the new background radial gradient
|
||||||
func NewBackgroundRadialGradient(params Params) BackgroundElement {
|
func NewBackgroundRadialGradient(params Params) BackgroundElement {
|
||||||
result := new(backgroundRadialGradient)
|
result := new(backgroundRadialGradient)
|
||||||
result.properties = map[string]any{}
|
result.init()
|
||||||
for tag, value := range params {
|
for tag, value := range params {
|
||||||
result.Set(tag, value)
|
result.Set(tag, value)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundGradient) parseGradientText(value string) []BackgroundGradientPoint {
|
func parseGradientText(value string) []BackgroundGradientPoint {
|
||||||
elements := strings.Split(value, ",")
|
elements := strings.Split(value, ",")
|
||||||
count := len(elements)
|
count := len(elements)
|
||||||
if count < 2 {
|
if count < 2 {
|
||||||
|
@ -107,31 +107,31 @@ func (gradient *backgroundGradient) parseGradientText(value string) []Background
|
||||||
return points
|
return points
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundGradient) Set(tag string, value any) bool {
|
func backgroundGradientSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
|
||||||
switch tag = strings.ToLower(tag); tag {
|
switch tag {
|
||||||
case Repeating:
|
case Repeating:
|
||||||
return gradient.setBoolProperty(tag, value)
|
return setBoolProperty(properties, tag, value)
|
||||||
|
|
||||||
case Gradient:
|
case Gradient:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if value != "" {
|
if value != "" {
|
||||||
if strings.Contains(value, " ") || strings.Contains(value, ",") {
|
if strings.Contains(value, " ") || strings.Contains(value, ",") {
|
||||||
if points := gradient.parseGradientText(value); len(points) >= 2 {
|
if points := parseGradientText(value); len(points) >= 2 {
|
||||||
gradient.properties[Gradient] = points
|
properties.setRaw(Gradient, points)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
} else if value[0] == '@' {
|
} else if value[0] == '@' {
|
||||||
gradient.properties[Gradient] = value
|
properties.setRaw(Gradient, value)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case []BackgroundGradientPoint:
|
case []BackgroundGradientPoint:
|
||||||
if len(value) >= 2 {
|
if len(value) >= 2 {
|
||||||
gradient.properties[Gradient] = value
|
properties.setRaw(Gradient, value)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case []Color:
|
case []Color:
|
||||||
|
@ -141,8 +141,8 @@ func (gradient *backgroundGradient) Set(tag string, value any) bool {
|
||||||
for i, color := range value {
|
for i, color := range value {
|
||||||
points[i].Color = color
|
points[i].Color = color
|
||||||
}
|
}
|
||||||
gradient.properties[Gradient] = points
|
properties.setRaw(Gradient, points)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case []GradientPoint:
|
case []GradientPoint:
|
||||||
|
@ -153,17 +153,17 @@ func (gradient *backgroundGradient) Set(tag string, value any) bool {
|
||||||
points[i].Color = point.Color
|
points[i].Color = point.Color
|
||||||
points[i].Pos = Percent(point.Offset * 100)
|
points[i].Pos = Percent(point.Offset * 100)
|
||||||
}
|
}
|
||||||
gradient.properties[Gradient] = points
|
properties.setRaw(Gradient, points)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLogF("Invalid gradient %v", value)
|
ErrorLogF("Invalid gradient %v", value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLogF("Property %s is not supported by a background gradient", tag)
|
ErrorLogF("Property %s is not supported by a background gradient", tag)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (point *BackgroundGradientPoint) setValue(text string) bool {
|
func (point *BackgroundGradientPoint) setValue(text string) bool {
|
||||||
|
@ -266,7 +266,7 @@ func (gradient *backgroundGradient) writeGradient(session Session, buffer *strin
|
||||||
case string:
|
case string:
|
||||||
if value != "" && value[0] == '@' {
|
if value != "" && value[0] == '@' {
|
||||||
if text, ok := session.Constant(value[1:]); ok {
|
if text, ok := session.Constant(value[1:]); ok {
|
||||||
points = gradient.parseGradientText(text)
|
points = parseGradientText(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,6 +312,13 @@ func (gradient *backgroundGradient) writeGradient(session Session, buffer *strin
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gradient *backgroundLinearGradient) init() {
|
||||||
|
gradient.backgroundElement.init()
|
||||||
|
gradient.set = backgroundLinearGradientSet
|
||||||
|
gradient.supportedProperties = append(gradient.supportedProperties, Direction)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (gradient *backgroundLinearGradient) Tag() string {
|
func (gradient *backgroundLinearGradient) Tag() string {
|
||||||
return "linear-gradient"
|
return "linear-gradient"
|
||||||
}
|
}
|
||||||
|
@ -324,26 +331,26 @@ func (image *backgroundLinearGradient) Clone() BackgroundElement {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundLinearGradient) Set(tag string, value any) bool {
|
func backgroundLinearGradientSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
if strings.ToLower(tag) == Direction {
|
if tag == Direction {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case AngleUnit:
|
case AngleUnit:
|
||||||
gradient.properties[Direction] = value
|
properties.setRaw(Direction, value)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if gradient.setSimpleProperty(tag, value) {
|
if setSimpleProperty(properties, tag, value) {
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
if angle, ok := StringToAngleUnit(value); ok {
|
if angle, ok := StringToAngleUnit(value); ok {
|
||||||
gradient.properties[Direction] = angle
|
properties.setRaw(Direction, angle)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gradient.setEnumProperty(tag, value, enumProperties[Direction].values)
|
return setEnumProperty(properties, tag, value, enumProperties[Direction].values)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gradient.backgroundGradient.Set(tag, value)
|
return backgroundGradientSet(properties, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundLinearGradient) cssStyle(session Session) string {
|
func (gradient *backgroundLinearGradient) cssStyle(session Session) string {
|
||||||
|
@ -400,7 +407,7 @@ func (gradient *backgroundLinearGradient) cssStyle(session Session) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundLinearGradient) writeString(buffer *strings.Builder, indent string) {
|
func (gradient *backgroundLinearGradient) writeString(buffer *strings.Builder, indent string) {
|
||||||
gradient.writeToBuffer(buffer, indent, gradient.Tag(), []string{
|
gradient.writeToBuffer(buffer, indent, gradient.Tag(), []PropertyName{
|
||||||
Gradient,
|
Gradient,
|
||||||
Repeating,
|
Repeating,
|
||||||
Direction,
|
Direction,
|
||||||
|
@ -411,6 +418,15 @@ func (gradient *backgroundLinearGradient) String() string {
|
||||||
return runStringWriter(gradient)
|
return runStringWriter(gradient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gradient *backgroundRadialGradient) init() {
|
||||||
|
gradient.backgroundElement.init()
|
||||||
|
gradient.normalize = normalizeRadialGradientTag
|
||||||
|
gradient.set = backgroundRadialGradientSet
|
||||||
|
gradient.supportedProperties = append(gradient.supportedProperties, []PropertyName{
|
||||||
|
RadialGradientRadius, RadialGradientShape, CenterX, CenterY,
|
||||||
|
}...)
|
||||||
|
}
|
||||||
|
|
||||||
func (gradient *backgroundRadialGradient) Tag() string {
|
func (gradient *backgroundRadialGradient) Tag() string {
|
||||||
return "radial-gradient"
|
return "radial-gradient"
|
||||||
}
|
}
|
||||||
|
@ -423,8 +439,8 @@ func (image *backgroundRadialGradient) Clone() BackgroundElement {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundRadialGradient) normalizeTag(tag string) string {
|
func normalizeRadialGradientTag(tag PropertyName) PropertyName {
|
||||||
tag = strings.ToLower(tag)
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case Radius:
|
case Radius:
|
||||||
tag = RadialGradientRadius
|
tag = RadialGradientRadius
|
||||||
|
@ -442,83 +458,75 @@ func (gradient *backgroundRadialGradient) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundRadialGradient) Set(tag string, value any) bool {
|
func backgroundRadialGradientSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
tag = gradient.normalizeTag(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case RadialGradientRadius:
|
case RadialGradientRadius:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case []SizeUnit:
|
case []SizeUnit:
|
||||||
switch len(value) {
|
switch len(value) {
|
||||||
case 0:
|
case 0:
|
||||||
delete(gradient.properties, RadialGradientRadius)
|
properties.setRaw(RadialGradientRadius, nil)
|
||||||
return true
|
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
if value[0].Type == Auto {
|
if value[0].Type == Auto {
|
||||||
delete(gradient.properties, RadialGradientRadius)
|
properties.setRaw(RadialGradientRadius, nil)
|
||||||
} else {
|
} else {
|
||||||
gradient.properties[RadialGradientRadius] = value[0]
|
properties.setRaw(RadialGradientRadius, value[0])
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
gradient.properties[RadialGradientRadius] = value
|
properties.setRaw(RadialGradientRadius, value)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case []any:
|
case []any:
|
||||||
switch len(value) {
|
switch len(value) {
|
||||||
case 0:
|
case 0:
|
||||||
delete(gradient.properties, RadialGradientRadius)
|
properties.setRaw(RadialGradientRadius, nil)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
return gradient.Set(RadialGradientRadius, value[0])
|
return backgroundRadialGradientSet(properties, RadialGradientRadius, value[0])
|
||||||
|
|
||||||
default:
|
default:
|
||||||
gradient.properties[RadialGradientRadius] = value
|
properties.setRaw(RadialGradientRadius, value)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if gradient.setSimpleProperty(RadialGradientRadius, value) {
|
if setSimpleProperty(properties, RadialGradientRadius, value) {
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
if size, err := stringToSizeUnit(value); err == nil {
|
if size, err := stringToSizeUnit(value); err == nil {
|
||||||
if size.Type == Auto {
|
if size.Type == Auto {
|
||||||
delete(gradient.properties, RadialGradientRadius)
|
properties.setRaw(RadialGradientRadius, nil)
|
||||||
} else {
|
} else {
|
||||||
gradient.properties[RadialGradientRadius] = size
|
properties.setRaw(RadialGradientRadius, size)
|
||||||
}
|
}
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
return gradient.setEnumProperty(RadialGradientRadius, value, enumProperties[RadialGradientRadius].values)
|
return setEnumProperty(properties, RadialGradientRadius, value, enumProperties[RadialGradientRadius].values)
|
||||||
|
|
||||||
case SizeUnit:
|
case SizeUnit:
|
||||||
if value.Type == Auto {
|
if value.Type == Auto {
|
||||||
delete(gradient.properties, RadialGradientRadius)
|
properties.setRaw(RadialGradientRadius, nil)
|
||||||
} else {
|
} else {
|
||||||
gradient.properties[RadialGradientRadius] = value
|
properties.setRaw(RadialGradientRadius, value)
|
||||||
}
|
}
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case int:
|
case int:
|
||||||
n := value
|
return setEnumProperty(properties, RadialGradientRadius, value, enumProperties[RadialGradientRadius].values)
|
||||||
if n >= 0 && n < len(enumProperties[RadialGradientRadius].values) {
|
|
||||||
return gradient.propertyList.Set(RadialGradientRadius, value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLogF(`Invalid value of "%s" property: %v`, tag, value)
|
ErrorLogF(`Invalid value of "%s" property: %v`, tag, value)
|
||||||
|
return nil
|
||||||
|
|
||||||
case RadialGradientShape, CenterX, CenterY:
|
case RadialGradientShape, CenterX, CenterY:
|
||||||
return gradient.propertyList.Set(tag, value)
|
return propertiesSet(properties, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gradient.backgroundGradient.Set(tag, value)
|
return backgroundGradientSet(properties, tag, value)
|
||||||
}
|
|
||||||
|
|
||||||
func (gradient *backgroundRadialGradient) Get(tag string) any {
|
|
||||||
return gradient.backgroundGradient.Get(gradient.normalizeTag(tag))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
||||||
|
@ -652,7 +660,7 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
func (gradient *backgroundRadialGradient) writeString(buffer *strings.Builder, indent string) {
|
func (gradient *backgroundRadialGradient) writeString(buffer *strings.Builder, indent string) {
|
||||||
gradient.writeToBuffer(buffer, indent, gradient.Tag(), []string{
|
gradient.writeToBuffer(buffer, indent, gradient.Tag(), []PropertyName{
|
||||||
Gradient,
|
Gradient,
|
||||||
CenterX,
|
CenterX,
|
||||||
CenterY,
|
CenterY,
|
||||||
|
|
444
border.go
444
border.go
|
@ -38,7 +38,7 @@ const (
|
||||||
// `2`(`DashedLine`) or "dashed" - Dashed line as a border.
|
// `2`(`DashedLine`) or "dashed" - Dashed line as a border.
|
||||||
// `3`(`DottedLine`) or "dotted" - Dotted line as a border.
|
// `3`(`DottedLine`) or "dotted" - Dotted line as a border.
|
||||||
// `4`(`DoubleLine`) or "double" - Double line as a border.
|
// `4`(`DoubleLine`) or "double" - Double line as a border.
|
||||||
LeftStyle = "left-style"
|
LeftStyle PropertyName = "left-style"
|
||||||
|
|
||||||
// RightStyle is the constant for "right-style" property tag.
|
// RightStyle is the constant for "right-style" property tag.
|
||||||
//
|
//
|
||||||
|
@ -53,7 +53,7 @@ const (
|
||||||
// `2`(`DashedLine`) or "dashed" - Dashed line as a border.
|
// `2`(`DashedLine`) or "dashed" - Dashed line as a border.
|
||||||
// `3`(`DottedLine`) or "dotted" - Dotted line as a border.
|
// `3`(`DottedLine`) or "dotted" - Dotted line as a border.
|
||||||
// `4`(`DoubleLine`) or "double" - Double line as a border.
|
// `4`(`DoubleLine`) or "double" - Double line as a border.
|
||||||
RightStyle = "right-style"
|
RightStyle PropertyName = "right-style"
|
||||||
|
|
||||||
// TopStyle is the constant for "top-style" property tag.
|
// TopStyle is the constant for "top-style" property tag.
|
||||||
//
|
//
|
||||||
|
@ -68,7 +68,7 @@ const (
|
||||||
// `2`(`DashedLine`) or "dashed" - Dashed line as a border.
|
// `2`(`DashedLine`) or "dashed" - Dashed line as a border.
|
||||||
// `3`(`DottedLine`) or "dotted" - Dotted line as a border.
|
// `3`(`DottedLine`) or "dotted" - Dotted line as a border.
|
||||||
// `4`(`DoubleLine`) or "double" - Double line as a border.
|
// `4`(`DoubleLine`) or "double" - Double line as a border.
|
||||||
TopStyle = "top-style"
|
TopStyle PropertyName = "top-style"
|
||||||
|
|
||||||
// BottomStyle is the constant for "bottom-style" property tag.
|
// BottomStyle is the constant for "bottom-style" property tag.
|
||||||
//
|
//
|
||||||
|
@ -83,7 +83,7 @@ const (
|
||||||
// `2`(`DashedLine`) or "dashed" - Dashed line as a border.
|
// `2`(`DashedLine`) or "dashed" - Dashed line as a border.
|
||||||
// `3`(`DottedLine`) or "dotted" - Dotted line as a border.
|
// `3`(`DottedLine`) or "dotted" - Dotted line as a border.
|
||||||
// `4`(`DoubleLine`) or "double" - Double line as a border.
|
// `4`(`DoubleLine`) or "double" - Double line as a border.
|
||||||
BottomStyle = "bottom-style"
|
BottomStyle PropertyName = "bottom-style"
|
||||||
|
|
||||||
// LeftWidth is the constant for "left-width" property tag.
|
// LeftWidth is the constant for "left-width" property tag.
|
||||||
//
|
//
|
||||||
|
@ -94,7 +94,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
LeftWidth = "left-width"
|
LeftWidth PropertyName = "left-width"
|
||||||
|
|
||||||
// RightWidth is the constant for "right-width" property tag.
|
// RightWidth is the constant for "right-width" property tag.
|
||||||
//
|
//
|
||||||
|
@ -105,7 +105,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RightWidth = "right-width"
|
RightWidth PropertyName = "right-width"
|
||||||
|
|
||||||
// TopWidth is the constant for "top-width" property tag.
|
// TopWidth is the constant for "top-width" property tag.
|
||||||
//
|
//
|
||||||
|
@ -116,7 +116,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TopWidth = "top-width"
|
TopWidth PropertyName = "top-width"
|
||||||
|
|
||||||
// BottomWidth is the constant for "bottom-width" property tag.
|
// BottomWidth is the constant for "bottom-width" property tag.
|
||||||
//
|
//
|
||||||
|
@ -127,7 +127,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
BottomWidth = "bottom-width"
|
BottomWidth PropertyName = "bottom-width"
|
||||||
|
|
||||||
// LeftColor is the constant for "left-color" property tag.
|
// LeftColor is the constant for "left-color" property tag.
|
||||||
//
|
//
|
||||||
|
@ -138,7 +138,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `Color`, other types converted to it during assignment.
|
// Internal type is `Color`, other types converted to it during assignment.
|
||||||
// See `Color` description for more details.
|
// See `Color` description for more details.
|
||||||
LeftColor = "left-color"
|
LeftColor PropertyName = "left-color"
|
||||||
|
|
||||||
// RightColor is the constant for "right-color" property tag.
|
// RightColor is the constant for "right-color" property tag.
|
||||||
//
|
//
|
||||||
|
@ -149,7 +149,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `Color`, other types converted to it during assignment.
|
// Internal type is `Color`, other types converted to it during assignment.
|
||||||
// See `Color` description for more details.
|
// See `Color` description for more details.
|
||||||
RightColor = "right-color"
|
RightColor PropertyName = "right-color"
|
||||||
|
|
||||||
// TopColor is the constant for "top-color" property tag.
|
// TopColor is the constant for "top-color" property tag.
|
||||||
//
|
//
|
||||||
|
@ -160,7 +160,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `Color`, other types converted to it during assignment.
|
// Internal type is `Color`, other types converted to it during assignment.
|
||||||
// See `Color` description for more details.
|
// See `Color` description for more details.
|
||||||
TopColor = "top-color"
|
TopColor PropertyName = "top-color"
|
||||||
|
|
||||||
// BottomColor is the constant for "bottom-color" property tag.
|
// BottomColor is the constant for "bottom-color" property tag.
|
||||||
//
|
//
|
||||||
|
@ -171,7 +171,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `Color`, other types converted to it during assignment.
|
// Internal type is `Color`, other types converted to it during assignment.
|
||||||
// See `Color` description for more details.
|
// See `Color` description for more details.
|
||||||
BottomColor = "bottom-color"
|
BottomColor PropertyName = "bottom-color"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BorderProperty is the interface of a view border data
|
// BorderProperty is the interface of a view border data
|
||||||
|
@ -183,7 +183,7 @@ type BorderProperty interface {
|
||||||
// ViewBorders returns top, right, bottom and left borders information all together
|
// ViewBorders returns top, right, bottom and left borders information all together
|
||||||
ViewBorders(session Session) ViewBorders
|
ViewBorders(session Session) ViewBorders
|
||||||
|
|
||||||
delete(tag string)
|
deleteTag(tag PropertyName) bool
|
||||||
cssStyle(builder cssBuilder, session Session)
|
cssStyle(builder cssBuilder, session Session)
|
||||||
cssWidth(builder cssBuilder, session Session)
|
cssWidth(builder cssBuilder, session Session)
|
||||||
cssColor(builder cssBuilder, session Session)
|
cssColor(builder cssBuilder, session Session)
|
||||||
|
@ -193,12 +193,12 @@ type BorderProperty interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type borderProperty struct {
|
type borderProperty struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBorderProperty(value any) BorderProperty {
|
func newBorderProperty(value any) BorderProperty {
|
||||||
border := new(borderProperty)
|
border := new(borderProperty)
|
||||||
border.properties = map[string]any{}
|
border.init()
|
||||||
|
|
||||||
if value != nil {
|
if value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
@ -270,9 +270,10 @@ func newBorderProperty(value any) BorderProperty {
|
||||||
// "width" (Width). Determines the line thickness (SizeUnit).
|
// "width" (Width). Determines the line thickness (SizeUnit).
|
||||||
func NewBorder(params Params) BorderProperty {
|
func NewBorder(params Params) BorderProperty {
|
||||||
border := new(borderProperty)
|
border := new(borderProperty)
|
||||||
border.properties = map[string]any{}
|
border.init()
|
||||||
|
|
||||||
if params != nil {
|
if params != nil {
|
||||||
for _, tag := range []string{Style, Width, ColorTag, Left, Right, Top, Bottom,
|
for _, tag := range []PropertyName{Style, Width, ColorTag, Left, Right, Top, Bottom,
|
||||||
LeftStyle, RightStyle, TopStyle, BottomStyle,
|
LeftStyle, RightStyle, TopStyle, BottomStyle,
|
||||||
LeftWidth, RightWidth, TopWidth, BottomWidth,
|
LeftWidth, RightWidth, TopWidth, BottomWidth,
|
||||||
LeftColor, RightColor, TopColor, BottomColor} {
|
LeftColor, RightColor, TopColor, BottomColor} {
|
||||||
|
@ -284,8 +285,37 @@ func NewBorder(params Params) BorderProperty {
|
||||||
return border
|
return border
|
||||||
}
|
}
|
||||||
|
|
||||||
func (border *borderProperty) normalizeTag(tag string) string {
|
func (border *borderProperty) init() {
|
||||||
tag = strings.ToLower(tag)
|
border.dataProperty.init()
|
||||||
|
border.normalize = normalizeBorderTag
|
||||||
|
border.get = borderGet
|
||||||
|
border.set = borderSet
|
||||||
|
border.remove = borderRemove
|
||||||
|
border.supportedProperties = []PropertyName{
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Top,
|
||||||
|
Bottom,
|
||||||
|
Style,
|
||||||
|
LeftStyle,
|
||||||
|
RightStyle,
|
||||||
|
TopStyle,
|
||||||
|
BottomStyle,
|
||||||
|
Width,
|
||||||
|
LeftWidth,
|
||||||
|
RightWidth,
|
||||||
|
TopWidth,
|
||||||
|
BottomWidth,
|
||||||
|
ColorTag,
|
||||||
|
LeftColor,
|
||||||
|
RightColor,
|
||||||
|
TopColor,
|
||||||
|
BottomColor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeBorderTag(tag PropertyName) PropertyName {
|
||||||
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case BorderLeft, CellBorderLeft:
|
case BorderLeft, CellBorderLeft:
|
||||||
return Left
|
return Left
|
||||||
|
@ -352,23 +382,23 @@ func (border *borderProperty) writeString(buffer *strings.Builder, indent string
|
||||||
buffer.WriteString("_{ ")
|
buffer.WriteString("_{ ")
|
||||||
comma := false
|
comma := false
|
||||||
|
|
||||||
write := func(tag string, value any) {
|
write := func(tag PropertyName, value any) {
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, BorderStyle, value, indent)
|
writePropertyValue(buffer, BorderStyle, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range []string{Style, Width, ColorTag} {
|
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
||||||
if value, ok := border.properties[tag]; ok {
|
if value, ok := border.properties[tag]; ok {
|
||||||
write(tag, value)
|
write(tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, side := range []string{Top, Right, Bottom, Left} {
|
for _, side := range []PropertyName{Top, Right, Bottom, Left} {
|
||||||
style, okStyle := border.properties[side+"-"+Style]
|
style, okStyle := border.properties[side+"-"+Style]
|
||||||
width, okWidth := border.properties[side+"-"+Width]
|
width, okWidth := border.properties[side+"-"+Width]
|
||||||
color, okColor := border.properties[side+"-"+ColorTag]
|
color, okColor := border.properties[side+"-"+ColorTag]
|
||||||
|
@ -378,7 +408,7 @@ func (border *borderProperty) writeString(buffer *strings.Builder, indent string
|
||||||
comma = false
|
comma = false
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(side)
|
buffer.WriteString(string(side))
|
||||||
buffer.WriteString(" = _{ ")
|
buffer.WriteString(" = _{ ")
|
||||||
if okStyle {
|
if okStyle {
|
||||||
write(Style, style)
|
write(Style, style)
|
||||||
|
@ -401,164 +431,96 @@ func (border *borderProperty) String() string {
|
||||||
return runStringWriter(border)
|
return runStringWriter(border)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (border *borderProperty) setSingleBorderObject(prefix string, obj DataObject) bool {
|
|
||||||
result := true
|
|
||||||
if text, ok := obj.PropertyValue(Style); ok {
|
|
||||||
if !border.setEnumProperty(prefix+"-style", text, enumProperties[BorderStyle].values) {
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if text, ok := obj.PropertyValue(ColorTag); ok {
|
|
||||||
if !border.setColorProperty(prefix+"-color", text) {
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if text, ok := obj.PropertyValue("width"); ok {
|
|
||||||
if !border.setSizeProperty(prefix+"-width", text) {
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (border *borderProperty) setBorderObject(obj DataObject) bool {
|
func (border *borderProperty) setBorderObject(obj DataObject) bool {
|
||||||
result := true
|
result := true
|
||||||
|
for i := 0; i < obj.PropertyCount(); i++ {
|
||||||
|
if node := obj.Property(i); node != nil {
|
||||||
|
tag := PropertyName(node.Tag())
|
||||||
|
switch node.Type() {
|
||||||
|
case TextNode:
|
||||||
|
if borderSet(border, tag, node.Text()) == nil {
|
||||||
|
result = false
|
||||||
|
}
|
||||||
|
|
||||||
for _, side := range []string{Top, Right, Bottom, Left} {
|
case ObjectNode:
|
||||||
if node := obj.PropertyByTag(side); node != nil {
|
if borderSet(border, tag, node.Object()) == nil {
|
||||||
if node.Type() == ObjectNode {
|
result = false
|
||||||
if !border.setSingleBorderObject(side, node.Object()) {
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(side, node)
|
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if text, ok := obj.PropertyValue(Style); ok {
|
|
||||||
values := split4Values(text)
|
|
||||||
styles := enumProperties[BorderStyle].values
|
|
||||||
switch len(values) {
|
|
||||||
case 1:
|
|
||||||
if !border.setEnumProperty(Style, values[0], styles) {
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
for n, tag := range [4]string{TopStyle, RightStyle, BottomStyle, LeftStyle} {
|
|
||||||
if !border.setEnumProperty(tag, values[n], styles) {
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
notCompatibleType(Style, text)
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if text, ok := obj.PropertyValue(ColorTag); ok {
|
|
||||||
values := split4Values(text)
|
|
||||||
switch len(values) {
|
|
||||||
case 1:
|
|
||||||
if !border.setColorProperty(ColorTag, values[0]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
for n, tag := range [4]string{TopColor, RightColor, BottomColor, LeftColor} {
|
|
||||||
if !border.setColorProperty(tag, values[n]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
notCompatibleType(ColorTag, text)
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if text, ok := obj.PropertyValue(Width); ok {
|
|
||||||
values := split4Values(text)
|
|
||||||
switch len(values) {
|
|
||||||
case 1:
|
|
||||||
if !border.setSizeProperty(Width, values[0]) {
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
for n, tag := range [4]string{TopWidth, RightWidth, BottomWidth, LeftWidth} {
|
|
||||||
if !border.setSizeProperty(tag, values[n]) {
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
notCompatibleType(Width, text)
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (border *borderProperty) Remove(tag string) {
|
func borderRemove(properties Properties, tag PropertyName) []PropertyName {
|
||||||
tag = border.normalizeTag(tag)
|
result := []PropertyName{}
|
||||||
|
removeTag := func(t PropertyName) {
|
||||||
|
if properties.getRaw(t) != nil {
|
||||||
|
properties.setRaw(t, nil)
|
||||||
|
result = append(result, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Style:
|
case Style:
|
||||||
for _, t := range []string{tag, TopStyle, RightStyle, BottomStyle, LeftStyle} {
|
for _, t := range []PropertyName{tag, TopStyle, RightStyle, BottomStyle, LeftStyle} {
|
||||||
delete(border.properties, t)
|
removeTag(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Width:
|
case Width:
|
||||||
for _, t := range []string{tag, TopWidth, RightWidth, BottomWidth, LeftWidth} {
|
for _, t := range []PropertyName{tag, TopWidth, RightWidth, BottomWidth, LeftWidth} {
|
||||||
delete(border.properties, t)
|
removeTag(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
case ColorTag:
|
case ColorTag:
|
||||||
for _, t := range []string{tag, TopColor, RightColor, BottomColor, LeftColor} {
|
for _, t := range []PropertyName{tag, TopColor, RightColor, BottomColor, LeftColor} {
|
||||||
delete(border.properties, t)
|
removeTag(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Left, Right, Top, Bottom:
|
case Left, Right, Top, Bottom:
|
||||||
border.Remove(tag + "-style")
|
removeTag(tag + "-style")
|
||||||
border.Remove(tag + "-width")
|
removeTag(tag + "-width")
|
||||||
border.Remove(tag + "-color")
|
removeTag(tag + "-color")
|
||||||
|
|
||||||
case LeftStyle, RightStyle, TopStyle, BottomStyle:
|
case LeftStyle, RightStyle, TopStyle, BottomStyle:
|
||||||
delete(border.properties, tag)
|
removeTag(tag)
|
||||||
if style, ok := border.properties[Style]; ok && style != nil {
|
if style := properties.getRaw(Style); style != nil {
|
||||||
for _, t := range []string{TopStyle, RightStyle, BottomStyle, LeftStyle} {
|
for _, t := range []PropertyName{TopStyle, RightStyle, BottomStyle, LeftStyle} {
|
||||||
if t != tag {
|
if t != tag {
|
||||||
if _, ok := border.properties[t]; !ok {
|
if properties.getRaw(t) == nil {
|
||||||
border.properties[t] = style
|
properties.setRaw(t, style)
|
||||||
|
result = append(result, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case LeftWidth, RightWidth, TopWidth, BottomWidth:
|
case LeftWidth, RightWidth, TopWidth, BottomWidth:
|
||||||
delete(border.properties, tag)
|
removeTag(tag)
|
||||||
if width, ok := border.properties[Width]; ok && width != nil {
|
if width := properties.getRaw(Width); width != nil {
|
||||||
for _, t := range []string{TopWidth, RightWidth, BottomWidth, LeftWidth} {
|
for _, t := range []PropertyName{TopWidth, RightWidth, BottomWidth, LeftWidth} {
|
||||||
if t != tag {
|
if t != tag {
|
||||||
if _, ok := border.properties[t]; !ok {
|
if properties.getRaw(t) == nil {
|
||||||
border.properties[t] = width
|
properties.setRaw(t, width)
|
||||||
|
result = append(result, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case LeftColor, RightColor, TopColor, BottomColor:
|
case LeftColor, RightColor, TopColor, BottomColor:
|
||||||
delete(border.properties, tag)
|
removeTag(tag)
|
||||||
if color, ok := border.properties[ColorTag]; ok && color != nil {
|
if color := properties.getRaw(ColorTag); color != nil {
|
||||||
for _, t := range []string{TopColor, RightColor, BottomColor, LeftColor} {
|
for _, t := range []PropertyName{TopColor, RightColor, BottomColor, LeftColor} {
|
||||||
if t != tag {
|
if t != tag {
|
||||||
if _, ok := border.properties[t]; !ok {
|
if properties.getRaw(t) == nil {
|
||||||
border.properties[t] = color
|
properties.setRaw(t, color)
|
||||||
|
result = append(result, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -567,80 +529,118 @@ func (border *borderProperty) Remove(tag string) {
|
||||||
default:
|
default:
|
||||||
ErrorLogF(`"%s" property is not compatible with the BorderProperty`, tag)
|
ErrorLogF(`"%s" property is not compatible with the BorderProperty`, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (border *borderProperty) Set(tag string, value any) bool {
|
func borderSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
if value == nil {
|
|
||||||
border.Remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
tag = border.normalizeTag(tag)
|
setSingleBorderObject := func(prefix PropertyName, obj DataObject) []PropertyName {
|
||||||
|
result := []PropertyName{}
|
||||||
|
if text, ok := obj.PropertyValue(string(Style)); ok {
|
||||||
|
props := setEnumProperty(properties, prefix+"-style", text, enumProperties[BorderStyle].values)
|
||||||
|
if props == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result = append(result, props...)
|
||||||
|
}
|
||||||
|
if text, ok := obj.PropertyValue(string(ColorTag)); ok {
|
||||||
|
props := setColorProperty(properties, prefix+"-color", text)
|
||||||
|
if props == nil && len(result) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result = append(result, props...)
|
||||||
|
}
|
||||||
|
if text, ok := obj.PropertyValue("width"); ok {
|
||||||
|
props := setSizeProperty(properties, prefix+"-width", text)
|
||||||
|
if props == nil && len(result) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result = append(result, props...)
|
||||||
|
}
|
||||||
|
if len(result) > 0 {
|
||||||
|
result = append(result, prefix)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Style:
|
case Style:
|
||||||
if border.setEnumProperty(Style, value, enumProperties[BorderStyle].values) {
|
if result := setEnumProperty(properties, Style, value, enumProperties[BorderStyle].values); result != nil {
|
||||||
for _, side := range []string{TopStyle, RightStyle, BottomStyle, LeftStyle} {
|
for _, side := range []PropertyName{TopStyle, RightStyle, BottomStyle, LeftStyle} {
|
||||||
delete(border.properties, side)
|
if value := properties.getRaw(side); value != nil {
|
||||||
|
properties.setRaw(side, nil)
|
||||||
|
result = append(result, side)
|
||||||
}
|
}
|
||||||
return true
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
case Width:
|
case Width:
|
||||||
if border.setSizeProperty(Width, value) {
|
if result := setSizeProperty(properties, Width, value); result != nil {
|
||||||
for _, side := range []string{TopWidth, RightWidth, BottomWidth, LeftWidth} {
|
for _, side := range []PropertyName{TopWidth, RightWidth, BottomWidth, LeftWidth} {
|
||||||
delete(border.properties, side)
|
if value := properties.getRaw(side); value != nil {
|
||||||
|
properties.setRaw(side, nil)
|
||||||
|
result = append(result, side)
|
||||||
}
|
}
|
||||||
return true
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
case ColorTag:
|
case ColorTag:
|
||||||
if border.setColorProperty(ColorTag, value) {
|
if result := setColorProperty(properties, ColorTag, value); result != nil {
|
||||||
for _, side := range []string{TopColor, RightColor, BottomColor, LeftColor} {
|
for _, side := range []PropertyName{TopColor, RightColor, BottomColor, LeftColor} {
|
||||||
delete(border.properties, side)
|
if value := properties.getRaw(side); value != nil {
|
||||||
|
properties.setRaw(side, nil)
|
||||||
|
result = append(result, side)
|
||||||
}
|
}
|
||||||
return true
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
case LeftStyle, RightStyle, TopStyle, BottomStyle:
|
case LeftStyle, RightStyle, TopStyle, BottomStyle:
|
||||||
return border.setEnumProperty(tag, value, enumProperties[BorderStyle].values)
|
return setEnumProperty(properties, tag, value, enumProperties[BorderStyle].values)
|
||||||
|
|
||||||
case LeftWidth, RightWidth, TopWidth, BottomWidth:
|
case LeftWidth, RightWidth, TopWidth, BottomWidth:
|
||||||
return border.setSizeProperty(tag, value)
|
return setSizeProperty(properties, tag, value)
|
||||||
|
|
||||||
case LeftColor, RightColor, TopColor, BottomColor:
|
case LeftColor, RightColor, TopColor, BottomColor:
|
||||||
return border.setColorProperty(tag, value)
|
return setColorProperty(properties, tag, value)
|
||||||
|
|
||||||
case Left, Right, Top, Bottom:
|
case Left, Right, Top, Bottom:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if obj := ParseDataText(value); obj != nil {
|
if obj := ParseDataText(value); obj != nil {
|
||||||
return border.setSingleBorderObject(tag, obj)
|
return setSingleBorderObject(tag, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
return border.setSingleBorderObject(tag, value)
|
return setSingleBorderObject(tag, value)
|
||||||
|
|
||||||
case BorderProperty:
|
case BorderProperty:
|
||||||
|
result := []PropertyName{}
|
||||||
styleTag := tag + "-" + Style
|
styleTag := tag + "-" + Style
|
||||||
if style := value.Get(styleTag); value != nil {
|
if style := value.Get(styleTag); value != nil {
|
||||||
border.properties[styleTag] = style
|
properties.setRaw(styleTag, style)
|
||||||
|
result = append(result, styleTag)
|
||||||
}
|
}
|
||||||
colorTag := tag + "-" + ColorTag
|
colorTag := tag + "-" + ColorTag
|
||||||
if color := value.Get(colorTag); value != nil {
|
if color := value.Get(colorTag); value != nil {
|
||||||
border.properties[colorTag] = color
|
properties.setRaw(colorTag, color)
|
||||||
|
result = append(result, colorTag)
|
||||||
}
|
}
|
||||||
widthTag := tag + "-" + Width
|
widthTag := tag + "-" + Width
|
||||||
if width := value.Get(widthTag); value != nil {
|
if width := value.Get(widthTag); value != nil {
|
||||||
border.properties[widthTag] = width
|
properties.setRaw(widthTag, width)
|
||||||
|
result = append(result, widthTag)
|
||||||
}
|
}
|
||||||
return true
|
return result
|
||||||
|
|
||||||
case ViewBorder:
|
case ViewBorder:
|
||||||
border.properties[tag+"-"+Style] = value.Style
|
properties.setRaw(tag+"-"+Style, value.Style)
|
||||||
border.properties[tag+"-"+Width] = value.Width
|
properties.setRaw(tag+"-"+Width, value.Width)
|
||||||
border.properties[tag+"-"+ColorTag] = value.Color
|
properties.setRaw(tag+"-"+ColorTag, value.Color)
|
||||||
return true
|
return []PropertyName{tag + "-" + Style, tag + "-" + Width, tag + "-" + ColorTag}
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
|
@ -648,105 +648,119 @@ func (border *borderProperty) Set(tag string, value any) bool {
|
||||||
ErrorLogF(`"%s" property is not compatible with the BorderProperty`, tag)
|
ErrorLogF(`"%s" property is not compatible with the BorderProperty`, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (border *borderProperty) Get(tag string) any {
|
func borderGet(properties Properties, tag PropertyName) any {
|
||||||
tag = border.normalizeTag(tag)
|
if result := properties.getRaw(tag); result != nil {
|
||||||
|
|
||||||
if result, ok := border.properties[tag]; ok {
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Left, Right, Top, Bottom:
|
case Left, Right, Top, Bottom:
|
||||||
result := newBorderProperty(nil)
|
result := newBorderProperty(nil)
|
||||||
if style, ok := border.properties[tag+"-"+Style]; ok {
|
if style := properties.getRaw(tag + "-" + Style); style != nil {
|
||||||
result.Set(Style, style)
|
result.Set(Style, style)
|
||||||
} else if style, ok := border.properties[Style]; ok {
|
} else if style := properties.getRaw(Style); style != nil {
|
||||||
result.Set(Style, style)
|
result.Set(Style, style)
|
||||||
}
|
}
|
||||||
if width, ok := border.properties[tag+"-"+Width]; ok {
|
if width := properties.getRaw(tag + "-" + Width); width != nil {
|
||||||
result.Set(Width, width)
|
result.Set(Width, width)
|
||||||
} else if width, ok := border.properties[Width]; ok {
|
} else if width := properties.getRaw(Width); width != nil {
|
||||||
result.Set(Width, width)
|
result.Set(Width, width)
|
||||||
}
|
}
|
||||||
if color, ok := border.properties[tag+"-"+ColorTag]; ok {
|
if color := properties.getRaw(tag + "-" + ColorTag); color != nil {
|
||||||
result.Set(ColorTag, color)
|
result.Set(ColorTag, color)
|
||||||
} else if color, ok := border.properties[ColorTag]; ok {
|
} else if color := properties.getRaw(ColorTag); color != nil {
|
||||||
result.Set(ColorTag, color)
|
result.Set(ColorTag, color)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
case LeftStyle, RightStyle, TopStyle, BottomStyle:
|
case LeftStyle, RightStyle, TopStyle, BottomStyle:
|
||||||
if style, ok := border.properties[tag]; ok {
|
if style := properties.getRaw(tag); style != nil {
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
return border.properties[Style]
|
return properties.getRaw(Style)
|
||||||
|
|
||||||
case LeftWidth, RightWidth, TopWidth, BottomWidth:
|
case LeftWidth, RightWidth, TopWidth, BottomWidth:
|
||||||
if width, ok := border.properties[tag]; ok {
|
if width := properties.getRaw(tag); width != nil {
|
||||||
return width
|
return width
|
||||||
}
|
}
|
||||||
return border.properties[Width]
|
return properties.getRaw(Width)
|
||||||
|
|
||||||
case LeftColor, RightColor, TopColor, BottomColor:
|
case LeftColor, RightColor, TopColor, BottomColor:
|
||||||
if color, ok := border.properties[tag]; ok {
|
if color := properties.getRaw(tag); color != nil {
|
||||||
return color
|
return color
|
||||||
}
|
}
|
||||||
return border.properties[ColorTag]
|
return properties.getRaw(ColorTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (border *borderProperty) delete(tag string) {
|
func (border *borderProperty) deleteTag(tag PropertyName) bool {
|
||||||
tag = border.normalizeTag(tag)
|
|
||||||
remove := []string{}
|
result := false
|
||||||
|
removeTags := func(tags []PropertyName) {
|
||||||
|
for _, tag := range tags {
|
||||||
|
if border.getRaw(tag) != nil {
|
||||||
|
border.setRaw(tag, nil)
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Style:
|
case Style:
|
||||||
remove = []string{Style, LeftStyle, RightStyle, TopStyle, BottomStyle}
|
removeTags([]PropertyName{Style, LeftStyle, RightStyle, TopStyle, BottomStyle})
|
||||||
|
|
||||||
case Width:
|
case Width:
|
||||||
remove = []string{Width, LeftWidth, RightWidth, TopWidth, BottomWidth}
|
removeTags([]PropertyName{Width, LeftWidth, RightWidth, TopWidth, BottomWidth})
|
||||||
|
|
||||||
case ColorTag:
|
case ColorTag:
|
||||||
remove = []string{ColorTag, LeftColor, RightColor, TopColor, BottomColor}
|
removeTags([]PropertyName{ColorTag, LeftColor, RightColor, TopColor, BottomColor})
|
||||||
|
|
||||||
case Left, Right, Top, Bottom:
|
case Left, Right, Top, Bottom:
|
||||||
if border.Get(Style) != nil {
|
if border.Get(Style) != nil {
|
||||||
border.properties[tag+"-"+Style] = 0
|
border.properties[tag+"-"+Style] = 0
|
||||||
remove = []string{tag + "-" + ColorTag, tag + "-" + Width}
|
result = true
|
||||||
|
removeTags([]PropertyName{tag + "-" + ColorTag, tag + "-" + Width})
|
||||||
} else {
|
} else {
|
||||||
remove = []string{tag + "-" + Style, tag + "-" + ColorTag, tag + "-" + Width}
|
removeTags([]PropertyName{tag + "-" + Style, tag + "-" + ColorTag, tag + "-" + Width})
|
||||||
}
|
}
|
||||||
|
|
||||||
case LeftStyle, RightStyle, TopStyle, BottomStyle:
|
case LeftStyle, RightStyle, TopStyle, BottomStyle:
|
||||||
|
if border.getRaw(tag) != nil {
|
||||||
if border.Get(Style) != nil {
|
if border.Get(Style) != nil {
|
||||||
border.properties[tag] = 0
|
border.properties[tag] = 0
|
||||||
|
result = true
|
||||||
} else {
|
} else {
|
||||||
remove = []string{tag}
|
removeTags([]PropertyName{tag})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case LeftWidth, RightWidth, TopWidth, BottomWidth:
|
case LeftWidth, RightWidth, TopWidth, BottomWidth:
|
||||||
|
if border.getRaw(tag) != nil {
|
||||||
if border.Get(Width) != nil {
|
if border.Get(Width) != nil {
|
||||||
border.properties[tag] = AutoSize()
|
border.properties[tag] = AutoSize()
|
||||||
|
result = true
|
||||||
} else {
|
} else {
|
||||||
remove = []string{tag}
|
removeTags([]PropertyName{tag})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case LeftColor, RightColor, TopColor, BottomColor:
|
case LeftColor, RightColor, TopColor, BottomColor:
|
||||||
|
if border.getRaw(tag) != nil {
|
||||||
if border.Get(ColorTag) != nil {
|
if border.Get(ColorTag) != nil {
|
||||||
border.properties[tag] = 0
|
border.properties[tag] = 0
|
||||||
|
result = true
|
||||||
} else {
|
} else {
|
||||||
remove = []string{tag}
|
removeTags([]PropertyName{tag})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range remove {
|
return result
|
||||||
delete(border.properties, tag)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (border *borderProperty) ViewBorders(session Session) ViewBorders {
|
func (border *borderProperty) ViewBorders(session Session) ViewBorders {
|
||||||
|
@ -755,7 +769,7 @@ func (border *borderProperty) ViewBorders(session Session) ViewBorders {
|
||||||
defWidth, _ := sizeProperty(border, Width, session)
|
defWidth, _ := sizeProperty(border, Width, session)
|
||||||
defColor, _ := colorProperty(border, ColorTag, session)
|
defColor, _ := colorProperty(border, ColorTag, session)
|
||||||
|
|
||||||
getBorder := func(prefix string) ViewBorder {
|
getBorder := func(prefix PropertyName) ViewBorder {
|
||||||
var result ViewBorder
|
var result ViewBorder
|
||||||
var ok bool
|
var ok bool
|
||||||
if result.Style, ok = valueToEnum(border.getRaw(prefix+Style), BorderStyle, session, NoneLine); !ok {
|
if result.Style, ok = valueToEnum(border.getRaw(prefix+Style), BorderStyle, session, NoneLine); !ok {
|
||||||
|
@ -784,9 +798,9 @@ func (border *borderProperty) cssStyle(builder cssBuilder, session Session) {
|
||||||
if borders.Top.Style == borders.Right.Style &&
|
if borders.Top.Style == borders.Right.Style &&
|
||||||
borders.Top.Style == borders.Left.Style &&
|
borders.Top.Style == borders.Left.Style &&
|
||||||
borders.Top.Style == borders.Bottom.Style {
|
borders.Top.Style == borders.Bottom.Style {
|
||||||
builder.add(BorderStyle, values[borders.Top.Style])
|
builder.add(string(BorderStyle), values[borders.Top.Style])
|
||||||
} else {
|
} else {
|
||||||
builder.addValues(BorderStyle, " ", values[borders.Top.Style],
|
builder.addValues(string(BorderStyle), " ", values[borders.Top.Style],
|
||||||
values[borders.Right.Style], values[borders.Bottom.Style], values[borders.Left.Style])
|
values[borders.Right.Style], values[borders.Bottom.Style], values[borders.Left.Style])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -870,11 +884,25 @@ func (border *ViewBorders) AllTheSame() bool {
|
||||||
border.Top.Width.Equal(border.Bottom.Width)
|
border.Top.Width.Equal(border.Bottom.Width)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBorder(style Properties, tag string) BorderProperty {
|
func getBorderProperty(properties Properties, tag PropertyName) BorderProperty {
|
||||||
if value := style.Get(tag); value != nil {
|
if value := properties.getRaw(tag); value != nil {
|
||||||
if border, ok := value.(BorderProperty); ok {
|
if border, ok := value.(BorderProperty); ok {
|
||||||
return border
|
return border
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setBorderPropertyElement(properties Properties, mainTag, tag PropertyName, value any) []PropertyName {
|
||||||
|
border := getBorderProperty(properties, mainTag)
|
||||||
|
if border == nil {
|
||||||
|
border = NewBorder(nil)
|
||||||
|
if border.Set(tag, value) {
|
||||||
|
properties.setRaw(mainTag, border)
|
||||||
|
return []PropertyName{mainTag, tag}
|
||||||
|
}
|
||||||
|
} else if border.Set(tag, value) {
|
||||||
|
return []PropertyName{mainTag, tag}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
177
bounds.go
177
bounds.go
|
@ -16,26 +16,33 @@ type BoundsProperty interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type boundsPropertyData struct {
|
type boundsPropertyData struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBoundsProperty creates the new BoundsProperty object.
|
// NewBoundsProperty creates the new BoundsProperty object.
|
||||||
// The following SizeUnit properties can be used: "left" (Left), "right" (Right), "top" (Top), and "bottom" (Bottom).
|
// The following SizeUnit properties can be used: "left" (Left), "right" (Right), "top" (Top), and "bottom" (Bottom).
|
||||||
func NewBoundsProperty(params Params) BoundsProperty {
|
func NewBoundsProperty(params Params) BoundsProperty {
|
||||||
bounds := new(boundsPropertyData)
|
bounds := new(boundsPropertyData)
|
||||||
bounds.properties = map[string]any{}
|
bounds.init()
|
||||||
|
|
||||||
if params != nil {
|
if params != nil {
|
||||||
for _, tag := range []string{Top, Right, Bottom, Left} {
|
for _, tag := range bounds.supportedProperties {
|
||||||
if value, ok := params[tag]; ok {
|
if value, ok := params[tag]; ok && value != nil {
|
||||||
bounds.Set(tag, value)
|
bounds.set(bounds, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bounds
|
return bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bounds *boundsPropertyData) normalizeTag(tag string) string {
|
func (bounds *boundsPropertyData) init() {
|
||||||
tag = strings.ToLower(tag)
|
bounds.dataProperty.init()
|
||||||
|
bounds.normalize = normalizeBoundsTag
|
||||||
|
bounds.supportedProperties = []PropertyName{Top, Right, Bottom, Left}
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeBoundsTag(tag PropertyName) PropertyName {
|
||||||
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case MarginTop, PaddingTop, CellPaddingTop,
|
case MarginTop, PaddingTop, CellPaddingTop,
|
||||||
"top-margin", "top-padding", "top-cell-padding":
|
"top-margin", "top-padding", "top-cell-padding":
|
||||||
|
@ -64,12 +71,12 @@ func (bounds *boundsPropertyData) String() string {
|
||||||
func (bounds *boundsPropertyData) writeString(buffer *strings.Builder, indent string) {
|
func (bounds *boundsPropertyData) writeString(buffer *strings.Builder, indent string) {
|
||||||
buffer.WriteString("_{ ")
|
buffer.WriteString("_{ ")
|
||||||
comma := false
|
comma := false
|
||||||
for _, tag := range []string{Top, Right, Bottom, Left} {
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left} {
|
||||||
if value, ok := bounds.properties[tag]; ok {
|
if value, ok := bounds.properties[tag]; ok {
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
|
@ -78,38 +85,6 @@ func (bounds *boundsPropertyData) writeString(buffer *strings.Builder, indent st
|
||||||
buffer.WriteString(" }")
|
buffer.WriteString(" }")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bounds *boundsPropertyData) Remove(tag string) {
|
|
||||||
bounds.propertyList.Remove(bounds.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bounds *boundsPropertyData) Set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
bounds.Remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
tag = bounds.normalizeTag(tag)
|
|
||||||
|
|
||||||
switch tag {
|
|
||||||
case Top, Right, Bottom, Left:
|
|
||||||
return bounds.setSizeProperty(tag, value)
|
|
||||||
|
|
||||||
default:
|
|
||||||
ErrorLogF(`"%s" property is not compatible with the BoundsProperty`, tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bounds *boundsPropertyData) Get(tag string) any {
|
|
||||||
tag = bounds.normalizeTag(tag)
|
|
||||||
if value, ok := bounds.properties[tag]; ok {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bounds *boundsPropertyData) Bounds(session Session) Bounds {
|
func (bounds *boundsPropertyData) Bounds(session Session) Bounds {
|
||||||
top, _ := sizeProperty(bounds, Top, session)
|
top, _ := sizeProperty(bounds, Top, session)
|
||||||
right, _ := sizeProperty(bounds, Right, session)
|
right, _ := sizeProperty(bounds, Right, session)
|
||||||
|
@ -141,7 +116,7 @@ func (bounds *Bounds) SetAll(value SizeUnit) {
|
||||||
bounds.Left = value
|
bounds.Left = value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bounds *Bounds) setFromProperties(tag, topTag, rightTag, bottomTag, leftTag string, properties Properties, session Session) {
|
func (bounds *Bounds) setFromProperties(tag, topTag, rightTag, bottomTag, leftTag PropertyName, properties Properties, session Session) {
|
||||||
bounds.Top = AutoSize()
|
bounds.Top = AutoSize()
|
||||||
if size, ok := sizeProperty(properties, tag, session); ok {
|
if size, ok := sizeProperty(properties, tag, session); ok {
|
||||||
bounds.Top = size
|
bounds.Top = size
|
||||||
|
@ -216,11 +191,11 @@ func (bounds *Bounds) String() string {
|
||||||
bounds.Bottom.String() + "," + bounds.Left.String()
|
bounds.Bottom.String() + "," + bounds.Left.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bounds *Bounds) cssValue(tag string, builder cssBuilder, session Session) {
|
func (bounds *Bounds) cssValue(tag PropertyName, builder cssBuilder, session Session) {
|
||||||
if bounds.allFieldsEqual() {
|
if bounds.allFieldsEqual() {
|
||||||
builder.add(tag, bounds.Top.cssString("0", session))
|
builder.add(string(tag), bounds.Top.cssString("0", session))
|
||||||
} else {
|
} else {
|
||||||
builder.addValues(tag, " ",
|
builder.addValues(string(tag), " ",
|
||||||
bounds.Top.cssString("0", session),
|
bounds.Top.cssString("0", session),
|
||||||
bounds.Right.cssString("0", session),
|
bounds.Right.cssString("0", session),
|
||||||
bounds.Bottom.cssString("0", session),
|
bounds.Bottom.cssString("0", session),
|
||||||
|
@ -234,8 +209,8 @@ func (bounds *Bounds) cssString(session Session) string {
|
||||||
return builder.finish()
|
return builder.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setBounds(tag string, value any) bool {
|
func setBoundsProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
if !properties.setSimpleProperty(tag, value) {
|
if !setSimpleProperty(properties, tag, value) {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if strings.Contains(value, ",") {
|
if strings.Contains(value, ",") {
|
||||||
|
@ -247,88 +222,119 @@ func (properties *propertyList) setBounds(tag string, value any) bool {
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
bounds := NewBoundsProperty(nil)
|
bounds := NewBoundsProperty(nil)
|
||||||
for i, tag := range []string{Top, Right, Bottom, Left} {
|
for i, tag := range []PropertyName{Top, Right, Bottom, Left} {
|
||||||
if !bounds.Set(tag, values[i]) {
|
if !bounds.Set(tag, values[i]) {
|
||||||
notCompatibleType(tag, value)
|
return nil
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
properties.properties[tag] = bounds
|
properties.setRaw(tag, bounds)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return properties.setSizeProperty(tag, value)
|
return setSizeProperty(properties, tag, value)
|
||||||
|
|
||||||
case SizeUnit:
|
case SizeUnit:
|
||||||
properties.properties[tag] = value
|
properties.setRaw(tag, value)
|
||||||
|
|
||||||
case float32:
|
case float32:
|
||||||
properties.properties[tag] = Px(float64(value))
|
properties.setRaw(tag, Px(float64(value)))
|
||||||
|
|
||||||
case float64:
|
case float64:
|
||||||
properties.properties[tag] = Px(value)
|
properties.setRaw(tag, Px(value))
|
||||||
|
|
||||||
case Bounds:
|
case Bounds:
|
||||||
bounds := NewBoundsProperty(nil)
|
bounds := NewBoundsProperty(nil)
|
||||||
if value.Top.Type != Auto {
|
if value.Top.Type != Auto {
|
||||||
bounds.Set(Top, value.Top)
|
bounds.setRaw(Top, value.Top)
|
||||||
}
|
}
|
||||||
if value.Right.Type != Auto {
|
if value.Right.Type != Auto {
|
||||||
bounds.Set(Right, value.Right)
|
bounds.setRaw(Right, value.Right)
|
||||||
}
|
}
|
||||||
if value.Bottom.Type != Auto {
|
if value.Bottom.Type != Auto {
|
||||||
bounds.Set(Bottom, value.Bottom)
|
bounds.setRaw(Bottom, value.Bottom)
|
||||||
}
|
}
|
||||||
if value.Left.Type != Auto {
|
if value.Left.Type != Auto {
|
||||||
bounds.Set(Left, value.Left)
|
bounds.setRaw(Left, value.Left)
|
||||||
}
|
}
|
||||||
properties.properties[tag] = bounds
|
properties.setRaw(tag, bounds)
|
||||||
|
|
||||||
case BoundsProperty:
|
case BoundsProperty:
|
||||||
properties.properties[tag] = value
|
properties.setRaw(tag, value)
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
bounds := NewBoundsProperty(nil)
|
bounds := NewBoundsProperty(nil)
|
||||||
for _, tag := range []string{Top, Right, Bottom, Left} {
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left} {
|
||||||
if text, ok := value.PropertyValue(tag); ok {
|
if text, ok := value.PropertyValue(string(tag)); ok {
|
||||||
if !bounds.Set(tag, text) {
|
if !bounds.Set(tag, text) {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
properties.properties[tag] = bounds
|
properties.setRaw(tag, bounds)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if n, ok := isInt(value); ok {
|
if n, ok := isInt(value); ok {
|
||||||
properties.properties[tag] = Px(float64(n))
|
properties.setRaw(tag, Px(float64(n)))
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) boundsProperty(tag string) BoundsProperty {
|
func removeBoundsPropertySide(properties Properties, mainTag, sideTag PropertyName) []PropertyName {
|
||||||
if value, ok := properties.properties[tag]; ok {
|
if bounds := getBoundsProperty(properties, mainTag); bounds != nil {
|
||||||
|
if bounds.getRaw(sideTag) != nil {
|
||||||
|
bounds.Remove(sideTag)
|
||||||
|
if bounds.empty() {
|
||||||
|
bounds = nil
|
||||||
|
}
|
||||||
|
properties.setRaw(mainTag, bounds)
|
||||||
|
return []PropertyName{mainTag, sideTag}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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}
|
||||||
|
}
|
||||||
|
|
||||||
|
notCompatibleType(sideTag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBoundsProperty(properties Properties, tag PropertyName) BoundsProperty {
|
||||||
|
if value := properties.getRaw(tag); value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
bounds := NewBoundsProperty(nil)
|
bounds := NewBoundsProperty(nil)
|
||||||
for _, t := range []string{Top, Right, Bottom, Left} {
|
for _, t := range []PropertyName{Top, Right, Bottom, Left} {
|
||||||
bounds.Set(t, value)
|
bounds.Set(t, value)
|
||||||
}
|
}
|
||||||
return bounds
|
return bounds
|
||||||
|
|
||||||
case SizeUnit:
|
case SizeUnit:
|
||||||
bounds := NewBoundsProperty(nil)
|
bounds := NewBoundsProperty(nil)
|
||||||
for _, t := range []string{Top, Right, Bottom, Left} {
|
for _, t := range []PropertyName{Top, Right, Bottom, Left} {
|
||||||
bounds.Set(t, value)
|
bounds.Set(t, value)
|
||||||
}
|
}
|
||||||
return bounds
|
return bounds
|
||||||
|
@ -345,29 +351,10 @@ func (properties *propertyList) boundsProperty(tag string) BoundsProperty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewBoundsProperty(nil)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) removeBoundsSide(mainTag, sideTag string) {
|
func getBounds(properties Properties, tag PropertyName, session Session) (Bounds, bool) {
|
||||||
bounds := properties.boundsProperty(mainTag)
|
|
||||||
if bounds.Get(sideTag) != nil {
|
|
||||||
bounds.Remove(sideTag)
|
|
||||||
properties.properties[mainTag] = bounds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (properties *propertyList) setBoundsSide(mainTag, sideTag string, value any) bool {
|
|
||||||
bounds := properties.boundsProperty(mainTag)
|
|
||||||
if bounds.Set(sideTag, value) {
|
|
||||||
properties.properties[mainTag] = bounds
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
notCompatibleType(sideTag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func boundsProperty(properties Properties, tag string, session Session) (Bounds, bool) {
|
|
||||||
if value := properties.Get(tag); value != nil {
|
if value := properties.Get(tag); value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
|
|
|
@ -18,6 +18,7 @@ func NewButton(session Session, params Params) Button {
|
||||||
|
|
||||||
func newButton(session Session) View {
|
func newButton(session Session) View {
|
||||||
return NewButton(session, nil)
|
return NewButton(session, nil)
|
||||||
|
//return new(buttonData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *buttonData) CreateSuperView(session Session) View {
|
func (button *buttonData) CreateSuperView(session Session) View {
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// DrawFunction is the constant for "draw-function" property tag.
|
// DrawFunction is the constant for "draw-function" property tag.
|
||||||
//
|
//
|
||||||
// Used by `CanvasView`.
|
// Used by `CanvasView`.
|
||||||
// Property sets the draw function of `CanvasView`.
|
// Property sets the draw function of `CanvasView`.
|
||||||
//
|
//
|
||||||
// Supported types: `func(Canvas)`.
|
// Supported types: `func(Canvas)`.
|
||||||
const DrawFunction = "draw-function"
|
const DrawFunction PropertyName = "draw-function"
|
||||||
|
|
||||||
// CanvasView interface of a custom draw view
|
// CanvasView interface of a custom draw view
|
||||||
type CanvasView interface {
|
type CanvasView interface {
|
||||||
|
@ -20,7 +18,6 @@ type CanvasView interface {
|
||||||
|
|
||||||
type canvasViewData struct {
|
type canvasViewData struct {
|
||||||
viewData
|
viewData
|
||||||
drawer func(Canvas)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCanvasView creates the new custom draw view
|
// NewCanvasView creates the new custom draw view
|
||||||
|
@ -32,21 +29,21 @@ func NewCanvasView(session Session, params Params) CanvasView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCanvasView(session Session) View {
|
func newCanvasView(session Session) View {
|
||||||
return NewCanvasView(session, nil)
|
return new(canvasViewData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of ViewsContainer by default values
|
// Init initialize fields of ViewsContainer by default values
|
||||||
func (canvasView *canvasViewData) init(session Session) {
|
func (canvasView *canvasViewData) init(session Session) {
|
||||||
canvasView.viewData.init(session)
|
canvasView.viewData.init(session)
|
||||||
canvasView.tag = "CanvasView"
|
canvasView.tag = "CanvasView"
|
||||||
|
canvasView.normalize = normalizeCanvasViewTag
|
||||||
|
canvasView.set = canvasViewSet
|
||||||
|
canvasView.remove = canvasViewRemove
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (canvasView *canvasViewData) String() string {
|
func normalizeCanvasViewTag(tag PropertyName) PropertyName {
|
||||||
return getViewString(canvasView, nil)
|
tag = defaultNormalize(tag)
|
||||||
}
|
|
||||||
|
|
||||||
func (canvasView *canvasViewData) normalizeTag(tag string) string {
|
|
||||||
tag = strings.ToLower(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case "draw-func":
|
case "draw-func":
|
||||||
tag = DrawFunction
|
tag = DrawFunction
|
||||||
|
@ -54,51 +51,36 @@ func (canvasView *canvasViewData) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (canvasView *canvasViewData) Remove(tag string) {
|
func canvasViewRemove(view View, tag PropertyName) []PropertyName {
|
||||||
canvasView.remove(canvasView.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (canvasView *canvasViewData) remove(tag string) {
|
|
||||||
if tag == DrawFunction {
|
if tag == DrawFunction {
|
||||||
canvasView.drawer = nil
|
if view.getRaw(DrawFunction) != nil {
|
||||||
|
view.setRaw(DrawFunction, nil)
|
||||||
|
if canvasView, ok := view.(CanvasView); ok {
|
||||||
canvasView.Redraw()
|
canvasView.Redraw()
|
||||||
canvasView.propertyChangedEvent(tag)
|
|
||||||
} else {
|
|
||||||
canvasView.viewData.remove(tag)
|
|
||||||
}
|
}
|
||||||
|
return []PropertyName{DrawFunction}
|
||||||
|
}
|
||||||
|
return []PropertyName{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (canvasView *canvasViewData) Set(tag string, value any) bool {
|
return viewRemove(view, tag)
|
||||||
return canvasView.set(canvasView.normalizeTag(tag), value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (canvasView *canvasViewData) set(tag string, value any) bool {
|
func canvasViewSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
if tag == DrawFunction {
|
if tag == DrawFunction {
|
||||||
if value == nil {
|
if fn, ok := value.(func(Canvas)); ok {
|
||||||
canvasView.drawer = nil
|
view.setRaw(DrawFunction, fn)
|
||||||
} else if fn, ok := value.(func(Canvas)); ok {
|
|
||||||
canvasView.drawer = fn
|
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
if canvasView, ok := view.(CanvasView); ok {
|
||||||
canvasView.Redraw()
|
canvasView.Redraw()
|
||||||
canvasView.propertyChangedEvent(tag)
|
}
|
||||||
return true
|
return []PropertyName{DrawFunction}
|
||||||
}
|
}
|
||||||
|
|
||||||
return canvasView.viewData.set(tag, value)
|
return viewSet(view, tag, value)
|
||||||
}
|
|
||||||
|
|
||||||
func (canvasView *canvasViewData) Get(tag string) any {
|
|
||||||
return canvasView.get(canvasView.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (canvasView *canvasViewData) get(tag string) any {
|
|
||||||
if tag == DrawFunction {
|
|
||||||
return canvasView.drawer
|
|
||||||
}
|
|
||||||
return canvasView.viewData.get(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (canvasView *canvasViewData) htmlTag() string {
|
func (canvasView *canvasViewData) htmlTag() string {
|
||||||
|
@ -106,15 +88,15 @@ func (canvasView *canvasViewData) htmlTag() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (canvasView *canvasViewData) Redraw() {
|
func (canvasView *canvasViewData) Redraw() {
|
||||||
if canvasView.drawer != nil {
|
|
||||||
canvas := newCanvas(canvasView)
|
canvas := newCanvas(canvasView)
|
||||||
canvas.ClearRect(0, 0, canvasView.frame.Width, canvasView.frame.Height)
|
canvas.ClearRect(0, 0, canvasView.frame.Width, canvasView.frame.Height)
|
||||||
if canvasView.drawer != nil {
|
if value := canvasView.getRaw(DrawFunction); value != nil {
|
||||||
canvasView.drawer(canvas)
|
if drawer, ok := value.(func(Canvas)); ok {
|
||||||
|
drawer(canvas)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
canvas.finishDraw()
|
canvas.finishDraw()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (canvasView *canvasViewData) onResize(self View, x, y, width, height float64) {
|
func (canvasView *canvasViewData) onResize(self View, x, y, width, height float64) {
|
||||||
canvasView.viewData.onResize(self, x, y, width, height)
|
canvasView.viewData.onResize(self, x, y, width, height)
|
||||||
|
|
213
checkbox.go
213
checkbox.go
|
@ -20,7 +20,7 @@ import (
|
||||||
// `func(checkbox rui.Checkbox)`,
|
// `func(checkbox rui.Checkbox)`,
|
||||||
// `func(checked bool)`,
|
// `func(checked bool)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
const CheckboxChangedEvent = "checkbox-event"
|
const CheckboxChangedEvent PropertyName = "checkbox-event"
|
||||||
|
|
||||||
// Checkbox represent a Checkbox view
|
// Checkbox represent a Checkbox view
|
||||||
type Checkbox interface {
|
type Checkbox interface {
|
||||||
|
@ -29,171 +29,132 @@ type Checkbox interface {
|
||||||
|
|
||||||
type checkboxData struct {
|
type checkboxData struct {
|
||||||
viewsContainerData
|
viewsContainerData
|
||||||
checkedListeners []func(Checkbox, bool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCheckbox create new Checkbox object and return it
|
// NewCheckbox create new Checkbox object and return it
|
||||||
func NewCheckbox(session Session, params Params) Checkbox {
|
func NewCheckbox(session Session, params Params) Checkbox {
|
||||||
view := new(checkboxData)
|
view := new(checkboxData)
|
||||||
view.init(session)
|
view.init(session)
|
||||||
setInitParams(view, Params{
|
|
||||||
ClickEvent: checkboxClickListener,
|
|
||||||
KeyDownEvent: checkboxKeyListener,
|
|
||||||
})
|
|
||||||
setInitParams(view, params)
|
setInitParams(view, params)
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCheckbox(session Session) View {
|
func newCheckbox(session Session) View {
|
||||||
return NewCheckbox(session, nil)
|
return new(checkboxData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *checkboxData) init(session Session) {
|
func (button *checkboxData) init(session Session) {
|
||||||
button.viewsContainerData.init(session)
|
button.viewsContainerData.init(session)
|
||||||
button.tag = "Checkbox"
|
button.tag = "Checkbox"
|
||||||
button.systemClass = "ruiGridLayout ruiCheckbox"
|
button.systemClass = "ruiGridLayout ruiCheckbox"
|
||||||
button.checkedListeners = []func(Checkbox, bool){}
|
button.set = button.setFunc
|
||||||
}
|
button.remove = button.removeFunc
|
||||||
|
button.changed = checkboxPropertyChanged
|
||||||
|
|
||||||
func (button *checkboxData) String() string {
|
button.setRaw(ClickEvent, checkboxClickListener)
|
||||||
return getViewString(button, nil)
|
button.setRaw(KeyDownEvent, checkboxKeyListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *checkboxData) Focusable() bool {
|
func (button *checkboxData) Focusable() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *checkboxData) Get(tag string) any {
|
func checkboxPropertyChanged(view View, tag PropertyName) {
|
||||||
switch strings.ToLower(tag) {
|
|
||||||
case CheckboxChangedEvent:
|
|
||||||
return button.checkedListeners
|
|
||||||
}
|
|
||||||
|
|
||||||
return button.viewsContainerData.Get(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (button *checkboxData) Set(tag string, value any) bool {
|
|
||||||
return button.set(tag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (button *checkboxData) set(tag string, value any) bool {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case CheckboxChangedEvent:
|
|
||||||
if !button.setChangedListener(value) {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
case Checked:
|
case Checked:
|
||||||
oldChecked := button.checked()
|
session := view.Session()
|
||||||
if !button.setBoolProperty(Checked, value) {
|
checked := IsCheckboxChecked(view)
|
||||||
return false
|
if listeners := GetCheckboxChangedListeners(view); len(listeners) > 0 {
|
||||||
}
|
if checkbox, ok := view.(Checkbox); ok {
|
||||||
if button.created {
|
for _, listener := range listeners {
|
||||||
checked := button.checked()
|
listener(checkbox, checked)
|
||||||
if checked != oldChecked {
|
|
||||||
button.changedCheckboxState(checked)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := allocStringBuilder()
|
||||||
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
|
checkboxHtml(view, buffer, checked)
|
||||||
|
session.updateInnerHTML(view.htmlID()+"checkbox", buffer.String())
|
||||||
|
|
||||||
case CheckboxHorizontalAlign, CheckboxVerticalAlign:
|
case CheckboxHorizontalAlign, CheckboxVerticalAlign:
|
||||||
if !button.setEnumProperty(tag, value, enumProperties[tag].values) {
|
htmlID := view.htmlID()
|
||||||
return false
|
session := view.Session()
|
||||||
}
|
updateCSSStyle(htmlID, session)
|
||||||
if button.created {
|
updateInnerHTML(htmlID, session)
|
||||||
htmlID := button.htmlID()
|
|
||||||
updateCSSStyle(htmlID, button.session)
|
|
||||||
updateInnerHTML(htmlID, button.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
case VerticalAlign:
|
case VerticalAlign:
|
||||||
if !button.setEnumProperty(tag, value, enumProperties[tag].values) {
|
view.Session().updateCSSProperty(view.htmlID()+"content", "align-items", checkboxVerticalAlignCSS(view))
|
||||||
return false
|
|
||||||
}
|
|
||||||
if button.created {
|
|
||||||
button.session.updateCSSProperty(button.htmlID()+"content", "align-items", button.cssVerticalAlign())
|
|
||||||
}
|
|
||||||
|
|
||||||
case HorizontalAlign:
|
case HorizontalAlign:
|
||||||
if !button.setEnumProperty(tag, value, enumProperties[tag].values) {
|
view.Session().updateCSSProperty(view.htmlID()+"content", "justify-items", checkboxHorizontalAlignCSS(view))
|
||||||
return false
|
|
||||||
}
|
|
||||||
if button.created {
|
|
||||||
button.session.updateCSSProperty(button.htmlID()+"content", "justify-items", button.cssHorizontalAlign())
|
|
||||||
}
|
|
||||||
|
|
||||||
case CellVerticalAlign, CellHorizontalAlign, CellWidth, CellHeight:
|
|
||||||
return false
|
|
||||||
|
|
||||||
case AccentColor:
|
case AccentColor:
|
||||||
if !button.setColorProperty(AccentColor, value) {
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
return false
|
|
||||||
}
|
|
||||||
if button.created {
|
|
||||||
updateInnerHTML(button.htmlID(), button.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return button.viewsContainerData.set(tag, value)
|
viewsContainerPropertyChanged(view, tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.propertyChangedEvent(tag)
|
func (button *checkboxData) setFunc(view View, tag PropertyName, value any) []PropertyName {
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (button *checkboxData) Remove(tag string) {
|
|
||||||
button.remove(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (button *checkboxData) remove(tag string) {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case ClickEvent:
|
case ClickEvent:
|
||||||
if !button.viewsContainerData.set(ClickEvent, checkboxClickListener) {
|
if button.viewsContainerData.setFunc(view, ClickEvent, value) != nil {
|
||||||
delete(button.properties, tag)
|
if value := view.getRaw(ClickEvent); value != nil {
|
||||||
|
if listeners, ok := value.([]func(View, MouseEvent)); ok {
|
||||||
|
listeners = append(listeners, checkboxClickListener)
|
||||||
|
view.setRaw(ClickEvent, listeners)
|
||||||
|
return []PropertyName{ClickEvent}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return button.viewsContainerData.setFunc(view, ClickEvent, checkboxClickListener)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
case KeyDownEvent:
|
case KeyDownEvent:
|
||||||
if !button.viewsContainerData.set(KeyDownEvent, checkboxKeyListener) {
|
if button.viewsContainerData.setFunc(view, KeyDownEvent, value) != nil {
|
||||||
delete(button.properties, tag)
|
if value := view.getRaw(KeyDownEvent); value != nil {
|
||||||
|
if listeners, ok := value.([]func(View, KeyEvent)); ok {
|
||||||
|
listeners = append(listeners, checkboxKeyListener)
|
||||||
|
view.setRaw(KeyDownEvent, listeners)
|
||||||
|
return []PropertyName{KeyDownEvent}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return button.viewsContainerData.setFunc(view, KeyDownEvent, checkboxKeyListener)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
case CheckboxChangedEvent:
|
case CheckboxChangedEvent:
|
||||||
if len(button.checkedListeners) > 0 {
|
return setViewEventListener[Checkbox, bool](view, tag, value)
|
||||||
button.checkedListeners = []func(Checkbox, bool){}
|
|
||||||
}
|
|
||||||
|
|
||||||
case Checked:
|
case Checked:
|
||||||
oldChecked := button.checked()
|
return setBoolProperty(view, Checked, value)
|
||||||
delete(button.properties, tag)
|
|
||||||
if button.created && oldChecked {
|
case CellVerticalAlign, CellHorizontalAlign, CellWidth, CellHeight:
|
||||||
button.changedCheckboxState(false)
|
ErrorLogF(`"%s" property is not compatible with the BoundsProperty`, string(tag))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case CheckboxHorizontalAlign, CheckboxVerticalAlign:
|
return button.viewsContainerData.setFunc(view, tag, value)
|
||||||
delete(button.properties, tag)
|
|
||||||
if button.created {
|
|
||||||
htmlID := button.htmlID()
|
|
||||||
updateCSSStyle(htmlID, button.session)
|
|
||||||
updateInnerHTML(htmlID, button.session)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case VerticalAlign:
|
func (button *checkboxData) removeFunc(view View, tag PropertyName) []PropertyName {
|
||||||
delete(button.properties, tag)
|
switch tag {
|
||||||
if button.created {
|
case ClickEvent:
|
||||||
button.session.updateCSSProperty(button.htmlID()+"content", "align-items", button.cssVerticalAlign())
|
button.setRaw(ClickEvent, checkboxClickListener)
|
||||||
|
return []PropertyName{ClickEvent}
|
||||||
|
|
||||||
|
case KeyDownEvent:
|
||||||
|
button.setRaw(KeyDownEvent, checkboxKeyListener)
|
||||||
|
return []PropertyName{ClickEvent}
|
||||||
}
|
}
|
||||||
|
|
||||||
case HorizontalAlign:
|
return button.viewsContainerData.removeFunc(view, tag)
|
||||||
delete(button.properties, tag)
|
|
||||||
if button.created {
|
|
||||||
button.session.updateCSSProperty(button.htmlID()+"content", "justify-items", button.cssHorizontalAlign())
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
button.viewsContainerData.remove(tag)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
button.propertyChangedEvent(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *checkboxData) checked() bool {
|
func (button *checkboxData) checked() bool {
|
||||||
|
@ -201,8 +162,9 @@ func (button *checkboxData) checked() bool {
|
||||||
return checked
|
return checked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func (button *checkboxData) changedCheckboxState(state bool) {
|
func (button *checkboxData) changedCheckboxState(state bool) {
|
||||||
for _, listener := range button.checkedListeners {
|
for _, listener := range GetCheckboxChangedListeners(button) {
|
||||||
listener(button, state)
|
listener(button, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,8 +174,9 @@ func (button *checkboxData) changedCheckboxState(state bool) {
|
||||||
button.htmlCheckbox(buffer, state)
|
button.htmlCheckbox(buffer, state)
|
||||||
button.Session().updateInnerHTML(button.htmlID()+"checkbox", buffer.String())
|
button.Session().updateInnerHTML(button.htmlID()+"checkbox", buffer.String())
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func checkboxClickListener(view View) {
|
func checkboxClickListener(view View, _ MouseEvent) {
|
||||||
view.Set(Checked, !IsCheckboxChecked(view))
|
view.Set(Checked, !IsCheckboxChecked(view))
|
||||||
BlurView(view)
|
BlurView(view)
|
||||||
}
|
}
|
||||||
|
@ -225,17 +188,6 @@ func checkboxKeyListener(view View, event KeyEvent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *checkboxData) setChangedListener(value any) bool {
|
|
||||||
listeners, ok := valueToEventListeners[Checkbox, bool](value)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
} else if listeners == nil {
|
|
||||||
listeners = []func(Checkbox, bool){}
|
|
||||||
}
|
|
||||||
button.checkedListeners = listeners
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (button *checkboxData) cssStyle(self View, builder cssBuilder) {
|
func (button *checkboxData) cssStyle(self View, builder cssBuilder) {
|
||||||
session := button.Session()
|
session := button.Session()
|
||||||
vAlign := GetCheckboxVerticalAlign(button)
|
vAlign := GetCheckboxVerticalAlign(button)
|
||||||
|
@ -265,7 +217,8 @@ func (button *checkboxData) cssStyle(self View, builder cssBuilder) {
|
||||||
button.viewsContainerData.cssStyle(self, builder)
|
button.viewsContainerData.cssStyle(self, builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *checkboxData) htmlCheckbox(buffer *strings.Builder, checked bool) (int, int) {
|
func checkboxHtml(button View, buffer *strings.Builder, checked bool) (int, int) {
|
||||||
|
//func (button *checkboxData) htmlCheckbox(buffer *strings.Builder, checked bool) (int, int) {
|
||||||
vAlign := GetCheckboxVerticalAlign(button)
|
vAlign := GetCheckboxVerticalAlign(button)
|
||||||
hAlign := GetCheckboxHorizontalAlign(button)
|
hAlign := GetCheckboxHorizontalAlign(button)
|
||||||
|
|
||||||
|
@ -317,7 +270,7 @@ func (button *checkboxData) htmlCheckbox(buffer *strings.Builder, checked bool)
|
||||||
|
|
||||||
func (button *checkboxData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (button *checkboxData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
|
|
||||||
vCheckboxAlign, hCheckboxAlign := button.htmlCheckbox(buffer, IsCheckboxChecked(button))
|
vCheckboxAlign, hCheckboxAlign := checkboxHtml(button, buffer, IsCheckboxChecked(button))
|
||||||
|
|
||||||
buffer.WriteString(`<div id="`)
|
buffer.WriteString(`<div id="`)
|
||||||
buffer.WriteString(button.htmlID())
|
buffer.WriteString(button.htmlID())
|
||||||
|
@ -335,11 +288,11 @@ func (button *checkboxData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(" align-items: ")
|
buffer.WriteString(" align-items: ")
|
||||||
buffer.WriteString(button.cssVerticalAlign())
|
buffer.WriteString(checkboxVerticalAlignCSS(button))
|
||||||
buffer.WriteRune(';')
|
buffer.WriteRune(';')
|
||||||
|
|
||||||
buffer.WriteString(" justify-items: ")
|
buffer.WriteString(" justify-items: ")
|
||||||
buffer.WriteString(button.cssHorizontalAlign())
|
buffer.WriteString(checkboxHorizontalAlignCSS(button))
|
||||||
buffer.WriteRune(';')
|
buffer.WriteRune(';')
|
||||||
|
|
||||||
buffer.WriteString(`">`)
|
buffer.WriteString(`">`)
|
||||||
|
@ -347,8 +300,8 @@ func (button *checkboxData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
buffer.WriteString(`</div>`)
|
buffer.WriteString(`</div>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *checkboxData) cssHorizontalAlign() string {
|
func checkboxHorizontalAlignCSS(view View) string {
|
||||||
align := GetHorizontalAlign(button)
|
align := GetHorizontalAlign(view)
|
||||||
values := enumProperties[CellHorizontalAlign].cssValues
|
values := enumProperties[CellHorizontalAlign].cssValues
|
||||||
if align >= 0 && align < len(values) {
|
if align >= 0 && align < len(values) {
|
||||||
return values[align]
|
return values[align]
|
||||||
|
@ -356,8 +309,8 @@ func (button *checkboxData) cssHorizontalAlign() string {
|
||||||
return values[0]
|
return values[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *checkboxData) cssVerticalAlign() string {
|
func checkboxVerticalAlignCSS(view View) string {
|
||||||
align := GetVerticalAlign(button)
|
align := GetVerticalAlign(view)
|
||||||
values := enumProperties[CellVerticalAlign].cssValues
|
values := enumProperties[CellVerticalAlign].cssValues
|
||||||
if align >= 0 && align < len(values) {
|
if align >= 0 && align < len(values) {
|
||||||
return values[align]
|
return values[align]
|
||||||
|
|
136
colorPicker.go
136
colorPicker.go
|
@ -25,7 +25,7 @@ const (
|
||||||
// `func(newColor rui.Color)`,
|
// `func(newColor rui.Color)`,
|
||||||
// `func(picker rui.ColorPicker)`,
|
// `func(picker rui.ColorPicker)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
ColorChangedEvent = "color-changed"
|
ColorChangedEvent PropertyName = "color-changed"
|
||||||
|
|
||||||
// ColorPickerValue is the constant for "color-picker-value" property tag.
|
// ColorPickerValue is the constant for "color-picker-value" property tag.
|
||||||
//
|
//
|
||||||
|
@ -36,7 +36,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `Color`, other types converted to it during assignment.
|
// Internal type is `Color`, other types converted to it during assignment.
|
||||||
// See `Color` description for more details.
|
// See `Color` description for more details.
|
||||||
ColorPickerValue = "color-picker-value"
|
ColorPickerValue PropertyName = "color-picker-value"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ColorPicker represent a ColorPicker view
|
// ColorPicker represent a ColorPicker view
|
||||||
|
@ -46,8 +46,6 @@ type ColorPicker interface {
|
||||||
|
|
||||||
type colorPickerData struct {
|
type colorPickerData struct {
|
||||||
viewData
|
viewData
|
||||||
dataList
|
|
||||||
colorChangedListeners []func(ColorPicker, Color, Color)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewColorPicker create new ColorPicker object and return it
|
// NewColorPicker create new ColorPicker object and return it
|
||||||
|
@ -59,125 +57,69 @@ func NewColorPicker(session Session, params Params) ColorPicker {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newColorPicker(session Session) View {
|
func newColorPicker(session Session) View {
|
||||||
return NewColorPicker(session, nil)
|
return new(colorPickerData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *colorPickerData) init(session Session) {
|
func (picker *colorPickerData) init(session Session) {
|
||||||
picker.viewData.init(session)
|
picker.viewData.init(session)
|
||||||
picker.tag = "ColorPicker"
|
picker.tag = "ColorPicker"
|
||||||
picker.hasHtmlDisabled = true
|
picker.hasHtmlDisabled = true
|
||||||
picker.colorChangedListeners = []func(ColorPicker, Color, Color){}
|
|
||||||
picker.properties[Padding] = Px(0)
|
picker.properties[Padding] = Px(0)
|
||||||
picker.dataListInit()
|
picker.normalize = normalizeColorPickerTag
|
||||||
|
picker.set = colorPickerSet
|
||||||
|
picker.changed = colorPickerPropertyChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *colorPickerData) String() string {
|
func normalizeColorPickerTag(tag PropertyName) PropertyName {
|
||||||
return getViewString(picker, nil)
|
tag = defaultNormalize(tag)
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *colorPickerData) normalizeTag(tag string) string {
|
|
||||||
tag = strings.ToLower(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Value, ColorTag:
|
case Value, ColorTag:
|
||||||
return ColorPickerValue
|
return ColorPickerValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return picker.normalizeDataListTag(tag)
|
return normalizeDataListTag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *colorPickerData) Remove(tag string) {
|
func colorPickerSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
picker.remove(picker.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *colorPickerData) remove(tag string) {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case ColorChangedEvent:
|
case ColorChangedEvent:
|
||||||
if len(picker.colorChangedListeners) > 0 {
|
return setEventWithOldListener[ColorPicker, Color](view, tag, value)
|
||||||
picker.colorChangedListeners = []func(ColorPicker, Color, Color){}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ColorPickerValue:
|
case ColorPickerValue:
|
||||||
oldColor := GetColorPickerValue(picker)
|
oldColor := GetColorPickerValue(view)
|
||||||
delete(picker.properties, ColorPickerValue)
|
result := setColorProperty(view, ColorPickerValue, value)
|
||||||
picker.colorChanged(oldColor)
|
if result != nil {
|
||||||
|
view.setRaw("old-color", oldColor)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
case DataList:
|
case DataList:
|
||||||
if len(picker.dataList.dataList) > 0 {
|
return setDataList(view, value, "")
|
||||||
picker.setDataList(picker, []string{}, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
return viewSet(view, tag, value)
|
||||||
picker.viewData.remove(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *colorPickerData) Set(tag string, value any) bool {
|
|
||||||
return picker.set(picker.normalizeTag(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *colorPickerData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
picker.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func colorPickerPropertyChanged(view View, tag PropertyName) {
|
||||||
switch tag {
|
switch tag {
|
||||||
case ColorChangedEvent:
|
|
||||||
listeners, ok := valueToEventWithOldListeners[ColorPicker, Color](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
} else if listeners == nil {
|
|
||||||
listeners = []func(ColorPicker, Color, Color){}
|
|
||||||
}
|
|
||||||
picker.colorChangedListeners = listeners
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case ColorPickerValue:
|
case ColorPickerValue:
|
||||||
oldColor := GetColorPickerValue(picker)
|
color := GetColorPickerValue(view)
|
||||||
if picker.setColorProperty(ColorPickerValue, value) {
|
view.Session().callFunc("setInputValue", view.htmlID(), color.rgbString())
|
||||||
picker.colorChanged(oldColor)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataList:
|
if listeners := GetColorChangedListeners(view); len(listeners) > 0 {
|
||||||
return picker.setDataList(picker, value, picker.created)
|
oldColor := Color(0)
|
||||||
|
if value := view.getRaw("old-color"); value != nil {
|
||||||
default:
|
oldColor = value.(Color)
|
||||||
return picker.viewData.set(tag, value)
|
|
||||||
}
|
}
|
||||||
return false
|
for _, listener := range listeners {
|
||||||
}
|
listener(view, color, oldColor)
|
||||||
|
|
||||||
func (picker *colorPickerData) colorChanged(oldColor Color) {
|
|
||||||
if newColor := GetColorPickerValue(picker); oldColor != newColor {
|
|
||||||
if picker.created {
|
|
||||||
picker.session.callFunc("setInputValue", picker.htmlID(), newColor.rgbString())
|
|
||||||
}
|
|
||||||
for _, listener := range picker.colorChangedListeners {
|
|
||||||
listener(picker, newColor, oldColor)
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(ColorTag)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *colorPickerData) Get(tag string) any {
|
|
||||||
return picker.get(picker.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *colorPickerData) get(tag string) any {
|
|
||||||
switch tag {
|
|
||||||
case ColorChangedEvent:
|
|
||||||
return picker.colorChangedListeners
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
return picker.dataList.dataList
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return picker.viewData.get(tag)
|
viewPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *colorPickerData) htmlTag() string {
|
func (picker *colorPickerData) htmlTag() string {
|
||||||
|
@ -185,7 +127,10 @@ func (picker *colorPickerData) htmlTag() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *colorPickerData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (picker *colorPickerData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
picker.dataListHtmlSubviews(self, buffer)
|
dataListHtmlSubviews(self, buffer, func(text string, session Session) string {
|
||||||
|
text, _ = session.resolveConstants(text)
|
||||||
|
return text
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder) {
|
func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
|
@ -200,20 +145,23 @@ func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder
|
||||||
buffer.WriteString(` onclick="stopEventPropagation(this, event)"`)
|
buffer.WriteString(` onclick="stopEventPropagation(this, event)"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
picker.dataListHtmlProperties(picker, buffer)
|
dataListHtmlProperties(picker, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *colorPickerData) handleCommand(self View, command string, data DataObject) bool {
|
func (picker *colorPickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyValue("text"); ok {
|
||||||
oldColor := GetColorPickerValue(picker)
|
|
||||||
if color, ok := StringToColor(text); ok {
|
if color, ok := StringToColor(text); ok {
|
||||||
|
oldColor := GetColorPickerValue(picker)
|
||||||
picker.properties[ColorPickerValue] = color
|
picker.properties[ColorPickerValue] = color
|
||||||
if color != oldColor {
|
if color != oldColor {
|
||||||
for _, listener := range picker.colorChangedListeners {
|
for _, listener := range GetColorChangedListeners(picker) {
|
||||||
listener(picker, color, oldColor)
|
listener(picker, color, oldColor)
|
||||||
}
|
}
|
||||||
|
if listener, ok := picker.changeListener[ColorPickerValue]; ok {
|
||||||
|
listener(picker, ColorPickerValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,7 +181,7 @@ func GetColorPickerValue(view View, subviewID ...string) Color {
|
||||||
if value, ok := colorProperty(view, ColorPickerValue, view.Session()); ok {
|
if value, ok := colorProperty(view, ColorPickerValue, view.Session()); ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
for _, tag := range []string{ColorPickerValue, Value, ColorTag} {
|
for _, tag := range []PropertyName{ColorPickerValue, Value, ColorTag} {
|
||||||
if value := valueFromStyle(view, tag); value != nil {
|
if value := valueFromStyle(view, tag); value != nil {
|
||||||
if result, ok := valueToColor(value, view.Session()); ok {
|
if result, ok := valueToColor(value, view.Session()); ok {
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -2,7 +2,6 @@ package rui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Constants for [ColumnLayout] specific properties and events
|
// Constants for [ColumnLayout] specific properties and events
|
||||||
|
@ -18,7 +17,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `0` or "0" - Use "column-width" to control how many columns will be created.
|
// `0` or "0" - Use "column-width" to control how many columns will be created.
|
||||||
// >= `0` or >= "0" - Тhe number of columns into which the content is divided.
|
// >= `0` or >= "0" - Тhe number of columns into which the content is divided.
|
||||||
ColumnCount = "column-count"
|
ColumnCount PropertyName = "column-count"
|
||||||
|
|
||||||
// ColumnWidth is the constant for "column-width" property tag.
|
// ColumnWidth is the constant for "column-width" property tag.
|
||||||
//
|
//
|
||||||
|
@ -29,7 +28,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
ColumnWidth = "column-width"
|
ColumnWidth PropertyName = "column-width"
|
||||||
|
|
||||||
// ColumnGap is the constant for "column-gap" property tag.
|
// ColumnGap is the constant for "column-gap" property tag.
|
||||||
//
|
//
|
||||||
|
@ -40,7 +39,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
ColumnGap = "column-gap"
|
ColumnGap PropertyName = "column-gap"
|
||||||
|
|
||||||
// ColumnSeparator is the constant for "column-separator" property tag.
|
// ColumnSeparator is the constant for "column-separator" property tag.
|
||||||
//
|
//
|
||||||
|
@ -51,7 +50,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `ColumnSeparatorProperty`, other types converted to it during assignment.
|
// Internal type is `ColumnSeparatorProperty`, other types converted to it during assignment.
|
||||||
// See `ColumnSeparatorProperty` and `ViewBorder` description for more details.
|
// See `ColumnSeparatorProperty` and `ViewBorder` description for more details.
|
||||||
ColumnSeparator = "column-separator"
|
ColumnSeparator PropertyName = "column-separator"
|
||||||
|
|
||||||
// ColumnSeparatorStyle is the constant for "column-separator-style" property tag.
|
// ColumnSeparatorStyle is the constant for "column-separator-style" property tag.
|
||||||
//
|
//
|
||||||
|
@ -66,7 +65,7 @@ const (
|
||||||
// `2`(`DashedLine`) or "dashed" - Dashed line as a separator.
|
// `2`(`DashedLine`) or "dashed" - Dashed line as a separator.
|
||||||
// `3`(`DottedLine`) or "dotted" - Dotted line as a separator.
|
// `3`(`DottedLine`) or "dotted" - Dotted line as a separator.
|
||||||
// `4`(`DoubleLine`) or "double" - Double line as a separator.
|
// `4`(`DoubleLine`) or "double" - Double line as a separator.
|
||||||
ColumnSeparatorStyle = "column-separator-style"
|
ColumnSeparatorStyle PropertyName = "column-separator-style"
|
||||||
|
|
||||||
// ColumnSeparatorWidth is the constant for "column-separator-width" property tag.
|
// ColumnSeparatorWidth is the constant for "column-separator-width" property tag.
|
||||||
//
|
//
|
||||||
|
@ -77,7 +76,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
ColumnSeparatorWidth = "column-separator-width"
|
ColumnSeparatorWidth PropertyName = "column-separator-width"
|
||||||
|
|
||||||
// ColumnSeparatorColor is the constant for "column-separator-color" property tag.
|
// ColumnSeparatorColor is the constant for "column-separator-color" property tag.
|
||||||
//
|
//
|
||||||
|
@ -88,7 +87,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `Color`, other types converted to it during assignment.
|
// Internal type is `Color`, other types converted to it during assignment.
|
||||||
// See `Color` description for more details.
|
// See `Color` description for more details.
|
||||||
ColumnSeparatorColor = "column-separator-color"
|
ColumnSeparatorColor PropertyName = "column-separator-color"
|
||||||
|
|
||||||
// ColumnFill is the constant for "column-fill" property tag.
|
// ColumnFill is the constant for "column-fill" property tag.
|
||||||
//
|
//
|
||||||
|
@ -100,7 +99,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `0`(`ColumnFillBalance`) or "balance" - Content is equally divided between columns.
|
// `0`(`ColumnFillBalance`) or "balance" - Content is equally divided between columns.
|
||||||
// `1`(`ColumnFillAuto`) or "auto" - Columns are filled sequentially. Content takes up only the room it needs, possibly resulting in some columns remaining empty.
|
// `1`(`ColumnFillAuto`) or "auto" - Columns are filled sequentially. Content takes up only the room it needs, possibly resulting in some columns remaining empty.
|
||||||
ColumnFill = "column-fill"
|
ColumnFill PropertyName = "column-fill"
|
||||||
|
|
||||||
// ColumnSpanAll is the constant for "column-span-all" property tag.
|
// ColumnSpanAll is the constant for "column-span-all" property tag.
|
||||||
//
|
//
|
||||||
|
@ -113,7 +112,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - View will span across all columns.
|
// `true` or `1` or "true", "yes", "on", "1" - View will span across all columns.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - View will be a part of a column.
|
// `false` or `0` or "false", "no", "off", "0" - View will be a part of a column.
|
||||||
ColumnSpanAll = "column-span-all"
|
ColumnSpanAll PropertyName = "column-span-all"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ColumnLayout represent a ColumnLayout view
|
// ColumnLayout represent a ColumnLayout view
|
||||||
|
@ -134,22 +133,20 @@ func NewColumnLayout(session Session, params Params) ColumnLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newColumnLayout(session Session) View {
|
func newColumnLayout(session Session) View {
|
||||||
return NewColumnLayout(session, nil)
|
return new(columnLayoutData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of ColumnLayout by default values
|
// Init initialize fields of ColumnLayout by default values
|
||||||
func (ColumnLayout *columnLayoutData) init(session Session) {
|
func (columnLayout *columnLayoutData) init(session Session) {
|
||||||
ColumnLayout.viewsContainerData.init(session)
|
columnLayout.viewsContainerData.init(session)
|
||||||
ColumnLayout.tag = "ColumnLayout"
|
columnLayout.tag = "ColumnLayout"
|
||||||
//ColumnLayout.systemClass = "ruiColumnLayout"
|
columnLayout.normalize = normalizeColumnLayoutTag
|
||||||
|
columnLayout.changed = columnLayoutPropertyChanged
|
||||||
|
//columnLayout.systemClass = "ruiColumnLayout"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (columnLayout *columnLayoutData) String() string {
|
func normalizeColumnLayoutTag(tag PropertyName) PropertyName {
|
||||||
return getViewString(columnLayout, nil)
|
tag = defaultNormalize(tag)
|
||||||
}
|
|
||||||
|
|
||||||
func (columnLayout *columnLayoutData) normalizeTag(tag string) string {
|
|
||||||
tag = strings.ToLower(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Gap:
|
case Gap:
|
||||||
return ColumnGap
|
return ColumnGap
|
||||||
|
@ -157,63 +154,29 @@ func (columnLayout *columnLayoutData) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (columnLayout *columnLayoutData) Get(tag string) any {
|
func columnLayoutPropertyChanged(view View, tag PropertyName) {
|
||||||
return columnLayout.get(columnLayout.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (columnLayout *columnLayoutData) Remove(tag string) {
|
|
||||||
columnLayout.remove(columnLayout.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (columnLayout *columnLayoutData) remove(tag string) {
|
|
||||||
columnLayout.viewsContainerData.remove(tag)
|
|
||||||
if columnLayout.created {
|
|
||||||
switch tag {
|
|
||||||
case ColumnCount, ColumnWidth, ColumnGap:
|
|
||||||
columnLayout.session.updateCSSProperty(columnLayout.htmlID(), tag, "")
|
|
||||||
|
|
||||||
case ColumnSeparator:
|
|
||||||
columnLayout.session.updateCSSProperty(columnLayout.htmlID(), "column-rule", "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (columnLayout *columnLayoutData) Set(tag string, value any) bool {
|
|
||||||
return columnLayout.set(columnLayout.normalizeTag(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (columnLayout *columnLayoutData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
columnLayout.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !columnLayout.viewsContainerData.set(tag, value) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if columnLayout.created {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case ColumnSeparator:
|
case ColumnSeparator:
|
||||||
css := ""
|
css := ""
|
||||||
session := columnLayout.Session()
|
session := view.Session()
|
||||||
if val, ok := columnLayout.properties[ColumnSeparator]; ok {
|
if value := view.getRaw(ColumnSeparator); value != nil {
|
||||||
separator := val.(ColumnSeparatorProperty)
|
separator := value.(ColumnSeparatorProperty)
|
||||||
css = separator.cssValue(columnLayout.Session())
|
css = separator.cssValue(view.Session())
|
||||||
}
|
}
|
||||||
session.updateCSSProperty(columnLayout.htmlID(), "column-rule", css)
|
session.updateCSSProperty(view.htmlID(), "column-rule", css)
|
||||||
|
|
||||||
case ColumnCount:
|
case ColumnCount:
|
||||||
session := columnLayout.Session()
|
session := view.Session()
|
||||||
if count, ok := intProperty(columnLayout, tag, session, 0); ok && count > 0 {
|
if count, ok := intProperty(view, tag, session, 0); ok && count > 0 {
|
||||||
session.updateCSSProperty(columnLayout.htmlID(), tag, strconv.Itoa(count))
|
session.updateCSSProperty(view.htmlID(), string(ColumnCount), strconv.Itoa(count))
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(columnLayout.htmlID(), tag, "auto")
|
session.updateCSSProperty(view.htmlID(), string(ColumnCount), "auto")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
viewsContainerPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetColumnCount returns int value which specifies number of columns into which the content of
|
// GetColumnCount returns int value which specifies number of columns into which the content of
|
||||||
// ColumnLayout is break. If the return value is 0 then the number of columns is calculated
|
// ColumnLayout is break. If the return value is 0 then the number of columns is calculated
|
||||||
|
|
|
@ -18,14 +18,14 @@ type ColumnSeparatorProperty interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type columnSeparatorProperty struct {
|
type columnSeparatorProperty struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
func newColumnSeparatorProperty(value any) ColumnSeparatorProperty {
|
func newColumnSeparatorProperty(value any) ColumnSeparatorProperty {
|
||||||
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
separator := new(columnSeparatorProperty)
|
separator := new(columnSeparatorProperty)
|
||||||
separator.properties = map[string]any{}
|
separator.init()
|
||||||
return separator
|
return separator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,17 +35,18 @@ func newColumnSeparatorProperty(value any) ColumnSeparatorProperty {
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
separator := new(columnSeparatorProperty)
|
separator := new(columnSeparatorProperty)
|
||||||
separator.properties = map[string]any{}
|
separator.init()
|
||||||
for _, tag := range []string{Style, Width, ColorTag} {
|
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
||||||
if val, ok := value.PropertyValue(tag); ok && val != "" {
|
if val, ok := value.PropertyValue(string(tag)); ok && val != "" {
|
||||||
separator.set(tag, value)
|
propertiesSet(separator, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return separator
|
return separator
|
||||||
|
|
||||||
case ViewBorder:
|
case ViewBorder:
|
||||||
separator := new(columnSeparatorProperty)
|
separator := new(columnSeparatorProperty)
|
||||||
separator.properties = map[string]any{
|
separator.init()
|
||||||
|
separator.properties = map[PropertyName]any{
|
||||||
Style: value.Style,
|
Style: value.Style,
|
||||||
Width: value.Width,
|
Width: value.Width,
|
||||||
ColorTag: value.Color,
|
ColorTag: value.Color,
|
||||||
|
@ -67,9 +68,9 @@ func newColumnSeparatorProperty(value any) ColumnSeparatorProperty {
|
||||||
// "width" (Width). Determines the line thickness (SizeUnit).
|
// "width" (Width). Determines the line thickness (SizeUnit).
|
||||||
func NewColumnSeparator(params Params) ColumnSeparatorProperty {
|
func NewColumnSeparator(params Params) ColumnSeparatorProperty {
|
||||||
separator := new(columnSeparatorProperty)
|
separator := new(columnSeparatorProperty)
|
||||||
separator.properties = map[string]any{}
|
separator.init()
|
||||||
if params != nil {
|
if params != nil {
|
||||||
for _, tag := range []string{Style, Width, ColorTag} {
|
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
||||||
if value, ok := params[tag]; ok && value != nil {
|
if value, ok := params[tag]; ok && value != nil {
|
||||||
separator.Set(tag, value)
|
separator.Set(tag, value)
|
||||||
}
|
}
|
||||||
|
@ -78,8 +79,14 @@ func NewColumnSeparator(params Params) ColumnSeparatorProperty {
|
||||||
return separator
|
return separator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (separator *columnSeparatorProperty) normalizeTag(tag string) string {
|
func (separator *columnSeparatorProperty) init() {
|
||||||
tag = strings.ToLower(tag)
|
separator.dataProperty.init()
|
||||||
|
separator.normalize = normalizeVolumnSeparatorTag
|
||||||
|
separator.supportedProperties = []PropertyName{Style, Width, ColorTag}
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeVolumnSeparatorTag(tag PropertyName) PropertyName {
|
||||||
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case ColumnSeparatorStyle, "separator-style":
|
case ColumnSeparatorStyle, "separator-style":
|
||||||
return Style
|
return Style
|
||||||
|
@ -97,12 +104,12 @@ func (separator *columnSeparatorProperty) normalizeTag(tag string) string {
|
||||||
func (separator *columnSeparatorProperty) writeString(buffer *strings.Builder, indent string) {
|
func (separator *columnSeparatorProperty) writeString(buffer *strings.Builder, indent string) {
|
||||||
buffer.WriteString("_{ ")
|
buffer.WriteString("_{ ")
|
||||||
comma := false
|
comma := false
|
||||||
for _, tag := range []string{Style, Width, ColorTag} {
|
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
||||||
if value, ok := separator.properties[tag]; ok {
|
if value, ok := separator.properties[tag]; ok {
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, BorderStyle, value, indent)
|
writePropertyValue(buffer, BorderStyle, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
|
@ -116,47 +123,12 @@ func (separator *columnSeparatorProperty) String() string {
|
||||||
return runStringWriter(separator)
|
return runStringWriter(separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (separator *columnSeparatorProperty) Remove(tag string) {
|
func getColumnSeparatorProperty(properties Properties) ColumnSeparatorProperty {
|
||||||
|
if val := properties.getRaw(ColumnSeparator); val != nil {
|
||||||
switch tag = separator.normalizeTag(tag); tag {
|
if separator, ok := val.(ColumnSeparatorProperty); ok {
|
||||||
case Style, Width, ColorTag:
|
return separator
|
||||||
delete(separator.properties, tag)
|
|
||||||
|
|
||||||
default:
|
|
||||||
ErrorLogF(`"%s" property is not compatible with the ColumnSeparatorProperty`, tag)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (separator *columnSeparatorProperty) Set(tag string, value any) bool {
|
|
||||||
tag = separator.normalizeTag(tag)
|
|
||||||
|
|
||||||
if value == nil {
|
|
||||||
separator.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
|
||||||
case Style:
|
|
||||||
return separator.setEnumProperty(Style, value, enumProperties[BorderStyle].values)
|
|
||||||
|
|
||||||
case Width:
|
|
||||||
return separator.setSizeProperty(Width, value)
|
|
||||||
|
|
||||||
case ColorTag:
|
|
||||||
return separator.setColorProperty(ColorTag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorLogF(`"%s" property is not compatible with the ColumnSeparatorProperty`, tag)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (separator *columnSeparatorProperty) Get(tag string) any {
|
|
||||||
tag = separator.normalizeTag(tag)
|
|
||||||
|
|
||||||
if result, ok := separator.properties[tag]; ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,9 @@ func InitCustomView(customView CustomView, tag string, session Session, params P
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (customView *CustomViewData) init(session Session) {
|
||||||
|
}
|
||||||
|
|
||||||
// SuperView returns a super view
|
// SuperView returns a super view
|
||||||
func (customView *CustomViewData) SuperView() View {
|
func (customView *CustomViewData) SuperView() View {
|
||||||
return customView.superView
|
return customView.superView
|
||||||
|
@ -57,29 +60,36 @@ func (customView *CustomViewData) setTag(tag string) {
|
||||||
|
|
||||||
// Get returns a value of the property with name defined by the argument.
|
// Get returns a value of the property with name defined by the argument.
|
||||||
// The type of return value depends on the property. If the property is not set then nil is returned.
|
// The type of return value depends on the property. If the property is not set then nil is returned.
|
||||||
func (customView *CustomViewData) Get(tag string) any {
|
func (customView *CustomViewData) Get(tag PropertyName) any {
|
||||||
return customView.superView.Get(tag)
|
return customView.superView.Get(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (customView *CustomViewData) getRaw(tag string) any {
|
func (customView *CustomViewData) getRaw(tag PropertyName) any {
|
||||||
return customView.superView.getRaw(tag)
|
return customView.superView.getRaw(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (customView *CustomViewData) setRaw(tag string, value any) {
|
func (customView *CustomViewData) setRaw(tag PropertyName, value any) {
|
||||||
customView.superView.setRaw(tag, value)
|
customView.superView.setRaw(tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (customView *CustomViewData) setContent(value any) bool {
|
||||||
|
if container, ok := customView.superView.(ViewsContainer); ok {
|
||||||
|
return container.setContent(value)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Set sets the value (second argument) of the property with name defined by the first argument.
|
// Set sets the value (second argument) of the property with name defined by the first argument.
|
||||||
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
||||||
// a description of the error is written to the log
|
// a description of the error is written to the log
|
||||||
func (customView *CustomViewData) Set(tag string, value any) bool {
|
func (customView *CustomViewData) Set(tag PropertyName, value any) bool {
|
||||||
return customView.superView.Set(tag, value)
|
return customView.superView.Set(tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAnimated sets the value (second argument) of the property with name defined by the first argument.
|
// SetAnimated sets the value (second argument) of the property with name defined by the first argument.
|
||||||
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
||||||
// a description of the error is written to the log
|
// a description of the error is written to the log
|
||||||
func (customView *CustomViewData) SetAnimated(tag string, value any, animation Animation) bool {
|
func (customView *CustomViewData) SetAnimated(tag PropertyName, value any, animation Animation) bool {
|
||||||
return customView.superView.SetAnimated(tag, value, animation)
|
return customView.superView.SetAnimated(tag, value, animation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,20 +98,24 @@ func (customView *CustomViewData) SetParams(params Params) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetChangeListener set the function to track the change of the View property
|
// SetChangeListener set the function to track the change of the View property
|
||||||
func (customView *CustomViewData) SetChangeListener(tag string, listener func(View, string)) {
|
func (customView *CustomViewData) SetChangeListener(tag PropertyName, listener func(View, PropertyName)) {
|
||||||
customView.superView.SetChangeListener(tag, listener)
|
customView.superView.SetChangeListener(tag, listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes the property with name defined by the argument
|
// Remove removes the property with name defined by the argument
|
||||||
func (customView *CustomViewData) Remove(tag string) {
|
func (customView *CustomViewData) Remove(tag PropertyName) {
|
||||||
customView.superView.Remove(tag)
|
customView.superView.Remove(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllTags returns an array of the set properties
|
// AllTags returns an array of the set properties
|
||||||
func (customView *CustomViewData) AllTags() []string {
|
func (customView *CustomViewData) AllTags() []PropertyName {
|
||||||
return customView.superView.AllTags()
|
return customView.superView.AllTags()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (customView *CustomViewData) empty() bool {
|
||||||
|
return customView.superView.empty()
|
||||||
|
}
|
||||||
|
|
||||||
// Clear removes all properties
|
// Clear removes all properties
|
||||||
func (customView *CustomViewData) Clear() {
|
func (customView *CustomViewData) Clear() {
|
||||||
customView.superView.Clear()
|
customView.superView.Clear()
|
||||||
|
@ -182,7 +196,7 @@ func (customView *CustomViewData) onItemResize(self View, index string, x, y, wi
|
||||||
customView.superView.onItemResize(customView.superView, index, x, y, width, height)
|
customView.superView.onItemResize(customView.superView, index, x, y, width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (customView *CustomViewData) handleCommand(self View, command string, data DataObject) bool {
|
func (customView *CustomViewData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
return customView.superView.handleCommand(customView.superView, command, data)
|
return customView.superView.handleCommand(customView.superView, command, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +224,10 @@ func (customView *CustomViewData) htmlProperties(self View, buffer *strings.Buil
|
||||||
customView.superView.htmlProperties(customView.superView, buffer)
|
customView.superView.htmlProperties(customView.superView, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (customView *CustomViewData) htmlDisabledProperty() bool {
|
||||||
|
return customView.superView.htmlDisabledProperty()
|
||||||
|
}
|
||||||
|
|
||||||
func (customView *CustomViewData) cssStyle(self View, builder cssBuilder) {
|
func (customView *CustomViewData) cssStyle(self View, builder cssBuilder) {
|
||||||
customView.superView.cssStyle(customView.superView, builder)
|
customView.superView.cssStyle(customView.superView, builder)
|
||||||
}
|
}
|
||||||
|
@ -274,9 +292,9 @@ func (customView *CustomViewData) ViewIndex(view View) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (customView *CustomViewData) exscludeTags() []string {
|
func (customView *CustomViewData) exscludeTags() []PropertyName {
|
||||||
if customView.superView != nil {
|
if customView.superView != nil {
|
||||||
exsclude := []string{}
|
exsclude := []PropertyName{}
|
||||||
for tag, value := range customView.defaultParams {
|
for tag, value := range customView.defaultParams {
|
||||||
if value == customView.superView.getRaw(tag) {
|
if value == customView.superView.getRaw(tag) {
|
||||||
exsclude = append(exsclude, tag)
|
exsclude = append(exsclude, tag)
|
||||||
|
@ -290,7 +308,10 @@ func (customView *CustomViewData) exscludeTags() []string {
|
||||||
// String convert internal representation of a [CustomViewData] into a string.
|
// String convert internal representation of a [CustomViewData] into a string.
|
||||||
func (customView *CustomViewData) String() string {
|
func (customView *CustomViewData) String() string {
|
||||||
if customView.superView != nil {
|
if customView.superView != nil {
|
||||||
return getViewString(customView, customView.exscludeTags())
|
buffer := allocStringBuilder()
|
||||||
|
defer freeStringBuilder(buffer)
|
||||||
|
writeViewStyle(customView.tag, customView, buffer, "", customView.exscludeTags())
|
||||||
|
return buffer.String()
|
||||||
}
|
}
|
||||||
return customView.tag + " { }"
|
return customView.tag + " { }"
|
||||||
}
|
}
|
||||||
|
@ -302,7 +323,7 @@ func (customView *CustomViewData) setScroll(x, y, width, height float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transition returns the transition animation of the property(tag). Returns nil is there is no transition animation.
|
// Transition returns the transition animation of the property(tag). Returns nil is there is no transition animation.
|
||||||
func (customView *CustomViewData) Transition(tag string) Animation {
|
func (customView *CustomViewData) Transition(tag PropertyName) Animation {
|
||||||
if customView.superView != nil {
|
if customView.superView != nil {
|
||||||
return customView.superView.Transition(tag)
|
return customView.superView.Transition(tag)
|
||||||
}
|
}
|
||||||
|
@ -310,17 +331,17 @@ func (customView *CustomViewData) Transition(tag string) Animation {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transitions returns a map of transition animations. The result is always non-nil.
|
// Transitions returns a map of transition animations. The result is always non-nil.
|
||||||
func (customView *CustomViewData) Transitions() map[string]Animation {
|
func (customView *CustomViewData) Transitions() map[PropertyName]Animation {
|
||||||
if customView.superView != nil {
|
if customView.superView != nil {
|
||||||
return customView.superView.Transitions()
|
return customView.superView.Transitions()
|
||||||
}
|
}
|
||||||
return map[string]Animation{}
|
return map[PropertyName]Animation{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTransition sets the transition animation for the property if "animation" argument is not nil, and
|
// SetTransition sets the transition animation for the property if "animation" argument is not nil, and
|
||||||
// removes the transition animation of the property if "animation" argument is nil.
|
// removes the transition animation of the property if "animation" argument is nil.
|
||||||
// The "tag" argument is the property name.
|
// The "tag" argument is the property name.
|
||||||
func (customView *CustomViewData) SetTransition(tag string, animation Animation) {
|
func (customView *CustomViewData) SetTransition(tag PropertyName, animation Animation) {
|
||||||
if customView.superView != nil {
|
if customView.superView != nil {
|
||||||
customView.superView.SetTransition(tag, animation)
|
customView.superView.SetTransition(tag, animation)
|
||||||
}
|
}
|
||||||
|
|
6
data.go
6
data.go
|
@ -212,12 +212,12 @@ func (object *dataObject) ToParams() Params {
|
||||||
switch node.Type() {
|
switch node.Type() {
|
||||||
case TextNode:
|
case TextNode:
|
||||||
if text := node.Text(); text != "" {
|
if text := node.Text(); text != "" {
|
||||||
params[node.Tag()] = text
|
params[PropertyName(node.Tag())] = text
|
||||||
}
|
}
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectNode:
|
||||||
if obj := node.Object(); obj != nil {
|
if obj := node.Object(); obj != nil {
|
||||||
params[node.Tag()] = node.Object()
|
params[PropertyName(node.Tag())] = node.Object()
|
||||||
}
|
}
|
||||||
|
|
||||||
case ArrayNode:
|
case ArrayNode:
|
||||||
|
@ -234,7 +234,7 @@ func (object *dataObject) ToParams() Params {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(array) > 0 {
|
if len(array) > 0 {
|
||||||
params[node.Tag()] = array
|
params[PropertyName(node.Tag())] = array
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
239
dataList.go
239
dataList.go
|
@ -1,6 +1,11 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DataList is the constant for "data-list" property tag.
|
// DataList is the constant for "data-list" property tag.
|
||||||
|
@ -98,23 +103,14 @@ const (
|
||||||
// `[]Color` - An array of color values which will be converted to a string array.
|
// `[]Color` - An array of color values which will be converted to a string array.
|
||||||
// `[]SizeUnit` - an array of size unit values which will be converted to a string array.
|
// `[]SizeUnit` - an array of size unit values which will be converted to a string array.
|
||||||
// `[]any` - this array must contain only types which were listed in Types section.
|
// `[]any` - this array must contain only types which were listed in Types section.
|
||||||
DataList = "data-list"
|
DataList PropertyName = "data-list"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dataList struct {
|
func dataListID(view View) string {
|
||||||
dataList []string
|
|
||||||
dataListHtml bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dataList) dataListInit() {
|
|
||||||
list.dataList = []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dataList) dataListID(view View) string {
|
|
||||||
return view.htmlID() + "-datalist"
|
return view.htmlID() + "-datalist"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *dataList) normalizeDataListTag(tag string) string {
|
func normalizeDataListTag(tag PropertyName) PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case "datalist":
|
case "datalist":
|
||||||
return DataList
|
return DataList
|
||||||
|
@ -123,6 +119,210 @@ func (list *dataList) normalizeDataListTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setDataList(properties Properties, value any, dateTimeFormat string) []PropertyName {
|
||||||
|
if items, ok := anyToStringArray(value, timeFormat); ok {
|
||||||
|
properties.setRaw(DataList, items)
|
||||||
|
return []PropertyName{DataList}
|
||||||
|
}
|
||||||
|
|
||||||
|
notCompatibleType(DataList, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func anyToStringArray(value any, dateTimeFormat string) ([]string, bool) {
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case string:
|
||||||
|
return []string{value}, true
|
||||||
|
|
||||||
|
case []string:
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case []DataValue:
|
||||||
|
items := make([]string, 0, len(value))
|
||||||
|
for _, val := range value {
|
||||||
|
if !val.IsObject() {
|
||||||
|
items = append(items, val.Value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []fmt.Stringer:
|
||||||
|
items := make([]string, len(value))
|
||||||
|
for i, str := range value {
|
||||||
|
items[i] = str.String()
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []Color:
|
||||||
|
items := make([]string, len(value))
|
||||||
|
for i, str := range value {
|
||||||
|
items[i] = str.String()
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []SizeUnit:
|
||||||
|
items := make([]string, len(value))
|
||||||
|
for i, str := range value {
|
||||||
|
items[i] = str.String()
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []AngleUnit:
|
||||||
|
items := make([]string, len(value))
|
||||||
|
for i, str := range value {
|
||||||
|
items[i] = str.String()
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []float32:
|
||||||
|
items := make([]string, len(value))
|
||||||
|
for i, val := range value {
|
||||||
|
items[i] = fmt.Sprintf("%g", float64(val))
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []float64:
|
||||||
|
items := make([]string, len(value))
|
||||||
|
for i, val := range value {
|
||||||
|
items[i] = fmt.Sprintf("%g", val)
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []int:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []uint:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []int8:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []uint8:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []int16:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []uint16:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []int32:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []uint32:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []int64:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []uint64:
|
||||||
|
return intArrayToStringArray(value), true
|
||||||
|
|
||||||
|
case []bool:
|
||||||
|
items := make([]string, len(value))
|
||||||
|
for i, val := range value {
|
||||||
|
if val {
|
||||||
|
items[i] = "true"
|
||||||
|
} else {
|
||||||
|
items[i] = "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []time.Time:
|
||||||
|
if dateTimeFormat == "" {
|
||||||
|
dateTimeFormat = dateFormat + " " + timeFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
items := make([]string, len(value))
|
||||||
|
for i, val := range value {
|
||||||
|
items[i] = val.Format(dateTimeFormat)
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
items := make([]string, 0, len(value))
|
||||||
|
for _, v := range value {
|
||||||
|
switch val := v.(type) {
|
||||||
|
case string:
|
||||||
|
items = append(items, val)
|
||||||
|
|
||||||
|
case fmt.Stringer:
|
||||||
|
items = append(items, val.String())
|
||||||
|
|
||||||
|
case bool:
|
||||||
|
if val {
|
||||||
|
items = append(items, "true")
|
||||||
|
} else {
|
||||||
|
items = append(items, "false")
|
||||||
|
}
|
||||||
|
|
||||||
|
case float32:
|
||||||
|
items = append(items, fmt.Sprintf("%g", float64(val)))
|
||||||
|
|
||||||
|
case float64:
|
||||||
|
items = append(items, fmt.Sprintf("%g", val))
|
||||||
|
|
||||||
|
case rune:
|
||||||
|
items = append(items, string(val))
|
||||||
|
|
||||||
|
default:
|
||||||
|
if n, ok := isInt(v); ok {
|
||||||
|
items = append(items, strconv.Itoa(n))
|
||||||
|
} else {
|
||||||
|
return []string{}, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return []string{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDataListProperty(properties Properties) []string {
|
||||||
|
if value := properties.getRaw(DataList); value != nil {
|
||||||
|
if items, ok := value.([]string); ok {
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataListHtmlSubviews(view View, buffer *strings.Builder, normalizeItem func(text string, session Session) string) {
|
||||||
|
if items := getDataListProperty(view); len(items) > 0 {
|
||||||
|
session := view.Session()
|
||||||
|
buffer.WriteString(`<datalist id="`)
|
||||||
|
buffer.WriteString(dataListID(view))
|
||||||
|
buffer.WriteString(`">`)
|
||||||
|
for _, text := range items {
|
||||||
|
text = normalizeItem(text, session)
|
||||||
|
|
||||||
|
if strings.ContainsRune(text, '"') {
|
||||||
|
text = strings.ReplaceAll(text, `"`, `"`)
|
||||||
|
}
|
||||||
|
if strings.ContainsRune(text, '\n') {
|
||||||
|
text = strings.ReplaceAll(text, "\n", `\n`)
|
||||||
|
}
|
||||||
|
buffer.WriteString(`<option value="`)
|
||||||
|
buffer.WriteString(text)
|
||||||
|
buffer.WriteString(`"></option>`)
|
||||||
|
}
|
||||||
|
buffer.WriteString(`</datalist>`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataListHtmlProperties(view View, buffer *strings.Builder) {
|
||||||
|
if len(getDataListProperty(view)) > 0 {
|
||||||
|
buffer.WriteString(` list="`)
|
||||||
|
buffer.WriteString(dataListID(view))
|
||||||
|
buffer.WriteString(`"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func (list *dataList) setDataList(view View, value any, created bool) bool {
|
func (list *dataList) setDataList(view View, value any, created bool) bool {
|
||||||
items, ok := anyToStringArray(value)
|
items, ok := anyToStringArray(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -133,7 +333,7 @@ func (list *dataList) setDataList(view View, value any, created bool) bool {
|
||||||
list.dataList = items
|
list.dataList = items
|
||||||
if created {
|
if created {
|
||||||
session := view.Session()
|
session := view.Session()
|
||||||
dataListID := list.dataListID(view)
|
dataListID := dataListID(view)
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
|
@ -162,7 +362,7 @@ func (list *dataList) dataListHtmlSubviews(view View, buffer *strings.Builder) {
|
||||||
|
|
||||||
func (list *dataList) dataListHtmlCode(view View, buffer *strings.Builder) {
|
func (list *dataList) dataListHtmlCode(view View, buffer *strings.Builder) {
|
||||||
buffer.WriteString(`<datalist id="`)
|
buffer.WriteString(`<datalist id="`)
|
||||||
buffer.WriteString(list.dataListID(view))
|
buffer.WriteString(dataListID(view))
|
||||||
buffer.WriteString(`">`)
|
buffer.WriteString(`">`)
|
||||||
list.dataListItemsHtml(buffer)
|
list.dataListItemsHtml(buffer)
|
||||||
buffer.WriteString(`</datalist>`)
|
buffer.WriteString(`</datalist>`)
|
||||||
|
@ -185,10 +385,11 @@ func (list *dataList) dataListItemsHtml(buffer *strings.Builder) {
|
||||||
func (list *dataList) dataListHtmlProperties(view View, buffer *strings.Builder) {
|
func (list *dataList) dataListHtmlProperties(view View, buffer *strings.Builder) {
|
||||||
if len(list.dataList) > 0 {
|
if len(list.dataList) > 0 {
|
||||||
buffer.WriteString(` list="`)
|
buffer.WriteString(` list="`)
|
||||||
buffer.WriteString(list.dataListID(view))
|
buffer.WriteString(dataListID(view))
|
||||||
buffer.WriteString(`"`)
|
buffer.WriteString(`"`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// GetDataList returns the data list of an editor.
|
// GetDataList returns the data list of an editor.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||||
|
@ -198,11 +399,7 @@ func GetDataList(view View, subviewID ...string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if value := view.Get(DataList); value != nil {
|
return getDataListProperty(view)
|
||||||
if list, ok := value.([]string); ok {
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{}
|
return []string{}
|
||||||
|
|
301
datePicker.go
301
datePicker.go
|
@ -27,7 +27,7 @@ const (
|
||||||
// `func(newDate time.Time)`,
|
// `func(newDate time.Time)`,
|
||||||
// `func(picker rui.DatePicker)`,
|
// `func(picker rui.DatePicker)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
DateChangedEvent = "date-changed"
|
DateChangedEvent PropertyName = "date-changed"
|
||||||
|
|
||||||
// DatePickerMin is the constant for "date-picker-min" property tag.
|
// DatePickerMin is the constant for "date-picker-min" property tag.
|
||||||
//
|
//
|
||||||
|
@ -50,7 +50,7 @@ const (
|
||||||
// "MM/DD/YYYY" - "01/02/2024".
|
// "MM/DD/YYYY" - "01/02/2024".
|
||||||
// "MM/DD/YY" - "01/02/24".
|
// "MM/DD/YY" - "01/02/24".
|
||||||
// "MMDDYY" - "010224".
|
// "MMDDYY" - "010224".
|
||||||
DatePickerMin = "date-picker-min"
|
DatePickerMin PropertyName = "date-picker-min"
|
||||||
|
|
||||||
// DatePickerMax is the constant for "date-picker-max" property tag.
|
// DatePickerMax is the constant for "date-picker-max" property tag.
|
||||||
//
|
//
|
||||||
|
@ -73,7 +73,7 @@ const (
|
||||||
// "MM/DD/YYYY" - "01/02/2024".
|
// "MM/DD/YYYY" - "01/02/2024".
|
||||||
// "MM/DD/YY" - "01/02/24".
|
// "MM/DD/YY" - "01/02/24".
|
||||||
// "MMDDYY" - "010224".
|
// "MMDDYY" - "010224".
|
||||||
DatePickerMax = "date-picker-max"
|
DatePickerMax PropertyName = "date-picker-max"
|
||||||
|
|
||||||
// DatePickerStep is the constant for "date-picker-step" property tag.
|
// DatePickerStep is the constant for "date-picker-step" property tag.
|
||||||
//
|
//
|
||||||
|
@ -84,7 +84,7 @@ const (
|
||||||
//
|
//
|
||||||
// Values:
|
// Values:
|
||||||
// >= `0` or >= "0" - Step value in days used to increment or decrement date.
|
// >= `0` or >= "0" - Step value in days used to increment or decrement date.
|
||||||
DatePickerStep = "date-picker-step"
|
DatePickerStep PropertyName = "date-picker-step"
|
||||||
|
|
||||||
// DatePickerValue is the constant for "date-picker-value" property tag.
|
// DatePickerValue is the constant for "date-picker-value" property tag.
|
||||||
//
|
//
|
||||||
|
@ -107,7 +107,7 @@ const (
|
||||||
// "MM/DD/YYYY" - "01/02/2024".
|
// "MM/DD/YYYY" - "01/02/2024".
|
||||||
// "MM/DD/YY" - "01/02/24".
|
// "MM/DD/YY" - "01/02/24".
|
||||||
// "MMDDYY" - "010224".
|
// "MMDDYY" - "010224".
|
||||||
DatePickerValue = "date-picker-value"
|
DatePickerValue PropertyName = "date-picker-value"
|
||||||
|
|
||||||
dateFormat = "2006-01-02"
|
dateFormat = "2006-01-02"
|
||||||
)
|
)
|
||||||
|
@ -119,8 +119,6 @@ type DatePicker interface {
|
||||||
|
|
||||||
type datePickerData struct {
|
type datePickerData struct {
|
||||||
viewData
|
viewData
|
||||||
dataList
|
|
||||||
dateChangedListeners []func(DatePicker, time.Time, time.Time)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDatePicker create new DatePicker object and return it
|
// NewDatePicker create new DatePicker object and return it
|
||||||
|
@ -132,114 +130,36 @@ func NewDatePicker(session Session, params Params) DatePicker {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDatePicker(session Session) View {
|
func newDatePicker(session Session) View {
|
||||||
return NewDatePicker(session, nil)
|
return new(datePickerData) // NewDatePicker(session, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *datePickerData) init(session Session) {
|
func (picker *datePickerData) init(session Session) {
|
||||||
picker.viewData.init(session)
|
picker.viewData.init(session)
|
||||||
picker.tag = "DatePicker"
|
picker.tag = "DatePicker"
|
||||||
picker.hasHtmlDisabled = true
|
picker.hasHtmlDisabled = true
|
||||||
picker.dateChangedListeners = []func(DatePicker, time.Time, time.Time){}
|
picker.normalize = normalizeDatePickerTag
|
||||||
picker.dataListInit()
|
picker.set = datePickerSet
|
||||||
}
|
picker.changed = datePickerPropertyChanged
|
||||||
|
|
||||||
func (picker *datePickerData) String() string {
|
|
||||||
return getViewString(picker, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *datePickerData) Focusable() bool {
|
func (picker *datePickerData) Focusable() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *datePickerData) normalizeTag(tag string) string {
|
func normalizeDatePickerTag(tag PropertyName) PropertyName {
|
||||||
tag = strings.ToLower(tag)
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case Type, Min, Max, Step, Value:
|
case Type, Min, Max, Step, Value:
|
||||||
return "date-picker-" + tag
|
return "date-picker-" + tag
|
||||||
}
|
}
|
||||||
|
|
||||||
return tag
|
return normalizeDataListTag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *datePickerData) Remove(tag string) {
|
func stringToDate(value string) (time.Time, bool) {
|
||||||
picker.remove(picker.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *datePickerData) remove(tag string) {
|
|
||||||
switch tag {
|
|
||||||
case DateChangedEvent:
|
|
||||||
if len(picker.dateChangedListeners) > 0 {
|
|
||||||
picker.dateChangedListeners = []func(DatePicker, time.Time, time.Time){}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
case DatePickerMin:
|
|
||||||
delete(picker.properties, DatePickerMin)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.removeProperty(picker.htmlID(), Min)
|
|
||||||
}
|
|
||||||
|
|
||||||
case DatePickerMax:
|
|
||||||
delete(picker.properties, DatePickerMax)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.removeProperty(picker.htmlID(), Max)
|
|
||||||
}
|
|
||||||
|
|
||||||
case DatePickerStep:
|
|
||||||
delete(picker.properties, DatePickerStep)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.removeProperty(picker.htmlID(), Step)
|
|
||||||
}
|
|
||||||
|
|
||||||
case DatePickerValue:
|
|
||||||
if _, ok := picker.properties[DatePickerValue]; ok {
|
|
||||||
oldDate := GetDatePickerValue(picker)
|
|
||||||
delete(picker.properties, DatePickerValue)
|
|
||||||
date := GetDatePickerValue(picker)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.callFunc("setInputValue", picker.htmlID(), date.Format(dateFormat))
|
|
||||||
}
|
|
||||||
for _, listener := range picker.dateChangedListeners {
|
|
||||||
listener(picker, date, oldDate)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
if len(picker.dataList.dataList) > 0 {
|
|
||||||
picker.setDataList(picker, []string{}, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
picker.viewData.remove(tag)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *datePickerData) Set(tag string, value any) bool {
|
|
||||||
return picker.set(picker.normalizeTag(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *datePickerData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
picker.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeValue := func(tag string) (time.Time, bool) {
|
|
||||||
switch value := value.(type) {
|
|
||||||
case time.Time:
|
|
||||||
picker.properties[tag] = value
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case string:
|
|
||||||
if text, ok := picker.Session().resolveConstants(value); ok {
|
|
||||||
format := "20060102"
|
format := "20060102"
|
||||||
if strings.ContainsRune(text, '-') {
|
if strings.ContainsRune(value, '-') {
|
||||||
if part := strings.Split(text, "-"); len(part) == 3 {
|
if part := strings.Split(value, "-"); len(part) == 3 {
|
||||||
if part[0] != "" && part[0][0] > '9' {
|
if part[0] != "" && part[0][0] > '9' {
|
||||||
if len(part[2]) == 2 {
|
if len(part[2]) == 2 {
|
||||||
format = "Jan-02-06"
|
format = "Jan-02-06"
|
||||||
|
@ -252,128 +172,122 @@ func (picker *datePickerData) set(tag string, value any) bool {
|
||||||
format = "2006-01-02"
|
format = "2006-01-02"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if strings.ContainsRune(text, ' ') {
|
} else if strings.ContainsRune(value, ' ') {
|
||||||
if part := strings.Split(text, " "); len(part) == 3 {
|
if part := strings.Split(value, " "); len(part) == 3 {
|
||||||
if part[0] != "" && part[0][0] > '9' {
|
if part[0] != "" && part[0][0] > '9' {
|
||||||
format = "January 02, 2006"
|
format = "January 02, 2006"
|
||||||
} else {
|
} else {
|
||||||
format = "02 January 2006"
|
format = "02 January 2006"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if strings.ContainsRune(text, '/') {
|
} else if strings.ContainsRune(value, '/') {
|
||||||
if part := strings.Split(text, "/"); len(part) == 3 {
|
if part := strings.Split(value, "/"); len(part) == 3 {
|
||||||
if len(part[2]) == 2 {
|
if len(part[2]) == 2 {
|
||||||
format = "01/02/06"
|
format = "01/02/06"
|
||||||
} else {
|
} else {
|
||||||
format = "01/02/2006"
|
format = "01/02/2006"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if len(text) == 6 {
|
} else if len(value) == 6 {
|
||||||
format = "010206"
|
format = "010206"
|
||||||
}
|
}
|
||||||
|
|
||||||
if date, err := time.Parse(format, text); err == nil {
|
if date, err := time.Parse(format, value); err == nil {
|
||||||
picker.properties[tag] = value
|
|
||||||
return date, true
|
return date, true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return time.Now(), false
|
return time.Now(), false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func datePickerSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
|
|
||||||
|
setDateValue := func(tag PropertyName) []PropertyName {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case time.Time:
|
||||||
|
view.setRaw(tag, value)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
|
||||||
|
case string:
|
||||||
|
if isConstantName(value) {
|
||||||
|
view.setRaw(tag, value)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
if date, ok := stringToDate(value); ok {
|
||||||
|
view.setRaw(tag, date)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
|
case DatePickerMin, DatePickerMax:
|
||||||
|
return setDateValue(tag)
|
||||||
|
|
||||||
|
case DatePickerStep:
|
||||||
|
return setIntProperty(view, DatePickerStep, value)
|
||||||
|
|
||||||
|
case DatePickerValue:
|
||||||
|
view.setRaw("old-date", GetDatePickerValue(view))
|
||||||
|
return setDateValue(tag)
|
||||||
|
|
||||||
|
case DateChangedEvent:
|
||||||
|
return setEventWithOldListener[DatePicker, time.Time](view, tag, value)
|
||||||
|
|
||||||
|
case DataList:
|
||||||
|
return setDataList(view, value, dateFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewSet(view, tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func datePickerPropertyChanged(view View, tag PropertyName) {
|
||||||
|
|
||||||
|
session := view.Session()
|
||||||
|
|
||||||
|
switch tag {
|
||||||
|
|
||||||
case DatePickerMin:
|
case DatePickerMin:
|
||||||
old, oldOK := getDateProperty(picker, DatePickerMin, Min)
|
if date, ok := GetDatePickerMin(view); ok {
|
||||||
if date, ok := setTimeValue(DatePickerMin); ok {
|
session.updateProperty(view.htmlID(), "min", date.Format(dateFormat))
|
||||||
if !oldOK || date != old {
|
} else {
|
||||||
if picker.created {
|
session.removeProperty(view.htmlID(), "min")
|
||||||
picker.session.updateProperty(picker.htmlID(), Min, date.Format(dateFormat))
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case DatePickerMax:
|
case DatePickerMax:
|
||||||
old, oldOK := getDateProperty(picker, DatePickerMax, Max)
|
if date, ok := GetDatePickerMax(view); ok {
|
||||||
if date, ok := setTimeValue(DatePickerMax); ok {
|
session.updateProperty(view.htmlID(), "max", date.Format(dateFormat))
|
||||||
if !oldOK || date != old {
|
} else {
|
||||||
if picker.created {
|
session.removeProperty(view.htmlID(), "max")
|
||||||
picker.session.updateProperty(picker.htmlID(), Max, date.Format(dateFormat))
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case DatePickerStep:
|
case DatePickerStep:
|
||||||
oldStep := GetDatePickerStep(picker)
|
if step := GetDatePickerStep(view); step > 0 {
|
||||||
if picker.setIntProperty(DatePickerStep, value) {
|
session.updateProperty(view.htmlID(), "step", strconv.Itoa(step))
|
||||||
if step := GetDatePickerStep(picker); oldStep != step {
|
|
||||||
if picker.created {
|
|
||||||
if step > 0 {
|
|
||||||
picker.session.updateProperty(picker.htmlID(), Step, strconv.Itoa(step))
|
|
||||||
} else {
|
} else {
|
||||||
picker.session.removeProperty(picker.htmlID(), Step)
|
session.removeProperty(view.htmlID(), "step")
|
||||||
}
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case DatePickerValue:
|
case DatePickerValue:
|
||||||
oldDate := GetDatePickerValue(picker)
|
date := GetDatePickerValue(view)
|
||||||
if date, ok := setTimeValue(DatePickerValue); ok {
|
session.callFunc("setInputValue", view.htmlID(), date.Format(dateFormat))
|
||||||
if date != oldDate {
|
|
||||||
if picker.created {
|
|
||||||
picker.session.callFunc("setInputValue", picker.htmlID(), date.Format(dateFormat))
|
|
||||||
}
|
|
||||||
for _, listener := range picker.dateChangedListeners {
|
|
||||||
listener(picker, date, oldDate)
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
case DateChangedEvent:
|
if listeners := GetDateChangedListeners(view); len(listeners) > 0 {
|
||||||
listeners, ok := valueToEventWithOldListeners[DatePicker, time.Time](value)
|
oldDate := time.Now()
|
||||||
if !ok {
|
if value := view.getRaw("old-date"); value != nil {
|
||||||
notCompatibleType(tag, value)
|
if date, ok := value.(time.Time); ok {
|
||||||
return false
|
oldDate = date
|
||||||
} else if listeners == nil {
|
}
|
||||||
listeners = []func(DatePicker, time.Time, time.Time){}
|
}
|
||||||
|
for _, listener := range listeners {
|
||||||
|
listener(view, date, oldDate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
picker.dateChangedListeners = listeners
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
return picker.setDataList(picker, value, picker.created)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return picker.viewData.set(tag, value)
|
viewPropertyChanged(view, tag)
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *datePickerData) Get(tag string) any {
|
|
||||||
return picker.get(picker.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *datePickerData) get(tag string) any {
|
|
||||||
switch tag {
|
|
||||||
case DateChangedEvent:
|
|
||||||
return picker.dateChangedListeners
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
return picker.dataList.dataList
|
|
||||||
|
|
||||||
default:
|
|
||||||
return picker.viewData.get(tag)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +296,13 @@ func (picker *datePickerData) htmlTag() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *datePickerData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (picker *datePickerData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
picker.dataListHtmlSubviews(self, buffer)
|
dataListHtmlSubviews(self, buffer, func(text string, session Session) string {
|
||||||
|
text, _ = session.resolveConstants(text)
|
||||||
|
if date, ok := stringToDate(text); ok {
|
||||||
|
return date.Format(dateFormat)
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder) {
|
func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
|
@ -417,10 +337,10 @@ func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder)
|
||||||
buffer.WriteString(` onclick="stopEventPropagation(this, event)"`)
|
buffer.WriteString(` onclick="stopEventPropagation(this, event)"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
picker.dataListHtmlProperties(picker, buffer)
|
dataListHtmlProperties(picker, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *datePickerData) handleCommand(self View, command string, data DataObject) bool {
|
func (picker *datePickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyValue("text"); ok {
|
||||||
|
@ -428,9 +348,12 @@ func (picker *datePickerData) handleCommand(self View, command string, data Data
|
||||||
oldValue := GetDatePickerValue(picker)
|
oldValue := GetDatePickerValue(picker)
|
||||||
picker.properties[DatePickerValue] = value
|
picker.properties[DatePickerValue] = value
|
||||||
if value != oldValue {
|
if value != oldValue {
|
||||||
for _, listener := range picker.dateChangedListeners {
|
for _, listener := range GetDateChangedListeners(picker) {
|
||||||
listener(picker, value, oldValue)
|
listener(picker, value, oldValue)
|
||||||
}
|
}
|
||||||
|
if listener, ok := picker.changeListener[DatePickerValue]; ok {
|
||||||
|
listener(picker, DatePickerValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,7 +363,7 @@ func (picker *datePickerData) handleCommand(self View, command string, data Data
|
||||||
return picker.viewData.handleCommand(self, command, data)
|
return picker.viewData.handleCommand(self, command, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDateProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
func getDateProperty(view View, mainTag, shortTag PropertyName) (time.Time, bool) {
|
||||||
valueToTime := func(value any) (time.Time, bool) {
|
valueToTime := func(value any) (time.Time, bool) {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
@ -449,7 +372,7 @@ func getDateProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if text, ok := view.Session().resolveConstants(value); ok {
|
if text, ok := view.Session().resolveConstants(value); ok {
|
||||||
if result, err := time.Parse(dateFormat, text); err == nil {
|
if result, ok := stringToDate(text); ok {
|
||||||
return result, true
|
return result, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,12 +386,14 @@ func getDateProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
||||||
return result, true
|
return result, true
|
||||||
}
|
}
|
||||||
|
|
||||||
if value := valueFromStyle(view, shortTag); value != nil {
|
for _, tag := range []PropertyName{mainTag, shortTag} {
|
||||||
|
if value := valueFromStyle(view, tag); value != nil {
|
||||||
if result, ok := valueToTime(value); ok {
|
if result, ok := valueToTime(value); ok {
|
||||||
return result, true
|
return result, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return time.Now(), false
|
return time.Now(), false
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ const (
|
||||||
//
|
//
|
||||||
// `string` - Summary as a text.
|
// `string` - Summary as a text.
|
||||||
// `View` - Summary as a view, in this case it can be quite complex if needed.
|
// `View` - Summary as a view, in this case it can be quite complex if needed.
|
||||||
Summary = "summary"
|
Summary PropertyName = "summary"
|
||||||
|
|
||||||
// Expanded is the constant for "expanded" property tag.
|
// Expanded is the constant for "expanded" property tag.
|
||||||
//
|
//
|
||||||
|
@ -25,7 +25,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Content is visible.
|
// `true` or `1` or "true", "yes", "on", "1" - Content is visible.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - Content is collapsed(hidden).
|
// `false` or `0` or "false", "no", "off", "0" - Content is collapsed(hidden).
|
||||||
Expanded = "expanded"
|
Expanded PropertyName = "expanded"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DetailsView represent a DetailsView view, which is a collapsible container of views
|
// DetailsView represent a DetailsView view, which is a collapsible container of views
|
||||||
|
@ -46,19 +46,21 @@ func NewDetailsView(session Session, params Params) DetailsView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDetailsView(session Session) View {
|
func newDetailsView(session Session) View {
|
||||||
return NewDetailsView(session, nil)
|
return new(detailsViewData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of DetailsView by default values
|
// Init initialize fields of DetailsView by default values
|
||||||
func (detailsView *detailsViewData) init(session Session) {
|
func (detailsView *detailsViewData) init(session Session) {
|
||||||
detailsView.viewsContainerData.init(session)
|
detailsView.viewsContainerData.init(session)
|
||||||
detailsView.tag = "DetailsView"
|
detailsView.tag = "DetailsView"
|
||||||
|
detailsView.set = detailsView.setFunc
|
||||||
|
detailsView.changed = detailsViewPropertyChanged
|
||||||
//detailsView.systemClass = "ruiDetailsView"
|
//detailsView.systemClass = "ruiDetailsView"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (detailsView *detailsViewData) Views() []View {
|
func (detailsView *detailsViewData) Views() []View {
|
||||||
views := detailsView.viewsContainerData.Views()
|
views := detailsView.viewsContainerData.Views()
|
||||||
if summary := detailsView.get(Summary); summary != nil {
|
if summary := detailsView.Get(Summary); summary != nil {
|
||||||
switch summary := summary.(type) {
|
switch summary := summary.(type) {
|
||||||
case View:
|
case View:
|
||||||
return append([]View{summary}, views...)
|
return append([]View{summary}, views...)
|
||||||
|
@ -67,94 +69,53 @@ func (detailsView *detailsViewData) Views() []View {
|
||||||
return views
|
return views
|
||||||
}
|
}
|
||||||
|
|
||||||
func (detailsView *detailsViewData) Remove(tag string) {
|
func (detailsView *detailsViewData) setFunc(self View, tag PropertyName, value any) []PropertyName {
|
||||||
detailsView.remove(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (detailsView *detailsViewData) remove(tag string) {
|
|
||||||
detailsView.viewsContainerData.remove(tag)
|
|
||||||
if detailsView.created {
|
|
||||||
switch tag {
|
|
||||||
case Summary:
|
|
||||||
updateInnerHTML(detailsView.htmlID(), detailsView.Session())
|
|
||||||
|
|
||||||
case Expanded:
|
|
||||||
detailsView.session.removeProperty(detailsView.htmlID(), "open")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (detailsView *detailsViewData) Set(tag string, value any) bool {
|
|
||||||
return detailsView.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (detailsView *detailsViewData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
detailsView.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Summary:
|
case Summary:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
detailsView.properties[Summary] = value
|
detailsView.setRaw(Summary, value)
|
||||||
|
|
||||||
case View:
|
case View:
|
||||||
detailsView.properties[Summary] = value
|
detailsView.setRaw(Summary, value)
|
||||||
value.setParentID(detailsView.htmlID())
|
value.setParentID(detailsView.htmlID())
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
if view := CreateViewFromObject(detailsView.Session(), value); view != nil {
|
if view := CreateViewFromObject(detailsView.Session(), value); view != nil {
|
||||||
detailsView.properties[Summary] = view
|
detailsView.setRaw(Summary, view)
|
||||||
view.setParentID(detailsView.htmlID())
|
view.setParentID(detailsView.htmlID())
|
||||||
} else {
|
} else {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
if detailsView.created {
|
return []PropertyName{tag}
|
||||||
updateInnerHTML(detailsView.htmlID(), detailsView.Session())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return detailsView.viewsContainerData.setFunc(detailsView, tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func detailsViewPropertyChanged(view View, tag PropertyName) {
|
||||||
|
switch tag {
|
||||||
|
case Summary:
|
||||||
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
|
|
||||||
case Expanded:
|
case Expanded:
|
||||||
if !detailsView.setBoolProperty(tag, value) {
|
if IsDetailsExpanded(view) {
|
||||||
notCompatibleType(tag, value)
|
view.Session().updateProperty(view.htmlID(), "open", "")
|
||||||
return false
|
|
||||||
}
|
|
||||||
if detailsView.created {
|
|
||||||
if IsDetailsExpanded(detailsView) {
|
|
||||||
detailsView.session.updateProperty(detailsView.htmlID(), "open", "")
|
|
||||||
} else {
|
} else {
|
||||||
detailsView.session.removeProperty(detailsView.htmlID(), "open")
|
view.Session().removeProperty(view.htmlID(), "open")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case NotTranslate:
|
case NotTranslate:
|
||||||
if !detailsView.viewData.set(tag, value) {
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
return false
|
|
||||||
}
|
|
||||||
if detailsView.created {
|
|
||||||
updateInnerHTML(detailsView.htmlID(), detailsView.Session())
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return detailsView.viewsContainerData.Set(tag, value)
|
viewsContainerPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
detailsView.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (detailsView *detailsViewData) Get(tag string) any {
|
|
||||||
return detailsView.get(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (detailsView *detailsViewData) get(tag string) any {
|
|
||||||
return detailsView.viewsContainerData.get(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (detailsView *detailsViewData) htmlTag() string {
|
func (detailsView *detailsViewData) htmlTag() string {
|
||||||
|
@ -190,11 +151,13 @@ func (detailsView *detailsViewData) htmlSubviews(self View, buffer *strings.Buil
|
||||||
detailsView.viewsContainerData.htmlSubviews(self, buffer)
|
detailsView.viewsContainerData.htmlSubviews(self, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (detailsView *detailsViewData) handleCommand(self View, command string, data DataObject) bool {
|
func (detailsView *detailsViewData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
if command == "details-open" {
|
if command == "details-open" {
|
||||||
if n, ok := dataIntProperty(data, "open"); ok {
|
if n, ok := dataIntProperty(data, "open"); ok {
|
||||||
detailsView.properties[Expanded] = (n != 0)
|
detailsView.properties[Expanded] = (n != 0)
|
||||||
detailsView.propertyChangedEvent(Expanded)
|
if listener, ok := detailsView.changeListener[Current]; ok {
|
||||||
|
listener(detailsView, Current)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
462
dropDownList.go
462
dropDownList.go
|
@ -1,7 +1,6 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -19,20 +18,15 @@ import (
|
||||||
// index - Index of a newly selected item.
|
// index - Index of a newly selected item.
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
const DropDownEvent = "drop-down-event"
|
const DropDownEvent PropertyName = "drop-down-event"
|
||||||
|
|
||||||
// DropDownList represent a DropDownList view
|
// DropDownList represent a DropDownList view
|
||||||
type DropDownList interface {
|
type DropDownList interface {
|
||||||
View
|
View
|
||||||
getItems() []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type dropDownListData struct {
|
type dropDownListData struct {
|
||||||
viewData
|
viewData
|
||||||
items []string
|
|
||||||
disabledItems []any
|
|
||||||
itemSeparators []any
|
|
||||||
dropDownListener []func(DropDownList, int, int)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDropDownList create new DropDownList object and return it
|
// NewDropDownList create new DropDownList object and return it
|
||||||
|
@ -44,167 +38,86 @@ func NewDropDownList(session Session, params Params) DropDownList {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDropDownList(session Session) View {
|
func newDropDownList(session Session) View {
|
||||||
return NewDropDownList(session, nil)
|
return new(dropDownListData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *dropDownListData) init(session Session) {
|
func (list *dropDownListData) init(session Session) {
|
||||||
list.viewData.init(session)
|
list.viewData.init(session)
|
||||||
list.tag = "DropDownList"
|
list.tag = "DropDownList"
|
||||||
list.hasHtmlDisabled = true
|
list.hasHtmlDisabled = true
|
||||||
list.items = []string{}
|
list.normalize = normalizeDropDownListTag
|
||||||
list.disabledItems = []any{}
|
list.set = dropDownListSet
|
||||||
list.itemSeparators = []any{}
|
list.changed = dropDownListPropertyChanged
|
||||||
list.dropDownListener = []func(DropDownList, int, int){}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dropDownListData) String() string {
|
|
||||||
return getViewString(list, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *dropDownListData) Focusable() bool {
|
func (list *dropDownListData) Focusable() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *dropDownListData) Remove(tag string) {
|
func normalizeDropDownListTag(tag PropertyName) PropertyName {
|
||||||
list.remove(strings.ToLower(tag))
|
tag = defaultNormalize(tag)
|
||||||
|
if tag == "separators" {
|
||||||
|
return ItemSeparators
|
||||||
|
}
|
||||||
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *dropDownListData) remove(tag string) {
|
func dropDownListSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case Items:
|
case Items:
|
||||||
if len(list.items) > 0 {
|
if items, ok := anyToStringArray(value, ""); ok {
|
||||||
list.items = []string{}
|
return setArrayPropertyValue(view, tag, items)
|
||||||
if list.created {
|
|
||||||
updateInnerHTML(list.htmlID(), list.session)
|
|
||||||
}
|
|
||||||
list.propertyChangedEvent(tag)
|
|
||||||
}
|
}
|
||||||
|
notCompatibleType(Items, value)
|
||||||
|
return nil
|
||||||
|
|
||||||
case DisabledItems:
|
case DisabledItems, ItemSeparators:
|
||||||
if len(list.disabledItems) > 0 {
|
if items, ok := parseIndicesArray(value); ok {
|
||||||
list.disabledItems = []any{}
|
return setArrayPropertyValue(view, tag, items)
|
||||||
if list.created {
|
|
||||||
updateInnerHTML(list.htmlID(), list.session)
|
|
||||||
}
|
|
||||||
list.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ItemSeparators, "separators":
|
|
||||||
if len(list.itemSeparators) > 0 {
|
|
||||||
list.itemSeparators = []any{}
|
|
||||||
if list.created {
|
|
||||||
updateInnerHTML(list.htmlID(), list.session)
|
|
||||||
}
|
|
||||||
list.propertyChangedEvent(ItemSeparators)
|
|
||||||
}
|
}
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
|
||||||
case DropDownEvent:
|
case DropDownEvent:
|
||||||
if len(list.dropDownListener) > 0 {
|
return setEventWithOldListener[DropDownList, int](view, tag, value)
|
||||||
list.dropDownListener = []func(DropDownList, int, int){}
|
|
||||||
list.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case Current:
|
case Current:
|
||||||
oldCurrent := GetCurrent(list)
|
if view, ok := view.(View); ok {
|
||||||
delete(list.properties, Current)
|
view.setRaw("old-current", GetCurrent(view))
|
||||||
if oldCurrent != 0 {
|
}
|
||||||
if list.created {
|
return setIntProperty(view, Current, value)
|
||||||
list.session.callFunc("selectDropDownListItem", list.htmlID(), 0)
|
}
|
||||||
|
|
||||||
|
return viewSet(view, tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dropDownListPropertyChanged(view View, tag PropertyName) {
|
||||||
|
switch tag {
|
||||||
|
case Items, DisabledItems, ItemSeparators:
|
||||||
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
|
|
||||||
|
case Current:
|
||||||
|
current := GetCurrent(view)
|
||||||
|
view.Session().callFunc("selectDropDownListItem", view.htmlID(), current)
|
||||||
|
|
||||||
|
if list, ok := view.(DropDownList); ok {
|
||||||
|
oldCurrent := -1
|
||||||
|
if value := view.getRaw("old-current"); value != nil {
|
||||||
|
if n, ok := value.(int); ok {
|
||||||
|
oldCurrent = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, listener := range GetDropDownListeners(view) {
|
||||||
|
listener(list, current, oldCurrent)
|
||||||
}
|
}
|
||||||
list.onSelectedItemChanged(0, oldCurrent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
list.viewData.remove(tag)
|
viewPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *dropDownListData) Set(tag string, value any) bool {
|
|
||||||
return list.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dropDownListData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
list.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
|
||||||
case Items:
|
|
||||||
return list.setItems(value)
|
|
||||||
|
|
||||||
case DisabledItems:
|
|
||||||
items, ok := list.parseIndicesArray(value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
list.disabledItems = items
|
|
||||||
if list.created {
|
|
||||||
updateInnerHTML(list.htmlID(), list.session)
|
|
||||||
}
|
|
||||||
list.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case ItemSeparators, "separators":
|
|
||||||
items, ok := list.parseIndicesArray(value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(ItemSeparators, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
list.itemSeparators = items
|
|
||||||
if list.created {
|
|
||||||
updateInnerHTML(list.htmlID(), list.session)
|
|
||||||
}
|
|
||||||
list.propertyChangedEvent(ItemSeparators)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case DropDownEvent:
|
|
||||||
listeners, ok := valueToEventWithOldListeners[DropDownList, int](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
} else if listeners == nil {
|
|
||||||
listeners = []func(DropDownList, int, int){}
|
|
||||||
}
|
|
||||||
list.dropDownListener = listeners
|
|
||||||
list.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case Current:
|
|
||||||
oldCurrent := GetCurrent(list)
|
|
||||||
if !list.setIntProperty(Current, value) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if current := GetCurrent(list); oldCurrent != current {
|
|
||||||
if list.created {
|
|
||||||
list.session.callFunc("selectDropDownListItem", list.htmlID(), current)
|
|
||||||
}
|
|
||||||
list.onSelectedItemChanged(current, oldCurrent)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return list.viewData.set(tag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dropDownListData) setItems(value any) bool {
|
|
||||||
items, ok := anyToStringArray(value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(Items, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
list.items = items
|
|
||||||
if list.created {
|
|
||||||
updateInnerHTML(list.htmlID(), list.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
list.propertyChangedEvent(Items)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func intArrayToStringArray[T int | uint | int8 | uint8 | int16 | uint16 | int32 | uint32 | int64 | uint64](array []T) []string {
|
func intArrayToStringArray[T int | uint | int8 | uint8 | int16 | uint16 | int32 | uint32 | int64 | uint64](array []T) []string {
|
||||||
items := make([]string, len(array))
|
items := make([]string, len(array))
|
||||||
for i, val := range array {
|
for i, val := range array {
|
||||||
|
@ -213,150 +126,11 @@ func intArrayToStringArray[T int | uint | int8 | uint8 | int16 | uint16 | int32
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
func anyToStringArray(value any) ([]string, bool) {
|
func parseIndicesArray(value any) ([]any, bool) {
|
||||||
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case int:
|
||||||
return []string{value}, true
|
return []any{value}, true
|
||||||
|
|
||||||
case []string:
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case []DataValue:
|
|
||||||
items := make([]string, 0, len(value))
|
|
||||||
for _, val := range value {
|
|
||||||
if !val.IsObject() {
|
|
||||||
items = append(items, val.Value())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items, true
|
|
||||||
|
|
||||||
case []fmt.Stringer:
|
|
||||||
items := make([]string, len(value))
|
|
||||||
for i, str := range value {
|
|
||||||
items[i] = str.String()
|
|
||||||
}
|
|
||||||
return items, true
|
|
||||||
|
|
||||||
case []Color:
|
|
||||||
items := make([]string, len(value))
|
|
||||||
for i, str := range value {
|
|
||||||
items[i] = str.String()
|
|
||||||
}
|
|
||||||
return items, true
|
|
||||||
|
|
||||||
case []SizeUnit:
|
|
||||||
items := make([]string, len(value))
|
|
||||||
for i, str := range value {
|
|
||||||
items[i] = str.String()
|
|
||||||
}
|
|
||||||
return items, true
|
|
||||||
|
|
||||||
case []AngleUnit:
|
|
||||||
items := make([]string, len(value))
|
|
||||||
for i, str := range value {
|
|
||||||
items[i] = str.String()
|
|
||||||
}
|
|
||||||
return items, true
|
|
||||||
|
|
||||||
case []float32:
|
|
||||||
items := make([]string, len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
items[i] = fmt.Sprintf("%g", float64(val))
|
|
||||||
}
|
|
||||||
return items, true
|
|
||||||
|
|
||||||
case []float64:
|
|
||||||
items := make([]string, len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
items[i] = fmt.Sprintf("%g", val)
|
|
||||||
}
|
|
||||||
return items, true
|
|
||||||
|
|
||||||
case []int:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []uint:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []int8:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []uint8:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []int16:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []uint16:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []int32:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []uint32:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []int64:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []uint64:
|
|
||||||
return intArrayToStringArray(value), true
|
|
||||||
|
|
||||||
case []bool:
|
|
||||||
items := make([]string, len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
if val {
|
|
||||||
items[i] = "true"
|
|
||||||
} else {
|
|
||||||
items[i] = "false"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items, true
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
items := make([]string, 0, len(value))
|
|
||||||
for _, v := range value {
|
|
||||||
switch val := v.(type) {
|
|
||||||
case string:
|
|
||||||
items = append(items, val)
|
|
||||||
|
|
||||||
case fmt.Stringer:
|
|
||||||
items = append(items, val.String())
|
|
||||||
|
|
||||||
case bool:
|
|
||||||
if val {
|
|
||||||
items = append(items, "true")
|
|
||||||
} else {
|
|
||||||
items = append(items, "false")
|
|
||||||
}
|
|
||||||
|
|
||||||
case float32:
|
|
||||||
items = append(items, fmt.Sprintf("%g", float64(val)))
|
|
||||||
|
|
||||||
case float64:
|
|
||||||
items = append(items, fmt.Sprintf("%g", val))
|
|
||||||
|
|
||||||
case rune:
|
|
||||||
items = append(items, string(val))
|
|
||||||
|
|
||||||
default:
|
|
||||||
if n, ok := isInt(v); ok {
|
|
||||||
items = append(items, strconv.Itoa(n))
|
|
||||||
} else {
|
|
||||||
return []string{}, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return items, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return []string{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dropDownListData) parseIndicesArray(value any) ([]any, bool) {
|
|
||||||
switch value := value.(type) {
|
|
||||||
case []int:
|
case []int:
|
||||||
items := make([]any, len(value))
|
items := make([]any, len(value))
|
||||||
for i, n := range value {
|
for i, n := range value {
|
||||||
|
@ -365,108 +139,72 @@ func (list *dropDownListData) parseIndicesArray(value any) ([]any, bool) {
|
||||||
return items, true
|
return items, true
|
||||||
|
|
||||||
case []any:
|
case []any:
|
||||||
items := make([]any, len(value))
|
items := make([]any, 0, len(value))
|
||||||
for i, val := range value {
|
for _, val := range value {
|
||||||
if val == nil {
|
if val != nil {
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch val := val.(type) {
|
switch val := val.(type) {
|
||||||
case string:
|
case string:
|
||||||
if isConstantName(val) {
|
if isConstantName(val) {
|
||||||
items[i] = val
|
items = append(items, val)
|
||||||
} else {
|
} else if n, err := strconv.Atoi(val); err == nil {
|
||||||
n, err := strconv.Atoi(val)
|
items = append(items, n)
|
||||||
if err != nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
items[i] = n
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if n, ok := isInt(val); ok {
|
|
||||||
items[i] = n
|
|
||||||
} else {
|
} else {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
if n, ok := isInt(val); ok {
|
||||||
|
items = append(items, n)
|
||||||
|
} else {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items, true
|
||||||
|
|
||||||
|
case []string:
|
||||||
|
items := make([]any, 0, len(value))
|
||||||
|
for _, str := range value {
|
||||||
|
if str = strings.Trim(str, " \t"); str != "" {
|
||||||
|
if isConstantName(str) {
|
||||||
|
items = append(items, str)
|
||||||
|
} else if n, err := strconv.Atoi(str); err == nil {
|
||||||
|
items = append(items, n)
|
||||||
|
} else {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return items, true
|
return items, true
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
values := strings.Split(value, ",")
|
return parseIndicesArray(strings.Split(value, ","))
|
||||||
items := make([]any, len(values))
|
|
||||||
for i, str := range values {
|
|
||||||
str = strings.Trim(str, " ")
|
|
||||||
if str == "" {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
if isConstantName(str) {
|
|
||||||
items[i] = str
|
|
||||||
} else {
|
|
||||||
n, err := strconv.Atoi(str)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
items[i] = n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items, true
|
|
||||||
|
|
||||||
case []DataValue:
|
case []DataValue:
|
||||||
items := make([]any, 0, len(value))
|
items := make([]string, 0, len(value))
|
||||||
for _, val := range value {
|
for _, val := range value {
|
||||||
if !val.IsObject() {
|
if !val.IsObject() {
|
||||||
items = append(items, val.Value())
|
items = append(items, val.Value())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list.parseIndicesArray(items)
|
return parseIndicesArray(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *dropDownListData) Get(tag string) any {
|
|
||||||
return list.get(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dropDownListData) get(tag string) any {
|
|
||||||
switch tag {
|
|
||||||
case Items:
|
|
||||||
return list.items
|
|
||||||
|
|
||||||
case DisabledItems:
|
|
||||||
return list.disabledItems
|
|
||||||
|
|
||||||
case ItemSeparators:
|
|
||||||
return list.itemSeparators
|
|
||||||
|
|
||||||
case Current:
|
|
||||||
result, _ := intProperty(list, Current, list.session, 0)
|
|
||||||
return result
|
|
||||||
|
|
||||||
case DropDownEvent:
|
|
||||||
return list.dropDownListener
|
|
||||||
}
|
|
||||||
|
|
||||||
return list.viewData.get(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dropDownListData) getItems() []string {
|
|
||||||
return list.items
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dropDownListData) htmlTag() string {
|
func (list *dropDownListData) htmlTag() string {
|
||||||
return "select"
|
return "select"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *dropDownListData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (list *dropDownListData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
if list.items != nil {
|
if items := GetDropDownItems(list); len(items) > 0 {
|
||||||
current := GetCurrent(list)
|
current := GetCurrent(list)
|
||||||
notTranslate := GetNotTranslate(list)
|
notTranslate := GetNotTranslate(list)
|
||||||
disabledItems := GetDropDownDisabledItems(list)
|
disabledItems := GetDropDownDisabledItems(list)
|
||||||
separators := GetDropDownItemSeparators(list)
|
separators := GetDropDownItemSeparators(list)
|
||||||
for i, item := range list.items {
|
for i, item := range items {
|
||||||
disabled := false
|
disabled := false
|
||||||
for _, index := range disabledItems {
|
for _, index := range disabledItems {
|
||||||
if i == index {
|
if i == index {
|
||||||
|
@ -503,22 +241,18 @@ func (list *dropDownListData) htmlProperties(self View, buffer *strings.Builder)
|
||||||
buffer.WriteString(` size="1" onchange="dropDownListEvent(this, event)"`)
|
buffer.WriteString(` size="1" onchange="dropDownListEvent(this, event)"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *dropDownListData) onSelectedItemChanged(number, old int) {
|
func (list *dropDownListData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
for _, listener := range list.dropDownListener {
|
|
||||||
listener(list, number, old)
|
|
||||||
}
|
|
||||||
list.propertyChangedEvent(Current)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (list *dropDownListData) handleCommand(self View, command string, data DataObject) bool {
|
|
||||||
switch command {
|
switch command {
|
||||||
case "itemSelected":
|
case "itemSelected":
|
||||||
if text, ok := data.PropertyValue("number"); ok {
|
if text, ok := data.PropertyValue("number"); ok {
|
||||||
if number, err := strconv.Atoi(text); err == nil {
|
if number, err := strconv.Atoi(text); err == nil {
|
||||||
if GetCurrent(list) != number && number >= 0 && number < len(list.items) {
|
items := GetDropDownItems(list)
|
||||||
|
if GetCurrent(list) != number && number >= 0 && number < len(items) {
|
||||||
old := GetCurrent(list)
|
old := GetCurrent(list)
|
||||||
list.properties[Current] = number
|
list.properties[Current] = number
|
||||||
list.onSelectedItemChanged(number, old)
|
for _, listener := range GetDropDownListeners(list) {
|
||||||
|
listener(list, number, old)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ErrorLog(err.Error())
|
ErrorLog(err.Error())
|
||||||
|
@ -544,14 +278,16 @@ func GetDropDownItems(view View, subviewID ...string) []string {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if list, ok := view.(DropDownList); ok {
|
if value := view.Get(Items); value != nil {
|
||||||
return list.getItems()
|
if items, ok := value.([]string); ok {
|
||||||
|
return items
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIndicesArray(view View, tag string) []int {
|
func getIndicesArray(view View, tag PropertyName) []int {
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if value := view.Get(tag); value != nil {
|
if value := view.Get(tag); value != nil {
|
||||||
if values, ok := value.([]any); ok {
|
if values, ok := value.([]any); ok {
|
||||||
|
|
325
editView.go
325
editView.go
|
@ -26,7 +26,7 @@ const (
|
||||||
// `func(newText string)`,
|
// `func(newText string)`,
|
||||||
// `func(editView rui.EditView)`,
|
// `func(editView rui.EditView)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
EditTextChangedEvent = "edit-text-changed"
|
EditTextChangedEvent PropertyName = "edit-text-changed"
|
||||||
|
|
||||||
// EditViewType is the constant for "edit-view-type" property tag.
|
// EditViewType is the constant for "edit-view-type" property tag.
|
||||||
//
|
//
|
||||||
|
@ -43,7 +43,7 @@ const (
|
||||||
// `4`(`URLText`) or "url" - Internet address input editor.
|
// `4`(`URLText`) or "url" - Internet address input editor.
|
||||||
// `5`(`PhoneText`) or "phone" - Phone number editor.
|
// `5`(`PhoneText`) or "phone" - Phone number editor.
|
||||||
// `6`(`MultiLineText`) or "multiline" - Multi-line text editor.
|
// `6`(`MultiLineText`) or "multiline" - Multi-line text editor.
|
||||||
EditViewType = "edit-view-type"
|
EditViewType PropertyName = "edit-view-type"
|
||||||
|
|
||||||
// EditViewPattern is the constant for "edit-view-pattern" property tag.
|
// EditViewPattern is the constant for "edit-view-pattern" property tag.
|
||||||
//
|
//
|
||||||
|
@ -51,7 +51,7 @@ const (
|
||||||
// Regular expression to limit editing of a text.
|
// Regular expression to limit editing of a text.
|
||||||
//
|
//
|
||||||
// Supported types: `string`.
|
// Supported types: `string`.
|
||||||
EditViewPattern = "edit-view-pattern"
|
EditViewPattern PropertyName = "edit-view-pattern"
|
||||||
|
|
||||||
// Spellcheck is the constant for "spellcheck" property tag.
|
// Spellcheck is the constant for "spellcheck" property tag.
|
||||||
//
|
//
|
||||||
|
@ -64,7 +64,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Enable spell checker for text.
|
// `true` or `1` or "true", "yes", "on", "1" - Enable spell checker for text.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - Disable spell checker for text.
|
// `false` or `0` or "false", "no", "off", "0" - Disable spell checker for text.
|
||||||
Spellcheck = "spellcheck"
|
Spellcheck PropertyName = "spellcheck"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Constants for the values of an [EditView] "edit-view-type" property
|
// Constants for the values of an [EditView] "edit-view-type" property
|
||||||
|
@ -97,12 +97,11 @@ type EditView interface {
|
||||||
|
|
||||||
// AppendText appends text to the current text of an EditView view
|
// AppendText appends text to the current text of an EditView view
|
||||||
AppendText(text string)
|
AppendText(text string)
|
||||||
|
textChanged(newText, oldText string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type editViewData struct {
|
type editViewData struct {
|
||||||
viewData
|
viewData
|
||||||
dataList
|
|
||||||
textChangeListeners []func(EditView, string, string)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEditView create new EditView object and return it
|
// NewEditView create new EditView object and return it
|
||||||
|
@ -114,27 +113,24 @@ func NewEditView(session Session, params Params) EditView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEditView(session Session) View {
|
func newEditView(session Session) View {
|
||||||
return NewEditView(session, nil)
|
return new(editViewData) // NewEditView(session, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) init(session Session) {
|
func (edit *editViewData) init(session Session) {
|
||||||
edit.viewData.init(session)
|
edit.viewData.init(session)
|
||||||
edit.hasHtmlDisabled = true
|
edit.hasHtmlDisabled = true
|
||||||
edit.textChangeListeners = []func(EditView, string, string){}
|
|
||||||
edit.tag = "EditView"
|
edit.tag = "EditView"
|
||||||
edit.dataListInit()
|
edit.normalize = normalizeEditViewTag
|
||||||
}
|
edit.set = editViewSet
|
||||||
|
edit.changed = editViewPropertyChanged
|
||||||
func (edit *editViewData) String() string {
|
|
||||||
return getViewString(edit, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) Focusable() bool {
|
func (edit *editViewData) Focusable() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) normalizeTag(tag string) string {
|
func normalizeEditViewTag(tag PropertyName) PropertyName {
|
||||||
tag = strings.ToLower(tag)
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case Type, "edit-type":
|
case Type, "edit-type":
|
||||||
return EditViewType
|
return EditViewType
|
||||||
|
@ -149,279 +145,109 @@ func (edit *editViewData) normalizeTag(tag string) string {
|
||||||
return EditWrap
|
return EditWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
return edit.normalizeDataListTag(tag)
|
return normalizeDataListTag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) Remove(tag string) {
|
func editViewSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
edit.remove(edit.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (edit *editViewData) remove(tag string) {
|
|
||||||
_, exists := edit.properties[tag]
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Hint:
|
|
||||||
if exists {
|
|
||||||
delete(edit.properties, Hint)
|
|
||||||
if edit.created {
|
|
||||||
edit.session.removeProperty(edit.htmlID(), "placeholder")
|
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case MaxLength:
|
|
||||||
if exists {
|
|
||||||
delete(edit.properties, MaxLength)
|
|
||||||
if edit.created {
|
|
||||||
edit.session.removeProperty(edit.htmlID(), "maxlength")
|
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ReadOnly, Spellcheck:
|
|
||||||
if exists {
|
|
||||||
delete(edit.properties, tag)
|
|
||||||
if edit.created {
|
|
||||||
edit.session.updateProperty(edit.htmlID(), tag, false)
|
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case EditTextChangedEvent:
|
|
||||||
if len(edit.textChangeListeners) > 0 {
|
|
||||||
edit.textChangeListeners = []func(EditView, string, string){}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case Text:
|
case Text:
|
||||||
if exists {
|
if text, ok := value.(string); ok {
|
||||||
oldText := GetText(edit)
|
old := ""
|
||||||
delete(edit.properties, tag)
|
if val := view.getRaw(Text); val != nil {
|
||||||
if oldText != "" {
|
if txt, ok := val.(string); ok {
|
||||||
edit.textChanged("", oldText)
|
old = txt
|
||||||
if edit.created {
|
|
||||||
edit.session.callFunc("setInputValue", edit.htmlID(), "")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
view.setRaw("old-text", old)
|
||||||
|
view.setRaw(tag, text)
|
||||||
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case EditViewPattern:
|
notCompatibleType(tag, value)
|
||||||
if exists {
|
return nil
|
||||||
oldText := GetEditViewPattern(edit)
|
|
||||||
delete(edit.properties, tag)
|
|
||||||
if oldText != "" {
|
|
||||||
if edit.created {
|
|
||||||
edit.session.removeProperty(edit.htmlID(), Pattern)
|
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case EditViewType:
|
case Hint:
|
||||||
if exists {
|
if text, ok := value.(string); ok {
|
||||||
oldType := GetEditViewType(edit)
|
return setStringPropertyValue(view, tag, strings.Trim(text, " \t\n"))
|
||||||
delete(edit.properties, tag)
|
|
||||||
if oldType != 0 {
|
|
||||||
if edit.created {
|
|
||||||
updateInnerHTML(edit.parentHTMLID(), edit.session)
|
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case EditWrap:
|
|
||||||
if exists {
|
|
||||||
oldWrap := IsEditViewWrap(edit)
|
|
||||||
delete(edit.properties, tag)
|
|
||||||
if GetEditViewType(edit) == MultiLineText {
|
|
||||||
if wrap := IsEditViewWrap(edit); wrap != oldWrap {
|
|
||||||
if edit.created {
|
|
||||||
if wrap {
|
|
||||||
edit.session.updateProperty(edit.htmlID(), "wrap", "soft")
|
|
||||||
} else {
|
|
||||||
edit.session.updateProperty(edit.htmlID(), "wrap", "off")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
|
||||||
case DataList:
|
case DataList:
|
||||||
if len(edit.dataList.dataList) > 0 {
|
setDataList(view, value, "")
|
||||||
edit.setDataList(edit, []string{}, true)
|
|
||||||
|
case EditTextChangedEvent:
|
||||||
|
return setEventWithOldListener[EditView, string](view, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
return viewSet(view, tag, value)
|
||||||
edit.viewData.remove(tag)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) Set(tag string, value any) bool {
|
func editViewPropertyChanged(view View, tag PropertyName) {
|
||||||
return edit.set(edit.normalizeTag(tag), value)
|
session := view.Session()
|
||||||
}
|
|
||||||
|
|
||||||
func (edit *editViewData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
edit.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Text:
|
case Text:
|
||||||
if text, ok := value.(string); ok {
|
text := GetText(view)
|
||||||
oldText := GetText(edit)
|
session.callFunc("setInputValue", view.htmlID(), text)
|
||||||
edit.properties[Text] = text
|
|
||||||
if text = GetText(edit); oldText != text {
|
if edit, ok := view.(EditView); ok {
|
||||||
edit.textChanged(text, oldText)
|
old := ""
|
||||||
if edit.created {
|
if val := view.getRaw("old-text"); val != nil {
|
||||||
edit.session.callFunc("setInputValue", edit.htmlID(), text)
|
if txt, ok := val.(string); ok {
|
||||||
|
old = txt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
edit.textChanged(text, old)
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
|
|
||||||
case Hint:
|
case Hint:
|
||||||
if text, ok := value.(string); ok {
|
if text := GetHint(view); text != "" {
|
||||||
oldText := GetHint(edit)
|
session.updateProperty(view.htmlID(), "placeholder", text)
|
||||||
edit.properties[Hint] = text
|
|
||||||
if text = GetHint(edit); oldText != text {
|
|
||||||
if edit.created {
|
|
||||||
if text != "" {
|
|
||||||
edit.session.updateProperty(edit.htmlID(), "placeholder", text)
|
|
||||||
} else {
|
} else {
|
||||||
edit.session.removeProperty(edit.htmlID(), "placeholder")
|
session.removeProperty(view.htmlID(), "placeholder")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
|
|
||||||
case MaxLength:
|
case MaxLength:
|
||||||
oldMaxLength := GetMaxLength(edit)
|
if maxLength := GetMaxLength(view); maxLength > 0 {
|
||||||
if edit.setIntProperty(MaxLength, value) {
|
session.updateProperty(view.htmlID(), "maxlength", strconv.Itoa(maxLength))
|
||||||
if maxLength := GetMaxLength(edit); maxLength != oldMaxLength {
|
|
||||||
if edit.created {
|
|
||||||
if maxLength > 0 {
|
|
||||||
edit.session.updateProperty(edit.htmlID(), "maxlength", strconv.Itoa(maxLength))
|
|
||||||
} else {
|
} else {
|
||||||
edit.session.removeProperty(edit.htmlID(), "maxlength")
|
session.removeProperty(view.htmlID(), "maxlength")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
|
|
||||||
case ReadOnly:
|
case ReadOnly:
|
||||||
if edit.setBoolProperty(ReadOnly, value) {
|
if IsReadOnly(view) {
|
||||||
if edit.created {
|
session.updateProperty(view.htmlID(), "readonly", "")
|
||||||
if IsReadOnly(edit) {
|
|
||||||
edit.session.updateProperty(edit.htmlID(), ReadOnly, "")
|
|
||||||
} else {
|
} else {
|
||||||
edit.session.removeProperty(edit.htmlID(), ReadOnly)
|
session.removeProperty(view.htmlID(), "readonly")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
|
|
||||||
case Spellcheck:
|
case Spellcheck:
|
||||||
if edit.setBoolProperty(Spellcheck, value) {
|
session.updateProperty(view.htmlID(), "spellcheck", IsSpellcheck(view))
|
||||||
if edit.created {
|
|
||||||
edit.session.updateProperty(edit.htmlID(), Spellcheck, IsSpellcheck(edit))
|
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
|
|
||||||
case EditViewPattern:
|
case EditViewPattern:
|
||||||
oldText := GetEditViewPattern(edit)
|
if text := GetEditViewPattern(view); text != "" {
|
||||||
if text, ok := value.(string); ok {
|
session.updateProperty(view.htmlID(), "pattern", text)
|
||||||
edit.properties[EditViewPattern] = text
|
|
||||||
if text = GetEditViewPattern(edit); oldText != text {
|
|
||||||
if edit.created {
|
|
||||||
if text != "" {
|
|
||||||
edit.session.updateProperty(edit.htmlID(), Pattern, text)
|
|
||||||
} else {
|
} else {
|
||||||
edit.session.removeProperty(edit.htmlID(), Pattern)
|
session.removeProperty(view.htmlID(), "pattern")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
|
|
||||||
case EditViewType:
|
case EditViewType:
|
||||||
oldType := GetEditViewType(edit)
|
updateInnerHTML(view.parentHTMLID(), session)
|
||||||
if edit.setEnumProperty(EditViewType, value, enumProperties[EditViewType].values) {
|
|
||||||
if GetEditViewType(edit) != oldType {
|
|
||||||
if edit.created {
|
|
||||||
updateInnerHTML(edit.parentHTMLID(), edit.session)
|
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
|
|
||||||
case EditWrap:
|
case EditWrap:
|
||||||
oldWrap := IsEditViewWrap(edit)
|
if wrap := IsEditViewWrap(view); wrap {
|
||||||
if edit.setBoolProperty(EditWrap, value) {
|
session.updateProperty(view.htmlID(), "wrap", "soft")
|
||||||
if GetEditViewType(edit) == MultiLineText {
|
|
||||||
if wrap := IsEditViewWrap(edit); wrap != oldWrap {
|
|
||||||
if edit.created {
|
|
||||||
if wrap {
|
|
||||||
edit.session.updateProperty(edit.htmlID(), "wrap", "soft")
|
|
||||||
} else {
|
} else {
|
||||||
edit.session.updateProperty(edit.htmlID(), "wrap", "off")
|
session.updateProperty(view.htmlID(), "wrap", "off")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
|
|
||||||
case DataList:
|
case DataList:
|
||||||
return edit.setDataList(edit, value, edit.created)
|
updateInnerHTML(view.htmlID(), session)
|
||||||
|
|
||||||
case EditTextChangedEvent:
|
default:
|
||||||
listeners, ok := valueToEventWithOldListeners[EditView, string](value)
|
viewPropertyChanged(view, tag)
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
} else if listeners == nil {
|
|
||||||
listeners = []func(EditView, string, string){}
|
|
||||||
}
|
}
|
||||||
edit.textChangeListeners = listeners
|
|
||||||
edit.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return edit.viewData.set(tag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (edit *editViewData) Get(tag string) any {
|
|
||||||
return edit.get(edit.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (edit *editViewData) get(tag string) any {
|
|
||||||
switch tag {
|
|
||||||
case EditTextChangedEvent:
|
|
||||||
return edit.textChangeListeners
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
return edit.dataList.dataList
|
|
||||||
}
|
|
||||||
return edit.viewData.get(tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) AppendText(text string) {
|
func (edit *editViewData) AppendText(text string) {
|
||||||
|
@ -432,21 +258,24 @@ func (edit *editViewData) AppendText(text string) {
|
||||||
textValue += text
|
textValue += text
|
||||||
edit.properties[Text] = textValue
|
edit.properties[Text] = textValue
|
||||||
edit.session.callFunc("appendToInnerHTML", edit.htmlID(), text)
|
edit.session.callFunc("appendToInnerHTML", edit.htmlID(), text)
|
||||||
|
edit.session.callFunc("appendToInputValue", edit.htmlID(), text)
|
||||||
edit.textChanged(textValue, oldText)
|
edit.textChanged(textValue, oldText)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
edit.set(Text, text)
|
edit.setRaw(Text, text)
|
||||||
} else {
|
} else {
|
||||||
edit.set(Text, GetText(edit)+text)
|
edit.setRaw(Text, GetText(edit)+text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) textChanged(newText, oldText string) {
|
func (edit *editViewData) textChanged(newText, oldText string) {
|
||||||
for _, listener := range edit.textChangeListeners {
|
for _, listener := range GetTextChangedListeners(edit) {
|
||||||
listener(edit, newText, oldText)
|
listener(edit, newText, oldText)
|
||||||
}
|
}
|
||||||
edit.propertyChangedEvent(Text)
|
if listener, ok := edit.changeListener[Text]; ok {
|
||||||
|
listener(edit, Text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) htmlTag() string {
|
func (edit *editViewData) htmlTag() string {
|
||||||
|
@ -462,7 +291,9 @@ func (edit *editViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
buffer.WriteString(text)
|
buffer.WriteString(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
edit.dataListHtmlSubviews(self, buffer)
|
dataListHtmlSubviews(self, buffer, func(text string, session Session) string {
|
||||||
|
return text
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
|
func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
|
@ -547,16 +378,16 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
edit.dataListHtmlProperties(edit, buffer)
|
dataListHtmlProperties(edit, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) handleCommand(self View, command string, data DataObject) bool {
|
func (edit *editViewData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
oldText := GetText(edit)
|
oldText := GetText(edit)
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyValue("text"); ok {
|
||||||
edit.properties[Text] = text
|
edit.setRaw(Text, text)
|
||||||
if text := GetText(edit); text != oldText {
|
if text != oldText {
|
||||||
edit.textChanged(text, oldText)
|
edit.textChanged(text, oldText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,526 @@
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
var eventJsFunc = map[PropertyName]struct{ jsEvent, jsFunc string }{
|
||||||
|
FocusEvent: {jsEvent: "onfocus", jsFunc: "focusEvent"},
|
||||||
|
LostFocusEvent: {jsEvent: "onblur", jsFunc: "blurEvent"},
|
||||||
|
KeyDownEvent: {jsEvent: "onkeydown", jsFunc: "keyDownEvent"},
|
||||||
|
KeyUpEvent: {jsEvent: "onkeyup", jsFunc: "keyUpEvent"},
|
||||||
|
ClickEvent: {jsEvent: "onclick", jsFunc: "clickEvent"},
|
||||||
|
DoubleClickEvent: {jsEvent: "ondblclick", jsFunc: "doubleClickEvent"},
|
||||||
|
MouseDown: {jsEvent: "onmousedown", jsFunc: "mouseDownEvent"},
|
||||||
|
MouseUp: {jsEvent: "onmouseup", jsFunc: "mouseUpEvent"},
|
||||||
|
MouseMove: {jsEvent: "onmousemove", jsFunc: "mouseMoveEvent"},
|
||||||
|
MouseOut: {jsEvent: "onmouseout", jsFunc: "mouseOutEvent"},
|
||||||
|
MouseOver: {jsEvent: "onmouseover", jsFunc: "mouseOverEvent"},
|
||||||
|
ContextMenuEvent: {jsEvent: "oncontextmenu", jsFunc: "contextMenuEvent"},
|
||||||
|
PointerDown: {jsEvent: "onpointerdown", jsFunc: "pointerDownEvent"},
|
||||||
|
PointerUp: {jsEvent: "onpointerup", jsFunc: "pointerUpEvent"},
|
||||||
|
PointerMove: {jsEvent: "onpointermove", jsFunc: "pointerMoveEvent"},
|
||||||
|
PointerCancel: {jsEvent: "onpointercancel", jsFunc: "pointerCancelEvent"},
|
||||||
|
PointerOut: {jsEvent: "onpointerout", jsFunc: "pointerOutEvent"},
|
||||||
|
PointerOver: {jsEvent: "onpointerover", jsFunc: "pointerOverEvent"},
|
||||||
|
TouchStart: {jsEvent: "ontouchstart", jsFunc: "touchStartEvent"},
|
||||||
|
TouchEnd: {jsEvent: "ontouchend", jsFunc: "touchEndEvent"},
|
||||||
|
TouchMove: {jsEvent: "ontouchmove", jsFunc: "touchMoveEvent"},
|
||||||
|
TouchCancel: {jsEvent: "ontouchcancel", jsFunc: "touchCancelEvent"},
|
||||||
|
TransitionRunEvent: {jsEvent: "ontransitionrun", jsFunc: "transitionRunEvent"},
|
||||||
|
TransitionStartEvent: {jsEvent: "ontransitionstart", jsFunc: "transitionStartEvent"},
|
||||||
|
TransitionEndEvent: {jsEvent: "ontransitionend", jsFunc: "transitionEndEvent"},
|
||||||
|
TransitionCancelEvent: {jsEvent: "ontransitioncancel", jsFunc: "transitionCancelEvent"},
|
||||||
|
AnimationStartEvent: {jsEvent: "onanimationstart", jsFunc: "animationStartEvent"},
|
||||||
|
AnimationEndEvent: {jsEvent: "onanimationend", jsFunc: "animationEndEvent"},
|
||||||
|
AnimationIterationEvent: {jsEvent: "onanimationiteration", jsFunc: "animationIterationEvent"},
|
||||||
|
AnimationCancelEvent: {jsEvent: "onanimationcancel", jsFunc: "animationCancelEvent"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToNoParamListeners[V any](value any) ([]func(V), bool) {
|
||||||
|
if value == nil {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case func(V):
|
||||||
|
return []func(V){value}, true
|
||||||
|
|
||||||
|
case func():
|
||||||
|
fn := func(V) {
|
||||||
|
value()
|
||||||
|
}
|
||||||
|
return []func(V){fn}, true
|
||||||
|
|
||||||
|
case []func(V):
|
||||||
|
if len(value) == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case []func():
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
listeners[i] = func(V) {
|
||||||
|
v()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
switch v := v.(type) {
|
||||||
|
case func(V):
|
||||||
|
listeners[i] = v
|
||||||
|
|
||||||
|
case func():
|
||||||
|
listeners[i] = func(V) {
|
||||||
|
v()
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToEventListeners[V View, E any](value any) ([]func(V, E), bool) {
|
||||||
|
if value == nil {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case func(V, E):
|
||||||
|
return []func(V, E){value}, true
|
||||||
|
|
||||||
|
case func(E):
|
||||||
|
fn := func(_ V, event E) {
|
||||||
|
value(event)
|
||||||
|
}
|
||||||
|
return []func(V, E){fn}, true
|
||||||
|
|
||||||
|
case func(V):
|
||||||
|
fn := func(view V, _ E) {
|
||||||
|
value(view)
|
||||||
|
}
|
||||||
|
return []func(V, E){fn}, true
|
||||||
|
|
||||||
|
case func():
|
||||||
|
fn := func(V, E) {
|
||||||
|
value()
|
||||||
|
}
|
||||||
|
return []func(V, E){fn}, true
|
||||||
|
|
||||||
|
case []func(V, E):
|
||||||
|
if len(value) == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case []func(E):
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
listeners[i] = func(_ V, event E) {
|
||||||
|
v(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []func(V):
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
listeners[i] = func(view V, _ E) {
|
||||||
|
v(view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []func():
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
listeners[i] = func(V, E) {
|
||||||
|
v()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
switch v := v.(type) {
|
||||||
|
case func(V, E):
|
||||||
|
listeners[i] = v
|
||||||
|
|
||||||
|
case func(E):
|
||||||
|
listeners[i] = func(_ V, event E) {
|
||||||
|
v(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
case func(V):
|
||||||
|
listeners[i] = func(view V, _ E) {
|
||||||
|
v(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
case func():
|
||||||
|
listeners[i] = func(V, E) {
|
||||||
|
v()
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToEventWithOldListeners[V View, E any](value any) ([]func(V, E, E), bool) {
|
||||||
|
if value == nil {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case func(V, E, E):
|
||||||
|
return []func(V, E, E){value}, true
|
||||||
|
|
||||||
|
case func(V, E):
|
||||||
|
fn := func(v V, val, _ E) {
|
||||||
|
value(v, val)
|
||||||
|
}
|
||||||
|
return []func(V, E, E){fn}, true
|
||||||
|
|
||||||
|
case func(E, E):
|
||||||
|
fn := func(_ V, val, old E) {
|
||||||
|
value(val, old)
|
||||||
|
}
|
||||||
|
return []func(V, E, E){fn}, true
|
||||||
|
|
||||||
|
case func(E):
|
||||||
|
fn := func(_ V, val, _ E) {
|
||||||
|
value(val)
|
||||||
|
}
|
||||||
|
return []func(V, E, E){fn}, true
|
||||||
|
|
||||||
|
case func(V):
|
||||||
|
fn := func(v V, _, _ E) {
|
||||||
|
value(v)
|
||||||
|
}
|
||||||
|
return []func(V, E, E){fn}, true
|
||||||
|
|
||||||
|
case func():
|
||||||
|
fn := func(V, E, E) {
|
||||||
|
value()
|
||||||
|
}
|
||||||
|
return []func(V, E, E){fn}, true
|
||||||
|
|
||||||
|
case []func(V, E, E):
|
||||||
|
if len(value) == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case []func(V, E):
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E, E), count)
|
||||||
|
for i, fn := range value {
|
||||||
|
if fn == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
listeners[i] = func(view V, val, _ E) {
|
||||||
|
fn(view, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []func(E):
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E, E), count)
|
||||||
|
for i, fn := range value {
|
||||||
|
if fn == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
listeners[i] = func(_ V, val, _ E) {
|
||||||
|
fn(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []func(E, E):
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E, E), count)
|
||||||
|
for i, fn := range value {
|
||||||
|
if fn == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
listeners[i] = func(_ V, val, old E) {
|
||||||
|
fn(val, old)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []func(V):
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E, E), count)
|
||||||
|
for i, fn := range value {
|
||||||
|
if fn == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
listeners[i] = func(view V, _, _ E) {
|
||||||
|
fn(view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []func():
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E, E), count)
|
||||||
|
for i, fn := range value {
|
||||||
|
if fn == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
listeners[i] = func(V, E, E) {
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(V, E, E), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
switch fn := v.(type) {
|
||||||
|
case func(V, E, E):
|
||||||
|
listeners[i] = fn
|
||||||
|
|
||||||
|
case func(V, E):
|
||||||
|
listeners[i] = func(view V, val, _ E) {
|
||||||
|
fn(view, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
case func(E, E):
|
||||||
|
listeners[i] = func(_ V, val, old E) {
|
||||||
|
fn(val, old)
|
||||||
|
}
|
||||||
|
|
||||||
|
case func(E):
|
||||||
|
listeners[i] = func(_ V, val, _ E) {
|
||||||
|
fn(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
case func(V):
|
||||||
|
listeners[i] = func(view V, _, _ E) {
|
||||||
|
fn(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
case func():
|
||||||
|
listeners[i] = func(V, E, E) {
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNoParamEventListeners[V View](view View, subviewID []string, tag PropertyName) []func(V) {
|
||||||
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
|
view = ViewByID(view, subviewID[0])
|
||||||
|
}
|
||||||
|
if view != nil {
|
||||||
|
if value := view.Get(tag); value != nil {
|
||||||
|
if result, ok := value.([]func(V)); ok {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []func(V){}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E) {
|
||||||
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
|
view = ViewByID(view, subviewID[0])
|
||||||
|
}
|
||||||
|
if view != nil {
|
||||||
|
if value := view.Get(tag); value != nil {
|
||||||
|
if result, ok := value.([]func(V, E)); ok {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []func(V, E){}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEventWithOldListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E, E) {
|
||||||
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
|
view = ViewByID(view, subviewID[0])
|
||||||
|
}
|
||||||
|
if view != nil {
|
||||||
|
if value := view.Get(tag); value != nil {
|
||||||
|
if result, ok := value.([]func(V, E, E)); ok {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []func(V, E, E){}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNoParamEventListener[V View](properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
if listeners, ok := valueToNoParamListeners[V](value); ok {
|
||||||
|
if len(listeners) > 0 {
|
||||||
|
properties.setRaw(tag, listeners)
|
||||||
|
} else if properties.getRaw(tag) != nil {
|
||||||
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
return []PropertyName{}
|
||||||
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setViewEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
if listeners, ok := valueToEventListeners[V, T](value); ok {
|
||||||
|
if len(listeners) > 0 {
|
||||||
|
properties.setRaw(tag, listeners)
|
||||||
|
} else if properties.getRaw(tag) != nil {
|
||||||
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
return []PropertyName{}
|
||||||
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setEventWithOldListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
listeners, ok := valueToEventWithOldListeners[V, T](value)
|
||||||
|
if !ok {
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
} else if len(listeners) > 0 {
|
||||||
|
properties.setRaw(tag, listeners)
|
||||||
|
} else if properties.getRaw(tag) != nil {
|
||||||
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
return []PropertyName{}
|
||||||
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
func viewEventsHtml[T any](view View, events []PropertyName, buffer *strings.Builder) {
|
||||||
|
for _, tag := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent} {
|
||||||
|
if value := view.getRaw(tag); value != nil {
|
||||||
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
|
if listeners, ok := value.([]func(View, T)); ok && len(listeners) > 0 {
|
||||||
|
buffer.WriteString(js.jsEvent)
|
||||||
|
buffer.WriteString(`="`)
|
||||||
|
buffer.WriteString(js.jsFunc)
|
||||||
|
buffer.WriteString(`(this, event)" `)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateEventListenerHtml(view View, tag PropertyName) {
|
||||||
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
|
value := view.getRaw(tag)
|
||||||
|
session := view.Session()
|
||||||
|
htmlID := view.htmlID()
|
||||||
|
if value == nil {
|
||||||
|
session.removeProperty(view.htmlID(), js.jsEvent)
|
||||||
|
} else {
|
||||||
|
session.updateProperty(htmlID, js.jsEvent, js.jsFunc+"(this, event)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
112
filePicker.go
112
filePicker.go
|
@ -25,7 +25,7 @@ const (
|
||||||
// `func(picker rui.FilePicker)`,
|
// `func(picker rui.FilePicker)`,
|
||||||
// `func(files []rui.FileInfo)`,
|
// `func(files []rui.FileInfo)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
FileSelectedEvent = "file-selected-event"
|
FileSelectedEvent PropertyName = "file-selected-event"
|
||||||
|
|
||||||
// Accept is the constant for "accept" property tag.
|
// Accept is the constant for "accept" property tag.
|
||||||
//
|
//
|
||||||
|
@ -39,7 +39,7 @@ const (
|
||||||
// Conversion rules:
|
// Conversion rules:
|
||||||
// `string` - may contain single value of multiple separated by comma(`,`).
|
// `string` - may contain single value of multiple separated by comma(`,`).
|
||||||
// `[]string` - an array of acceptable file extensions or MIME types.
|
// `[]string` - an array of acceptable file extensions or MIME types.
|
||||||
Accept = "accept"
|
Accept PropertyName = "accept"
|
||||||
|
|
||||||
// Multiple is the constant for "multiple" property tag.
|
// Multiple is the constant for "multiple" property tag.
|
||||||
//
|
//
|
||||||
|
@ -51,7 +51,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Several files can be selected.
|
// `true` or `1` or "true", "yes", "on", "1" - Several files can be selected.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - Only one file can be selected.
|
// `false` or `0` or "false", "no", "off", "0" - Only one file can be selected.
|
||||||
Multiple = "multiple"
|
Multiple PropertyName = "multiple"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileInfo describes a file which selected in the FilePicker view
|
// FileInfo describes a file which selected in the FilePicker view
|
||||||
|
@ -83,7 +83,6 @@ type FilePicker interface {
|
||||||
type filePickerData struct {
|
type filePickerData struct {
|
||||||
viewData
|
viewData
|
||||||
files []FileInfo
|
files []FileInfo
|
||||||
fileSelectedListeners []func(FilePicker, []FileInfo)
|
|
||||||
loader map[int]func(FileInfo, []byte)
|
loader map[int]func(FileInfo, []byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +114,7 @@ func NewFilePicker(session Session, params Params) FilePicker {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFilePicker(session Session) View {
|
func newFilePicker(session Session) View {
|
||||||
return NewFilePicker(session, nil)
|
return new(filePickerData) // NewFilePicker(session, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *filePickerData) init(session Session) {
|
func (picker *filePickerData) init(session Session) {
|
||||||
|
@ -124,11 +123,9 @@ func (picker *filePickerData) init(session Session) {
|
||||||
picker.hasHtmlDisabled = true
|
picker.hasHtmlDisabled = true
|
||||||
picker.files = []FileInfo{}
|
picker.files = []FileInfo{}
|
||||||
picker.loader = map[int]func(FileInfo, []byte){}
|
picker.loader = map[int]func(FileInfo, []byte){}
|
||||||
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){}
|
picker.set = filePickerSet
|
||||||
}
|
picker.changed = filePickerPropertyChanged
|
||||||
|
|
||||||
func (picker *filePickerData) String() string {
|
|
||||||
return getViewString(picker, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *filePickerData) Focusable() bool {
|
func (picker *filePickerData) Focusable() bool {
|
||||||
|
@ -153,62 +150,27 @@ func (picker *filePickerData) LoadFile(file FileInfo, result func(FileInfo, []by
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *filePickerData) Remove(tag string) {
|
func filePickerSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
picker.remove(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *filePickerData) remove(tag string) {
|
setAccept := func(value string) []PropertyName {
|
||||||
switch tag {
|
if value != "" {
|
||||||
case FileSelectedEvent:
|
view.setRaw(tag, value)
|
||||||
if len(picker.fileSelectedListeners) > 0 {
|
} else if view.getRaw(tag) != nil {
|
||||||
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){}
|
view.setRaw(tag, nil)
|
||||||
picker.propertyChangedEvent(tag)
|
} else {
|
||||||
|
return []PropertyName{}
|
||||||
}
|
}
|
||||||
|
return []PropertyName{Accept}
|
||||||
case Accept:
|
|
||||||
delete(picker.properties, tag)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.removeProperty(picker.htmlID(), "accept")
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
|
|
||||||
default:
|
|
||||||
picker.viewData.remove(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *filePickerData) Set(tag string, value any) bool {
|
|
||||||
return picker.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *filePickerData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
picker.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case FileSelectedEvent:
|
case FileSelectedEvent:
|
||||||
listeners, ok := valueToEventListeners[FilePicker, []FileInfo](value)
|
return setViewEventListener[FilePicker, []FileInfo](view, tag, value)
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
} else if listeners == nil {
|
|
||||||
listeners = []func(FilePicker, []FileInfo){}
|
|
||||||
}
|
|
||||||
picker.fileSelectedListeners = listeners
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case Accept:
|
case Accept:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
value = strings.Trim(value, " \t\n")
|
return setAccept(strings.Trim(value, " \t\n"))
|
||||||
if value == "" {
|
|
||||||
picker.remove(Accept)
|
|
||||||
} else {
|
|
||||||
picker.properties[Accept] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
case []string:
|
case []string:
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
|
@ -222,29 +184,27 @@ func (picker *filePickerData) set(tag string, value any) bool {
|
||||||
buffer.WriteString(val)
|
buffer.WriteString(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if buffer.Len() == 0 {
|
return setAccept(buffer.String())
|
||||||
picker.remove(Accept)
|
|
||||||
} else {
|
|
||||||
picker.properties[Accept] = buffer.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if picker.created {
|
return viewSet(view, tag, value)
|
||||||
if css := picker.acceptCSS(); css != "" {
|
}
|
||||||
picker.session.updateProperty(picker.htmlID(), "accept", css)
|
|
||||||
|
func filePickerPropertyChanged(view View, tag PropertyName) {
|
||||||
|
switch tag {
|
||||||
|
case Accept:
|
||||||
|
session := view.Session()
|
||||||
|
if css := acceptPropertyCSS(view); css != "" {
|
||||||
|
session.updateProperty(view.htmlID(), "accept", css)
|
||||||
} else {
|
} else {
|
||||||
picker.session.removeProperty(picker.htmlID(), "accept")
|
session.removeProperty(view.htmlID(), "accept")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return picker.viewData.set(tag, value)
|
viewPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,10 +212,10 @@ func (picker *filePickerData) htmlTag() string {
|
||||||
return "input"
|
return "input"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *filePickerData) acceptCSS() string {
|
func acceptPropertyCSS(view View) string {
|
||||||
accept, ok := stringProperty(picker, Accept, picker.Session())
|
accept, ok := stringProperty(view, Accept, view.Session())
|
||||||
if !ok {
|
if !ok {
|
||||||
if value := valueFromStyle(picker, Accept); value != nil {
|
if value := valueFromStyle(view, Accept); value != nil {
|
||||||
accept, ok = value.(string)
|
accept, ok = value.(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,7 +242,7 @@ func (picker *filePickerData) acceptCSS() string {
|
||||||
func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder) {
|
func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
picker.viewData.htmlProperties(self, buffer)
|
picker.viewData.htmlProperties(self, buffer)
|
||||||
|
|
||||||
if accept := picker.acceptCSS(); accept != "" {
|
if accept := acceptPropertyCSS(picker); accept != "" {
|
||||||
buffer.WriteString(` accept="`)
|
buffer.WriteString(` accept="`)
|
||||||
buffer.WriteString(accept)
|
buffer.WriteString(accept)
|
||||||
buffer.WriteRune('"')
|
buffer.WriteRune('"')
|
||||||
|
@ -299,7 +259,7 @@ func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *filePickerData) handleCommand(self View, command string, data DataObject) bool {
|
func (picker *filePickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "fileSelected":
|
case "fileSelected":
|
||||||
if node := data.PropertyByTag("files"); node != nil && node.Type() == ArrayNode {
|
if node := data.PropertyByTag("files"); node != nil && node.Type() == ArrayNode {
|
||||||
|
@ -312,7 +272,7 @@ func (picker *filePickerData) handleCommand(self View, command string, data Data
|
||||||
}
|
}
|
||||||
picker.files = files
|
picker.files = files
|
||||||
|
|
||||||
for _, listener := range picker.fileSelectedListeners {
|
for _, listener := range GetFileSelectedListeners(picker) {
|
||||||
listener(picker, files)
|
listener(picker, files)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
132
focusEvents.go
132
focusEvents.go
|
@ -17,7 +17,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
FocusEvent = "focus-event"
|
FocusEvent PropertyName = "focus-event"
|
||||||
|
|
||||||
// LostFocusEvent is the constant for "lost-focus-event" property tag.
|
// LostFocusEvent is the constant for "lost-focus-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -32,132 +32,13 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
LostFocusEvent = "lost-focus-event"
|
LostFocusEvent PropertyName = "lost-focus-event"
|
||||||
)
|
)
|
||||||
|
|
||||||
func valueToNoParamListeners[V any](value any) ([]func(V), bool) {
|
|
||||||
if value == nil {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case func(V):
|
|
||||||
return []func(V){value}, true
|
|
||||||
|
|
||||||
case func():
|
|
||||||
fn := func(V) {
|
|
||||||
value()
|
|
||||||
}
|
|
||||||
return []func(V){fn}, true
|
|
||||||
|
|
||||||
case []func(V):
|
|
||||||
if len(value) == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
for _, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case []func():
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(V) {
|
|
||||||
v()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
switch v := v.(type) {
|
|
||||||
case func(V):
|
|
||||||
listeners[i] = v
|
|
||||||
|
|
||||||
case func():
|
|
||||||
listeners[i] = func(V) {
|
|
||||||
v()
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
var focusEvents = map[string]struct{ jsEvent, jsFunc string }{
|
|
||||||
FocusEvent: {jsEvent: "onfocus", jsFunc: "focusEvent"},
|
|
||||||
LostFocusEvent: {jsEvent: "onblur", jsFunc: "blurEvent"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) setFocusListener(tag string, value any) bool {
|
|
||||||
listeners, ok := valueToNoParamListeners[View](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if listeners == nil {
|
|
||||||
view.removeFocusListener(tag)
|
|
||||||
} else if js, ok := focusEvents[tag]; ok {
|
|
||||||
view.properties[tag] = listeners
|
|
||||||
if view.created {
|
|
||||||
view.session.updateProperty(view.htmlID(), js.jsEvent, js.jsFunc+"(this, event)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) removeFocusListener(tag string) {
|
|
||||||
delete(view.properties, tag)
|
|
||||||
if view.created {
|
|
||||||
if js, ok := focusEvents[tag]; ok {
|
|
||||||
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFocusListeners(view View, subviewID []string, tag string) []func(View) {
|
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
|
||||||
view = ViewByID(view, subviewID[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
if view != nil {
|
|
||||||
if value := view.Get(tag); value != nil {
|
|
||||||
if result, ok := value.([]func(View)); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []func(View){}
|
|
||||||
}
|
|
||||||
|
|
||||||
func focusEventsHtml(view View, buffer *strings.Builder) {
|
func focusEventsHtml(view View, buffer *strings.Builder) {
|
||||||
if view.Focusable() {
|
if view.Focusable() {
|
||||||
for _, js := range focusEvents {
|
for _, tag := range []PropertyName{FocusEvent, LostFocusEvent} {
|
||||||
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
buffer.WriteString(js.jsEvent)
|
buffer.WriteString(js.jsEvent)
|
||||||
buffer.WriteString(`="`)
|
buffer.WriteString(`="`)
|
||||||
buffer.WriteString(js.jsFunc)
|
buffer.WriteString(js.jsFunc)
|
||||||
|
@ -165,15 +46,16 @@ func focusEventsHtml(view View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetFocusListeners returns a FocusListener list. If there are no listeners then the empty list is returned
|
// GetFocusListeners returns a FocusListener list. If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||||
func GetFocusListeners(view View, subviewID ...string) []func(View) {
|
func GetFocusListeners(view View, subviewID ...string) []func(View) {
|
||||||
return getFocusListeners(view, subviewID, FocusEvent)
|
return getNoParamEventListeners[View](view, subviewID, FocusEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLostFocusListeners returns a LostFocusListener list. If there are no listeners then the empty list is returned
|
// GetLostFocusListeners returns a LostFocusListener list. If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||||
func GetLostFocusListeners(view View, subviewID ...string) []func(View) {
|
func GetLostFocusListeners(view View, subviewID ...string) []func(View) {
|
||||||
return getFocusListeners(view, subviewID, LostFocusEvent)
|
return getNoParamEventListeners[View](view, subviewID, LostFocusEvent)
|
||||||
}
|
}
|
||||||
|
|
195
gridLayout.go
195
gridLayout.go
|
@ -24,7 +24,7 @@ const (
|
||||||
//
|
//
|
||||||
// Usage in `SvgImageView`:
|
// Usage in `SvgImageView`:
|
||||||
// Same as "vertical-align".
|
// Same as "vertical-align".
|
||||||
CellVerticalAlign = "cell-vertical-align"
|
CellVerticalAlign PropertyName = "cell-vertical-align"
|
||||||
|
|
||||||
// CellHorizontalAlign is the constant for "cell-horizontal-align" property tag.
|
// CellHorizontalAlign is the constant for "cell-horizontal-align" property tag.
|
||||||
//
|
//
|
||||||
|
@ -43,7 +43,7 @@ const (
|
||||||
//
|
//
|
||||||
// Usage in `SvgImageView`:
|
// Usage in `SvgImageView`:
|
||||||
// Same as "horizontal-align".
|
// Same as "horizontal-align".
|
||||||
CellHorizontalAlign = "cell-horizontal-align"
|
CellHorizontalAlign PropertyName = "cell-horizontal-align"
|
||||||
|
|
||||||
// CellVerticalSelfAlign is the constant for "cell-vertical-self-align" property tag.
|
// CellVerticalSelfAlign is the constant for "cell-vertical-self-align" property tag.
|
||||||
//
|
//
|
||||||
|
@ -58,7 +58,7 @@ const (
|
||||||
// `1`(`BottomAlign`) or "bottom" - Bottom alignment.
|
// `1`(`BottomAlign`) or "bottom" - Bottom alignment.
|
||||||
// `2`(`CenterAlign`) or "center" - Center alignment.
|
// `2`(`CenterAlign`) or "center" - Center alignment.
|
||||||
// `3`(`StretchAlign`) or "stretch" - Full height stretch.
|
// `3`(`StretchAlign`) or "stretch" - Full height stretch.
|
||||||
CellVerticalSelfAlign = "cell-vertical-self-align"
|
CellVerticalSelfAlign PropertyName = "cell-vertical-self-align"
|
||||||
|
|
||||||
// CellHorizontalSelfAlign is the constant for "cell-horizontal-self-align" property tag.
|
// CellHorizontalSelfAlign is the constant for "cell-horizontal-self-align" property tag.
|
||||||
//
|
//
|
||||||
|
@ -73,7 +73,7 @@ const (
|
||||||
// `1`(`RightAlign`) or "right" - Right alignment.
|
// `1`(`RightAlign`) or "right" - Right alignment.
|
||||||
// `2`(`CenterAlign`) or "center" - Center alignment.
|
// `2`(`CenterAlign`) or "center" - Center alignment.
|
||||||
// `3`(`StretchAlign`) or "stretch" - Full width stretch.
|
// `3`(`StretchAlign`) or "stretch" - Full width stretch.
|
||||||
CellHorizontalSelfAlign = "cell-horizontal-self-align"
|
CellHorizontalSelfAlign PropertyName = "cell-horizontal-self-align"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GridAdapter is an interface to define [GridLayout] content. [GridLayout] will query interface functions to populate
|
// GridAdapter is an interface to define [GridLayout] content. [GridLayout] will query interface functions to populate
|
||||||
|
@ -126,7 +126,8 @@ func NewGridLayout(session Session, params Params) GridLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGridLayout(session Session) View {
|
func newGridLayout(session Session) View {
|
||||||
return NewGridLayout(session, nil)
|
//return NewGridLayout(session, nil)
|
||||||
|
return new(gridLayoutData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of GridLayout by default values
|
// Init initialize fields of GridLayout by default values
|
||||||
|
@ -135,13 +136,14 @@ func (gridLayout *gridLayoutData) init(session Session) {
|
||||||
gridLayout.tag = "GridLayout"
|
gridLayout.tag = "GridLayout"
|
||||||
gridLayout.systemClass = "ruiGridLayout"
|
gridLayout.systemClass = "ruiGridLayout"
|
||||||
gridLayout.adapter = nil
|
gridLayout.adapter = nil
|
||||||
|
gridLayout.normalize = normalizeGridLayoutTag
|
||||||
|
gridLayout.getFunc = gridLayout.get
|
||||||
|
gridLayout.set = gridLayout.setFunc
|
||||||
|
gridLayout.remove = gridLayout.removeFunc
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gridLayout *gridLayoutData) String() string {
|
func setGridCellSize(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
return getViewString(gridLayout, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (style *viewStyle) setGridCellSize(tag string, value any) bool {
|
|
||||||
setValues := func(values []string) bool {
|
setValues := func(values []string) bool {
|
||||||
count := len(values)
|
count := len(values)
|
||||||
if count > 1 {
|
if count > 1 {
|
||||||
|
@ -159,11 +161,11 @@ func (style *viewStyle) setGridCellSize(tag string, value any) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
style.properties[tag] = sizes
|
properties.setRaw(tag, sizes)
|
||||||
} else if isConstantName(values[0]) {
|
} else if isConstantName(values[0]) {
|
||||||
style.properties[tag] = values[0]
|
properties.setRaw(tag, values[0])
|
||||||
} else if size, err := stringToSizeUnit(values[0]); err == nil {
|
} else if size, err := stringToSizeUnit(values[0]); err == nil {
|
||||||
style.properties[tag] = size
|
properties.setRaw(tag, size)
|
||||||
} else {
|
} else {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return false
|
||||||
|
@ -175,41 +177,41 @@ func (style *viewStyle) setGridCellSize(tag string, value any) bool {
|
||||||
case CellWidth, CellHeight:
|
case CellWidth, CellHeight:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case SizeUnit, []SizeUnit:
|
case SizeUnit, []SizeUnit:
|
||||||
style.properties[tag] = value
|
properties.setRaw(tag, value)
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if !setValues(strings.Split(value, ",")) {
|
if !setValues(strings.Split(value, ",")) {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case []string:
|
case []string:
|
||||||
if !setValues(value) {
|
if !setValues(value) {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case []DataValue:
|
case []DataValue:
|
||||||
count := len(value)
|
count := len(value)
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
values := make([]string, count)
|
values := make([]string, count)
|
||||||
for i, val := range value {
|
for i, val := range value {
|
||||||
if val.IsObject() {
|
if val.IsObject() {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
values[i] = val.Value()
|
values[i] = val.Value()
|
||||||
}
|
}
|
||||||
if !setValues(values) {
|
if !setValues(values) {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case []any:
|
case []any:
|
||||||
count := len(value)
|
count := len(value)
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
sizes := make([]any, count)
|
sizes := make([]any, count)
|
||||||
for i, val := range value {
|
for i, val := range value {
|
||||||
|
@ -224,29 +226,29 @@ func (style *viewStyle) setGridCellSize(tag string, value any) bool {
|
||||||
sizes[i] = size
|
sizes[i] = size
|
||||||
} else {
|
} else {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
style.properties[tag] = sizes
|
properties.setRaw(tag, sizes)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) gridCellSizesCSS(tag string, session Session) string {
|
func gridCellSizesCSS(properties Properties, tag PropertyName, session Session) string {
|
||||||
switch cellSize := gridCellSizes(style, tag, session); len(cellSize) {
|
switch cellSize := gridCellSizes(properties, tag, session); len(cellSize) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -283,8 +285,8 @@ func (style *viewStyle) gridCellSizesCSS(tag string, session Session) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gridLayout *gridLayoutData) normalizeTag(tag string) string {
|
func normalizeGridLayoutTag(tag PropertyName) PropertyName {
|
||||||
tag = strings.ToLower(tag)
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case VerticalAlign:
|
case VerticalAlign:
|
||||||
return CellVerticalAlign
|
return CellVerticalAlign
|
||||||
|
@ -301,99 +303,97 @@ func (gridLayout *gridLayoutData) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gridLayout *gridLayoutData) Get(tag string) any {
|
func (gridLayout *gridLayoutData) get(self View, tag PropertyName) any {
|
||||||
return gridLayout.get(gridLayout.normalizeTag(tag))
|
switch tag {
|
||||||
}
|
case Gap:
|
||||||
|
|
||||||
func (gridLayout *gridLayoutData) get(tag string) any {
|
|
||||||
if tag == Gap {
|
|
||||||
rowGap := GetGridRowGap(gridLayout)
|
rowGap := GetGridRowGap(gridLayout)
|
||||||
columnGap := GetGridColumnGap(gridLayout)
|
columnGap := GetGridColumnGap(gridLayout)
|
||||||
if rowGap.Equal(columnGap) {
|
if rowGap.Equal(columnGap) {
|
||||||
return rowGap
|
return rowGap
|
||||||
}
|
}
|
||||||
return AutoSize()
|
return AutoSize()
|
||||||
}
|
|
||||||
|
|
||||||
return gridLayout.viewsContainerData.get(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gridLayout *gridLayoutData) Remove(tag string) {
|
|
||||||
gridLayout.remove(gridLayout.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gridLayout *gridLayoutData) remove(tag string) {
|
|
||||||
switch tag {
|
|
||||||
case Gap:
|
|
||||||
gridLayout.remove(GridRowGap)
|
|
||||||
gridLayout.remove(GridColumnGap)
|
|
||||||
gridLayout.propertyChangedEvent(Gap)
|
|
||||||
return
|
|
||||||
|
|
||||||
case Content:
|
case Content:
|
||||||
gridLayout.adapter = nil
|
if gridLayout.adapter != nil {
|
||||||
}
|
return gridLayout.adapter
|
||||||
|
|
||||||
gridLayout.viewsContainerData.remove(tag)
|
|
||||||
|
|
||||||
if gridLayout.created {
|
|
||||||
switch tag {
|
|
||||||
case CellWidth:
|
|
||||||
gridLayout.session.updateCSSProperty(gridLayout.htmlID(), `grid-template-columns`,
|
|
||||||
gridLayout.gridCellSizesCSS(CellWidth, gridLayout.session))
|
|
||||||
|
|
||||||
case CellHeight:
|
|
||||||
gridLayout.session.updateCSSProperty(gridLayout.htmlID(), `grid-template-rows`,
|
|
||||||
gridLayout.gridCellSizesCSS(CellHeight, gridLayout.session))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return gridLayout.viewsContainerData.get(gridLayout, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gridLayout *gridLayoutData) Set(tag string, value any) bool {
|
func (gridLayout *gridLayoutData) removeFunc(self View, tag PropertyName) []PropertyName {
|
||||||
return gridLayout.set(gridLayout.normalizeTag(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gridLayout *gridLayoutData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
gridLayout.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Gap:
|
case Gap:
|
||||||
return gridLayout.set(GridRowGap, value) && gridLayout.set(GridColumnGap, value)
|
result := []PropertyName{}
|
||||||
|
for _, tag := range []PropertyName{GridRowGap, GridColumnGap} {
|
||||||
|
if gridLayout.getRaw(tag) != nil {
|
||||||
|
gridLayout.setRaw(tag, nil)
|
||||||
|
result = append(result, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
case Content:
|
||||||
|
if len(gridLayout.views) > 0 || gridLayout.adapter != nil {
|
||||||
|
gridLayout.views = []View{}
|
||||||
|
gridLayout.adapter = nil
|
||||||
|
return []PropertyName{Content}
|
||||||
|
}
|
||||||
|
return []PropertyName{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gridLayout.viewsContainerData.removeFunc(gridLayout, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gridLayout *gridLayoutData) setFunc(self View, tag PropertyName, value any) []PropertyName {
|
||||||
|
switch tag {
|
||||||
|
case Gap:
|
||||||
|
result := gridLayout.setFunc(gridLayout, GridRowGap, value)
|
||||||
|
if result != nil {
|
||||||
|
if gap := gridLayout.getRaw(GridRowGap); gap != nil {
|
||||||
|
gridLayout.setRaw(GridColumnGap, gap)
|
||||||
|
result = append(result, GridColumnGap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
case Content:
|
case Content:
|
||||||
if adapter, ok := value.(GridAdapter); ok {
|
if adapter, ok := value.(GridAdapter); ok {
|
||||||
gridLayout.adapter = adapter
|
gridLayout.adapter = adapter
|
||||||
gridLayout.UpdateGridContent()
|
gridLayout.createGridContent()
|
||||||
return true
|
} else if gridLayout.setContent(value) {
|
||||||
}
|
|
||||||
gridLayout.adapter = nil
|
gridLayout.adapter = nil
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []PropertyName{Content}
|
||||||
}
|
}
|
||||||
|
|
||||||
if gridLayout.viewsContainerData.set(tag, value) {
|
return gridLayout.viewsContainerData.setFunc(gridLayout, tag, value)
|
||||||
if gridLayout.created {
|
}
|
||||||
|
|
||||||
|
func gridLayoutPropertyChanged(view View, tag PropertyName) {
|
||||||
switch tag {
|
switch tag {
|
||||||
case CellWidth:
|
case CellWidth:
|
||||||
gridLayout.session.updateCSSProperty(gridLayout.htmlID(), `grid-template-columns`,
|
view.Session().updateCSSProperty(view.htmlID(), `grid-template-columns`,
|
||||||
gridLayout.gridCellSizesCSS(CellWidth, gridLayout.session))
|
gridCellSizesCSS(view, CellWidth, view.Session()))
|
||||||
|
|
||||||
case CellHeight:
|
case CellHeight:
|
||||||
gridLayout.session.updateCSSProperty(gridLayout.htmlID(), `grid-template-rows`,
|
view.Session().updateCSSProperty(view.htmlID(), `grid-template-rows`,
|
||||||
gridLayout.gridCellSizesCSS(CellHeight, gridLayout.session))
|
gridCellSizesCSS(view, CellHeight, view.Session()))
|
||||||
|
|
||||||
|
default:
|
||||||
|
viewsContainerPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func (gridLayout *gridLayoutData) createGridContent() bool {
|
||||||
|
if gridLayout.adapter == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gridLayout *gridLayoutData) UpdateGridContent() {
|
adapter := gridLayout.adapter
|
||||||
if adapter := gridLayout.adapter; adapter != nil {
|
|
||||||
gridLayout.views = []View{}
|
gridLayout.views = []View{}
|
||||||
|
|
||||||
session := gridLayout.session
|
session := gridLayout.session
|
||||||
|
@ -448,15 +448,22 @@ func (gridLayout *gridLayoutData) UpdateGridContent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gridLayout *gridLayoutData) UpdateGridContent() {
|
||||||
|
if gridLayout.createGridContent() {
|
||||||
if gridLayout.created {
|
if gridLayout.created {
|
||||||
updateInnerHTML(htmlID, session)
|
updateInnerHTML(gridLayout.htmlID(), gridLayout.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
gridLayout.propertyChangedEvent(Content)
|
if listener, ok := gridLayout.changeListener[Content]; ok {
|
||||||
|
listener(gridLayout, Content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gridCellSizes(properties Properties, tag string, session Session) []SizeUnit {
|
func gridCellSizes(properties Properties, tag PropertyName, session Session) []SizeUnit {
|
||||||
if value := properties.Get(tag); value != nil {
|
if value := properties.Get(tag); value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case []SizeUnit:
|
case []SizeUnit:
|
||||||
|
|
176
imageView.go
176
imageView.go
|
@ -20,7 +20,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
LoadedEvent = "loaded-event"
|
LoadedEvent PropertyName = "loaded-event"
|
||||||
|
|
||||||
// ErrorEvent is the constant for "error-event" property tag.
|
// ErrorEvent is the constant for "error-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -35,7 +35,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
ErrorEvent = "error-event"
|
ErrorEvent PropertyName = "error-event"
|
||||||
|
|
||||||
// NoneFit - value of the "object-fit" property of an ImageView. The replaced content is not resized
|
// NoneFit - value of the "object-fit" property of an ImageView. The replaced content is not resized
|
||||||
NoneFit = 0
|
NoneFit = 0
|
||||||
|
@ -88,7 +88,7 @@ func NewImageView(session Session, params Params) ImageView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newImageView(session Session) View {
|
func newImageView(session Session) View {
|
||||||
return NewImageView(session, nil)
|
return new(imageViewData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of imageView by default values
|
// Init initialize fields of imageView by default values
|
||||||
|
@ -96,14 +96,13 @@ func (imageView *imageViewData) init(session Session) {
|
||||||
imageView.viewData.init(session)
|
imageView.viewData.init(session)
|
||||||
imageView.tag = "ImageView"
|
imageView.tag = "ImageView"
|
||||||
imageView.systemClass = "ruiImageView"
|
imageView.systemClass = "ruiImageView"
|
||||||
|
imageView.normalize = normalizeImageViewTag
|
||||||
|
imageView.set = imageViewSet
|
||||||
|
imageView.changed = imageViewPropertyChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imageView *imageViewData) String() string {
|
func normalizeImageViewTag(tag PropertyName) PropertyName {
|
||||||
return getViewString(imageView, nil)
|
tag = defaultNormalize(tag)
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *imageViewData) normalizeTag(tag string) string {
|
|
||||||
tag = strings.ToLower(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case "source":
|
case "source":
|
||||||
tag = Source
|
tag = Source
|
||||||
|
@ -123,127 +122,58 @@ func (imageView *imageViewData) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imageView *imageViewData) Remove(tag string) {
|
func imageViewSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
imageView.remove(imageView.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *imageViewData) remove(tag string) {
|
|
||||||
imageView.viewData.remove(tag)
|
|
||||||
if imageView.created {
|
|
||||||
switch tag {
|
|
||||||
case Source:
|
|
||||||
imageView.session.updateProperty(imageView.htmlID(), "src", "")
|
|
||||||
imageView.session.removeProperty(imageView.htmlID(), "srcset")
|
|
||||||
|
|
||||||
case AltText:
|
|
||||||
updateInnerHTML(imageView.htmlID(), imageView.session)
|
|
||||||
|
|
||||||
case ImageVerticalAlign, ImageHorizontalAlign:
|
|
||||||
updateCSSStyle(imageView.htmlID(), imageView.session)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *imageViewData) Set(tag string, value any) bool {
|
|
||||||
return imageView.set(imageView.normalizeTag(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *imageViewData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
imageView.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Source:
|
case Source, SrcSet, AltText:
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
imageView.properties[tag] = text
|
return setStringPropertyValue(view, tag, text)
|
||||||
if imageView.created {
|
|
||||||
src, srcset := imageView.src(text)
|
|
||||||
imageView.session.updateProperty(imageView.htmlID(), "src", src)
|
|
||||||
|
|
||||||
if srcset != "" {
|
|
||||||
imageView.session.updateProperty(imageView.htmlID(), "srcset", srcset)
|
|
||||||
} else {
|
|
||||||
imageView.session.removeProperty(imageView.htmlID(), "srcset")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imageView.propertyChangedEvent(Source)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
notCompatibleType(Source, value)
|
|
||||||
|
|
||||||
case SrcSet:
|
|
||||||
if text, ok := value.(string); ok {
|
|
||||||
if text == "" {
|
|
||||||
delete(imageView.properties, tag)
|
|
||||||
} else {
|
|
||||||
imageView.properties[tag] = text
|
|
||||||
}
|
|
||||||
if imageView.created {
|
|
||||||
_, srcset := imageView.src(text)
|
|
||||||
if srcset != "" {
|
|
||||||
imageView.session.updateProperty(imageView.htmlID(), "srcset", srcset)
|
|
||||||
} else {
|
|
||||||
imageView.session.removeProperty(imageView.htmlID(), "srcset")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imageView.propertyChangedEvent(Source)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
notCompatibleType(Source, value)
|
|
||||||
|
|
||||||
case AltText:
|
|
||||||
if text, ok := value.(string); ok {
|
|
||||||
imageView.properties[AltText] = text
|
|
||||||
if imageView.created {
|
|
||||||
updateInnerHTML(imageView.htmlID(), imageView.session)
|
|
||||||
}
|
|
||||||
imageView.propertyChangedEvent(Source)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
|
||||||
case LoadedEvent, ErrorEvent:
|
case LoadedEvent, ErrorEvent:
|
||||||
if listeners, ok := valueToNoParamListeners[ImageView](value); ok {
|
return setNoParamEventListener[ImageView](view, tag, value)
|
||||||
if listeners == nil {
|
}
|
||||||
delete(imageView.properties, tag)
|
|
||||||
|
return viewSet(view, tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageViewPropertyChanged(view View, tag PropertyName) {
|
||||||
|
session := view.Session()
|
||||||
|
htmlID := view.htmlID()
|
||||||
|
|
||||||
|
switch tag {
|
||||||
|
case Source:
|
||||||
|
src, srcset := imageViewSrc(view, GetImageViewSource(view))
|
||||||
|
session.updateProperty(htmlID, "src", src)
|
||||||
|
if srcset != "" {
|
||||||
|
session.updateProperty(htmlID, "srcset", srcset)
|
||||||
} else {
|
} else {
|
||||||
imageView.properties[tag] = listeners
|
session.removeProperty(htmlID, "srcset")
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
|
case SrcSet:
|
||||||
|
_, srcset := imageViewSrc(view, GetImageViewSource(view))
|
||||||
|
if srcset != "" {
|
||||||
|
session.updateProperty(htmlID, "srcset", srcset)
|
||||||
|
} else {
|
||||||
|
session.removeProperty(htmlID, "srcset")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AltText:
|
||||||
|
updateInnerHTML(htmlID, session)
|
||||||
|
|
||||||
|
case ImageVerticalAlign, ImageHorizontalAlign:
|
||||||
|
updateCSSStyle(htmlID, session)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if imageView.viewData.set(tag, value) {
|
viewPropertyChanged(view, tag)
|
||||||
if imageView.created {
|
|
||||||
switch tag {
|
|
||||||
case ImageVerticalAlign, ImageHorizontalAlign:
|
|
||||||
updateCSSStyle(imageView.htmlID(), imageView.session)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
func imageViewSrcSet(view View, path string) string {
|
||||||
}
|
if value := view.getRaw(SrcSet); value != nil {
|
||||||
|
|
||||||
func (imageView *imageViewData) Get(tag string) any {
|
|
||||||
return imageView.viewData.get(imageView.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *imageViewData) imageListeners(tag string) []func(ImageView) {
|
|
||||||
if value := imageView.getRaw(tag); value != nil {
|
|
||||||
if listeners, ok := value.([]func(ImageView)); ok {
|
|
||||||
return listeners
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []func(ImageView){}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *imageViewData) srcSet(path string) string {
|
|
||||||
if value := imageView.getRaw(SrcSet); value != nil {
|
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
srcset := strings.Split(text, ",")
|
srcset := strings.Split(text, ",")
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
|
@ -286,9 +216,9 @@ func (imageView *imageViewData) htmlTag() string {
|
||||||
return "img"
|
return "img"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imageView *imageViewData) src(src string) (string, string) {
|
func imageViewSrc(view View, src string) (string, string) {
|
||||||
if src != "" && src[0] == '@' {
|
if src != "" && src[0] == '@' {
|
||||||
if image, ok := imageView.Session().ImageConstant(src[1:]); ok {
|
if image, ok := view.Session().ImageConstant(src[1:]); ok {
|
||||||
src = image
|
src = image
|
||||||
} else {
|
} else {
|
||||||
src = ""
|
src = ""
|
||||||
|
@ -296,7 +226,7 @@ func (imageView *imageViewData) src(src string) (string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if src != "" {
|
if src != "" {
|
||||||
return src, imageView.srcSet(src)
|
return src, imageViewSrcSet(view, src)
|
||||||
}
|
}
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
@ -306,7 +236,7 @@ func (imageView *imageViewData) htmlProperties(self View, buffer *strings.Builde
|
||||||
imageView.viewData.htmlProperties(self, buffer)
|
imageView.viewData.htmlProperties(self, buffer)
|
||||||
|
|
||||||
if imageResource, ok := imageProperty(imageView, Source, imageView.Session()); ok && imageResource != "" {
|
if imageResource, ok := imageProperty(imageView, Source, imageView.Session()); ok && imageResource != "" {
|
||||||
if src, srcset := imageView.src(imageResource); src != "" {
|
if src, srcset := imageViewSrc(imageView, imageResource); src != "" {
|
||||||
buffer.WriteString(` src="`)
|
buffer.WriteString(` src="`)
|
||||||
buffer.WriteString(src)
|
buffer.WriteString(src)
|
||||||
buffer.WriteString(`"`)
|
buffer.WriteString(`"`)
|
||||||
|
@ -326,7 +256,7 @@ func (imageView *imageViewData) htmlProperties(self View, buffer *strings.Builde
|
||||||
|
|
||||||
buffer.WriteString(` onload="imageLoaded(this, event)"`)
|
buffer.WriteString(` onload="imageLoaded(this, event)"`)
|
||||||
|
|
||||||
if len(imageView.imageListeners(ErrorEvent)) > 0 {
|
if len(getNoParamEventListeners[ImageView](imageView, nil, ErrorEvent)) > 0 {
|
||||||
buffer.WriteString(` onerror="imageError(this, event)"`)
|
buffer.WriteString(` onerror="imageError(this, event)"`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,10 +296,10 @@ func (imageView *imageViewData) cssStyle(self View, builder cssBuilder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imageView *imageViewData) handleCommand(self View, command string, data DataObject) bool {
|
func (imageView *imageViewData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "imageViewError":
|
case "imageViewError":
|
||||||
for _, listener := range imageView.imageListeners(ErrorEvent) {
|
for _, listener := range getNoParamEventListeners[ImageView](imageView, nil, ErrorEvent) {
|
||||||
listener(imageView)
|
listener(imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +308,7 @@ func (imageView *imageViewData) handleCommand(self View, command string, data Da
|
||||||
imageView.naturalHeight = dataFloatProperty(data, "natural-height")
|
imageView.naturalHeight = dataFloatProperty(data, "natural-height")
|
||||||
imageView.currentSrc, _ = data.PropertyValue("current-src")
|
imageView.currentSrc, _ = data.PropertyValue("current-src")
|
||||||
|
|
||||||
for _, listener := range imageView.imageListeners(LoadedEvent) {
|
for _, listener := range getNoParamEventListeners[ImageView](imageView, nil, LoadedEvent) {
|
||||||
listener(imageView)
|
listener(imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
374
keyEvents.go
374
keyEvents.go
|
@ -20,7 +20,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.KeyEvent)`,
|
// `func(event rui.KeyEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
KeyDownEvent = "key-down-event"
|
KeyDownEvent PropertyName = "key-down-event"
|
||||||
|
|
||||||
// KeyUpEvent is the constant for "key-up-event" property tag.
|
// KeyUpEvent is the constant for "key-up-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -38,7 +38,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.KeyEvent)`,
|
// `func(event rui.KeyEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
KeyUpEvent = "key-up-event"
|
KeyUpEvent PropertyName = "key-up-event"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ControlKeyMask represent ORed state of keyboard's control keys like [AltKey], [CtrlKey], [ShiftKey] and [MetaKey]
|
// ControlKeyMask represent ORed state of keyboard's control keys like [AltKey], [CtrlKey], [ShiftKey] and [MetaKey]
|
||||||
|
@ -429,342 +429,21 @@ func (event *KeyEvent) init(data DataObject) {
|
||||||
event.MetaKey = getBool("metaKey")
|
event.MetaKey = getBool("metaKey")
|
||||||
}
|
}
|
||||||
|
|
||||||
func valueToEventListeners[V View, E any](value any) ([]func(V, E), bool) {
|
/*
|
||||||
if value == nil {
|
func setKeyListener(properties Properties, tag PropertyName, value any) bool {
|
||||||
return nil, true
|
if listeners, ok := valueToEventListeners[View, KeyEvent](value); ok {
|
||||||
|
if len(listeners) == 0 {
|
||||||
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
properties.setRaw(tag, listeners)
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
switch value := value.(type) {
|
|
||||||
case func(V, E):
|
|
||||||
return []func(V, E){value}, true
|
|
||||||
|
|
||||||
case func(E):
|
|
||||||
fn := func(_ V, event E) {
|
|
||||||
value(event)
|
|
||||||
}
|
}
|
||||||
return []func(V, E){fn}, true
|
|
||||||
|
|
||||||
case func(V):
|
|
||||||
fn := func(view V, _ E) {
|
|
||||||
value(view)
|
|
||||||
}
|
|
||||||
return []func(V, E){fn}, true
|
|
||||||
|
|
||||||
case func():
|
|
||||||
fn := func(V, E) {
|
|
||||||
value()
|
|
||||||
}
|
|
||||||
return []func(V, E){fn}, true
|
|
||||||
|
|
||||||
case []func(V, E):
|
|
||||||
if len(value) == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
for _, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case []func(E):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ V, event E) {
|
|
||||||
v(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func(V):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(view V, _ E) {
|
|
||||||
v(view)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func():
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(V, E) {
|
|
||||||
v()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
switch v := v.(type) {
|
|
||||||
case func(V, E):
|
|
||||||
listeners[i] = v
|
|
||||||
|
|
||||||
case func(E):
|
|
||||||
listeners[i] = func(_ V, event E) {
|
|
||||||
v(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(V):
|
|
||||||
listeners[i] = func(view V, _ E) {
|
|
||||||
v(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func():
|
|
||||||
listeners[i] = func(V, E) {
|
|
||||||
v()
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func valueToEventWithOldListeners[V View, E any](value any) ([]func(V, E, E), bool) {
|
|
||||||
if value == nil {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case func(V, E, E):
|
|
||||||
return []func(V, E, E){value}, true
|
|
||||||
|
|
||||||
case func(V, E):
|
|
||||||
fn := func(v V, val, _ E) {
|
|
||||||
value(v, val)
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case func(E, E):
|
|
||||||
fn := func(_ V, val, old E) {
|
|
||||||
value(val, old)
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case func(E):
|
|
||||||
fn := func(_ V, val, _ E) {
|
|
||||||
value(val)
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case func(V):
|
|
||||||
fn := func(v V, _, _ E) {
|
|
||||||
value(v)
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case func():
|
|
||||||
fn := func(V, E, E) {
|
|
||||||
value()
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case []func(V, E, E):
|
|
||||||
if len(value) == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
for _, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case []func(V, E):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(view V, val, _ E) {
|
|
||||||
fn(view, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func(E):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ V, val, _ E) {
|
|
||||||
fn(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func(E, E):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ V, val, old E) {
|
|
||||||
fn(val, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func(V):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(view V, _, _ E) {
|
|
||||||
fn(view)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func():
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(V, E, E) {
|
|
||||||
fn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
switch fn := v.(type) {
|
|
||||||
case func(V, E, E):
|
|
||||||
listeners[i] = fn
|
|
||||||
|
|
||||||
case func(V, E):
|
|
||||||
listeners[i] = func(view V, val, _ E) {
|
|
||||||
fn(view, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(E, E):
|
|
||||||
listeners[i] = func(_ V, val, old E) {
|
|
||||||
fn(val, old)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(E):
|
|
||||||
listeners[i] = func(_ V, val, _ E) {
|
|
||||||
fn(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(V):
|
|
||||||
listeners[i] = func(view V, _, _ E) {
|
|
||||||
fn(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func():
|
|
||||||
listeners[i] = func(V, E, E) {
|
|
||||||
fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) setKeyListener(tag string, value any) bool {
|
|
||||||
listeners, ok := valueToEventListeners[View, KeyEvent](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if listeners == nil {
|
func (view *viewData) removeKeyListener(tag PropertyName) {
|
||||||
view.removeKeyListener(tag)
|
|
||||||
} else {
|
|
||||||
switch tag {
|
|
||||||
case KeyDownEvent:
|
|
||||||
view.properties[tag] = listeners
|
|
||||||
if view.created {
|
|
||||||
view.session.updateProperty(view.htmlID(), "onkeydown", "keyDownEvent(this, event)")
|
|
||||||
}
|
|
||||||
|
|
||||||
case KeyUpEvent:
|
|
||||||
view.properties[tag] = listeners
|
|
||||||
if view.created {
|
|
||||||
view.session.updateProperty(view.htmlID(), "onkeyup", "keyUpEvent(this, event)")
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) removeKeyListener(tag string) {
|
|
||||||
delete(view.properties, tag)
|
delete(view.properties, tag)
|
||||||
if view.created {
|
if view.created {
|
||||||
switch tag {
|
switch tag {
|
||||||
|
@ -778,34 +457,7 @@ func (view *viewData) removeKeyListener(tag string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
func getEventWithOldListeners[V View, E any](view View, subviewID []string, tag string) []func(V, E, E) {
|
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
|
||||||
view = ViewByID(view, subviewID[0])
|
|
||||||
}
|
|
||||||
if view != nil {
|
|
||||||
if value := view.Get(tag); value != nil {
|
|
||||||
if result, ok := value.([]func(V, E, E)); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []func(V, E, E){}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEventListeners[V View, E any](view View, subviewID []string, tag string) []func(V, E) {
|
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
|
||||||
view = ViewByID(view, subviewID[0])
|
|
||||||
}
|
|
||||||
if view != nil {
|
|
||||||
if value := view.Get(tag); value != nil {
|
|
||||||
if result, ok := value.([]func(V, E)); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []func(V, E){}
|
|
||||||
}
|
|
||||||
|
|
||||||
func keyEventsHtml(view View, buffer *strings.Builder) {
|
func keyEventsHtml(view View, buffer *strings.Builder) {
|
||||||
if len(getEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 {
|
if len(getEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 {
|
||||||
|
@ -821,7 +473,7 @@ func keyEventsHtml(view View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleKeyEvents(view View, tag string, data DataObject) {
|
func handleKeyEvents(view View, tag PropertyName, data DataObject) {
|
||||||
var event KeyEvent
|
var event KeyEvent
|
||||||
event.init(data)
|
event.init(data)
|
||||||
listeners := getEventListeners[View, KeyEvent](view, nil, tag)
|
listeners := getEventListeners[View, KeyEvent](view, nil, tag)
|
||||||
|
|
141
listLayout.go
141
listLayout.go
|
@ -37,6 +37,7 @@ type ListLayout interface {
|
||||||
// UpdateContent updates child Views if the "content" property value is set to ListAdapter,
|
// UpdateContent updates child Views if the "content" property value is set to ListAdapter,
|
||||||
// otherwise does nothing
|
// otherwise does nothing
|
||||||
UpdateContent()
|
UpdateContent()
|
||||||
|
setAdapter(ListAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
type listLayoutData struct {
|
type listLayoutData struct {
|
||||||
|
@ -53,7 +54,8 @@ func NewListLayout(session Session, params Params) ListLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newListLayout(session Session) View {
|
func newListLayout(session Session) View {
|
||||||
return NewListLayout(session, nil)
|
//return NewListLayout(session, nil)
|
||||||
|
return new(listLayoutData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of ViewsAlignContainer by default values
|
// Init initialize fields of ViewsAlignContainer by default values
|
||||||
|
@ -61,14 +63,16 @@ func (listLayout *listLayoutData) init(session Session) {
|
||||||
listLayout.viewsContainerData.init(session)
|
listLayout.viewsContainerData.init(session)
|
||||||
listLayout.tag = "ListLayout"
|
listLayout.tag = "ListLayout"
|
||||||
listLayout.systemClass = "ruiListLayout"
|
listLayout.systemClass = "ruiListLayout"
|
||||||
|
listLayout.normalize = normalizeListLayoutTag
|
||||||
|
listLayout.getFunc = listLayout.get
|
||||||
|
listLayout.set = listLayout.setFunc
|
||||||
|
listLayout.remove = listLayout.removeFunc
|
||||||
|
listLayout.changed = listLayoutPropertyChanged
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (listLayout *listLayoutData) String() string {
|
func normalizeListLayoutTag(tag PropertyName) PropertyName {
|
||||||
return getViewString(listLayout, nil)
|
tag = defaultNormalize(tag)
|
||||||
}
|
|
||||||
|
|
||||||
func (listLayout *listLayoutData) normalizeTag(tag string) string {
|
|
||||||
tag = strings.ToLower(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case "wrap":
|
case "wrap":
|
||||||
tag = ListWrap
|
tag = ListWrap
|
||||||
|
@ -82,80 +86,79 @@ func (listLayout *listLayoutData) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (listLayout *listLayoutData) Get(tag string) any {
|
func (listLayout *listLayoutData) get(self View, tag PropertyName) any {
|
||||||
return listLayout.get(listLayout.normalizeTag(tag))
|
switch tag {
|
||||||
}
|
case Gap:
|
||||||
|
|
||||||
func (listLayout *listLayoutData) get(tag string) any {
|
|
||||||
if tag == Gap {
|
|
||||||
if rowGap := GetListRowGap(listLayout); rowGap.Equal(GetListColumnGap(listLayout)) {
|
if rowGap := GetListRowGap(listLayout); rowGap.Equal(GetListColumnGap(listLayout)) {
|
||||||
return rowGap
|
return rowGap
|
||||||
}
|
}
|
||||||
return AutoSize()
|
return AutoSize()
|
||||||
}
|
|
||||||
|
|
||||||
return listLayout.viewsContainerData.get(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (listLayout *listLayoutData) Remove(tag string) {
|
|
||||||
listLayout.remove(listLayout.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (listLayout *listLayoutData) remove(tag string) {
|
|
||||||
switch tag {
|
|
||||||
case Gap:
|
|
||||||
listLayout.remove(ListRowGap)
|
|
||||||
listLayout.remove(ListColumnGap)
|
|
||||||
return
|
|
||||||
|
|
||||||
case Content:
|
case Content:
|
||||||
listLayout.adapter = nil
|
if listLayout.adapter != nil {
|
||||||
}
|
return listLayout.adapter
|
||||||
|
|
||||||
listLayout.viewsContainerData.remove(tag)
|
|
||||||
if listLayout.created {
|
|
||||||
switch tag {
|
|
||||||
case Orientation, ListWrap, HorizontalAlign, VerticalAlign:
|
|
||||||
updateCSSStyle(listLayout.htmlID(), listLayout.session)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (listLayout *listLayoutData) Set(tag string, value any) bool {
|
return listLayout.viewsContainerData.get(listLayout, tag)
|
||||||
return listLayout.set(listLayout.normalizeTag(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (listLayout *listLayoutData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
listLayout.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (listLayout *listLayoutData) removeFunc(self View, tag PropertyName) []PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case Gap:
|
case Gap:
|
||||||
return listLayout.set(ListRowGap, value) && listLayout.set(ListColumnGap, value)
|
result := []PropertyName{}
|
||||||
|
for _, tag := range []PropertyName{ListRowGap, ListColumnGap} {
|
||||||
|
if listLayout.getRaw(tag) != nil {
|
||||||
|
listLayout.setRaw(tag, nil)
|
||||||
|
result = append(result, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
case Content:
|
||||||
|
listLayout.viewsContainerData.removeFunc(listLayout, Content)
|
||||||
|
listLayout.adapter = nil
|
||||||
|
return []PropertyName{Content}
|
||||||
|
}
|
||||||
|
|
||||||
|
return listLayout.viewsContainerData.removeFunc(listLayout, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (listLayout *listLayoutData) setFunc(self View, tag PropertyName, value any) []PropertyName {
|
||||||
|
switch tag {
|
||||||
|
case Gap:
|
||||||
|
result := listLayout.setFunc(listLayout, ListRowGap, value)
|
||||||
|
if result != nil {
|
||||||
|
if gap := listLayout.getRaw(ListRowGap); gap != nil {
|
||||||
|
listLayout.setRaw(ListColumnGap, gap)
|
||||||
|
result = append(result, ListColumnGap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
case Content:
|
case Content:
|
||||||
if adapter, ok := value.(ListAdapter); ok {
|
if adapter, ok := value.(ListAdapter); ok {
|
||||||
listLayout.adapter = adapter
|
listLayout.adapter = adapter
|
||||||
listLayout.UpdateContent()
|
listLayout.createContent()
|
||||||
// TODO
|
} else if listLayout.setContent(value) {
|
||||||
return true
|
|
||||||
}
|
|
||||||
listLayout.adapter = nil
|
listLayout.adapter = nil
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []PropertyName{Content}
|
||||||
|
}
|
||||||
|
return listLayout.viewsContainerData.setFunc(listLayout, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if listLayout.viewsContainerData.set(tag, value) {
|
func listLayoutPropertyChanged(view View, tag PropertyName) {
|
||||||
if listLayout.created {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Orientation, ListWrap, HorizontalAlign, VerticalAlign:
|
case Orientation, ListWrap, HorizontalAlign, VerticalAlign:
|
||||||
updateCSSStyle(listLayout.htmlID(), listLayout.session)
|
updateCSSStyle(view.htmlID(), view.Session())
|
||||||
|
|
||||||
|
default:
|
||||||
|
viewsContainerPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (listLayout *listLayoutData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (listLayout *listLayoutData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
if listLayout.views != nil {
|
if listLayout.views != nil {
|
||||||
|
@ -166,7 +169,14 @@ func (listLayout *listLayoutData) htmlSubviews(self View, buffer *strings.Builde
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (listLayout *listLayoutData) UpdateContent() {
|
func (listLayout *listLayoutData) setAdapter(adapter ListAdapter) {
|
||||||
|
listLayout.adapter = adapter
|
||||||
|
if adapter != nil {
|
||||||
|
listLayout.createContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (listLayout *listLayoutData) createContent() bool {
|
||||||
if adapter := listLayout.adapter; adapter != nil {
|
if adapter := listLayout.adapter; adapter != nil {
|
||||||
listLayout.views = []View{}
|
listLayout.views = []View{}
|
||||||
|
|
||||||
|
@ -185,11 +195,20 @@ func (listLayout *listLayoutData) UpdateContent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if listLayout.created {
|
return true
|
||||||
updateInnerHTML(htmlID, session)
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
listLayout.propertyChangedEvent(Content)
|
func (listLayout *listLayoutData) UpdateContent() {
|
||||||
|
if listLayout.createContent() {
|
||||||
|
if listLayout.created {
|
||||||
|
updateInnerHTML(listLayout.htmlID(), listLayout.session)
|
||||||
|
}
|
||||||
|
|
||||||
|
if listener, ok := listLayout.changeListener[Content]; ok {
|
||||||
|
listener(listLayout, Content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
696
listView.go
696
listView.go
File diff suppressed because it is too large
Load Diff
291
mediaPlayer.go
291
mediaPlayer.go
|
@ -32,7 +32,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - The browser will offer controls to allow the user to control video playback, volume, seeking and pause/resume playback.
|
// `true` or `1` or "true", "yes", "on", "1" - The browser will offer controls to allow the user to control video playback, volume, seeking and pause/resume playback.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - No controls will be visible to the end user.
|
// `false` or `0` or "false", "no", "off", "0" - No controls will be visible to the end user.
|
||||||
Controls = "controls"
|
Controls PropertyName = "controls"
|
||||||
|
|
||||||
// Loop is the constant for "loop" property tag.
|
// Loop is the constant for "loop" property tag.
|
||||||
//
|
//
|
||||||
|
@ -55,7 +55,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - The video player will automatically seek back to the start upon reaching the end of the video.
|
// `true` or `1` or "true", "yes", "on", "1" - The video player will automatically seek back to the start upon reaching the end of the video.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - Video player will stop playing when the end of the media file has been reached.
|
// `false` or `0` or "false", "no", "off", "0" - Video player will stop playing when the end of the media file has been reached.
|
||||||
Loop = "loop"
|
Loop PropertyName = "loop"
|
||||||
|
|
||||||
// Muted is the constant for "muted" property tag.
|
// Muted is the constant for "muted" property tag.
|
||||||
//
|
//
|
||||||
|
@ -78,7 +78,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Video will be muted.
|
// `true` or `1` or "true", "yes", "on", "1" - Video will be muted.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - Video playing normally.
|
// `false` or `0` or "false", "no", "off", "0" - Video playing normally.
|
||||||
Muted = "muted"
|
Muted PropertyName = "muted"
|
||||||
|
|
||||||
// Preload is the constant for "preload" property tag.
|
// Preload is the constant for "preload" property tag.
|
||||||
//
|
//
|
||||||
|
@ -105,7 +105,7 @@ const (
|
||||||
// `0`(`PreloadNone`) or "none" - Media file must not be pre-loaded.
|
// `0`(`PreloadNone`) or "none" - Media file must not be pre-loaded.
|
||||||
// `1`(`PreloadMetadata`) or "metadata" - Only metadata is preloaded.
|
// `1`(`PreloadMetadata`) or "metadata" - Only metadata is preloaded.
|
||||||
// `2`(`PreloadAuto`) or "auto" - The entire media file can be downloaded even if the user doesn't have to use it.
|
// `2`(`PreloadAuto`) or "auto" - The entire media file can be downloaded even if the user doesn't have to use it.
|
||||||
Preload = "preload"
|
Preload PropertyName = "preload"
|
||||||
|
|
||||||
// AbortEvent is the constant for "abort-event" property tag.
|
// AbortEvent is the constant for "abort-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -134,7 +134,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
AbortEvent = "abort-event"
|
AbortEvent PropertyName = "abort-event"
|
||||||
|
|
||||||
// CanPlayEvent is the constant for "can-play-event" property tag.
|
// CanPlayEvent is the constant for "can-play-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -165,7 +165,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
CanPlayEvent = "can-play-event"
|
CanPlayEvent PropertyName = "can-play-event"
|
||||||
|
|
||||||
// CanPlayThroughEvent is the constant for "can-play-through-event" property tag.
|
// CanPlayThroughEvent is the constant for "can-play-through-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -194,7 +194,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
CanPlayThroughEvent = "can-play-through-event"
|
CanPlayThroughEvent PropertyName = "can-play-through-event"
|
||||||
|
|
||||||
// CompleteEvent is the constant for "complete-event" property tag.
|
// CompleteEvent is the constant for "complete-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -223,7 +223,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
CompleteEvent = "complete-event"
|
CompleteEvent PropertyName = "complete-event"
|
||||||
|
|
||||||
// DurationChangedEvent is the constant for "duration-changed-event" property tag.
|
// DurationChangedEvent is the constant for "duration-changed-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -258,7 +258,7 @@ const (
|
||||||
// `func(player rui.MediaPlayer)`,
|
// `func(player rui.MediaPlayer)`,
|
||||||
// `func(duration float64)`,
|
// `func(duration float64)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
DurationChangedEvent = "duration-changed-event"
|
DurationChangedEvent PropertyName = "duration-changed-event"
|
||||||
|
|
||||||
// EmptiedEvent is the constant for "emptied-event" property tag.
|
// EmptiedEvent is the constant for "emptied-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -289,7 +289,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
EmptiedEvent = "emptied-event"
|
EmptiedEvent PropertyName = "emptied-event"
|
||||||
|
|
||||||
// EndedEvent is the constant for "ended-event" property tag.
|
// EndedEvent is the constant for "ended-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -318,7 +318,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
EndedEvent = "ended-event"
|
EndedEvent PropertyName = "ended-event"
|
||||||
|
|
||||||
// LoadedDataEvent is the constant for "loaded-data-event" property tag.
|
// LoadedDataEvent is the constant for "loaded-data-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -347,7 +347,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
LoadedDataEvent = "loaded-data-event"
|
LoadedDataEvent PropertyName = "loaded-data-event"
|
||||||
|
|
||||||
// LoadedMetadataEvent is the constant for "loaded-metadata-event" property tag.
|
// LoadedMetadataEvent is the constant for "loaded-metadata-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -376,7 +376,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
LoadedMetadataEvent = "loaded-metadata-event"
|
LoadedMetadataEvent PropertyName = "loaded-metadata-event"
|
||||||
|
|
||||||
// LoadStartEvent is the constant for "load-start-event" property tag.
|
// LoadStartEvent is the constant for "load-start-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -405,7 +405,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
LoadStartEvent = "load-start-event"
|
LoadStartEvent PropertyName = "load-start-event"
|
||||||
|
|
||||||
// PauseEvent is the constant for "pause-event" property tag.
|
// PauseEvent is the constant for "pause-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -434,7 +434,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PauseEvent = "pause-event"
|
PauseEvent PropertyName = "pause-event"
|
||||||
|
|
||||||
// PlayEvent is the constant for "play-event" property tag.
|
// PlayEvent is the constant for "play-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -463,7 +463,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PlayEvent = "play-event"
|
PlayEvent PropertyName = "play-event"
|
||||||
|
|
||||||
// PlayingEvent is the constant for "playing-event" property tag.
|
// PlayingEvent is the constant for "playing-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -492,7 +492,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PlayingEvent = "playing-event"
|
PlayingEvent PropertyName = "playing-event"
|
||||||
|
|
||||||
// ProgressEvent is the constant for "progress-event" property tag.
|
// ProgressEvent is the constant for "progress-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -521,7 +521,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
ProgressEvent = "progress-event"
|
ProgressEvent PropertyName = "progress-event"
|
||||||
|
|
||||||
// RateChangedEvent is the constant for "rate-changed-event" property tag.
|
// RateChangedEvent is the constant for "rate-changed-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -556,7 +556,7 @@ const (
|
||||||
// `func(player rui.MediaPlayer)`,
|
// `func(player rui.MediaPlayer)`,
|
||||||
// `func(rate float64)`,
|
// `func(rate float64)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
RateChangedEvent = "rate-changed-event"
|
RateChangedEvent PropertyName = "rate-changed-event"
|
||||||
|
|
||||||
// SeekedEvent is the constant for "seeked-event" property tag.
|
// SeekedEvent is the constant for "seeked-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -585,7 +585,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
SeekedEvent = "seeked-event"
|
SeekedEvent PropertyName = "seeked-event"
|
||||||
|
|
||||||
// SeekingEvent is the constant for "seeking-event" property tag.
|
// SeekingEvent is the constant for "seeking-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -614,7 +614,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
SeekingEvent = "seeking-event"
|
SeekingEvent PropertyName = "seeking-event"
|
||||||
|
|
||||||
// StalledEvent is the constant for "stalled-event" property tag.
|
// StalledEvent is the constant for "stalled-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -643,7 +643,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
StalledEvent = "stalled-event"
|
StalledEvent PropertyName = "stalled-event"
|
||||||
|
|
||||||
// SuspendEvent is the constant for "suspend-event" property tag.
|
// SuspendEvent is the constant for "suspend-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -672,7 +672,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
SuspendEvent = "suspend-event"
|
SuspendEvent PropertyName = "suspend-event"
|
||||||
|
|
||||||
// TimeUpdateEvent is the constant for "time-update-event" property tag.
|
// TimeUpdateEvent is the constant for "time-update-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -707,7 +707,7 @@ const (
|
||||||
// `func(player rui.MediaPlayer)`,
|
// `func(player rui.MediaPlayer)`,
|
||||||
// `func(time float64)`,
|
// `func(time float64)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TimeUpdateEvent = "time-update-event"
|
TimeUpdateEvent PropertyName = "time-update-event"
|
||||||
|
|
||||||
// VolumeChangedEvent is the constant for "volume-changed-event" property tag.
|
// VolumeChangedEvent is the constant for "volume-changed-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -742,7 +742,7 @@ const (
|
||||||
// `func(player rui.MediaPlayer)`,
|
// `func(player rui.MediaPlayer)`,
|
||||||
// `func(volume float64)`,
|
// `func(volume float64)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
VolumeChangedEvent = "volume-changed-event"
|
VolumeChangedEvent PropertyName = "volume-changed-event"
|
||||||
|
|
||||||
// WaitingEvent is the constant for "waiting-event" property tag.
|
// WaitingEvent is the constant for "waiting-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -771,7 +771,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
WaitingEvent = "waiting-event"
|
WaitingEvent PropertyName = "waiting-event"
|
||||||
|
|
||||||
// PlayerErrorEvent is the constant for "player-error-event" property tag.
|
// PlayerErrorEvent is the constant for "player-error-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -820,7 +820,7 @@ const (
|
||||||
// `func(code int, message string)`,
|
// `func(code int, message string)`,
|
||||||
// `func(player rui.MediaPlayer)`,
|
// `func(player rui.MediaPlayer)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PlayerErrorEvent = "player-error-event"
|
PlayerErrorEvent PropertyName = "player-error-event"
|
||||||
|
|
||||||
// PreloadNone - value of the view "preload" property: indicates that the audio/video should not be preloaded.
|
// PreloadNone - value of the view "preload" property: indicates that the audio/video should not be preloaded.
|
||||||
PreloadNone = 0
|
PreloadNone = 0
|
||||||
|
@ -907,119 +907,70 @@ type MediaSource struct {
|
||||||
func (player *mediaPlayerData) init(session Session) {
|
func (player *mediaPlayerData) init(session Session) {
|
||||||
player.viewData.init(session)
|
player.viewData.init(session)
|
||||||
player.tag = "MediaPlayer"
|
player.tag = "MediaPlayer"
|
||||||
}
|
player.set = mediaPlayerSet
|
||||||
|
player.changed = mediaPlayerPropertyChanged
|
||||||
func (player *mediaPlayerData) String() string {
|
|
||||||
return getViewString(player, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *mediaPlayerData) Focusable() bool {
|
func (player *mediaPlayerData) Focusable() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *mediaPlayerData) Remove(tag string) {
|
func mediaPlayerSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
player.remove(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *mediaPlayerData) remove(tag string) {
|
|
||||||
player.viewData.remove(tag)
|
|
||||||
player.propertyChanged(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *mediaPlayerData) Set(tag string, value any) bool {
|
|
||||||
return player.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *mediaPlayerData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
player.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Controls, Loop, Muted, Preload:
|
|
||||||
if player.viewData.set(tag, value) {
|
|
||||||
player.propertyChanged(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, LoadStartEvent,
|
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, LoadStartEvent,
|
||||||
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent,
|
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent,
|
||||||
ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent:
|
ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent:
|
||||||
if listeners, ok := valueToNoParamListeners[MediaPlayer](value); ok {
|
|
||||||
if listeners == nil {
|
return setNoParamEventListener[MediaPlayer](view, tag, value)
|
||||||
delete(player.properties, tag)
|
|
||||||
} else {
|
|
||||||
player.properties[tag] = listeners
|
|
||||||
}
|
|
||||||
player.propertyChanged(tag)
|
|
||||||
player.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
|
|
||||||
case DurationChangedEvent, RateChangedEvent, TimeUpdateEvent, VolumeChangedEvent:
|
case DurationChangedEvent, RateChangedEvent, TimeUpdateEvent, VolumeChangedEvent:
|
||||||
if listeners, ok := valueToEventListeners[MediaPlayer, float64](value); ok {
|
|
||||||
if listeners == nil {
|
return setViewEventListener[MediaPlayer, float64](view, tag, value)
|
||||||
delete(player.properties, tag)
|
|
||||||
} else {
|
|
||||||
player.properties[tag] = listeners
|
|
||||||
}
|
|
||||||
player.propertyChanged(tag)
|
|
||||||
player.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
|
|
||||||
case PlayerErrorEvent:
|
case PlayerErrorEvent:
|
||||||
if listeners, ok := valueToPlayerErrorListeners(value); ok {
|
if listeners, ok := valueToPlayerErrorListeners(value); ok {
|
||||||
if listeners == nil {
|
if len(listeners) > 0 {
|
||||||
delete(player.properties, tag)
|
view.setRaw(tag, listeners)
|
||||||
|
} else if view.getRaw(tag) != nil {
|
||||||
|
view.setRaw(tag, nil)
|
||||||
} else {
|
} else {
|
||||||
player.properties[tag] = listeners
|
return []PropertyName{}
|
||||||
}
|
}
|
||||||
player.propertyChanged(tag)
|
return []PropertyName{tag}
|
||||||
player.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
|
||||||
case Source:
|
case Source:
|
||||||
if player.setSource(value) {
|
return setMediaPlayerSource(view, value)
|
||||||
player.propertyChanged(tag)
|
|
||||||
player.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
return viewSet(view, tag, value)
|
||||||
return player.viewData.set(tag, value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
func setMediaPlayerSource(properties Properties, value any) []PropertyName {
|
||||||
}
|
|
||||||
|
|
||||||
func (player *mediaPlayerData) setSource(value any) bool {
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
src := MediaSource{Url: value, MimeType: ""}
|
src := MediaSource{Url: value, MimeType: ""}
|
||||||
player.properties[Source] = []MediaSource{src}
|
properties.setRaw(Source, []MediaSource{src})
|
||||||
|
|
||||||
case MediaSource:
|
case MediaSource:
|
||||||
player.properties[Source] = []MediaSource{value}
|
properties.setRaw(Source, []MediaSource{value})
|
||||||
|
|
||||||
case []MediaSource:
|
case []MediaSource:
|
||||||
player.properties[Source] = value
|
properties.setRaw(Source, value)
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
url, ok := value.PropertyValue("src")
|
url, ok := value.PropertyValue("src")
|
||||||
if !ok || url == "" {
|
if !ok || url == "" {
|
||||||
invalidPropertyValue(Source, value)
|
invalidPropertyValue(Source, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mimeType, _ := value.PropertyValue("mime-type")
|
mimeType, _ := value.PropertyValue("mime-type")
|
||||||
src := MediaSource{Url: url, MimeType: mimeType}
|
src := MediaSource{Url: url, MimeType: mimeType}
|
||||||
player.properties[Source] = []MediaSource{src}
|
properties.setRaw(Source, []MediaSource{src})
|
||||||
|
|
||||||
case []DataValue:
|
case []DataValue:
|
||||||
src := []MediaSource{}
|
src := []MediaSource{}
|
||||||
|
@ -1031,7 +982,7 @@ func (player *mediaPlayerData) setSource(value any) bool {
|
||||||
src = append(src, MediaSource{Url: url, MimeType: mimeType})
|
src = append(src, MediaSource{Url: url, MimeType: mimeType})
|
||||||
} else {
|
} else {
|
||||||
invalidPropertyValue(Source, value)
|
invalidPropertyValue(Source, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
src = append(src, MediaSource{Url: val.Value(), MimeType: ""})
|
src = append(src, MediaSource{Url: val.Value(), MimeType: ""})
|
||||||
|
@ -1040,16 +991,16 @@ func (player *mediaPlayerData) setSource(value any) bool {
|
||||||
|
|
||||||
if len(src) == 0 {
|
if len(src) == 0 {
|
||||||
invalidPropertyValue(Source, value)
|
invalidPropertyValue(Source, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
player.properties[Source] = src
|
properties.setRaw(Source, src)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(Source, value)
|
notCompatibleType(Source, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{Source}
|
||||||
}
|
}
|
||||||
|
|
||||||
func valueToPlayerErrorListeners(value any) ([]func(MediaPlayer, int, string), bool) {
|
func valueToPlayerErrorListeners(value any) ([]func(MediaPlayer, int, string), bool) {
|
||||||
|
@ -1177,109 +1128,106 @@ func valueToPlayerErrorListeners(value any) ([]func(MediaPlayer, int, string), b
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func playerEvents() []struct{ tag, cssTag string } {
|
func mediaPlayerEvents() map[PropertyName]string {
|
||||||
return []struct{ tag, cssTag string }{
|
return map[PropertyName]string{
|
||||||
{AbortEvent, "onabort"},
|
AbortEvent: "onabort",
|
||||||
{CanPlayEvent, "oncanplay"},
|
CanPlayEvent: "oncanplay",
|
||||||
{CanPlayThroughEvent, "oncanplaythrough"},
|
CanPlayThroughEvent: "oncanplaythrough",
|
||||||
{CompleteEvent, "oncomplete"},
|
CompleteEvent: "oncomplete",
|
||||||
{EmptiedEvent, "onemptied"},
|
EmptiedEvent: "onemptied",
|
||||||
{EndedEvent, "ended"},
|
EndedEvent: "ended",
|
||||||
{LoadedDataEvent, "onloadeddata"},
|
LoadedDataEvent: "onloadeddata",
|
||||||
{LoadedMetadataEvent, "onloadedmetadata"},
|
LoadedMetadataEvent: "onloadedmetadata",
|
||||||
{LoadStartEvent, "onloadstart"},
|
LoadStartEvent: "onloadstart",
|
||||||
{PauseEvent, "onpause"},
|
PauseEvent: "onpause",
|
||||||
{PlayEvent, "onplay"},
|
PlayEvent: "onplay",
|
||||||
{PlayingEvent, "onplaying"},
|
PlayingEvent: "onplaying",
|
||||||
{ProgressEvent, "onprogress"},
|
ProgressEvent: "onprogress",
|
||||||
{SeekedEvent, "onseeked"},
|
SeekedEvent: "onseeked",
|
||||||
{SeekingEvent, "onseeking"},
|
SeekingEvent: "onseeking",
|
||||||
{StalledEvent, "onstalled"},
|
StalledEvent: "onstalled",
|
||||||
{SuspendEvent, "onsuspend"},
|
SuspendEvent: "onsuspend",
|
||||||
{WaitingEvent, "onwaiting"},
|
WaitingEvent: "onwaiting",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *mediaPlayerData) propertyChanged(tag string) {
|
func mediaPlayerPropertyChanged(view View, tag PropertyName) {
|
||||||
if player.created {
|
session := view.Session()
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Controls, Loop:
|
case Controls, Loop:
|
||||||
value, _ := boolProperty(player, tag, player.session)
|
value, _ := boolProperty(view, tag, session)
|
||||||
if value {
|
if value {
|
||||||
player.session.updateProperty(player.htmlID(), tag, value)
|
session.updateProperty(view.htmlID(), string(tag), value)
|
||||||
} else {
|
} else {
|
||||||
player.session.removeProperty(player.htmlID(), tag)
|
session.removeProperty(view.htmlID(), string(tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
case Muted:
|
case Muted:
|
||||||
value, _ := boolProperty(player, tag, player.session)
|
value, _ := boolProperty(view, Muted, session)
|
||||||
player.session.callFunc("setMediaMuted", player.htmlID(), value)
|
session.callFunc("setMediaMuted", view.htmlID(), value)
|
||||||
|
|
||||||
case Preload:
|
case Preload:
|
||||||
value, _ := enumProperty(player, tag, player.session, 0)
|
value, _ := enumProperty(view, Preload, session, 0)
|
||||||
values := enumProperties[Preload].values
|
values := enumProperties[Preload].values
|
||||||
player.session.updateProperty(player.htmlID(), tag, values[value])
|
session.updateProperty(view.htmlID(), string(Preload), values[value])
|
||||||
|
|
||||||
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent,
|
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent,
|
||||||
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, ProgressEvent,
|
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, ProgressEvent,
|
||||||
LoadStartEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent:
|
LoadStartEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent:
|
||||||
|
|
||||||
for _, event := range playerEvents() {
|
if cssTag, ok := mediaPlayerEvents()[tag]; ok {
|
||||||
if event.tag == tag {
|
fn := ""
|
||||||
if value := player.getRaw(event.tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
switch value := value.(type) {
|
if listeners, ok := value.([]func(MediaPlayer)); ok && len(listeners) > 0 {
|
||||||
case []func(MediaPlayer):
|
fn = fmt.Sprintf(`viewEvent(this, "%s")`, string(tag))
|
||||||
if len(value) > 0 {
|
|
||||||
fn := fmt.Sprintf(`playerEvent(this, "%s")`, event.tag)
|
|
||||||
player.session.updateProperty(player.htmlID(), event.cssTag, fn)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
session.updateProperty(view.htmlID(), cssTag, fn)
|
||||||
player.session.updateProperty(player.htmlID(), tag, "")
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
case TimeUpdateEvent:
|
case TimeUpdateEvent:
|
||||||
if value := player.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
player.session.updateProperty(player.htmlID(), "ontimeupdate", "playerTimeUpdatedEvent(this)")
|
session.updateProperty(view.htmlID(), "ontimeupdate", "viewTimeUpdatedEvent(this)")
|
||||||
} else {
|
} else {
|
||||||
player.session.updateProperty(player.htmlID(), "ontimeupdate", "")
|
session.updateProperty(view.htmlID(), "ontimeupdate", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
case VolumeChangedEvent:
|
case VolumeChangedEvent:
|
||||||
if value := player.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
player.session.updateProperty(player.htmlID(), "onvolumechange", "playerVolumeChangedEvent(this)")
|
session.updateProperty(view.htmlID(), "onvolumechange", "viewVolumeChangedEvent(this)")
|
||||||
} else {
|
} else {
|
||||||
player.session.updateProperty(player.htmlID(), "onvolumechange", "")
|
session.updateProperty(view.htmlID(), "onvolumechange", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
case DurationChangedEvent:
|
case DurationChangedEvent:
|
||||||
if value := player.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
player.session.updateProperty(player.htmlID(), "ondurationchange", "playerDurationChangedEvent(this)")
|
session.updateProperty(view.htmlID(), "ondurationchange", "viewDurationChangedEvent(this)")
|
||||||
} else {
|
} else {
|
||||||
player.session.updateProperty(player.htmlID(), "ondurationchange", "")
|
session.updateProperty(view.htmlID(), "ondurationchange", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
case RateChangedEvent:
|
case RateChangedEvent:
|
||||||
if value := player.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
player.session.updateProperty(player.htmlID(), "onratechange", "playerRateChangedEvent(this)")
|
session.updateProperty(view.htmlID(), "onratechange", "viewRateChangedEvent(this)")
|
||||||
} else {
|
} else {
|
||||||
player.session.updateProperty(player.htmlID(), "onratechange", "")
|
session.updateProperty(view.htmlID(), "onratechange", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
case PlayerErrorEvent:
|
case PlayerErrorEvent:
|
||||||
if value := player.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
player.session.updateProperty(player.htmlID(), "onerror", "playerErrorEvent(this)")
|
session.updateProperty(view.htmlID(), "onerror", "viewErrorEvent(this)")
|
||||||
} else {
|
} else {
|
||||||
player.session.updateProperty(player.htmlID(), "onerror", "")
|
session.updateProperty(view.htmlID(), "onerror", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
case Source:
|
case Source:
|
||||||
updateInnerHTML(player.htmlID(), player.session)
|
updateInnerHTML(view.htmlID(), session)
|
||||||
}
|
|
||||||
|
default:
|
||||||
|
viewPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *mediaPlayerData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (player *mediaPlayerData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
|
@ -1305,10 +1253,10 @@ func (player *mediaPlayerData) htmlSubviews(self View, buffer *strings.Builder)
|
||||||
|
|
||||||
func (player *mediaPlayerData) htmlProperties(self View, buffer *strings.Builder) {
|
func (player *mediaPlayerData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
player.viewData.htmlProperties(self, buffer)
|
player.viewData.htmlProperties(self, buffer)
|
||||||
for _, tag := range []string{Controls, Loop, Muted, Preload} {
|
for _, tag := range []PropertyName{Controls, Loop, Muted, Preload} {
|
||||||
if value, _ := boolProperty(player, tag, player.session); value {
|
if value, _ := boolProperty(player, tag, player.session); value {
|
||||||
buffer.WriteRune(' ')
|
buffer.WriteRune(' ')
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1319,20 +1267,17 @@ func (player *mediaPlayerData) htmlProperties(self View, buffer *strings.Builder
|
||||||
buffer.WriteRune('"')
|
buffer.WriteRune('"')
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, event := range playerEvents() {
|
for tag, cssTag := range mediaPlayerEvents() {
|
||||||
if value := player.getRaw(event.tag); value != nil {
|
if value := player.getRaw(tag); value != nil {
|
||||||
switch value := value.(type) {
|
if listeners, ok := value.([]func(MediaPlayer)); ok && len(listeners) > 0 {
|
||||||
case []func(MediaPlayer):
|
|
||||||
if len(value) > 0 {
|
|
||||||
buffer.WriteString(` `)
|
buffer.WriteString(` `)
|
||||||
buffer.WriteString(event.cssTag)
|
buffer.WriteString(cssTag)
|
||||||
buffer.WriteString(`="playerEvent(this, '`)
|
buffer.WriteString(`="playerEvent(this, '`)
|
||||||
buffer.WriteString(event.tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(`')"`)
|
buffer.WriteString(`')"`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if value := player.getRaw(TimeUpdateEvent); value != nil {
|
if value := player.getRaw(TimeUpdateEvent); value != nil {
|
||||||
buffer.WriteString(` ontimeupdate="playerTimeUpdatedEvent(this)"`)
|
buffer.WriteString(` ontimeupdate="playerTimeUpdatedEvent(this)"`)
|
||||||
|
@ -1355,7 +1300,7 @@ func (player *mediaPlayerData) htmlProperties(self View, buffer *strings.Builder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *mediaPlayerData) handleCommand(self View, command string, data DataObject) bool {
|
func (player *mediaPlayerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, LoadStartEvent,
|
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, LoadStartEvent,
|
||||||
EmptiedEvent, EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent,
|
EmptiedEvent, EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent,
|
||||||
|
|
|
@ -23,7 +23,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.MouseEvent)`,
|
// `func(event rui.MouseEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
ClickEvent = "click-event"
|
ClickEvent PropertyName = "click-event"
|
||||||
|
|
||||||
// DoubleClickEvent is the constant for "double-click-event" property tag.
|
// DoubleClickEvent is the constant for "double-click-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -41,7 +41,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.MouseEvent)`,
|
// `func(event rui.MouseEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
DoubleClickEvent = "double-click-event"
|
DoubleClickEvent PropertyName = "double-click-event"
|
||||||
|
|
||||||
// MouseDown is the constant for "mouse-down" property tag.
|
// MouseDown is the constant for "mouse-down" property tag.
|
||||||
//
|
//
|
||||||
|
@ -59,7 +59,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.MouseEvent)`,
|
// `func(event rui.MouseEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
MouseDown = "mouse-down"
|
MouseDown PropertyName = "mouse-down"
|
||||||
|
|
||||||
// MouseUp is the constant for "mouse-up" property tag.
|
// MouseUp is the constant for "mouse-up" property tag.
|
||||||
//
|
//
|
||||||
|
@ -78,7 +78,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.MouseEvent)`,
|
// `func(event rui.MouseEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
MouseUp = "mouse-up"
|
MouseUp PropertyName = "mouse-up"
|
||||||
|
|
||||||
// MouseMove is the constant for "mouse-move" property tag.
|
// MouseMove is the constant for "mouse-move" property tag.
|
||||||
//
|
//
|
||||||
|
@ -96,7 +96,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.MouseEvent)`,
|
// `func(event rui.MouseEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
MouseMove = "mouse-move"
|
MouseMove PropertyName = "mouse-move"
|
||||||
|
|
||||||
// MouseOut is the constant for "mouse-out" property tag.
|
// MouseOut is the constant for "mouse-out" property tag.
|
||||||
//
|
//
|
||||||
|
@ -116,7 +116,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.MouseEvent)`,
|
// `func(event rui.MouseEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
MouseOut = "mouse-out"
|
MouseOut PropertyName = "mouse-out"
|
||||||
|
|
||||||
// MouseOver is the constant for "mouse-over" property tag.
|
// MouseOver is the constant for "mouse-over" property tag.
|
||||||
//
|
//
|
||||||
|
@ -135,7 +135,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.MouseEvent)`,
|
// `func(event rui.MouseEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
MouseOver = "mouse-over"
|
MouseOver PropertyName = "mouse-over"
|
||||||
|
|
||||||
// ContextMenuEvent is the constant for "context-menu-event" property tag.
|
// ContextMenuEvent is the constant for "context-menu-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -153,7 +153,7 @@ const (
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func(event rui.MouseEvent)`,
|
// `func(event rui.MouseEvent)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
ContextMenuEvent = "context-menu-event"
|
ContextMenuEvent PropertyName = "context-menu-event"
|
||||||
|
|
||||||
// PrimaryMouseButton is a number of the main pressed button, usually the left button or the un-initialized state
|
// PrimaryMouseButton is a number of the main pressed button, usually the left button or the un-initialized state
|
||||||
PrimaryMouseButton = 0
|
PrimaryMouseButton = 0
|
||||||
|
@ -228,49 +228,33 @@ type MouseEvent struct {
|
||||||
MetaKey bool
|
MetaKey bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var mouseEvents = map[string]struct{ jsEvent, jsFunc string }{
|
/*
|
||||||
ClickEvent: {jsEvent: "onclick", jsFunc: "clickEvent"},
|
func setMouseListener(properties Properties, tag PropertyName, value any) bool {
|
||||||
DoubleClickEvent: {jsEvent: "ondblclick", jsFunc: "doubleClickEvent"},
|
if listeners, ok := valueToEventListeners[View, MouseEvent](value); ok {
|
||||||
MouseDown: {jsEvent: "onmousedown", jsFunc: "mouseDownEvent"},
|
if len(listeners) == 0 {
|
||||||
MouseUp: {jsEvent: "onmouseup", jsFunc: "mouseUpEvent"},
|
properties.setRaw(tag, nil)
|
||||||
MouseMove: {jsEvent: "onmousemove", jsFunc: "mouseMoveEvent"},
|
} else {
|
||||||
MouseOut: {jsEvent: "onmouseout", jsFunc: "mouseOutEvent"},
|
properties.setRaw(tag, listeners)
|
||||||
MouseOver: {jsEvent: "onmouseover", jsFunc: "mouseOverEvent"},
|
}
|
||||||
ContextMenuEvent: {jsEvent: "oncontextmenu", jsFunc: "contextMenuEvent"},
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) setMouseListener(tag string, value any) bool {
|
|
||||||
listeners, ok := valueToEventListeners[View, MouseEvent](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if listeners == nil {
|
func (view *viewData) removeMouseListener(tag PropertyName) {
|
||||||
view.removeMouseListener(tag)
|
|
||||||
} else if js, ok := mouseEvents[tag]; ok {
|
|
||||||
view.properties[tag] = listeners
|
|
||||||
if view.created {
|
|
||||||
view.session.updateProperty(view.htmlID(), js.jsEvent, js.jsFunc+"(this, event)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) removeMouseListener(tag string) {
|
|
||||||
delete(view.properties, tag)
|
delete(view.properties, tag)
|
||||||
if view.created {
|
if view.created {
|
||||||
if js, ok := mouseEvents[tag]; ok {
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mouseEventsHtml(view View, buffer *strings.Builder, hasTooltip bool) {
|
func mouseEventsHtml(view View, buffer *strings.Builder, hasTooltip bool) {
|
||||||
for tag, js := range mouseEvents {
|
for _, tag := range []PropertyName{ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent} {
|
||||||
if value := view.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
if listeners, ok := value.([]func(View, MouseEvent)); ok && len(listeners) > 0 {
|
if listeners, ok := value.([]func(View, MouseEvent)); ok && len(listeners) > 0 {
|
||||||
buffer.WriteString(js.jsEvent)
|
buffer.WriteString(js.jsEvent)
|
||||||
buffer.WriteString(`="`)
|
buffer.WriteString(`="`)
|
||||||
|
@ -279,12 +263,14 @@ func mouseEventsHtml(view View, buffer *strings.Builder, hasTooltip bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if hasTooltip {
|
if hasTooltip {
|
||||||
buffer.WriteString(`onmouseenter="mouseEnterEvent(this, event)" `)
|
buffer.WriteString(`onmouseenter="mouseEnterEvent(this, event)" `)
|
||||||
buffer.WriteString(`onmouseleave="mouseLeaveEvent(this, event)" `)
|
buffer.WriteString(`onmouseleave="mouseLeaveEvent(this, event)" `)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func getTimeStamp(data DataObject) uint64 {
|
func getTimeStamp(data DataObject) uint64 {
|
||||||
if value, ok := data.PropertyValue("timeStamp"); ok {
|
if value, ok := data.PropertyValue("timeStamp"); ok {
|
||||||
|
@ -315,7 +301,7 @@ func (event *MouseEvent) init(data DataObject) {
|
||||||
event.MetaKey = dataBoolProperty(data, "metaKey")
|
event.MetaKey = dataBoolProperty(data, "metaKey")
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMouseEvents(view View, tag string, data DataObject) {
|
func handleMouseEvents(view View, tag PropertyName, data DataObject) {
|
||||||
listeners := getEventListeners[View, MouseEvent](view, nil, tag)
|
listeners := getEventListeners[View, MouseEvent](view, nil, tag)
|
||||||
if len(listeners) > 0 {
|
if len(listeners) > 0 {
|
||||||
var event MouseEvent
|
var event MouseEvent
|
||||||
|
|
183
numberPicker.go
183
numberPicker.go
|
@ -26,7 +26,7 @@ const (
|
||||||
// `func(newValue, oldValue float64)`,
|
// `func(newValue, oldValue float64)`,
|
||||||
// `func(newValue float64)`,
|
// `func(newValue float64)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
NumberChangedEvent = "number-changed"
|
NumberChangedEvent PropertyName = "number-changed"
|
||||||
|
|
||||||
// NumberPickerType is the constant for "number-picker-type" property tag.
|
// NumberPickerType is the constant for "number-picker-type" property tag.
|
||||||
//
|
//
|
||||||
|
@ -38,7 +38,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `0`(`NumberEditor`) or "editor" - Displayed as an editor.
|
// `0`(`NumberEditor`) or "editor" - Displayed as an editor.
|
||||||
// `1`(`NumberSlider`) or "slider" - Displayed as a slider.
|
// `1`(`NumberSlider`) or "slider" - Displayed as a slider.
|
||||||
NumberPickerType = "number-picker-type"
|
NumberPickerType PropertyName = "number-picker-type"
|
||||||
|
|
||||||
// NumberPickerMin is the constant for "number-picker-min" property tag.
|
// NumberPickerMin is the constant for "number-picker-min" property tag.
|
||||||
//
|
//
|
||||||
|
@ -48,7 +48,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
NumberPickerMin = "number-picker-min"
|
NumberPickerMin PropertyName = "number-picker-min"
|
||||||
|
|
||||||
// NumberPickerMax is the constant for "number-picker-max" property tag.
|
// NumberPickerMax is the constant for "number-picker-max" property tag.
|
||||||
//
|
//
|
||||||
|
@ -58,7 +58,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
NumberPickerMax = "number-picker-max"
|
NumberPickerMax PropertyName = "number-picker-max"
|
||||||
|
|
||||||
// NumberPickerStep is the constant for "number-picker-step" property tag.
|
// NumberPickerStep is the constant for "number-picker-step" property tag.
|
||||||
//
|
//
|
||||||
|
@ -68,7 +68,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
NumberPickerStep = "number-picker-step"
|
NumberPickerStep PropertyName = "number-picker-step"
|
||||||
|
|
||||||
// NumberPickerValue is the constant for "number-picker-value" property tag.
|
// NumberPickerValue is the constant for "number-picker-value" property tag.
|
||||||
//
|
//
|
||||||
|
@ -78,7 +78,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
NumberPickerValue = "number-picker-value"
|
NumberPickerValue PropertyName = "number-picker-value"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Constants which describe values of the "number-picker-type" property of a [NumberPicker]
|
// Constants which describe values of the "number-picker-type" property of a [NumberPicker]
|
||||||
|
@ -97,8 +97,6 @@ type NumberPicker interface {
|
||||||
|
|
||||||
type numberPickerData struct {
|
type numberPickerData struct {
|
||||||
viewData
|
viewData
|
||||||
dataList
|
|
||||||
numberChangedListeners []func(NumberPicker, float64, float64)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNumberPicker create new NumberPicker object and return it
|
// NewNumberPicker create new NumberPicker object and return it
|
||||||
|
@ -110,165 +108,92 @@ func NewNumberPicker(session Session, params Params) NumberPicker {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNumberPicker(session Session) View {
|
func newNumberPicker(session Session) View {
|
||||||
return NewNumberPicker(session, nil)
|
return new(numberPickerData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) init(session Session) {
|
func (picker *numberPickerData) init(session Session) {
|
||||||
picker.viewData.init(session)
|
picker.viewData.init(session)
|
||||||
picker.tag = "NumberPicker"
|
picker.tag = "NumberPicker"
|
||||||
picker.hasHtmlDisabled = true
|
picker.hasHtmlDisabled = true
|
||||||
picker.numberChangedListeners = []func(NumberPicker, float64, float64){}
|
picker.normalize = normalizeNumberPickerTag
|
||||||
picker.dataListInit()
|
picker.set = numberPickerSet
|
||||||
}
|
picker.changed = numberPickerPropertyChanged
|
||||||
|
|
||||||
func (picker *numberPickerData) String() string {
|
|
||||||
return getViewString(picker, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) Focusable() bool {
|
func (picker *numberPickerData) Focusable() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) normalizeTag(tag string) string {
|
func normalizeNumberPickerTag(tag PropertyName) PropertyName {
|
||||||
tag = strings.ToLower(tag)
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case Type, Min, Max, Step, Value:
|
case Type, Min, Max, Step, Value:
|
||||||
return "number-picker-" + tag
|
return "number-picker-" + tag
|
||||||
}
|
}
|
||||||
|
|
||||||
return picker.normalizeDataListTag(tag)
|
return normalizeDataListTag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) Remove(tag string) {
|
func numberPickerSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
picker.remove(picker.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *numberPickerData) remove(tag string) {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case NumberChangedEvent:
|
case NumberChangedEvent:
|
||||||
if len(picker.numberChangedListeners) > 0 {
|
return setEventWithOldListener[NumberPicker, float64](view, tag, value)
|
||||||
picker.numberChangedListeners = []func(NumberPicker, float64, float64){}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case NumberPickerValue:
|
case NumberPickerValue:
|
||||||
oldValue := GetNumberPickerValue(picker)
|
view.setRaw("old-number", GetNumberPickerValue(view))
|
||||||
picker.viewData.remove(tag)
|
min, max := GetNumberPickerMinMax(view)
|
||||||
if oldValue != 0 {
|
|
||||||
if picker.created {
|
return setFloatProperty(view, NumberPickerValue, value, min, max)
|
||||||
picker.session.callFunc("setInputValue", picker.htmlID(), 0)
|
|
||||||
}
|
|
||||||
for _, listener := range picker.numberChangedListeners {
|
|
||||||
listener(picker, 0, oldValue)
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataList:
|
case DataList:
|
||||||
if len(picker.dataList.dataList) > 0 {
|
return setDataList(view, value, "")
|
||||||
picker.setDataList(picker, []string{}, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
return viewSet(view, tag, value)
|
||||||
picker.viewData.remove(tag)
|
|
||||||
picker.propertyChanged(tag)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) Set(tag string, value any) bool {
|
func numberPickerPropertyChanged(view View, tag PropertyName) {
|
||||||
return picker.set(picker.normalizeTag(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *numberPickerData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
picker.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
|
||||||
case NumberChangedEvent:
|
|
||||||
listeners, ok := valueToEventWithOldListeners[NumberPicker, float64](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
} else if listeners == nil {
|
|
||||||
listeners = []func(NumberPicker, float64, float64){}
|
|
||||||
}
|
|
||||||
picker.numberChangedListeners = listeners
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case NumberPickerValue:
|
|
||||||
oldValue := GetNumberPickerValue(picker)
|
|
||||||
min, max := GetNumberPickerMinMax(picker)
|
|
||||||
if picker.setFloatProperty(NumberPickerValue, value, min, max) {
|
|
||||||
if f, ok := floatProperty(picker, NumberPickerValue, picker.Session(), min); ok && f != oldValue {
|
|
||||||
newValue, _ := floatTextProperty(picker, NumberPickerValue, picker.Session(), min)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.callFunc("setInputValue", picker.htmlID(), newValue)
|
|
||||||
}
|
|
||||||
for _, listener := range picker.numberChangedListeners {
|
|
||||||
listener(picker, f, oldValue)
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
return picker.setDataList(picker, value, picker.created)
|
|
||||||
|
|
||||||
default:
|
|
||||||
if picker.viewData.set(tag, value) {
|
|
||||||
picker.propertyChanged(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *numberPickerData) propertyChanged(tag string) {
|
|
||||||
if picker.created {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case NumberPickerType:
|
case NumberPickerType:
|
||||||
if GetNumberPickerType(picker) == NumberSlider {
|
if GetNumberPickerType(view) == NumberSlider {
|
||||||
picker.session.updateProperty(picker.htmlID(), "type", "range")
|
view.Session().updateProperty(view.htmlID(), "type", "range")
|
||||||
} else {
|
} else {
|
||||||
picker.session.updateProperty(picker.htmlID(), "type", "number")
|
view.Session().updateProperty(view.htmlID(), "type", "number")
|
||||||
}
|
}
|
||||||
|
|
||||||
case NumberPickerMin:
|
case NumberPickerMin:
|
||||||
min, _ := GetNumberPickerMinMax(picker)
|
min, _ := GetNumberPickerMinMax(view)
|
||||||
picker.session.updateProperty(picker.htmlID(), Min, strconv.FormatFloat(min, 'f', -1, 32))
|
view.Session().updateProperty(view.htmlID(), "min", strconv.FormatFloat(min, 'f', -1, 32))
|
||||||
|
|
||||||
case NumberPickerMax:
|
case NumberPickerMax:
|
||||||
_, max := GetNumberPickerMinMax(picker)
|
_, max := GetNumberPickerMinMax(view)
|
||||||
picker.session.updateProperty(picker.htmlID(), Max, strconv.FormatFloat(max, 'f', -1, 32))
|
view.Session().updateProperty(view.htmlID(), "max", strconv.FormatFloat(max, 'f', -1, 32))
|
||||||
|
|
||||||
case NumberPickerStep:
|
case NumberPickerStep:
|
||||||
if step := GetNumberPickerStep(picker); step > 0 {
|
if step := GetNumberPickerStep(view); step > 0 {
|
||||||
picker.session.updateProperty(picker.htmlID(), Step, strconv.FormatFloat(step, 'f', -1, 32))
|
view.Session().updateProperty(view.htmlID(), "step", strconv.FormatFloat(step, 'f', -1, 32))
|
||||||
} else {
|
} else {
|
||||||
picker.session.updateProperty(picker.htmlID(), Step, "any")
|
view.Session().updateProperty(view.htmlID(), "step", "any")
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) Get(tag string) any {
|
case TimePickerValue:
|
||||||
return picker.get(picker.normalizeTag(tag))
|
value := GetNumberPickerValue(view)
|
||||||
|
view.Session().callFunc("setInputValue", view.htmlID(), value)
|
||||||
|
|
||||||
|
if listeners := GetNumberChangedListeners(view); len(listeners) > 0 {
|
||||||
|
old := 0.0
|
||||||
|
if val := view.getRaw("old-number"); val != nil {
|
||||||
|
if n, ok := val.(float64); ok {
|
||||||
|
old = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, listener := range listeners {
|
||||||
|
listener(view, value, old)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) get(tag string) any {
|
|
||||||
switch tag {
|
|
||||||
case NumberChangedEvent:
|
|
||||||
return picker.numberChangedListeners
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
return picker.dataList.dataList
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return picker.viewData.get(tag)
|
viewPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +202,10 @@ func (picker *numberPickerData) htmlTag() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (picker *numberPickerData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
picker.dataListHtmlSubviews(self, buffer)
|
dataListHtmlSubviews(self, buffer, func(text string, session Session) string {
|
||||||
|
text, _ = session.resolveConstants(text)
|
||||||
|
return text
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builder) {
|
func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
|
@ -317,10 +245,10 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde
|
||||||
|
|
||||||
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
||||||
|
|
||||||
picker.dataListHtmlProperties(picker, buffer)
|
dataListHtmlProperties(picker, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) handleCommand(self View, command string, data DataObject) bool {
|
func (picker *numberPickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyValue("text"); ok {
|
||||||
|
@ -328,9 +256,12 @@ func (picker *numberPickerData) handleCommand(self View, command string, data Da
|
||||||
oldValue := GetNumberPickerValue(picker)
|
oldValue := GetNumberPickerValue(picker)
|
||||||
picker.properties[NumberPickerValue] = text
|
picker.properties[NumberPickerValue] = text
|
||||||
if value != oldValue {
|
if value != oldValue {
|
||||||
for _, listener := range picker.numberChangedListeners {
|
for _, listener := range GetNumberChangedListeners(picker) {
|
||||||
listener(picker, value, oldValue)
|
listener(picker, value, oldValue)
|
||||||
}
|
}
|
||||||
|
if listener, ok := picker.changeListener[NumberPickerValue]; ok {
|
||||||
|
listener(picker, NumberPickerValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
66
outline.go
66
outline.go
|
@ -16,7 +16,7 @@ type OutlineProperty interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type outlinePropertyData struct {
|
type outlinePropertyData struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOutlineProperty creates the new OutlineProperty.
|
// NewOutlineProperty creates the new OutlineProperty.
|
||||||
|
@ -27,22 +27,29 @@ type outlinePropertyData struct {
|
||||||
// "width" (Width). Determines the line thickness (SizeUnit).
|
// "width" (Width). Determines the line thickness (SizeUnit).
|
||||||
func NewOutlineProperty(params Params) OutlineProperty {
|
func NewOutlineProperty(params Params) OutlineProperty {
|
||||||
outline := new(outlinePropertyData)
|
outline := new(outlinePropertyData)
|
||||||
outline.properties = map[string]any{}
|
outline.init()
|
||||||
for tag, value := range params {
|
for tag, value := range params {
|
||||||
outline.Set(tag, value)
|
outline.Set(tag, value)
|
||||||
}
|
}
|
||||||
return outline
|
return outline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (outline *outlinePropertyData) init() {
|
||||||
|
outline.propertyList.init()
|
||||||
|
outline.normalize = normalizeOutlineTag
|
||||||
|
outline.set = outlineSet
|
||||||
|
outline.supportedProperties = []PropertyName{Style, Width, ColorTag}
|
||||||
|
}
|
||||||
|
|
||||||
func (outline *outlinePropertyData) writeString(buffer *strings.Builder, indent string) {
|
func (outline *outlinePropertyData) writeString(buffer *strings.Builder, indent string) {
|
||||||
buffer.WriteString("_{ ")
|
buffer.WriteString("_{ ")
|
||||||
comma := false
|
comma := false
|
||||||
for _, tag := range []string{Style, Width, ColorTag} {
|
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
||||||
if value, ok := outline.properties[tag]; ok {
|
if value, ok := outline.properties[tag]; ok {
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, BorderStyle, value, indent)
|
writePropertyValue(buffer, BorderStyle, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
|
@ -56,46 +63,33 @@ func (outline *outlinePropertyData) String() string {
|
||||||
return runStringWriter(outline)
|
return runStringWriter(outline)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (outline *outlinePropertyData) normalizeTag(tag string) string {
|
func normalizeOutlineTag(tag PropertyName) PropertyName {
|
||||||
return strings.TrimPrefix(strings.ToLower(tag), "outline-")
|
tag = defaultNormalize(tag)
|
||||||
|
return PropertyName(strings.TrimPrefix(string(tag), "outline-"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (outline *outlinePropertyData) Remove(tag string) {
|
func outlineSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
delete(outline.properties, outline.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (outline *outlinePropertyData) Set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
outline.Remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
tag = outline.normalizeTag(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Style:
|
case Style:
|
||||||
return outline.setEnumProperty(Style, value, enumProperties[BorderStyle].values)
|
return setEnumProperty(properties, Style, value, enumProperties[BorderStyle].values)
|
||||||
|
|
||||||
case Width:
|
case Width:
|
||||||
if width, ok := value.(SizeUnit); ok {
|
if width, ok := value.(SizeUnit); ok {
|
||||||
switch width.Type {
|
switch width.Type {
|
||||||
case SizeInFraction, SizeInPercent:
|
case SizeInFraction, SizeInPercent:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return outline.setSizeProperty(Width, value)
|
return setSizeProperty(properties, Width, value)
|
||||||
|
|
||||||
case ColorTag:
|
case ColorTag:
|
||||||
return outline.setColorProperty(ColorTag, value)
|
return setColorProperty(properties, ColorTag, value)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ErrorLogF(`"%s" property is not compatible with the OutlineProperty`, tag)
|
ErrorLogF(`"%s" property is not compatible with the OutlineProperty`, tag)
|
||||||
}
|
}
|
||||||
return false
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
func (outline *outlinePropertyData) Get(tag string) any {
|
|
||||||
return outline.propertyList.Get(outline.normalizeTag(tag))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (outline *outlinePropertyData) ViewOutline(session Session) ViewOutline {
|
func (outline *outlinePropertyData) ViewOutline(session Session) ViewOutline {
|
||||||
|
@ -132,7 +126,7 @@ func (outline ViewOutline) cssString(session Session) string {
|
||||||
return builder.finish()
|
return builder.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOutline(properties Properties) OutlineProperty {
|
func getOutlineProperty(properties Properties) OutlineProperty {
|
||||||
if value := properties.Get(Outline); value != nil {
|
if value := properties.Get(Outline); value != nil {
|
||||||
if outline, ok := value.(OutlineProperty); ok {
|
if outline, ok := value.(OutlineProperty); ok {
|
||||||
return outline
|
return outline
|
||||||
|
@ -142,30 +136,30 @@ func getOutline(properties Properties) OutlineProperty {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) setOutline(value any) bool {
|
func setOutlineProperty(properties Properties, value any) []PropertyName {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case OutlineProperty:
|
case OutlineProperty:
|
||||||
style.properties[Outline] = value
|
properties.setRaw(Outline, value)
|
||||||
|
|
||||||
case ViewOutline:
|
case ViewOutline:
|
||||||
style.properties[Outline] = NewOutlineProperty(Params{Style: value.Style, Width: value.Width, ColorTag: value.Color})
|
properties.setRaw(Outline, NewOutlineProperty(Params{Style: value.Style, Width: value.Width, ColorTag: value.Color}))
|
||||||
|
|
||||||
case ViewBorder:
|
case ViewBorder:
|
||||||
style.properties[Outline] = NewOutlineProperty(Params{Style: value.Style, Width: value.Width, ColorTag: value.Color})
|
properties.setRaw(Outline, NewOutlineProperty(Params{Style: value.Style, Width: value.Width, ColorTag: value.Color}))
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
outline := NewOutlineProperty(nil)
|
outline := NewOutlineProperty(nil)
|
||||||
for _, tag := range []string{Style, Width, ColorTag} {
|
for _, tag := range []PropertyName{Style, Width, ColorTag} {
|
||||||
if text, ok := value.PropertyValue(tag); ok && text != "" {
|
if text, ok := value.PropertyValue(string(tag)); ok && text != "" {
|
||||||
outline.Set(tag, text)
|
outline.Set(tag, text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
style.properties[Outline] = outline
|
properties.setRaw(Outline, outline)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(Outline, value)
|
notCompatibleType(Outline, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{Outline}
|
||||||
}
|
}
|
||||||
|
|
24
params.go
24
params.go
|
@ -3,15 +3,15 @@ package rui
|
||||||
import "sort"
|
import "sort"
|
||||||
|
|
||||||
// Params defines a type of a parameters list
|
// Params defines a type of a parameters list
|
||||||
type Params map[string]any
|
type Params map[PropertyName]any
|
||||||
|
|
||||||
// Get returns a value of the property with name defined by the argument. The type of return value depends
|
// Get returns a value of the property with name defined by the argument. The type of return value depends
|
||||||
// on the property. If the property is not set then nil is returned.
|
// on the property. If the property is not set then nil is returned.
|
||||||
func (params Params) Get(tag string) any {
|
func (params Params) Get(tag PropertyName) any {
|
||||||
return params.getRaw(tag)
|
return params.getRaw(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params Params) getRaw(tag string) any {
|
func (params Params) getRaw(tag PropertyName) any {
|
||||||
if value, ok := params[tag]; ok {
|
if value, ok := params[tag]; ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,12 @@ func (params Params) getRaw(tag string) any {
|
||||||
|
|
||||||
// Set sets the value (second argument) of the property with name defined by the first argument.
|
// Set sets the value (second argument) of the property with name defined by the first argument.
|
||||||
// Return "true" if the value has been set, in the opposite case "false" is returned and a description of an error is written to the log
|
// Return "true" if the value has been set, in the opposite case "false" is returned and a description of an error is written to the log
|
||||||
func (params Params) Set(tag string, value any) bool {
|
func (params Params) Set(tag PropertyName, value any) bool {
|
||||||
params.setRaw(tag, value)
|
params.setRaw(tag, value)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params Params) setRaw(tag string, value any) {
|
func (params Params) setRaw(tag PropertyName, value any) {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
params[tag] = value
|
params[tag] = value
|
||||||
} else {
|
} else {
|
||||||
|
@ -34,7 +34,7 @@ func (params Params) setRaw(tag string, value any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes the property with name defined by the argument from a map.
|
// Remove removes the property with name defined by the argument from a map.
|
||||||
func (params Params) Remove(tag string) {
|
func (params Params) Remove(tag PropertyName) {
|
||||||
delete(params, tag)
|
delete(params, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,11 +46,17 @@ func (params Params) Clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllTags returns a sorted slice of all properties.
|
// AllTags returns a sorted slice of all properties.
|
||||||
func (params Params) AllTags() []string {
|
func (params Params) AllTags() []PropertyName {
|
||||||
tags := make([]string, 0, len(params))
|
tags := make([]PropertyName, 0, len(params))
|
||||||
for t := range params {
|
for t := range params {
|
||||||
tags = append(tags, t)
|
tags = append(tags, t)
|
||||||
}
|
}
|
||||||
sort.Strings(tags)
|
sort.Slice(tags, func(i, j int) bool {
|
||||||
|
return tags[i] < tags[j]
|
||||||
|
})
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (params Params) empty() bool {
|
||||||
|
return len(params) == 0
|
||||||
|
}
|
||||||
|
|
1
path.go
1
path.go
|
@ -55,7 +55,6 @@ type Path interface {
|
||||||
// If the shape has already been closed or has only one point, this function does nothing.
|
// If the shape has already been closed or has only one point, this function does nothing.
|
||||||
Close()
|
Close()
|
||||||
|
|
||||||
//create(session Session)
|
|
||||||
obj() any
|
obj() any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Constants for [View] specific pointer events properties
|
// Constants for [View] specific pointer events properties
|
||||||
const (
|
const (
|
||||||
// PointerDown is the constant for "pointer-down" property tag.
|
// PointerDown is the constant for "pointer-down" property tag.
|
||||||
|
@ -24,7 +20,7 @@ const (
|
||||||
// `func(event rui.PointerEvent)`,
|
// `func(event rui.PointerEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PointerDown = "pointer-down"
|
PointerDown PropertyName = "pointer-down"
|
||||||
|
|
||||||
// PointerUp is the constant for "pointer-up" property tag.
|
// PointerUp is the constant for "pointer-up" property tag.
|
||||||
//
|
//
|
||||||
|
@ -42,7 +38,7 @@ const (
|
||||||
// `func(event rui.PointerEvent)`,
|
// `func(event rui.PointerEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PointerUp = "pointer-up"
|
PointerUp PropertyName = "pointer-up"
|
||||||
|
|
||||||
// PointerMove is the constant for "pointer-move" property tag.
|
// PointerMove is the constant for "pointer-move" property tag.
|
||||||
//
|
//
|
||||||
|
@ -60,7 +56,7 @@ const (
|
||||||
// `func(event rui.PointerEvent)`,
|
// `func(event rui.PointerEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PointerMove = "pointer-move"
|
PointerMove PropertyName = "pointer-move"
|
||||||
|
|
||||||
// PointerCancel is the constant for "pointer-cancel" property tag.
|
// PointerCancel is the constant for "pointer-cancel" property tag.
|
||||||
//
|
//
|
||||||
|
@ -78,7 +74,7 @@ const (
|
||||||
// `func(event rui.PointerEvent)`,
|
// `func(event rui.PointerEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PointerCancel = "pointer-cancel"
|
PointerCancel PropertyName = "pointer-cancel"
|
||||||
|
|
||||||
// PointerOut is the constant for "pointer-out" property tag.
|
// PointerOut is the constant for "pointer-out" property tag.
|
||||||
//
|
//
|
||||||
|
@ -98,7 +94,7 @@ const (
|
||||||
// `func(event rui.PointerEvent)`,
|
// `func(event rui.PointerEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PointerOut = "pointer-out"
|
PointerOut PropertyName = "pointer-out"
|
||||||
|
|
||||||
// PointerOver is the constant for "pointer-over" property tag.
|
// PointerOver is the constant for "pointer-over" property tag.
|
||||||
//
|
//
|
||||||
|
@ -116,7 +112,7 @@ const (
|
||||||
// `func(event rui.PointerEvent)`,
|
// `func(event rui.PointerEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
PointerOver = "pointer-over"
|
PointerOver PropertyName = "pointer-over"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PointerEvent represent a stylus events. Also inherit [MouseEvent] attributes
|
// PointerEvent represent a stylus events. Also inherit [MouseEvent] attributes
|
||||||
|
@ -158,47 +154,33 @@ type PointerEvent struct {
|
||||||
IsPrimary bool
|
IsPrimary bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var pointerEvents = map[string]struct{ jsEvent, jsFunc string }{
|
/*
|
||||||
PointerDown: {jsEvent: "onpointerdown", jsFunc: "pointerDownEvent"},
|
func setPointerListener(properties Properties, tag PropertyName, value any) bool {
|
||||||
PointerUp: {jsEvent: "onpointerup", jsFunc: "pointerUpEvent"},
|
if listeners, ok := valueToEventListeners[View, PointerEvent](value); ok {
|
||||||
PointerMove: {jsEvent: "onpointermove", jsFunc: "pointerMoveEvent"},
|
if len(listeners) == 0 {
|
||||||
PointerCancel: {jsEvent: "onpointercancel", jsFunc: "pointerCancelEvent"},
|
properties.setRaw(tag, nil)
|
||||||
PointerOut: {jsEvent: "onpointerout", jsFunc: "pointerOutEvent"},
|
} else {
|
||||||
PointerOver: {jsEvent: "onpointerover", jsFunc: "pointerOverEvent"},
|
properties.setRaw(tag, listeners)
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) setPointerListener(tag string, value any) bool {
|
|
||||||
listeners, ok := valueToEventListeners[View, PointerEvent](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if listeners == nil {
|
func (view *viewData) removePointerListener(tag PropertyName) {
|
||||||
view.removePointerListener(tag)
|
|
||||||
} else if js, ok := pointerEvents[tag]; ok {
|
|
||||||
view.properties[tag] = listeners
|
|
||||||
if view.created {
|
|
||||||
view.session.updateProperty(view.htmlID(), js.jsEvent, js.jsFunc+"(this, event)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) removePointerListener(tag string) {
|
|
||||||
delete(view.properties, tag)
|
delete(view.properties, tag)
|
||||||
if view.created {
|
if view.created {
|
||||||
if js, ok := pointerEvents[tag]; ok {
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pointerEventsHtml(view View, buffer *strings.Builder) {
|
func pointerEventsHtml(view View, buffer *strings.Builder) {
|
||||||
for tag, js := range pointerEvents {
|
for _, tag := range []PropertyName{PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel} {
|
||||||
if value := view.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
if listeners, ok := value.([]func(View, PointerEvent)); ok && len(listeners) > 0 {
|
if listeners, ok := value.([]func(View, PointerEvent)); ok && len(listeners) > 0 {
|
||||||
buffer.WriteString(js.jsEvent)
|
buffer.WriteString(js.jsEvent)
|
||||||
buffer.WriteString(`="`)
|
buffer.WriteString(`="`)
|
||||||
|
@ -208,6 +190,8 @@ func pointerEventsHtml(view View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (event *PointerEvent) init(data DataObject) {
|
func (event *PointerEvent) init(data DataObject) {
|
||||||
event.MouseEvent.init(data)
|
event.MouseEvent.init(data)
|
||||||
|
@ -225,7 +209,7 @@ func (event *PointerEvent) init(data DataObject) {
|
||||||
event.IsPrimary = dataBoolProperty(data, "isPrimary")
|
event.IsPrimary = dataBoolProperty(data, "isPrimary")
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePointerEvents(view View, tag string, data DataObject) {
|
func handlePointerEvents(view View, tag PropertyName, data DataObject) {
|
||||||
listeners := getEventListeners[View, PointerEvent](view, nil, tag)
|
listeners := getEventListeners[View, PointerEvent](view, nil, tag)
|
||||||
if len(listeners) == 0 {
|
if len(listeners) == 0 {
|
||||||
return
|
return
|
||||||
|
|
22
popup.go
22
popup.go
|
@ -27,7 +27,7 @@ const (
|
||||||
// Set popup title style. Default title style is "ruiPopupTitle".
|
// Set popup title style. Default title style is "ruiPopupTitle".
|
||||||
//
|
//
|
||||||
// Supported types: `string`.
|
// Supported types: `string`.
|
||||||
TitleStyle = "title-style"
|
TitleStyle PropertyName = "title-style"
|
||||||
|
|
||||||
// CloseButton is the constant for "close-button" property tag.
|
// CloseButton is the constant for "close-button" property tag.
|
||||||
//
|
//
|
||||||
|
@ -39,7 +39,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Close button will be added to a title bar of a window.
|
// `true` or `1` or "true", "yes", "on", "1" - Close button will be added to a title bar of a window.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - Popup without a close button.
|
// `false` or `0` or "false", "no", "off", "0" - Popup without a close button.
|
||||||
CloseButton = "close-button"
|
CloseButton PropertyName = "close-button"
|
||||||
|
|
||||||
// OutsideClose is the constant for "outside-close" property tag.
|
// OutsideClose is the constant for "outside-close" property tag.
|
||||||
//
|
//
|
||||||
|
@ -51,7 +51,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Clicking outside the popup window will automatically call the `Dismiss()` method.
|
// `true` or `1` or "true", "yes", "on", "1" - Clicking outside the popup window will automatically call the `Dismiss()` method.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - Clicking outside the popup window has no effect.
|
// `false` or `0` or "false", "no", "off", "0" - Clicking outside the popup window has no effect.
|
||||||
OutsideClose = "outside-close"
|
OutsideClose PropertyName = "outside-close"
|
||||||
|
|
||||||
// Buttons is the constant for "buttons" property tag.
|
// Buttons is the constant for "buttons" property tag.
|
||||||
//
|
//
|
||||||
|
@ -62,7 +62,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `[]PopupButton`, other types converted to it during assignment.
|
// Internal type is `[]PopupButton`, other types converted to it during assignment.
|
||||||
// See `PopupButton` description for more details.
|
// See `PopupButton` description for more details.
|
||||||
Buttons = "buttons"
|
Buttons PropertyName = "buttons"
|
||||||
|
|
||||||
// ButtonsAlign is the constant for "buttons-align" property tag.
|
// ButtonsAlign is the constant for "buttons-align" property tag.
|
||||||
//
|
//
|
||||||
|
@ -76,7 +76,7 @@ const (
|
||||||
// `1`(`RightAlign`) or "right" - Right alignment.
|
// `1`(`RightAlign`) or "right" - Right alignment.
|
||||||
// `2`(`CenterAlign`) or "center" - Center alignment.
|
// `2`(`CenterAlign`) or "center" - Center alignment.
|
||||||
// `3`(`StretchAlign`) or "stretch" - Width alignment.
|
// `3`(`StretchAlign`) or "stretch" - Width alignment.
|
||||||
ButtonsAlign = "buttons-align"
|
ButtonsAlign PropertyName = "buttons-align"
|
||||||
|
|
||||||
// DismissEvent is the constant for "dismiss-event" property tag.
|
// DismissEvent is the constant for "dismiss-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -91,7 +91,7 @@ const (
|
||||||
//
|
//
|
||||||
// Allowed listener formats:
|
// Allowed listener formats:
|
||||||
// `func()`.
|
// `func()`.
|
||||||
DismissEvent = "dismiss-event"
|
DismissEvent PropertyName = "dismiss-event"
|
||||||
|
|
||||||
// Arrow is the constant for "arrow" property tag.
|
// Arrow is the constant for "arrow" property tag.
|
||||||
//
|
//
|
||||||
|
@ -106,7 +106,7 @@ const (
|
||||||
// `2`(`RightArrow`) or "right" - Arrow on the right side of the pop-up window.
|
// `2`(`RightArrow`) or "right" - Arrow on the right side of the pop-up window.
|
||||||
// `3`(`BottomArrow`) or "bottom" - Arrow at the bottom of the pop-up window.
|
// `3`(`BottomArrow`) or "bottom" - Arrow at the bottom of the pop-up window.
|
||||||
// `4`(`LeftArrow`) or "left" - Arrow on the left side of the pop-up window.
|
// `4`(`LeftArrow`) or "left" - Arrow on the left side of the pop-up window.
|
||||||
Arrow = "arrow"
|
Arrow PropertyName = "arrow"
|
||||||
|
|
||||||
// ArrowAlign is the constant for "arrow-align" property tag.
|
// ArrowAlign is the constant for "arrow-align" property tag.
|
||||||
//
|
//
|
||||||
|
@ -119,7 +119,7 @@ const (
|
||||||
// `0`(`TopAlign`/`LeftAlign`) or "top" - Top/left alignment.
|
// `0`(`TopAlign`/`LeftAlign`) or "top" - Top/left alignment.
|
||||||
// `1`(`BottomAlign`/`RightAlign`) or "bottom" - Bottom/right alignment.
|
// `1`(`BottomAlign`/`RightAlign`) or "bottom" - Bottom/right alignment.
|
||||||
// `2`(`CenterAlign`) or "center" - Center alignment.
|
// `2`(`CenterAlign`) or "center" - Center alignment.
|
||||||
ArrowAlign = "arrow-align"
|
ArrowAlign PropertyName = "arrow-align"
|
||||||
|
|
||||||
// ArrowSize is the constant for "arrow-size" property tag.
|
// ArrowSize is the constant for "arrow-size" property tag.
|
||||||
//
|
//
|
||||||
|
@ -130,7 +130,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
ArrowSize = "arrow-size"
|
ArrowSize PropertyName = "arrow-size"
|
||||||
|
|
||||||
// ArrowWidth is the constant for "arrow-width" property tag.
|
// ArrowWidth is the constant for "arrow-width" property tag.
|
||||||
//
|
//
|
||||||
|
@ -141,7 +141,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
ArrowWidth = "arrow-width"
|
ArrowWidth PropertyName = "arrow-width"
|
||||||
|
|
||||||
// ArrowOffset is the constant for "arrow-offset" property tag.
|
// ArrowOffset is the constant for "arrow-offset" property tag.
|
||||||
//
|
//
|
||||||
|
@ -152,7 +152,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
ArrowOffset = "arrow-offset"
|
ArrowOffset PropertyName = "arrow-offset"
|
||||||
|
|
||||||
// NoneArrow is value of the popup "arrow" property: no arrow
|
// NoneArrow is value of the popup "arrow" property: no arrow
|
||||||
NoneArrow = 0
|
NoneArrow = 0
|
||||||
|
|
|
@ -15,7 +15,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
ProgressBarMax = "progress-max"
|
ProgressBarMax PropertyName = "progress-max"
|
||||||
|
|
||||||
// ProgressBarValue is the constant for "progress-value" property tag.
|
// ProgressBarValue is the constant for "progress-value" property tag.
|
||||||
//
|
//
|
||||||
|
@ -25,7 +25,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
ProgressBarValue = "progress-value"
|
ProgressBarValue PropertyName = "progress-value"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProgressBar represents a ProgressBar view
|
// ProgressBar represents a ProgressBar view
|
||||||
|
@ -46,20 +46,18 @@ func NewProgressBar(session Session, params Params) ProgressBar {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProgressBar(session Session) View {
|
func newProgressBar(session Session) View {
|
||||||
return NewProgressBar(session, nil)
|
return new(progressBarData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (progress *progressBarData) init(session Session) {
|
func (progress *progressBarData) init(session Session) {
|
||||||
progress.viewData.init(session)
|
progress.viewData.init(session)
|
||||||
progress.tag = "ProgressBar"
|
progress.tag = "ProgressBar"
|
||||||
|
progress.normalize = normalizeProgressBarTag
|
||||||
|
progress.changed = progressBarPropertyChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
func (progress *progressBarData) String() string {
|
func normalizeProgressBarTag(tag PropertyName) PropertyName {
|
||||||
return getViewString(progress, nil)
|
tag = defaultNormalize(tag)
|
||||||
}
|
|
||||||
|
|
||||||
func (progress *progressBarData) normalizeTag(tag string) string {
|
|
||||||
tag = strings.ToLower(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Max, "progress-bar-max", "progressbar-max":
|
case Max, "progress-bar-max", "progressbar-max":
|
||||||
return ProgressBarMax
|
return ProgressBarMax
|
||||||
|
@ -70,43 +68,20 @@ func (progress *progressBarData) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (progress *progressBarData) Remove(tag string) {
|
func progressBarPropertyChanged(view View, tag PropertyName) {
|
||||||
progress.remove(progress.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (progress *progressBarData) remove(tag string) {
|
|
||||||
progress.viewData.remove(tag)
|
|
||||||
progress.propertyChanged(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (progress *progressBarData) propertyChanged(tag string) {
|
|
||||||
if progress.created {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case ProgressBarMax:
|
case ProgressBarMax:
|
||||||
progress.session.updateProperty(progress.htmlID(), Max,
|
view.Session().updateProperty(view.htmlID(), "max",
|
||||||
strconv.FormatFloat(GetProgressBarMax(progress), 'f', -1, 32))
|
strconv.FormatFloat(GetProgressBarMax(view), 'f', -1, 32))
|
||||||
|
|
||||||
case ProgressBarValue:
|
case ProgressBarValue:
|
||||||
progress.session.updateProperty(progress.htmlID(), Value,
|
view.Session().updateProperty(view.htmlID(), "value",
|
||||||
strconv.FormatFloat(GetProgressBarValue(progress), 'f', -1, 32))
|
strconv.FormatFloat(GetProgressBarValue(view), 'f', -1, 32))
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (progress *progressBarData) Set(tag string, value any) bool {
|
default:
|
||||||
return progress.set(progress.normalizeTag(tag), value)
|
viewPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (progress *progressBarData) set(tag string, value any) bool {
|
|
||||||
if progress.viewData.set(tag, value) {
|
|
||||||
progress.propertyChanged(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (progress *progressBarData) Get(tag string) any {
|
|
||||||
return progress.get(progress.normalizeTag(tag))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (progress *progressBarData) htmlTag() string {
|
func (progress *progressBarData) htmlTag() string {
|
||||||
|
|
110
properties.go
110
properties.go
|
@ -9,71 +9,96 @@ import (
|
||||||
type Properties interface {
|
type Properties interface {
|
||||||
// Get returns a value of the property with name defined by the argument.
|
// Get returns a value of the property with name defined by the argument.
|
||||||
// The type of return value depends on the property. If the property is not set then nil is returned.
|
// The type of return value depends on the property. If the property is not set then nil is returned.
|
||||||
Get(tag string) any
|
Get(tag PropertyName) any
|
||||||
getRaw(tag string) any
|
getRaw(tag PropertyName) any
|
||||||
|
|
||||||
// Set sets the value (second argument) of the property with name defined by the first argument.
|
// Set sets the value (second argument) of the property with name defined by the first argument.
|
||||||
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
||||||
// a description of the error is written to the log
|
// a description of the error is written to the log
|
||||||
Set(tag string, value any) bool
|
Set(tag PropertyName, value any) bool
|
||||||
setRaw(tag string, value any)
|
setRaw(tag PropertyName, value any)
|
||||||
|
|
||||||
// Remove removes the property with name defined by the argument
|
// Remove removes the property with name defined by the argument
|
||||||
Remove(tag string)
|
Remove(tag PropertyName)
|
||||||
|
|
||||||
// Clear removes all properties
|
// Clear removes all properties
|
||||||
Clear()
|
Clear()
|
||||||
|
|
||||||
// AllTags returns an array of the set properties
|
// AllTags returns an array of the set properties
|
||||||
AllTags() []string
|
AllTags() []PropertyName
|
||||||
|
|
||||||
|
empty() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type propertyList struct {
|
type propertyList struct {
|
||||||
properties map[string]any
|
properties map[PropertyName]any
|
||||||
|
normalize func(PropertyName) PropertyName
|
||||||
|
//getFunc func(PropertyName) any
|
||||||
|
//set func(Properties, PropertyName, any) []PropertyName
|
||||||
|
//remove func(Properties, PropertyName) []PropertyName
|
||||||
|
}
|
||||||
|
|
||||||
|
type dataProperty struct {
|
||||||
|
propertyList
|
||||||
|
supportedProperties []PropertyName
|
||||||
|
get func(Properties, PropertyName) any
|
||||||
|
set func(Properties, PropertyName, any) []PropertyName
|
||||||
|
remove func(Properties, PropertyName) []PropertyName
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultNormalize(tag PropertyName) PropertyName {
|
||||||
|
return PropertyName(strings.ToLower(strings.Trim(string(tag), " \t")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) init() {
|
func (properties *propertyList) init() {
|
||||||
properties.properties = map[string]any{}
|
properties.properties = map[PropertyName]any{}
|
||||||
|
properties.normalize = defaultNormalize
|
||||||
|
//properties.getFunc = properties.getRaw
|
||||||
|
//properties.set = propertiesSet
|
||||||
|
//properties.remove = propertiesRemove
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) Get(tag string) any {
|
func (properties *propertyList) empty() bool {
|
||||||
return properties.getRaw(strings.ToLower(tag))
|
return len(properties.properties) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) getRaw(tag string) any {
|
func (properties *propertyList) getRaw(tag PropertyName) any {
|
||||||
if value, ok := properties.properties[tag]; ok {
|
if value, ok := properties.properties[tag]; ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setRaw(tag string, value any) {
|
func (properties *propertyList) setRaw(tag PropertyName, value any) {
|
||||||
|
if value == nil {
|
||||||
|
delete(properties.properties, tag)
|
||||||
|
} else {
|
||||||
properties.properties[tag] = value
|
properties.properties[tag] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) Remove(tag string) {
|
|
||||||
delete(properties.properties, strings.ToLower(tag))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) remove(tag string) {
|
/*
|
||||||
delete(properties.properties, tag)
|
func (properties *propertyList) Remove(tag PropertyName) {
|
||||||
|
properties.remove(properties, properties.normalize(tag))
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
func (properties *propertyList) Clear() {
|
func (properties *propertyList) Clear() {
|
||||||
properties.properties = map[string]any{}
|
properties.properties = map[PropertyName]any{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) AllTags() []string {
|
func (properties *propertyList) AllTags() []PropertyName {
|
||||||
tags := make([]string, 0, len(properties.properties))
|
tags := make([]PropertyName, 0, len(properties.properties))
|
||||||
for t := range properties.properties {
|
for tag := range properties.properties {
|
||||||
tags = append(tags, t)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
sort.Strings(tags)
|
sort.Slice(tags, func(i, j int) bool {
|
||||||
|
return tags[i] < tags[j]
|
||||||
|
})
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) writeToBuffer(buffer *strings.Builder,
|
func (properties *propertyList) writeToBuffer(buffer *strings.Builder,
|
||||||
indent string, objectTag string, tags []string) {
|
indent string, objectTag string, tags []PropertyName) {
|
||||||
|
|
||||||
buffer.WriteString(objectTag)
|
buffer.WriteString(objectTag)
|
||||||
buffer.WriteString(" {\n")
|
buffer.WriteString(" {\n")
|
||||||
|
@ -83,7 +108,7 @@ func (properties *propertyList) writeToBuffer(buffer *strings.Builder,
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if value, ok := properties.properties[tag]; ok {
|
if value, ok := properties.properties[tag]; ok {
|
||||||
buffer.WriteString(indent2)
|
buffer.WriteString(indent2)
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent2)
|
writePropertyValue(buffer, tag, value, indent2)
|
||||||
buffer.WriteString(",\n")
|
buffer.WriteString(",\n")
|
||||||
|
@ -100,14 +125,41 @@ func parseProperties(properties Properties, object DataObject) {
|
||||||
if node := object.Property(i); node != nil {
|
if node := object.Property(i); node != nil {
|
||||||
switch node.Type() {
|
switch node.Type() {
|
||||||
case TextNode:
|
case TextNode:
|
||||||
properties.Set(node.Tag(), node.Text())
|
properties.Set(PropertyName(node.Tag()), node.Text())
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectNode:
|
||||||
properties.Set(node.Tag(), node.Object())
|
properties.Set(PropertyName(node.Tag()), node.Object())
|
||||||
|
|
||||||
case ArrayNode:
|
case ArrayNode:
|
||||||
properties.Set(node.Tag(), node.ArrayElements())
|
properties.Set(PropertyName(node.Tag()), node.ArrayElements())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func propertiesGet(properties Properties, tag PropertyName) any {
|
||||||
|
return properties.getRaw(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func propertiesRemove(properties Properties, tag PropertyName) []PropertyName {
|
||||||
|
if properties.getRaw(tag) == nil {
|
||||||
|
return []PropertyName{}
|
||||||
|
}
|
||||||
|
properties.setRaw(tag, nil)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *dataProperty) init() {
|
||||||
|
data.propertyList.init()
|
||||||
|
data.get = propertiesGet
|
||||||
|
data.set = propertiesSet
|
||||||
|
data.remove = propertiesRemove
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *dataProperty) Get(tag PropertyName) any {
|
||||||
|
return propertiesGet(data, data.normalize(tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *dataProperty) Remove(tag PropertyName) {
|
||||||
|
data.remove(data, data.normalize(tag))
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func stringProperty(properties Properties, tag string, session Session) (string, bool) {
|
func stringProperty(properties Properties, tag PropertyName, session Session) (string, bool) {
|
||||||
if value := properties.getRaw(tag); value != nil {
|
if value := properties.getRaw(tag); value != nil {
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
return session.resolveConstants(text)
|
return session.resolveConstants(text)
|
||||||
|
@ -15,7 +15,7 @@ func stringProperty(properties Properties, tag string, session Session) (string,
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func imageProperty(properties Properties, tag string, session Session) (string, bool) {
|
func imageProperty(properties Properties, tag PropertyName, session Session) (string, bool) {
|
||||||
if value := properties.getRaw(tag); value != nil {
|
if value := properties.getRaw(tag); value != nil {
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
if text != "" && text[0] == '@' {
|
if text != "" && text[0] == '@' {
|
||||||
|
@ -61,11 +61,11 @@ func valueToSizeUnit(value any, session Session) (SizeUnit, bool) {
|
||||||
return AutoSize(), false
|
return AutoSize(), false
|
||||||
}
|
}
|
||||||
|
|
||||||
func sizeProperty(properties Properties, tag string, session Session) (SizeUnit, bool) {
|
func sizeProperty(properties Properties, tag PropertyName, session Session) (SizeUnit, bool) {
|
||||||
return valueToSizeUnit(properties.getRaw(tag), session)
|
return valueToSizeUnit(properties.getRaw(tag), session)
|
||||||
}
|
}
|
||||||
|
|
||||||
func angleProperty(properties Properties, tag string, session Session) (AngleUnit, bool) {
|
func angleProperty(properties Properties, tag PropertyName, session Session) (AngleUnit, bool) {
|
||||||
if value := properties.getRaw(tag); value != nil {
|
if value := properties.getRaw(tag); value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case AngleUnit:
|
case AngleUnit:
|
||||||
|
@ -98,11 +98,11 @@ func valueToColor(value any, session Session) (Color, bool) {
|
||||||
return Color(0), false
|
return Color(0), false
|
||||||
}
|
}
|
||||||
|
|
||||||
func colorProperty(properties Properties, tag string, session Session) (Color, bool) {
|
func colorProperty(properties Properties, tag PropertyName, session Session) (Color, bool) {
|
||||||
return valueToColor(properties.getRaw(tag), session)
|
return valueToColor(properties.getRaw(tag), session)
|
||||||
}
|
}
|
||||||
|
|
||||||
func valueToEnum(value any, tag string, session Session, defaultValue int) (int, bool) {
|
func valueToEnum(value any, tag PropertyName, session Session, defaultValue int) (int, bool) {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
values := enumProperties[tag].values
|
values := enumProperties[tag].values
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
@ -165,7 +165,7 @@ func enumStringToInt(value string, enumValues []string, logError bool) (int, boo
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func enumProperty(properties Properties, tag string, session Session, defaultValue int) (int, bool) {
|
func enumProperty(properties Properties, tag PropertyName, session Session, defaultValue int) (int, bool) {
|
||||||
return valueToEnum(properties.getRaw(tag), tag, session, defaultValue)
|
return valueToEnum(properties.getRaw(tag), tag, session, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ func valueToBool(value any, session Session) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func boolProperty(properties Properties, tag string, session Session) (bool, bool) {
|
func boolProperty(properties Properties, tag PropertyName, session Session) (bool, bool) {
|
||||||
return valueToBool(properties.getRaw(tag), session)
|
return valueToBool(properties.getRaw(tag), session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ func valueToInt(value any, session Session, defaultValue int) (int, bool) {
|
||||||
return defaultValue, false
|
return defaultValue, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func intProperty(properties Properties, tag string, session Session, defaultValue int) (int, bool) {
|
func intProperty(properties Properties, tag PropertyName, session Session, defaultValue int) (int, bool) {
|
||||||
return valueToInt(properties.getRaw(tag), session, defaultValue)
|
return valueToInt(properties.getRaw(tag), session, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ func valueToFloat(value any, session Session, defaultValue float64) (float64, bo
|
||||||
return defaultValue, false
|
return defaultValue, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func floatProperty(properties Properties, tag string, session Session, defaultValue float64) (float64, bool) {
|
func floatProperty(properties Properties, tag PropertyName, session Session, defaultValue float64) (float64, bool) {
|
||||||
return valueToFloat(properties.getRaw(tag), session, defaultValue)
|
return valueToFloat(properties.getRaw(tag), session, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ func valueToFloatText(value any, session Session, defaultValue float64) (string,
|
||||||
return fmt.Sprintf("%g", defaultValue), false
|
return fmt.Sprintf("%g", defaultValue), false
|
||||||
}
|
}
|
||||||
|
|
||||||
func floatTextProperty(properties Properties, tag string, session Session, defaultValue float64) (string, bool) {
|
func floatTextProperty(properties Properties, tag PropertyName, session Session, defaultValue float64) (string, bool) {
|
||||||
return valueToFloatText(properties.getRaw(tag), session, defaultValue)
|
return valueToFloatText(properties.getRaw(tag), session, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,6 +297,6 @@ func valueToRange(value any, session Session) (Range, bool) {
|
||||||
return Range{}, false
|
return Range{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func rangeProperty(properties Properties, tag string, session Session) (Range, bool) {
|
func rangeProperty(properties Properties, tag PropertyName, session Session) (Range, bool) {
|
||||||
return valueToRange(properties.getRaw(tag), session)
|
return valueToRange(properties.getRaw(tag), session)
|
||||||
}
|
}
|
||||||
|
|
346
propertyNames.go
346
propertyNames.go
File diff suppressed because it is too large
Load Diff
385
propertySet.go
385
propertySet.go
|
@ -6,7 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var colorProperties = []string{
|
var colorProperties = []PropertyName{
|
||||||
ColorTag,
|
ColorTag,
|
||||||
BackgroundColor,
|
BackgroundColor,
|
||||||
TextColor,
|
TextColor,
|
||||||
|
@ -21,7 +21,7 @@ var colorProperties = []string{
|
||||||
ColorPickerValue,
|
ColorPickerValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPropertyInList(tag string, list []string) bool {
|
func isPropertyInList(tag PropertyName, list []PropertyName) bool {
|
||||||
for _, prop := range list {
|
for _, prop := range list {
|
||||||
if prop == tag {
|
if prop == tag {
|
||||||
return true
|
return true
|
||||||
|
@ -30,11 +30,11 @@ func isPropertyInList(tag string, list []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var angleProperties = []string{
|
var angleProperties = []PropertyName{
|
||||||
From,
|
From,
|
||||||
}
|
}
|
||||||
|
|
||||||
var boolProperties = []string{
|
var boolProperties = []PropertyName{
|
||||||
Disabled,
|
Disabled,
|
||||||
Focusable,
|
Focusable,
|
||||||
Inset,
|
Inset,
|
||||||
|
@ -63,7 +63,7 @@ var boolProperties = []string{
|
||||||
ColumnSpanAll,
|
ColumnSpanAll,
|
||||||
}
|
}
|
||||||
|
|
||||||
var intProperties = []string{
|
var intProperties = []PropertyName{
|
||||||
ZIndex,
|
ZIndex,
|
||||||
TabSize,
|
TabSize,
|
||||||
HeadHeight,
|
HeadHeight,
|
||||||
|
@ -73,9 +73,10 @@ var intProperties = []string{
|
||||||
ColumnCount,
|
ColumnCount,
|
||||||
Order,
|
Order,
|
||||||
TabIndex,
|
TabIndex,
|
||||||
|
MaxLength,
|
||||||
}
|
}
|
||||||
|
|
||||||
var floatProperties = map[string]struct{ min, max float64 }{
|
var floatProperties = map[PropertyName]struct{ min, max float64 }{
|
||||||
Opacity: {min: 0, max: 1},
|
Opacity: {min: 0, max: 1},
|
||||||
NumberPickerMax: {min: -math.MaxFloat64, max: math.MaxFloat64},
|
NumberPickerMax: {min: -math.MaxFloat64, max: math.MaxFloat64},
|
||||||
NumberPickerMin: {min: -math.MaxFloat64, max: math.MaxFloat64},
|
NumberPickerMin: {min: -math.MaxFloat64, max: math.MaxFloat64},
|
||||||
|
@ -87,79 +88,79 @@ var floatProperties = map[string]struct{ min, max float64 }{
|
||||||
VideoHeight: {min: 0, max: 10000},
|
VideoHeight: {min: 0, max: 10000},
|
||||||
}
|
}
|
||||||
|
|
||||||
var sizeProperties = map[string]string{
|
var sizeProperties = map[PropertyName]string{
|
||||||
Width: Width,
|
Width: string(Width),
|
||||||
Height: Height,
|
Height: string(Height),
|
||||||
MinWidth: MinWidth,
|
MinWidth: string(MinWidth),
|
||||||
MinHeight: MinHeight,
|
MinHeight: string(MinHeight),
|
||||||
MaxWidth: MaxWidth,
|
MaxWidth: string(MaxWidth),
|
||||||
MaxHeight: MaxHeight,
|
MaxHeight: string(MaxHeight),
|
||||||
Left: Left,
|
Left: string(Left),
|
||||||
Right: Right,
|
Right: string(Right),
|
||||||
Top: Top,
|
Top: string(Top),
|
||||||
Bottom: Bottom,
|
Bottom: string(Bottom),
|
||||||
TextSize: "font-size",
|
TextSize: "font-size",
|
||||||
TextIndent: TextIndent,
|
TextIndent: string(TextIndent),
|
||||||
LetterSpacing: LetterSpacing,
|
LetterSpacing: string(LetterSpacing),
|
||||||
WordSpacing: WordSpacing,
|
WordSpacing: string(WordSpacing),
|
||||||
LineHeight: LineHeight,
|
LineHeight: string(LineHeight),
|
||||||
TextLineThickness: "text-decoration-thickness",
|
TextLineThickness: "text-decoration-thickness",
|
||||||
ListRowGap: "row-gap",
|
ListRowGap: "row-gap",
|
||||||
ListColumnGap: "column-gap",
|
ListColumnGap: "column-gap",
|
||||||
GridRowGap: GridRowGap,
|
GridRowGap: string(GridRowGap),
|
||||||
GridColumnGap: GridColumnGap,
|
GridColumnGap: string(GridColumnGap),
|
||||||
ColumnWidth: ColumnWidth,
|
ColumnWidth: string(ColumnWidth),
|
||||||
ColumnGap: ColumnGap,
|
ColumnGap: string(ColumnGap),
|
||||||
Gap: Gap,
|
Gap: string(Gap),
|
||||||
Margin: Margin,
|
Margin: string(Margin),
|
||||||
MarginLeft: MarginLeft,
|
MarginLeft: string(MarginLeft),
|
||||||
MarginRight: MarginRight,
|
MarginRight: string(MarginRight),
|
||||||
MarginTop: MarginTop,
|
MarginTop: string(MarginTop),
|
||||||
MarginBottom: MarginBottom,
|
MarginBottom: string(MarginBottom),
|
||||||
Padding: Padding,
|
Padding: string(Padding),
|
||||||
PaddingLeft: PaddingLeft,
|
PaddingLeft: string(PaddingLeft),
|
||||||
PaddingRight: PaddingRight,
|
PaddingRight: string(PaddingRight),
|
||||||
PaddingTop: PaddingTop,
|
PaddingTop: string(PaddingTop),
|
||||||
PaddingBottom: PaddingBottom,
|
PaddingBottom: string(PaddingBottom),
|
||||||
BorderWidth: BorderWidth,
|
BorderWidth: string(BorderWidth),
|
||||||
BorderLeftWidth: BorderLeftWidth,
|
BorderLeftWidth: string(BorderLeftWidth),
|
||||||
BorderRightWidth: BorderRightWidth,
|
BorderRightWidth: string(BorderRightWidth),
|
||||||
BorderTopWidth: BorderTopWidth,
|
BorderTopWidth: string(BorderTopWidth),
|
||||||
BorderBottomWidth: BorderBottomWidth,
|
BorderBottomWidth: string(BorderBottomWidth),
|
||||||
OutlineWidth: OutlineWidth,
|
OutlineWidth: string(OutlineWidth),
|
||||||
OutlineOffset: OutlineOffset,
|
OutlineOffset: string(OutlineOffset),
|
||||||
XOffset: XOffset,
|
XOffset: string(XOffset),
|
||||||
YOffset: YOffset,
|
YOffset: string(YOffset),
|
||||||
BlurRadius: BlurRadius,
|
BlurRadius: string(BlurRadius),
|
||||||
SpreadRadius: SpreadRadius,
|
SpreadRadius: string(SpreadRadius),
|
||||||
Perspective: Perspective,
|
Perspective: string(Perspective),
|
||||||
PerspectiveOriginX: PerspectiveOriginX,
|
PerspectiveOriginX: string(PerspectiveOriginX),
|
||||||
PerspectiveOriginY: PerspectiveOriginY,
|
PerspectiveOriginY: string(PerspectiveOriginY),
|
||||||
OriginX: OriginX,
|
OriginX: string(OriginX),
|
||||||
OriginY: OriginY,
|
OriginY: string(OriginY),
|
||||||
OriginZ: OriginZ,
|
OriginZ: string(OriginZ),
|
||||||
Radius: Radius,
|
Radius: string(Radius),
|
||||||
RadiusX: RadiusX,
|
RadiusX: string(RadiusX),
|
||||||
RadiusY: RadiusY,
|
RadiusY: string(RadiusY),
|
||||||
RadiusTopLeft: RadiusTopLeft,
|
RadiusTopLeft: string(RadiusTopLeft),
|
||||||
RadiusTopLeftX: RadiusTopLeftX,
|
RadiusTopLeftX: string(RadiusTopLeftX),
|
||||||
RadiusTopLeftY: RadiusTopLeftY,
|
RadiusTopLeftY: string(RadiusTopLeftY),
|
||||||
RadiusTopRight: RadiusTopRight,
|
RadiusTopRight: string(RadiusTopRight),
|
||||||
RadiusTopRightX: RadiusTopRightX,
|
RadiusTopRightX: string(RadiusTopRightX),
|
||||||
RadiusTopRightY: RadiusTopRightY,
|
RadiusTopRightY: string(RadiusTopRightY),
|
||||||
RadiusBottomLeft: RadiusBottomLeft,
|
RadiusBottomLeft: string(RadiusBottomLeft),
|
||||||
RadiusBottomLeftX: RadiusBottomLeftX,
|
RadiusBottomLeftX: string(RadiusBottomLeftX),
|
||||||
RadiusBottomLeftY: RadiusBottomLeftY,
|
RadiusBottomLeftY: string(RadiusBottomLeftY),
|
||||||
RadiusBottomRight: RadiusBottomRight,
|
RadiusBottomRight: string(RadiusBottomRight),
|
||||||
RadiusBottomRightX: RadiusBottomRightX,
|
RadiusBottomRightX: string(RadiusBottomRightX),
|
||||||
RadiusBottomRightY: RadiusBottomRightY,
|
RadiusBottomRightY: string(RadiusBottomRightY),
|
||||||
ItemWidth: ItemWidth,
|
ItemWidth: string(ItemWidth),
|
||||||
ItemHeight: ItemHeight,
|
ItemHeight: string(ItemHeight),
|
||||||
CenterX: CenterX,
|
CenterX: string(CenterX),
|
||||||
CenterY: CenterX,
|
CenterY: string(CenterX),
|
||||||
}
|
}
|
||||||
|
|
||||||
var enumProperties = map[string]struct {
|
var enumProperties = map[PropertyName]struct {
|
||||||
values []string
|
values []string
|
||||||
cssTag string
|
cssTag string
|
||||||
cssValues []string
|
cssValues []string
|
||||||
|
@ -176,17 +177,17 @@ var enumProperties = map[string]struct {
|
||||||
},
|
},
|
||||||
Overflow: {
|
Overflow: {
|
||||||
[]string{"hidden", "visible", "scroll", "auto"},
|
[]string{"hidden", "visible", "scroll", "auto"},
|
||||||
Overflow,
|
string(Overflow),
|
||||||
[]string{"hidden", "visible", "scroll", "auto"},
|
[]string{"hidden", "visible", "scroll", "auto"},
|
||||||
},
|
},
|
||||||
TextAlign: {
|
TextAlign: {
|
||||||
[]string{"left", "right", "center", "justify"},
|
[]string{"left", "right", "center", "justify"},
|
||||||
TextAlign,
|
string(TextAlign),
|
||||||
[]string{"left", "right", "center", "justify"},
|
[]string{"left", "right", "center", "justify"},
|
||||||
},
|
},
|
||||||
TextTransform: {
|
TextTransform: {
|
||||||
[]string{"none", "capitalize", "lowercase", "uppercase"},
|
[]string{"none", "capitalize", "lowercase", "uppercase"},
|
||||||
TextTransform,
|
string(TextTransform),
|
||||||
[]string{"none", "capitalize", "lowercase", "uppercase"},
|
[]string{"none", "capitalize", "lowercase", "uppercase"},
|
||||||
},
|
},
|
||||||
TextWeight: {
|
TextWeight: {
|
||||||
|
@ -196,27 +197,27 @@ var enumProperties = map[string]struct {
|
||||||
},
|
},
|
||||||
WhiteSpace: {
|
WhiteSpace: {
|
||||||
[]string{"normal", "nowrap", "pre", "pre-wrap", "pre-line", "break-spaces"},
|
[]string{"normal", "nowrap", "pre", "pre-wrap", "pre-line", "break-spaces"},
|
||||||
WhiteSpace,
|
string(WhiteSpace),
|
||||||
[]string{"normal", "nowrap", "pre", "pre-wrap", "pre-line", "break-spaces"},
|
[]string{"normal", "nowrap", "pre", "pre-wrap", "pre-line", "break-spaces"},
|
||||||
},
|
},
|
||||||
WordBreak: {
|
WordBreak: {
|
||||||
[]string{"normal", "break-all", "keep-all", "break-word"},
|
[]string{"normal", "break-all", "keep-all", "break-word"},
|
||||||
WordBreak,
|
string(WordBreak),
|
||||||
[]string{"normal", "break-all", "keep-all", "break-word"},
|
[]string{"normal", "break-all", "keep-all", "break-word"},
|
||||||
},
|
},
|
||||||
TextOverflow: {
|
TextOverflow: {
|
||||||
[]string{"clip", "ellipsis"},
|
[]string{"clip", "ellipsis"},
|
||||||
TextOverflow,
|
string(TextOverflow),
|
||||||
[]string{"clip", "ellipsis"},
|
[]string{"clip", "ellipsis"},
|
||||||
},
|
},
|
||||||
TextWrap: {
|
TextWrap: {
|
||||||
[]string{"wrap", "nowrap", "balance"},
|
[]string{"wrap", "nowrap", "balance"},
|
||||||
TextWrap,
|
string(TextWrap),
|
||||||
[]string{"wrap", "nowrap", "balance"},
|
[]string{"wrap", "nowrap", "balance"},
|
||||||
},
|
},
|
||||||
WritingMode: {
|
WritingMode: {
|
||||||
[]string{"horizontal-top-to-bottom", "horizontal-bottom-to-top", "vertical-right-to-left", "vertical-left-to-right"},
|
[]string{"horizontal-top-to-bottom", "horizontal-bottom-to-top", "vertical-right-to-left", "vertical-left-to-right"},
|
||||||
WritingMode,
|
string(WritingMode),
|
||||||
[]string{"horizontal-tb", "horizontal-bt", "vertical-rl", "vertical-lr"},
|
[]string{"horizontal-tb", "horizontal-bt", "vertical-rl", "vertical-lr"},
|
||||||
},
|
},
|
||||||
TextDirection: {
|
TextDirection: {
|
||||||
|
@ -236,7 +237,7 @@ var enumProperties = map[string]struct {
|
||||||
},
|
},
|
||||||
BorderStyle: {
|
BorderStyle: {
|
||||||
[]string{"none", "solid", "dashed", "dotted", "double"},
|
[]string{"none", "solid", "dashed", "dotted", "double"},
|
||||||
BorderStyle,
|
string(BorderStyle),
|
||||||
[]string{"none", "solid", "dashed", "dotted", "double"},
|
[]string{"none", "solid", "dashed", "dotted", "double"},
|
||||||
},
|
},
|
||||||
TopStyle: {
|
TopStyle: {
|
||||||
|
@ -261,7 +262,7 @@ var enumProperties = map[string]struct {
|
||||||
},
|
},
|
||||||
OutlineStyle: {
|
OutlineStyle: {
|
||||||
[]string{"none", "solid", "dashed", "dotted", "double"},
|
[]string{"none", "solid", "dashed", "dotted", "double"},
|
||||||
OutlineStyle,
|
string(OutlineStyle),
|
||||||
[]string{"none", "solid", "dashed", "dotted", "double"},
|
[]string{"none", "solid", "dashed", "dotted", "double"},
|
||||||
},
|
},
|
||||||
Tabs: {
|
Tabs: {
|
||||||
|
@ -336,7 +337,7 @@ var enumProperties = map[string]struct {
|
||||||
},
|
},
|
||||||
GridAutoFlow: {
|
GridAutoFlow: {
|
||||||
[]string{"row", "column", "row-dense", "column-dense"},
|
[]string{"row", "column", "row-dense", "column-dense"},
|
||||||
GridAutoFlow,
|
string(GridAutoFlow),
|
||||||
[]string{"row", "column", "row dense", "column dense"},
|
[]string{"row", "column", "row dense", "column dense"},
|
||||||
},
|
},
|
||||||
ImageVerticalAlign: {
|
ImageVerticalAlign: {
|
||||||
|
@ -376,7 +377,7 @@ var enumProperties = map[string]struct {
|
||||||
},
|
},
|
||||||
Cursor: {
|
Cursor: {
|
||||||
[]string{"auto", "default", "none", "context-menu", "help", "pointer", "progress", "wait", "cell", "crosshair", "text", "vertical-text", "alias", "copy", "move", "no-drop", "not-allowed", "e-resize", "n-resize", "ne-resize", "nw-resize", "s-resize", "se-resize", "sw-resize", "w-resize", "ew-resize", "ns-resize", "nesw-resize", "nwse-resize", "col-resize", "row-resize", "all-scroll", "zoom-in", "zoom-out", "grab", "grabbing"},
|
[]string{"auto", "default", "none", "context-menu", "help", "pointer", "progress", "wait", "cell", "crosshair", "text", "vertical-text", "alias", "copy", "move", "no-drop", "not-allowed", "e-resize", "n-resize", "ne-resize", "nw-resize", "s-resize", "se-resize", "sw-resize", "w-resize", "ew-resize", "ns-resize", "nesw-resize", "nwse-resize", "col-resize", "row-resize", "all-scroll", "zoom-in", "zoom-out", "grab", "grabbing"},
|
||||||
Cursor,
|
string(Cursor),
|
||||||
[]string{"auto", "default", "none", "context-menu", "help", "pointer", "progress", "wait", "cell", "crosshair", "text", "vertical-text", "alias", "copy", "move", "no-drop", "not-allowed", "e-resize", "n-resize", "ne-resize", "nw-resize", "s-resize", "se-resize", "sw-resize", "w-resize", "ew-resize", "ns-resize", "nesw-resize", "nwse-resize", "col-resize", "row-resize", "all-scroll", "zoom-in", "zoom-out", "grab", "grabbing"},
|
[]string{"auto", "default", "none", "context-menu", "help", "pointer", "progress", "wait", "cell", "crosshair", "text", "vertical-text", "alias", "copy", "move", "no-drop", "not-allowed", "e-resize", "n-resize", "ne-resize", "nw-resize", "s-resize", "se-resize", "sw-resize", "w-resize", "ew-resize", "ns-resize", "nesw-resize", "nwse-resize", "col-resize", "row-resize", "all-scroll", "zoom-in", "zoom-out", "grab", "grabbing"},
|
||||||
},
|
},
|
||||||
Fit: {
|
Fit: {
|
||||||
|
@ -456,27 +457,27 @@ var enumProperties = map[string]struct {
|
||||||
},
|
},
|
||||||
MixBlendMode: {
|
MixBlendMode: {
|
||||||
[]string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"},
|
[]string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"},
|
||||||
MixBlendMode,
|
string(MixBlendMode),
|
||||||
[]string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"},
|
[]string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"},
|
||||||
},
|
},
|
||||||
BackgroundBlendMode: {
|
BackgroundBlendMode: {
|
||||||
[]string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"},
|
[]string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"},
|
||||||
BackgroundBlendMode,
|
string(BackgroundBlendMode),
|
||||||
[]string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"},
|
[]string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"},
|
||||||
},
|
},
|
||||||
ColumnFill: {
|
ColumnFill: {
|
||||||
[]string{"balance", "auto"},
|
[]string{"balance", "auto"},
|
||||||
ColumnFill,
|
string(ColumnFill),
|
||||||
[]string{"balance", "auto"},
|
[]string{"balance", "auto"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func notCompatibleType(tag string, value any) {
|
func notCompatibleType(tag PropertyName, value any) {
|
||||||
ErrorLogF(`"%T" type not compatible with "%s" property`, value, tag)
|
ErrorLogF(`"%T" type not compatible with "%s" property`, value, string(tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
func invalidPropertyValue(tag string, value any) {
|
func invalidPropertyValue(tag PropertyName, value any) {
|
||||||
ErrorLogF(`Invalid value "%v" of "%s" property`, value, tag)
|
ErrorLogF(`Invalid value "%v" of "%s" property`, value, string(tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
func isConstantName(text string) bool {
|
func isConstantName(text string) bool {
|
||||||
|
@ -537,26 +538,48 @@ func isInt(value any) (int, bool) {
|
||||||
return n, true
|
return n, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setSimpleProperty(tag string, value any) bool {
|
func setSimpleProperty(properties Properties, tag PropertyName, value any) bool {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
delete(properties.properties, tag)
|
properties.setRaw(tag, nil)
|
||||||
return true
|
return true
|
||||||
} else if text, ok := value.(string); ok {
|
} else if text, ok := value.(string); ok {
|
||||||
text = strings.Trim(text, " \t\n\r")
|
text = strings.Trim(text, " \t\n\r")
|
||||||
if text == "" {
|
if text == "" {
|
||||||
delete(properties.properties, tag)
|
properties.setRaw(tag, nil)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if isConstantName(text) {
|
if isConstantName(text) {
|
||||||
properties.properties[tag] = text
|
properties.setRaw(tag, text)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setSizeProperty(tag string, value any) bool {
|
func setStringPropertyValue(properties Properties, tag PropertyName, text any) []PropertyName {
|
||||||
if !properties.setSimpleProperty(tag, value) {
|
if text != "" {
|
||||||
|
properties.setRaw(tag, text)
|
||||||
|
} else if properties.getRaw(tag) != nil {
|
||||||
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
return []PropertyName{}
|
||||||
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setArrayPropertyValue[T any](properties Properties, tag PropertyName, value []T) []PropertyName {
|
||||||
|
if len(value) > 0 {
|
||||||
|
properties.setRaw(tag, value)
|
||||||
|
} else if properties.getRaw(tag) != nil {
|
||||||
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
return []PropertyName{}
|
||||||
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setSizeProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
if !setSimpleProperty(properties, tag, value) {
|
||||||
var size SizeUnit
|
var size SizeUnit
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
|
@ -566,7 +589,7 @@ func (properties *propertyList) setSizeProperty(tag string, value any) bool {
|
||||||
size.Function = fn
|
size.Function = fn
|
||||||
} else if size, ok = StringToSizeUnit(value); !ok {
|
} else if size, ok = StringToSizeUnit(value); !ok {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
case SizeUnit:
|
case SizeUnit:
|
||||||
size = value
|
size = value
|
||||||
|
@ -589,29 +612,29 @@ func (properties *propertyList) setSizeProperty(tag string, value any) bool {
|
||||||
size.Value = float64(n)
|
size.Value = float64(n)
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if size.Type == Auto {
|
if size.Type == Auto {
|
||||||
delete(properties.properties, tag)
|
properties.setRaw(tag, nil)
|
||||||
} else {
|
} else {
|
||||||
properties.properties[tag] = size
|
properties.setRaw(tag, size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setAngleProperty(tag string, value any) bool {
|
func setAngleProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
if !properties.setSimpleProperty(tag, value) {
|
if !setSimpleProperty(properties, tag, value) {
|
||||||
var angle AngleUnit
|
var angle AngleUnit
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
var ok bool
|
var ok bool
|
||||||
if angle, ok = StringToAngleUnit(value); !ok {
|
if angle, ok = StringToAngleUnit(value); !ok {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
case AngleUnit:
|
case AngleUnit:
|
||||||
angle = value
|
angle = value
|
||||||
|
@ -627,24 +650,24 @@ func (properties *propertyList) setAngleProperty(tag string, value any) bool {
|
||||||
angle = Rad(float64(n))
|
angle = Rad(float64(n))
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
properties.properties[tag] = angle
|
properties.setRaw(tag, angle)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setColorProperty(tag string, value any) bool {
|
func setColorProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
if !properties.setSimpleProperty(tag, value) {
|
if !setSimpleProperty(properties, tag, value) {
|
||||||
var result Color
|
var result Color
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
var err error
|
var err error
|
||||||
if result, err = stringToColor(value); err != nil {
|
if result, err = stringToColor(value); err != nil {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
case Color:
|
case Color:
|
||||||
result = value
|
result = value
|
||||||
|
@ -654,105 +677,101 @@ func (properties *propertyList) setColorProperty(tag string, value any) bool {
|
||||||
result = Color(color)
|
result = Color(color)
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if result == 0 {
|
properties.setRaw(tag, result)
|
||||||
delete(properties.properties, tag)
|
|
||||||
} else {
|
|
||||||
properties.properties[tag] = result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setEnumProperty(tag string, value any, values []string) bool {
|
func setEnumProperty(properties Properties, tag PropertyName, value any, values []string) []PropertyName {
|
||||||
if !properties.setSimpleProperty(tag, value) {
|
if !setSimpleProperty(properties, tag, value) {
|
||||||
var n int
|
var n int
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
if n, ok = enumStringToInt(text, values, false); !ok {
|
if n, ok = enumStringToInt(text, values, false); !ok {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
} else if i, ok := isInt(value); ok {
|
} else if i, ok := isInt(value); ok {
|
||||||
if i < 0 || i >= len(values) {
|
if i < 0 || i >= len(values) {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
n = i
|
n = i
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
properties.properties[tag] = n
|
properties.setRaw(tag, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setBoolProperty(tag string, value any) bool {
|
func setBoolProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
if !properties.setSimpleProperty(tag, value) {
|
if !setSimpleProperty(properties, tag, value) {
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
switch strings.ToLower(strings.Trim(text, " \t")) {
|
switch strings.ToLower(strings.Trim(text, " \t")) {
|
||||||
case "true", "yes", "on", "1":
|
case "true", "yes", "on", "1":
|
||||||
properties.properties[tag] = true
|
properties.setRaw(tag, true)
|
||||||
|
|
||||||
case "false", "no", "off", "0":
|
case "false", "no", "off", "0":
|
||||||
properties.properties[tag] = false
|
properties.setRaw(tag, false)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
} else if n, ok := isInt(value); ok {
|
} else if n, ok := isInt(value); ok {
|
||||||
switch n {
|
switch n {
|
||||||
case 1:
|
case 1:
|
||||||
properties.properties[tag] = true
|
properties.setRaw(tag, true)
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
properties.properties[tag] = false
|
properties.setRaw(tag, false)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
} else if b, ok := value.(bool); ok {
|
} else if b, ok := value.(bool); ok {
|
||||||
properties.properties[tag] = b
|
properties.setRaw(tag, b)
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setIntProperty(tag string, value any) bool {
|
func setIntProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
if !properties.setSimpleProperty(tag, value) {
|
if !setSimpleProperty(properties, tag, value) {
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
n, err := strconv.Atoi(strings.Trim(text, " \t"))
|
n, err := strconv.Atoi(strings.Trim(text, " \t"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
ErrorLog(err.Error())
|
ErrorLog(err.Error())
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
properties.properties[tag] = n
|
properties.setRaw(tag, n)
|
||||||
} else if n, ok := isInt(value); ok {
|
} else if n, ok := isInt(value); ok {
|
||||||
properties.properties[tag] = n
|
properties.setRaw(tag, n)
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setFloatProperty(tag string, value any, min, max float64) bool {
|
func setFloatProperty(properties Properties, tag PropertyName, value any, min, max float64) []PropertyName {
|
||||||
if !properties.setSimpleProperty(tag, value) {
|
if !setSimpleProperty(properties, tag, value) {
|
||||||
f := float64(0)
|
f := float64(0)
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
|
@ -760,14 +779,14 @@ func (properties *propertyList) setFloatProperty(tag string, value any, min, max
|
||||||
if f, err = strconv.ParseFloat(strings.Trim(value, " \t"), 64); err != nil {
|
if f, err = strconv.ParseFloat(strings.Trim(value, " \t"), 64); err != nil {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
ErrorLog(err.Error())
|
ErrorLog(err.Error())
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
if f < min || f > max {
|
if f < min || f > max {
|
||||||
ErrorLogF(`"%T" out of range of "%s" property`, value, tag)
|
ErrorLogF(`"%T" out of range of "%s" property`, value, tag)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
properties.properties[tag] = value
|
properties.setRaw(tag, value)
|
||||||
return true
|
return nil
|
||||||
|
|
||||||
case float32:
|
case float32:
|
||||||
f = float64(value)
|
f = float64(value)
|
||||||
|
@ -780,64 +799,84 @@ func (properties *propertyList) setFloatProperty(tag string, value any, min, max
|
||||||
f = float64(n)
|
f = float64(n)
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f >= min && f <= max {
|
if f >= min && f <= max {
|
||||||
properties.properties[tag] = f
|
properties.setRaw(tag, f)
|
||||||
} else {
|
} else {
|
||||||
ErrorLogF(`"%T" out of range of "%s" property`, value, tag)
|
ErrorLogF(`"%T" out of range of "%s" property`, value, tag)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
|
||||||
|
|
||||||
func (properties *propertyList) Set(tag string, value any) bool {
|
|
||||||
return properties.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (properties *propertyList) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
delete(properties.properties, tag)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func propertiesSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
if _, ok := sizeProperties[tag]; ok {
|
if _, ok := sizeProperties[tag]; ok {
|
||||||
return properties.setSizeProperty(tag, value)
|
return setSizeProperty(properties, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if valuesData, ok := enumProperties[tag]; ok {
|
if valuesData, ok := enumProperties[tag]; ok {
|
||||||
return properties.setEnumProperty(tag, value, valuesData.values)
|
return setEnumProperty(properties, tag, value, valuesData.values)
|
||||||
}
|
}
|
||||||
|
|
||||||
if limits, ok := floatProperties[tag]; ok {
|
if limits, ok := floatProperties[tag]; ok {
|
||||||
return properties.setFloatProperty(tag, value, limits.min, limits.max)
|
return setFloatProperty(properties, tag, value, limits.min, limits.max)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPropertyInList(tag, colorProperties) {
|
if isPropertyInList(tag, colorProperties) {
|
||||||
return properties.setColorProperty(tag, value)
|
return setColorProperty(properties, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPropertyInList(tag, angleProperties) {
|
if isPropertyInList(tag, angleProperties) {
|
||||||
return properties.setAngleProperty(tag, value)
|
return setAngleProperty(properties, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPropertyInList(tag, boolProperties) {
|
if isPropertyInList(tag, boolProperties) {
|
||||||
return properties.setBoolProperty(tag, value)
|
return setBoolProperty(properties, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPropertyInList(tag, intProperties) {
|
if isPropertyInList(tag, intProperties) {
|
||||||
return properties.setIntProperty(tag, value)
|
return setIntProperty(properties, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
properties.properties[tag] = text
|
properties.setRaw(tag, text)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (properties *propertyList) Set(tag PropertyName, value any) bool {
|
||||||
|
tag = properties.normalize(tag)
|
||||||
|
if value == nil {
|
||||||
|
properties.remove(properties, tag)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties.set(properties, tag, value) != nil
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (data *dataProperty) Set(tag PropertyName, value any) bool {
|
||||||
|
if value == nil {
|
||||||
|
data.Remove(tag)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = data.normalize(tag)
|
||||||
|
for _, supported := range data.supportedProperties {
|
||||||
|
if tag == supported {
|
||||||
|
return data.set(data, tag, value) != nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorLogF(`"%s" property is not supported`, string(tag))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
381
radius.go
381
radius.go
|
@ -37,7 +37,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
Radius = "radius"
|
Radius PropertyName = "radius"
|
||||||
|
|
||||||
// RadiusX is the constant for "radius-x" property tag.
|
// RadiusX is the constant for "radius-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -58,7 +58,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusX = "radius-x"
|
RadiusX PropertyName = "radius-x"
|
||||||
|
|
||||||
// RadiusY is the constant for "radius-y" property tag.
|
// RadiusY is the constant for "radius-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -79,7 +79,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusY = "radius-y"
|
RadiusY PropertyName = "radius-y"
|
||||||
|
|
||||||
// RadiusTopLeft is the constant for "radius-top-left" property tag.
|
// RadiusTopLeft is the constant for "radius-top-left" property tag.
|
||||||
//
|
//
|
||||||
|
@ -90,7 +90,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusTopLeft = "radius-top-left"
|
RadiusTopLeft PropertyName = "radius-top-left"
|
||||||
|
|
||||||
// RadiusTopLeftX is the constant for "radius-top-left-x" property tag.
|
// RadiusTopLeftX is the constant for "radius-top-left-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -101,7 +101,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusTopLeftX = "radius-top-left-x"
|
RadiusTopLeftX PropertyName = "radius-top-left-x"
|
||||||
|
|
||||||
// RadiusTopLeftY is the constant for "radius-top-left-y" property tag.
|
// RadiusTopLeftY is the constant for "radius-top-left-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -112,7 +112,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusTopLeftY = "radius-top-left-y"
|
RadiusTopLeftY PropertyName = "radius-top-left-y"
|
||||||
|
|
||||||
// RadiusTopRight is the constant for "radius-top-right" property tag.
|
// RadiusTopRight is the constant for "radius-top-right" property tag.
|
||||||
//
|
//
|
||||||
|
@ -123,7 +123,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusTopRight = "radius-top-right"
|
RadiusTopRight PropertyName = "radius-top-right"
|
||||||
|
|
||||||
// RadiusTopRightX is the constant for "radius-top-right-x" property tag.
|
// RadiusTopRightX is the constant for "radius-top-right-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -134,7 +134,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusTopRightX = "radius-top-right-x"
|
RadiusTopRightX PropertyName = "radius-top-right-x"
|
||||||
|
|
||||||
// RadiusTopRightY is the constant for "radius-top-right-y" property tag.
|
// RadiusTopRightY is the constant for "radius-top-right-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -145,7 +145,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusTopRightY = "radius-top-right-y"
|
RadiusTopRightY PropertyName = "radius-top-right-y"
|
||||||
|
|
||||||
// RadiusBottomLeft is the constant for "radius-bottom-left" property tag.
|
// RadiusBottomLeft is the constant for "radius-bottom-left" property tag.
|
||||||
//
|
//
|
||||||
|
@ -156,7 +156,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusBottomLeft = "radius-bottom-left"
|
RadiusBottomLeft PropertyName = "radius-bottom-left"
|
||||||
|
|
||||||
// RadiusBottomLeftX is the constant for "radius-bottom-left-x" property tag.
|
// RadiusBottomLeftX is the constant for "radius-bottom-left-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -167,7 +167,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusBottomLeftX = "radius-bottom-left-x"
|
RadiusBottomLeftX PropertyName = "radius-bottom-left-x"
|
||||||
|
|
||||||
// RadiusBottomLeftY is the constant for "radius-bottom-left-y" property tag.
|
// RadiusBottomLeftY is the constant for "radius-bottom-left-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -178,7 +178,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusBottomLeftY = "radius-bottom-left-y"
|
RadiusBottomLeftY PropertyName = "radius-bottom-left-y"
|
||||||
|
|
||||||
// RadiusBottomRight is the constant for "radius-bottom-right" property tag.
|
// RadiusBottomRight is the constant for "radius-bottom-right" property tag.
|
||||||
//
|
//
|
||||||
|
@ -189,7 +189,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusBottomRight = "radius-bottom-right"
|
RadiusBottomRight PropertyName = "radius-bottom-right"
|
||||||
|
|
||||||
// RadiusBottomRightX is the constant for "radius-bottom-right-x" property tag.
|
// RadiusBottomRightX is the constant for "radius-bottom-right-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -200,7 +200,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusBottomRightX = "radius-bottom-right-x"
|
RadiusBottomRightX PropertyName = "radius-bottom-right-x"
|
||||||
|
|
||||||
// RadiusBottomRightY is the constant for "radius-bottom-right-y" property tag.
|
// RadiusBottomRightY is the constant for "radius-bottom-right-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -211,7 +211,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
RadiusBottomRightY = "radius-bottom-right-y"
|
RadiusBottomRightY PropertyName = "radius-bottom-right-y"
|
||||||
|
|
||||||
// X is the constant for "x" property tag.
|
// X is the constant for "x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -232,7 +232,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
X = "x"
|
X PropertyName = "x"
|
||||||
|
|
||||||
// Y is the constant for "y" property tag.
|
// Y is the constant for "y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -253,7 +253,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
Y = "y"
|
Y PropertyName = "y"
|
||||||
|
|
||||||
// TopLeft is the constant for "top-left" property tag.
|
// TopLeft is the constant for "top-left" property tag.
|
||||||
//
|
//
|
||||||
|
@ -264,7 +264,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TopLeft = "top-left"
|
TopLeft PropertyName = "top-left"
|
||||||
|
|
||||||
// TopLeftX is the constant for "top-left-x" property tag.
|
// TopLeftX is the constant for "top-left-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -275,7 +275,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TopLeftX = "top-left-x"
|
TopLeftX PropertyName = "top-left-x"
|
||||||
|
|
||||||
// TopLeftY is the constant for "top-left-y" property tag.
|
// TopLeftY is the constant for "top-left-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -286,7 +286,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TopLeftY = "top-left-y"
|
TopLeftY PropertyName = "top-left-y"
|
||||||
|
|
||||||
// TopRight is the constant for "top-right" property tag.
|
// TopRight is the constant for "top-right" property tag.
|
||||||
//
|
//
|
||||||
|
@ -297,7 +297,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TopRight = "top-right"
|
TopRight PropertyName = "top-right"
|
||||||
|
|
||||||
// TopRightX is the constant for "top-right-x" property tag.
|
// TopRightX is the constant for "top-right-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -308,7 +308,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TopRightX = "top-right-x"
|
TopRightX PropertyName = "top-right-x"
|
||||||
|
|
||||||
// TopRightY is the constant for "top-right-y" property tag.
|
// TopRightY is the constant for "top-right-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -319,7 +319,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TopRightY = "top-right-y"
|
TopRightY PropertyName = "top-right-y"
|
||||||
|
|
||||||
// BottomLeft is the constant for "bottom-left" property tag.
|
// BottomLeft is the constant for "bottom-left" property tag.
|
||||||
//
|
//
|
||||||
|
@ -330,7 +330,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
BottomLeft = "bottom-left"
|
BottomLeft PropertyName = "bottom-left"
|
||||||
|
|
||||||
// BottomLeftX is the constant for "bottom-left-x" property tag.
|
// BottomLeftX is the constant for "bottom-left-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -341,7 +341,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
BottomLeftX = "bottom-left-x"
|
BottomLeftX PropertyName = "bottom-left-x"
|
||||||
|
|
||||||
// BottomLeftY is the constant for "bottom-left-y" property tag.
|
// BottomLeftY is the constant for "bottom-left-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -352,7 +352,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
BottomLeftY = "bottom-left-y"
|
BottomLeftY PropertyName = "bottom-left-y"
|
||||||
|
|
||||||
// BottomRight is the constant for "bottom-right" property tag.
|
// BottomRight is the constant for "bottom-right" property tag.
|
||||||
//
|
//
|
||||||
|
@ -363,7 +363,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
BottomRight = "bottom-right"
|
BottomRight PropertyName = "bottom-right"
|
||||||
|
|
||||||
// BottomRightX is the constant for "bottom-right-x" property tag.
|
// BottomRightX is the constant for "bottom-right-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -374,7 +374,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
BottomRightX = "bottom-right-x"
|
BottomRightX PropertyName = "bottom-right-x"
|
||||||
|
|
||||||
// BottomRightY is the constant for "bottom-right-y" property tag.
|
// BottomRightY is the constant for "bottom-right-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -385,7 +385,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
BottomRightY = "bottom-right-y"
|
BottomRightY PropertyName = "bottom-right-y"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RadiusProperty is a description of the [View] (shape) elliptical corner radius.
|
// RadiusProperty is a description of the [View] (shape) elliptical corner radius.
|
||||||
|
@ -399,38 +399,46 @@ type RadiusProperty interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type radiusPropertyData struct {
|
type radiusPropertyData struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRadiusProperty creates the new RadiusProperty
|
// NewRadiusProperty creates the new RadiusProperty
|
||||||
func NewRadiusProperty(params Params) RadiusProperty {
|
func NewRadiusProperty(params Params) RadiusProperty {
|
||||||
result := new(radiusPropertyData)
|
result := new(radiusPropertyData)
|
||||||
result.properties = map[string]any{}
|
result.dataProperty.init()
|
||||||
|
result.normalize = radiusPropertyNormalize
|
||||||
|
result.get = radiusPropertyGet
|
||||||
|
result.remove = radiusPropertyRemove
|
||||||
|
result.set = radiusPropertySet
|
||||||
|
result.supportedProperties = []PropertyName{
|
||||||
|
X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
||||||
|
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY,
|
||||||
|
}
|
||||||
|
|
||||||
if params != nil {
|
if params != nil {
|
||||||
for _, tag := range []string{X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
for _, tag := range result.supportedProperties {
|
||||||
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY} {
|
|
||||||
if value, ok := params[tag]; ok {
|
if value, ok := params[tag]; ok {
|
||||||
result.Set(tag, value)
|
radiusPropertySet(result, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (radius *radiusPropertyData) normalizeTag(tag string) string {
|
func radiusPropertyNormalize(tag PropertyName) PropertyName {
|
||||||
return strings.TrimPrefix(strings.ToLower(tag), "radius-")
|
name := strings.TrimPrefix(strings.ToLower(string(tag)), "radius-")
|
||||||
|
return PropertyName(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (radius *radiusPropertyData) writeString(buffer *strings.Builder, indent string) {
|
func (radius *radiusPropertyData) writeString(buffer *strings.Builder, indent string) {
|
||||||
buffer.WriteString("_{ ")
|
buffer.WriteString("_{ ")
|
||||||
comma := false
|
comma := false
|
||||||
for _, tag := range []string{X, Y, TopLeft, TopLeftX, TopLeftY, TopRight, TopRightX, TopRightY,
|
for _, tag := range radius.supportedProperties {
|
||||||
BottomLeft, BottomLeftX, BottomLeftY, BottomRight, BottomRightX, BottomRightY} {
|
|
||||||
if value, ok := radius.properties[tag]; ok {
|
if value, ok := radius.properties[tag]; ok {
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
|
@ -444,26 +452,54 @@ func (radius *radiusPropertyData) String() string {
|
||||||
return runStringWriter(radius)
|
return runStringWriter(radius)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (radius *radiusPropertyData) delete(tags []string) {
|
func radiusPropertyRemove(properties Properties, tag PropertyName) []PropertyName {
|
||||||
for _, tag := range tags {
|
result := []PropertyName{}
|
||||||
delete(radius.properties, tag)
|
removeTag := func(tag PropertyName) {
|
||||||
|
if properties.getRaw(tag) != nil {
|
||||||
|
properties.setRaw(tag, nil)
|
||||||
|
result = append(result, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (radius *radiusPropertyData) deleteUnusedTags() {
|
switch tag {
|
||||||
for _, tag := range []string{X, Y} {
|
case X, Y:
|
||||||
if _, ok := radius.properties[tag]; ok {
|
if properties.getRaw(tag) == nil {
|
||||||
|
for _, prefix := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
||||||
|
removeTag(prefix + "-" + tag)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
||||||
|
removeTag(tag)
|
||||||
|
|
||||||
|
case TopLeft, TopRight, BottomLeft, BottomRight:
|
||||||
|
for _, tag := range []PropertyName{tag, tag + "-x", tag + "-y"} {
|
||||||
|
removeTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ErrorLogF(`"%s" property is not compatible with the RadiusProperty`, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteRadiusUnusedTags(radius Properties, result []PropertyName) {
|
||||||
|
|
||||||
|
for _, tag := range []PropertyName{X, Y} {
|
||||||
|
if radius.getRaw(tag) != nil {
|
||||||
unused := true
|
unused := true
|
||||||
for _, t := range []string{TopLeft, TopRight, BottomLeft, BottomRight} {
|
for _, t := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
||||||
if _, ok := radius.properties[t+"-"+tag]; !ok {
|
if radius.getRaw(t+"-"+tag) == nil && radius.getRaw(t) == nil {
|
||||||
if _, ok := radius.properties[t]; !ok {
|
|
||||||
unused = false
|
unused = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if unused {
|
if unused {
|
||||||
delete(radius.properties, tag)
|
radius.setRaw(tag, nil)
|
||||||
|
result = append(result, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -485,124 +521,122 @@ func (radius *radiusPropertyData) deleteUnusedTags() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range []string{TopLeft, TopRight, BottomLeft, BottomRight} {
|
for _, tag := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
||||||
tagX := tag + "-x"
|
tagX := tag + "-x"
|
||||||
tagY := tag + "-y"
|
tagY := tag + "-y"
|
||||||
valueX, okX := radius.properties[tagX]
|
valueX := radius.getRaw(tagX)
|
||||||
valueY, okY := radius.properties[tagY]
|
valueY := radius.getRaw(tagY)
|
||||||
|
|
||||||
if value, ok := radius.properties[tag]; ok {
|
if value := radius.getRaw(tag); value != nil {
|
||||||
if okX && okY {
|
if valueX != nil && valueY != nil {
|
||||||
delete(radius.properties, tag)
|
radius.setRaw(tag, nil)
|
||||||
} else if okX && !okY {
|
result = append(result, tag)
|
||||||
|
} else if valueX != nil && valueY == nil {
|
||||||
if equalValue(value, valueX) {
|
if equalValue(value, valueX) {
|
||||||
delete(radius.properties, tagX)
|
radius.setRaw(tagX, nil)
|
||||||
|
result = append(result, tagX)
|
||||||
} else {
|
} else {
|
||||||
radius.properties[tagY] = value
|
radius.setRaw(tagY, value)
|
||||||
delete(radius.properties, tag)
|
result = append(result, tagY)
|
||||||
|
radius.setRaw(tag, nil)
|
||||||
|
result = append(result, tag)
|
||||||
}
|
}
|
||||||
} else if !okX && okY {
|
} else if valueX == nil && valueY != nil {
|
||||||
if equalValue(value, valueY) {
|
if equalValue(value, valueY) {
|
||||||
delete(radius.properties, tagY)
|
radius.setRaw(tagY, nil)
|
||||||
|
result = append(result, tagY)
|
||||||
} else {
|
} else {
|
||||||
radius.properties[tagX] = value
|
radius.setRaw(tagX, value)
|
||||||
delete(radius.properties, tag)
|
result = append(result, tagX)
|
||||||
|
radius.setRaw(tag, nil)
|
||||||
|
result = append(result, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if okX && okY && equalValue(valueX, valueY) {
|
} else if valueX != nil && valueY != nil && equalValue(valueX, valueY) {
|
||||||
radius.properties[tag] = valueX
|
radius.setRaw(tag, valueX)
|
||||||
delete(radius.properties, tagX)
|
result = append(result, tag)
|
||||||
delete(radius.properties, tagY)
|
radius.setRaw(tagX, nil)
|
||||||
|
result = append(result, tagX)
|
||||||
|
radius.setRaw(tagY, nil)
|
||||||
|
result = append(result, tagY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (radius *radiusPropertyData) Remove(tag string) {
|
func radiusPropertySet(radius Properties, tag PropertyName, value any) []PropertyName {
|
||||||
tag = radius.normalizeTag(tag)
|
var result []PropertyName = nil
|
||||||
|
|
||||||
switch tag {
|
deleteTags := func(tags []PropertyName) {
|
||||||
case X, Y:
|
for _, tag := range tags {
|
||||||
if _, ok := radius.properties[tag]; ok {
|
if radius.getRaw(tag) != nil {
|
||||||
radius.Set(tag, AutoSize())
|
radius.setRaw(tag, nil)
|
||||||
delete(radius.properties, tag)
|
result = append(result, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
|
||||||
delete(radius.properties, tag)
|
|
||||||
|
|
||||||
case TopLeft, TopRight, BottomLeft, BottomRight:
|
|
||||||
radius.delete([]string{tag, tag + "-x", tag + "-y"})
|
|
||||||
|
|
||||||
default:
|
|
||||||
ErrorLogF(`"%s" property is not compatible with the RadiusProperty`, tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (radius *radiusPropertyData) Set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
radius.Remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
tag = radius.normalizeTag(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case X:
|
case X:
|
||||||
if radius.setSizeProperty(tag, value) {
|
if result = setSizeProperty(radius, tag, value); result != nil {
|
||||||
radius.delete([]string{TopLeftX, TopRightX, BottomLeftX, BottomRightX})
|
deleteTags([]PropertyName{TopLeftX, TopRightX, BottomLeftX, BottomRightX})
|
||||||
for _, t := range []string{TopLeft, TopRight, BottomLeft, BottomRight} {
|
for _, t := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
||||||
if val, ok := radius.properties[t]; ok {
|
if val := radius.getRaw(t); val != nil {
|
||||||
if _, ok := radius.properties[t+"-y"]; !ok {
|
t2 := t + "-y"
|
||||||
radius.properties[t+"-y"] = val
|
if radius.getRaw(t2) != nil {
|
||||||
|
radius.setRaw(t2, val)
|
||||||
|
result = append(result, t2)
|
||||||
}
|
}
|
||||||
delete(radius.properties, t)
|
radius.setRaw(t, nil)
|
||||||
|
result = append(result, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case Y:
|
case Y:
|
||||||
if radius.setSizeProperty(tag, value) {
|
if result = setSizeProperty(radius, tag, value); result != nil {
|
||||||
radius.delete([]string{TopLeftY, TopRightY, BottomLeftY, BottomRightY})
|
deleteTags([]PropertyName{TopLeftY, TopRightY, BottomLeftY, BottomRightY})
|
||||||
for _, t := range []string{TopLeft, TopRight, BottomLeft, BottomRight} {
|
for _, t := range []PropertyName{TopLeft, TopRight, BottomLeft, BottomRight} {
|
||||||
if val, ok := radius.properties[t]; ok {
|
if val := radius.getRaw(t); val != nil {
|
||||||
if _, ok := radius.properties[t+"-x"]; !ok {
|
t2 := t + "-x"
|
||||||
radius.properties[t+"-x"] = val
|
if radius.getRaw(t2) != nil {
|
||||||
|
radius.setRaw(t2, val)
|
||||||
|
result = append(result, t2)
|
||||||
}
|
}
|
||||||
delete(radius.properties, t)
|
radius.setRaw(t, nil)
|
||||||
|
result = append(result, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
||||||
if radius.setSizeProperty(tag, value) {
|
if result = setSizeProperty(radius, tag, value); result != nil {
|
||||||
radius.deleteUnusedTags()
|
deleteRadiusUnusedTags(radius, result)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case TopLeft, TopRight, BottomLeft, BottomRight:
|
case TopLeft, TopRight, BottomLeft, BottomRight:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case SizeUnit:
|
case SizeUnit:
|
||||||
radius.properties[tag] = value
|
radius.setRaw(tag, value)
|
||||||
radius.delete([]string{tag + "-x", tag + "-y"})
|
result = []PropertyName{tag}
|
||||||
radius.deleteUnusedTags()
|
deleteTags([]PropertyName{tag + "-x", tag + "-y"})
|
||||||
return true
|
deleteRadiusUnusedTags(radius, result)
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if strings.Contains(value, "/") {
|
if strings.Contains(value, "/") {
|
||||||
if values := strings.Split(value, "/"); len(values) == 2 {
|
if values := strings.Split(value, "/"); len(values) == 2 {
|
||||||
xOK := radius.Set(tag+"-x", value[0])
|
if result = radiusPropertySet(radius, tag+"-x", value[0]); result != nil {
|
||||||
yOK := radius.Set(tag+"-y", value[1])
|
if resultY := radiusPropertySet(radius, tag+"-y", value[1]); resultY != nil {
|
||||||
return xOK && yOK
|
result = append(result, resultY...)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if radius.setSizeProperty(tag, value) {
|
if result = setSizeProperty(radius, tag, value); result != nil {
|
||||||
radius.delete([]string{tag + "-x", tag + "-y"})
|
deleteTags([]PropertyName{tag + "-x", tag + "-y"})
|
||||||
radius.deleteUnusedTags()
|
deleteRadiusUnusedTags(radius, result)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -611,33 +645,32 @@ func (radius *radiusPropertyData) Set(tag string, value any) bool {
|
||||||
ErrorLogF(`"%s" property is not compatible with the RadiusProperty`, tag)
|
ErrorLogF(`"%s" property is not compatible with the RadiusProperty`, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (radius *radiusPropertyData) Get(tag string) any {
|
func radiusPropertyGet(properties Properties, tag PropertyName) any {
|
||||||
tag = radius.normalizeTag(tag)
|
if value := properties.getRaw(tag); value != nil {
|
||||||
if value, ok := radius.properties[tag]; ok {
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
case TopLeftX, TopLeftY, TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY:
|
||||||
tagLen := len(tag)
|
tagLen := len(tag)
|
||||||
if value, ok := radius.properties[tag[:tagLen-2]]; ok {
|
if value := properties.getRaw(tag[:tagLen-2]); value != nil {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
if value, ok := radius.properties[tag[tagLen-1:]]; ok {
|
if value := properties.getRaw(tag[tagLen-1:]); value != nil {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case TopLeftX, TopRightX, BottomLeftX, BottomRightX:
|
case TopLeftX, TopRightX, BottomLeftX, BottomRightX:
|
||||||
if value, ok := radius.properties[X]; ok {
|
if value := properties.getRaw(X); value != nil {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
case TopLeftY, TopRightY, BottomLeftY, BottomRightY:
|
case TopLeftY, TopRightY, BottomLeftY, BottomRightY:
|
||||||
if value, ok := radius.properties[Y]; ok {
|
if value := properties.getRaw(Y); value != nil {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -649,7 +682,7 @@ func (radius *radiusPropertyData) BoxRadius(session Session) BoxRadius {
|
||||||
x, _ := sizeProperty(radius, X, session)
|
x, _ := sizeProperty(radius, X, session)
|
||||||
y, _ := sizeProperty(radius, Y, session)
|
y, _ := sizeProperty(radius, Y, session)
|
||||||
|
|
||||||
getRadius := func(tag string) (SizeUnit, SizeUnit) {
|
getRadius := func(tag PropertyName) (SizeUnit, SizeUnit) {
|
||||||
rx := x
|
rx := x
|
||||||
ry := y
|
ry := y
|
||||||
if r, ok := sizeProperty(radius, tag, session); ok {
|
if r, ok := sizeProperty(radius, tag, session); ok {
|
||||||
|
@ -866,21 +899,18 @@ func getRadiusProperty(style Properties) RadiusProperty {
|
||||||
return NewRadiusProperty(nil)
|
return NewRadiusProperty(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setRadius(value any) bool {
|
func setRadiusProperty(properties Properties, value any) []PropertyName {
|
||||||
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
delete(properties.properties, Radius)
|
return propertiesRemove(properties, Radius)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case RadiusProperty:
|
case RadiusProperty:
|
||||||
properties.properties[Radius] = value
|
properties.setRaw(Radius, value)
|
||||||
return true
|
|
||||||
|
|
||||||
case SizeUnit:
|
case SizeUnit:
|
||||||
properties.properties[Radius] = value
|
properties.setRaw(Radius, value)
|
||||||
return true
|
|
||||||
|
|
||||||
case BoxRadius:
|
case BoxRadius:
|
||||||
radius := NewRadiusProperty(nil)
|
radius := NewRadiusProperty(nil)
|
||||||
|
@ -913,78 +943,85 @@ func (properties *propertyList) setRadius(value any) bool {
|
||||||
radius.Set(BottomRightY, value.BottomRightY)
|
radius.Set(BottomRightY, value.BottomRightY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
properties.properties[Radius] = radius
|
properties.setRaw(Radius, radius)
|
||||||
return true
|
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if strings.Contains(value, "/") {
|
if strings.Contains(value, "/") {
|
||||||
values := strings.Split(value, "/")
|
values := strings.Split(value, "/")
|
||||||
if len(values) == 2 {
|
if len(values) == 2 {
|
||||||
okX := properties.setRadiusElement(RadiusX, values[0])
|
if setRadiusPropertyElement(properties, RadiusX, values[0]) {
|
||||||
okY := properties.setRadiusElement(RadiusY, values[1])
|
result := []PropertyName{Radius, RadiusX}
|
||||||
return okX && okY
|
if setRadiusPropertyElement(properties, RadiusY, values[1]) {
|
||||||
} else {
|
result = append(result, RadiusY)
|
||||||
notCompatibleType(Radius, value)
|
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notCompatibleType(Radius, value)
|
||||||
|
return nil
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return properties.setSizeProperty(Radius, value)
|
return setSizeProperty(properties, Radius, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
radius := NewRadiusProperty(nil)
|
radius := NewRadiusProperty(nil)
|
||||||
for _, tag := range []string{X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
for _, tag := range []PropertyName{X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
||||||
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY} {
|
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY} {
|
||||||
if value, ok := value.PropertyValue(tag); ok {
|
if value, ok := value.PropertyValue(string(tag)); ok {
|
||||||
radius.Set(tag, value)
|
radius.Set(tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
properties.properties[Radius] = radius
|
properties.setRaw(Radius, radius)
|
||||||
return true
|
|
||||||
|
|
||||||
case float32:
|
case float32:
|
||||||
return properties.setRadius(Px(float64(value)))
|
properties.setRaw(Radius, Px(float64(value)))
|
||||||
|
|
||||||
case float64:
|
case float64:
|
||||||
return properties.setRadius(Px(value))
|
properties.setRaw(Radius, Px(value))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if n, ok := isInt(value); ok {
|
if n, ok := isInt(value); ok {
|
||||||
return properties.setRadius(Px(float64(n)))
|
properties.setRaw(Radius, Px(float64(n)))
|
||||||
}
|
} else {
|
||||||
notCompatibleType(Radius, value)
|
notCompatibleType(Radius, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return []PropertyName{Radius}
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeRadiusPropertyElement(properties Properties, tag PropertyName) bool {
|
||||||
|
if value := properties.getRaw(Radius); value != nil {
|
||||||
|
radius := getRadiusProperty(properties)
|
||||||
|
radius.Remove(tag)
|
||||||
|
if radius.empty() {
|
||||||
|
properties.setRaw(Radius, nil)
|
||||||
|
} else {
|
||||||
|
properties.setRaw(Radius, radius)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) removeRadiusElement(tag string) {
|
func setRadiusPropertyElement(properties Properties, tag PropertyName, value any) bool {
|
||||||
if value, ok := properties.properties[Radius]; ok && value != nil {
|
|
||||||
radius := getRadiusProperty(properties)
|
|
||||||
radius.Remove(tag)
|
|
||||||
if len(radius.AllTags()) == 0 {
|
|
||||||
delete(properties.properties, Radius)
|
|
||||||
} else {
|
|
||||||
properties.properties[Radius] = radius
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (properties *propertyList) setRadiusElement(tag string, value any) bool {
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
properties.removeRadiusElement(tag)
|
removeRadiusPropertyElement(properties, tag)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
radius := getRadiusProperty(properties)
|
radius := getRadiusProperty(properties)
|
||||||
if radius.Set(tag, value) {
|
if radius.Set(tag, value) {
|
||||||
properties.properties[Radius] = radius
|
properties.setRaw(Radius, radius)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRadiusElement(style Properties, tag string) any {
|
func getRadiusElement(style Properties, tag PropertyName) any {
|
||||||
value := style.Get(Radius)
|
value := style.Get(Radius)
|
||||||
if value != nil {
|
if value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Range defines range limits. The First and Last value are included in the range
|
||||||
|
type Range struct {
|
||||||
|
First, Last int
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of the Range struct
|
||||||
|
func (r Range) String() string {
|
||||||
|
if r.First == r.Last {
|
||||||
|
return fmt.Sprintf("%d", r.First)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d:%d", r.First, r.Last)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Range) setValue(value string) bool {
|
||||||
|
var err error
|
||||||
|
if strings.Contains(value, ":") {
|
||||||
|
values := strings.Split(value, ":")
|
||||||
|
if len(values) != 2 {
|
||||||
|
ErrorLog("Invalid range value: " + value)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r.First, err = strconv.Atoi(strings.Trim(values[0], " \t\n\r")); err != nil {
|
||||||
|
ErrorLog(`Invalid first range value "` + value + `" (` + err.Error() + ")")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r.Last, err = strconv.Atoi(strings.Trim(values[1], " \t\n\r")); err != nil {
|
||||||
|
ErrorLog(`Invalid last range value "` + value + `" (` + err.Error() + ")")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.First, err = strconv.Atoi(value); err != nil {
|
||||||
|
ErrorLog(`Invalid range value "` + value + `" (` + err.Error() + ")")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
r.Last = r.First
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func setRangeProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case string:
|
||||||
|
if setSimpleProperty(properties, tag, value) {
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r Range
|
||||||
|
if !r.setValue(value) {
|
||||||
|
invalidPropertyValue(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
properties.setRaw(tag, r)
|
||||||
|
|
||||||
|
case Range:
|
||||||
|
properties.setRaw(tag, value)
|
||||||
|
|
||||||
|
default:
|
||||||
|
if n, ok := isInt(value); ok {
|
||||||
|
properties.setRaw(tag, Range{First: n, Last: n})
|
||||||
|
} else {
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
221
resizable.go
221
resizable.go
|
@ -62,7 +62,6 @@ type Resizable interface {
|
||||||
|
|
||||||
type resizableData struct {
|
type resizableData struct {
|
||||||
viewData
|
viewData
|
||||||
content []View
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResizable create new Resizable object and return it
|
// NewResizable create new Resizable object and return it
|
||||||
|
@ -74,147 +73,99 @@ func NewResizable(session Session, params Params) Resizable {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newResizable(session Session) View {
|
func newResizable(session Session) View {
|
||||||
return NewResizable(session, nil)
|
return new(resizableData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) init(session Session) {
|
func (resizable *resizableData) init(session Session) {
|
||||||
resizable.viewData.init(session)
|
resizable.viewData.init(session)
|
||||||
resizable.tag = "Resizable"
|
resizable.tag = "Resizable"
|
||||||
resizable.systemClass = "ruiGridLayout"
|
resizable.systemClass = "ruiGridLayout"
|
||||||
resizable.content = []View{}
|
resizable.set = resizableSet
|
||||||
}
|
resizable.changed = resizablePropertyChanged
|
||||||
|
|
||||||
func (resizable *resizableData) String() string {
|
|
||||||
return getViewString(resizable, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) Views() []View {
|
func (resizable *resizableData) Views() []View {
|
||||||
return resizable.content
|
if view := resizable.content(); view != nil {
|
||||||
|
return []View{view}
|
||||||
|
}
|
||||||
|
return []View{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) Remove(tag string) {
|
func (resizable *resizableData) content() View {
|
||||||
resizable.remove(strings.ToLower(tag))
|
if value := resizable.getRaw(Content); value != nil {
|
||||||
|
if content, ok := value.(View); ok {
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) remove(tag string) {
|
func resizableSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case Side:
|
case Side:
|
||||||
oldSide := resizable.getSide()
|
return resizableSetSide(view, value)
|
||||||
delete(resizable.properties, Side)
|
|
||||||
if oldSide != resizable.getSide() {
|
|
||||||
if resizable.created {
|
|
||||||
updateInnerHTML(resizable.htmlID(), resizable.Session())
|
|
||||||
resizable.updateResizeBorderWidth()
|
|
||||||
}
|
|
||||||
resizable.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ResizeBorderWidth:
|
case ResizeBorderWidth:
|
||||||
w := resizable.resizeBorderWidth()
|
return setSizeProperty(view, tag, value)
|
||||||
delete(resizable.properties, ResizeBorderWidth)
|
|
||||||
if !w.Equal(resizable.resizeBorderWidth()) {
|
|
||||||
resizable.updateResizeBorderWidth()
|
|
||||||
resizable.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case Content:
|
|
||||||
if len(resizable.content) > 0 {
|
|
||||||
resizable.content = []View{}
|
|
||||||
if resizable.created {
|
|
||||||
updateInnerHTML(resizable.htmlID(), resizable.Session())
|
|
||||||
}
|
|
||||||
resizable.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
resizable.viewData.remove(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (resizable *resizableData) Set(tag string, value any) bool {
|
|
||||||
return resizable.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (resizable *resizableData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
resizable.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
|
||||||
case Side:
|
|
||||||
oldSide := resizable.getSide()
|
|
||||||
if !resizable.setSide(value) {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if oldSide != resizable.getSide() {
|
|
||||||
if resizable.created {
|
|
||||||
updateInnerHTML(resizable.htmlID(), resizable.Session())
|
|
||||||
resizable.updateResizeBorderWidth()
|
|
||||||
}
|
|
||||||
resizable.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
|
|
||||||
case ResizeBorderWidth:
|
|
||||||
w := resizable.resizeBorderWidth()
|
|
||||||
ok := resizable.setSizeProperty(tag, value)
|
|
||||||
if ok && !w.Equal(resizable.resizeBorderWidth()) {
|
|
||||||
resizable.updateResizeBorderWidth()
|
|
||||||
resizable.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return ok
|
|
||||||
|
|
||||||
case Content:
|
case Content:
|
||||||
var newContent View = nil
|
var newContent View = nil
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
newContent = NewTextView(resizable.Session(), Params{Text: value})
|
newContent = NewTextView(view.Session(), Params{Text: value})
|
||||||
|
|
||||||
case View:
|
case View:
|
||||||
newContent = value
|
newContent = value
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
if view := CreateViewFromObject(resizable.Session(), value); view != nil {
|
if newContent = CreateViewFromObject(view.Session(), value); newContent == nil {
|
||||||
newContent = view
|
return nil
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(resizable.content) == 0 {
|
view.setRaw(Content, newContent)
|
||||||
resizable.content = []View{newContent}
|
return []PropertyName{}
|
||||||
} else {
|
|
||||||
resizable.content[0] = newContent
|
|
||||||
}
|
|
||||||
if resizable.created {
|
|
||||||
updateInnerHTML(resizable.htmlID(), resizable.Session())
|
|
||||||
}
|
|
||||||
resizable.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case CellWidth, CellHeight, GridRowGap, GridColumnGap, CellVerticalAlign, CellHorizontalAlign:
|
case CellWidth, CellHeight, GridRowGap, GridColumnGap, CellVerticalAlign, CellHorizontalAlign:
|
||||||
ErrorLogF(`Not supported "%s" property`, tag)
|
ErrorLogF(`Not supported "%s" property`, string(tag))
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return resizable.viewData.set(tag, value)
|
return viewSet(view, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) Get(tag string) any {
|
func resizablePropertyChanged(view View, tag PropertyName) {
|
||||||
return resizable.get(strings.ToLower(tag))
|
switch tag {
|
||||||
|
case Side:
|
||||||
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case ResizeBorderWidth:
|
||||||
|
htmlID := view.htmlID()
|
||||||
|
session := view.Session()
|
||||||
|
column, row := resizableCellSizeCSS(view)
|
||||||
|
|
||||||
|
session.updateCSSProperty(htmlID, "grid-template-columns", column)
|
||||||
|
session.updateCSSProperty(htmlID, "grid-template-rows", row)
|
||||||
|
|
||||||
|
case Content:
|
||||||
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
|
|
||||||
|
default:
|
||||||
|
viewPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) getSide() int {
|
}
|
||||||
if value := resizable.getRaw(Side); value != nil {
|
|
||||||
|
func resizableSide(view View) int {
|
||||||
|
if value := view.getRaw(Side); value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if value, ok := resizable.session.resolveConstants(value); ok {
|
if value, ok := view.Session().resolveConstants(value); ok {
|
||||||
validValues := map[string]int{
|
validValues := map[string]int{
|
||||||
"top": TopSide,
|
"top": TopSide,
|
||||||
"right": RightSide,
|
"right": RightSide,
|
||||||
|
@ -258,15 +209,15 @@ func (resizable *resizableData) getSide() int {
|
||||||
return AllSides
|
return AllSides
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) setSide(value any) bool {
|
func resizableSetSide(properties Properties, value any) []PropertyName {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if n, err := strconv.Atoi(value); err == nil {
|
if n, err := strconv.Atoi(value); err == nil {
|
||||||
if n >= 1 && n <= AllSides {
|
if n >= 1 && n <= AllSides {
|
||||||
resizable.properties[Side] = n
|
properties.setRaw(Side, n)
|
||||||
return true
|
return []PropertyName{Side}
|
||||||
}
|
}
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
validValues := map[string]int{
|
validValues := map[string]int{
|
||||||
"top": TopSide,
|
"top": TopSide,
|
||||||
|
@ -287,13 +238,13 @@ func (resizable *resizableData) setSide(value any) bool {
|
||||||
hasConst = true
|
hasConst = true
|
||||||
} else if n, err := strconv.Atoi(val); err == nil {
|
} else if n, err := strconv.Atoi(val); err == nil {
|
||||||
if n < 1 || n > AllSides {
|
if n < 1 || n > AllSides {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
sides |= n
|
sides |= n
|
||||||
} else if n, ok := validValues[val]; ok {
|
} else if n, ok := validValues[val]; ok {
|
||||||
sides |= n
|
sides |= n
|
||||||
} else {
|
} else {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,69 +253,58 @@ func (resizable *resizableData) setSide(value any) bool {
|
||||||
for i := 1; i < len(values); i++ {
|
for i := 1; i < len(values); i++ {
|
||||||
value += "|" + values[i]
|
value += "|" + values[i]
|
||||||
}
|
}
|
||||||
resizable.properties[Side] = value
|
properties.setRaw(Side, value)
|
||||||
return true
|
return []PropertyName{Side}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sides >= 1 && sides <= AllSides {
|
if sides >= 1 && sides <= AllSides {
|
||||||
resizable.properties[Side] = sides
|
properties.setRaw(Side, sides)
|
||||||
return true
|
return []PropertyName{Side}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if value[0] == '@' {
|
} else if value[0] == '@' {
|
||||||
resizable.properties[Side] = value
|
properties.setRaw(Side, value)
|
||||||
return true
|
return []PropertyName{Side}
|
||||||
} else if n, ok := validValues[value]; ok {
|
} else if n, ok := validValues[value]; ok {
|
||||||
resizable.properties[Side] = n
|
properties.setRaw(Side, n)
|
||||||
return true
|
return []PropertyName{Side}
|
||||||
}
|
}
|
||||||
|
|
||||||
case int:
|
case int:
|
||||||
if value >= 1 && value <= AllSides {
|
if value >= 1 && value <= AllSides {
|
||||||
resizable.properties[Side] = value
|
properties.setRaw(Side, value)
|
||||||
return true
|
return []PropertyName{Side}
|
||||||
} else {
|
} else {
|
||||||
ErrorLogF(`Invalid value %d of "side" property`, value)
|
ErrorLogF(`Invalid value %d of "side" property`, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if n, ok := isInt(value); ok {
|
if n, ok := isInt(value); ok {
|
||||||
if n >= 1 && n <= AllSides {
|
if n >= 1 && n <= AllSides {
|
||||||
resizable.properties[Side] = n
|
properties.setRaw(Side, n)
|
||||||
return true
|
return []PropertyName{Side}
|
||||||
} else {
|
} else {
|
||||||
ErrorLogF(`Invalid value %d of "side" property`, n)
|
ErrorLogF(`Invalid value %d of "side" property`, n)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) resizeBorderWidth() SizeUnit {
|
func resizableBorderWidth(view View) SizeUnit {
|
||||||
result, _ := sizeProperty(resizable, ResizeBorderWidth, resizable.Session())
|
result, _ := sizeProperty(view, ResizeBorderWidth, view.Session())
|
||||||
if result.Type == Auto || result.Value == 0 {
|
if result.Type == Auto || result.Value == 0 {
|
||||||
return Px(4)
|
return Px(4)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) updateResizeBorderWidth() {
|
func resizableCellSizeCSS(view View) (string, string) {
|
||||||
if resizable.created {
|
w := resizableBorderWidth(view).cssString("4px", view.Session())
|
||||||
htmlID := resizable.htmlID()
|
side := resizableSide(view)
|
||||||
session := resizable.Session()
|
|
||||||
column, row := resizable.cellSizeCSS()
|
|
||||||
|
|
||||||
session.updateCSSProperty(htmlID, "grid-template-columns", column)
|
|
||||||
session.updateCSSProperty(htmlID, "grid-template-rows", row)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (resizable *resizableData) cellSizeCSS() (string, string) {
|
|
||||||
w := resizable.resizeBorderWidth().cssString("4px", resizable.Session())
|
|
||||||
side := resizable.getSide()
|
|
||||||
column := "1fr"
|
column := "1fr"
|
||||||
row := "1fr"
|
row := "1fr"
|
||||||
|
|
||||||
|
@ -392,7 +332,7 @@ func (resizable *resizableData) cellSizeCSS() (string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resizable *resizableData) cssStyle(self View, builder cssBuilder) {
|
func (resizable *resizableData) cssStyle(self View, builder cssBuilder) {
|
||||||
column, row := resizable.cellSizeCSS()
|
column, row := resizableCellSizeCSS(resizable)
|
||||||
|
|
||||||
builder.add("grid-template-columns", column)
|
builder.add("grid-template-columns", column)
|
||||||
builder.add("grid-template-rows", row)
|
builder.add("grid-template-rows", row)
|
||||||
|
@ -402,12 +342,12 @@ func (resizable *resizableData) cssStyle(self View, builder cssBuilder) {
|
||||||
|
|
||||||
func (resizable *resizableData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (resizable *resizableData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
|
|
||||||
side := resizable.getSide()
|
side := resizableSide(resizable)
|
||||||
left := 1
|
left := 1
|
||||||
top := 1
|
top := 1
|
||||||
leftSide := (side & LeftSide) != 0
|
leftSide := (side & LeftSide) != 0
|
||||||
rightSide := (side & RightSide) != 0
|
rightSide := (side & RightSide) != 0
|
||||||
w := resizable.resizeBorderWidth().cssString("4px", resizable.Session())
|
w := resizableBorderWidth(resizable).cssString("4px", resizable.Session())
|
||||||
|
|
||||||
if leftSide {
|
if leftSide {
|
||||||
left = 2
|
left = 2
|
||||||
|
@ -484,8 +424,7 @@ func (resizable *resizableData) htmlSubviews(self View, buffer *strings.Builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(resizable.content) > 0 {
|
if view := resizable.content(); view != nil {
|
||||||
view := resizable.content[0]
|
|
||||||
view.addToCSSStyle(map[string]string{
|
view.addToCSSStyle(map[string]string{
|
||||||
"grid-column-start": strconv.Itoa(left),
|
"grid-column-start": strconv.Itoa(left),
|
||||||
"grid-column-end": strconv.Itoa(left + 1),
|
"grid-column-end": strconv.Itoa(left + 1),
|
||||||
|
|
|
@ -16,7 +16,7 @@ package rui
|
||||||
// `func(frame rui.Frame)`,
|
// `func(frame rui.Frame)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
const ResizeEvent = "resize-event"
|
const ResizeEvent PropertyName = "resize-event"
|
||||||
|
|
||||||
func (view *viewData) onResize(self View, x, y, width, height float64) {
|
func (view *viewData) onResize(self View, x, y, width, height float64) {
|
||||||
view.frame.Left = x
|
view.frame.Left = x
|
||||||
|
@ -31,21 +31,20 @@ func (view *viewData) onResize(self View, x, y, width, height float64) {
|
||||||
func (view *viewData) onItemResize(self View, index string, x, y, width, height float64) {
|
func (view *viewData) onItemResize(self View, index string, x, y, width, height float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) setFrameListener(tag string, value any) bool {
|
/*
|
||||||
listeners, ok := valueToEventListeners[View, Frame](value)
|
func setFrameListener(properties Properties, tag PropertyName, value any) bool {
|
||||||
if !ok {
|
if listeners, ok := valueToEventListeners[View, Frame](value); ok {
|
||||||
|
if len(listeners) == 0 {
|
||||||
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
properties.setRaw(tag, listeners)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if listeners == nil {
|
|
||||||
delete(view.properties, tag)
|
|
||||||
} else {
|
|
||||||
view.properties[tag] = listeners
|
|
||||||
}
|
|
||||||
view.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) setNoResizeEvent() {
|
func (view *viewData) setNoResizeEvent() {
|
||||||
view.noResizeEvent = true
|
view.noResizeEvent = true
|
||||||
|
|
|
@ -16,7 +16,7 @@ package rui
|
||||||
// `func(frame rui.Frame)`,
|
// `func(frame rui.Frame)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
const ScrollEvent = "scroll-event"
|
const ScrollEvent PropertyName = "scroll-event"
|
||||||
|
|
||||||
func (view *viewData) onScroll(self View, x, y, width, height float64) {
|
func (view *viewData) onScroll(self View, x, y, width, height float64) {
|
||||||
view.scroll.Left = x
|
view.scroll.Left = x
|
||||||
|
|
16
session.go
16
session.go
|
@ -89,11 +89,11 @@ type Session interface {
|
||||||
RootView() View
|
RootView() View
|
||||||
// Get returns a value of the view (with id defined by the first argument) property with name defined by the second argument.
|
// Get returns a value of the view (with id defined by the first argument) property with name defined by the second argument.
|
||||||
// The type of return value depends on the property. If the property is not set then nil is returned.
|
// The type of return value depends on the property. If the property is not set then nil is returned.
|
||||||
Get(viewID, tag string) any
|
Get(viewID string, tag PropertyName) any
|
||||||
// Set sets the value (third argument) of the property (second argument) of the view with id defined by the first argument.
|
// Set sets the value (third argument) of the property (second argument) of the view with id defined by the first argument.
|
||||||
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
||||||
// a description of the error is written to the log
|
// a description of the error is written to the log
|
||||||
Set(viewID, tag string, value any) bool
|
Set(viewID string, tag PropertyName, value any) bool
|
||||||
|
|
||||||
// DownloadFile downloads (saves) on the client side the file located at the specified path on the server.
|
// DownloadFile downloads (saves) on the client side the file located at the specified path on the server.
|
||||||
DownloadFile(path string)
|
DownloadFile(path string)
|
||||||
|
@ -134,7 +134,7 @@ type Session interface {
|
||||||
|
|
||||||
viewByHTMLID(id string) View
|
viewByHTMLID(id string) View
|
||||||
nextViewID() string
|
nextViewID() string
|
||||||
styleProperty(styleTag, property string) any
|
styleProperty(styleTag string, propertyTag PropertyName) any
|
||||||
|
|
||||||
setBridge(events chan DataObject, bridge bridge)
|
setBridge(events chan DataObject, bridge bridge)
|
||||||
writeInitScript(writer *strings.Builder)
|
writeInitScript(writer *strings.Builder)
|
||||||
|
@ -270,7 +270,7 @@ func (session *sessionData) close() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) styleProperty(styleTag, propertyTag string) any {
|
func (session *sessionData) styleProperty(styleTag string, propertyTag PropertyName) any {
|
||||||
if style := session.getCurrentTheme().style(styleTag); style != nil {
|
if style := session.getCurrentTheme().style(styleTag); style != nil {
|
||||||
return style.getRaw(propertyTag)
|
return style.getRaw(propertyTag)
|
||||||
}
|
}
|
||||||
|
@ -376,14 +376,14 @@ func (session *sessionData) setIgnoreViewUpdates(ignore bool) {
|
||||||
session.ignoreUpdates = ignore
|
session.ignoreUpdates = ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) Get(viewID, tag string) any {
|
func (session *sessionData) Get(viewID string, tag PropertyName) any {
|
||||||
if view := ViewByID(session.RootView(), viewID); view != nil {
|
if view := ViewByID(session.RootView(), viewID); view != nil {
|
||||||
return view.Get(tag)
|
return view.Get(tag)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *sessionData) Set(viewID, tag string, value any) bool {
|
func (session *sessionData) Set(viewID string, tag PropertyName, value any) bool {
|
||||||
if view := ViewByID(session.RootView(), viewID); view != nil {
|
if view := ViewByID(session.RootView(), viewID); view != nil {
|
||||||
return view.Set(tag, value)
|
return view.Set(tag, value)
|
||||||
}
|
}
|
||||||
|
@ -785,10 +785,10 @@ func (session *sessionData) handleEvent(command string, data DataObject) {
|
||||||
if viewID, ok := data.PropertyValue("id"); ok {
|
if viewID, ok := data.PropertyValue("id"); ok {
|
||||||
if viewID != "body" {
|
if viewID != "body" {
|
||||||
if view := session.viewByHTMLID(viewID); view != nil {
|
if view := session.viewByHTMLID(viewID); view != nil {
|
||||||
view.handleCommand(view, command, data)
|
view.handleCommand(view, PropertyName(command), data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if command == KeyDownEvent {
|
if command == string(KeyDownEvent) {
|
||||||
var event KeyEvent
|
var event KeyEvent
|
||||||
event.init(data)
|
event.init(data)
|
||||||
session.hotKey(event)
|
session.hotKey(event)
|
||||||
|
|
70
shadow.go
70
shadow.go
|
@ -42,7 +42,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `Color`, other types converted to it during assignment.
|
// Internal type is `Color`, other types converted to it during assignment.
|
||||||
// See `Color` description for more details.
|
// See `Color` description for more details.
|
||||||
ColorTag = "color"
|
ColorTag PropertyName = "color"
|
||||||
|
|
||||||
// Inset is the constant for "inset" property tag.
|
// Inset is the constant for "inset" property tag.
|
||||||
//
|
//
|
||||||
|
@ -55,7 +55,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Drop shadow inside the frame(as if the content was depressed inside the box).
|
// `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).
|
// `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 = "inset"
|
Inset PropertyName = "inset"
|
||||||
|
|
||||||
// XOffset is the constant for "x-offset" property tag.
|
// XOffset is the constant for "x-offset" property tag.
|
||||||
//
|
//
|
||||||
|
@ -66,7 +66,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
XOffset = "x-offset"
|
XOffset PropertyName = "x-offset"
|
||||||
|
|
||||||
// YOffset is the constant for "y-offset" property tag.
|
// YOffset is the constant for "y-offset" property tag.
|
||||||
//
|
//
|
||||||
|
@ -77,7 +77,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
YOffset = "y-offset"
|
YOffset PropertyName = "y-offset"
|
||||||
|
|
||||||
// BlurRadius is the constant for "blur" property tag.
|
// BlurRadius is the constant for "blur" property tag.
|
||||||
//
|
//
|
||||||
|
@ -89,7 +89,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
BlurRadius = "blur"
|
BlurRadius PropertyName = "blur"
|
||||||
|
|
||||||
// SpreadRadius is the constant for "spread-radius" property tag.
|
// SpreadRadius is the constant for "spread-radius" property tag.
|
||||||
//
|
//
|
||||||
|
@ -100,7 +100,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
SpreadRadius = "spread-radius"
|
SpreadRadius PropertyName = "spread-radius"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ViewShadow contains attributes of the view shadow
|
// ViewShadow contains attributes of the view shadow
|
||||||
|
@ -114,7 +114,7 @@ type ViewShadow interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type viewShadowData struct {
|
type viewShadowData struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewViewShadow create the new shadow for a view. Arguments:
|
// NewViewShadow create the new shadow for a view. Arguments:
|
||||||
|
@ -188,11 +188,12 @@ func NewTextShadow(offsetX, offsetY, blurRadius SizeUnit, color Color) ViewShado
|
||||||
// "inset" (Inset). Controls (bool) whether to draw shadow inside the frame or outside.
|
// "inset" (Inset). Controls (bool) whether to draw shadow inside the frame or outside.
|
||||||
func NewShadowWithParams(params Params) ViewShadow {
|
func NewShadowWithParams(params Params) ViewShadow {
|
||||||
shadow := new(viewShadowData)
|
shadow := new(viewShadowData)
|
||||||
shadow.propertyList.init()
|
shadow.init()
|
||||||
|
|
||||||
if params != nil {
|
if params != nil {
|
||||||
for _, tag := range []string{ColorTag, Inset, XOffset, YOffset, BlurRadius, SpreadRadius} {
|
for _, tag := range []PropertyName{ColorTag, Inset, XOffset, YOffset, BlurRadius, SpreadRadius} {
|
||||||
if value, ok := params[tag]; ok && value != nil {
|
if value, ok := params[tag]; ok && value != nil {
|
||||||
shadow.Set(tag, value)
|
shadow.set(shadow, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,33 +203,14 @@ func NewShadowWithParams(params Params) ViewShadow {
|
||||||
// parseViewShadow parse DataObject and create ViewShadow object
|
// parseViewShadow parse DataObject and create ViewShadow object
|
||||||
func parseViewShadow(object DataObject) ViewShadow {
|
func parseViewShadow(object DataObject) ViewShadow {
|
||||||
shadow := new(viewShadowData)
|
shadow := new(viewShadowData)
|
||||||
shadow.propertyList.init()
|
shadow.init()
|
||||||
parseProperties(shadow, object)
|
parseProperties(shadow, object)
|
||||||
return shadow
|
return shadow
|
||||||
}
|
}
|
||||||
|
|
||||||
func (shadow *viewShadowData) Remove(tag string) {
|
func (shadow *viewShadowData) init() {
|
||||||
delete(shadow.properties, strings.ToLower(tag))
|
shadow.dataProperty.init()
|
||||||
}
|
shadow.supportedProperties = []PropertyName{ColorTag, Inset, XOffset, YOffset, BlurRadius, SpreadRadius}
|
||||||
|
|
||||||
func (shadow *viewShadowData) Set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
shadow.Remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
tag = strings.ToLower(tag)
|
|
||||||
switch tag {
|
|
||||||
case ColorTag, Inset, XOffset, YOffset, BlurRadius, SpreadRadius:
|
|
||||||
return shadow.propertyList.Set(tag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorLogF(`"%s" property is not supported by Shadow`, tag)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (shadow *viewShadowData) Get(tag string) any {
|
|
||||||
return shadow.propertyList.Get(strings.ToLower(tag))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (shadow *viewShadowData) cssStyle(buffer *strings.Builder, session Session, lead string) bool {
|
func (shadow *viewShadowData) cssStyle(buffer *strings.Builder, session Session, lead string) bool {
|
||||||
|
@ -316,7 +298,7 @@ func (shadow *viewShadowData) writeString(buffer *strings.Builder, indent string
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
|
@ -325,29 +307,29 @@ func (shadow *viewShadowData) writeString(buffer *strings.Builder, indent string
|
||||||
buffer.WriteString(" }")
|
buffer.WriteString(" }")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (properties *propertyList) setShadow(tag string, value any) bool {
|
func setShadowProperty(properties Properties, tag PropertyName, value any) bool {
|
||||||
|
|
||||||
if value == nil {
|
if value == nil {
|
||||||
delete(properties.properties, tag)
|
properties.setRaw(tag, nil)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case ViewShadow:
|
case ViewShadow:
|
||||||
properties.properties[tag] = []ViewShadow{value}
|
properties.setRaw(tag, []ViewShadow{value})
|
||||||
|
|
||||||
case []ViewShadow:
|
case []ViewShadow:
|
||||||
if len(value) == 0 {
|
if len(value) == 0 {
|
||||||
delete(properties.properties, tag)
|
properties.setRaw(tag, nil)
|
||||||
} else {
|
} else {
|
||||||
properties.properties[tag] = value
|
properties.setRaw(tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataValue:
|
case DataValue:
|
||||||
if !value.IsObject() {
|
if !value.IsObject() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
properties.properties[tag] = []ViewShadow{parseViewShadow(value.Object())}
|
properties.setRaw(tag, []ViewShadow{parseViewShadow(value.Object())})
|
||||||
|
|
||||||
case []DataValue:
|
case []DataValue:
|
||||||
shadows := []ViewShadow{}
|
shadows := []ViewShadow{}
|
||||||
|
@ -359,7 +341,7 @@ func (properties *propertyList) setShadow(tag string, value any) bool {
|
||||||
if len(shadows) == 0 {
|
if len(shadows) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
properties.properties[tag] = shadows
|
properties.setRaw(tag, shadows)
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
obj := NewDataObject(value)
|
obj := NewDataObject(value)
|
||||||
|
@ -367,7 +349,7 @@ func (properties *propertyList) setShadow(tag string, value any) bool {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
properties.properties[tag] = []ViewShadow{parseViewShadow(obj)}
|
properties.setRaw(tag, []ViewShadow{parseViewShadow(obj)})
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
|
@ -377,7 +359,7 @@ func (properties *propertyList) setShadow(tag string, value any) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getShadows(properties Properties, tag string) []ViewShadow {
|
func getShadows(properties Properties, tag PropertyName) []ViewShadow {
|
||||||
if value := properties.Get(tag); value != nil {
|
if value := properties.Get(tag); value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case []ViewShadow:
|
case []ViewShadow:
|
||||||
|
@ -390,7 +372,7 @@ func getShadows(properties Properties, tag string) []ViewShadow {
|
||||||
return []ViewShadow{}
|
return []ViewShadow{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func shadowCSS(properties Properties, tag string, session Session) string {
|
func shadowCSS(properties Properties, tag PropertyName, session Session) string {
|
||||||
shadows := getShadows(properties, tag)
|
shadows := getShadows(properties, tag)
|
||||||
if len(shadows) == 0 {
|
if len(shadows) == 0 {
|
||||||
return ""
|
return ""
|
||||||
|
|
127
stackLayout.go
127
stackLayout.go
|
@ -55,7 +55,7 @@ type StackLayout interface {
|
||||||
|
|
||||||
type stackLayoutData struct {
|
type stackLayoutData struct {
|
||||||
viewsContainerData
|
viewsContainerData
|
||||||
peek int
|
peek, prevPeek int
|
||||||
pushView, popView View
|
pushView, popView View
|
||||||
animationType int
|
animationType int
|
||||||
onPushFinished func()
|
onPushFinished func()
|
||||||
|
@ -71,7 +71,8 @@ func NewStackLayout(session Session, params Params) StackLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStackLayout(session Session) View {
|
func newStackLayout(session Session) View {
|
||||||
return NewStackLayout(session, nil)
|
//return NewStackLayout(session, nil)
|
||||||
|
return new(stackLayoutData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of ViewsContainer by default values
|
// Init initialize fields of ViewsContainer by default values
|
||||||
|
@ -80,10 +81,9 @@ func (layout *stackLayoutData) init(session Session) {
|
||||||
layout.tag = "StackLayout"
|
layout.tag = "StackLayout"
|
||||||
layout.systemClass = "ruiStackLayout"
|
layout.systemClass = "ruiStackLayout"
|
||||||
layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished}
|
layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished}
|
||||||
}
|
layout.getFunc = layout.get
|
||||||
|
layout.set = layout.setFunc
|
||||||
func (layout *stackLayoutData) String() string {
|
layout.remove = layout.removeFunc
|
||||||
return getViewString(layout, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (layout *stackLayoutData) pushFinished(view View, tag string) {
|
func (layout *stackLayoutData) pushFinished(view View, tag string) {
|
||||||
|
@ -97,7 +97,7 @@ func (layout *stackLayoutData) pushFinished(view View, tag string) {
|
||||||
layout.peek = 0
|
layout.peek = 0
|
||||||
}
|
}
|
||||||
updateInnerHTML(layout.htmlID(), layout.session)
|
updateInnerHTML(layout.htmlID(), layout.session)
|
||||||
layout.propertyChangedEvent(Current)
|
layout.currentChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.onPushFinished != nil {
|
if layout.onPushFinished != nil {
|
||||||
|
@ -121,97 +121,91 @@ func (layout *stackLayoutData) popFinished(view View, tag string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (layout *stackLayoutData) Set(tag string, value any) bool {
|
func (layout *stackLayoutData) setFunc(view View, tag PropertyName, value any) []PropertyName {
|
||||||
return layout.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (layout *stackLayoutData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
layout.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case TransitionEndEvent:
|
case TransitionEndEvent:
|
||||||
listeners, ok := valueToEventListeners[View, string](value)
|
listeners, ok := valueToEventListeners[View, string](value)
|
||||||
if ok && listeners != nil {
|
if ok && listeners != nil {
|
||||||
listeners = append(listeners, layout.pushFinished)
|
listeners = append(listeners, layout.pushFinished)
|
||||||
listeners = append(listeners, layout.popFinished)
|
listeners = append(listeners, layout.popFinished)
|
||||||
layout.properties[TransitionEndEvent] = listeners
|
view.setRaw(TransitionEndEvent, listeners)
|
||||||
layout.propertyChangedEvent(TransitionEndEvent)
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
return ok
|
return nil
|
||||||
|
|
||||||
case Current:
|
case Current:
|
||||||
setCurrent := func(index int) {
|
newCurrent := 0
|
||||||
if index != layout.peek {
|
|
||||||
if layout.peek < len(layout.views) {
|
|
||||||
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(layout.peek), "visibility", "hidden")
|
|
||||||
}
|
|
||||||
|
|
||||||
layout.peek = index
|
|
||||||
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(index), "visibility", "visible")
|
|
||||||
layout.propertyChangedEvent(Current)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
text, ok := layout.session.resolveConstants(value)
|
text, ok := layout.session.resolveConstants(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
n, err := strconv.Atoi(strings.Trim(text, " \t"))
|
n, err := strconv.Atoi(strings.Trim(text, " \t"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
invalidPropertyValue(tag, value)
|
invalidPropertyValue(tag, value)
|
||||||
ErrorLog(err.Error())
|
ErrorLog(err.Error())
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
setCurrent(n)
|
newCurrent = n
|
||||||
|
|
||||||
default:
|
default:
|
||||||
n, ok := isInt(value)
|
n, ok := isInt(value)
|
||||||
if !ok {
|
if !ok {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
} else if n < 0 || n >= len(layout.views) {
|
} else if n < 0 || n >= len(layout.views) {
|
||||||
ErrorLogF(`The view index "%d" of "%s" property is out of range`, n, tag)
|
ErrorLogF(`The view index "%d" of "%s" property is out of range`, n, tag)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
setCurrent(n)
|
newCurrent = n
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return layout.viewsContainerData.set(tag, value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (layout *stackLayoutData) Remove(tag string) {
|
layout.prevPeek = layout.peek
|
||||||
layout.remove(strings.ToLower(tag))
|
if newCurrent == layout.peek {
|
||||||
|
return []PropertyName{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (layout *stackLayoutData) remove(tag string) {
|
layout.peek = newCurrent
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
return layout.viewsContainerData.setFunc(view, tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (layout *stackLayoutData) propertyChanged(view View, tag PropertyName) {
|
||||||
|
switch tag {
|
||||||
|
case Current:
|
||||||
|
if layout.prevPeek != layout.peek {
|
||||||
|
if layout.prevPeek < len(layout.views) {
|
||||||
|
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(layout.prevPeek), "visibility", "hidden")
|
||||||
|
}
|
||||||
|
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(layout.prevPeek), "visibility", "visible")
|
||||||
|
layout.prevPeek = layout.peek
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
viewsContainerPropertyChanged(view, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (layout *stackLayoutData) removeFunc(view View, tag PropertyName) []PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case TransitionEndEvent:
|
case TransitionEndEvent:
|
||||||
layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished}
|
view.setRaw(TransitionEndEvent, []func(View, string){layout.pushFinished, layout.popFinished})
|
||||||
layout.propertyChangedEvent(TransitionEndEvent)
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case Current:
|
case Current:
|
||||||
layout.set(Current, 0)
|
view.setRaw(Current, 0)
|
||||||
|
return []PropertyName{tag}
|
||||||
default:
|
|
||||||
layout.viewsContainerData.remove(tag)
|
|
||||||
}
|
}
|
||||||
|
return layout.viewsContainerData.removeFunc(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (layout *stackLayoutData) Get(tag string) any {
|
func (layout *stackLayoutData) get(view View, tag PropertyName) any {
|
||||||
return layout.get(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (layout *stackLayoutData) get(tag string) any {
|
|
||||||
if tag == Current {
|
if tag == Current {
|
||||||
return layout.peek
|
return layout.peek
|
||||||
}
|
}
|
||||||
return layout.viewsContainerData.get(tag)
|
return layout.viewsContainerData.get(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (layout *stackLayoutData) Peek() View {
|
func (layout *stackLayoutData) Peek() View {
|
||||||
|
@ -233,7 +227,7 @@ func (layout *stackLayoutData) MoveToFront(view View) bool {
|
||||||
|
|
||||||
layout.peek = i
|
layout.peek = i
|
||||||
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(i), "visibility", "visible")
|
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(i), "visibility", "visible")
|
||||||
layout.propertyChangedEvent(Current)
|
layout.currentChanged()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -243,6 +237,12 @@ func (layout *stackLayoutData) MoveToFront(view View) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (layout *stackLayoutData) currentChanged() {
|
||||||
|
if listener, ok := layout.changeListener[Current]; ok {
|
||||||
|
listener(layout, Current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (layout *stackLayoutData) MoveToFrontByID(viewID string) bool {
|
func (layout *stackLayoutData) MoveToFrontByID(viewID string) bool {
|
||||||
peek := int(layout.peek)
|
peek := int(layout.peek)
|
||||||
for i, view := range layout.views {
|
for i, view := range layout.views {
|
||||||
|
@ -254,7 +254,7 @@ func (layout *stackLayoutData) MoveToFrontByID(viewID string) bool {
|
||||||
|
|
||||||
layout.peek = i
|
layout.peek = i
|
||||||
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(i), "visibility", "visible")
|
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(i), "visibility", "visible")
|
||||||
layout.propertyChangedEvent(Current)
|
layout.currentChanged()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -268,7 +268,7 @@ func (layout *stackLayoutData) Append(view View) {
|
||||||
if view != nil {
|
if view != nil {
|
||||||
layout.peek = len(layout.views)
|
layout.peek = len(layout.views)
|
||||||
layout.viewsContainerData.Append(view)
|
layout.viewsContainerData.Append(view)
|
||||||
layout.propertyChangedEvent(Current)
|
layout.currentChanged()
|
||||||
} else {
|
} else {
|
||||||
ErrorLog("StackLayout.Append(nil, ....) is forbidden")
|
ErrorLog("StackLayout.Append(nil, ....) is forbidden")
|
||||||
}
|
}
|
||||||
|
@ -283,7 +283,7 @@ func (layout *stackLayoutData) Insert(view View, index int) {
|
||||||
layout.peek = count
|
layout.peek = count
|
||||||
}
|
}
|
||||||
layout.viewsContainerData.Insert(view, index)
|
layout.viewsContainerData.Insert(view, index)
|
||||||
layout.propertyChangedEvent(Current)
|
layout.currentChanged()
|
||||||
} else {
|
} else {
|
||||||
ErrorLog("StackLayout.Insert(nil, ....) is forbidden")
|
ErrorLog("StackLayout.Insert(nil, ....) is forbidden")
|
||||||
}
|
}
|
||||||
|
@ -297,7 +297,7 @@ func (layout *stackLayoutData) RemoveView(index int) View {
|
||||||
if layout.peek > 0 {
|
if layout.peek > 0 {
|
||||||
layout.peek--
|
layout.peek--
|
||||||
}
|
}
|
||||||
defer layout.propertyChangedEvent(Current)
|
defer layout.currentChanged()
|
||||||
return layout.viewsContainerData.RemoveView(index)
|
return layout.viewsContainerData.RemoveView(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +352,10 @@ func (layout *stackLayoutData) Push(view View, animation int, onPushFinished fun
|
||||||
|
|
||||||
layout.views = append(layout.views, view)
|
layout.views = append(layout.views, view)
|
||||||
view.setParentID(htmlID)
|
view.setParentID(htmlID)
|
||||||
layout.propertyChangedEvent(Content)
|
|
||||||
|
if listener, ok := layout.changeListener[Content]; ok {
|
||||||
|
listener(layout, Content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (layout *stackLayoutData) Pop(animation int, onPopFinished func(View)) bool {
|
func (layout *stackLayoutData) Pop(animation int, onPopFinished func(View)) bool {
|
||||||
|
|
|
@ -25,7 +25,7 @@ func NewSvgImageView(session Session, params Params) SvgImageView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSvgImageView(session Session) View {
|
func newSvgImageView(session Session) View {
|
||||||
return NewSvgImageView(session, nil)
|
return new(svgImageViewData) // NewSvgImageView(session, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of imageView by default values
|
// Init initialize fields of imageView by default values
|
||||||
|
@ -33,14 +33,14 @@ func (imageView *svgImageViewData) init(session Session) {
|
||||||
imageView.viewData.init(session)
|
imageView.viewData.init(session)
|
||||||
imageView.tag = "SvgImageView"
|
imageView.tag = "SvgImageView"
|
||||||
imageView.systemClass = "ruiSvgImageView"
|
imageView.systemClass = "ruiSvgImageView"
|
||||||
|
imageView.normalize = normalizeSvgImageViewTag
|
||||||
|
imageView.set = svgImageViewSet
|
||||||
|
imageView.changed = svgImageViewPropertyChanged
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imageView *svgImageViewData) String() string {
|
func normalizeSvgImageViewTag(tag PropertyName) PropertyName {
|
||||||
return getViewString(imageView, nil)
|
tag = defaultNormalize(tag)
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *svgImageViewData) normalizeTag(tag string) string {
|
|
||||||
tag = strings.ToLower(tag)
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Source, "source":
|
case Source, "source":
|
||||||
tag = Content
|
tag = Content
|
||||||
|
@ -54,51 +54,29 @@ func (imageView *svgImageViewData) normalizeTag(tag string) string {
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imageView *svgImageViewData) Remove(tag string) {
|
func svgImageViewSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
imageView.remove(imageView.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *svgImageViewData) remove(tag string) {
|
|
||||||
imageView.viewData.remove(tag)
|
|
||||||
|
|
||||||
if imageView.created {
|
|
||||||
switch tag {
|
|
||||||
case Content:
|
|
||||||
updateInnerHTML(imageView.htmlID(), imageView.session)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *svgImageViewData) Set(tag string, value any) bool {
|
|
||||||
return imageView.set(imageView.normalizeTag(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (imageView *svgImageViewData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
imageView.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Content:
|
case Content:
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
imageView.properties[Content] = text
|
view.setRaw(Content, text)
|
||||||
if imageView.created {
|
return []PropertyName{tag}
|
||||||
updateInnerHTML(imageView.htmlID(), imageView.session)
|
|
||||||
}
|
|
||||||
imageView.propertyChangedEvent(Content)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
notCompatibleType(Source, value)
|
notCompatibleType(Source, value)
|
||||||
return false
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return imageView.viewData.set(tag, value)
|
return viewSet(view, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imageView *svgImageViewData) Get(tag string) any {
|
func svgImageViewPropertyChanged(view View, tag PropertyName) {
|
||||||
return imageView.viewData.get(imageView.normalizeTag(tag))
|
switch tag {
|
||||||
|
case Content:
|
||||||
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
|
|
||||||
|
default:
|
||||||
|
viewPropertyChanged(view, tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imageView *svgImageViewData) htmlTag() string {
|
func (imageView *svgImageViewData) htmlTag() string {
|
||||||
|
|
|
@ -256,78 +256,3 @@ func (style *simpleTableLineStyle) RowStyle(row int) Params {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (table *tableViewData) setLineStyle(tag string, value any) bool {
|
|
||||||
switch value := value.(type) {
|
|
||||||
case []Params:
|
|
||||||
if len(value) > 0 {
|
|
||||||
style := new(simpleTableLineStyle)
|
|
||||||
style.params = value
|
|
||||||
table.properties[tag] = style
|
|
||||||
} else {
|
|
||||||
delete(table.properties, tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataNode:
|
|
||||||
if params := value.ArrayAsParams(); len(params) > 0 {
|
|
||||||
style := new(simpleTableLineStyle)
|
|
||||||
style.params = params
|
|
||||||
table.properties[tag] = style
|
|
||||||
} else {
|
|
||||||
delete(table.properties, tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *tableViewData) setRowStyle(value any) bool {
|
|
||||||
switch value := value.(type) {
|
|
||||||
case TableRowStyle:
|
|
||||||
table.properties[RowStyle] = value
|
|
||||||
}
|
|
||||||
return table.setLineStyle(RowStyle, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *tableViewData) getRowStyle() TableRowStyle {
|
|
||||||
for _, tag := range []string{RowStyle, Content} {
|
|
||||||
if value := table.getRaw(tag); value != nil {
|
|
||||||
if style, ok := value.(TableRowStyle); ok {
|
|
||||||
return style
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *tableViewData) setColumnStyle(value any) bool {
|
|
||||||
switch value := value.(type) {
|
|
||||||
case TableColumnStyle:
|
|
||||||
table.properties[ColumnStyle] = value
|
|
||||||
}
|
|
||||||
return table.setLineStyle(ColumnStyle, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *tableViewData) getColumnStyle() TableColumnStyle {
|
|
||||||
for _, tag := range []string{ColumnStyle, Content} {
|
|
||||||
if value := table.getRaw(tag); value != nil {
|
|
||||||
if style, ok := value.(TableColumnStyle); ok {
|
|
||||||
return style
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (table *tableViewData) getCellStyle() TableCellStyle {
|
|
||||||
for _, tag := range []string{CellStyle, Content} {
|
|
||||||
if value := table.getRaw(tag); value != nil {
|
|
||||||
if style, ok := value.(TableCellStyle); ok {
|
|
||||||
return style
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
559
tableView.go
559
tableView.go
File diff suppressed because it is too large
Load Diff
|
@ -1,17 +1,19 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
import "strings"
|
func newTableCellView(session Session) *tableCellView {
|
||||||
|
view := new(tableCellView)
|
||||||
func (cell *tableCellView) Set(tag string, value any) bool {
|
view.init(session)
|
||||||
return cell.set(strings.ToLower(tag), value)
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cell *tableCellView) set(tag string, value any) bool {
|
func (cell *tableCellView) init(session Session) {
|
||||||
switch tag {
|
cell.viewData.init(session)
|
||||||
case VerticalAlign:
|
cell.normalize = func(tag PropertyName) PropertyName {
|
||||||
tag = TableVerticalAlign
|
if tag == VerticalAlign {
|
||||||
|
return TableVerticalAlign
|
||||||
|
}
|
||||||
|
return tag
|
||||||
}
|
}
|
||||||
return cell.viewData.set(tag, value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cell *tableCellView) cssStyle(self View, builder cssBuilder) {
|
func (cell *tableCellView) cssStyle(self View, builder cssBuilder) {
|
||||||
|
@ -31,8 +33,10 @@ func GetTableContent(view View, subviewID ...string) TableAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if tableView, ok := view.(TableView); ok {
|
if content := view.getRaw(Content); content != nil {
|
||||||
return tableView.content()
|
if adapter, ok := content.(TableAdapter); ok {
|
||||||
|
return adapter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +51,12 @@ func GetTableRowStyle(view View, subviewID ...string) TableRowStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if tableView, ok := view.(TableView); ok {
|
for _, tag := range []PropertyName{RowStyle, Content} {
|
||||||
return tableView.getRowStyle()
|
if value := view.getRaw(tag); value != nil {
|
||||||
|
if style, ok := value.(TableRowStyle); ok {
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +71,12 @@ func GetTableColumnStyle(view View, subviewID ...string) TableColumnStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if tableView, ok := view.(TableView); ok {
|
for _, tag := range []PropertyName{ColumnStyle, Content} {
|
||||||
return tableView.getColumnStyle()
|
if value := view.getRaw(tag); value != nil {
|
||||||
|
if style, ok := value.(TableColumnStyle); ok {
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,10 +91,15 @@ func GetTableCellStyle(view View, subviewID ...string) TableCellStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if tableView, ok := view.(TableView); ok {
|
for _, tag := range []PropertyName{CellStyle, Content} {
|
||||||
return tableView.getCellStyle()
|
if value := view.getRaw(tag); value != nil {
|
||||||
|
if style, ok := value.(TableCellStyle); ok {
|
||||||
|
return style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -125,9 +142,7 @@ func GetTableCurrent(view View, subviewID ...string) CellIndex {
|
||||||
|
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if selectionMode := GetTableSelectionMode(view); selectionMode != NoneSelection {
|
if selectionMode := GetTableSelectionMode(view); selectionMode != NoneSelection {
|
||||||
if tableView, ok := view.(TableView); ok {
|
return tableViewCurrent(view)
|
||||||
return tableView.getCurrent()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CellIndex{Row: -1, Column: -1}
|
return CellIndex{Row: -1, Column: -1}
|
||||||
|
@ -137,34 +152,14 @@ func GetTableCurrent(view View, subviewID ...string) CellIndex {
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||||
func GetTableCellClickedListeners(view View, subviewID ...string) []func(TableView, int, int) {
|
func GetTableCellClickedListeners(view View, subviewID ...string) []func(TableView, int, int) {
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
return getEventWithOldListeners[TableView, int](view, subviewID, TableCellClickedEvent)
|
||||||
view = ViewByID(view, subviewID[0])
|
|
||||||
}
|
|
||||||
if view != nil {
|
|
||||||
if value := view.Get(TableCellClickedEvent); value != nil {
|
|
||||||
if result, ok := value.([]func(TableView, int, int)); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []func(TableView, int, int){}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableCellSelectedListeners returns listeners of event which occurs when a table cell becomes selected.
|
// GetTableCellSelectedListeners returns listeners of event which occurs when a table cell becomes selected.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||||
func GetTableCellSelectedListeners(view View, subviewID ...string) []func(TableView, int, int) {
|
func GetTableCellSelectedListeners(view View, subviewID ...string) []func(TableView, int, int) {
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
return getEventWithOldListeners[TableView, int](view, subviewID, TableCellSelectedEvent)
|
||||||
view = ViewByID(view, subviewID[0])
|
|
||||||
}
|
|
||||||
if view != nil {
|
|
||||||
if value := view.Get(TableCellSelectedEvent); value != nil {
|
|
||||||
if result, ok := value.([]func(TableView, int, int)); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []func(TableView, int, int){}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableRowClickedListeners returns listeners of event which occurs when the user clicks on a table row.
|
// GetTableRowClickedListeners returns listeners of event which occurs when the user clicks on a table row.
|
||||||
|
|
338
tabsLayout.go
338
tabsLayout.go
|
@ -5,7 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Constants for [TabsLayout] specific properties and events
|
// Constants for [TabsLayout] specific view and events
|
||||||
const (
|
const (
|
||||||
// CurrentTabChangedEvent is the constant for "current-tab-changed" property tag.
|
// CurrentTabChangedEvent is the constant for "current-tab-changed" property tag.
|
||||||
//
|
//
|
||||||
|
@ -25,7 +25,7 @@ const (
|
||||||
// `func(newTab, oldTab int)`,
|
// `func(newTab, oldTab int)`,
|
||||||
// `func(newTab int)`,
|
// `func(newTab int)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
CurrentTabChangedEvent = "current-tab-changed"
|
CurrentTabChangedEvent PropertyName = "current-tab-changed"
|
||||||
|
|
||||||
// Icon is the constant for "icon" property tag.
|
// Icon is the constant for "icon" property tag.
|
||||||
//
|
//
|
||||||
|
@ -47,7 +47,7 @@ const (
|
||||||
// Values:
|
// Values:
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Tab(s) has close button.
|
// `true` or `1` or "true", "yes", "on", "1" - Tab(s) has close button.
|
||||||
// `false` or `0` or "false", "no", "off", "0" - No close button in tab(s).
|
// `false` or `0` or "false", "no", "off", "0" - No close button in tab(s).
|
||||||
TabCloseButton = "tab-close-button"
|
TabCloseButton PropertyName = "tab-close-button"
|
||||||
|
|
||||||
// TabCloseEvent is the constant for "tab-close-event" property tag.
|
// TabCloseEvent is the constant for "tab-close-event" property tag.
|
||||||
//
|
//
|
||||||
|
@ -65,7 +65,7 @@ const (
|
||||||
// `func(tab int)`,
|
// `func(tab int)`,
|
||||||
// `func(tabsLayout rui.TabsLayout)`,
|
// `func(tabsLayout rui.TabsLayout)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TabCloseEvent = "tab-close-event"
|
TabCloseEvent PropertyName = "tab-close-event"
|
||||||
|
|
||||||
// Tabs is the constant for "tabs" property tag.
|
// Tabs is the constant for "tabs" property tag.
|
||||||
//
|
//
|
||||||
|
@ -82,7 +82,7 @@ const (
|
||||||
// `4`(`LeftListTabs`) or "left-list" - Tabs on the left. The tabs are displayed as a list.
|
// `4`(`LeftListTabs`) or "left-list" - Tabs on the left. The tabs are displayed as a list.
|
||||||
// `5`(`RightListTabs`) or "right-list" - Tabs on the right. The tabs are displayed as a list.
|
// `5`(`RightListTabs`) or "right-list" - Tabs on the right. The tabs are displayed as a list.
|
||||||
// `6`(`HiddenTabs`) or "hidden" - Tabs are hidden.
|
// `6`(`HiddenTabs`) or "hidden" - Tabs are hidden.
|
||||||
Tabs = "tabs"
|
Tabs PropertyName = "tabs"
|
||||||
|
|
||||||
// TabBarStyle is the constant for "tab-bar-style" property tag.
|
// TabBarStyle is the constant for "tab-bar-style" property tag.
|
||||||
//
|
//
|
||||||
|
@ -90,7 +90,7 @@ const (
|
||||||
// Set the style for the display of the tab bar. The default value is "ruiTabBar".
|
// Set the style for the display of the tab bar. The default value is "ruiTabBar".
|
||||||
//
|
//
|
||||||
// Supported types: `string`.
|
// Supported types: `string`.
|
||||||
TabBarStyle = "tab-bar-style"
|
TabBarStyle PropertyName = "tab-bar-style"
|
||||||
|
|
||||||
// TabStyle is the constant for "tab-style" property tag.
|
// TabStyle is the constant for "tab-style" property tag.
|
||||||
//
|
//
|
||||||
|
@ -98,7 +98,7 @@ const (
|
||||||
// Set the style for the display of the tab. The default value is "ruiTab" or "ruiVerticalTab".
|
// Set the style for the display of the tab. The default value is "ruiTab" or "ruiVerticalTab".
|
||||||
//
|
//
|
||||||
// Supported types: `string`.
|
// Supported types: `string`.
|
||||||
TabStyle = "tab-style"
|
TabStyle PropertyName = "tab-style"
|
||||||
|
|
||||||
// CurrentTabStyle is the constant for "current-tab-style" property tag.
|
// CurrentTabStyle is the constant for "current-tab-style" property tag.
|
||||||
//
|
//
|
||||||
|
@ -107,7 +107,7 @@ const (
|
||||||
// "ruiCurrentVerticalTab".
|
// "ruiCurrentVerticalTab".
|
||||||
//
|
//
|
||||||
// Supported types: `string`.
|
// Supported types: `string`.
|
||||||
CurrentTabStyle = "current-tab-style"
|
CurrentTabStyle PropertyName = "current-tab-style"
|
||||||
|
|
||||||
inactiveTabStyle = "data-inactiveTabStyle"
|
inactiveTabStyle = "data-inactiveTabStyle"
|
||||||
activeTabStyle = "data-activeTabStyle"
|
activeTabStyle = "data-activeTabStyle"
|
||||||
|
@ -139,8 +139,6 @@ type TabsLayout interface {
|
||||||
|
|
||||||
type tabsLayoutData struct {
|
type tabsLayoutData struct {
|
||||||
viewsContainerData
|
viewsContainerData
|
||||||
tabListener []func(TabsLayout, int, int)
|
|
||||||
tabCloseListener []func(TabsLayout, int)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTabsLayout create new TabsLayout object and return it
|
// NewTabsLayout create new TabsLayout object and return it
|
||||||
|
@ -152,7 +150,8 @@ func NewTabsLayout(session Session, params Params) TabsLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTabsLayout(session Session) View {
|
func newTabsLayout(session Session) View {
|
||||||
return NewTabsLayout(session, nil)
|
//return NewTabsLayout(session, nil)
|
||||||
|
return new(tabsLayoutData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of ViewsContainer by default values
|
// Init initialize fields of ViewsContainer by default values
|
||||||
|
@ -160,199 +159,82 @@ func (tabsLayout *tabsLayoutData) init(session Session) {
|
||||||
tabsLayout.viewsContainerData.init(session)
|
tabsLayout.viewsContainerData.init(session)
|
||||||
tabsLayout.tag = "TabsLayout"
|
tabsLayout.tag = "TabsLayout"
|
||||||
tabsLayout.systemClass = "ruiTabsLayout"
|
tabsLayout.systemClass = "ruiTabsLayout"
|
||||||
tabsLayout.tabListener = []func(TabsLayout, int, int){}
|
tabsLayout.set = tabsLayout.setFunc
|
||||||
tabsLayout.tabCloseListener = []func(TabsLayout, int){}
|
tabsLayout.changed = tabsLayout.propertyChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) String() string {
|
func tabsLayoutCurrent(view View, defaultValue int) int {
|
||||||
return getViewString(tabsLayout, nil)
|
result, _ := intProperty(view, Current, view.Session(), defaultValue)
|
||||||
}
|
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) currentItem(defaultValue int) int {
|
|
||||||
result, _ := intProperty(tabsLayout, Current, tabsLayout.session, defaultValue)
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) Get(tag string) any {
|
func (tabsLayout *tabsLayoutData) setFunc(view View, tag PropertyName, value any) []PropertyName {
|
||||||
return tabsLayout.get(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) get(tag string) any {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case CurrentTabChangedEvent:
|
case CurrentTabChangedEvent:
|
||||||
return tabsLayout.tabListener
|
return setEventWithOldListener[TabsLayout, int](view, tag, value)
|
||||||
|
|
||||||
case TabCloseEvent:
|
case TabCloseEvent:
|
||||||
return tabsLayout.tabCloseListener
|
return setViewEventListener[TabsLayout, int](view, tag, value)
|
||||||
}
|
|
||||||
|
|
||||||
return tabsLayout.viewsContainerData.get(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) Remove(tag string) {
|
|
||||||
tabsLayout.remove(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) remove(tag string) {
|
|
||||||
switch tag {
|
|
||||||
case CurrentTabChangedEvent:
|
|
||||||
if len(tabsLayout.tabListener) > 0 {
|
|
||||||
tabsLayout.tabListener = []func(TabsLayout, int, int){}
|
|
||||||
tabsLayout.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
case TabCloseEvent:
|
|
||||||
if len(tabsLayout.tabCloseListener) > 0 {
|
|
||||||
tabsLayout.tabCloseListener = []func(TabsLayout, int){}
|
|
||||||
tabsLayout.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
case Current:
|
case Current:
|
||||||
oldCurrent := tabsLayout.currentItem(0)
|
view.setRaw("old-current", tabsLayoutCurrent(view, -1))
|
||||||
delete(tabsLayout.properties, Current)
|
|
||||||
if oldCurrent == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if tabsLayout.created {
|
|
||||||
tabsLayout.session.callFunc("activateTab", tabsLayout.htmlID(), 0)
|
|
||||||
for _, listener := range tabsLayout.tabListener {
|
|
||||||
listener(tabsLayout, 0, oldCurrent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case Tabs:
|
|
||||||
delete(tabsLayout.properties, Tabs)
|
|
||||||
if tabsLayout.created {
|
|
||||||
htmlID := tabsLayout.htmlID()
|
|
||||||
tabsLayout.session.updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle())
|
|
||||||
tabsLayout.session.updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle())
|
|
||||||
updateCSSStyle(htmlID, tabsLayout.session)
|
|
||||||
updateInnerHTML(htmlID, tabsLayout.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
case TabStyle, CurrentTabStyle:
|
|
||||||
delete(tabsLayout.properties, tag)
|
|
||||||
if tabsLayout.created {
|
|
||||||
htmlID := tabsLayout.htmlID()
|
|
||||||
tabsLayout.session.updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle())
|
|
||||||
tabsLayout.session.updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle())
|
|
||||||
updateInnerHTML(htmlID, tabsLayout.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
case TabCloseButton:
|
|
||||||
delete(tabsLayout.properties, tag)
|
|
||||||
if tabsLayout.created {
|
|
||||||
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
tabsLayout.viewsContainerData.remove(tag)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tabsLayout.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) Set(tag string, value any) bool {
|
|
||||||
return tabsLayout.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
tabsLayout.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
|
||||||
case CurrentTabChangedEvent:
|
|
||||||
listeners := tabsLayout.valueToTabListeners(value)
|
|
||||||
if listeners == nil {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
tabsLayout.tabListener = listeners
|
|
||||||
|
|
||||||
case TabCloseEvent:
|
|
||||||
listeners, ok := valueToEventListeners[TabsLayout, int](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
} else if listeners == nil {
|
|
||||||
listeners = []func(TabsLayout, int){}
|
|
||||||
}
|
|
||||||
tabsLayout.tabCloseListener = listeners
|
|
||||||
|
|
||||||
case Current:
|
|
||||||
if current, ok := value.(int); ok && current < 0 {
|
if current, ok := value.(int); ok && current < 0 {
|
||||||
tabsLayout.remove(Current)
|
view.setRaw(Current, nil)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
oldCurrent := tabsLayout.currentItem(-1)
|
return setIntProperty(view, Current, value)
|
||||||
if !tabsLayout.setIntProperty(Current, value) {
|
|
||||||
return false
|
case TabStyle, CurrentTabStyle, TabBarStyle:
|
||||||
|
if text, ok := value.(string); ok {
|
||||||
|
return setStringPropertyValue(view, tag, text)
|
||||||
|
}
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
current := tabsLayout.currentItem(0)
|
return tabsLayout.viewsContainerData.setFunc(tabsLayout, tag, value)
|
||||||
if oldCurrent == current {
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
if tabsLayout.created {
|
|
||||||
tabsLayout.session.callFunc("activateTab", tabsLayout.htmlID(), current)
|
func (tabsLayout *tabsLayoutData) propertyChanged(view View, tag PropertyName) {
|
||||||
for _, listener := range tabsLayout.tabListener {
|
switch tag {
|
||||||
|
case Current:
|
||||||
|
session := view.Session()
|
||||||
|
current := GetCurrent(view)
|
||||||
|
session.callFunc("activateTab", view.htmlID(), current)
|
||||||
|
|
||||||
|
if listeners := getEventWithOldListeners[TabsLayout, int](view, nil, CurrentTabChangedEvent); len(listeners) > 0 {
|
||||||
|
oldCurrent, _ := intProperty(view, "old-current", session, -1)
|
||||||
|
for _, listener := range listeners {
|
||||||
listener(tabsLayout, current, oldCurrent)
|
listener(tabsLayout, current, oldCurrent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case Tabs:
|
case Tabs:
|
||||||
if !tabsLayout.setEnumProperty(Tabs, value, enumProperties[Tabs].values) {
|
htmlID := view.htmlID()
|
||||||
return false
|
session := view.Session()
|
||||||
}
|
session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(view))
|
||||||
if tabsLayout.created {
|
session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(view))
|
||||||
htmlID := tabsLayout.htmlID()
|
updateCSSStyle(htmlID, session)
|
||||||
tabsLayout.session.updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle())
|
updateInnerHTML(htmlID, session)
|
||||||
tabsLayout.session.updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle())
|
|
||||||
updateCSSStyle(htmlID, tabsLayout.session)
|
|
||||||
updateInnerHTML(htmlID, tabsLayout.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
case TabStyle, CurrentTabStyle, TabBarStyle:
|
case TabStyle, CurrentTabStyle, TabBarStyle:
|
||||||
if text, ok := value.(string); ok {
|
htmlID := view.htmlID()
|
||||||
if text == "" {
|
session := view.Session()
|
||||||
delete(tabsLayout.properties, tag)
|
session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(view))
|
||||||
} else {
|
session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(view))
|
||||||
tabsLayout.properties[tag] = text
|
updateInnerHTML(htmlID, session)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if tabsLayout.created {
|
|
||||||
htmlID := tabsLayout.htmlID()
|
|
||||||
tabsLayout.session.updateProperty(htmlID, inactiveTabStyle, tabsLayout.inactiveTabStyle())
|
|
||||||
tabsLayout.session.updateProperty(htmlID, activeTabStyle, tabsLayout.activeTabStyle())
|
|
||||||
updateInnerHTML(htmlID, tabsLayout.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
case TabCloseButton:
|
case TabCloseButton:
|
||||||
if !tabsLayout.setBoolProperty(tag, value) {
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
return false
|
|
||||||
}
|
|
||||||
if tabsLayout.created {
|
|
||||||
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return tabsLayout.viewsContainerData.set(tag, value)
|
viewsContainerPropertyChanged(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
tabsLayout.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayout, int, int) {
|
func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayout, int, int) {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return []func(TabsLayout, int, int){}
|
return []func(TabsLayout, int, int){}
|
||||||
|
@ -499,6 +381,7 @@ func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayo
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) tabsLocation() int {
|
func (tabsLayout *tabsLayoutData) tabsLocation() int {
|
||||||
tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0)
|
tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0)
|
||||||
|
@ -519,36 +402,42 @@ func (tabsLayout *tabsLayoutData) tabBarStyle() string {
|
||||||
return "ruiTabBar"
|
return "ruiTabBar"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) inactiveTabStyle() string {
|
func tabsLayoutInactiveTabStyle(view View) string {
|
||||||
if style, ok := stringProperty(tabsLayout, TabStyle, tabsLayout.session); ok {
|
session := view.Session()
|
||||||
|
if style, ok := stringProperty(view, TabStyle, session); ok {
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
if value := valueFromStyle(tabsLayout, TabStyle); value != nil {
|
if value := valueFromStyle(view, TabStyle); value != nil {
|
||||||
if style, ok := value.(string); ok {
|
if style, ok := value.(string); ok {
|
||||||
if style, ok = tabsLayout.session.resolveConstants(style); ok {
|
if style, ok = session.resolveConstants(style); ok {
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch tabsLayout.tabsLocation() {
|
|
||||||
|
tabs, _ := enumProperty(view, Tabs, session, 0)
|
||||||
|
switch tabs {
|
||||||
case LeftTabs, RightTabs:
|
case LeftTabs, RightTabs:
|
||||||
return "ruiVerticalTab"
|
return "ruiVerticalTab"
|
||||||
}
|
}
|
||||||
return "ruiTab"
|
return "ruiTab"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) activeTabStyle() string {
|
func tabsLayoutActiveTabStyle(view View) string {
|
||||||
if style, ok := stringProperty(tabsLayout, CurrentTabStyle, tabsLayout.session); ok {
|
session := view.Session()
|
||||||
|
if style, ok := stringProperty(view, CurrentTabStyle, session); ok {
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
if value := valueFromStyle(tabsLayout, CurrentTabStyle); value != nil {
|
if value := valueFromStyle(view, CurrentTabStyle); value != nil {
|
||||||
if style, ok := value.(string); ok {
|
if style, ok := value.(string); ok {
|
||||||
if style, ok = tabsLayout.session.resolveConstants(style); ok {
|
if style, ok = session.resolveConstants(style); ok {
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch tabsLayout.tabsLocation() {
|
|
||||||
|
tabs, _ := enumProperty(view, Tabs, session, 0)
|
||||||
|
switch tabs {
|
||||||
case LeftTabs, RightTabs:
|
case LeftTabs, RightTabs:
|
||||||
return "ruiCurrentVerticalTab"
|
return "ruiCurrentVerticalTab"
|
||||||
}
|
}
|
||||||
|
@ -610,7 +499,7 @@ func (tabsLayout *tabsLayoutData) ListItem(index int, session Session) View {
|
||||||
Column: 2,
|
Column: 2,
|
||||||
Content: "✕",
|
Content: "✕",
|
||||||
ClickEvent: func() {
|
ClickEvent: func() {
|
||||||
for _, listener := range tabsLayout.tabCloseListener {
|
for _, listener := range getEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
|
||||||
listener(tabsLayout, index)
|
listener(tabsLayout, index)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -632,7 +521,7 @@ func (tabsLayout *tabsLayoutData) IsListItemEnabled(index int) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) updateTitle(view View, tag string) {
|
func (tabsLayout *tabsLayoutData) updateTitle(view View, tag PropertyName) {
|
||||||
session := tabsLayout.session
|
session := tabsLayout.session
|
||||||
title, _ := stringProperty(view, Title, session)
|
title, _ := stringProperty(view, Title, session)
|
||||||
if !GetNotTranslate(tabsLayout) {
|
if !GetNotTranslate(tabsLayout) {
|
||||||
|
@ -641,13 +530,13 @@ func (tabsLayout *tabsLayoutData) updateTitle(view View, tag string) {
|
||||||
session.updateInnerHTML(view.htmlID()+"-title", title)
|
session.updateInnerHTML(view.htmlID()+"-title", title)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) updateIcon(view View, tag string) {
|
func (tabsLayout *tabsLayoutData) updateIcon(view View, tag PropertyName) {
|
||||||
session := tabsLayout.session
|
session := tabsLayout.session
|
||||||
icon, _ := stringProperty(view, Icon, session)
|
icon, _ := stringProperty(view, Icon, session)
|
||||||
session.updateProperty(view.htmlID()+"-icon", "src", icon)
|
session.updateProperty(view.htmlID()+"-icon", "src", icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) updateTabCloseButton(view View, tag string) {
|
func (tabsLayout *tabsLayoutData) updateTabCloseButton(view View, tag PropertyName) {
|
||||||
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
|
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,11 +551,8 @@ func (tabsLayout *tabsLayoutData) Append(view View) {
|
||||||
view.SetChangeListener(Icon, tabsLayout.updateIcon)
|
view.SetChangeListener(Icon, tabsLayout.updateIcon)
|
||||||
view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton)
|
view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton)
|
||||||
if len(tabsLayout.views) == 1 {
|
if len(tabsLayout.views) == 1 {
|
||||||
tabsLayout.properties[Current] = 0
|
tabsLayout.setRaw(Current, nil)
|
||||||
for _, listener := range tabsLayout.tabListener {
|
tabsLayout.Set(Current, 0)
|
||||||
listener(tabsLayout, 0, -1)
|
|
||||||
}
|
|
||||||
defer tabsLayout.propertyChangedEvent(Current)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -677,9 +563,9 @@ func (tabsLayout *tabsLayoutData) Insert(view View, index int) {
|
||||||
tabsLayout.views = []View{}
|
tabsLayout.views = []View{}
|
||||||
}
|
}
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if current := tabsLayout.currentItem(0); current >= index {
|
if current := GetCurrent(tabsLayout); current >= index {
|
||||||
tabsLayout.properties[Current] = current + 1
|
tabsLayout.setRaw(Current, current+1)
|
||||||
defer tabsLayout.propertyChangedEvent(Current)
|
defer tabsLayout.currentChanged()
|
||||||
}
|
}
|
||||||
tabsLayout.viewsContainerData.Insert(view, index)
|
tabsLayout.viewsContainerData.Insert(view, index)
|
||||||
view.SetChangeListener(Title, tabsLayout.updateTitle)
|
view.SetChangeListener(Title, tabsLayout.updateTitle)
|
||||||
|
@ -688,8 +574,38 @@ func (tabsLayout *tabsLayoutData) Insert(view View, index int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tabsLayout *tabsLayoutData) currentChanged() {
|
||||||
|
if listener, ok := tabsLayout.changeListener[Current]; ok {
|
||||||
|
listener(tabsLayout, Current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove removes view from list and return it
|
// Remove removes view from list and return it
|
||||||
func (tabsLayout *tabsLayoutData) RemoveView(index int) View {
|
func (tabsLayout *tabsLayoutData) RemoveView(index int) View {
|
||||||
|
|
||||||
|
if index < 0 || index >= len(tabsLayout.views) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
oldCurrent := GetCurrent(tabsLayout)
|
||||||
|
newCurrent := oldCurrent
|
||||||
|
if index < oldCurrent || (index == oldCurrent && oldCurrent > 0) {
|
||||||
|
newCurrent--
|
||||||
|
}
|
||||||
|
|
||||||
|
if view := tabsLayout.viewsContainerData.RemoveView(index); view != nil {
|
||||||
|
view.SetChangeListener(Title, nil)
|
||||||
|
view.SetChangeListener(Icon, nil)
|
||||||
|
view.SetChangeListener(TabCloseButton, nil)
|
||||||
|
|
||||||
|
if newCurrent != oldCurrent {
|
||||||
|
tabsLayout.setRaw(Current, newCurrent)
|
||||||
|
tabsLayout.currentChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
/*
|
||||||
if tabsLayout.views == nil {
|
if tabsLayout.views == nil {
|
||||||
tabsLayout.views = []View{}
|
tabsLayout.views = []View{}
|
||||||
return nil
|
return nil
|
||||||
|
@ -706,7 +622,7 @@ func (tabsLayout *tabsLayoutData) RemoveView(index int) View {
|
||||||
view.SetChangeListener(Icon, nil)
|
view.SetChangeListener(Icon, nil)
|
||||||
view.SetChangeListener(TabCloseButton, nil)
|
view.SetChangeListener(TabCloseButton, nil)
|
||||||
|
|
||||||
current := tabsLayout.currentItem(0)
|
current := GetCurrent(tabsLayout)
|
||||||
if index < current || (index == current && current > 0) {
|
if index < current || (index == current && current > 0) {
|
||||||
current--
|
current--
|
||||||
}
|
}
|
||||||
|
@ -725,19 +641,20 @@ func (tabsLayout *tabsLayoutData) RemoveView(index int) View {
|
||||||
updateInnerHTML(tabsLayout.parentHTMLID(), tabsLayout.session)
|
updateInnerHTML(tabsLayout.parentHTMLID(), tabsLayout.session)
|
||||||
tabsLayout.propertyChangedEvent(Content)
|
tabsLayout.propertyChangedEvent(Content)
|
||||||
|
|
||||||
delete(tabsLayout.properties, Current)
|
delete(tabsLayout.view, Current)
|
||||||
tabsLayout.set(Current, current)
|
tabsLayout.Set(Current, current)
|
||||||
return view
|
return view
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) htmlProperties(self View, buffer *strings.Builder) {
|
func (tabsLayout *tabsLayoutData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
tabsLayout.viewsContainerData.htmlProperties(self, buffer)
|
tabsLayout.viewsContainerData.htmlProperties(self, buffer)
|
||||||
buffer.WriteString(` data-inactiveTabStyle="`)
|
buffer.WriteString(` data-inactiveTabStyle="`)
|
||||||
buffer.WriteString(tabsLayout.inactiveTabStyle())
|
buffer.WriteString(tabsLayoutInactiveTabStyle(tabsLayout))
|
||||||
buffer.WriteString(`" data-activeTabStyle="`)
|
buffer.WriteString(`" data-activeTabStyle="`)
|
||||||
buffer.WriteString(tabsLayout.activeTabStyle())
|
buffer.WriteString(tabsLayoutActiveTabStyle(tabsLayout))
|
||||||
buffer.WriteString(`" data-current="`)
|
buffer.WriteString(`" data-current="`)
|
||||||
buffer.WriteString(strconv.Itoa(tabsLayout.currentItem(0)))
|
buffer.WriteString(strconv.Itoa(GetCurrent(tabsLayout)))
|
||||||
buffer.WriteRune('"')
|
buffer.WriteRune('"')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,8 +680,7 @@ func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builde
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//viewCount := len(tabsLayout.views)
|
current := GetCurrent(tabsLayout)
|
||||||
current := tabsLayout.currentItem(0)
|
|
||||||
location := tabsLayout.tabsLocation()
|
location := tabsLayout.tabsLocation()
|
||||||
tabsLayoutID := tabsLayout.htmlID()
|
tabsLayoutID := tabsLayout.htmlID()
|
||||||
|
|
||||||
|
@ -796,8 +712,8 @@ func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builde
|
||||||
|
|
||||||
buffer.WriteString(`">`)
|
buffer.WriteString(`">`)
|
||||||
|
|
||||||
inactiveStyle := tabsLayout.inactiveTabStyle()
|
inactiveStyle := tabsLayoutInactiveTabStyle(tabsLayout)
|
||||||
activeStyle := tabsLayout.activeTabStyle()
|
activeStyle := tabsLayoutActiveTabStyle(tabsLayout)
|
||||||
|
|
||||||
notTranslate := GetNotTranslate(tabsLayout)
|
notTranslate := GetNotTranslate(tabsLayout)
|
||||||
closeButton, _ := boolProperty(tabsLayout, TabCloseButton, tabsLayout.session)
|
closeButton, _ := boolProperty(tabsLayout, TabCloseButton, tabsLayout.session)
|
||||||
|
@ -947,18 +863,18 @@ func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builde
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) handleCommand(self View, command string, data DataObject) bool {
|
func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "tabClick":
|
case "tabClick":
|
||||||
if numberText, ok := data.PropertyValue("number"); ok {
|
if numberText, ok := data.PropertyValue("number"); ok {
|
||||||
if number, err := strconv.Atoi(numberText); err == nil {
|
if number, err := strconv.Atoi(numberText); err == nil {
|
||||||
current := tabsLayout.currentItem(0)
|
current := GetCurrent(tabsLayout)
|
||||||
if current != number {
|
if current != number {
|
||||||
tabsLayout.properties[Current] = number
|
tabsLayout.setRaw(Current, number)
|
||||||
for _, listener := range tabsLayout.tabListener {
|
for _, listener := range getEventWithOldListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) {
|
||||||
listener(tabsLayout, number, current)
|
listener(tabsLayout, number, current)
|
||||||
}
|
}
|
||||||
tabsLayout.propertyChangedEvent(Current)
|
tabsLayout.currentChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -967,7 +883,7 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command string, data
|
||||||
case "tabCloseClick":
|
case "tabCloseClick":
|
||||||
if numberText, ok := data.PropertyValue("number"); ok {
|
if numberText, ok := data.PropertyValue("number"); ok {
|
||||||
if number, err := strconv.Atoi(numberText); err == nil {
|
if number, err := strconv.Atoi(numberText); err == nil {
|
||||||
for _, listener := range tabsLayout.tabCloseListener {
|
for _, listener := range getEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
|
||||||
listener(tabsLayout, number)
|
listener(tabsLayout, number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
99
textView.go
99
textView.go
|
@ -23,116 +23,79 @@ func NewTextView(session Session, params Params) TextView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTextView(session Session) View {
|
func newTextView(session Session) View {
|
||||||
return NewTextView(session, nil)
|
return new(textViewData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init initialize fields of TextView by default values
|
// Init initialize fields of TextView by default values
|
||||||
func (textView *textViewData) init(session Session) {
|
func (textView *textViewData) init(session Session) {
|
||||||
textView.viewData.init(session)
|
textView.viewData.init(session)
|
||||||
textView.tag = "TextView"
|
textView.tag = "TextView"
|
||||||
|
textView.set = textViewSet
|
||||||
|
textView.changed = textViewPropertyChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
func (textView *textViewData) String() string {
|
func textViewPropertyChanged(view View, tag PropertyName) {
|
||||||
return getViewString(textView, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (textView *textViewData) Get(tag string) any {
|
|
||||||
return textView.get(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (textView *textViewData) Remove(tag string) {
|
|
||||||
textView.remove(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (textView *textViewData) remove(tag string) {
|
|
||||||
textView.viewData.remove(tag)
|
|
||||||
if textView.created {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Text:
|
case Text:
|
||||||
updateInnerHTML(textView.htmlID(), textView.session)
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
|
|
||||||
case TextOverflow:
|
case TextOverflow:
|
||||||
textView.textOverflowUpdated()
|
session := view.Session()
|
||||||
|
if n, ok := enumProperty(view, TextOverflow, session, 0); ok {
|
||||||
|
values := enumProperties[TextOverflow].cssValues
|
||||||
|
if n >= 0 && n < len(values) {
|
||||||
|
session.updateCSSProperty(view.htmlID(), string(TextOverflow), values[n])
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
session.updateCSSProperty(view.htmlID(), string(TextOverflow), "")
|
||||||
|
|
||||||
|
case NotTranslate:
|
||||||
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
|
|
||||||
|
default:
|
||||||
|
viewPropertyChanged(view, tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (textView *textViewData) Set(tag string, value any) bool {
|
func textViewSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
return textView.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (textView *textViewData) set(tag string, value any) bool {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Text:
|
case Text:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
textView.properties[Text] = value
|
view.setRaw(Text, value)
|
||||||
|
|
||||||
case fmt.Stringer:
|
case fmt.Stringer:
|
||||||
textView.properties[Text] = value.String()
|
view.setRaw(Text, value.String())
|
||||||
|
|
||||||
case float32:
|
case float32:
|
||||||
textView.properties[Text] = fmt.Sprintf("%g", float64(value))
|
view.setRaw(Text, fmt.Sprintf("%g", float64(value)))
|
||||||
|
|
||||||
case float64:
|
case float64:
|
||||||
textView.properties[Text] = fmt.Sprintf("%g", value)
|
view.setRaw(Text, fmt.Sprintf("%g", value))
|
||||||
|
|
||||||
case []rune:
|
case []rune:
|
||||||
textView.properties[Text] = string(value)
|
view.setRaw(Text, string(value))
|
||||||
|
|
||||||
case bool:
|
case bool:
|
||||||
if value {
|
if value {
|
||||||
textView.properties[Text] = "true"
|
view.setRaw(Text, "true")
|
||||||
} else {
|
} else {
|
||||||
textView.properties[Text] = "false"
|
view.setRaw(Text, "false")
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if n, ok := isInt(value); ok {
|
if n, ok := isInt(value); ok {
|
||||||
textView.properties[Text] = fmt.Sprintf("%d", n)
|
view.setRaw(Text, fmt.Sprintf("%d", n))
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if textView.created {
|
return []PropertyName{Text}
|
||||||
updateInnerHTML(textView.htmlID(), textView.session)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case TextOverflow:
|
return viewSet(view, tag, value)
|
||||||
if !textView.viewData.set(tag, value) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if textView.created {
|
|
||||||
textView.textOverflowUpdated()
|
|
||||||
}
|
|
||||||
|
|
||||||
case NotTranslate:
|
|
||||||
if !textView.viewData.set(tag, value) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if textView.created {
|
|
||||||
updateInnerHTML(textView.htmlID(), textView.Session())
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return textView.viewData.set(tag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
textView.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (textView *textViewData) textOverflowUpdated() {
|
|
||||||
session := textView.Session()
|
|
||||||
if n, ok := enumProperty(textView, TextOverflow, session, 0); ok {
|
|
||||||
values := enumProperties[TextOverflow].cssValues
|
|
||||||
if n >= 0 && n < len(values) {
|
|
||||||
session.updateCSSProperty(textView.htmlID(), TextOverflow, values[n])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
session.updateCSSProperty(textView.htmlID(), TextOverflow, "")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
|
|
6
theme.go
6
theme.go
|
@ -699,13 +699,13 @@ func (theme *theme) addText(themeText string) bool {
|
||||||
if node := obj.Property(i); node != nil {
|
if node := obj.Property(i); node != nil {
|
||||||
switch node.Type() {
|
switch node.Type() {
|
||||||
case ArrayNode:
|
case ArrayNode:
|
||||||
params[node.Tag()] = node.ArrayElements()
|
params[PropertyName(node.Tag())] = node.ArrayElements()
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectNode:
|
||||||
params[node.Tag()] = node.Object()
|
params[PropertyName(node.Tag())] = node.Object()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
params[node.Tag()] = node.Text()
|
params[PropertyName(node.Tag())] = node.Text()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
292
timePicker.go
292
timePicker.go
|
@ -27,7 +27,7 @@ const (
|
||||||
// `func(newTime time.Time)`,
|
// `func(newTime time.Time)`,
|
||||||
// `func(picker rui.TimePicker)`,
|
// `func(picker rui.TimePicker)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TimeChangedEvent = "time-changed"
|
TimeChangedEvent PropertyName = "time-changed"
|
||||||
|
|
||||||
// TimePickerMin is the constant for "time-picker-min" property tag.
|
// TimePickerMin is the constant for "time-picker-min" property tag.
|
||||||
//
|
//
|
||||||
|
@ -44,7 +44,7 @@ const (
|
||||||
// "HH:MM:SS PM" - "08:15:00 AM".
|
// "HH:MM:SS PM" - "08:15:00 AM".
|
||||||
// "HH:MM" - "08:15".
|
// "HH:MM" - "08:15".
|
||||||
// "HH:MM PM" - "08:15 AM".
|
// "HH:MM PM" - "08:15 AM".
|
||||||
TimePickerMin = "time-picker-min"
|
TimePickerMin PropertyName = "time-picker-min"
|
||||||
|
|
||||||
// TimePickerMax is the constant for "time-picker-max" property tag.
|
// TimePickerMax is the constant for "time-picker-max" property tag.
|
||||||
//
|
//
|
||||||
|
@ -61,7 +61,7 @@ const (
|
||||||
// "HH:MM:SS PM" - "08:15:00 AM".
|
// "HH:MM:SS PM" - "08:15:00 AM".
|
||||||
// "HH:MM" - "08:15".
|
// "HH:MM" - "08:15".
|
||||||
// "HH:MM PM" - "08:15 AM".
|
// "HH:MM PM" - "08:15 AM".
|
||||||
TimePickerMax = "time-picker-max"
|
TimePickerMax PropertyName = "time-picker-max"
|
||||||
|
|
||||||
// TimePickerStep is the constant for "time-picker-step" property tag.
|
// TimePickerStep is the constant for "time-picker-step" property tag.
|
||||||
//
|
//
|
||||||
|
@ -72,7 +72,7 @@ const (
|
||||||
//
|
//
|
||||||
// Values:
|
// Values:
|
||||||
// >= `0` or >= "0" - Step value in seconds used to increment or decrement time.
|
// >= `0` or >= "0" - Step value in seconds used to increment or decrement time.
|
||||||
TimePickerStep = "time-picker-step"
|
TimePickerStep PropertyName = "time-picker-step"
|
||||||
|
|
||||||
// TimePickerValue is the constant for "time-picker-value" property tag.
|
// TimePickerValue is the constant for "time-picker-value" property tag.
|
||||||
//
|
//
|
||||||
|
@ -89,7 +89,7 @@ const (
|
||||||
// "HH:MM:SS PM" - "08:15:00 AM".
|
// "HH:MM:SS PM" - "08:15:00 AM".
|
||||||
// "HH:MM" - "08:15".
|
// "HH:MM" - "08:15".
|
||||||
// "HH:MM PM" - "08:15 AM".
|
// "HH:MM PM" - "08:15 AM".
|
||||||
TimePickerValue = "time-picker-value"
|
TimePickerValue PropertyName = "time-picker-value"
|
||||||
|
|
||||||
timeFormat = "15:04:05"
|
timeFormat = "15:04:05"
|
||||||
)
|
)
|
||||||
|
@ -101,8 +101,6 @@ type TimePicker interface {
|
||||||
|
|
||||||
type timePickerData struct {
|
type timePickerData struct {
|
||||||
viewData
|
viewData
|
||||||
dataList
|
|
||||||
timeChangedListeners []func(TimePicker, time.Time, time.Time)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTimePicker create new TimePicker object and return it
|
// NewTimePicker create new TimePicker object and return it
|
||||||
|
@ -114,116 +112,38 @@ func NewTimePicker(session Session, params Params) TimePicker {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTimePicker(session Session) View {
|
func newTimePicker(session Session) View {
|
||||||
return NewTimePicker(session, nil)
|
return new(timePickerData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *timePickerData) init(session Session) {
|
func (picker *timePickerData) init(session Session) {
|
||||||
picker.viewData.init(session)
|
picker.viewData.init(session)
|
||||||
picker.tag = "TimePicker"
|
picker.tag = "TimePicker"
|
||||||
picker.hasHtmlDisabled = true
|
picker.hasHtmlDisabled = true
|
||||||
picker.timeChangedListeners = []func(TimePicker, time.Time, time.Time){}
|
picker.normalize = normalizeTimePickerTag
|
||||||
picker.dataListInit()
|
picker.set = timePickerSet
|
||||||
}
|
picker.changed = timePickerPropertyChanged
|
||||||
|
|
||||||
func (picker *timePickerData) String() string {
|
|
||||||
return getViewString(picker, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *timePickerData) Focusable() bool {
|
func (picker *timePickerData) Focusable() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *timePickerData) normalizeTag(tag string) string {
|
func normalizeTimePickerTag(tag PropertyName) PropertyName {
|
||||||
tag = strings.ToLower(tag)
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case Type, Min, Max, Step, Value:
|
case Type, Min, Max, Step, Value:
|
||||||
return "time-picker-" + tag
|
return "time-picker-" + tag
|
||||||
}
|
}
|
||||||
|
|
||||||
return tag
|
return normalizeDataListTag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *timePickerData) Remove(tag string) {
|
func stringToTime(value string) (time.Time, bool) {
|
||||||
picker.remove(picker.normalizeTag(tag))
|
lowText := strings.ToUpper(value)
|
||||||
}
|
pm := strings.HasSuffix(lowText, "PM") || strings.HasSuffix(lowText, "AM")
|
||||||
|
|
||||||
func (picker *timePickerData) remove(tag string) {
|
|
||||||
switch tag {
|
|
||||||
case TimeChangedEvent:
|
|
||||||
if len(picker.timeChangedListeners) > 0 {
|
|
||||||
picker.timeChangedListeners = []func(TimePicker, time.Time, time.Time){}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
case TimePickerMin:
|
|
||||||
delete(picker.properties, TimePickerMin)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.removeProperty(picker.htmlID(), Min)
|
|
||||||
}
|
|
||||||
|
|
||||||
case TimePickerMax:
|
|
||||||
delete(picker.properties, TimePickerMax)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.removeProperty(picker.htmlID(), Max)
|
|
||||||
}
|
|
||||||
|
|
||||||
case TimePickerStep:
|
|
||||||
delete(picker.properties, TimePickerStep)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.removeProperty(picker.htmlID(), Step)
|
|
||||||
}
|
|
||||||
|
|
||||||
case TimePickerValue:
|
|
||||||
if _, ok := picker.properties[TimePickerValue]; ok {
|
|
||||||
oldTime := GetTimePickerValue(picker)
|
|
||||||
delete(picker.properties, TimePickerValue)
|
|
||||||
time := GetTimePickerValue(picker)
|
|
||||||
if picker.created {
|
|
||||||
picker.session.callFunc("setInputValue", picker.htmlID(), time.Format(timeFormat))
|
|
||||||
}
|
|
||||||
for _, listener := range picker.timeChangedListeners {
|
|
||||||
listener(picker, time, oldTime)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
if len(picker.dataList.dataList) > 0 {
|
|
||||||
picker.setDataList(picker, []string{}, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
picker.viewData.remove(tag)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *timePickerData) Set(tag string, value any) bool {
|
|
||||||
return picker.set(picker.normalizeTag(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *timePickerData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
picker.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeValue := func(tag string) (time.Time, bool) {
|
|
||||||
switch value := value.(type) {
|
|
||||||
case time.Time:
|
|
||||||
picker.properties[tag] = value
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case string:
|
|
||||||
if text, ok := picker.Session().resolveConstants(value); ok {
|
|
||||||
lowText := strings.ToLower(text)
|
|
||||||
pm := strings.HasSuffix(lowText, "pm") || strings.HasSuffix(lowText, "am")
|
|
||||||
|
|
||||||
var format string
|
var format string
|
||||||
switch len(strings.Split(text, ":")) {
|
switch len(strings.Split(value, ":")) {
|
||||||
case 2:
|
case 2:
|
||||||
if pm {
|
if pm {
|
||||||
format = "3:04 PM"
|
format = "3:04 PM"
|
||||||
|
@ -239,111 +159,107 @@ func (picker *timePickerData) set(tag string, value any) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if time, err := time.Parse(format, text); err == nil {
|
result, err := time.Parse(format, value)
|
||||||
picker.properties[tag] = value
|
if err != nil {
|
||||||
return time, true
|
|
||||||
} else {
|
|
||||||
ErrorLog(err.Error())
|
ErrorLog(err.Error())
|
||||||
}
|
|
||||||
return time.Now(), false
|
return time.Now(), false
|
||||||
}
|
}
|
||||||
|
return result, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func timePickerSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
|
|
||||||
|
setTimeValue := func(tag PropertyName) []PropertyName {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case time.Time:
|
||||||
|
view.setRaw(tag, value)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
|
||||||
|
case string:
|
||||||
|
if isConstantName(value) {
|
||||||
|
view.setRaw(tag, value)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
if time, ok := stringToTime(value); ok {
|
||||||
|
view.setRaw(tag, time)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return time.Now(), false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case TimePickerMin:
|
case TimePickerMin:
|
||||||
old, oldOK := getTimeProperty(picker, TimePickerMin, Min)
|
return setTimeValue(TimePickerMin)
|
||||||
if time, ok := setTimeValue(TimePickerMin); ok {
|
|
||||||
if !oldOK || time != old {
|
case TimePickerMax:
|
||||||
if picker.created {
|
return setTimeValue(TimePickerMax)
|
||||||
picker.session.updateProperty(picker.htmlID(), Min, time.Format(timeFormat))
|
|
||||||
|
case TimePickerStep:
|
||||||
|
return setIntProperty(view, TimePickerStep, value)
|
||||||
|
|
||||||
|
case TimePickerValue:
|
||||||
|
view.setRaw("old-time", GetTimePickerValue(view))
|
||||||
|
return setTimeValue(tag)
|
||||||
|
|
||||||
|
case TimeChangedEvent:
|
||||||
|
return setEventWithOldListener[TimePicker, time.Time](view, tag, value)
|
||||||
|
|
||||||
|
case DataList:
|
||||||
|
return setDataList(view, value, timeFormat)
|
||||||
}
|
}
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
|
return viewSet(view, tag, value)
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
|
func timePickerPropertyChanged(view View, tag PropertyName) {
|
||||||
|
|
||||||
|
session := view.Session()
|
||||||
|
|
||||||
|
switch tag {
|
||||||
|
|
||||||
|
case TimePickerMin:
|
||||||
|
if time, ok := GetTimePickerMin(view); ok {
|
||||||
|
session.updateProperty(view.htmlID(), "min", time.Format(timeFormat))
|
||||||
|
} else {
|
||||||
|
session.removeProperty(view.htmlID(), "min")
|
||||||
}
|
}
|
||||||
|
|
||||||
case TimePickerMax:
|
case TimePickerMax:
|
||||||
old, oldOK := getTimeProperty(picker, TimePickerMax, Max)
|
if time, ok := GetTimePickerMax(view); ok {
|
||||||
if time, ok := setTimeValue(TimePickerMax); ok {
|
session.updateProperty(view.htmlID(), "max", time.Format(timeFormat))
|
||||||
if !oldOK || time != old {
|
} else {
|
||||||
if picker.created {
|
session.removeProperty(view.htmlID(), "max")
|
||||||
picker.session.updateProperty(picker.htmlID(), Max, time.Format(timeFormat))
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case TimePickerStep:
|
case TimePickerStep:
|
||||||
oldStep := GetTimePickerStep(picker)
|
if step := GetTimePickerStep(view); step > 0 {
|
||||||
if picker.setIntProperty(TimePickerStep, value) {
|
session.updateProperty(view.htmlID(), "step", strconv.Itoa(step))
|
||||||
if step := GetTimePickerStep(picker); oldStep != step {
|
|
||||||
if picker.created {
|
|
||||||
if step > 0 {
|
|
||||||
picker.session.updateProperty(picker.htmlID(), Step, strconv.Itoa(step))
|
|
||||||
} else {
|
} else {
|
||||||
picker.session.removeProperty(picker.htmlID(), Step)
|
session.removeProperty(view.htmlID(), "step")
|
||||||
}
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case TimePickerValue:
|
case TimePickerValue:
|
||||||
oldTime := GetTimePickerValue(picker)
|
value := GetTimePickerValue(view)
|
||||||
if time, ok := setTimeValue(TimePickerValue); ok {
|
session.callFunc("setInputValue", view.htmlID(), value.Format(timeFormat))
|
||||||
if time != oldTime {
|
|
||||||
if picker.created {
|
|
||||||
picker.session.callFunc("setInputValue", picker.htmlID(), time.Format(timeFormat))
|
|
||||||
}
|
|
||||||
for _, listener := range picker.timeChangedListeners {
|
|
||||||
listener(picker, time, oldTime)
|
|
||||||
}
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
case TimeChangedEvent:
|
if listeners := GetTimeChangedListeners(view); len(listeners) > 0 {
|
||||||
listeners, ok := valueToEventWithOldListeners[TimePicker, time.Time](value)
|
oldTime := time.Now()
|
||||||
if !ok {
|
if val := view.getRaw("old-time"); val != nil {
|
||||||
notCompatibleType(tag, value)
|
if time, ok := val.(time.Time); ok {
|
||||||
return false
|
oldTime = time
|
||||||
} else if listeners == nil {
|
}
|
||||||
listeners = []func(TimePicker, time.Time, time.Time){}
|
}
|
||||||
|
for _, listener := range listeners {
|
||||||
|
listener(view, value, oldTime)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
picker.timeChangedListeners = listeners
|
|
||||||
picker.propertyChangedEvent(tag)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
return picker.setDataList(picker, value, picker.created)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return picker.viewData.set(tag, value)
|
viewPropertyChanged(view, tag)
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *timePickerData) Get(tag string) any {
|
|
||||||
return picker.get(picker.normalizeTag(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (picker *timePickerData) get(tag string) any {
|
|
||||||
switch tag {
|
|
||||||
case TimeChangedEvent:
|
|
||||||
return picker.timeChangedListeners
|
|
||||||
|
|
||||||
case DataList:
|
|
||||||
return picker.dataList.dataList
|
|
||||||
|
|
||||||
default:
|
|
||||||
return picker.viewData.get(tag)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +268,13 @@ func (picker *timePickerData) htmlTag() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *timePickerData) htmlSubviews(self View, buffer *strings.Builder) {
|
func (picker *timePickerData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
picker.dataListHtmlSubviews(self, buffer)
|
dataListHtmlSubviews(self, buffer, func(text string, session Session) string {
|
||||||
|
text, _ = session.resolveConstants(text)
|
||||||
|
if time, ok := stringToTime(text); ok {
|
||||||
|
return time.Format(timeFormat)
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder) {
|
func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
|
@ -387,10 +309,10 @@ func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder)
|
||||||
buffer.WriteString(` onclick="stopEventPropagation(this, event)"`)
|
buffer.WriteString(` onclick="stopEventPropagation(this, event)"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
picker.dataListHtmlProperties(picker, buffer)
|
dataListHtmlProperties(picker, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *timePickerData) handleCommand(self View, command string, data DataObject) bool {
|
func (picker *timePickerData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
case "textChanged":
|
case "textChanged":
|
||||||
if text, ok := data.PropertyValue("text"); ok {
|
if text, ok := data.PropertyValue("text"); ok {
|
||||||
|
@ -398,9 +320,13 @@ func (picker *timePickerData) handleCommand(self View, command string, data Data
|
||||||
oldValue := GetTimePickerValue(picker)
|
oldValue := GetTimePickerValue(picker)
|
||||||
picker.properties[TimePickerValue] = value
|
picker.properties[TimePickerValue] = value
|
||||||
if value != oldValue {
|
if value != oldValue {
|
||||||
for _, listener := range picker.timeChangedListeners {
|
for _, listener := range GetTimeChangedListeners(picker) {
|
||||||
listener(picker, value, oldValue)
|
listener(picker, value, oldValue)
|
||||||
}
|
}
|
||||||
|
if listener, ok := picker.changeListener[TimePickerValue]; ok {
|
||||||
|
listener(picker, TimePickerValue)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -410,7 +336,7 @@ func (picker *timePickerData) handleCommand(self View, command string, data Data
|
||||||
return picker.viewData.handleCommand(self, command, data)
|
return picker.viewData.handleCommand(self, command, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTimeProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
func getTimeProperty(view View, mainTag, shortTag PropertyName) (time.Time, bool) {
|
||||||
valueToTime := func(value any) (time.Time, bool) {
|
valueToTime := func(value any) (time.Time, bool) {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
@ -419,7 +345,7 @@ func getTimeProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if text, ok := view.Session().resolveConstants(value); ok {
|
if text, ok := view.Session().resolveConstants(value); ok {
|
||||||
if result, err := time.Parse(timeFormat, text); err == nil {
|
if result, ok := stringToTime(text); ok {
|
||||||
return result, true
|
return result, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -433,12 +359,14 @@ func getTimeProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
||||||
return result, true
|
return result, true
|
||||||
}
|
}
|
||||||
|
|
||||||
if value := valueFromStyle(view, shortTag); value != nil {
|
for _, tag := range []PropertyName{mainTag, shortTag} {
|
||||||
|
if value := valueFromStyle(view, tag); value != nil {
|
||||||
if result, ok := valueToTime(value); ok {
|
if result, ok := valueToTime(value); ok {
|
||||||
return result, true
|
return result, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return time.Now(), false
|
return time.Now(), false
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package rui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Constants which represent [View] specific touch events properties
|
// Constants which represent [View] specific touch events properties
|
||||||
|
@ -23,7 +22,7 @@ const (
|
||||||
// `func(event rui.TouchEvent)`,
|
// `func(event rui.TouchEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TouchStart = "touch-start"
|
TouchStart PropertyName = "touch-start"
|
||||||
|
|
||||||
// TouchEnd is the constant for "touch-end" property tag.
|
// TouchEnd is the constant for "touch-end" property tag.
|
||||||
//
|
//
|
||||||
|
@ -41,7 +40,7 @@ const (
|
||||||
// `func(event rui.TouchEvent)`,
|
// `func(event rui.TouchEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TouchEnd = "touch-end"
|
TouchEnd PropertyName = "touch-end"
|
||||||
|
|
||||||
// TouchMove is the constant for "touch-move" property tag.
|
// TouchMove is the constant for "touch-move" property tag.
|
||||||
//
|
//
|
||||||
|
@ -59,7 +58,7 @@ const (
|
||||||
// `func(event rui.TouchEvent)`,
|
// `func(event rui.TouchEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TouchMove = "touch-move"
|
TouchMove PropertyName = "touch-move"
|
||||||
|
|
||||||
// TouchCancel is the constant for "touch-cancel" property tag.
|
// TouchCancel is the constant for "touch-cancel" property tag.
|
||||||
//
|
//
|
||||||
|
@ -78,7 +77,7 @@ const (
|
||||||
// `func(event rui.TouchEvent)`,
|
// `func(event rui.TouchEvent)`,
|
||||||
// `func(view rui.View)`,
|
// `func(view rui.View)`,
|
||||||
// `func()`.
|
// `func()`.
|
||||||
TouchCancel = "touch-cancel"
|
TouchCancel PropertyName = "touch-cancel"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Touch contains parameters of a single touch of a touch event
|
// Touch contains parameters of a single touch of a touch event
|
||||||
|
@ -143,45 +142,33 @@ type TouchEvent struct {
|
||||||
MetaKey bool
|
MetaKey bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var touchEvents = map[string]struct{ jsEvent, jsFunc string }{
|
/*
|
||||||
TouchStart: {jsEvent: "ontouchstart", jsFunc: "touchStartEvent"},
|
func setTouchListener(properties Properties, tag PropertyName, value any) bool {
|
||||||
TouchEnd: {jsEvent: "ontouchend", jsFunc: "touchEndEvent"},
|
if listeners, ok := valueToEventListeners[View, TouchEvent](value); ok {
|
||||||
TouchMove: {jsEvent: "ontouchmove", jsFunc: "touchMoveEvent"},
|
if len(listeners) == 0 {
|
||||||
TouchCancel: {jsEvent: "ontouchcancel", jsFunc: "touchCancelEvent"},
|
properties.setRaw(tag, nil)
|
||||||
|
} else {
|
||||||
|
properties.setRaw(tag, listeners)
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) setTouchListener(tag string, value any) bool {
|
|
||||||
listeners, ok := valueToEventListeners[View, TouchEvent](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if listeners == nil {
|
func (view *viewData) removeTouchListener(tag PropertyName) {
|
||||||
view.removeTouchListener(tag)
|
|
||||||
} else if js, ok := touchEvents[tag]; ok {
|
|
||||||
view.properties[tag] = listeners
|
|
||||||
if view.created {
|
|
||||||
view.session.updateProperty(view.htmlID(), js.jsEvent, js.jsFunc+"(this, event)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) removeTouchListener(tag string) {
|
|
||||||
delete(view.properties, tag)
|
delete(view.properties, tag)
|
||||||
if view.created {
|
if view.created {
|
||||||
if js, ok := touchEvents[tag]; ok {
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func touchEventsHtml(view View, buffer *strings.Builder) {
|
func touchEventsHtml(view View, buffer *strings.Builder) {
|
||||||
for tag, js := range touchEvents {
|
for _, tag := range []PropertyName{TouchStart, TouchEnd, TouchMove, TouchCancel} {
|
||||||
if value := view.getRaw(tag); value != nil {
|
if value := view.getRaw(tag); value != nil {
|
||||||
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
if listeners, ok := value.([]func(View, TouchEvent)); ok && len(listeners) > 0 {
|
if listeners, ok := value.([]func(View, TouchEvent)); ok && len(listeners) > 0 {
|
||||||
buffer.WriteString(js.jsEvent)
|
buffer.WriteString(js.jsEvent)
|
||||||
buffer.WriteString(`="`)
|
buffer.WriteString(`="`)
|
||||||
|
@ -191,6 +178,8 @@ func touchEventsHtml(view View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (event *TouchEvent) init(data DataObject) {
|
func (event *TouchEvent) init(data DataObject) {
|
||||||
|
|
||||||
|
@ -225,7 +214,7 @@ func (event *TouchEvent) init(data DataObject) {
|
||||||
event.MetaKey = dataBoolProperty(data, "metaKey")
|
event.MetaKey = dataBoolProperty(data, "metaKey")
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleTouchEvents(view View, tag string, data DataObject) {
|
func handleTouchEvents(view View, tag PropertyName, data DataObject) {
|
||||||
listeners := getEventListeners[View, TouchEvent](view, nil, tag)
|
listeners := getEventListeners[View, TouchEvent](view, nil, tag)
|
||||||
if len(listeners) == 0 {
|
if len(listeners) == 0 {
|
||||||
return
|
return
|
||||||
|
|
|
@ -15,7 +15,7 @@ const (
|
||||||
//
|
//
|
||||||
// Values:
|
// Values:
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
VideoWidth = "video-width"
|
VideoWidth PropertyName = "video-width"
|
||||||
|
|
||||||
// VideoHeight is the constant for "video-height" property tag.
|
// VideoHeight is the constant for "video-height" property tag.
|
||||||
//
|
//
|
||||||
|
@ -25,7 +25,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
VideoHeight = "video-height"
|
VideoHeight PropertyName = "video-height"
|
||||||
|
|
||||||
// Poster is the constant for "poster" property tag.
|
// Poster is the constant for "poster" property tag.
|
||||||
//
|
//
|
||||||
|
@ -34,7 +34,7 @@ const (
|
||||||
// displayed until the first frame is available, then the first frame is shown as the poster frame.
|
// displayed until the first frame is available, then the first frame is shown as the poster frame.
|
||||||
//
|
//
|
||||||
// Supported types: `string`.
|
// Supported types: `string`.
|
||||||
Poster = "poster"
|
Poster PropertyName = "poster"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VideoPlayer is a type of a [View] which can play video files
|
// VideoPlayer is a type of a [View] which can play video files
|
||||||
|
@ -50,70 +50,33 @@ type videoPlayerData struct {
|
||||||
func NewVideoPlayer(session Session, params Params) VideoPlayer {
|
func NewVideoPlayer(session Session, params Params) VideoPlayer {
|
||||||
view := new(videoPlayerData)
|
view := new(videoPlayerData)
|
||||||
view.init(session)
|
view.init(session)
|
||||||
view.tag = "VideoPlayer"
|
|
||||||
setInitParams(view, params)
|
setInitParams(view, params)
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
func newVideoPlayer(session Session) View {
|
func newVideoPlayer(session Session) View {
|
||||||
return NewVideoPlayer(session, nil)
|
return new(videoPlayerData) // NewVideoPlayer(session, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *videoPlayerData) init(session Session) {
|
func (player *videoPlayerData) init(session Session) {
|
||||||
player.mediaPlayerData.init(session)
|
player.mediaPlayerData.init(session)
|
||||||
player.tag = "VideoPlayer"
|
player.tag = "VideoPlayer"
|
||||||
}
|
player.changed = videoPlayerPropertyChanged
|
||||||
|
|
||||||
func (player *videoPlayerData) String() string {
|
|
||||||
return getViewString(player, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *videoPlayerData) htmlTag() string {
|
func (player *videoPlayerData) htmlTag() string {
|
||||||
return "video"
|
return "video"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *videoPlayerData) Remove(tag string) {
|
func videoPlayerPropertyChanged(view View, tag PropertyName) {
|
||||||
player.remove(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *videoPlayerData) remove(tag string) {
|
session := view.Session()
|
||||||
switch tag {
|
|
||||||
|
|
||||||
case VideoWidth:
|
|
||||||
delete(player.properties, tag)
|
|
||||||
player.session.removeProperty(player.htmlID(), "width")
|
|
||||||
|
|
||||||
case VideoHeight:
|
|
||||||
delete(player.properties, tag)
|
|
||||||
player.session.removeProperty(player.htmlID(), "height")
|
|
||||||
|
|
||||||
case Poster:
|
|
||||||
delete(player.properties, tag)
|
|
||||||
player.session.removeProperty(player.htmlID(), Poster)
|
|
||||||
|
|
||||||
default:
|
|
||||||
player.mediaPlayerData.remove(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *videoPlayerData) Set(tag string, value any) bool {
|
|
||||||
return player.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *videoPlayerData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
player.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if player.mediaPlayerData.set(tag, value) {
|
|
||||||
session := player.Session()
|
|
||||||
updateSize := func(cssTag string) {
|
updateSize := func(cssTag string) {
|
||||||
if size, ok := floatTextProperty(player, tag, session, 0); ok {
|
if size, ok := floatTextProperty(view, tag, session, 0); ok {
|
||||||
if size != "0" {
|
if size != "0" {
|
||||||
session.updateProperty(player.htmlID(), cssTag, size)
|
session.updateProperty(view.htmlID(), cssTag, size)
|
||||||
} else {
|
} else {
|
||||||
session.removeProperty(player.htmlID(), cssTag)
|
session.removeProperty(view.htmlID(), cssTag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,14 +89,15 @@ func (player *videoPlayerData) set(tag string, value any) bool {
|
||||||
updateSize("height")
|
updateSize("height")
|
||||||
|
|
||||||
case Poster:
|
case Poster:
|
||||||
if url, ok := stringProperty(player, Poster, session); ok {
|
if url, ok := stringProperty(view, Poster, session); ok {
|
||||||
session.updateProperty(player.htmlID(), Poster, url)
|
session.updateProperty(view.htmlID(), string(Poster), url)
|
||||||
}
|
} else {
|
||||||
}
|
session.removeProperty(view.htmlID(), string(Poster))
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
default:
|
||||||
|
mediaPlayerPropertyChanged(view, tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (player *videoPlayerData) htmlProperties(self View, buffer *strings.Builder) {
|
func (player *videoPlayerData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
|
|
544
view.go
544
view.go
|
@ -62,15 +62,16 @@ type View interface {
|
||||||
// SetAnimated sets the value (second argument) of the property with name defined by the first argument.
|
// SetAnimated sets the value (second argument) of the property with name defined by the first argument.
|
||||||
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
// Return "true" if the value has been set, in the opposite case "false" are returned and
|
||||||
// a description of the error is written to the log
|
// a description of the error is written to the log
|
||||||
SetAnimated(tag string, value any, animation Animation) bool
|
SetAnimated(tag PropertyName, value any, animation Animation) bool
|
||||||
|
|
||||||
// SetChangeListener set the function to track the change of the View property
|
// SetChangeListener set the function to track the change of the View property
|
||||||
SetChangeListener(tag string, listener func(View, string))
|
SetChangeListener(tag PropertyName, listener func(View, PropertyName))
|
||||||
|
|
||||||
// HasFocus returns 'true' if the view has focus
|
// HasFocus returns 'true' if the view has focus
|
||||||
HasFocus() bool
|
HasFocus() bool
|
||||||
|
|
||||||
handleCommand(self View, command string, data DataObject) bool
|
init(session Session)
|
||||||
|
handleCommand(self View, command PropertyName, data DataObject) bool
|
||||||
htmlClass(disabled bool) string
|
htmlClass(disabled bool) string
|
||||||
htmlTag() string
|
htmlTag() string
|
||||||
closeHTMLTag() bool
|
closeHTMLTag() bool
|
||||||
|
@ -81,7 +82,8 @@ type View interface {
|
||||||
htmlProperties(self View, buffer *strings.Builder)
|
htmlProperties(self View, buffer *strings.Builder)
|
||||||
cssStyle(self View, builder cssBuilder)
|
cssStyle(self View, builder cssBuilder)
|
||||||
addToCSSStyle(addCSS map[string]string)
|
addToCSSStyle(addCSS map[string]string)
|
||||||
exscludeTags() []string
|
exscludeTags() []PropertyName
|
||||||
|
htmlDisabledProperty() bool
|
||||||
|
|
||||||
onResize(self View, x, y, width, height float64)
|
onResize(self View, x, y, width, height float64)
|
||||||
onItemResize(self View, index string, x, y, width, height float64)
|
onItemResize(self View, index string, x, y, width, height float64)
|
||||||
|
@ -99,8 +101,8 @@ type viewData struct {
|
||||||
_htmlID string
|
_htmlID string
|
||||||
parentID string
|
parentID string
|
||||||
systemClass string
|
systemClass string
|
||||||
changeListener map[string]func(View, string)
|
changeListener map[PropertyName]func(View, PropertyName)
|
||||||
singleTransition map[string]Animation
|
singleTransition map[PropertyName]Animation
|
||||||
addCSS map[string]string
|
addCSS map[string]string
|
||||||
frame Frame
|
frame Frame
|
||||||
scroll Frame
|
scroll Frame
|
||||||
|
@ -108,12 +110,21 @@ type viewData struct {
|
||||||
created bool
|
created bool
|
||||||
hasFocus bool
|
hasFocus bool
|
||||||
hasHtmlDisabled bool
|
hasHtmlDisabled bool
|
||||||
//animation map[string]AnimationEndListener
|
getFunc func(view View, tag PropertyName) any
|
||||||
|
set func(view View, tag PropertyName, value any) []PropertyName
|
||||||
|
remove func(view View, tag PropertyName) []PropertyName
|
||||||
|
changed func(view View, tag PropertyName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newView(session Session) View {
|
func newView(session Session) View {
|
||||||
|
return new(viewData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewView create new View object and return it
|
||||||
|
func NewView(session Session, params Params) View {
|
||||||
view := new(viewData)
|
view := new(viewData)
|
||||||
view.init(session)
|
view.init(session)
|
||||||
|
setInitParams(view, params)
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,22 +143,18 @@ func setInitParams(view View, params Params) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewView create new View object and return it
|
|
||||||
func NewView(session Session, params Params) View {
|
|
||||||
view := new(viewData)
|
|
||||||
view.init(session)
|
|
||||||
setInitParams(view, params)
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) init(session Session) {
|
func (view *viewData) init(session Session) {
|
||||||
view.viewStyle.init()
|
view.viewStyle.init()
|
||||||
|
view.getFunc = viewGet
|
||||||
|
view.set = viewSet
|
||||||
|
view.normalize = normalizeViewTag
|
||||||
|
view.changed = viewPropertyChanged
|
||||||
view.tag = "View"
|
view.tag = "View"
|
||||||
view.session = session
|
view.session = session
|
||||||
view.changeListener = map[string]func(View, string){}
|
view.changeListener = map[PropertyName]func(View, PropertyName){}
|
||||||
view.addCSS = map[string]string{}
|
view.addCSS = map[string]string{}
|
||||||
//view.animation = map[string]AnimationEndListener{}
|
//view.animation = map[string]AnimationEndListener{}
|
||||||
view.singleTransition = map[string]Animation{}
|
view.singleTransition = map[PropertyName]Animation{}
|
||||||
view.noResizeEvent = false
|
view.noResizeEvent = false
|
||||||
view.created = false
|
view.created = false
|
||||||
view.hasHtmlDisabled = false
|
view.hasHtmlDisabled = false
|
||||||
|
@ -205,71 +212,112 @@ func (view *viewData) Focusable() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) Remove(tag string) {
|
func (view *viewData) Remove(tag PropertyName) {
|
||||||
view.remove(strings.ToLower(tag))
|
tag = view.normalize(tag)
|
||||||
}
|
var changedTags []PropertyName = nil
|
||||||
|
|
||||||
func (view *viewData) remove(tag string) {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case ID:
|
case ID:
|
||||||
|
if view.viewID != "" {
|
||||||
view.viewID = ""
|
view.viewID = ""
|
||||||
|
changedTags = []PropertyName{ID}
|
||||||
case TabIndex, "tab-index":
|
|
||||||
delete(view.properties, tag)
|
|
||||||
if view.Focusable() {
|
|
||||||
view.session.updateProperty(view.htmlID(), "tabindex", "0")
|
|
||||||
} else {
|
|
||||||
view.session.updateProperty(view.htmlID(), "tabindex", "-1")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case UserData:
|
case AnimationTag:
|
||||||
delete(view.properties, tag)
|
if val := view.getRaw(AnimationTag); val != nil {
|
||||||
|
if animations, ok := val.([]Animation); ok {
|
||||||
case Style, StyleDisabled:
|
for _, animation := range animations {
|
||||||
if _, ok := view.properties[tag]; ok {
|
animation.unused(view.session)
|
||||||
delete(view.properties, tag)
|
}
|
||||||
view.session.updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case FocusEvent, LostFocusEvent:
|
view.setRaw(AnimationTag, nil)
|
||||||
view.removeFocusListener(tag)
|
changedTags = []PropertyName{AnimationTag}
|
||||||
|
|
||||||
case KeyDownEvent, KeyUpEvent:
|
|
||||||
view.removeKeyListener(tag)
|
|
||||||
|
|
||||||
case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent:
|
|
||||||
view.removeMouseListener(tag)
|
|
||||||
|
|
||||||
case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel:
|
|
||||||
view.removePointerListener(tag)
|
|
||||||
|
|
||||||
case TouchStart, TouchEnd, TouchMove, TouchCancel:
|
|
||||||
view.removeTouchListener(tag)
|
|
||||||
|
|
||||||
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
|
|
||||||
view.removeTransitionListener(tag)
|
|
||||||
|
|
||||||
case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
|
|
||||||
view.removeAnimationListener(tag)
|
|
||||||
|
|
||||||
case ResizeEvent, ScrollEvent:
|
|
||||||
delete(view.properties, tag)
|
|
||||||
|
|
||||||
case Content:
|
|
||||||
if _, ok := view.properties[Content]; ok {
|
|
||||||
delete(view.properties, Content)
|
|
||||||
updateInnerHTML(view.htmlID(), view.session)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
view.viewStyle.remove(tag)
|
changedTags = view.remove(view, tag)
|
||||||
viewPropertyChanged(view, tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
view.propertyChangedEvent(tag)
|
if view.created && len(changedTags) > 0 {
|
||||||
|
for _, tag := range changedTags {
|
||||||
|
view.changed(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) propertyChangedEvent(tag string) {
|
for _, tag := range changedTags {
|
||||||
|
if listener, ok := view.changeListener[tag]; ok {
|
||||||
|
listener(view, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (view *viewData) Set(tag PropertyName, value any) bool {
|
||||||
|
if value == nil {
|
||||||
|
view.Remove(tag)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = view.normalize(tag)
|
||||||
|
var changedTags []PropertyName = nil
|
||||||
|
|
||||||
|
switch tag {
|
||||||
|
case ID:
|
||||||
|
text, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
notCompatibleType(ID, value)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
view.viewID = text
|
||||||
|
changedTags = []PropertyName{ID}
|
||||||
|
|
||||||
|
case AnimationTag:
|
||||||
|
oldAnimations := []Animation{}
|
||||||
|
if val := view.getRaw(AnimationTag); val != nil {
|
||||||
|
if animation, ok := val.([]Animation); ok {
|
||||||
|
oldAnimations = animation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !setAnimationProperty(view, tag, value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, animation := range oldAnimations {
|
||||||
|
animation.unused(view.session)
|
||||||
|
}
|
||||||
|
changedTags = []PropertyName{AnimationTag}
|
||||||
|
|
||||||
|
default:
|
||||||
|
changedTags = viewSet(view, tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if view.created && len(changedTags) > 0 {
|
||||||
|
for _, tag := range changedTags {
|
||||||
|
view.changed(view, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tag := range changedTags {
|
||||||
|
if listener, ok := view.changeListener[tag]; ok {
|
||||||
|
listener(view, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changedTags != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeViewTag(tag PropertyName) PropertyName {
|
||||||
|
tag = normalizeViewStyleTag(tag)
|
||||||
|
switch tag {
|
||||||
|
case "tab-index":
|
||||||
|
return TabIndex
|
||||||
|
}
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (view *viewData) propertyChangedEvent(tag PropertyName) {
|
||||||
if listener, ok := view.changeListener[tag]; ok {
|
if listener, ok := view.changeListener[tag]; ok {
|
||||||
listener(view, tag)
|
listener(view, tag)
|
||||||
}
|
}
|
||||||
|
@ -319,113 +367,58 @@ func (view *viewData) propertyChangedEvent(tag string) {
|
||||||
listener(view, tag)
|
listener(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (view *viewData) Set(tag string, value any) bool {
|
func viewRemove(properties Properties, tag PropertyName) []PropertyName {
|
||||||
return view.set(strings.ToLower(tag), value)
|
return viewStyleRemove(properties, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) set(tag string, value any) bool {
|
func viewSet(view View, tag PropertyName, value any) []PropertyName {
|
||||||
if value == nil {
|
|
||||||
view.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
result := func(res bool) bool {
|
|
||||||
if res {
|
|
||||||
view.propertyChangedEvent(tag)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case ID:
|
|
||||||
text, ok := value.(string)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(ID, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
view.viewID = text
|
|
||||||
|
|
||||||
case AnimationTag:
|
|
||||||
oldAnimations := []Animation{}
|
|
||||||
if val, ok := view.properties[AnimationTag]; ok && val != nil {
|
|
||||||
if animation, ok := val.([]Animation); ok {
|
|
||||||
oldAnimations = animation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !view.setAnimation(tag, value) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, animation := range oldAnimations {
|
|
||||||
animation.unused(view.session)
|
|
||||||
}
|
|
||||||
if view.created {
|
|
||||||
viewPropertyChanged(view, tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
case TabIndex, "tab-index":
|
case TabIndex, "tab-index":
|
||||||
if !view.setIntProperty(tag, value) {
|
return setIntProperty(view, TabIndex, value)
|
||||||
return false
|
|
||||||
}
|
|
||||||
if value, ok := intProperty(view, TabIndex, view.Session(), 0); ok {
|
|
||||||
view.session.updateProperty(view.htmlID(), "tabindex", strconv.Itoa(value))
|
|
||||||
} else if view.Focusable() {
|
|
||||||
view.session.updateProperty(view.htmlID(), "tabindex", "0")
|
|
||||||
} else {
|
|
||||||
view.session.updateProperty(view.htmlID(), "tabindex", "-1")
|
|
||||||
}
|
|
||||||
|
|
||||||
case UserData:
|
case UserData:
|
||||||
view.properties[tag] = value
|
view.setRaw(tag, value)
|
||||||
|
return []PropertyName{UserData}
|
||||||
|
|
||||||
case Style, StyleDisabled:
|
case Style, StyleDisabled:
|
||||||
text, ok := value.(string)
|
if text, ok := value.(string); ok {
|
||||||
if !ok {
|
view.setRaw(tag, text)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
notCompatibleType(ID, value)
|
notCompatibleType(ID, value)
|
||||||
return false
|
return nil
|
||||||
}
|
|
||||||
view.properties[tag] = text
|
|
||||||
if view.created {
|
|
||||||
view.session.updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)))
|
|
||||||
}
|
|
||||||
|
|
||||||
case FocusEvent, LostFocusEvent:
|
case FocusEvent, LostFocusEvent:
|
||||||
return result(view.setFocusListener(tag, value))
|
return setNoParamEventListener[View](view, tag, value)
|
||||||
|
|
||||||
case KeyDownEvent, KeyUpEvent:
|
case KeyDownEvent, KeyUpEvent:
|
||||||
return result(view.setKeyListener(tag, value))
|
return setViewEventListener[View, KeyEvent](view, tag, value)
|
||||||
|
|
||||||
case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent:
|
case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent:
|
||||||
return result(view.setMouseListener(tag, value))
|
return setViewEventListener[View, MouseEvent](view, tag, value)
|
||||||
|
|
||||||
case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel:
|
case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel:
|
||||||
return result(view.setPointerListener(tag, value))
|
return setViewEventListener[View, PointerEvent](view, tag, value)
|
||||||
|
|
||||||
case TouchStart, TouchEnd, TouchMove, TouchCancel:
|
case TouchStart, TouchEnd, TouchMove, TouchCancel:
|
||||||
return result(view.setTouchListener(tag, value))
|
return setViewEventListener[View, TouchEvent](view, tag, value)
|
||||||
|
|
||||||
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
|
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent,
|
||||||
return result(view.setTransitionListener(tag, value))
|
AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
|
||||||
|
return setViewEventListener[View, string](view, tag, value)
|
||||||
case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
|
//return setTransitionListener(view, tag, value), tag
|
||||||
return result(view.setAnimationListener(tag, value))
|
//return setAnimationListener(view, tag, value), tag
|
||||||
|
|
||||||
case ResizeEvent, ScrollEvent:
|
case ResizeEvent, ScrollEvent:
|
||||||
return result(view.setFrameListener(tag, value))
|
return setViewEventListener[View, Frame](view, tag, value)
|
||||||
|
//return setFrameListener(view, tag, value), tag
|
||||||
default:
|
|
||||||
if !view.viewStyle.set(tag, value) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if view.created {
|
|
||||||
viewPropertyChanged(view, tag)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
view.propertyChangedEvent(tag)
|
return viewStyleSet(view, tag, value)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) SetParams(params Params) bool {
|
func (view *viewData) SetParams(params Params) bool {
|
||||||
|
@ -446,15 +439,29 @@ func (view *viewData) SetParams(params Params) bool {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func viewPropertyChanged(view *viewData, tag string) {
|
func viewPropertyChanged(view View, tag PropertyName) {
|
||||||
|
/*
|
||||||
if view.updateTransformProperty(tag) {
|
if view.updateTransformProperty(tag) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
htmlID := view.htmlID()
|
htmlID := view.htmlID()
|
||||||
session := view.session
|
session := view.Session()
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
|
case TabIndex:
|
||||||
|
if value, ok := intProperty(view, TabIndex, view.Session(), 0); ok {
|
||||||
|
session.updateProperty(view.htmlID(), "tabindex", strconv.Itoa(value))
|
||||||
|
} else if view.Focusable() {
|
||||||
|
session.updateProperty(view.htmlID(), "tabindex", "0")
|
||||||
|
} else {
|
||||||
|
session.updateProperty(view.htmlID(), "tabindex", "-1")
|
||||||
|
}
|
||||||
|
|
||||||
|
case Style, StyleDisabled:
|
||||||
|
session.updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)))
|
||||||
|
|
||||||
case Disabled:
|
case Disabled:
|
||||||
tabIndex := GetTabIndex(view, htmlID)
|
tabIndex := GetTabIndex(view, htmlID)
|
||||||
enabledClass := view.htmlClass(false)
|
enabledClass := view.htmlClass(false)
|
||||||
|
@ -462,7 +469,7 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
session.startUpdateScript(htmlID)
|
session.startUpdateScript(htmlID)
|
||||||
if IsDisabled(view) {
|
if IsDisabled(view) {
|
||||||
session.updateProperty(htmlID, "data-disabled", "1")
|
session.updateProperty(htmlID, "data-disabled", "1")
|
||||||
if view.hasHtmlDisabled {
|
if view.htmlDisabledProperty() {
|
||||||
session.updateProperty(htmlID, "disabled", true)
|
session.updateProperty(htmlID, "disabled", true)
|
||||||
}
|
}
|
||||||
if tabIndex >= 0 {
|
if tabIndex >= 0 {
|
||||||
|
@ -473,7 +480,7 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
session.updateProperty(htmlID, "data-disabled", "0")
|
session.updateProperty(htmlID, "data-disabled", "0")
|
||||||
if view.hasHtmlDisabled {
|
if view.htmlDisabledProperty() {
|
||||||
session.removeProperty(htmlID, "disabled")
|
session.removeProperty(htmlID, "disabled")
|
||||||
}
|
}
|
||||||
if tabIndex >= 0 {
|
if tabIndex >= 0 {
|
||||||
|
@ -485,82 +492,65 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
}
|
}
|
||||||
session.finishUpdateScript(htmlID)
|
session.finishUpdateScript(htmlID)
|
||||||
updateInnerHTML(htmlID, session)
|
updateInnerHTML(htmlID, session)
|
||||||
return
|
|
||||||
|
|
||||||
case Visibility:
|
case Visibility:
|
||||||
switch GetVisibility(view) {
|
switch GetVisibility(view) {
|
||||||
case Invisible:
|
case Invisible:
|
||||||
session.updateCSSProperty(htmlID, Visibility, "hidden")
|
session.updateCSSProperty(htmlID, string(Visibility), "hidden")
|
||||||
session.updateCSSProperty(htmlID, "display", "")
|
session.updateCSSProperty(htmlID, "display", "")
|
||||||
session.callFunc("hideTooltip")
|
session.callFunc("hideTooltip")
|
||||||
|
|
||||||
case Gone:
|
case Gone:
|
||||||
session.updateCSSProperty(htmlID, Visibility, "hidden")
|
session.updateCSSProperty(htmlID, string(Visibility), "hidden")
|
||||||
session.updateCSSProperty(htmlID, "display", "none")
|
session.updateCSSProperty(htmlID, "display", "none")
|
||||||
session.callFunc("hideTooltip")
|
session.callFunc("hideTooltip")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
session.updateCSSProperty(htmlID, Visibility, "visible")
|
session.updateCSSProperty(htmlID, string(Visibility), "visible")
|
||||||
session.updateCSSProperty(htmlID, "display", "")
|
session.updateCSSProperty(htmlID, "display", "")
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case Background:
|
case Background:
|
||||||
session.updateCSSProperty(htmlID, Background, view.backgroundCSS(session))
|
session.updateCSSProperty(htmlID, string(Background), backgroundCSS(view, session))
|
||||||
return
|
|
||||||
|
|
||||||
case Border:
|
case Border, BorderLeft, BorderRight, BorderTop, BorderBottom:
|
||||||
if getBorder(view, Border) == nil {
|
cssWidth := ""
|
||||||
if session.startUpdateScript(htmlID) {
|
cssColor := ""
|
||||||
defer session.finishUpdateScript(htmlID)
|
cssStyle := "none"
|
||||||
}
|
|
||||||
session.updateCSSProperty(htmlID, BorderWidth, "")
|
|
||||||
session.updateCSSProperty(htmlID, BorderColor, "")
|
|
||||||
session.updateCSSProperty(htmlID, BorderStyle, "none")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
|
|
||||||
case BorderLeft, BorderRight, BorderTop, BorderBottom:
|
if border := getBorderProperty(view, Border); border != nil {
|
||||||
if border := getBorder(view, Border); border != nil {
|
cssWidth = border.cssWidthValue(session)
|
||||||
if session.startUpdateScript(htmlID) {
|
cssColor = border.cssColorValue(session)
|
||||||
defer session.finishUpdateScript(htmlID)
|
cssStyle = border.cssStyleValue(session)
|
||||||
}
|
}
|
||||||
session.updateCSSProperty(htmlID, BorderWidth, border.cssWidthValue(session))
|
|
||||||
session.updateCSSProperty(htmlID, BorderColor, border.cssColorValue(session))
|
session.updateCSSProperty(htmlID, string(BorderWidth), cssWidth)
|
||||||
session.updateCSSProperty(htmlID, BorderStyle, border.cssStyleValue(session))
|
session.updateCSSProperty(htmlID, string(BorderColor), cssColor)
|
||||||
}
|
session.updateCSSProperty(htmlID, string(BorderStyle), cssStyle)
|
||||||
return
|
|
||||||
|
|
||||||
case BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle:
|
case BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle:
|
||||||
if border := getBorder(view, Border); border != nil {
|
if border := getBorderProperty(view, Border); border != nil {
|
||||||
session.updateCSSProperty(htmlID, BorderStyle, border.cssStyleValue(session))
|
session.updateCSSProperty(htmlID, string(BorderStyle), border.cssStyleValue(session))
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor:
|
case BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor:
|
||||||
if border := getBorder(view, Border); border != nil {
|
if border := getBorderProperty(view, Border); border != nil {
|
||||||
session.updateCSSProperty(htmlID, BorderColor, border.cssColorValue(session))
|
session.updateCSSProperty(htmlID, string(BorderColor), border.cssColorValue(session))
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
|
case BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
|
||||||
if border := getBorder(view, Border); border != nil {
|
if border := getBorderProperty(view, Border); border != nil {
|
||||||
session.updateCSSProperty(htmlID, BorderWidth, border.cssWidthValue(session))
|
session.updateCSSProperty(htmlID, string(BorderWidth), border.cssWidthValue(session))
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case Outline, OutlineColor, OutlineStyle, OutlineWidth:
|
case Outline, OutlineColor, OutlineStyle, OutlineWidth:
|
||||||
session.updateCSSProperty(htmlID, Outline, GetOutline(view).cssString(session))
|
session.updateCSSProperty(htmlID, string(Outline), GetOutline(view).cssString(session))
|
||||||
return
|
|
||||||
|
|
||||||
case Shadow:
|
case Shadow:
|
||||||
session.updateCSSProperty(htmlID, "box-shadow", shadowCSS(view, Shadow, session))
|
session.updateCSSProperty(htmlID, "box-shadow", shadowCSS(view, Shadow, session))
|
||||||
return
|
|
||||||
|
|
||||||
case TextShadow:
|
case TextShadow:
|
||||||
session.updateCSSProperty(htmlID, "text-shadow", shadowCSS(view, TextShadow, session))
|
session.updateCSSProperty(htmlID, "text-shadow", shadowCSS(view, TextShadow, session))
|
||||||
return
|
|
||||||
|
|
||||||
case Radius, RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
case Radius, RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
||||||
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
||||||
|
@ -568,19 +558,16 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
||||||
radius := GetRadius(view)
|
radius := GetRadius(view)
|
||||||
session.updateCSSProperty(htmlID, "border-radius", radius.cssString(session))
|
session.updateCSSProperty(htmlID, "border-radius", radius.cssString(session))
|
||||||
return
|
|
||||||
|
|
||||||
case Margin, MarginTop, MarginRight, MarginBottom, MarginLeft,
|
case Margin, MarginTop, MarginRight, MarginBottom, MarginLeft,
|
||||||
"top-margin", "right-margin", "bottom-margin", "left-margin":
|
"top-margin", "right-margin", "bottom-margin", "left-margin":
|
||||||
margin := GetMargin(view)
|
margin := GetMargin(view)
|
||||||
session.updateCSSProperty(htmlID, Margin, margin.cssString(session))
|
session.updateCSSProperty(htmlID, string(Margin), margin.cssString(session))
|
||||||
return
|
|
||||||
|
|
||||||
case Padding, PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
|
case Padding, PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
|
||||||
"top-padding", "right-padding", "bottom-padding", "left-padding":
|
"top-padding", "right-padding", "bottom-padding", "left-padding":
|
||||||
padding := GetPadding(view)
|
padding := GetPadding(view)
|
||||||
session.updateCSSProperty(htmlID, Padding, padding.cssString(session))
|
session.updateCSSProperty(htmlID, string(Padding), padding.cssString(session))
|
||||||
return
|
|
||||||
|
|
||||||
case AvoidBreak:
|
case AvoidBreak:
|
||||||
if avoid, ok := boolProperty(view, AvoidBreak, session); ok {
|
if avoid, ok := boolProperty(view, AvoidBreak, session); ok {
|
||||||
|
@ -590,7 +577,6 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
session.updateCSSProperty(htmlID, "break-inside", "auto")
|
session.updateCSSProperty(htmlID, "break-inside", "auto")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case Clip:
|
case Clip:
|
||||||
if clip := getClipShape(view, Clip, session); clip != nil && clip.valid(session) {
|
if clip := getClipShape(view, Clip, session); clip != nil && clip.valid(session) {
|
||||||
|
@ -598,29 +584,26 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, `clip-path`, "none")
|
session.updateCSSProperty(htmlID, `clip-path`, "none")
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case ShapeOutside:
|
case ShapeOutside:
|
||||||
if clip := getClipShape(view, ShapeOutside, session); clip != nil && clip.valid(session) {
|
if clip := getClipShape(view, ShapeOutside, session); clip != nil && clip.valid(session) {
|
||||||
session.updateCSSProperty(htmlID, ShapeOutside, clip.cssStyle(session))
|
session.updateCSSProperty(htmlID, string(ShapeOutside), clip.cssStyle(session))
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, ShapeOutside, "none")
|
session.updateCSSProperty(htmlID, string(ShapeOutside), "none")
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case Filter:
|
case Filter:
|
||||||
text := ""
|
text := ""
|
||||||
if value := view.getRaw(tag); value != nil {
|
if value := view.getRaw(Filter); value != nil {
|
||||||
if filter, ok := value.(ViewFilter); ok {
|
if filter, ok := value.(ViewFilter); ok {
|
||||||
text = filter.cssStyle(session)
|
text = filter.cssStyle(session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session.updateCSSProperty(htmlID, tag, text)
|
session.updateCSSProperty(htmlID, string(Filter), text)
|
||||||
return
|
|
||||||
|
|
||||||
case BackdropFilter:
|
case BackdropFilter:
|
||||||
text := ""
|
text := ""
|
||||||
if value := view.getRaw(tag); value != nil {
|
if value := view.getRaw(BackdropFilter); value != nil {
|
||||||
if filter, ok := value.(ViewFilter); ok {
|
if filter, ok := value.(ViewFilter); ok {
|
||||||
text = filter.cssStyle(session)
|
text = filter.cssStyle(session)
|
||||||
}
|
}
|
||||||
|
@ -629,8 +612,7 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
defer session.finishUpdateScript(htmlID)
|
defer session.finishUpdateScript(htmlID)
|
||||||
}
|
}
|
||||||
session.updateCSSProperty(htmlID, "-webkit-backdrop-filter", text)
|
session.updateCSSProperty(htmlID, "-webkit-backdrop-filter", text)
|
||||||
session.updateCSSProperty(htmlID, tag, text)
|
session.updateCSSProperty(htmlID, string(BackdropFilter), text)
|
||||||
return
|
|
||||||
|
|
||||||
case FontName:
|
case FontName:
|
||||||
if font, ok := stringProperty(view, FontName, session); ok {
|
if font, ok := stringProperty(view, FontName, session); ok {
|
||||||
|
@ -638,7 +620,6 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, "font-family", "")
|
session.updateCSSProperty(htmlID, "font-family", "")
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case Italic:
|
case Italic:
|
||||||
if state, ok := boolProperty(view, tag, session); ok {
|
if state, ok := boolProperty(view, tag, session); ok {
|
||||||
|
@ -650,7 +631,6 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, "font-style", "")
|
session.updateCSSProperty(htmlID, "font-style", "")
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case SmallCaps:
|
case SmallCaps:
|
||||||
if state, ok := boolProperty(view, tag, session); ok {
|
if state, ok := boolProperty(view, tag, session); ok {
|
||||||
|
@ -662,22 +642,18 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, "font-variant", "")
|
session.updateCSSProperty(htmlID, "font-variant", "")
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case Strikethrough, Overline, Underline:
|
case Strikethrough, Overline, Underline:
|
||||||
session.updateCSSProperty(htmlID, "text-decoration", view.cssTextDecoration(session))
|
session.updateCSSProperty(htmlID, "text-decoration", textDecorationCSS(view, session))
|
||||||
for _, tag2 := range []string{TextLineColor, TextLineStyle, TextLineThickness} {
|
for _, tag2 := range []PropertyName{TextLineColor, TextLineStyle, TextLineThickness} {
|
||||||
viewPropertyChanged(view, tag2)
|
viewPropertyChanged(view, tag2)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case Transition:
|
case Transition:
|
||||||
view.updateTransitionCSS()
|
session.updateCSSProperty(htmlID, "transition", transitionCSS(view, session))
|
||||||
return
|
|
||||||
|
|
||||||
case AnimationTag:
|
case AnimationTag:
|
||||||
session.updateCSSProperty(htmlID, AnimationTag, view.animationCSS(session))
|
session.updateCSSProperty(htmlID, "animation", animationCSS(view, session))
|
||||||
return
|
|
||||||
|
|
||||||
case AnimationPaused:
|
case AnimationPaused:
|
||||||
paused, ok := boolProperty(view, AnimationPaused, session)
|
paused, ok := boolProperty(view, AnimationPaused, session)
|
||||||
|
@ -688,21 +664,18 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, `animation-play-state`, `running`)
|
session.updateCSSProperty(htmlID, `animation-play-state`, `running`)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case ZIndex, Order, TabSize:
|
case ZIndex, Order, TabSize:
|
||||||
if i, ok := intProperty(view, tag, session, 0); ok {
|
if i, ok := intProperty(view, tag, session, 0); ok {
|
||||||
session.updateCSSProperty(htmlID, tag, strconv.Itoa(i))
|
session.updateCSSProperty(htmlID, string(tag), strconv.Itoa(i))
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, tag, "")
|
session.updateCSSProperty(htmlID, string(tag), "")
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case Row, Column:
|
case Row, Column:
|
||||||
if parentID := view.parentHTMLID(); parentID != "" {
|
if parentID := view.parentHTMLID(); parentID != "" {
|
||||||
updateInnerHTML(parentID, session)
|
updateInnerHTML(parentID, session)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case UserSelect:
|
case UserSelect:
|
||||||
if session.startUpdateScript(htmlID) {
|
if session.startUpdateScript(htmlID) {
|
||||||
|
@ -720,7 +693,6 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
session.updateCSSProperty(htmlID, "-webkit-user-select", "")
|
session.updateCSSProperty(htmlID, "-webkit-user-select", "")
|
||||||
session.updateCSSProperty(htmlID, "user-select", "")
|
session.updateCSSProperty(htmlID, "user-select", "")
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case ColumnSpanAll:
|
case ColumnSpanAll:
|
||||||
if spanAll, ok := boolProperty(view, ColumnSpanAll, session); ok && spanAll {
|
if spanAll, ok := boolProperty(view, ColumnSpanAll, session); ok && spanAll {
|
||||||
|
@ -728,7 +700,6 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, `column-span`, `none`)
|
session.updateCSSProperty(htmlID, `column-span`, `none`)
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
|
||||||
case Tooltip:
|
case Tooltip:
|
||||||
if tooltip := GetTooltip(view); tooltip == "" {
|
if tooltip := GetTooltip(view); tooltip == "" {
|
||||||
|
@ -738,9 +709,58 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
session.updateProperty(htmlID, "onmouseenter", "mouseEnterEvent(this, event)")
|
session.updateProperty(htmlID, "onmouseenter", "mouseEnterEvent(this, event)")
|
||||||
session.updateProperty(htmlID, "onmouseleave", "mouseLeaveEvent(this, event)")
|
session.updateProperty(htmlID, "onmouseleave", "mouseLeaveEvent(this, event)")
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
case PerspectiveOriginX, PerspectiveOriginY:
|
||||||
|
if getTransform3D(view, session) {
|
||||||
|
x, y := GetPerspectiveOrigin(view)
|
||||||
|
value := ""
|
||||||
|
if x.Type != Auto || y.Type != Auto {
|
||||||
|
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
|
||||||
|
}
|
||||||
|
session.updateCSSProperty(htmlID, "perspective-origin", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BackfaceVisible:
|
||||||
|
if getTransform3D(view, session) {
|
||||||
|
if GetBackfaceVisible(view) {
|
||||||
|
session.updateCSSProperty(htmlID, string(BackfaceVisible), "visible")
|
||||||
|
} else {
|
||||||
|
session.updateCSSProperty(htmlID, string(BackfaceVisible), "hidden")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case OriginX, OriginY, OriginZ:
|
||||||
|
x, y, z := getOrigin(view, session)
|
||||||
|
value := ""
|
||||||
|
|
||||||
|
if z.Type != Auto {
|
||||||
|
value = x.cssString("50%", session) + " " + y.cssString("50%", session) + " " + z.cssString("50%", session)
|
||||||
|
} else if x.Type != Auto || y.Type != Auto {
|
||||||
|
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
|
||||||
|
}
|
||||||
|
session.updateCSSProperty(htmlID, "transform-origin", value)
|
||||||
|
|
||||||
|
case TransformTag, Perspective, SkewX, SkewY, TranslateX, TranslateY, TranslateZ,
|
||||||
|
ScaleX, ScaleY, ScaleZ, Rotate, RotateX, RotateY, RotateZ:
|
||||||
|
css := ""
|
||||||
|
if transform := getTransformProperty(view); transform != nil {
|
||||||
|
css = transform.transformCSS(session)
|
||||||
|
}
|
||||||
|
session.updateCSSProperty(htmlID, "transform", css)
|
||||||
|
|
||||||
|
case FocusEvent, LostFocusEvent, ResizeEvent, ScrollEvent, KeyDownEvent, KeyUpEvent,
|
||||||
|
ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent,
|
||||||
|
PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel,
|
||||||
|
TouchStart, TouchEnd, TouchMove, TouchCancel,
|
||||||
|
TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent,
|
||||||
|
AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
|
||||||
|
|
||||||
|
updateEventListenerHtml(view, tag)
|
||||||
|
|
||||||
|
case DataList:
|
||||||
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
|
|
||||||
|
default:
|
||||||
if cssTag, ok := sizeProperties[tag]; ok {
|
if cssTag, ok := sizeProperties[tag]; ok {
|
||||||
if size, ok := sizeProperty(view, tag, session); ok {
|
if size, ok := sizeProperty(view, tag, session); ok {
|
||||||
session.updateCSSProperty(htmlID, cssTag, size.cssString("", session))
|
session.updateCSSProperty(htmlID, cssTag, size.cssString("", session))
|
||||||
|
@ -750,12 +770,12 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
colorTags := map[string]string{
|
colorTags := map[PropertyName]string{
|
||||||
BackgroundColor: BackgroundColor,
|
BackgroundColor: string(BackgroundColor),
|
||||||
TextColor: "color",
|
TextColor: "color",
|
||||||
TextLineColor: "text-decoration-color",
|
TextLineColor: "text-decoration-color",
|
||||||
CaretColor: CaretColor,
|
CaretColor: string(CaretColor),
|
||||||
AccentColor: AccentColor,
|
AccentColor: string(AccentColor),
|
||||||
}
|
}
|
||||||
if cssTag, ok := colorTags[tag]; ok {
|
if cssTag, ok := colorTags[tag]; ok {
|
||||||
if color, ok := colorProperty(view, tag, session); ok {
|
if color, ok := colorProperty(view, tag, session); ok {
|
||||||
|
@ -775,31 +795,23 @@ func viewPropertyChanged(view *viewData, tag string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, floatTag := range []string{Opacity, ScaleX, ScaleY, ScaleZ, RotateX, RotateY, RotateZ} {
|
if f, ok := floatTextProperty(view, Opacity, session, 0); ok {
|
||||||
if tag == floatTag {
|
session.updateCSSProperty(htmlID, string(Opacity), f)
|
||||||
if f, ok := floatTextProperty(view, floatTag, session, 0); ok {
|
|
||||||
session.updateCSSProperty(htmlID, floatTag, f)
|
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, floatTag, "")
|
session.updateCSSProperty(htmlID, string(Opacity), "")
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) Get(tag string) any {
|
func viewGet(view View, tag PropertyName) any {
|
||||||
return view.get(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) get(tag string) any {
|
|
||||||
if tag == ID {
|
if tag == ID {
|
||||||
if view.viewID != "" {
|
if id := view.ID(); id != "" {
|
||||||
return view.viewID
|
return id
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return view.viewStyle.get(tag)
|
return viewStyleGet(view, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) htmlTag() string {
|
func (view *viewData) htmlTag() string {
|
||||||
|
@ -848,6 +860,10 @@ func (view *viewData) cssStyle(self View, builder cssBuilder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (view *viewData) htmlDisabledProperty() bool {
|
||||||
|
return view.hasHtmlDisabled
|
||||||
|
}
|
||||||
|
|
||||||
func (view *viewData) htmlProperties(self View, buffer *strings.Builder) {
|
func (view *viewData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
view.created = true
|
view.created = true
|
||||||
|
|
||||||
|
@ -908,23 +924,30 @@ func viewHTML(view View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasTooltip := false
|
|
||||||
if tooltip := GetTooltip(view); tooltip != "" {
|
if tooltip := GetTooltip(view); tooltip != "" {
|
||||||
buffer.WriteString(`data-tooltip=" `)
|
buffer.WriteString(`data-tooltip=" `)
|
||||||
buffer.WriteString(tooltip)
|
buffer.WriteString(tooltip)
|
||||||
buffer.WriteString(`" `)
|
buffer.WriteString(`" onmouseenter="mouseEnterEvent(this, event)" onmouseleave="mouseLeaveEvent(this, event)" `)
|
||||||
hasTooltip = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(`onscroll="scrollEvent(this, event)" `)
|
buffer.WriteString(`onscroll="scrollEvent(this, event)" `)
|
||||||
|
|
||||||
keyEventsHtml(view, buffer)
|
|
||||||
mouseEventsHtml(view, buffer, hasTooltip)
|
|
||||||
pointerEventsHtml(view, buffer)
|
|
||||||
touchEventsHtml(view, buffer)
|
|
||||||
focusEventsHtml(view, buffer)
|
focusEventsHtml(view, buffer)
|
||||||
transitionEventsHtml(view, buffer)
|
keyEventsHtml(view, buffer)
|
||||||
animationEventsHtml(view, buffer)
|
|
||||||
|
viewEventsHtml[MouseEvent](view, []PropertyName{ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent}, buffer)
|
||||||
|
//mouseEventsHtml(view, buffer, hasTooltip)
|
||||||
|
|
||||||
|
viewEventsHtml[PointerEvent](view, []PropertyName{PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel}, buffer)
|
||||||
|
//pointerEventsHtml(view, buffer)
|
||||||
|
|
||||||
|
viewEventsHtml[TouchEvent](view, []PropertyName{TouchStart, TouchEnd, TouchMove, TouchCancel}, buffer)
|
||||||
|
//touchEventsHtml(view, buffer)
|
||||||
|
|
||||||
|
viewEventsHtml[string](view, []PropertyName{TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent,
|
||||||
|
AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent}, buffer)
|
||||||
|
//transitionEventsHtml(view, buffer)
|
||||||
|
//animationEventsHtml(view, buffer)
|
||||||
|
|
||||||
buffer.WriteRune('>')
|
buffer.WriteRune('>')
|
||||||
view.htmlSubviews(view, buffer)
|
view.htmlSubviews(view, buffer)
|
||||||
|
@ -957,7 +980,7 @@ func (view *viewData) htmlClass(disabled bool) string {
|
||||||
return cls
|
return cls
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) handleCommand(self View, command string, data DataObject) bool {
|
func (view *viewData) handleCommand(self View, command PropertyName, data DataObject) bool {
|
||||||
switch command {
|
switch command {
|
||||||
|
|
||||||
case KeyDownEvent, KeyUpEvent:
|
case KeyDownEvent, KeyUpEvent:
|
||||||
|
@ -976,13 +999,13 @@ func (view *viewData) handleCommand(self View, command string, data DataObject)
|
||||||
|
|
||||||
case FocusEvent:
|
case FocusEvent:
|
||||||
view.hasFocus = true
|
view.hasFocus = true
|
||||||
for _, listener := range getFocusListeners(view, nil, command) {
|
for _, listener := range getNoParamEventListeners[View](view, nil, command) {
|
||||||
listener(self)
|
listener(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
case LostFocusEvent:
|
case LostFocusEvent:
|
||||||
view.hasFocus = false
|
view.hasFocus = false
|
||||||
for _, listener := range getFocusListeners(view, nil, command) {
|
for _, listener := range getNoParamEventListeners[View](view, nil, command) {
|
||||||
listener(self)
|
listener(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1030,7 +1053,7 @@ func (view *viewData) handleCommand(self View, command string, data DataObject)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) SetChangeListener(tag string, listener func(View, string)) {
|
func (view *viewData) SetChangeListener(tag PropertyName, listener func(View, PropertyName)) {
|
||||||
if listener == nil {
|
if listener == nil {
|
||||||
delete(view.changeListener, tag)
|
delete(view.changeListener, tag)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1043,9 +1066,12 @@ func (view *viewData) HasFocus() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) String() string {
|
func (view *viewData) String() string {
|
||||||
return getViewString(view, nil)
|
buffer := allocStringBuilder()
|
||||||
|
defer freeStringBuilder(buffer)
|
||||||
|
writeViewStyle(view.tag, view, buffer, "", nil)
|
||||||
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) exscludeTags() []string {
|
func (view *viewData) exscludeTags() []PropertyName {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
273
viewClip.go
273
viewClip.go
|
@ -15,19 +15,19 @@ type ClipShape interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type insetClip struct {
|
type insetClip struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
type ellipseClip struct {
|
type ellipseClip struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
type circleClip struct {
|
type circleClip struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
type polygonClip struct {
|
type polygonClip struct {
|
||||||
points []any
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsetClip creates a rectangle View clipping area.
|
// InsetClip creates a rectangle View clipping area.
|
||||||
|
@ -39,12 +39,12 @@ type polygonClip struct {
|
||||||
func InsetClip(top, right, bottom, left SizeUnit, radius RadiusProperty) ClipShape {
|
func InsetClip(top, right, bottom, left SizeUnit, radius RadiusProperty) ClipShape {
|
||||||
clip := new(insetClip)
|
clip := new(insetClip)
|
||||||
clip.init()
|
clip.init()
|
||||||
clip.Set(Top, top)
|
clip.setRaw(Top, top)
|
||||||
clip.Set(Right, right)
|
clip.setRaw(Right, right)
|
||||||
clip.Set(Bottom, bottom)
|
clip.setRaw(Bottom, bottom)
|
||||||
clip.Set(Left, left)
|
clip.setRaw(Left, left)
|
||||||
if radius != nil {
|
if radius != nil {
|
||||||
clip.Set(Radius, radius)
|
clip.setRaw(Radius, radius)
|
||||||
}
|
}
|
||||||
return clip
|
return clip
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,9 @@ func InsetClip(top, right, bottom, left SizeUnit, radius RadiusProperty) ClipSha
|
||||||
func CircleClip(x, y, radius SizeUnit) ClipShape {
|
func CircleClip(x, y, radius SizeUnit) ClipShape {
|
||||||
clip := new(circleClip)
|
clip := new(circleClip)
|
||||||
clip.init()
|
clip.init()
|
||||||
clip.Set(X, x)
|
clip.setRaw(X, x)
|
||||||
clip.Set(Y, y)
|
clip.setRaw(Y, y)
|
||||||
clip.Set(Radius, radius)
|
clip.setRaw(Radius, radius)
|
||||||
return clip
|
return clip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,10 +63,10 @@ func CircleClip(x, y, radius SizeUnit) ClipShape {
|
||||||
func EllipseClip(x, y, rx, ry SizeUnit) ClipShape {
|
func EllipseClip(x, y, rx, ry SizeUnit) ClipShape {
|
||||||
clip := new(ellipseClip)
|
clip := new(ellipseClip)
|
||||||
clip.init()
|
clip.init()
|
||||||
clip.Set(X, x)
|
clip.setRaw(X, x)
|
||||||
clip.Set(Y, y)
|
clip.setRaw(Y, y)
|
||||||
clip.Set(RadiusX, rx)
|
clip.setRaw(RadiusX, rx)
|
||||||
clip.Set(RadiusY, ry)
|
clip.setRaw(RadiusY, ry)
|
||||||
return clip
|
return clip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,8 +75,8 @@ func EllipseClip(x, y, rx, ry SizeUnit) ClipShape {
|
||||||
// or the text representation of SizeUnit, or elements of SizeUnit type.
|
// or the text representation of SizeUnit, or elements of SizeUnit type.
|
||||||
func PolygonClip(points []any) ClipShape {
|
func PolygonClip(points []any) ClipShape {
|
||||||
clip := new(polygonClip)
|
clip := new(polygonClip)
|
||||||
clip.points = []any{}
|
clip.init()
|
||||||
if clip.Set(Points, points) {
|
if polygonClipSet(clip, Points, points) != nil {
|
||||||
return clip
|
return clip
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -85,34 +85,45 @@ func PolygonClip(points []any) ClipShape {
|
||||||
// PolygonPointsClip creates a polygon View clipping area.
|
// PolygonPointsClip creates a polygon View clipping area.
|
||||||
func PolygonPointsClip(points []SizeUnit) ClipShape {
|
func PolygonPointsClip(points []SizeUnit) ClipShape {
|
||||||
clip := new(polygonClip)
|
clip := new(polygonClip)
|
||||||
clip.points = []any{}
|
clip.init()
|
||||||
if clip.Set(Points, points) {
|
if polygonClipSet(clip, Points, points) != nil {
|
||||||
return clip
|
return clip
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *insetClip) Set(tag string, value any) bool {
|
func (clip *insetClip) init() {
|
||||||
switch strings.ToLower(tag) {
|
clip.dataProperty.init()
|
||||||
case Top, Right, Bottom, Left:
|
clip.set = insetClipSet
|
||||||
if value == nil {
|
clip.supportedProperties = []PropertyName{
|
||||||
clip.Remove(tag)
|
Top, Right, Bottom, Left, Radius,
|
||||||
return true
|
RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
||||||
|
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
||||||
|
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
||||||
|
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY,
|
||||||
}
|
}
|
||||||
return clip.setSizeProperty(tag, value)
|
}
|
||||||
|
|
||||||
|
func insetClipSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
switch tag {
|
||||||
|
case Top, Right, Bottom, Left:
|
||||||
|
return setSizeProperty(properties, tag, value)
|
||||||
|
|
||||||
case Radius:
|
case Radius:
|
||||||
return clip.setRadius(value)
|
return setRadiusProperty(properties, value)
|
||||||
|
|
||||||
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
||||||
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
||||||
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
||||||
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
||||||
return clip.setRadiusElement(tag, value)
|
if setRadiusPropertyElement(properties, tag, value) {
|
||||||
|
return []PropertyName{tag, Radius}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLogF(`"%s" property is not supported by the inset clip shape`, tag)
|
ErrorLogF(`"%s" property is not supported by the inset clip shape`, tag)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *insetClip) String() string {
|
func (clip *insetClip) String() string {
|
||||||
|
@ -122,12 +133,12 @@ func (clip *insetClip) String() string {
|
||||||
func (clip *insetClip) writeString(buffer *strings.Builder, indent string) {
|
func (clip *insetClip) writeString(buffer *strings.Builder, indent string) {
|
||||||
buffer.WriteString("inset { ")
|
buffer.WriteString("inset { ")
|
||||||
comma := false
|
comma := false
|
||||||
for _, tag := range []string{Top, Right, Bottom, Left, Radius} {
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius} {
|
||||||
if value, ok := clip.properties[tag]; ok {
|
if value, ok := clip.properties[tag]; ok {
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
|
@ -143,7 +154,7 @@ func (clip *insetClip) cssStyle(session Session) string {
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
leadText := "inset("
|
leadText := "inset("
|
||||||
for _, tag := range []string{Top, Right, Bottom, Left} {
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left} {
|
||||||
value, _ := sizeProperty(clip, tag, session)
|
value, _ := sizeProperty(clip, tag, session)
|
||||||
buffer.WriteString(leadText)
|
buffer.WriteString(leadText)
|
||||||
buffer.WriteString(value.cssString("0px", session))
|
buffer.WriteString(value.cssString("0px", session))
|
||||||
|
@ -160,7 +171,7 @@ func (clip *insetClip) cssStyle(session Session) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *insetClip) valid(session Session) bool {
|
func (clip *insetClip) valid(session Session) bool {
|
||||||
for _, tag := range []string{Top, Right, Bottom, Left, Radius, RadiusX, RadiusY} {
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius, RadiusX, RadiusY} {
|
||||||
if value, ok := sizeProperty(clip, tag, session); ok && value.Type != Auto && value.Value != 0 {
|
if value, ok := sizeProperty(clip, tag, session); ok && value.Type != Auto && value.Value != 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -168,18 +179,20 @@ func (clip *insetClip) valid(session Session) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *circleClip) Set(tag string, value any) bool {
|
func (clip *circleClip) init() {
|
||||||
if value == nil {
|
clip.dataProperty.init()
|
||||||
clip.Remove(tag)
|
clip.set = circleClipSet
|
||||||
|
clip.supportedProperties = []PropertyName{X, Y, Radius}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch strings.ToLower(tag) {
|
func circleClipSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
switch tag {
|
||||||
case X, Y, Radius:
|
case X, Y, Radius:
|
||||||
return clip.setSizeProperty(tag, value)
|
return setSizeProperty(properties, tag, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLogF(`"%s" property is not supported by the circle clip shape`, tag)
|
ErrorLogF(`"%s" property is not supported by the circle clip shape`, tag)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *circleClip) String() string {
|
func (clip *circleClip) String() string {
|
||||||
|
@ -189,12 +202,12 @@ func (clip *circleClip) String() string {
|
||||||
func (clip *circleClip) writeString(buffer *strings.Builder, indent string) {
|
func (clip *circleClip) writeString(buffer *strings.Builder, indent string) {
|
||||||
buffer.WriteString("circle { ")
|
buffer.WriteString("circle { ")
|
||||||
comma := false
|
comma := false
|
||||||
for _, tag := range []string{Radius, X, Y} {
|
for _, tag := range []PropertyName{Radius, X, Y} {
|
||||||
if value, ok := clip.properties[tag]; ok {
|
if value, ok := clip.properties[tag]; ok {
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
|
@ -232,22 +245,27 @@ func (clip *circleClip) valid(session Session) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *ellipseClip) Set(tag string, value any) bool {
|
func (clip *ellipseClip) init() {
|
||||||
if value == nil {
|
clip.dataProperty.init()
|
||||||
clip.Remove(tag)
|
clip.set = ellipseClipSet
|
||||||
|
clip.supportedProperties = []PropertyName{X, Y, Radius, RadiusX, RadiusY}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch strings.ToLower(tag) {
|
func ellipseClipSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
switch tag {
|
||||||
case X, Y, RadiusX, RadiusY:
|
case X, Y, RadiusX, RadiusY:
|
||||||
return clip.setSizeProperty(tag, value)
|
return setSizeProperty(properties, tag, value)
|
||||||
|
|
||||||
case Radius:
|
case Radius:
|
||||||
return clip.setSizeProperty(RadiusX, value) &&
|
if result := setSizeProperty(properties, RadiusX, value); result != nil {
|
||||||
clip.setSizeProperty(RadiusY, value)
|
properties.setRaw(RadiusY, properties.getRaw(RadiusX))
|
||||||
|
return append(result, RadiusY)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLogF(`"%s" property is not supported by the ellipse clip shape`, tag)
|
ErrorLogF(`"%s" property is not supported by the ellipse clip shape`, tag)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *ellipseClip) String() string {
|
func (clip *ellipseClip) String() string {
|
||||||
|
@ -257,12 +275,12 @@ func (clip *ellipseClip) String() string {
|
||||||
func (clip *ellipseClip) writeString(buffer *strings.Builder, indent string) {
|
func (clip *ellipseClip) writeString(buffer *strings.Builder, indent string) {
|
||||||
buffer.WriteString("ellipse { ")
|
buffer.WriteString("ellipse { ")
|
||||||
comma := false
|
comma := false
|
||||||
for _, tag := range []string{RadiusX, RadiusY, X, Y} {
|
for _, tag := range []PropertyName{RadiusX, RadiusY, X, Y} {
|
||||||
if value, ok := clip.properties[tag]; ok {
|
if value, ok := clip.properties[tag]; ok {
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
|
@ -302,104 +320,91 @@ func (clip *ellipseClip) valid(session Session) bool {
|
||||||
return rx.Value != 0 && ry.Value != 0
|
return rx.Value != 0 && ry.Value != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *polygonClip) Get(tag string) any {
|
func (clip *polygonClip) init() {
|
||||||
if Points == strings.ToLower(tag) {
|
clip.dataProperty.init()
|
||||||
return clip.points
|
clip.set = polygonClipSet
|
||||||
}
|
clip.supportedProperties = []PropertyName{Points}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *polygonClip) getRaw(tag string) any {
|
func polygonClipSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
return clip.Get(tag)
|
if Points == tag {
|
||||||
}
|
|
||||||
|
|
||||||
func (clip *polygonClip) Set(tag string, value any) bool {
|
|
||||||
if Points == strings.ToLower(tag) {
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case []any:
|
case []any:
|
||||||
result := true
|
points := make([]any, len(value))
|
||||||
clip.points = make([]any, len(value))
|
|
||||||
for i, val := range value {
|
for i, val := range value {
|
||||||
switch val := val.(type) {
|
switch val := val.(type) {
|
||||||
case string:
|
case string:
|
||||||
if isConstantName(val) {
|
if isConstantName(val) {
|
||||||
clip.points[i] = val
|
points[i] = val
|
||||||
} else if size, ok := StringToSizeUnit(val); ok {
|
} else if size, ok := StringToSizeUnit(val); ok {
|
||||||
clip.points[i] = size
|
points[i] = size
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, val)
|
notCompatibleType(tag, val)
|
||||||
result = false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case SizeUnit:
|
case SizeUnit:
|
||||||
clip.points[i] = val
|
points[i] = val
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notCompatibleType(tag, val)
|
notCompatibleType(tag, val)
|
||||||
clip.points[i] = AutoSize()
|
points[i] = AutoSize()
|
||||||
result = false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
properties.setRaw(Points, points)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case []SizeUnit:
|
case []SizeUnit:
|
||||||
clip.points = make([]any, len(value))
|
points := make([]any, len(value))
|
||||||
for i, point := range value {
|
for i, point := range value {
|
||||||
clip.points[i] = point
|
points[i] = point
|
||||||
}
|
}
|
||||||
return true
|
properties.setRaw(Points, points)
|
||||||
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
result := true
|
|
||||||
values := strings.Split(value, ",")
|
values := strings.Split(value, ",")
|
||||||
clip.points = make([]any, len(values))
|
points := make([]any, len(values))
|
||||||
for i, val := range values {
|
for i, val := range values {
|
||||||
val = strings.Trim(val, " \t\n\r")
|
val = strings.Trim(val, " \t\n\r")
|
||||||
if isConstantName(val) {
|
if isConstantName(val) {
|
||||||
clip.points[i] = val
|
points[i] = val
|
||||||
} else if size, ok := StringToSizeUnit(val); ok {
|
} else if size, ok := StringToSizeUnit(val); ok {
|
||||||
clip.points[i] = size
|
points[i] = size
|
||||||
} else {
|
} else {
|
||||||
notCompatibleType(tag, val)
|
notCompatibleType(tag, val)
|
||||||
result = false
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
properties.setRaw(Points, points)
|
||||||
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
func (clip *polygonClip) setRaw(tag string, value any) {
|
|
||||||
clip.Set(tag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (clip *polygonClip) Remove(tag string) {
|
|
||||||
if Points == strings.ToLower(tag) {
|
|
||||||
clip.points = []any{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (clip *polygonClip) Clear() {
|
|
||||||
clip.points = []any{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (clip *polygonClip) AllTags() []string {
|
|
||||||
return []string{Points}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *polygonClip) String() string {
|
func (clip *polygonClip) String() string {
|
||||||
return runStringWriter(clip)
|
return runStringWriter(clip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (clip *polygonClip) points() []any {
|
||||||
|
if value := clip.getRaw(Points); value != nil {
|
||||||
|
if points, ok := value.([]any); ok {
|
||||||
|
return points
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (clip *polygonClip) writeString(buffer *strings.Builder, indent string) {
|
func (clip *polygonClip) writeString(buffer *strings.Builder, indent string) {
|
||||||
|
|
||||||
buffer.WriteString("inset { ")
|
buffer.WriteString("inset { ")
|
||||||
|
|
||||||
if clip.points != nil {
|
if points := clip.points(); points != nil {
|
||||||
buffer.WriteString(Points)
|
buffer.WriteString(string(Points))
|
||||||
buffer.WriteString(` = "`)
|
buffer.WriteString(` = "`)
|
||||||
for i, value := range clip.points {
|
for i, value := range points {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
|
@ -408,13 +413,13 @@ func (clip *polygonClip) writeString(buffer *strings.Builder, indent string) {
|
||||||
|
|
||||||
buffer.WriteString(`" `)
|
buffer.WriteString(`" `)
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteRune('}')
|
buffer.WriteRune('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *polygonClip) cssStyle(session Session) string {
|
func (clip *polygonClip) cssStyle(session Session) string {
|
||||||
|
|
||||||
count := len(clip.points)
|
points := clip.points()
|
||||||
|
count := len(points)
|
||||||
if count < 2 {
|
if count < 2 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -443,9 +448,9 @@ func (clip *polygonClip) cssStyle(session Session) string {
|
||||||
leadText := "polygon("
|
leadText := "polygon("
|
||||||
for i := 1; i < count; i += 2 {
|
for i := 1; i < count; i += 2 {
|
||||||
buffer.WriteString(leadText)
|
buffer.WriteString(leadText)
|
||||||
writePoint(clip.points[i-1])
|
writePoint(points[i-1])
|
||||||
buffer.WriteRune(' ')
|
buffer.WriteRune(' ')
|
||||||
writePoint(clip.points[i])
|
writePoint(points[i])
|
||||||
leadText = ", "
|
leadText = ", "
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,42 +459,46 @@ func (clip *polygonClip) cssStyle(session Session) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clip *polygonClip) valid(session Session) bool {
|
func (clip *polygonClip) valid(session Session) bool {
|
||||||
return len(clip.points) > 0
|
return len(clip.points()) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseClipShape(obj DataObject) ClipShape {
|
func parseClipShape(obj DataObject) ClipShape {
|
||||||
switch obj.Tag() {
|
switch obj.Tag() {
|
||||||
case "inset":
|
case "inset":
|
||||||
clip := new(insetClip)
|
clip := new(insetClip)
|
||||||
for _, tag := range []string{Top, Right, Bottom, Left, Radius, RadiusX, RadiusY} {
|
clip.init()
|
||||||
if value, ok := obj.PropertyValue(tag); ok {
|
for _, tag := range []PropertyName{Top, Right, Bottom, Left, Radius, RadiusX, RadiusY} {
|
||||||
clip.Set(tag, value)
|
if value, ok := obj.PropertyValue(string(tag)); ok {
|
||||||
|
insetClipSet(clip, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return clip
|
return clip
|
||||||
|
|
||||||
case "circle":
|
case "circle":
|
||||||
clip := new(ellipseClip)
|
clip := new(ellipseClip)
|
||||||
for _, tag := range []string{X, Y, Radius} {
|
clip.init()
|
||||||
if value, ok := obj.PropertyValue(tag); ok {
|
for _, tag := range []PropertyName{X, Y, Radius} {
|
||||||
clip.Set(tag, value)
|
if value, ok := obj.PropertyValue(string(tag)); ok {
|
||||||
|
circleClipSet(clip, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return clip
|
return clip
|
||||||
|
|
||||||
case "ellipse":
|
case "ellipse":
|
||||||
clip := new(ellipseClip)
|
clip := new(ellipseClip)
|
||||||
for _, tag := range []string{X, Y, RadiusX, RadiusY} {
|
clip.init()
|
||||||
if value, ok := obj.PropertyValue(tag); ok {
|
for _, tag := range []PropertyName{X, Y, RadiusX, RadiusY} {
|
||||||
clip.Set(tag, value)
|
if value, ok := obj.PropertyValue(string(tag)); ok {
|
||||||
|
ellipseClipSet(clip, tag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return clip
|
return clip
|
||||||
|
|
||||||
case "polygon":
|
case "polygon":
|
||||||
clip := new(ellipseClip)
|
clip := new(ellipseClip)
|
||||||
if value, ok := obj.PropertyValue(Points); ok {
|
clip.init()
|
||||||
clip.Set(Points, value)
|
if value, ok := obj.PropertyValue(string(Points)); ok {
|
||||||
|
polygonClipSet(clip, Points, value)
|
||||||
}
|
}
|
||||||
return clip
|
return clip
|
||||||
}
|
}
|
||||||
|
@ -497,45 +506,45 @@ func parseClipShape(obj DataObject) ClipShape {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) setClipShape(tag string, value any) bool {
|
func setClipShapeProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case ClipShape:
|
case ClipShape:
|
||||||
style.properties[tag] = value
|
properties.setRaw(tag, value)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if isConstantName(value) {
|
if isConstantName(value) {
|
||||||
style.properties[tag] = value
|
properties.setRaw(tag, value)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj := NewDataObject(value); obj == nil {
|
if obj := NewDataObject(value); obj == nil {
|
||||||
if clip := parseClipShape(obj); clip != nil {
|
if clip := parseClipShape(obj); clip != nil {
|
||||||
style.properties[tag] = clip
|
properties.setRaw(tag, clip)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
if clip := parseClipShape(value); clip != nil {
|
if clip := parseClipShape(value); clip != nil {
|
||||||
style.properties[tag] = clip
|
properties.setRaw(tag, clip)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataValue:
|
case DataValue:
|
||||||
if value.IsObject() {
|
if value.IsObject() {
|
||||||
if clip := parseClipShape(value.Object()); clip != nil {
|
if clip := parseClipShape(value.Object()); clip != nil {
|
||||||
style.properties[tag] = clip
|
properties.setRaw(tag, clip)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getClipShape(prop Properties, tag string, session Session) ClipShape {
|
func getClipShape(prop Properties, tag PropertyName, session Session) ClipShape {
|
||||||
if value := prop.getRaw(tag); value != nil {
|
if value := prop.getRaw(tag); value != nil {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case ClipShape:
|
case ClipShape:
|
||||||
|
|
|
@ -85,6 +85,7 @@ func CreateViewFromObject(session Session, object DataObject) View {
|
||||||
defer session.setIgnoreViewUpdates(false)
|
defer session.setIgnoreViewUpdates(false)
|
||||||
}
|
}
|
||||||
view := creator(session)
|
view := creator(session)
|
||||||
|
view.init(session)
|
||||||
if customView, ok := view.(CustomView); ok {
|
if customView, ok := view.(CustomView); ok {
|
||||||
if !InitCustomView(customView, tag, session, nil) {
|
if !InitCustomView(customView, tag, session, nil) {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -17,7 +17,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
Blur = "blur"
|
Blur PropertyName = "blur"
|
||||||
|
|
||||||
// Brightness is the constant for "brightness" property tag.
|
// Brightness is the constant for "brightness" property tag.
|
||||||
//
|
//
|
||||||
|
@ -29,7 +29,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
Brightness = "brightness"
|
Brightness PropertyName = "brightness"
|
||||||
|
|
||||||
// Contrast is the constant for "contrast" property tag.
|
// Contrast is the constant for "contrast" property tag.
|
||||||
//
|
//
|
||||||
|
@ -40,7 +40,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
Contrast = "contrast"
|
Contrast PropertyName = "contrast"
|
||||||
|
|
||||||
// DropShadow is the constant for "drop-shadow" property tag.
|
// DropShadow is the constant for "drop-shadow" property tag.
|
||||||
//
|
//
|
||||||
|
@ -58,7 +58,7 @@ const (
|
||||||
// `[]ViewShadow` - stored as is, no conversion performed.
|
// `[]ViewShadow` - stored as is, no conversion performed.
|
||||||
// `ViewShadow` - converted to `[]ViewShadow`.
|
// `ViewShadow` - converted to `[]ViewShadow`.
|
||||||
// `string` - string representation of `ViewShadow`. Example: "_{blur = 1em, color = black, spread-radius = 0.5em}".
|
// `string` - string representation of `ViewShadow`. Example: "_{blur = 1em, color = black, spread-radius = 0.5em}".
|
||||||
DropShadow = "drop-shadow"
|
DropShadow PropertyName = "drop-shadow"
|
||||||
|
|
||||||
// Grayscale is the constant for "grayscale" property tag.
|
// Grayscale is the constant for "grayscale" property tag.
|
||||||
//
|
//
|
||||||
|
@ -70,7 +70,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
Grayscale = "grayscale"
|
Grayscale PropertyName = "grayscale"
|
||||||
|
|
||||||
// HueRotate is the constant for "hue-rotate" property tag.
|
// HueRotate is the constant for "hue-rotate" property tag.
|
||||||
//
|
//
|
||||||
|
@ -89,7 +89,7 @@ const (
|
||||||
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
|
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
|
||||||
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
|
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
|
||||||
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
|
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
|
||||||
HueRotate = "hue-rotate"
|
HueRotate PropertyName = "hue-rotate"
|
||||||
|
|
||||||
// Invert is the constant for "invert" property tag.
|
// Invert is the constant for "invert" property tag.
|
||||||
//
|
//
|
||||||
|
@ -101,7 +101,7 @@ const (
|
||||||
// Supported types: `float64`, `int`, `string`.
|
// Supported types: `float64`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
Invert = "invert"
|
Invert PropertyName = "invert"
|
||||||
|
|
||||||
// Saturate is the constant for "saturate" property tag.
|
// Saturate is the constant for "saturate" property tag.
|
||||||
//
|
//
|
||||||
|
@ -113,7 +113,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
Saturate = "saturate"
|
Saturate PropertyName = "saturate"
|
||||||
|
|
||||||
// Sepia is the constant for "sepia" property tag.
|
// Sepia is the constant for "sepia" property tag.
|
||||||
//
|
//
|
||||||
|
@ -125,9 +125,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
Sepia = "sepia"
|
Sepia PropertyName = "sepia"
|
||||||
|
|
||||||
//Opacity = "opacity"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ViewFilter defines an applied to a View a graphical effects like blur or color shift.
|
// ViewFilter defines an applied to a View a graphical effects like blur or color shift.
|
||||||
|
@ -140,21 +138,21 @@ type ViewFilter interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type viewFilter struct {
|
type viewFilter struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewViewFilter creates the new ViewFilter
|
// NewViewFilter creates the new ViewFilter
|
||||||
func NewViewFilter(params Params) ViewFilter {
|
func NewViewFilter(params Params) ViewFilter {
|
||||||
if params != nil {
|
if len(params) > 0 {
|
||||||
filter := new(viewFilter)
|
filter := new(viewFilter)
|
||||||
filter.init()
|
filter.init()
|
||||||
for tag, value := range params {
|
for tag, value := range params {
|
||||||
filter.Set(tag, value)
|
if !filter.Set(tag, value) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(filter.properties) > 0 {
|
|
||||||
return filter
|
return filter
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,10 +164,10 @@ func newViewFilter(obj DataObject) ViewFilter {
|
||||||
tag := node.Tag()
|
tag := node.Tag()
|
||||||
switch node.Type() {
|
switch node.Type() {
|
||||||
case TextNode:
|
case TextNode:
|
||||||
filter.Set(tag, node.Text())
|
filter.Set(PropertyName(tag), node.Text())
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectNode:
|
||||||
if tag == HueRotate {
|
if tag == string(HueRotate) {
|
||||||
// TODO
|
// TODO
|
||||||
} else {
|
} else {
|
||||||
ErrorLog(`Invalid value of "` + tag + `"`)
|
ErrorLog(`Invalid value of "` + tag + `"`)
|
||||||
|
@ -188,28 +186,31 @@ func newViewFilter(obj DataObject) ViewFilter {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (filter *viewFilter) Set(tag string, value any) bool {
|
func (filter *viewFilter) init() {
|
||||||
if value == nil {
|
filter.dataProperty.init()
|
||||||
filter.Remove(tag)
|
filter.set = viewFilterSet
|
||||||
return true
|
filter.supportedProperties = []PropertyName{Blur, Brightness, Contrast, Saturate, Grayscale, Invert, Opacity, Sepia, HueRotate, DropShadow}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch strings.ToLower(tag) {
|
func viewFilterSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
switch tag {
|
||||||
case Blur, Brightness, Contrast, Saturate:
|
case Blur, Brightness, Contrast, Saturate:
|
||||||
return filter.setFloatProperty(tag, value, 0, 10000)
|
return setFloatProperty(properties, tag, value, 0, 10000)
|
||||||
|
|
||||||
case Grayscale, Invert, Opacity, Sepia:
|
case Grayscale, Invert, Opacity, Sepia:
|
||||||
return filter.setFloatProperty(tag, value, 0, 100)
|
return setFloatProperty(properties, tag, value, 0, 100)
|
||||||
|
|
||||||
case HueRotate:
|
case HueRotate:
|
||||||
return filter.setAngleProperty(tag, value)
|
return setAngleProperty(properties, tag, value)
|
||||||
|
|
||||||
case DropShadow:
|
case DropShadow:
|
||||||
return filter.setShadow(tag, value)
|
if setShadowProperty(properties, tag, value) {
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLogF(`"%s" property is not supported by the view filter`, tag)
|
ErrorLogF(`"%s" property is not supported by the view filter`, tag)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (filter *viewFilter) String() string {
|
func (filter *viewFilter) String() string {
|
||||||
|
@ -225,7 +226,7 @@ func (filter *viewFilter) writeString(buffer *strings.Builder, indent string) {
|
||||||
if comma {
|
if comma {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
comma = true
|
comma = true
|
||||||
|
@ -239,18 +240,18 @@ func (filter *viewFilter) cssStyle(session Session) string {
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
if value, ok := floatTextProperty(filter, Blur, session, 0); ok {
|
if value, ok := floatTextProperty(filter, Blur, session, 0); ok {
|
||||||
buffer.WriteString(Blur)
|
buffer.WriteString(string(Blur))
|
||||||
buffer.WriteRune('(')
|
buffer.WriteRune('(')
|
||||||
buffer.WriteString(value)
|
buffer.WriteString(value)
|
||||||
buffer.WriteString("px)")
|
buffer.WriteString("px)")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range []string{Brightness, Contrast, Saturate, Grayscale, Invert, Opacity, Sepia} {
|
for _, tag := range []PropertyName{Brightness, Contrast, Saturate, Grayscale, Invert, Opacity, Sepia} {
|
||||||
if value, ok := floatTextProperty(filter, tag, session, 0); ok {
|
if value, ok := floatTextProperty(filter, tag, session, 0); ok {
|
||||||
if buffer.Len() > 0 {
|
if buffer.Len() > 0 {
|
||||||
buffer.WriteRune(' ')
|
buffer.WriteRune(' ')
|
||||||
}
|
}
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteRune('(')
|
buffer.WriteRune('(')
|
||||||
buffer.WriteString(value)
|
buffer.WriteString(value)
|
||||||
buffer.WriteString("%)")
|
buffer.WriteString("%)")
|
||||||
|
@ -261,7 +262,7 @@ func (filter *viewFilter) cssStyle(session Session) string {
|
||||||
if buffer.Len() > 0 {
|
if buffer.Len() > 0 {
|
||||||
buffer.WriteRune(' ')
|
buffer.WriteRune(' ')
|
||||||
}
|
}
|
||||||
buffer.WriteString(HueRotate)
|
buffer.WriteString(string(HueRotate))
|
||||||
buffer.WriteRune('(')
|
buffer.WriteRune('(')
|
||||||
buffer.WriteString(value.cssString())
|
buffer.WriteString(value.cssString())
|
||||||
buffer.WriteRune(')')
|
buffer.WriteRune(')')
|
||||||
|
@ -284,36 +285,37 @@ func (filter *viewFilter) cssStyle(session Session) string {
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) setFilter(tag string, value any) bool {
|
func setFilterProperty(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case ViewFilter:
|
case ViewFilter:
|
||||||
style.properties[tag] = value
|
properties.setRaw(tag, value)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if obj := NewDataObject(value); obj == nil {
|
if obj := NewDataObject(value); obj == nil {
|
||||||
if filter := newViewFilter(obj); filter != nil {
|
if filter := newViewFilter(obj); filter != nil {
|
||||||
style.properties[tag] = filter
|
properties.setRaw(tag, filter)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
if filter := newViewFilter(value); filter != nil {
|
if filter := newViewFilter(value); filter != nil {
|
||||||
style.properties[tag] = filter
|
properties.setRaw(tag, filter)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
case DataValue:
|
case DataValue:
|
||||||
if value.IsObject() {
|
if value.IsObject() {
|
||||||
if filter := newViewFilter(value.Object()); filter != nil {
|
if filter := newViewFilter(value.Object()); filter != nil {
|
||||||
style.properties[tag] = filter
|
properties.setRaw(tag, filter)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFilter returns a View graphical effects like blur or color shift.
|
// GetFilter returns a View graphical effects like blur or color shift.
|
||||||
|
|
229
viewStyle.go
229
viewStyle.go
|
@ -12,72 +12,31 @@ type ViewStyle interface {
|
||||||
Properties
|
Properties
|
||||||
|
|
||||||
// Transition returns the transition animation of the property. Returns nil is there is no transition animation.
|
// Transition returns the transition animation of the property. Returns nil is there is no transition animation.
|
||||||
Transition(tag string) Animation
|
Transition(tag PropertyName) Animation
|
||||||
|
|
||||||
// Transitions returns the map of transition animations. The result is always non-nil.
|
// Transitions returns the map of transition animations. The result is always non-nil.
|
||||||
Transitions() map[string]Animation
|
Transitions() map[PropertyName]Animation
|
||||||
|
|
||||||
// SetTransition sets the transition animation for the property if "animation" argument is not nil, and
|
// SetTransition sets the transition animation for the property if "animation" argument is not nil, and
|
||||||
// removes the transition animation of the property if "animation" argument is nil.
|
// removes the transition animation of the property if "animation" argument is nil.
|
||||||
// The "tag" argument is the property name.
|
// The "tag" argument is the property name.
|
||||||
SetTransition(tag string, animation Animation)
|
SetTransition(tag PropertyName, animation Animation)
|
||||||
|
|
||||||
cssViewStyle(buffer cssBuilder, session Session)
|
cssViewStyle(buffer cssBuilder, session Session)
|
||||||
}
|
}
|
||||||
|
|
||||||
type viewStyle struct {
|
type viewStyle struct {
|
||||||
propertyList
|
propertyList
|
||||||
transitions map[string]Animation
|
//transitions map[PropertyName]Animation
|
||||||
}
|
|
||||||
|
|
||||||
// Range defines range limits. The First and Last value are included in the range
|
|
||||||
type Range struct {
|
|
||||||
First, Last int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type stringWriter interface {
|
type stringWriter interface {
|
||||||
writeString(buffer *strings.Builder, indent string)
|
writeString(buffer *strings.Builder, indent string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of the Range struct
|
|
||||||
func (r Range) String() string {
|
|
||||||
if r.First == r.Last {
|
|
||||||
return fmt.Sprintf("%d", r.First)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%d:%d", r.First, r.Last)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Range) setValue(value string) bool {
|
|
||||||
var err error
|
|
||||||
if strings.Contains(value, ":") {
|
|
||||||
values := strings.Split(value, ":")
|
|
||||||
if len(values) != 2 {
|
|
||||||
ErrorLog("Invalid range value: " + value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if r.First, err = strconv.Atoi(strings.Trim(values[0], " \t\n\r")); err != nil {
|
|
||||||
ErrorLog(`Invalid first range value "` + value + `" (` + err.Error() + ")")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if r.Last, err = strconv.Atoi(strings.Trim(values[1], " \t\n\r")); err != nil {
|
|
||||||
ErrorLog(`Invalid last range value "` + value + `" (` + err.Error() + ")")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.First, err = strconv.Atoi(value); err != nil {
|
|
||||||
ErrorLog(`Invalid range value "` + value + `" (` + err.Error() + ")")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
r.Last = r.First
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (style *viewStyle) init() {
|
func (style *viewStyle) init() {
|
||||||
style.propertyList.init()
|
style.propertyList.init()
|
||||||
//style.shadows = []ViewShadow{}
|
style.normalize = normalizeViewStyleTag
|
||||||
style.transitions = map[string]Animation{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewViewStyle create new ViewStyle object
|
// NewViewStyle create new ViewStyle object
|
||||||
|
@ -90,19 +49,19 @@ func NewViewStyle(params Params) ViewStyle {
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) cssTextDecoration(session Session) string {
|
func textDecorationCSS(properties Properties, session Session) string {
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
noDecoration := false
|
noDecoration := false
|
||||||
if strikethrough, ok := boolProperty(style, Strikethrough, session); ok {
|
if strikethrough, ok := boolProperty(properties, Strikethrough, session); ok {
|
||||||
if strikethrough {
|
if strikethrough {
|
||||||
buffer.WriteString("line-through")
|
buffer.WriteString("line-through")
|
||||||
}
|
}
|
||||||
noDecoration = true
|
noDecoration = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if overline, ok := boolProperty(style, Overline, session); ok {
|
if overline, ok := boolProperty(properties, Overline, session); ok {
|
||||||
if overline {
|
if overline {
|
||||||
if buffer.Len() > 0 {
|
if buffer.Len() > 0 {
|
||||||
buffer.WriteRune(' ')
|
buffer.WriteRune(' ')
|
||||||
|
@ -112,7 +71,7 @@ func (style *viewStyle) cssTextDecoration(session Session) string {
|
||||||
noDecoration = true
|
noDecoration = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if underline, ok := boolProperty(style, Underline, session); ok {
|
if underline, ok := boolProperty(properties, Underline, session); ok {
|
||||||
if underline {
|
if underline {
|
||||||
if buffer.Len() > 0 {
|
if buffer.Len() > 0 {
|
||||||
buffer.WriteRune(' ')
|
buffer.WriteRune(' ')
|
||||||
|
@ -149,8 +108,8 @@ func split4Values(text string) []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) backgroundCSS(session Session) string {
|
func backgroundCSS(properties Properties, session Session) string {
|
||||||
if value, ok := style.properties[Background]; ok {
|
if value := properties.getRaw(Background); value != nil {
|
||||||
if backgrounds, ok := value.([]BackgroundElement); ok {
|
if backgrounds, ok := value.([]BackgroundElement); ok {
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
@ -184,15 +143,15 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if margin, ok := boundsProperty(style, Margin, session); ok {
|
if margin, ok := getBounds(style, Margin, session); ok {
|
||||||
margin.cssValue(Margin, builder, session)
|
margin.cssValue(Margin, builder, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
if padding, ok := boundsProperty(style, Padding, session); ok {
|
if padding, ok := getBounds(style, Padding, session); ok {
|
||||||
padding.cssValue(Padding, builder, session)
|
padding.cssValue(Padding, builder, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
if border := getBorder(style, Border); border != nil {
|
if border := getBorderProperty(style, Border); border != nil {
|
||||||
border.cssStyle(builder, session)
|
border.cssStyle(builder, session)
|
||||||
border.cssWidth(builder, session)
|
border.cssWidth(builder, session)
|
||||||
border.cssColor(builder, session)
|
border.cssColor(builder, session)
|
||||||
|
@ -201,27 +160,27 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
radius := getRadius(style, session)
|
radius := getRadius(style, session)
|
||||||
radius.cssValue(builder, session)
|
radius.cssValue(builder, session)
|
||||||
|
|
||||||
if outline := getOutline(style); outline != nil {
|
if outline := getOutlineProperty(style); outline != nil {
|
||||||
outline.ViewOutline(session).cssValue(builder, session)
|
outline.ViewOutline(session).cssValue(builder, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range []string{ZIndex, Order} {
|
for _, tag := range []PropertyName{ZIndex, Order} {
|
||||||
if value, ok := intProperty(style, tag, session, 0); ok {
|
if value, ok := intProperty(style, tag, session, 0); ok {
|
||||||
builder.add(tag, strconv.Itoa(value))
|
builder.add(string(tag), strconv.Itoa(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opacity, ok := floatProperty(style, Opacity, session, 1.0); ok && opacity >= 0 && opacity <= 1 {
|
if opacity, ok := floatProperty(style, Opacity, session, 1.0); ok && opacity >= 0 && opacity <= 1 {
|
||||||
builder.add(Opacity, strconv.FormatFloat(opacity, 'f', 3, 32))
|
builder.add(string(Opacity), strconv.FormatFloat(opacity, 'f', 3, 32))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range []string{ColumnCount, TabSize} {
|
for _, tag := range []PropertyName{ColumnCount, TabSize} {
|
||||||
if value, ok := intProperty(style, tag, session, 0); ok && value > 0 {
|
if value, ok := intProperty(style, tag, session, 0); ok && value > 0 {
|
||||||
builder.add(tag, strconv.Itoa(value))
|
builder.add(string(tag), strconv.Itoa(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range []string{
|
for _, tag := range []PropertyName{
|
||||||
Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight, Left, Right, Top, Bottom,
|
Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight, Left, Right, Top, Bottom,
|
||||||
TextSize, TextIndent, LetterSpacing, WordSpacing, LineHeight, TextLineThickness,
|
TextSize, TextIndent, LetterSpacing, WordSpacing, LineHeight, TextLineThickness,
|
||||||
ListRowGap, ListColumnGap, GridRowGap, GridColumnGap, ColumnGap, ColumnWidth, OutlineOffset} {
|
ListRowGap, ListColumnGap, GridRowGap, GridColumnGap, ColumnGap, ColumnWidth, OutlineOffset} {
|
||||||
|
@ -229,18 +188,22 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
if size, ok := sizeProperty(style, tag, session); ok && size.Type != Auto {
|
if size, ok := sizeProperty(style, tag, session); ok && size.Type != Auto {
|
||||||
cssTag, ok := sizeProperties[tag]
|
cssTag, ok := sizeProperties[tag]
|
||||||
if !ok {
|
if !ok {
|
||||||
cssTag = tag
|
cssTag = string(tag)
|
||||||
}
|
}
|
||||||
builder.add(cssTag, size.cssString("", session))
|
builder.add(cssTag, size.cssString("", session))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
colorProperties := []struct{ property, cssTag string }{
|
type propertyCss struct {
|
||||||
{BackgroundColor, BackgroundColor},
|
property PropertyName
|
||||||
|
cssTag string
|
||||||
|
}
|
||||||
|
colorProperties := []propertyCss{
|
||||||
|
{BackgroundColor, string(BackgroundColor)},
|
||||||
{TextColor, "color"},
|
{TextColor, "color"},
|
||||||
{TextLineColor, "text-decoration-color"},
|
{TextLineColor, "text-decoration-color"},
|
||||||
{CaretColor, CaretColor},
|
{CaretColor, string(CaretColor)},
|
||||||
{AccentColor, AccentColor},
|
{AccentColor, string(AccentColor)},
|
||||||
}
|
}
|
||||||
for _, p := range colorProperties {
|
for _, p := range colorProperties {
|
||||||
if color, ok := colorProperty(style, p.property, session); ok && color != 0 {
|
if color, ok := colorProperty(style, p.property, session); ok && color != 0 {
|
||||||
|
@ -249,10 +212,10 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := enumProperty(style, BackgroundClip, session, 0); ok {
|
if value, ok := enumProperty(style, BackgroundClip, session, 0); ok {
|
||||||
builder.add(BackgroundClip, enumProperties[BackgroundClip].values[value])
|
builder.add(string(BackgroundClip), enumProperties[BackgroundClip].values[value])
|
||||||
}
|
}
|
||||||
|
|
||||||
if background := style.backgroundCSS(session); background != "" {
|
if background := backgroundCSS(style, session); background != "" {
|
||||||
builder.add("background", background)
|
builder.add("background", background)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +224,7 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
}
|
}
|
||||||
|
|
||||||
writingMode := 0
|
writingMode := 0
|
||||||
for _, tag := range []string{
|
for _, tag := range []PropertyName{
|
||||||
Overflow, TextAlign, TextTransform, TextWeight, TextLineStyle, WritingMode, TextDirection,
|
Overflow, TextAlign, TextTransform, TextWeight, TextLineStyle, WritingMode, TextDirection,
|
||||||
VerticalTextOrientation, CellVerticalAlign, CellHorizontalAlign, GridAutoFlow, Cursor,
|
VerticalTextOrientation, CellVerticalAlign, CellHorizontalAlign, GridAutoFlow, Cursor,
|
||||||
WhiteSpace, WordBreak, TextOverflow, Float, TableVerticalAlign, Resize, MixBlendMode, BackgroundBlendMode} {
|
WhiteSpace, WordBreak, TextOverflow, Float, TableVerticalAlign, Resize, MixBlendMode, BackgroundBlendMode} {
|
||||||
|
@ -282,7 +245,11 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, prop := range []struct{ tag, cssTag, off, on string }{
|
type boolPropertyCss struct {
|
||||||
|
tag PropertyName
|
||||||
|
cssTag, off, on string
|
||||||
|
}
|
||||||
|
for _, prop := range []boolPropertyCss{
|
||||||
{tag: Italic, cssTag: "font-style", off: "normal", on: "italic"},
|
{tag: Italic, cssTag: "font-style", off: "normal", on: "italic"},
|
||||||
{tag: SmallCaps, cssTag: "font-variant", off: "normal", on: "small-caps"},
|
{tag: SmallCaps, cssTag: "font-variant", off: "normal", on: "small-caps"},
|
||||||
} {
|
} {
|
||||||
|
@ -295,7 +262,7 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if text := style.cssTextDecoration(session); text != "" {
|
if text := textDecorationCSS(style, session); text != "" {
|
||||||
builder.add("text-decoration", text)
|
builder.add("text-decoration", text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,10 +383,10 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
if r, ok := rangeProperty(style, Column, session); ok {
|
if r, ok := rangeProperty(style, Column, session); ok {
|
||||||
builder.add("grid-column", fmt.Sprintf("%d / %d", r.First+1, r.Last+2))
|
builder.add("grid-column", fmt.Sprintf("%d / %d", r.First+1, r.Last+2))
|
||||||
}
|
}
|
||||||
if text := style.gridCellSizesCSS(CellWidth, session); text != "" {
|
if text := gridCellSizesCSS(style, CellWidth, session); text != "" {
|
||||||
builder.add(`grid-template-columns`, text)
|
builder.add(`grid-template-columns`, text)
|
||||||
}
|
}
|
||||||
if text := style.gridCellSizesCSS(CellHeight, session); text != "" {
|
if text := gridCellSizesCSS(style, CellHeight, session); text != "" {
|
||||||
builder.add(`grid-template-rows`, text)
|
builder.add(`grid-template-rows`, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,7 +403,7 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
if value := style.getRaw(Filter); value != nil {
|
if value := style.getRaw(Filter); value != nil {
|
||||||
if filter, ok := value.(ViewFilter); ok {
|
if filter, ok := value.(ViewFilter); ok {
|
||||||
if text := filter.cssStyle(session); text != "" {
|
if text := filter.cssStyle(session); text != "" {
|
||||||
builder.add(Filter, text)
|
builder.add(string(Filter), text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -445,17 +412,17 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||||
if filter, ok := value.(ViewFilter); ok {
|
if filter, ok := value.(ViewFilter); ok {
|
||||||
if text := filter.cssStyle(session); text != "" {
|
if text := filter.cssStyle(session); text != "" {
|
||||||
builder.add(`-webkit-backdrop-filter`, text)
|
builder.add(`-webkit-backdrop-filter`, text)
|
||||||
builder.add(BackdropFilter, text)
|
builder.add(string(BackdropFilter), text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if transition := style.transitionCSS(session); transition != "" {
|
if transition := transitionCSS(style, session); transition != "" {
|
||||||
builder.add(`transition`, transition)
|
builder.add(`transition`, transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
if animation := style.animationCSS(session); animation != "" {
|
if animation := animationCSS(style, session); animation != "" {
|
||||||
builder.add(AnimationTag, animation)
|
builder.add(string(AnimationTag), animation)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pause, ok := boolProperty(style, AnimationPaused, session); ok {
|
if pause, ok := boolProperty(style, AnimationPaused, session); ok {
|
||||||
|
@ -504,20 +471,48 @@ func valueToOrientation(value any, session Session) (int, bool) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) Get(tag string) any {
|
func normalizeViewStyleTag(tag PropertyName) PropertyName {
|
||||||
return style.get(strings.ToLower(tag))
|
tag = defaultNormalize(tag)
|
||||||
|
switch tag {
|
||||||
|
case "top-margin":
|
||||||
|
return MarginTop
|
||||||
|
|
||||||
|
case "right-margin":
|
||||||
|
return MarginRight
|
||||||
|
|
||||||
|
case "bottom-margin":
|
||||||
|
return MarginBottom
|
||||||
|
|
||||||
|
case "left-margin":
|
||||||
|
return MarginLeft
|
||||||
|
|
||||||
|
case "top-padding":
|
||||||
|
return PaddingTop
|
||||||
|
|
||||||
|
case "right-padding":
|
||||||
|
return PaddingRight
|
||||||
|
|
||||||
|
case "bottom-padding":
|
||||||
|
return PaddingBottom
|
||||||
|
|
||||||
|
case "left-padding":
|
||||||
|
return PaddingLeft
|
||||||
|
}
|
||||||
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) get(tag string) any {
|
func (style *viewStyle) Get(tag PropertyName) any {
|
||||||
|
return viewStyleGet(style, normalizeViewStyleTag(tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
func viewStyleGet(style Properties, tag PropertyName) any {
|
||||||
switch tag {
|
switch tag {
|
||||||
case Border, CellBorder:
|
|
||||||
return getBorder(&style.propertyList, tag)
|
|
||||||
|
|
||||||
case BorderLeft, BorderRight, BorderTop, BorderBottom,
|
case BorderLeft, BorderRight, BorderTop, BorderBottom,
|
||||||
BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle,
|
BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle,
|
||||||
BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor,
|
BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor,
|
||||||
BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
|
BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
|
||||||
if border := getBorder(style, Border); border != nil {
|
if border := getBorderProperty(style, Border); border != nil {
|
||||||
return border.Get(tag)
|
return border.Get(tag)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -526,7 +521,7 @@ func (style *viewStyle) get(tag string) any {
|
||||||
CellBorderStyle, CellBorderLeftStyle, CellBorderRightStyle, CellBorderTopStyle, CellBorderBottomStyle,
|
CellBorderStyle, CellBorderLeftStyle, CellBorderRightStyle, CellBorderTopStyle, CellBorderBottomStyle,
|
||||||
CellBorderColor, CellBorderLeftColor, CellBorderRightColor, CellBorderTopColor, CellBorderBottomColor,
|
CellBorderColor, CellBorderLeftColor, CellBorderRightColor, CellBorderTopColor, CellBorderBottomColor,
|
||||||
CellBorderWidth, CellBorderLeftWidth, CellBorderRightWidth, CellBorderTopWidth, CellBorderBottomWidth:
|
CellBorderWidth, CellBorderLeftWidth, CellBorderRightWidth, CellBorderTopWidth, CellBorderBottomWidth:
|
||||||
if border := getBorder(style, CellBorder); border != nil {
|
if border := getBorderProperty(style, CellBorder); border != nil {
|
||||||
return border.Get(tag)
|
return border.Get(tag)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -537,46 +532,22 @@ func (style *viewStyle) get(tag string) any {
|
||||||
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
||||||
return getRadiusElement(style, tag)
|
return getRadiusElement(style, tag)
|
||||||
|
|
||||||
case ColumnSeparator:
|
|
||||||
if val, ok := style.properties[ColumnSeparator]; ok {
|
|
||||||
return val.(ColumnSeparatorProperty)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
|
|
||||||
case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor:
|
case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor:
|
||||||
if val, ok := style.properties[ColumnSeparator]; ok {
|
if val := style.getRaw(ColumnSeparator); val != nil {
|
||||||
separator := val.(ColumnSeparatorProperty)
|
separator := val.(ColumnSeparatorProperty)
|
||||||
return separator.Get(tag)
|
return separator.Get(tag)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case Transition:
|
|
||||||
if len(style.transitions) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result := map[string]Animation{}
|
|
||||||
for tag, animation := range style.transitions {
|
|
||||||
result[tag] = animation
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
|
|
||||||
case RotateX, RotateY, RotateZ, Rotate, SkewX, SkewY, ScaleX, ScaleY, ScaleZ,
|
case RotateX, RotateY, RotateZ, Rotate, SkewX, SkewY, ScaleX, ScaleY, ScaleZ,
|
||||||
TranslateX, TranslateY, TranslateZ:
|
TranslateX, TranslateY, TranslateZ:
|
||||||
if transform := style.transformProperty(); transform != nil {
|
if transform := getTransformProperty(style); transform != nil {
|
||||||
return transform.Get(tag)
|
return transform.Get(tag)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return style.propertyList.getRaw(tag)
|
return style.getRaw(tag)
|
||||||
}
|
|
||||||
|
|
||||||
func (style *viewStyle) AllTags() []string {
|
|
||||||
result := style.propertyList.AllTags()
|
|
||||||
if len(style.transitions) > 0 {
|
|
||||||
result = append(result, Transition)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func supportedPropertyValue(value any) bool {
|
func supportedPropertyValue(value any) bool {
|
||||||
|
@ -595,14 +566,14 @@ func supportedPropertyValue(value any) bool {
|
||||||
case []BackgroundElement:
|
case []BackgroundElement:
|
||||||
case []BackgroundGradientPoint:
|
case []BackgroundGradientPoint:
|
||||||
case []BackgroundGradientAngle:
|
case []BackgroundGradientAngle:
|
||||||
case map[string]Animation:
|
case map[PropertyName]Animation:
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func writePropertyValue(buffer *strings.Builder, tag string, value any, indent string) {
|
func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, indent string) {
|
||||||
|
|
||||||
writeString := func(text string) {
|
writeString := func(text string) {
|
||||||
simple := (tag != Text && tag != Title && tag != Summary)
|
simple := (tag != Text && tag != Title && tag != Summary)
|
||||||
|
@ -804,7 +775,7 @@ func writePropertyValue(buffer *strings.Builder, tag string, value any, indent s
|
||||||
}
|
}
|
||||||
buffer.WriteRune('"')
|
buffer.WriteRune('"')
|
||||||
|
|
||||||
case map[string]Animation:
|
case map[PropertyName]Animation:
|
||||||
switch count := len(value); count {
|
switch count := len(value); count {
|
||||||
case 0:
|
case 0:
|
||||||
buffer.WriteString("[]")
|
buffer.WriteString("[]")
|
||||||
|
@ -816,11 +787,13 @@ func writePropertyValue(buffer *strings.Builder, tag string, value any, indent s
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
tags := make([]string, 0, len(value))
|
tags := make([]PropertyName, 0, len(value))
|
||||||
for tag := range value {
|
for tag := range value {
|
||||||
tags = append(tags, tag)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
sort.Strings(tags)
|
sort.Slice(tags, func(i, j int) bool {
|
||||||
|
return tags[i] < tags[j]
|
||||||
|
})
|
||||||
buffer.WriteString("[\n")
|
buffer.WriteString("[\n")
|
||||||
indent2 := indent + "\t"
|
indent2 := indent + "\t"
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
|
@ -836,12 +809,12 @@ func writePropertyValue(buffer *strings.Builder, tag string, value any, indent s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeViewStyle(name string, view ViewStyle, buffer *strings.Builder, indent string, excludeTags []string) {
|
func writeViewStyle(name string, view Properties, buffer *strings.Builder, indent string, excludeTags []PropertyName) {
|
||||||
buffer.WriteString(name)
|
buffer.WriteString(name)
|
||||||
buffer.WriteString(" {\n")
|
buffer.WriteString(" {\n")
|
||||||
indent += "\t"
|
indent += "\t"
|
||||||
|
|
||||||
writeProperty := func(tag string, value any) {
|
writeProperty := func(tag PropertyName, value any) {
|
||||||
for _, exclude := range excludeTags {
|
for _, exclude := range excludeTags {
|
||||||
if exclude == tag {
|
if exclude == tag {
|
||||||
return
|
return
|
||||||
|
@ -850,7 +823,7 @@ func writeViewStyle(name string, view ViewStyle, buffer *strings.Builder, indent
|
||||||
|
|
||||||
if supportedPropertyValue(value) {
|
if supportedPropertyValue(value) {
|
||||||
buffer.WriteString(indent)
|
buffer.WriteString(indent)
|
||||||
buffer.WriteString(tag)
|
buffer.WriteString(string(tag))
|
||||||
buffer.WriteString(" = ")
|
buffer.WriteString(" = ")
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
buffer.WriteString(",\n")
|
buffer.WriteString(",\n")
|
||||||
|
@ -858,7 +831,7 @@ func writeViewStyle(name string, view ViewStyle, buffer *strings.Builder, indent
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := view.AllTags()
|
tags := view.AllTags()
|
||||||
removeTag := func(tag string) {
|
removeTag := func(tag PropertyName) {
|
||||||
for i, t := range tags {
|
for i, t := range tags {
|
||||||
if t == tag {
|
if t == tag {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
@ -873,7 +846,7 @@ func writeViewStyle(name string, view ViewStyle, buffer *strings.Builder, indent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tagOrder := []string{
|
tagOrder := []PropertyName{
|
||||||
ID, Row, Column, Top, Right, Bottom, Left, Semantics, Cursor, Visibility,
|
ID, Row, Column, Top, Right, Bottom, Left, Semantics, Cursor, Visibility,
|
||||||
Opacity, ZIndex, Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight,
|
Opacity, ZIndex, Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight,
|
||||||
Margin, Padding, BackgroundClip, BackgroundColor, Background, Border, Radius, Outline, Shadow,
|
Margin, Padding, BackgroundClip, BackgroundColor, Background, Border, Radius, Outline, Shadow,
|
||||||
|
@ -894,7 +867,7 @@ func writeViewStyle(name string, view ViewStyle, buffer *strings.Builder, indent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finalTags := []string{
|
finalTags := []PropertyName{
|
||||||
Perspective, PerspectiveOriginX, PerspectiveOriginY, BackfaceVisible, OriginX, OriginY, OriginZ,
|
Perspective, PerspectiveOriginX, PerspectiveOriginY, BackfaceVisible, OriginX, OriginY, OriginZ,
|
||||||
TransformTag, Clip, Filter, BackdropFilter, Summary, Content, Transition}
|
TransformTag, Clip, Filter, BackdropFilter, Summary, Content, Transition}
|
||||||
for _, tag := range finalTags {
|
for _, tag := range finalTags {
|
||||||
|
@ -918,14 +891,6 @@ func writeViewStyle(name string, view ViewStyle, buffer *strings.Builder, indent
|
||||||
buffer.WriteString("}")
|
buffer.WriteString("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getViewString(view View, excludeTags []string) string {
|
|
||||||
buffer := allocStringBuilder()
|
|
||||||
defer freeStringBuilder(buffer)
|
|
||||||
writeViewStyle(view.Tag(), view, buffer, "", excludeTags)
|
|
||||||
return buffer.String()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func runStringWriter(writer stringWriter) string {
|
func runStringWriter(writer stringWriter) string {
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
471
viewStyleSet.go
471
viewStyleSet.go
|
@ -4,87 +4,94 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (style *viewStyle) setRange(tag string, value any) bool {
|
func setTransitionProperty(properties Properties, value any) bool {
|
||||||
switch value := value.(type) {
|
|
||||||
case string:
|
|
||||||
if strings.Contains(value, "@") {
|
|
||||||
style.properties[tag] = value
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
var r Range
|
|
||||||
if !r.setValue(value) {
|
|
||||||
invalidPropertyValue(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
style.properties[tag] = r
|
|
||||||
|
|
||||||
case int:
|
transitions := map[PropertyName]Animation{}
|
||||||
style.properties[tag] = Range{First: value, Last: value}
|
|
||||||
|
|
||||||
case Range:
|
|
||||||
style.properties[tag] = value
|
|
||||||
|
|
||||||
default:
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (style *viewStyle) setBackground(value any) bool {
|
|
||||||
background := []BackgroundElement{}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case BackgroundElement:
|
|
||||||
background = []BackgroundElement{value}
|
|
||||||
|
|
||||||
case []BackgroundElement:
|
|
||||||
background = value
|
|
||||||
|
|
||||||
case []DataValue:
|
|
||||||
for _, el := range value {
|
|
||||||
if el.IsObject() {
|
|
||||||
if element := createBackground(el.Object()); element != nil {
|
|
||||||
background = append(background, element)
|
|
||||||
}
|
|
||||||
} else if obj := ParseDataText(el.Value()); obj != nil {
|
|
||||||
if element := createBackground(obj); element != nil {
|
|
||||||
background = append(background, element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataObject:
|
|
||||||
if element := createBackground(value); element != nil {
|
|
||||||
background = []BackgroundElement{element}
|
|
||||||
}
|
|
||||||
|
|
||||||
case []DataObject:
|
|
||||||
for _, obj := range value {
|
|
||||||
if element := createBackground(obj); element != nil {
|
|
||||||
background = append(background, element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case string:
|
|
||||||
if obj := ParseDataText(value); obj != nil {
|
|
||||||
if element := createBackground(obj); element != nil {
|
|
||||||
background = []BackgroundElement{element}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(background) > 0 {
|
|
||||||
style.properties[Background] = background
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (style *viewStyle) setTransition(tag string, value any) bool {
|
|
||||||
setObject := func(obj DataObject) bool {
|
setObject := func(obj DataObject) bool {
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
tag := strings.ToLower(tag)
|
tag := strings.ToLower(obj.Tag())
|
||||||
|
switch tag {
|
||||||
|
case "", "_":
|
||||||
|
ErrorLog("Invalid transition property name")
|
||||||
|
|
||||||
|
default:
|
||||||
|
transitions[PropertyName(tag)] = parseAnimation(obj)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case Params:
|
||||||
|
for tag, val := range value {
|
||||||
|
tag = defaultNormalize(tag)
|
||||||
|
if tag == "" {
|
||||||
|
ErrorLog("Invalid transition property name")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if val != nil {
|
||||||
|
if animation, ok := val.(Animation); ok {
|
||||||
|
transitions[PropertyName(tag)] = animation
|
||||||
|
} else {
|
||||||
|
notCompatibleType(Transition, val)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(transitions) == 0 {
|
||||||
|
transitions = nil
|
||||||
|
}
|
||||||
|
properties.setRaw(Transition, transitions)
|
||||||
|
return true
|
||||||
|
|
||||||
|
case DataObject:
|
||||||
|
if setObject(value) {
|
||||||
|
properties.setRaw(Transition, transitions)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
|
||||||
|
case DataNode:
|
||||||
|
switch value.Type() {
|
||||||
|
case ObjectNode:
|
||||||
|
if setObject(value.Object()) {
|
||||||
|
properties.setRaw(Transition, transitions)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
|
||||||
|
case ArrayNode:
|
||||||
|
for i := 0; i < value.ArraySize(); i++ {
|
||||||
|
if obj := value.ArrayElement(i).Object(); obj != nil {
|
||||||
|
if !setObject(obj) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notCompatibleType(Transition, value.ArrayElement(i))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(transitions) == 0 {
|
||||||
|
transitions = nil
|
||||||
|
}
|
||||||
|
properties.setRaw(Transition, transitions)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notCompatibleType(Transition, value)
|
||||||
|
return false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (style *viewStyle) setTransition(tag PropertyName, value any) bool {
|
||||||
|
setObject := func(obj DataObject) bool {
|
||||||
|
if obj != nil {
|
||||||
|
tag := defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case "", "_":
|
case "", "_":
|
||||||
ErrorLog("Invalid transition property name")
|
ErrorLog("Invalid transition property name")
|
||||||
|
@ -101,7 +108,7 @@ func (style *viewStyle) setTransition(tag string, value any) bool {
|
||||||
case Params:
|
case Params:
|
||||||
result := true
|
result := true
|
||||||
for tag, val := range value {
|
for tag, val := range value {
|
||||||
tag = strings.ToLower(strings.Trim(tag, " \t"))
|
tag = defaultNormalize(tag)
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
ErrorLog("Invalid transition property name")
|
ErrorLog("Invalid transition property name")
|
||||||
result = false
|
result = false
|
||||||
|
@ -141,69 +148,17 @@ func (style *viewStyle) setTransition(tag string, value any) bool {
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (style *viewStyle) setAnimation(tag string, value any) bool {
|
func viewStyleRemove(properties Properties, tag PropertyName) []PropertyName {
|
||||||
|
|
||||||
set := func(animations []Animation) {
|
|
||||||
style.properties[tag] = animations
|
|
||||||
for _, animation := range animations {
|
|
||||||
animation.used()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case Animation:
|
|
||||||
set([]Animation{value})
|
|
||||||
return true
|
|
||||||
|
|
||||||
case []Animation:
|
|
||||||
set(value)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case DataObject:
|
|
||||||
if animation := parseAnimation(value); animation.hasAnimatedProperty() {
|
|
||||||
set([]Animation{animation})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
case DataNode:
|
|
||||||
animations := []Animation{}
|
|
||||||
result := true
|
|
||||||
for i := 0; i < value.ArraySize(); i++ {
|
|
||||||
if obj := value.ArrayElement(i).Object(); obj != nil {
|
|
||||||
if anim := parseAnimation(obj); anim.hasAnimatedProperty() {
|
|
||||||
animations = append(animations, anim)
|
|
||||||
} else {
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
notCompatibleType(tag, value.ArrayElement(i))
|
|
||||||
result = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if result && len(animations) > 0 {
|
|
||||||
set(animations)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (style *viewStyle) Remove(tag string) {
|
|
||||||
style.remove(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (style *viewStyle) remove(tag string) {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case BorderStyle, BorderColor, BorderWidth,
|
case BorderStyle, BorderColor, BorderWidth,
|
||||||
BorderLeft, BorderLeftStyle, BorderLeftColor, BorderLeftWidth,
|
BorderLeft, BorderLeftStyle, BorderLeftColor, BorderLeftWidth,
|
||||||
BorderRight, BorderRightStyle, BorderRightColor, BorderRightWidth,
|
BorderRight, BorderRightStyle, BorderRightColor, BorderRightWidth,
|
||||||
BorderTop, BorderTopStyle, BorderTopColor, BorderTopWidth,
|
BorderTop, BorderTopStyle, BorderTopColor, BorderTopWidth,
|
||||||
BorderBottom, BorderBottomStyle, BorderBottomColor, BorderBottomWidth:
|
BorderBottom, BorderBottomStyle, BorderBottomColor, BorderBottomWidth:
|
||||||
if border := getBorder(style, Border); border != nil {
|
if border := getBorderProperty(properties, Border); border != nil && border.deleteTag(tag) {
|
||||||
border.delete(tag)
|
return []PropertyName{Border}
|
||||||
}
|
}
|
||||||
|
|
||||||
case CellBorderStyle, CellBorderColor, CellBorderWidth,
|
case CellBorderStyle, CellBorderColor, CellBorderWidth,
|
||||||
|
@ -211,58 +166,59 @@ func (style *viewStyle) remove(tag string) {
|
||||||
CellBorderRight, CellBorderRightStyle, CellBorderRightColor, CellBorderRightWidth,
|
CellBorderRight, CellBorderRightStyle, CellBorderRightColor, CellBorderRightWidth,
|
||||||
CellBorderTop, CellBorderTopStyle, CellBorderTopColor, CellBorderTopWidth,
|
CellBorderTop, CellBorderTopStyle, CellBorderTopColor, CellBorderTopWidth,
|
||||||
CellBorderBottom, CellBorderBottomStyle, CellBorderBottomColor, CellBorderBottomWidth:
|
CellBorderBottom, CellBorderBottomStyle, CellBorderBottomColor, CellBorderBottomWidth:
|
||||||
if border := getBorder(style, CellBorder); border != nil {
|
if border := getBorderProperty(properties, CellBorder); border != nil && border.deleteTag(tag) {
|
||||||
border.delete(tag)
|
return []PropertyName{CellBorder}
|
||||||
}
|
}
|
||||||
|
|
||||||
case MarginTop, MarginRight, MarginBottom, MarginLeft,
|
case MarginTop, MarginRight, MarginBottom, MarginLeft:
|
||||||
"top-margin", "right-margin", "bottom-margin", "left-margin":
|
return removeBoundsPropertySide(properties, Margin, tag)
|
||||||
style.removeBoundsSide(Margin, tag)
|
|
||||||
|
|
||||||
case PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
|
case PaddingTop, PaddingRight, PaddingBottom, PaddingLeft:
|
||||||
"top-padding", "right-padding", "bottom-padding", "left-padding":
|
return removeBoundsPropertySide(properties, Padding, tag)
|
||||||
style.removeBoundsSide(Padding, tag)
|
|
||||||
|
|
||||||
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
|
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
|
||||||
style.removeBoundsSide(CellPadding, tag)
|
return removeBoundsPropertySide(properties, CellPadding, tag)
|
||||||
|
|
||||||
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
||||||
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
||||||
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
||||||
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
||||||
style.removeRadiusElement(tag)
|
if removeRadiusPropertyElement(properties, tag) {
|
||||||
|
return []PropertyName{Radius, tag}
|
||||||
|
}
|
||||||
|
|
||||||
case OutlineStyle, OutlineWidth, OutlineColor:
|
case OutlineStyle, OutlineWidth, OutlineColor:
|
||||||
if outline := getOutline(style); outline != nil {
|
if outline := getOutlineProperty(properties); outline != nil {
|
||||||
outline.Remove(tag)
|
outline.Remove(tag)
|
||||||
|
if outline.empty() {
|
||||||
|
properties.setRaw(Outline, nil)
|
||||||
|
}
|
||||||
|
return []PropertyName{Outline, tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
style.propertyList.remove(tag)
|
return propertiesRemove(properties, tag)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) Set(tag string, value any) bool {
|
return []PropertyName{}
|
||||||
return style.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (style *viewStyle) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
style.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func viewStyleSet(style Properties, tag PropertyName, value any) []PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case Shadow, TextShadow:
|
case Shadow, TextShadow:
|
||||||
return style.setShadow(tag, value)
|
if setShadowProperty(style, tag, value) {
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
|
||||||
case Background:
|
case Background:
|
||||||
return style.setBackground(value)
|
return setBackgroundProperty(style, value)
|
||||||
|
|
||||||
case Border, CellBorder:
|
case Border, CellBorder:
|
||||||
if border := newBorderProperty(value); border != nil {
|
if border := newBorderProperty(value); border != nil {
|
||||||
style.properties[tag] = border
|
style.setRaw(tag, border)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case BorderStyle, BorderColor, BorderWidth,
|
case BorderStyle, BorderColor, BorderWidth,
|
||||||
|
@ -271,16 +227,7 @@ func (style *viewStyle) set(tag string, value any) bool {
|
||||||
BorderTop, BorderTopStyle, BorderTopColor, BorderTopWidth,
|
BorderTop, BorderTopStyle, BorderTopColor, BorderTopWidth,
|
||||||
BorderBottom, BorderBottomStyle, BorderBottomColor, BorderBottomWidth:
|
BorderBottom, BorderBottomStyle, BorderBottomColor, BorderBottomWidth:
|
||||||
|
|
||||||
border := getBorder(style, Border)
|
return setBorderPropertyElement(style, Border, tag, value)
|
||||||
if border == nil {
|
|
||||||
border = NewBorder(nil)
|
|
||||||
if border.Set(tag, value) {
|
|
||||||
style.properties[Border] = border
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return border.Set(tag, value)
|
|
||||||
|
|
||||||
case CellBorderStyle, CellBorderColor, CellBorderWidth,
|
case CellBorderStyle, CellBorderColor, CellBorderWidth,
|
||||||
CellBorderLeft, CellBorderLeftStyle, CellBorderLeftColor, CellBorderLeftWidth,
|
CellBorderLeft, CellBorderLeftStyle, CellBorderLeftColor, CellBorderLeftWidth,
|
||||||
|
@ -288,173 +235,211 @@ func (style *viewStyle) set(tag string, value any) bool {
|
||||||
CellBorderTop, CellBorderTopStyle, CellBorderTopColor, CellBorderTopWidth,
|
CellBorderTop, CellBorderTopStyle, CellBorderTopColor, CellBorderTopWidth,
|
||||||
CellBorderBottom, CellBorderBottomStyle, CellBorderBottomColor, CellBorderBottomWidth:
|
CellBorderBottom, CellBorderBottomStyle, CellBorderBottomColor, CellBorderBottomWidth:
|
||||||
|
|
||||||
border := getBorder(style, CellBorder)
|
return setBorderPropertyElement(style, CellBorder, tag, value)
|
||||||
if border == nil {
|
|
||||||
border = NewBorder(nil)
|
|
||||||
if border.Set(tag, value) {
|
|
||||||
style.properties[CellBorder] = border
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return border.Set(tag, value)
|
|
||||||
|
|
||||||
case Radius:
|
case Radius:
|
||||||
return style.setRadius(value)
|
return setRadiusProperty(style, value)
|
||||||
|
|
||||||
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
|
||||||
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
||||||
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
||||||
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
||||||
return style.setRadiusElement(tag, value)
|
if setRadiusPropertyElement(style, tag, value) {
|
||||||
|
return []PropertyName{Radius, tag}
|
||||||
|
}
|
||||||
|
|
||||||
case Margin, Padding, CellPadding:
|
case Margin, Padding, CellPadding:
|
||||||
return style.setBounds(tag, value)
|
return setBoundsProperty(style, tag, value)
|
||||||
|
|
||||||
case MarginTop, MarginRight, MarginBottom, MarginLeft,
|
case MarginTop, MarginRight, MarginBottom, MarginLeft:
|
||||||
"top-margin", "right-margin", "bottom-margin", "left-margin":
|
return setBoundsPropertySide(style, Margin, tag, value)
|
||||||
return style.setBoundsSide(Margin, tag, value)
|
|
||||||
|
|
||||||
case PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
|
case PaddingTop, PaddingRight, PaddingBottom, PaddingLeft:
|
||||||
"top-padding", "right-padding", "bottom-padding", "left-padding":
|
return setBoundsPropertySide(style, Padding, tag, value)
|
||||||
return style.setBoundsSide(Padding, tag, value)
|
|
||||||
|
|
||||||
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
|
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
|
||||||
return style.setBoundsSide(CellPadding, tag, value)
|
return setBoundsPropertySide(style, CellPadding, tag, value)
|
||||||
|
|
||||||
case HeadStyle, FootStyle:
|
case HeadStyle, FootStyle:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
style.properties[tag] = value
|
style.setRaw(tag, value)
|
||||||
return true
|
|
||||||
|
|
||||||
case Params:
|
case Params:
|
||||||
style.properties[tag] = value
|
style.setRaw(tag, value)
|
||||||
return true
|
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
if params := value.ToParams(); len(params) > 0 {
|
if params := value.ToParams(); len(params) > 0 {
|
||||||
style.properties[tag] = params
|
style.setRaw(tag, params)
|
||||||
|
} else {
|
||||||
|
style.setRaw(tag, nil)
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
|
default:
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case CellStyle, ColumnStyle, RowStyle:
|
case CellStyle, ColumnStyle, RowStyle:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
style.properties[tag] = value
|
style.setRaw(tag, value)
|
||||||
return true
|
|
||||||
|
|
||||||
case Params:
|
case Params:
|
||||||
style.properties[tag] = value
|
style.setRaw(tag, value)
|
||||||
return true
|
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
if params := value.ToParams(); len(params) > 0 {
|
if params := value.ToParams(); len(params) > 0 {
|
||||||
style.properties[tag] = params
|
style.setRaw(tag, params)
|
||||||
|
} else {
|
||||||
|
style.setRaw(tag, nil)
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
|
|
||||||
case DataNode:
|
case DataNode:
|
||||||
switch value.Type() {
|
switch value.Type() {
|
||||||
case TextNode:
|
case TextNode:
|
||||||
if text := value.Text(); text != "" {
|
if text := value.Text(); text != "" {
|
||||||
style.properties[tag] = text
|
style.setRaw(tag, text)
|
||||||
|
} else {
|
||||||
|
style.setRaw(tag, nil)
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
|
|
||||||
case ObjectNode:
|
case ObjectNode:
|
||||||
if obj := value.Object(); obj != nil {
|
if obj := value.Object(); obj != nil {
|
||||||
if params := obj.ToParams(); len(params) > 0 {
|
if params := obj.ToParams(); len(params) > 0 {
|
||||||
style.properties[tag] = params
|
style.setRaw(tag, params)
|
||||||
|
} else {
|
||||||
|
style.setRaw(tag, nil)
|
||||||
}
|
}
|
||||||
return true
|
} else {
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case ArrayNode:
|
default:
|
||||||
// TODO
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
|
||||||
case Outline:
|
case Outline:
|
||||||
return style.setOutline(value)
|
return setOutlineProperty(style, value)
|
||||||
|
|
||||||
case OutlineStyle, OutlineWidth, OutlineColor:
|
case OutlineStyle, OutlineWidth, OutlineColor:
|
||||||
if outline := getOutline(style); outline != nil {
|
if outline := getOutlineProperty(style); outline != nil {
|
||||||
return outline.Set(tag, value)
|
if outline.Set(tag, value) {
|
||||||
|
return []PropertyName{Outline, tag}
|
||||||
}
|
}
|
||||||
style.properties[Outline] = NewOutlineProperty(Params{tag: value})
|
} else {
|
||||||
return true
|
outline := NewOutlineProperty(nil)
|
||||||
|
if outline.Set(tag, value) {
|
||||||
|
style.setRaw(Outline, outline)
|
||||||
|
return []PropertyName{Outline, tag}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
case TransformTag:
|
case TransformTag:
|
||||||
return style.setTransform(value)
|
if setTransformProperty(style, value) {
|
||||||
|
return []PropertyName{TransformTag}
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
case RotateX, RotateY, RotateZ, Rotate, SkewX, SkewY, ScaleX, ScaleY, ScaleZ,
|
case Perspective, RotateX, RotateY, RotateZ, Rotate, SkewX, SkewY, ScaleX, ScaleY, ScaleZ,
|
||||||
TranslateX, TranslateY, TranslateZ:
|
TranslateX, TranslateY, TranslateZ:
|
||||||
return style.setTransformProperty(tag, value)
|
return setTransformPropertyElement(style, tag, value)
|
||||||
|
|
||||||
case Orientation:
|
case Orientation:
|
||||||
if text, ok := value.(string); ok {
|
if text, ok := value.(string); ok {
|
||||||
switch strings.ToLower(text) {
|
switch strings.ToLower(text) {
|
||||||
case "vertical":
|
case "vertical":
|
||||||
style.properties[Orientation] = TopDownOrientation
|
style.setRaw(Orientation, TopDownOrientation)
|
||||||
return true
|
return []PropertyName{Orientation}
|
||||||
|
|
||||||
case "horizontal":
|
case "horizontal":
|
||||||
style.properties[Orientation] = StartToEndOrientation
|
style.setRaw(Orientation, StartToEndOrientation)
|
||||||
return true
|
return []PropertyName{Orientation}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case TextWeight:
|
case TextWeight:
|
||||||
if n, ok := value.(int); ok && n >= 100 && n%100 == 0 {
|
if n, ok := value.(int); ok {
|
||||||
|
if n >= 100 && n%100 == 0 {
|
||||||
n /= 100
|
n /= 100
|
||||||
if n > 0 && n <= 9 {
|
if n > 0 && n <= 9 {
|
||||||
style.properties[TextWeight] = n
|
style.setRaw(TextWeight, n)
|
||||||
return true
|
return []PropertyName{TextWeight}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case Row, Column:
|
case Row, Column:
|
||||||
return style.setRange(tag, value)
|
return setRangeProperty(style, tag, value)
|
||||||
|
|
||||||
case CellWidth, CellHeight:
|
case CellWidth, CellHeight:
|
||||||
return style.setGridCellSize(tag, value)
|
return setGridCellSize(style, tag, value)
|
||||||
|
|
||||||
case ColumnSeparator:
|
case ColumnSeparator:
|
||||||
if separator := newColumnSeparatorProperty(value); separator != nil {
|
if separator := newColumnSeparatorProperty(value); separator != nil {
|
||||||
style.properties[ColumnSeparator] = separator
|
style.setRaw(ColumnSeparator, separator)
|
||||||
return true
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
return false
|
return nil
|
||||||
|
|
||||||
case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor:
|
case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor:
|
||||||
var separator ColumnSeparatorProperty = nil
|
if separator := getColumnSeparatorProperty(style); separator != nil {
|
||||||
if val, ok := style.properties[ColumnSeparator]; ok {
|
|
||||||
separator = val.(ColumnSeparatorProperty)
|
|
||||||
}
|
|
||||||
if separator == nil {
|
|
||||||
separator = newColumnSeparatorProperty(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
if separator.Set(tag, value) {
|
if separator.Set(tag, value) {
|
||||||
style.properties[ColumnSeparator] = separator
|
return []PropertyName{ColumnSeparator, tag}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return false
|
} else {
|
||||||
|
separator := newColumnSeparatorProperty(nil)
|
||||||
|
if separator.Set(tag, value) {
|
||||||
|
style.setRaw(ColumnSeparator, separator)
|
||||||
|
return []PropertyName{ColumnSeparator, tag}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
case Clip, ShapeOutside:
|
case Clip, ShapeOutside:
|
||||||
return style.setClipShape(tag, value)
|
return setClipShapeProperty(style, tag, value)
|
||||||
|
|
||||||
case Filter, BackdropFilter:
|
case Filter, BackdropFilter:
|
||||||
return style.setFilter(tag, value)
|
return setFilterProperty(style, tag, value)
|
||||||
|
|
||||||
case Transition:
|
case Transition:
|
||||||
return style.setTransition(tag, value)
|
if setTransitionProperty(style, value) {
|
||||||
|
return []PropertyName{tag}
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
case AnimationTag:
|
case AnimationTag:
|
||||||
return style.setAnimation(tag, value)
|
if setAnimationProperty(style, tag, value) {
|
||||||
|
return []PropertyName{tag}
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return style.propertyList.set(tag, value)
|
return propertiesSet(style, tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (style *viewStyle) Set(tag PropertyName, value any) bool {
|
||||||
|
if value == nil {
|
||||||
|
style.Remove(tag)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewStyleSet(style, normalizeViewStyleTag(tag), value) != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (style *viewStyle) Remove(tag PropertyName) {
|
||||||
|
viewStyleRemove(style, normalizeViewStyleTag(tag))
|
||||||
}
|
}
|
||||||
|
|
480
viewTransform.go
480
viewTransform.go
|
@ -8,87 +8,6 @@ import (
|
||||||
|
|
||||||
// Constants for [Transform] specific properties
|
// Constants for [Transform] specific properties
|
||||||
const (
|
const (
|
||||||
// Perspective is the constant for "perspective" property tag.
|
|
||||||
//
|
|
||||||
// Used by `View`.
|
|
||||||
// Distance between the z-plane and the user in order to give a 3D-positioned element some perspective. Each 3D element
|
|
||||||
// with z > 0 becomes larger, each 3D-element with z < 0 becomes smaller. The default value is 0 (no 3D effects).
|
|
||||||
//
|
|
||||||
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
||||||
//
|
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
||||||
// See `SizeUnit` description for more details.
|
|
||||||
Perspective = "perspective"
|
|
||||||
|
|
||||||
// PerspectiveOriginX is the constant for "perspective-origin-x" property tag.
|
|
||||||
//
|
|
||||||
// Used by `View`.
|
|
||||||
// x-coordinate of the position at which the viewer is looking. It is used as the vanishing point by the "perspective"
|
|
||||||
// property. The default value is 50%.
|
|
||||||
//
|
|
||||||
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
||||||
//
|
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
||||||
// See `SizeUnit` description for more details.
|
|
||||||
PerspectiveOriginX = "perspective-origin-x"
|
|
||||||
|
|
||||||
// PerspectiveOriginY is the constant for "perspective-origin-y" property tag.
|
|
||||||
//
|
|
||||||
// Used by `View`.
|
|
||||||
// y-coordinate of the position at which the viewer is looking. It is used as the vanishing point by the "perspective"
|
|
||||||
// property. The default value is 50%.
|
|
||||||
//
|
|
||||||
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
||||||
//
|
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
||||||
// See `SizeUnit` description for more details.
|
|
||||||
PerspectiveOriginY = "perspective-origin-y"
|
|
||||||
|
|
||||||
// BackfaceVisible is the constant for "backface-visibility" property tag.
|
|
||||||
//
|
|
||||||
// Used by `View`.
|
|
||||||
// Controls whether the back face of a view is visible when turned towards the user. Default value is `true`.
|
|
||||||
//
|
|
||||||
// Supported types: `bool`, `int`, `string`.
|
|
||||||
//
|
|
||||||
// Values:
|
|
||||||
// `true` or `1` or "true", "yes", "on", "1" - Back face is visible when turned towards the user.
|
|
||||||
// `false` or `0` or "false", "no", "off", "0" - Back face is hidden, effectively making the view invisible when turned away from the user.
|
|
||||||
BackfaceVisible = "backface-visibility"
|
|
||||||
|
|
||||||
// OriginX is the constant for "origin-x" property tag.
|
|
||||||
//
|
|
||||||
// Used by `View`.
|
|
||||||
// x-coordinate of the point around which a view transformation is applied. The default value is 50%.
|
|
||||||
//
|
|
||||||
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
||||||
//
|
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
||||||
// See `SizeUnit` description for more details.
|
|
||||||
OriginX = "origin-x"
|
|
||||||
|
|
||||||
// OriginY is the constant for "origin-y" property tag.
|
|
||||||
//
|
|
||||||
// Used by `View`.
|
|
||||||
// y-coordinate of the point around which a view transformation is applied. The default value is 50%.
|
|
||||||
//
|
|
||||||
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
||||||
//
|
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
||||||
// See `SizeUnit` description for more details.
|
|
||||||
OriginY = "origin-y"
|
|
||||||
|
|
||||||
// OriginZ is the constant for "origin-z" property tag.
|
|
||||||
//
|
|
||||||
// Used by `View`.
|
|
||||||
// z-coordinate of the point around which a view transformation is applied. The default value is 50%.
|
|
||||||
//
|
|
||||||
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
|
||||||
//
|
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
|
||||||
// See `SizeUnit` description for more details.
|
|
||||||
OriginZ = "origin-z"
|
|
||||||
|
|
||||||
// TransformTag is the constant for "transform" property tag.
|
// TransformTag is the constant for "transform" property tag.
|
||||||
//
|
//
|
||||||
// Used by `View`.
|
// Used by `View`.
|
||||||
|
@ -101,7 +20,88 @@ const (
|
||||||
// Conversion rules:
|
// Conversion rules:
|
||||||
// `Transform` - stored as is, no conversion performed.
|
// `Transform` - stored as is, no conversion performed.
|
||||||
// `string` - string representation of `Transform` interface. Example: "_{translate-x = 10px, scale-y = 1.1}".
|
// `string` - string representation of `Transform` interface. Example: "_{translate-x = 10px, scale-y = 1.1}".
|
||||||
TransformTag = "transform"
|
TransformTag PropertyName = "transform"
|
||||||
|
|
||||||
|
// Perspective is the constant for "perspective" property tag.
|
||||||
|
//
|
||||||
|
// Used by `View`.
|
||||||
|
// Distance between the z-plane and the user in order to give a 3D-positioned element some perspective. Each 3D element
|
||||||
|
// with z > 0 becomes larger, each 3D-element with z < 0 becomes smaller. The default value is 0 (no 3D effects).
|
||||||
|
//
|
||||||
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
||||||
|
//
|
||||||
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
|
// See `SizeUnit` description for more details.
|
||||||
|
Perspective PropertyName = "perspective"
|
||||||
|
|
||||||
|
// PerspectiveOriginX is the constant for "perspective-origin-x" property tag.
|
||||||
|
//
|
||||||
|
// Used by `View`.
|
||||||
|
// x-coordinate of the position at which the viewer is looking. It is used as the vanishing point by the "perspective"
|
||||||
|
// property. The default value is 50%.
|
||||||
|
//
|
||||||
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
||||||
|
//
|
||||||
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
|
// See `SizeUnit` description for more details.
|
||||||
|
PerspectiveOriginX PropertyName = "perspective-origin-x"
|
||||||
|
|
||||||
|
// PerspectiveOriginY is the constant for "perspective-origin-y" property tag.
|
||||||
|
//
|
||||||
|
// Used by `View`.
|
||||||
|
// y-coordinate of the position at which the viewer is looking. It is used as the vanishing point by the "perspective"
|
||||||
|
// property. The default value is 50%.
|
||||||
|
//
|
||||||
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
||||||
|
//
|
||||||
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
|
// See `SizeUnit` description for more details.
|
||||||
|
PerspectiveOriginY PropertyName = "perspective-origin-y"
|
||||||
|
|
||||||
|
// BackfaceVisible is the constant for "backface-visibility" property tag.
|
||||||
|
//
|
||||||
|
// Used by `View`.
|
||||||
|
// Controls whether the back face of a view is visible when turned towards the user. Default value is `true`.
|
||||||
|
//
|
||||||
|
// Supported types: `bool`, `int`, `string`.
|
||||||
|
//
|
||||||
|
// Values:
|
||||||
|
// `true` or `1` or "true", "yes", "on", "1" - Back face is visible when turned towards the user.
|
||||||
|
// `false` or `0` or "false", "no", "off", "0" - Back face is hidden, effectively making the view invisible when turned away from the user.
|
||||||
|
BackfaceVisible PropertyName = "backface-visibility"
|
||||||
|
|
||||||
|
// OriginX is the constant for "origin-x" property tag.
|
||||||
|
//
|
||||||
|
// Used by `View`.
|
||||||
|
// x-coordinate of the point around which a view transformation is applied. The default value is 50%.
|
||||||
|
//
|
||||||
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
||||||
|
//
|
||||||
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
|
// See `SizeUnit` description for more details.
|
||||||
|
OriginX PropertyName = "origin-x"
|
||||||
|
|
||||||
|
// OriginY is the constant for "origin-y" property tag.
|
||||||
|
//
|
||||||
|
// Used by `View`.
|
||||||
|
// y-coordinate of the point around which a view transformation is applied. The default value is 50%.
|
||||||
|
//
|
||||||
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
||||||
|
//
|
||||||
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
|
// See `SizeUnit` description for more details.
|
||||||
|
OriginY PropertyName = "origin-y"
|
||||||
|
|
||||||
|
// OriginZ is the constant for "origin-z" property tag.
|
||||||
|
//
|
||||||
|
// Used by `View`.
|
||||||
|
// z-coordinate of the point around which a view transformation is applied. The default value is 50%.
|
||||||
|
//
|
||||||
|
// Supported types: `SizeUnit`, `SizeFunc`, `string`, `float`, `int`.
|
||||||
|
//
|
||||||
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
|
// See `SizeUnit` description for more details.
|
||||||
|
OriginZ PropertyName = "origin-z"
|
||||||
|
|
||||||
// TranslateX is the constant for "translate-x" property tag.
|
// TranslateX is the constant for "translate-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -122,7 +122,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TranslateX = "translate-x"
|
TranslateX PropertyName = "translate-x"
|
||||||
|
|
||||||
// TranslateY is the constant for "translate-y" property tag.
|
// TranslateY is the constant for "translate-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -143,7 +143,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TranslateY = "translate-y"
|
TranslateY PropertyName = "translate-y"
|
||||||
|
|
||||||
// TranslateZ is the constant for "translate-z" property tag.
|
// TranslateZ is the constant for "translate-z" property tag.
|
||||||
//
|
//
|
||||||
|
@ -164,7 +164,7 @@ const (
|
||||||
//
|
//
|
||||||
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
// Internal type is `SizeUnit`, other types converted to it during assignment.
|
||||||
// See `SizeUnit` description for more details.
|
// See `SizeUnit` description for more details.
|
||||||
TranslateZ = "translate-z"
|
TranslateZ PropertyName = "translate-z"
|
||||||
|
|
||||||
// ScaleX is the constant for "scale-x" property tag.
|
// ScaleX is the constant for "scale-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -185,7 +185,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
ScaleX = "scale-x"
|
ScaleX PropertyName = "scale-x"
|
||||||
|
|
||||||
// ScaleY is the constant for "scale-y" property tag.
|
// ScaleY is the constant for "scale-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -206,7 +206,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
ScaleY = "scale-y"
|
ScaleY PropertyName = "scale-y"
|
||||||
|
|
||||||
// ScaleZ is the constant for "scale-z" property tag.
|
// ScaleZ is the constant for "scale-z" property tag.
|
||||||
//
|
//
|
||||||
|
@ -227,7 +227,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
ScaleZ = "scale-z"
|
ScaleZ PropertyName = "scale-z"
|
||||||
|
|
||||||
// Rotate is the constant for "rotate" property tag.
|
// Rotate is the constant for "rotate" property tag.
|
||||||
//
|
//
|
||||||
|
@ -260,7 +260,7 @@ const (
|
||||||
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
|
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
|
||||||
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
|
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
|
||||||
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
|
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
|
||||||
Rotate = "rotate"
|
Rotate PropertyName = "rotate"
|
||||||
|
|
||||||
// RotateX is the constant for "rotate-x" property tag.
|
// RotateX is the constant for "rotate-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -279,7 +279,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
RotateX = "rotate-x"
|
RotateX PropertyName = "rotate-x"
|
||||||
|
|
||||||
// RotateY is the constant for "rotate-y" property tag.
|
// RotateY is the constant for "rotate-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -298,7 +298,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
RotateY = "rotate-y"
|
RotateY PropertyName = "rotate-y"
|
||||||
|
|
||||||
// RotateZ is the constant for "rotate-z" property tag.
|
// RotateZ is the constant for "rotate-z" property tag.
|
||||||
//
|
//
|
||||||
|
@ -317,7 +317,7 @@ const (
|
||||||
// Supported types: `float`, `int`, `string`.
|
// Supported types: `float`, `int`, `string`.
|
||||||
//
|
//
|
||||||
// Internal type is `float`, other types converted to it during assignment.
|
// Internal type is `float`, other types converted to it during assignment.
|
||||||
RotateZ = "rotate-z"
|
RotateZ PropertyName = "rotate-z"
|
||||||
|
|
||||||
// SkewX is the constant for "skew-x" property tag.
|
// SkewX is the constant for "skew-x" property tag.
|
||||||
//
|
//
|
||||||
|
@ -350,7 +350,7 @@ const (
|
||||||
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
|
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
|
||||||
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
|
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
|
||||||
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
|
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
|
||||||
SkewX = "skew-x"
|
SkewX PropertyName = "skew-x"
|
||||||
|
|
||||||
// SkewY is the constant for "skew-y" property tag.
|
// SkewY is the constant for "skew-y" property tag.
|
||||||
//
|
//
|
||||||
|
@ -383,44 +383,97 @@ const (
|
||||||
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
|
// `string` - must contain string representation of `AngleUnit`. If numeric value will be provided without any suffix then `AngleUnit` with value and `Radian` value type will be created.
|
||||||
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
|
// `float` - a new `AngleUnit` value will be created with `Radian` as a type.
|
||||||
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
|
// `int` - a new `AngleUnit` value will be created with `Radian` as a type.
|
||||||
SkewY = "skew-y"
|
SkewY PropertyName = "skew-y"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Transform interface specifies view transformation parameters: the x-, y-, and z-axis translation values,
|
// Transform interface specifies view transformation parameters: the x-, y-, and z-axis translation values,
|
||||||
// the x-, y-, and z-axis scaling values, the angle to use to distort the element along the abscissa and ordinate,
|
// the x-, y-, and z-axis scaling values, the angle to use to distort the element along the abscissa and ordinate,
|
||||||
// the angle of the view rotation.
|
// the angle of the view rotation.
|
||||||
// Valid property tags: TranslateX ("translate-x"), TranslateY ("translate-y"), TranslateZ ("translate-z"),
|
// Valid property tags: Perspective ("perspective"), TranslateX ("translate-x"), TranslateY ("translate-y"), TranslateZ ("translate-z"),
|
||||||
// ScaleX ("scale-x"), ScaleY ("scale-y"), ScaleZ ("scale-z"), Rotate ("rotate"), RotateX ("rotate-x"),
|
// ScaleX ("scale-x"), ScaleY ("scale-y"), ScaleZ ("scale-z"), Rotate ("rotate"), RotateX ("rotate-x"),
|
||||||
// RotateY ("rotate-y"), RotateZ ("rotate-z"), SkewX ("skew-x"), and SkewY ("skew-y")
|
// RotateY ("rotate-y"), RotateZ ("rotate-z"), SkewX ("skew-x"), and SkewY ("skew-y")
|
||||||
type Transform interface {
|
type Transform interface {
|
||||||
Properties
|
Properties
|
||||||
fmt.Stringer
|
fmt.Stringer
|
||||||
stringWriter
|
stringWriter
|
||||||
transformCSS(session Session, transform3D bool) string
|
transformCSS(session Session) string
|
||||||
}
|
}
|
||||||
|
|
||||||
type transformData struct {
|
type transformData struct {
|
||||||
propertyList
|
dataProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTransform creates a new transform property data and return its interface
|
// NewTransform creates a new transform property data and return its interface
|
||||||
func NewTransform(params Params) Transform {
|
func NewTransform(params Params) Transform {
|
||||||
transform := new(transformData)
|
transform := new(transformData)
|
||||||
transform.properties = map[string]any{}
|
transform.init()
|
||||||
|
|
||||||
for tag, value := range params {
|
for tag, value := range params {
|
||||||
transform.Set(tag, value)
|
transform.Set(tag, value)
|
||||||
}
|
}
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) setTransform(value any) bool {
|
func (transform *transformData) init() {
|
||||||
|
transform.dataProperty.init()
|
||||||
|
transform.set = transformSet
|
||||||
|
transform.supportedProperties = []PropertyName{
|
||||||
|
RotateX, RotateY, RotateZ, Rotate, SkewX, SkewY, ScaleX, ScaleY, ScaleZ,
|
||||||
|
Perspective, TranslateX, TranslateY, TranslateZ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (transform *transformData) String() string {
|
||||||
|
buffer := allocStringBuilder()
|
||||||
|
defer freeStringBuilder(buffer)
|
||||||
|
transform.writeString(buffer, "")
|
||||||
|
return buffer.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (transform *transformData) writeString(buffer *strings.Builder, indent string) {
|
||||||
|
buffer.WriteString("_{ ")
|
||||||
|
comma := false
|
||||||
|
for _, tag := range transform.supportedProperties {
|
||||||
|
if value, ok := transform.properties[tag]; ok {
|
||||||
|
if comma {
|
||||||
|
buffer.WriteString(", ")
|
||||||
|
}
|
||||||
|
buffer.WriteString(string(tag))
|
||||||
|
buffer.WriteString(" = ")
|
||||||
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
|
comma = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.WriteString(" }")
|
||||||
|
}
|
||||||
|
|
||||||
|
func transformSet(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
|
switch tag {
|
||||||
|
|
||||||
|
case RotateX, RotateY, RotateZ:
|
||||||
|
return setFloatProperty(properties, tag, value, 0, 1)
|
||||||
|
|
||||||
|
case Rotate, SkewX, SkewY:
|
||||||
|
return setAngleProperty(properties, tag, value)
|
||||||
|
|
||||||
|
case ScaleX, ScaleY, ScaleZ:
|
||||||
|
return setFloatProperty(properties, tag, value, -math.MaxFloat64, math.MaxFloat64)
|
||||||
|
|
||||||
|
case Perspective, TranslateX, TranslateY, TranslateZ:
|
||||||
|
return setSizeProperty(properties, tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTransformProperty(properties Properties, value any) bool {
|
||||||
|
|
||||||
setObject := func(obj DataObject) bool {
|
setObject := func(obj DataObject) bool {
|
||||||
transform := NewTransform(nil)
|
transform := NewTransform(nil)
|
||||||
ok := true
|
ok := true
|
||||||
for i := 0; i < obj.PropertyCount(); i++ {
|
for i := 0; i < obj.PropertyCount(); i++ {
|
||||||
if prop := obj.Property(i); prop.Type() == TextNode {
|
if prop := obj.Property(i); prop.Type() == TextNode {
|
||||||
if !transform.Set(prop.Tag(), prop.Text()) {
|
if !transform.Set(PropertyName(prop.Tag()), prop.Text()) {
|
||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -428,17 +481,17 @@ func (style *viewStyle) setTransform(value any) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok && len(transform.AllTags()) == 0 {
|
if !ok && transform.empty() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
style.properties[TransformTag] = transform
|
properties.setRaw(TransformTag, transform)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case Transform:
|
case Transform:
|
||||||
style.properties[TransformTag] = value
|
properties.setRaw(TransformTag, value)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
|
@ -462,8 +515,8 @@ func (style *viewStyle) setTransform(value any) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) transformProperty() Transform {
|
func getTransformProperty(properties Properties) Transform {
|
||||||
if val, ok := style.properties[TransformTag]; ok {
|
if val := properties.getRaw(TransformTag); val != nil {
|
||||||
if transform, ok := val.(Transform); ok {
|
if transform, ok := val.(Transform); ok {
|
||||||
return transform
|
return transform
|
||||||
}
|
}
|
||||||
|
@ -471,80 +524,26 @@ func (style *viewStyle) transformProperty() Transform {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) setTransformProperty(tag string, value any) bool {
|
func setTransformPropertyElement(properties Properties, tag PropertyName, value any) []PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case RotateX, RotateY, RotateZ, Rotate, SkewX, SkewY, ScaleX, ScaleY, ScaleZ, TranslateX, TranslateY, TranslateZ:
|
case Perspective, RotateX, RotateY, RotateZ, Rotate, SkewX, SkewY, ScaleX, ScaleY, ScaleZ, TranslateX, TranslateY, TranslateZ:
|
||||||
if transform := style.transformProperty(); transform != nil {
|
if transform := getTransformProperty(properties); transform != nil {
|
||||||
return transform.Set(tag, value)
|
if result := transformSet(transform, tag, value); result != nil {
|
||||||
|
result = append(result, TransformTag)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
transform := NewTransform(nil)
|
transform := NewTransform(nil)
|
||||||
if !transform.Set(tag, value) {
|
if result := transformSet(transform, tag, value); result != nil {
|
||||||
return false
|
properties.setRaw(TransformTag, transform)
|
||||||
}
|
result = append(result, TransformTag)
|
||||||
|
}
|
||||||
style.properties[TransformTag] = transform
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
ErrorLogF(`"Transform" interface does not support the "%s" property`, tag)
|
ErrorLogF(`"Transform" interface does not support the "%s" property`, tag)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transform *transformData) String() string {
|
return nil
|
||||||
buffer := allocStringBuilder()
|
|
||||||
defer freeStringBuilder(buffer)
|
|
||||||
transform.writeString(buffer, "")
|
|
||||||
return buffer.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (transform *transformData) writeString(buffer *strings.Builder, indent string) {
|
|
||||||
buffer.WriteString("_{ ")
|
|
||||||
comma := false
|
|
||||||
for _, tag := range []string{SkewX, SkewY, TranslateX, TranslateY, TranslateZ,
|
|
||||||
ScaleX, ScaleY, ScaleZ, Rotate, RotateX, RotateY, RotateZ} {
|
|
||||||
if value, ok := transform.properties[tag]; ok {
|
|
||||||
if comma {
|
|
||||||
buffer.WriteString(", ")
|
|
||||||
}
|
|
||||||
buffer.WriteString(tag)
|
|
||||||
buffer.WriteString(" = ")
|
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
|
||||||
comma = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.WriteString(" }")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (transform *transformData) Set(tag string, value any) bool {
|
|
||||||
return transform.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (transform *transformData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
_, exist := transform.properties[tag]
|
|
||||||
if exist {
|
|
||||||
delete(transform.properties, tag)
|
|
||||||
}
|
|
||||||
return exist
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tag {
|
|
||||||
|
|
||||||
case RotateX, RotateY, RotateZ:
|
|
||||||
return transform.setFloatProperty(tag, value, 0, 1)
|
|
||||||
|
|
||||||
case Rotate, SkewX, SkewY:
|
|
||||||
return transform.setAngleProperty(tag, value)
|
|
||||||
|
|
||||||
case ScaleX, ScaleY, ScaleZ:
|
|
||||||
return transform.setFloatProperty(tag, value, -math.MaxFloat64, math.MaxFloat64)
|
|
||||||
|
|
||||||
case TranslateX, TranslateY, TranslateZ:
|
|
||||||
return transform.setSizeProperty(tag, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTransform3D(style Properties, session Session) bool {
|
func getTransform3D(style Properties, session Session) bool {
|
||||||
|
@ -578,61 +577,75 @@ func (transform *transformData) getTranslate(session Session) (SizeUnit, SizeUni
|
||||||
return x, y, z
|
return x, y, z
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transform *transformData) transformCSS(session Session, transform3D bool) string {
|
func (transform *transformData) transformCSS(session Session) string {
|
||||||
|
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
|
if perspective, ok := sizeProperty(transform, Perspective, session); ok && perspective.Type != Auto && perspective.Value != 0 {
|
||||||
|
buffer.WriteString(`perspective(`)
|
||||||
|
buffer.WriteString(perspective.cssString("0", session))
|
||||||
|
buffer.WriteString(") ")
|
||||||
|
}
|
||||||
|
|
||||||
skewX, skewY, skewOK := transform.getSkew(session)
|
skewX, skewY, skewOK := transform.getSkew(session)
|
||||||
if skewOK {
|
if skewOK {
|
||||||
buffer.WriteString(`skew(`)
|
buffer.WriteString(`skew(`)
|
||||||
buffer.WriteString(skewX.cssString())
|
buffer.WriteString(skewX.cssString())
|
||||||
buffer.WriteRune(',')
|
buffer.WriteRune(',')
|
||||||
buffer.WriteString(skewY.cssString())
|
buffer.WriteString(skewY.cssString())
|
||||||
buffer.WriteRune(')')
|
buffer.WriteString(") ")
|
||||||
}
|
}
|
||||||
|
|
||||||
x, y, z := transform.getTranslate(session)
|
x, y, z := transform.getTranslate(session)
|
||||||
|
if z.Type != Auto && z.Value != 0 {
|
||||||
|
|
||||||
scaleX, okScaleX := floatTextProperty(transform, ScaleX, session, 1)
|
|
||||||
scaleY, okScaleY := floatTextProperty(transform, ScaleY, session, 1)
|
|
||||||
|
|
||||||
if transform3D {
|
|
||||||
if x.Type != Auto || y.Type != Auto || z.Type != Auto {
|
|
||||||
if buffer.Len() > 0 {
|
|
||||||
buffer.WriteRune(' ')
|
|
||||||
}
|
|
||||||
buffer.WriteString(`translate3d(`)
|
buffer.WriteString(`translate3d(`)
|
||||||
buffer.WriteString(x.cssString("0", session))
|
buffer.WriteString(x.cssString("0", session))
|
||||||
buffer.WriteRune(',')
|
buffer.WriteRune(',')
|
||||||
buffer.WriteString(y.cssString("0", session))
|
buffer.WriteString(y.cssString("0", session))
|
||||||
buffer.WriteRune(',')
|
buffer.WriteRune(',')
|
||||||
buffer.WriteString(z.cssString("0", session))
|
buffer.WriteString(z.cssString("0", session))
|
||||||
buffer.WriteRune(')')
|
buffer.WriteString(") ")
|
||||||
|
|
||||||
|
} else if (x.Type != Auto && x.Value != 0) || (y.Type != Auto && y.Value != 0) {
|
||||||
|
|
||||||
|
buffer.WriteString(`translate(`)
|
||||||
|
buffer.WriteString(x.cssString("0", session))
|
||||||
|
buffer.WriteRune(',')
|
||||||
|
buffer.WriteString(y.cssString("0", session))
|
||||||
|
buffer.WriteString(") ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scaleX, okScaleX := floatTextProperty(transform, ScaleX, session, 1)
|
||||||
|
scaleY, okScaleY := floatTextProperty(transform, ScaleY, session, 1)
|
||||||
scaleZ, okScaleZ := floatTextProperty(transform, ScaleZ, session, 1)
|
scaleZ, okScaleZ := floatTextProperty(transform, ScaleZ, session, 1)
|
||||||
if okScaleX || okScaleY || okScaleZ {
|
if okScaleZ {
|
||||||
if buffer.Len() > 0 {
|
|
||||||
buffer.WriteRune(' ')
|
|
||||||
}
|
|
||||||
buffer.WriteString(`scale3d(`)
|
buffer.WriteString(`scale3d(`)
|
||||||
buffer.WriteString(scaleX)
|
buffer.WriteString(scaleX)
|
||||||
buffer.WriteRune(',')
|
buffer.WriteRune(',')
|
||||||
buffer.WriteString(scaleY)
|
buffer.WriteString(scaleY)
|
||||||
buffer.WriteRune(',')
|
buffer.WriteRune(',')
|
||||||
buffer.WriteString(scaleZ)
|
buffer.WriteString(scaleZ)
|
||||||
buffer.WriteRune(')')
|
buffer.WriteString(") ")
|
||||||
|
|
||||||
|
} else if okScaleX || okScaleY {
|
||||||
|
|
||||||
|
buffer.WriteString(`scale(`)
|
||||||
|
buffer.WriteString(scaleX)
|
||||||
|
buffer.WriteRune(',')
|
||||||
|
buffer.WriteString(scaleY)
|
||||||
|
buffer.WriteString(") ")
|
||||||
}
|
}
|
||||||
|
|
||||||
if angle, ok := angleProperty(transform, Rotate, session); ok {
|
if angle, ok := angleProperty(transform, Rotate, session); ok {
|
||||||
rotateX, _ := floatTextProperty(transform, RotateX, session, 1)
|
rotateX, xOK := floatTextProperty(transform, RotateX, session, 1)
|
||||||
rotateY, _ := floatTextProperty(transform, RotateY, session, 1)
|
rotateY, yOK := floatTextProperty(transform, RotateY, session, 1)
|
||||||
rotateZ, _ := floatTextProperty(transform, RotateZ, session, 1)
|
rotateZ, zOK := floatTextProperty(transform, RotateZ, session, 1)
|
||||||
|
|
||||||
|
if xOK || yOK || zOK {
|
||||||
|
|
||||||
if buffer.Len() > 0 {
|
|
||||||
buffer.WriteRune(' ')
|
|
||||||
}
|
|
||||||
buffer.WriteString(`rotate3d(`)
|
buffer.WriteString(`rotate3d(`)
|
||||||
buffer.WriteString(rotateX)
|
buffer.WriteString(rotateX)
|
||||||
buffer.WriteRune(',')
|
buffer.WriteRune(',')
|
||||||
|
@ -641,53 +654,25 @@ func (transform *transformData) transformCSS(session Session, transform3D bool)
|
||||||
buffer.WriteString(rotateZ)
|
buffer.WriteString(rotateZ)
|
||||||
buffer.WriteRune(',')
|
buffer.WriteRune(',')
|
||||||
buffer.WriteString(angle.cssString())
|
buffer.WriteString(angle.cssString())
|
||||||
buffer.WriteRune(')')
|
buffer.WriteString(") ")
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if x.Type != Auto || y.Type != Auto {
|
|
||||||
if buffer.Len() > 0 {
|
|
||||||
buffer.WriteRune(' ')
|
|
||||||
}
|
|
||||||
buffer.WriteString(`translate(`)
|
|
||||||
buffer.WriteString(x.cssString("0", session))
|
|
||||||
buffer.WriteRune(',')
|
|
||||||
buffer.WriteString(y.cssString("0", session))
|
|
||||||
buffer.WriteRune(')')
|
|
||||||
}
|
|
||||||
|
|
||||||
if okScaleX || okScaleY {
|
|
||||||
if buffer.Len() > 0 {
|
|
||||||
buffer.WriteRune(' ')
|
|
||||||
}
|
|
||||||
buffer.WriteString(`scale(`)
|
|
||||||
buffer.WriteString(scaleX)
|
|
||||||
buffer.WriteRune(',')
|
|
||||||
buffer.WriteString(scaleY)
|
|
||||||
buffer.WriteRune(')')
|
|
||||||
}
|
|
||||||
|
|
||||||
if angle, ok := angleProperty(transform, Rotate, session); ok {
|
|
||||||
if buffer.Len() > 0 {
|
|
||||||
buffer.WriteRune(' ')
|
|
||||||
}
|
|
||||||
buffer.WriteString(`rotate(`)
|
buffer.WriteString(`rotate(`)
|
||||||
buffer.WriteString(angle.cssString())
|
buffer.WriteString(angle.cssString())
|
||||||
buffer.WriteRune(')')
|
buffer.WriteString(") ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer.String()
|
length := buffer.Len()
|
||||||
|
if length == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
result := buffer.String()
|
||||||
|
return result[:length-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Session) {
|
func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Session) {
|
||||||
transform3D := getTransform3D(style, session)
|
|
||||||
if transform3D {
|
|
||||||
if perspective, ok := sizeProperty(style, Perspective, session); ok && perspective.Type != Auto && perspective.Value != 0 {
|
|
||||||
builder.add(`perspective`, perspective.cssString("0", session))
|
|
||||||
}
|
|
||||||
|
|
||||||
x, y := getPerspectiveOrigin(style, session)
|
x, y := getPerspectiveOrigin(style, session)
|
||||||
if x.Type != Auto || y.Type != Auto {
|
if x.Type != Auto || y.Type != Auto {
|
||||||
builder.addValues(`perspective-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session))
|
builder.addValues(`perspective-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session))
|
||||||
|
@ -702,29 +687,23 @@ func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Sessio
|
||||||
}
|
}
|
||||||
|
|
||||||
x, y, z := getOrigin(style, session)
|
x, y, z := getOrigin(style, session)
|
||||||
if x.Type != Auto || y.Type != Auto || z.Type != Auto {
|
if z.Type != Auto && z.Value != 0 {
|
||||||
builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session), z.cssString("0", session))
|
builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session), z.cssString("0", session))
|
||||||
}
|
} else if x.Type != Auto || y.Type != Auto {
|
||||||
} else {
|
|
||||||
x, y, _ := getOrigin(style, session)
|
|
||||||
if x.Type != Auto || y.Type != Auto {
|
|
||||||
builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session))
|
builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if transform := style.transformProperty(); transform != nil {
|
if transform := getTransformProperty(style); transform != nil {
|
||||||
builder.add(`transform`, transform.transformCSS(session, transform3D))
|
builder.add(`transform`, transform.transformCSS(session))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) updateTransformProperty(tag string) bool {
|
/*
|
||||||
|
func (view *viewData) updateTransformProperty(tag PropertyName) bool {
|
||||||
htmlID := view.htmlID()
|
htmlID := view.htmlID()
|
||||||
session := view.session
|
session := view.session
|
||||||
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Perspective:
|
|
||||||
updateCSSStyle(htmlID, session)
|
|
||||||
|
|
||||||
case PerspectiveOriginX, PerspectiveOriginY:
|
case PerspectiveOriginX, PerspectiveOriginY:
|
||||||
if getTransform3D(view, session) {
|
if getTransform3D(view, session) {
|
||||||
x, y := GetPerspectiveOrigin(view)
|
x, y := GetPerspectiveOrigin(view)
|
||||||
|
@ -738,31 +717,27 @@ func (view *viewData) updateTransformProperty(tag string) bool {
|
||||||
case BackfaceVisible:
|
case BackfaceVisible:
|
||||||
if getTransform3D(view, session) {
|
if getTransform3D(view, session) {
|
||||||
if GetBackfaceVisible(view) {
|
if GetBackfaceVisible(view) {
|
||||||
session.updateCSSProperty(htmlID, BackfaceVisible, "visible")
|
session.updateCSSProperty(htmlID, string(BackfaceVisible), "visible")
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, BackfaceVisible, "hidden")
|
session.updateCSSProperty(htmlID, string(BackfaceVisible), "hidden")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case OriginX, OriginY, OriginZ:
|
case OriginX, OriginY, OriginZ:
|
||||||
x, y, z := getOrigin(view, session)
|
x, y, z := getOrigin(view, session)
|
||||||
value := ""
|
value := ""
|
||||||
if getTransform3D(view, session) {
|
|
||||||
if x.Type != Auto || y.Type != Auto || z.Type != Auto {
|
if z.Type != Auto {
|
||||||
value = x.cssString("50%", session) + " " + y.cssString("50%", session) + " " + z.cssString("50%", session)
|
value = x.cssString("50%", session) + " " + y.cssString("50%", session) + " " + z.cssString("50%", session)
|
||||||
}
|
} else if x.Type != Auto || y.Type != Auto {
|
||||||
} else {
|
|
||||||
if x.Type != Auto || y.Type != Auto {
|
|
||||||
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
|
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
session.updateCSSProperty(htmlID, "transform-origin", value)
|
session.updateCSSProperty(htmlID, "transform-origin", value)
|
||||||
|
|
||||||
case TransformTag, SkewX, SkewY, TranslateX, TranslateY, TranslateZ,
|
case TransformTag, SkewX, SkewY, TranslateX, TranslateY, TranslateZ,
|
||||||
ScaleX, ScaleY, ScaleZ, Rotate, RotateX, RotateY, RotateZ:
|
ScaleX, ScaleY, ScaleZ, Rotate, RotateX, RotateY, RotateZ:
|
||||||
if transform := view.transformProperty(); transform != nil {
|
if transform := getTransformProperty(view); transform != nil {
|
||||||
transform3D := getTransform3D(view, session)
|
session.updateCSSProperty(htmlID, "transform", transform.transformCSS(session))
|
||||||
session.updateCSSProperty(htmlID, "transform", transform.transformCSS(session, transform3D))
|
|
||||||
} else {
|
} else {
|
||||||
session.updateCSSProperty(htmlID, "transform", "")
|
session.updateCSSProperty(htmlID, "transform", "")
|
||||||
}
|
}
|
||||||
|
@ -773,3 +748,4 @@ func (view *viewData) updateTransformProperty(tag string) bool {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
26
viewUtils.go
26
viewUtils.go
|
@ -3,7 +3,7 @@ package rui
|
||||||
// Get returns a value of the property with name "tag" of the "rootView" subview with "viewID" id value.
|
// Get returns a value of the property with name "tag" of the "rootView" subview with "viewID" id value.
|
||||||
// The type of return value depends on the property.
|
// The type of return value depends on the property.
|
||||||
// If the subview don't exists or the property is not set then nil is returned.
|
// If the subview don't exists or the property is not set then nil is returned.
|
||||||
func Get(rootView View, viewID, tag string) any {
|
func Get(rootView View, viewID string, tag PropertyName) any {
|
||||||
var view View
|
var view View
|
||||||
if viewID != "" {
|
if viewID != "" {
|
||||||
view = ViewByID(rootView, viewID)
|
view = ViewByID(rootView, viewID)
|
||||||
|
@ -19,7 +19,7 @@ func Get(rootView View, viewID, tag string) any {
|
||||||
// Set sets the property with name "tag" of the "rootView" subview with "viewID" id by value. Result:
|
// Set sets the property with name "tag" of the "rootView" subview with "viewID" id by value. Result:
|
||||||
// true - success,
|
// true - success,
|
||||||
// false - error (incompatible type or invalid format of a string value, see AppLog).
|
// false - error (incompatible type or invalid format of a string value, see AppLog).
|
||||||
func Set(rootView View, viewID, tag string, value any) bool {
|
func Set(rootView View, viewID string, tag PropertyName, value any) bool {
|
||||||
var view View
|
var view View
|
||||||
if viewID != "" {
|
if viewID != "" {
|
||||||
view = ViewByID(rootView, viewID)
|
view = ViewByID(rootView, viewID)
|
||||||
|
@ -34,7 +34,7 @@ func Set(rootView View, viewID, tag string, value any) bool {
|
||||||
|
|
||||||
// SetChangeListener sets a listener for changing a subview property value.
|
// SetChangeListener sets a listener for changing a subview property value.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a listener for the first argument (view) is set
|
// If the second argument (subviewID) is not specified or it is "" then a listener for the first argument (view) is set
|
||||||
func SetChangeListener(view View, viewID, tag string, listener func(View, string)) {
|
func SetChangeListener(view View, viewID string, tag PropertyName, listener func(View, PropertyName)) {
|
||||||
if viewID != "" {
|
if viewID != "" {
|
||||||
view = ViewByID(view, viewID)
|
view = ViewByID(view, viewID)
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ func GetBorder(view View, subviewID ...string) ViewBorders {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if border := getBorder(view, Border); border != nil {
|
if border := getBorderProperty(view, Border); border != nil {
|
||||||
return border.ViewBorders(view.Session())
|
return border.ViewBorders(view.Session())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +320,7 @@ func GetOutline(view View, subviewID ...string) ViewOutline {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
if view != nil {
|
if view != nil {
|
||||||
if outline := getOutline(view); outline != nil {
|
if outline := getOutlineProperty(view); outline != nil {
|
||||||
return outline.ViewOutline(view.Session())
|
return outline.ViewOutline(view.Session())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -706,9 +706,9 @@ func GetNotTranslate(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, NotTranslate, true)
|
return boolStyledProperty(view, subviewID, NotTranslate, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func valueFromStyle(view View, tag string) any {
|
func valueFromStyle(view View, tag PropertyName) any {
|
||||||
session := view.Session()
|
session := view.Session()
|
||||||
getValue := func(styleTag string) any {
|
getValue := func(styleTag PropertyName) any {
|
||||||
if style, ok := stringProperty(view, styleTag, session); ok {
|
if style, ok := stringProperty(view, styleTag, session); ok {
|
||||||
if style, ok := session.resolveConstants(style); ok {
|
if style, ok := session.resolveConstants(style); ok {
|
||||||
return session.styleProperty(style, tag)
|
return session.styleProperty(style, tag)
|
||||||
|
@ -725,7 +725,7 @@ func valueFromStyle(view View, tag string) any {
|
||||||
return getValue(Style)
|
return getValue(Style)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sizeStyledProperty(view View, subviewID []string, tag string, inherit bool) SizeUnit {
|
func sizeStyledProperty(view View, subviewID []string, tag PropertyName, inherit bool) SizeUnit {
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
|
@ -749,7 +749,7 @@ func sizeStyledProperty(view View, subviewID []string, tag string, inherit bool)
|
||||||
return AutoSize()
|
return AutoSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func enumStyledProperty(view View, subviewID []string, tag string, defaultValue int, inherit bool) int {
|
func enumStyledProperty(view View, subviewID []string, tag PropertyName, defaultValue int, inherit bool) int {
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
|
@ -773,7 +773,7 @@ func enumStyledProperty(view View, subviewID []string, tag string, defaultValue
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func boolStyledProperty(view View, subviewID []string, tag string, inherit bool) bool {
|
func boolStyledProperty(view View, subviewID []string, tag PropertyName, inherit bool) bool {
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
|
@ -798,7 +798,7 @@ func boolStyledProperty(view View, subviewID []string, tag string, inherit bool)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func intStyledProperty(view View, subviewID []string, tag string, defaultValue int) int {
|
func intStyledProperty(view View, subviewID []string, tag PropertyName, defaultValue int) int {
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
|
@ -815,7 +815,7 @@ func intStyledProperty(view View, subviewID []string, tag string, defaultValue i
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func floatStyledProperty(view View, subviewID []string, tag string, defaultValue float64) float64 {
|
func floatStyledProperty(view View, subviewID []string, tag PropertyName, defaultValue float64) float64 {
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
|
@ -831,7 +831,7 @@ func floatStyledProperty(view View, subviewID []string, tag string, defaultValue
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func colorStyledProperty(view View, subviewID []string, tag string, inherit bool) Color {
|
func colorStyledProperty(view View, subviewID []string, tag PropertyName, inherit bool) Color {
|
||||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||||
view = ViewByID(view, subviewID[0])
|
view = ViewByID(view, subviewID[0])
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ type ViewsContainer interface {
|
||||||
|
|
||||||
// ViewIndex returns the index of view, -1 overwise
|
// ViewIndex returns the index of view, -1 overwise
|
||||||
ViewIndex(view View) int
|
ViewIndex(view View) int
|
||||||
|
|
||||||
|
setContent(value any) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type viewsContainerData struct {
|
type viewsContainerData struct {
|
||||||
|
@ -36,10 +38,10 @@ func (container *viewsContainerData) init(session Session) {
|
||||||
container.viewData.init(session)
|
container.viewData.init(session)
|
||||||
container.tag = "ViewsContainer"
|
container.tag = "ViewsContainer"
|
||||||
container.views = []View{}
|
container.views = []View{}
|
||||||
}
|
container.getFunc = container.get
|
||||||
|
container.set = container.setFunc
|
||||||
func (container *viewsContainerData) String() string {
|
container.remove = container.removeFunc
|
||||||
return getViewString(container, nil)
|
container.changed = viewsContainerPropertyChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *viewsContainerData) setParentID(parentID string) {
|
func (container *viewsContainerData) setParentID(parentID string) {
|
||||||
|
@ -62,6 +64,13 @@ func (container *viewsContainerData) Views() []View {
|
||||||
return []View{}
|
return []View{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func viewsContainerContentChanged(container *viewsContainerData) {
|
||||||
|
updateInnerHTML(container.htmlID(), container.Session())
|
||||||
|
if listener, ok := container.changeListener[Content]; ok {
|
||||||
|
listener(container, Content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Append appends a view to the end of the list of a view children
|
// Append appends a view to the end of the list of a view children
|
||||||
func (container *viewsContainerData) Append(view View) {
|
func (container *viewsContainerData) Append(view View) {
|
||||||
if view != nil {
|
if view != nil {
|
||||||
|
@ -72,8 +81,7 @@ func (container *viewsContainerData) Append(view View) {
|
||||||
} else {
|
} else {
|
||||||
container.views = append(container.views, view)
|
container.views = append(container.views, view)
|
||||||
}
|
}
|
||||||
updateInnerHTML(container.htmlID(), container.session)
|
viewsContainerContentChanged(container)
|
||||||
container.propertyChangedEvent(Content)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,13 +94,11 @@ func (container *viewsContainerData) Insert(view View, index int) {
|
||||||
} else if index > 0 {
|
} else if index > 0 {
|
||||||
view.setParentID(htmlID)
|
view.setParentID(htmlID)
|
||||||
container.views = append(container.views[:index], append([]View{view}, container.views[index:]...)...)
|
container.views = append(container.views[:index], append([]View{view}, container.views[index:]...)...)
|
||||||
updateInnerHTML(container.htmlID(), container.session)
|
viewsContainerContentChanged(container)
|
||||||
container.propertyChangedEvent(Content)
|
|
||||||
} else {
|
} else {
|
||||||
view.setParentID(htmlID)
|
view.setParentID(htmlID)
|
||||||
container.views = append([]View{view}, container.views...)
|
container.views = append([]View{view}, container.views...)
|
||||||
updateInnerHTML(container.htmlID(), container.session)
|
viewsContainerContentChanged(container)
|
||||||
container.propertyChangedEvent(Content)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,8 +125,7 @@ func (container *viewsContainerData) RemoveView(index int) View {
|
||||||
}
|
}
|
||||||
|
|
||||||
view.setParentID("")
|
view.setParentID("")
|
||||||
updateInnerHTML(container.htmlID(), container.session)
|
viewsContainerContentChanged(container)
|
||||||
container.propertyChangedEvent(Content)
|
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,67 +163,60 @@ func viewFromTextValue(text string, session Session) View {
|
||||||
return NewTextView(session, Params{Text: text})
|
return NewTextView(session, Params{Text: text})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *viewsContainerData) Remove(tag string) {
|
func (container *viewsContainerData) removeFunc(view View, tag PropertyName) []PropertyName {
|
||||||
container.remove(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (container *viewsContainerData) remove(tag string) {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Content:
|
case Content:
|
||||||
if container.views == nil || len(container.views) > 0 {
|
if len(container.views) > 0 {
|
||||||
container.views = []View{}
|
container.views = []View{}
|
||||||
updateInnerHTML(container.htmlID(), container.Session())
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
container.propertyChangedEvent(Content)
|
return []PropertyName{}
|
||||||
|
|
||||||
case Disabled:
|
case Disabled:
|
||||||
if _, ok := container.properties[Disabled]; ok {
|
if view.getRaw(Disabled) != nil {
|
||||||
delete(container.properties, Disabled)
|
view.setRaw(Disabled, nil)
|
||||||
if container.views != nil {
|
|
||||||
for _, view := range container.views {
|
for _, view := range container.views {
|
||||||
view.Remove(Disabled)
|
view.Remove(Disabled)
|
||||||
}
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
container.propertyChangedEvent(tag)
|
}
|
||||||
}
|
return viewRemove(view, tag)
|
||||||
|
|
||||||
default:
|
|
||||||
container.viewData.remove(tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (container *viewsContainerData) Set(tag string, value any) bool {
|
|
||||||
return container.set(strings.ToLower(tag), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (container *viewsContainerData) set(tag string, value any) bool {
|
|
||||||
if value == nil {
|
|
||||||
container.remove(tag)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (container *viewsContainerData) setFunc(self View, tag PropertyName, value any) []PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case Content:
|
case Content:
|
||||||
return container.setContent(value)
|
if container.setContent(value) {
|
||||||
|
return []PropertyName{tag}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
case Disabled:
|
case Disabled:
|
||||||
oldDisabled := IsDisabled(container)
|
oldDisabled := IsDisabled(container)
|
||||||
if container.viewData.Set(Disabled, value) {
|
result := viewSet(self, Disabled, value)
|
||||||
|
if result != nil {
|
||||||
disabled := IsDisabled(container)
|
disabled := IsDisabled(container)
|
||||||
if oldDisabled != disabled {
|
if oldDisabled != disabled {
|
||||||
if container.views != nil {
|
|
||||||
for _, view := range container.views {
|
for _, view := range container.views {
|
||||||
view.Set(Disabled, disabled)
|
view.Set(Disabled, disabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
container.propertyChangedEvent(tag)
|
return result
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return container.viewData.set(tag, value)
|
return viewSet(self, tag, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func viewsContainerPropertyChanged(view View, tag PropertyName) {
|
||||||
|
switch tag {
|
||||||
|
case Content:
|
||||||
|
updateInnerHTML(view.htmlID(), view.Session())
|
||||||
|
|
||||||
|
default:
|
||||||
|
viewPropertyChanged(view, tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *viewsContainerData) setContent(value any) bool {
|
func (container *viewsContainerData) setContent(value any) bool {
|
||||||
|
@ -291,25 +289,16 @@ func (container *viewsContainerData) setContent(value any) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.created {
|
|
||||||
updateInnerHTML(htmlID, container.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
container.propertyChangedEvent(Content)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (container *viewsContainerData) Get(tag string) any {
|
func (container *viewsContainerData) get(view View, tag PropertyName) any {
|
||||||
return container.get(strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (container *viewsContainerData) get(tag string) any {
|
|
||||||
switch tag {
|
switch tag {
|
||||||
case Content:
|
case Content:
|
||||||
return container.views
|
return container.views
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return container.viewData.get(tag)
|
return viewGet(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue