forked from mbk-lab/rui_orig
Merge branch '0.9'
This commit is contained in:
commit
3c4315ed78
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,3 +1,18 @@
|
|||
# v0.9.0
|
||||
|
||||
* Requires go 1.18 or higher
|
||||
* The "interface{}" type replaced by "any"
|
||||
* Added SizeFunc interface and Function field to SizeUnit struct
|
||||
* Added MaxSize, MinSize, SumSize, SubSize, MulSize, DivSize, ClampSize functions
|
||||
* Added "list-row-gap", "list-column-gap", "accent-color", "tab-size", "overflow",
|
||||
"arrow", "arrow-align", "arrow-size", "arrow-width", and "arrow-offset" properties
|
||||
* Added "@ruiArrowSize" and "@ruiArrowWidth" constants to the default theme
|
||||
* Added Transition, Transitions, and SetTransition functions to the ViewStyle interface
|
||||
* Added GetListRowGap, GetListColumnGap, GetAccentColor, GetTabSize, GetOverflow, IsTimingFunctionValid, and GetTransitions functions
|
||||
* Changed GetTransition functions
|
||||
* Added the OpenURL function to the Session interface
|
||||
* Changed the type of the second argument of all Get functions to "subviewID ...string" (previously "subviewID string")
|
||||
|
||||
# v0.8.0
|
||||
|
||||
* Added "loaded-event" and "error-event" events to ImageView
|
||||
|
|
471
README-ru.md
471
README-ru.md
File diff suppressed because it is too large
Load Diff
|
@ -14,7 +14,7 @@ type absoluteLayoutData struct {
|
|||
// NewAbsoluteLayout create new AbsoluteLayout object and return it
|
||||
func NewAbsoluteLayout(session Session, params Params) AbsoluteLayout {
|
||||
view := new(absoluteLayoutData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ func newAbsoluteLayout(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of ViewsContainer by default values
|
||||
func (layout *absoluteLayoutData) Init(session Session) {
|
||||
layout.viewsContainerData.Init(session)
|
||||
func (layout *absoluteLayoutData) init(session Session) {
|
||||
layout.viewsContainerData.init(session)
|
||||
layout.tag = "AbsoluteLayout"
|
||||
layout.systemClass = "ruiAbsoluteLayout"
|
||||
}
|
||||
|
|
153
animation.go
153
animation.go
|
@ -55,16 +55,19 @@ const (
|
|||
// The animation plays forwards each cycle. In other words, each time the animation cycles,
|
||||
// the animation will reset to the beginning state and start over again. This is the default value.
|
||||
NormalAnimation = 0
|
||||
|
||||
// ReverseAnimation is value of the "animation-direction" property.
|
||||
// The animation plays backwards each cycle. In other words, each time the animation cycles,
|
||||
// the animation will reset to the end state and start over again. Animation steps are performed
|
||||
// backwards, and timing functions are also reversed.
|
||||
// For example, an "ease-in" timing function becomes "ease-out".
|
||||
ReverseAnimation = 1
|
||||
|
||||
// AlternateAnimation is value of the "animation-direction" property.
|
||||
// The animation reverses direction each cycle, with the first iteration being played forwards.
|
||||
// The count to determine if a cycle is even or odd starts at one.
|
||||
AlternateAnimation = 2
|
||||
|
||||
// AlternateReverseAnimation is value of the "animation-direction" property.
|
||||
// The animation reverses direction each cycle, with the first iteration being played backwards.
|
||||
// The count to determine if a cycle is even or odd starts at one.
|
||||
|
@ -107,11 +110,11 @@ type AnimatedProperty struct {
|
|||
// Tag is the name of the property
|
||||
Tag string
|
||||
// From is the initial value of the property
|
||||
From interface{}
|
||||
From any
|
||||
// To is the final value of the property
|
||||
To interface{}
|
||||
To any
|
||||
// KeyFrames is intermediate property values
|
||||
KeyFrames map[int]interface{}
|
||||
KeyFrames map[int]any
|
||||
}
|
||||
|
||||
type animationData struct {
|
||||
|
@ -184,7 +187,7 @@ func (animation *animationData) normalizeTag(tag string) string {
|
|||
return tag
|
||||
}
|
||||
|
||||
func (animation *animationData) Set(tag string, value interface{}) bool {
|
||||
func (animation *animationData) Set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
animation.Remove(tag)
|
||||
return true
|
||||
|
@ -285,7 +288,7 @@ func (animation *animationData) Set(tag string, value interface{}) bool {
|
|||
ErrorLogF(`key-frame "%d" is out of range`, n)
|
||||
} else {
|
||||
if result.KeyFrames == nil {
|
||||
result.KeyFrames = map[int]interface{}{n: node.Text()}
|
||||
result.KeyFrames = map[int]any{n: node.Text()}
|
||||
} else {
|
||||
result.KeyFrames[n] = node.Text()
|
||||
}
|
||||
|
@ -359,7 +362,7 @@ func (animation *animationData) Remove(tag string) {
|
|||
delete(animation.properties, animation.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (animation *animationData) Get(tag string) interface{} {
|
||||
func (animation *animationData) Get(tag string) any {
|
||||
return animation.getRaw(animation.normalizeTag(tag))
|
||||
}
|
||||
|
||||
|
@ -397,7 +400,7 @@ func (animation *animationData) animationCSS(session Session) string {
|
|||
|
||||
buffer.WriteString(animation.keyFramesName)
|
||||
|
||||
if duration, _ := floatProperty(animation, Duration, session, 1); duration > 0 {
|
||||
if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 {
|
||||
buffer.WriteString(fmt.Sprintf(" %gs ", duration))
|
||||
} else {
|
||||
buffer.WriteString(" 1s ")
|
||||
|
@ -405,7 +408,7 @@ func (animation *animationData) animationCSS(session Session) string {
|
|||
|
||||
buffer.WriteString(animation.timingFunctionCSS(session))
|
||||
|
||||
if delay, _ := floatProperty(animation, Delay, session, 0); delay > 0 {
|
||||
if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 {
|
||||
buffer.WriteString(fmt.Sprintf(" %gs", delay))
|
||||
} else {
|
||||
buffer.WriteString(" 0s")
|
||||
|
@ -435,7 +438,7 @@ func (animation *animationData) animationCSS(session Session) string {
|
|||
|
||||
func (animation *animationData) transitionCSS(buffer *strings.Builder, session Session) {
|
||||
|
||||
if duration, _ := floatProperty(animation, Duration, session, 1); duration > 0 {
|
||||
if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 {
|
||||
buffer.WriteString(fmt.Sprintf(" %gs ", duration))
|
||||
} else {
|
||||
buffer.WriteString(" 1s ")
|
||||
|
@ -443,7 +446,7 @@ func (animation *animationData) transitionCSS(buffer *strings.Builder, session S
|
|||
|
||||
buffer.WriteString(animation.timingFunctionCSS(session))
|
||||
|
||||
if delay, _ := floatProperty(animation, Delay, session, 0); delay > 0 {
|
||||
if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 {
|
||||
buffer.WriteString(fmt.Sprintf(" %gs", delay))
|
||||
}
|
||||
}
|
||||
|
@ -481,6 +484,8 @@ func (animation *animationData) writeTransitionString(tag string, buffer *string
|
|||
buffer.WriteRune('"')
|
||||
buffer.WriteString(timingFunction)
|
||||
buffer.WriteRune('"')
|
||||
} else {
|
||||
buffer.WriteString(timingFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -490,14 +495,14 @@ func (animation *animationData) writeTransitionString(tag string, buffer *string
|
|||
|
||||
func (animation *animationData) timingFunctionCSS(session Session) string {
|
||||
if timingFunction, ok := stringProperty(animation, TimingFunction, session); ok {
|
||||
if timingFunction, ok = session.resolveConstants(timingFunction); ok && validateTimingFunction(timingFunction) {
|
||||
if timingFunction, ok = session.resolveConstants(timingFunction); ok && isTimingFunctionValid(timingFunction) {
|
||||
return timingFunction
|
||||
}
|
||||
}
|
||||
return ("ease")
|
||||
}
|
||||
|
||||
func validateTimingFunction(timingFunction string) bool {
|
||||
func isTimingFunctionValid(timingFunction string) bool {
|
||||
switch timingFunction {
|
||||
case "", EaseTiming, EaseInTiming, EaseOutTiming, EaseInOutTiming, LinearTiming:
|
||||
return true
|
||||
|
@ -529,6 +534,14 @@ func validateTimingFunction(timingFunction string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// IsTimingFunctionValid returns "true" if the "timingFunction" argument is the valid timing function.
|
||||
func IsTimingFunctionValid(timingFunction string, session Session) bool {
|
||||
if timingFunc, ok := session.resolveConstants(strings.Trim(timingFunction, " \t\n")); ok {
|
||||
return isTimingFunctionValid(timingFunc)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (session *sessionData) registerAnimation(props []AnimatedProperty) string {
|
||||
|
||||
session.animationCounter++
|
||||
|
@ -602,7 +615,7 @@ func (session *sessionData) registerAnimation(props []AnimatedProperty) string {
|
|||
return name
|
||||
}
|
||||
|
||||
func (view *viewData) SetAnimated(tag string, value interface{}, animation Animation) bool {
|
||||
func (view *viewData) SetAnimated(tag string, value any, animation Animation) bool {
|
||||
if animation == nil {
|
||||
return view.Set(tag, value)
|
||||
}
|
||||
|
@ -659,11 +672,29 @@ func (style *viewStyle) transitionCSS(session Session) string {
|
|||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
convert := map[string]string{
|
||||
CellHeight: "grid-template-rows",
|
||||
CellWidth: "grid-template-columns",
|
||||
Row: "grid-row",
|
||||
Column: "grid-column",
|
||||
Clip: "clip-path",
|
||||
Shadow: "box-shadow",
|
||||
ColumnSeparator: "column-rule",
|
||||
FontName: "font",
|
||||
TextSize: "font-size",
|
||||
TextLineThickness: "text-decoration-thickness",
|
||||
}
|
||||
|
||||
for tag, animation := range style.transitions {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
|
||||
if cssTag, ok := convert[tag]; ok {
|
||||
buffer.WriteString(cssTag)
|
||||
} else {
|
||||
buffer.WriteString(tag)
|
||||
}
|
||||
animation.transitionCSS(buffer, session)
|
||||
}
|
||||
return buffer.String()
|
||||
|
@ -673,18 +704,42 @@ func (view *viewData) updateTransitionCSS() {
|
|||
updateCSSProperty(view.htmlID(), "transition", view.transitionCSS(view.Session()), view.Session())
|
||||
}
|
||||
|
||||
func (view *viewData) getTransitions() Params {
|
||||
result := Params{}
|
||||
for tag, animation := range view.transitions {
|
||||
func (style *viewStyle) Transition(tag string) Animation {
|
||||
if style.transitions != nil {
|
||||
if anim, ok := style.transitions[tag]; ok {
|
||||
return anim
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (style *viewStyle) Transitions() map[string]Animation {
|
||||
result := map[string]Animation{}
|
||||
for tag, animation := range style.transitions {
|
||||
result[tag] = animation
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (style *viewStyle) SetTransition(tag string, animation Animation) {
|
||||
if animation == nil {
|
||||
delete(style.transitions, tag)
|
||||
} else {
|
||||
style.transitions[tag] = animation
|
||||
}
|
||||
}
|
||||
|
||||
func (view *viewData) SetTransition(tag string, animation Animation) {
|
||||
view.viewStyle.SetTransition(tag, animation)
|
||||
if view.created {
|
||||
updateCSSProperty(view.htmlID(), "transition", view.transitionCSS(view.Session()), view.Session())
|
||||
}
|
||||
}
|
||||
|
||||
// SetAnimated sets the property with name "tag" of the "rootView" subview with "viewID" id by value. Result:
|
||||
// true - success,
|
||||
// false - error (incompatible type or invalid format of a string value, see AppLog).
|
||||
func SetAnimated(rootView View, viewID, tag string, value interface{}, animation Animation) bool {
|
||||
func SetAnimated(rootView View, viewID, tag string, value any, animation Animation) bool {
|
||||
if view := ViewByID(rootView, viewID); view != nil {
|
||||
return view.SetAnimated(tag, value, animation)
|
||||
}
|
||||
|
@ -692,58 +747,60 @@ func SetAnimated(rootView View, viewID, tag string, value interface{}, animation
|
|||
}
|
||||
|
||||
// IsAnimationPaused returns "true" if an animation of the subview is paused, "false" otherwise.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func IsAnimationPaused(view View, subviewID string) bool {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := boolStyledProperty(view, AnimationPaused); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func IsAnimationPaused(view View, subviewID ...string) bool {
|
||||
return boolStyledProperty(view, subviewID, AnimationPaused, false)
|
||||
}
|
||||
|
||||
// GetTransition returns the subview transitions. The result is always non-nil.
|
||||
// If the second argument (subviewID) is "" then transitions of the first argument (view) is returned
|
||||
func GetTransition(view View, subviewID string) Params {
|
||||
// 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
|
||||
func GetTransitions(view View, subviewID ...string) map[string]Animation {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
return view.Transitions()
|
||||
}
|
||||
|
||||
return map[string]Animation{}
|
||||
}
|
||||
|
||||
// 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
|
||||
func GetTransition(view View, subviewID, tag string) Animation {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
return view.getTransitions()
|
||||
return view.Transition(tag)
|
||||
}
|
||||
|
||||
return Params{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddTransition adds the transition for the subview property.
|
||||
// If the second argument (subviewID) 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 {
|
||||
if tag == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if tag != "" {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
|
||||
if view == nil {
|
||||
return false
|
||||
if view != nil {
|
||||
view.SetTransition(tag, animation)
|
||||
return true
|
||||
}
|
||||
|
||||
transitions := view.getTransitions()
|
||||
transitions[tag] = animation
|
||||
return view.Set(Transition, transitions)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetAnimation returns the subview animations. The result is always non-nil.
|
||||
// If the second argument (subviewID) is "" then transitions of the first argument (view) is returned
|
||||
func GetAnimation(view View, subviewID string) []Animation {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then transitions of the first argument (view) is returned
|
||||
func GetAnimation(view View, subviewID ...string) []Animation {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
|
|
|
@ -51,131 +51,6 @@ const (
|
|||
AnimationIterationEvent = "animation-iteration-event"
|
||||
)
|
||||
|
||||
func valueToAnimationListeners(value interface{}) ([]func(View, string), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(View, string):
|
||||
return []func(View, string){value}, true
|
||||
|
||||
case func(string):
|
||||
fn := func(_ View, event string) {
|
||||
value(event)
|
||||
}
|
||||
return []func(View, string){fn}, true
|
||||
|
||||
case func(View):
|
||||
fn := func(view View, _ string) {
|
||||
value(view)
|
||||
}
|
||||
return []func(View, string){fn}, true
|
||||
|
||||
case func():
|
||||
fn := func(View, string) {
|
||||
value()
|
||||
}
|
||||
return []func(View, string){fn}, true
|
||||
|
||||
case []func(View, string):
|
||||
if len(value) == 0 {
|
||||
return nil, true
|
||||
}
|
||||
for _, fn := range value {
|
||||
if fn == nil {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return value, true
|
||||
|
||||
case []func(string):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, string), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(_ View, event string) {
|
||||
v(event)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func(View):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, string), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(view View, _ string) {
|
||||
v(view)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func():
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, string), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(View, string) {
|
||||
v()
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, string), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(View, string):
|
||||
listeners[i] = v
|
||||
|
||||
case func(string):
|
||||
listeners[i] = func(_ View, event string) {
|
||||
v(event)
|
||||
}
|
||||
|
||||
case func(View):
|
||||
listeners[i] = func(view View, _ string) {
|
||||
v(view)
|
||||
}
|
||||
|
||||
case func():
|
||||
listeners[i] = func(View, string) {
|
||||
v()
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var transitionEvents = map[string]struct{ jsEvent, jsFunc string }{
|
||||
TransitionRunEvent: {jsEvent: "ontransitionrun", jsFunc: "transitionRunEvent"},
|
||||
TransitionStartEvent: {jsEvent: "ontransitionstart", jsFunc: "transitionStartEvent"},
|
||||
|
@ -183,8 +58,8 @@ var transitionEvents = map[string]struct{ jsEvent, jsFunc string }{
|
|||
TransitionCancelEvent: {jsEvent: "ontransitioncancel", jsFunc: "transitionCancelEvent"},
|
||||
}
|
||||
|
||||
func (view *viewData) setTransitionListener(tag string, value interface{}) bool {
|
||||
listeners, ok := valueToAnimationListeners(value)
|
||||
func (view *viewData) setTransitionListener(tag string, value any) bool {
|
||||
listeners, ok := valueToEventListeners[View, string](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
|
@ -212,20 +87,6 @@ func (view *viewData) removeTransitionListener(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func getAnimationListeners(view View, subviewID string, tag string) []func(View, string) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(tag); value != nil {
|
||||
if result, ok := value.([]func(View, string)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(View, string){}
|
||||
}
|
||||
|
||||
func transitionEventsHtml(view View, buffer *strings.Builder) {
|
||||
for tag, js := range transitionEvents {
|
||||
if value := view.getRaw(tag); value != nil {
|
||||
|
@ -250,7 +111,7 @@ func (view *viewData) handleTransitionEvents(tag string, data DataObject) {
|
|||
}
|
||||
}
|
||||
|
||||
for _, listener := range getAnimationListeners(view, "", tag) {
|
||||
for _, listener := range getEventListeners[View, string](view, nil, tag) {
|
||||
listener(view, property)
|
||||
}
|
||||
}
|
||||
|
@ -263,8 +124,8 @@ var animationEvents = map[string]struct{ jsEvent, jsFunc string }{
|
|||
AnimationCancelEvent: {jsEvent: "onanimationcancel", jsFunc: "animationCancelEvent"},
|
||||
}
|
||||
|
||||
func (view *viewData) setAnimationListener(tag string, value interface{}) bool {
|
||||
listeners, ok := valueToAnimationListeners(value)
|
||||
func (view *viewData) setAnimationListener(tag string, value any) bool {
|
||||
listeners, ok := valueToEventListeners[View, string](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
|
@ -303,10 +164,10 @@ func animationEventsHtml(view View, buffer *strings.Builder) {
|
|||
}
|
||||
|
||||
func (view *viewData) handleAnimationEvents(tag string, data DataObject) {
|
||||
if listeners := getAnimationListeners(view, "", tag); len(listeners) > 0 {
|
||||
if listeners := getEventListeners[View, string](view, nil, tag); len(listeners) > 0 {
|
||||
id := ""
|
||||
if name, ok := data.PropertyValue("name"); ok {
|
||||
for _, animation := range GetAnimation(view, "") {
|
||||
for _, animation := range GetAnimation(view) {
|
||||
if name == animation.animationName() {
|
||||
id, _ = stringProperty(animation, ID, view.Session())
|
||||
}
|
||||
|
@ -320,56 +181,56 @@ func (view *viewData) handleAnimationEvents(tag string, data DataObject) {
|
|||
|
||||
// GetTransitionRunListeners returns the "transition-run-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTransitionRunListeners(view View, subviewID string) []func(View, string) {
|
||||
return getAnimationListeners(view, subviewID, TransitionRunEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTransitionRunListeners(view View, subviewID ...string) []func(View, string) {
|
||||
return getEventListeners[View, string](view, subviewID, TransitionRunEvent)
|
||||
}
|
||||
|
||||
// GetTransitionStartListeners returns the "transition-start-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTransitionStartListeners(view View, subviewID string) []func(View, string) {
|
||||
return getAnimationListeners(view, subviewID, TransitionStartEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTransitionStartListeners(view View, subviewID ...string) []func(View, string) {
|
||||
return getEventListeners[View, string](view, subviewID, TransitionStartEvent)
|
||||
}
|
||||
|
||||
// GetTransitionEndListeners returns the "transition-end-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTransitionEndListeners(view View, subviewID string) []func(View, string) {
|
||||
return getAnimationListeners(view, subviewID, TransitionEndEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTransitionEndListeners(view View, subviewID ...string) []func(View, string) {
|
||||
return getEventListeners[View, string](view, subviewID, TransitionEndEvent)
|
||||
}
|
||||
|
||||
// GetTransitionCancelListeners returns the "transition-cancel-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTransitionCancelListeners(view View, subviewID string) []func(View, string) {
|
||||
return getAnimationListeners(view, subviewID, TransitionCancelEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTransitionCancelListeners(view View, subviewID ...string) []func(View, string) {
|
||||
return getEventListeners[View, string](view, subviewID, TransitionCancelEvent)
|
||||
}
|
||||
|
||||
// GetAnimationStartListeners returns the "animation-start-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetAnimationStartListeners(view View, subviewID string) []func(View, string) {
|
||||
return getAnimationListeners(view, subviewID, AnimationStartEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetAnimationStartListeners(view View, subviewID ...string) []func(View, string) {
|
||||
return getEventListeners[View, string](view, subviewID, AnimationStartEvent)
|
||||
}
|
||||
|
||||
// GetAnimationEndListeners returns the "animation-end-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetAnimationEndListeners(view View, subviewID string) []func(View, string) {
|
||||
return getAnimationListeners(view, subviewID, AnimationEndEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetAnimationEndListeners(view View, subviewID ...string) []func(View, string) {
|
||||
return getEventListeners[View, string](view, subviewID, AnimationEndEvent)
|
||||
}
|
||||
|
||||
// GetAnimationCancelListeners returns the "animation-cancel-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetAnimationCancelListeners(view View, subviewID string) []func(View, string) {
|
||||
return getAnimationListeners(view, subviewID, AnimationCancelEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetAnimationCancelListeners(view View, subviewID ...string) []func(View, string) {
|
||||
return getEventListeners[View, string](view, subviewID, AnimationCancelEvent)
|
||||
}
|
||||
|
||||
// GetAnimationIterationListeners returns the "animation-iteration-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetAnimationIterationListeners(view View, subviewID string) []func(View, string) {
|
||||
return getAnimationListeners(view, subviewID, AnimationIterationEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetAnimationIterationListeners(view View, subviewID ...string) []func(View, string) {
|
||||
return getEventListeners[View, string](view, subviewID, AnimationIterationEvent)
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func DebugLog(text string) {
|
|||
}
|
||||
|
||||
// DebugLogF print the text to the debug log
|
||||
func DebugLogF(format string, a ...interface{}) {
|
||||
func DebugLogF(format string, a ...any) {
|
||||
if debugLogFunc != nil {
|
||||
debugLogFunc(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func ErrorLog(text string) {
|
|||
}
|
||||
|
||||
// ErrorLogF print the text to the error log
|
||||
func ErrorLogF(format string, a ...interface{}) {
|
||||
func ErrorLogF(format string, a ...any) {
|
||||
lastError = fmt.Sprintf(format, a...)
|
||||
if errorLogFunc != nil {
|
||||
errorLogFunc(lastError)
|
||||
|
|
|
@ -1793,6 +1793,7 @@ function imageLoaded(element, event) {
|
|||
",natural-height=" + element.naturalHeight +
|
||||
",current-src=\"" + element.currentSrc + "\"}";
|
||||
sendMessage(message);
|
||||
scanElementsSize()
|
||||
}
|
||||
|
||||
function imageError(element, event) {
|
||||
|
|
|
@ -59,7 +59,6 @@ ul:focus {
|
|||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
.ruiRoot {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
|
|
|
@ -11,7 +11,7 @@ type audioPlayerData struct {
|
|||
// NewAudioPlayer create new MediaPlayer object and return it
|
||||
func NewAudioPlayer(session Session, params Params) AudioPlayer {
|
||||
view := new(audioPlayerData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
view.tag = "AudioPlayer"
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
|
@ -21,8 +21,8 @@ func newAudioPlayer(session Session) View {
|
|||
return NewAudioPlayer(session, nil)
|
||||
}
|
||||
|
||||
func (player *audioPlayerData) Init(session Session) {
|
||||
player.mediaPlayerData.Init(session)
|
||||
func (player *audioPlayerData) init(session Session) {
|
||||
player.mediaPlayerData.init(session)
|
||||
player.tag = "AudioPlayer"
|
||||
}
|
||||
|
||||
|
|
|
@ -81,22 +81,22 @@ func createBackground(obj DataObject) BackgroundElement {
|
|||
switch obj.Tag() {
|
||||
case "image":
|
||||
image := new(backgroundImage)
|
||||
image.properties = map[string]interface{}{}
|
||||
image.properties = map[string]any{}
|
||||
result = image
|
||||
|
||||
case "linear-gradient":
|
||||
gradient := new(backgroundLinearGradient)
|
||||
gradient.properties = map[string]interface{}{}
|
||||
gradient.properties = map[string]any{}
|
||||
result = gradient
|
||||
|
||||
case "radial-gradient":
|
||||
gradient := new(backgroundRadialGradient)
|
||||
gradient.properties = map[string]interface{}{}
|
||||
gradient.properties = map[string]any{}
|
||||
result = gradient
|
||||
|
||||
case "conic-gradient":
|
||||
gradient := new(backgroundConicGradient)
|
||||
gradient.properties = map[string]interface{}{}
|
||||
gradient.properties = map[string]any{}
|
||||
result = gradient
|
||||
|
||||
default:
|
||||
|
@ -118,7 +118,7 @@ func createBackground(obj DataObject) BackgroundElement {
|
|||
// NewBackgroundImage creates the new background image
|
||||
func NewBackgroundImage(params Params) BackgroundElement {
|
||||
result := new(backgroundImage)
|
||||
result.properties = map[string]interface{}{}
|
||||
result.properties = map[string]any{}
|
||||
for tag, value := range params {
|
||||
result.Set(tag, value)
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ func (image *backgroundImage) normalizeTag(tag string) string {
|
|||
return tag
|
||||
}
|
||||
|
||||
func (image *backgroundImage) Set(tag string, value interface{}) bool {
|
||||
func (image *backgroundImage) Set(tag string, value any) bool {
|
||||
tag = image.normalizeTag(tag)
|
||||
switch tag {
|
||||
case Attachment, Width, Height, Repeat, ImageHorizontalAlign, ImageVerticalAlign,
|
||||
|
@ -167,7 +167,7 @@ func (image *backgroundImage) Set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (image *backgroundImage) Get(tag string) interface{} {
|
||||
func (image *backgroundImage) Get(tag string) any {
|
||||
return image.backgroundElement.Get(image.normalizeTag(tag))
|
||||
}
|
||||
|
||||
|
@ -219,9 +219,9 @@ func (image *backgroundImage) cssStyle(session Session) string {
|
|||
|
||||
if width.Type != Auto || height.Type != Auto {
|
||||
buffer.WriteString(` / `)
|
||||
buffer.WriteString(width.cssString("auto"))
|
||||
buffer.WriteString(width.cssString("auto", session))
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(height.cssString("auto"))
|
||||
buffer.WriteString(height.cssString("auto", session))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,16 +12,16 @@ type backgroundConicGradient struct {
|
|||
type BackgroundGradientAngle struct {
|
||||
// Color - the color of the key angle. Must not be nil.
|
||||
// Can take a value of Color type or string (color constant or textual description of the color)
|
||||
Color interface{}
|
||||
Color any
|
||||
// Angle - the key angle. Optional (may be nil).
|
||||
// Can take a value of AngleUnit type or string (angle constant or textual description of the angle)
|
||||
Angle interface{}
|
||||
Angle any
|
||||
}
|
||||
|
||||
// NewBackgroundConicGradient creates the new background conic gradient
|
||||
func NewBackgroundConicGradient(params Params) BackgroundElement {
|
||||
result := new(backgroundConicGradient)
|
||||
result.properties = map[string]interface{}{}
|
||||
result.properties = map[string]any{}
|
||||
for tag, value := range params {
|
||||
result.Set(tag, value)
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ func (gradient *backgroundConicGradient) normalizeTag(tag string) string {
|
|||
return tag
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) Set(tag string, value interface{}) bool {
|
||||
func (gradient *backgroundConicGradient) Set(tag string, value any) bool {
|
||||
tag = gradient.normalizeTag(tag)
|
||||
switch tag {
|
||||
case CenterX, CenterY, Repeating, From:
|
||||
|
@ -153,7 +153,7 @@ func (gradient *backgroundConicGradient) Set(tag string, value interface{}) bool
|
|||
return false
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) stringToAngle(text string) (interface{}, bool) {
|
||||
func (gradient *backgroundConicGradient) stringToAngle(text string) (any, bool) {
|
||||
if text == "" {
|
||||
return nil, false
|
||||
} else if text[0] == '@' {
|
||||
|
@ -216,7 +216,7 @@ func (gradient *backgroundConicGradient) parseGradientText(value string) []Backg
|
|||
return vector
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) setGradient(value interface{}) bool {
|
||||
func (gradient *backgroundConicGradient) setGradient(value any) bool {
|
||||
if value == nil {
|
||||
delete(gradient.properties, Gradient)
|
||||
return true
|
||||
|
@ -262,7 +262,7 @@ func (gradient *backgroundConicGradient) setGradient(value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) Get(tag string) interface{} {
|
||||
func (gradient *backgroundConicGradient) Get(tag string) any {
|
||||
return gradient.backgroundElement.Get(gradient.normalizeTag(tag))
|
||||
}
|
||||
|
||||
|
@ -316,9 +316,9 @@ func (gradient *backgroundConicGradient) cssStyle(session Session) string {
|
|||
buffer.WriteRune(' ')
|
||||
}
|
||||
buffer.WriteString("at ")
|
||||
buffer.WriteString(x.cssString("50%"))
|
||||
buffer.WriteString(x.cssString("50%", session))
|
||||
buffer.WriteString(" ")
|
||||
buffer.WriteString(y.cssString("50%"))
|
||||
buffer.WriteString(y.cssString("50%", session))
|
||||
comma = true
|
||||
}
|
||||
|
||||
|
|
|
@ -50,10 +50,10 @@ const (
|
|||
type BackgroundGradientPoint struct {
|
||||
// Color - the color of the point. Must not be nil.
|
||||
// Can take a value of Color type or string (color constant or textual description of the color)
|
||||
Color interface{}
|
||||
Color any
|
||||
// Pos - the distance from the start of the gradient straight line. Optional (may be nil).
|
||||
// Can take a value of SizeUnit type or string (angle constant or textual description of the SizeUnit)
|
||||
Pos interface{}
|
||||
Pos any
|
||||
}
|
||||
|
||||
type backgroundGradient struct {
|
||||
|
@ -71,7 +71,7 @@ type backgroundRadialGradient struct {
|
|||
// NewBackgroundLinearGradient creates the new background linear gradient
|
||||
func NewBackgroundLinearGradient(params Params) BackgroundElement {
|
||||
result := new(backgroundLinearGradient)
|
||||
result.properties = map[string]interface{}{}
|
||||
result.properties = map[string]any{}
|
||||
for tag, value := range params {
|
||||
result.Set(tag, value)
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ func NewBackgroundLinearGradient(params Params) BackgroundElement {
|
|||
// NewBackgroundRadialGradient creates the new background radial gradient
|
||||
func NewBackgroundRadialGradient(params Params) BackgroundElement {
|
||||
result := new(backgroundRadialGradient)
|
||||
result.properties = map[string]interface{}{}
|
||||
result.properties = map[string]any{}
|
||||
for tag, value := range params {
|
||||
result.Set(tag, value)
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ func (gradient *backgroundGradient) parseGradientText(value string) []Background
|
|||
return points
|
||||
}
|
||||
|
||||
func (gradient *backgroundGradient) Set(tag string, value interface{}) bool {
|
||||
func (gradient *backgroundGradient) Set(tag string, value any) bool {
|
||||
|
||||
switch tag = strings.ToLower(tag); tag {
|
||||
case Repeating:
|
||||
|
@ -261,19 +261,18 @@ func (gradient *backgroundGradient) writeGradient(session Session, buffer *strin
|
|||
switch value := point.Pos.(type) {
|
||||
case string:
|
||||
if value != "" {
|
||||
if value[0] == '@' {
|
||||
value, _ = session.Constant(value[1:])
|
||||
}
|
||||
if value, ok := session.resolveConstants(value); ok {
|
||||
if pos, ok := StringToSizeUnit(value); ok && pos.Type != Auto {
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(pos.cssString(""))
|
||||
buffer.WriteString(pos.cssString("", session))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case SizeUnit:
|
||||
if value.Type != Auto {
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(value.cssString(""))
|
||||
buffer.WriteString(value.cssString("", session))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +295,7 @@ func (image *backgroundLinearGradient) Clone() BackgroundElement {
|
|||
return result
|
||||
}
|
||||
|
||||
func (gradient *backgroundLinearGradient) Set(tag string, value interface{}) bool {
|
||||
func (gradient *backgroundLinearGradient) Set(tag string, value any) bool {
|
||||
if strings.ToLower(tag) == Direction {
|
||||
switch value := value.(type) {
|
||||
case AngleUnit:
|
||||
|
@ -402,7 +401,7 @@ func (gradient *backgroundRadialGradient) normalizeTag(tag string) string {
|
|||
return tag
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) Set(tag string, value interface{}) bool {
|
||||
func (gradient *backgroundRadialGradient) Set(tag string, value any) bool {
|
||||
tag = gradient.normalizeTag(tag)
|
||||
switch tag {
|
||||
case RadialGradientRadius:
|
||||
|
@ -426,7 +425,7 @@ func (gradient *backgroundRadialGradient) Set(tag string, value interface{}) boo
|
|||
return true
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
switch len(value) {
|
||||
case 0:
|
||||
delete(gradient.properties, RadialGradientRadius)
|
||||
|
@ -477,7 +476,7 @@ func (gradient *backgroundRadialGradient) Set(tag string, value interface{}) boo
|
|||
return gradient.backgroundGradient.Set(tag, value)
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) Get(tag string) interface{} {
|
||||
func (gradient *backgroundRadialGradient) Get(tag string) any {
|
||||
return gradient.backgroundGradient.Get(gradient.normalizeTag(tag))
|
||||
}
|
||||
|
||||
|
@ -512,9 +511,9 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
|||
if r, ok := StringToSizeUnit(text); ok && r.Type != Auto {
|
||||
buffer.WriteString("ellipse ")
|
||||
shapeText = ""
|
||||
buffer.WriteString(r.cssString(""))
|
||||
buffer.WriteString(r.cssString("", session))
|
||||
buffer.WriteString(" ")
|
||||
buffer.WriteString(r.cssString(""))
|
||||
buffer.WriteString(r.cssString("", session))
|
||||
buffer.WriteString(" ")
|
||||
} else {
|
||||
ErrorLog(`Invalid radial gradient radius: ` + text)
|
||||
|
@ -539,9 +538,9 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
|||
if value.Type != Auto {
|
||||
buffer.WriteString("ellipse ")
|
||||
shapeText = ""
|
||||
buffer.WriteString(value.cssString(""))
|
||||
buffer.WriteString(value.cssString("", session))
|
||||
buffer.WriteString(" ")
|
||||
buffer.WriteString(value.cssString(""))
|
||||
buffer.WriteString(value.cssString("", session))
|
||||
buffer.WriteString(" ")
|
||||
}
|
||||
|
||||
|
@ -553,11 +552,11 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
|||
buffer.WriteString("ellipse ")
|
||||
shapeText = ""
|
||||
for i := 0; i < count; i++ {
|
||||
buffer.WriteString(value[i].cssString("50%"))
|
||||
buffer.WriteString(value[i].cssString("50%", session))
|
||||
buffer.WriteString(" ")
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
count := len(value)
|
||||
if count > 2 {
|
||||
count = 2
|
||||
|
@ -568,13 +567,13 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
|||
if value[i] != nil {
|
||||
switch value := value[i].(type) {
|
||||
case SizeUnit:
|
||||
buffer.WriteString(value.cssString("50%"))
|
||||
buffer.WriteString(value.cssString("50%", session))
|
||||
buffer.WriteString(" ")
|
||||
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok {
|
||||
if size, err := stringToSizeUnit(text); err == nil {
|
||||
buffer.WriteString(size.cssString("50%"))
|
||||
buffer.WriteString(size.cssString("50%", session))
|
||||
buffer.WriteString(" ")
|
||||
} else {
|
||||
buffer.WriteString("50% ")
|
||||
|
@ -597,9 +596,9 @@ func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
|||
buffer.WriteString(shapeText)
|
||||
}
|
||||
buffer.WriteString("at ")
|
||||
buffer.WriteString(x.cssString("50%"))
|
||||
buffer.WriteString(x.cssString("50%", session))
|
||||
buffer.WriteString(" ")
|
||||
buffer.WriteString(y.cssString("50%"))
|
||||
buffer.WriteString(y.cssString("50%", session))
|
||||
}
|
||||
|
||||
buffer.WriteString(", ")
|
||||
|
|
21
border.go
21
border.go
|
@ -64,9 +64,9 @@ type borderProperty struct {
|
|||
propertyList
|
||||
}
|
||||
|
||||
func newBorderProperty(value interface{}) BorderProperty {
|
||||
func newBorderProperty(value any) BorderProperty {
|
||||
border := new(borderProperty)
|
||||
border.properties = map[string]interface{}{}
|
||||
border.properties = map[string]any{}
|
||||
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
|
@ -131,7 +131,7 @@ func newBorderProperty(value interface{}) BorderProperty {
|
|||
// NewBorder creates the new BorderProperty
|
||||
func NewBorder(params Params) BorderProperty {
|
||||
border := new(borderProperty)
|
||||
border.properties = map[string]interface{}{}
|
||||
border.properties = map[string]any{}
|
||||
if params != nil {
|
||||
for _, tag := range []string{Style, Width, ColorTag, Left, Right, Top, Bottom,
|
||||
LeftStyle, RightStyle, TopStyle, BottomStyle,
|
||||
|
@ -213,7 +213,7 @@ func (border *borderProperty) writeString(buffer *strings.Builder, indent string
|
|||
buffer.WriteString("_{ ")
|
||||
comma := false
|
||||
|
||||
write := func(tag string, value interface{}) {
|
||||
write := func(tag string, value any) {
|
||||
if comma {
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
|
@ -430,7 +430,7 @@ func (border *borderProperty) Remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (border *borderProperty) Set(tag string, value interface{}) bool {
|
||||
func (border *borderProperty) Set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
border.Remove(tag)
|
||||
return true
|
||||
|
@ -512,7 +512,7 @@ func (border *borderProperty) Set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (border *borderProperty) Get(tag string) interface{} {
|
||||
func (border *borderProperty) Get(tag string) any {
|
||||
tag = border.normalizeTag(tag)
|
||||
|
||||
if result, ok := border.properties[tag]; ok {
|
||||
|
@ -658,11 +658,14 @@ func (border *borderProperty) cssWidth(builder cssBuilder, session Session) {
|
|||
borders.Top.Width == borders.Left.Width &&
|
||||
borders.Top.Width == borders.Bottom.Width {
|
||||
if borders.Top.Width.Type != Auto {
|
||||
builder.add("border-width", borders.Top.Width.cssString("0"))
|
||||
builder.add("border-width", borders.Top.Width.cssString("0", session))
|
||||
}
|
||||
} else {
|
||||
builder.addValues("border-width", " ", borders.Top.Width.cssString("0"),
|
||||
borders.Right.Width.cssString("0"), borders.Bottom.Width.cssString("0"), borders.Left.Width.cssString("0"))
|
||||
builder.addValues("border-width", " ",
|
||||
borders.Top.Width.cssString("0", session),
|
||||
borders.Right.Width.cssString("0", session),
|
||||
borders.Bottom.Width.cssString("0", session),
|
||||
borders.Left.Width.cssString("0", session))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
35
bounds.go
35
bounds.go
|
@ -20,7 +20,7 @@ type boundsPropertyData struct {
|
|||
// NewBoundsProperty creates the new BoundsProperty object
|
||||
func NewBoundsProperty(params Params) BoundsProperty {
|
||||
bounds := new(boundsPropertyData)
|
||||
bounds.properties = map[string]interface{}{}
|
||||
bounds.properties = map[string]any{}
|
||||
if params != nil {
|
||||
for _, tag := range []string{Top, Right, Bottom, Left} {
|
||||
if value, ok := params[tag]; ok {
|
||||
|
@ -79,7 +79,7 @@ func (bounds *boundsPropertyData) Remove(tag string) {
|
|||
bounds.propertyList.Remove(bounds.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (bounds *boundsPropertyData) Set(tag string, value interface{}) bool {
|
||||
func (bounds *boundsPropertyData) Set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
bounds.Remove(tag)
|
||||
return true
|
||||
|
@ -98,7 +98,7 @@ func (bounds *boundsPropertyData) Set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (bounds *boundsPropertyData) Get(tag string) interface{} {
|
||||
func (bounds *boundsPropertyData) Get(tag string) any {
|
||||
tag = bounds.normalizeTag(tag)
|
||||
if value, ok := bounds.properties[tag]; ok {
|
||||
return value
|
||||
|
@ -213,22 +213,25 @@ func (bounds *Bounds) String() string {
|
|||
bounds.Bottom.String() + "," + bounds.Left.String()
|
||||
}
|
||||
|
||||
func (bounds *Bounds) cssValue(tag string, builder cssBuilder) {
|
||||
func (bounds *Bounds) cssValue(tag string, builder cssBuilder, session Session) {
|
||||
if bounds.allFieldsEqual() {
|
||||
builder.add(tag, bounds.Top.cssString("0"))
|
||||
builder.add(tag, bounds.Top.cssString("0", session))
|
||||
} else {
|
||||
builder.addValues(tag, " ", bounds.Top.cssString("0"), bounds.Right.cssString("0"),
|
||||
bounds.Bottom.cssString("0"), bounds.Left.cssString("0"))
|
||||
builder.addValues(tag, " ",
|
||||
bounds.Top.cssString("0", session),
|
||||
bounds.Right.cssString("0", session),
|
||||
bounds.Bottom.cssString("0", session),
|
||||
bounds.Left.cssString("0", session))
|
||||
}
|
||||
}
|
||||
|
||||
func (bounds *Bounds) cssString() string {
|
||||
func (bounds *Bounds) cssString(session Session) string {
|
||||
var builder cssValueBuilder
|
||||
bounds.cssValue("", &builder)
|
||||
bounds.cssValue("", &builder, session)
|
||||
return builder.finish()
|
||||
}
|
||||
|
||||
func (properties *propertyList) setBounds(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) setBounds(tag string, value any) bool {
|
||||
if !properties.setSimpleProperty(tag, value) {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
|
@ -260,6 +263,12 @@ func (properties *propertyList) setBounds(tag string, value interface{}) bool {
|
|||
case SizeUnit:
|
||||
properties.properties[tag] = value
|
||||
|
||||
case float32:
|
||||
properties.properties[tag] = Px(float64(value))
|
||||
|
||||
case float64:
|
||||
properties.properties[tag] = Px(value)
|
||||
|
||||
case Bounds:
|
||||
bounds := NewBoundsProperty(nil)
|
||||
if value.Top.Type != Auto {
|
||||
|
@ -292,10 +301,14 @@ func (properties *propertyList) setBounds(tag string, value interface{}) bool {
|
|||
properties.properties[tag] = bounds
|
||||
|
||||
default:
|
||||
if n, ok := isInt(value); ok {
|
||||
properties.properties[tag] = Px(float64(n))
|
||||
} else {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -340,7 +353,7 @@ func (properties *propertyList) removeBoundsSide(mainTag, sideTag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (properties *propertyList) setBoundsSide(mainTag, sideTag string, value interface{}) bool {
|
||||
func (properties *propertyList) setBoundsSide(mainTag, sideTag string, value any) bool {
|
||||
bounds := properties.boundsProperty(mainTag)
|
||||
if bounds.Set(sideTag, value) {
|
||||
properties.properties[mainTag] = bounds
|
||||
|
|
|
@ -592,7 +592,7 @@ func (canvas *canvasData) writeFont(name string, script *strings.Builder) {
|
|||
|
||||
func (canvas *canvasData) SetFont(name string, size SizeUnit) {
|
||||
canvas.script.WriteString("\nctx.font = '")
|
||||
canvas.script.WriteString(size.cssString("1em"))
|
||||
canvas.script.WriteString(size.cssString("1rem", canvas.View().Session()))
|
||||
canvas.writeFont(name, &canvas.script)
|
||||
}
|
||||
|
||||
|
@ -616,7 +616,7 @@ func (canvas *canvasData) setFontWithParams(name string, size SizeUnit, params F
|
|||
}
|
||||
}
|
||||
|
||||
script.WriteString(size.cssString("1em"))
|
||||
script.WriteString(size.cssString("1rem", canvas.View().Session()))
|
||||
switch params.LineHeight.Type {
|
||||
case Auto:
|
||||
|
||||
|
@ -634,7 +634,7 @@ func (canvas *canvasData) setFontWithParams(name string, size SizeUnit, params F
|
|||
|
||||
default:
|
||||
script.WriteString("/")
|
||||
script.WriteString(params.LineHeight.cssString(""))
|
||||
script.WriteString(params.LineHeight.cssString("", canvas.View().Session()))
|
||||
}
|
||||
|
||||
canvas.writeFont(name, script)
|
||||
|
|
|
@ -21,7 +21,7 @@ type canvasViewData struct {
|
|||
// NewCanvasView creates the new custom draw view
|
||||
func NewCanvasView(session Session, params Params) CanvasView {
|
||||
view := new(canvasViewData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ func newCanvasView(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of ViewsContainer by default values
|
||||
func (canvasView *canvasViewData) Init(session Session) {
|
||||
canvasView.viewData.Init(session)
|
||||
func (canvasView *canvasViewData) init(session Session) {
|
||||
canvasView.viewData.init(session)
|
||||
canvasView.tag = "CanvasView"
|
||||
}
|
||||
|
||||
|
@ -63,11 +63,11 @@ func (canvasView *canvasViewData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (canvasView *canvasViewData) Set(tag string, value interface{}) bool {
|
||||
func (canvasView *canvasViewData) Set(tag string, value any) bool {
|
||||
return canvasView.set(canvasView.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (canvasView *canvasViewData) set(tag string, value interface{}) bool {
|
||||
func (canvasView *canvasViewData) set(tag string, value any) bool {
|
||||
if tag == DrawFunction {
|
||||
if value == nil {
|
||||
canvasView.drawer = nil
|
||||
|
@ -85,11 +85,11 @@ func (canvasView *canvasViewData) set(tag string, value interface{}) bool {
|
|||
return canvasView.viewData.set(tag, value)
|
||||
}
|
||||
|
||||
func (canvasView *canvasViewData) Get(tag string) interface{} {
|
||||
func (canvasView *canvasViewData) Get(tag string) any {
|
||||
return canvasView.get(canvasView.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (canvasView *canvasViewData) get(tag string) interface{} {
|
||||
func (canvasView *canvasViewData) get(tag string) any {
|
||||
if tag == DrawFunction {
|
||||
return canvasView.drawer
|
||||
}
|
||||
|
|
118
checkbox.go
118
checkbox.go
|
@ -23,7 +23,7 @@ type checkboxData struct {
|
|||
// NewCheckbox create new Checkbox object and return it
|
||||
func NewCheckbox(session Session, params Params) Checkbox {
|
||||
view := new(checkboxData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, Params{
|
||||
ClickEvent: checkboxClickListener,
|
||||
KeyDownEvent: checkboxKeyListener,
|
||||
|
@ -36,8 +36,8 @@ func newCheckbox(session Session) View {
|
|||
return NewCheckbox(session, nil)
|
||||
}
|
||||
|
||||
func (button *checkboxData) Init(session Session) {
|
||||
button.viewsContainerData.Init(session)
|
||||
func (button *checkboxData) init(session Session) {
|
||||
button.viewsContainerData.init(session)
|
||||
button.tag = "Checkbox"
|
||||
button.systemClass = "ruiGridLayout ruiCheckbox"
|
||||
button.checkedListeners = []func(Checkbox, bool){}
|
||||
|
@ -51,7 +51,7 @@ func (button *checkboxData) Focusable() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (button *checkboxData) Get(tag string) interface{} {
|
||||
func (button *checkboxData) Get(tag string) any {
|
||||
switch strings.ToLower(tag) {
|
||||
case CheckboxChangedEvent:
|
||||
return button.checkedListeners
|
||||
|
@ -60,11 +60,11 @@ func (button *checkboxData) Get(tag string) interface{} {
|
|||
return button.viewsContainerData.Get(tag)
|
||||
}
|
||||
|
||||
func (button *checkboxData) Set(tag string, value interface{}) bool {
|
||||
func (button *checkboxData) Set(tag string, value any) bool {
|
||||
return button.set(tag, value)
|
||||
}
|
||||
|
||||
func (button *checkboxData) set(tag string, value interface{}) bool {
|
||||
func (button *checkboxData) set(tag string, value any) bool {
|
||||
switch tag {
|
||||
case CheckboxChangedEvent:
|
||||
if !button.setChangedListener(value) {
|
||||
|
@ -194,80 +194,32 @@ func (button *checkboxData) changedCheckboxState(state bool) {
|
|||
}
|
||||
|
||||
func checkboxClickListener(view View) {
|
||||
view.Set(Checked, !IsCheckboxChecked(view, ""))
|
||||
view.Set(Checked, !IsCheckboxChecked(view))
|
||||
BlurView(view)
|
||||
}
|
||||
|
||||
func checkboxKeyListener(view View, event KeyEvent) {
|
||||
switch event.Code {
|
||||
case "Enter", "Space":
|
||||
view.Set(Checked, !IsCheckboxChecked(view, ""))
|
||||
view.Set(Checked, !IsCheckboxChecked(view))
|
||||
}
|
||||
}
|
||||
|
||||
func (button *checkboxData) setChangedListener(value interface{}) bool {
|
||||
if value == nil {
|
||||
if len(button.checkedListeners) > 0 {
|
||||
button.checkedListeners = []func(Checkbox, bool){}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(Checkbox, bool):
|
||||
button.checkedListeners = []func(Checkbox, bool){value}
|
||||
|
||||
case func(bool):
|
||||
fn := func(_ Checkbox, checked bool) {
|
||||
value(checked)
|
||||
}
|
||||
button.checkedListeners = []func(Checkbox, bool){fn}
|
||||
|
||||
case []func(Checkbox, bool):
|
||||
button.checkedListeners = value
|
||||
|
||||
case []func(bool):
|
||||
listeners := make([]func(Checkbox, bool), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
func (button *checkboxData) setChangedListener(value any) bool {
|
||||
listeners, ok := valueToEventListeners[Checkbox, bool](value)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(_ Checkbox, checked bool) {
|
||||
val(checked)
|
||||
}
|
||||
} else if listeners == nil {
|
||||
listeners = []func(Checkbox, bool){}
|
||||
}
|
||||
button.checkedListeners = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(Checkbox, bool), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case func(Checkbox, bool):
|
||||
listeners[i] = val
|
||||
|
||||
case func(bool):
|
||||
listeners[i] = func(_ Checkbox, date bool) {
|
||||
val(date)
|
||||
}
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
button.checkedListeners = listeners
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (button *checkboxData) cssStyle(self View, builder cssBuilder) {
|
||||
session := button.Session()
|
||||
vAlign, _ := enumStyledProperty(button, CheckboxVerticalAlign, LeftAlign)
|
||||
hAlign, _ := enumStyledProperty(button, CheckboxHorizontalAlign, TopAlign)
|
||||
vAlign := GetCheckboxVerticalAlign(button)
|
||||
hAlign := GetCheckboxHorizontalAlign(button)
|
||||
switch hAlign {
|
||||
case CenterAlign:
|
||||
if vAlign == BottomAlign {
|
||||
|
@ -284,7 +236,7 @@ func (button *checkboxData) cssStyle(self View, builder cssBuilder) {
|
|||
}
|
||||
|
||||
if gap, ok := sizeConstant(session, "ruiCheckboxGap"); ok && gap.Type != Auto && gap.Value > 0 {
|
||||
builder.add("gap", gap.cssString("0"))
|
||||
builder.add("gap", gap.cssString("0", session))
|
||||
}
|
||||
|
||||
builder.add("align-items", "stretch")
|
||||
|
@ -294,8 +246,8 @@ func (button *checkboxData) cssStyle(self View, builder cssBuilder) {
|
|||
}
|
||||
|
||||
func (button *checkboxData) htmlCheckbox(buffer *strings.Builder, checked bool) (int, int) {
|
||||
vAlign, _ := enumStyledProperty(button, CheckboxVerticalAlign, LeftAlign)
|
||||
hAlign, _ := enumStyledProperty(button, CheckboxHorizontalAlign, TopAlign)
|
||||
vAlign := GetCheckboxVerticalAlign(button)
|
||||
hAlign := GetCheckboxHorizontalAlign(button)
|
||||
|
||||
buffer.WriteString(`<div id="`)
|
||||
buffer.WriteString(button.htmlID())
|
||||
|
@ -339,7 +291,7 @@ func (button *checkboxData) htmlCheckbox(buffer *strings.Builder, checked bool)
|
|||
|
||||
func (button *checkboxData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||
|
||||
vCheckboxAlign, hCheckboxAlign := button.htmlCheckbox(buffer, IsCheckboxChecked(button, ""))
|
||||
vCheckboxAlign, hCheckboxAlign := button.htmlCheckbox(buffer, IsCheckboxChecked(button))
|
||||
|
||||
buffer.WriteString(`<div id="`)
|
||||
buffer.WriteString(button.htmlID())
|
||||
|
@ -370,7 +322,7 @@ func (button *checkboxData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
}
|
||||
|
||||
func (button *checkboxData) cssHorizontalAlign() string {
|
||||
align, _ := enumStyledProperty(button, HorizontalAlign, TopAlign)
|
||||
align := GetHorizontalAlign(button)
|
||||
values := enumProperties[CellHorizontalAlign].cssValues
|
||||
if align >= 0 && align < len(values) {
|
||||
return values[align]
|
||||
|
@ -379,7 +331,7 @@ func (button *checkboxData) cssHorizontalAlign() string {
|
|||
}
|
||||
|
||||
func (button *checkboxData) cssVerticalAlign() string {
|
||||
align, _ := enumStyledProperty(button, VerticalAlign, TopAlign)
|
||||
align := GetVerticalAlign(button)
|
||||
values := enumProperties[CellVerticalAlign].cssValues
|
||||
if align >= 0 && align < len(values) {
|
||||
return values[align]
|
||||
|
@ -388,17 +340,19 @@ func (button *checkboxData) cssVerticalAlign() string {
|
|||
}
|
||||
|
||||
// IsCheckboxChecked returns true if the Checkbox is checked, false otherwise.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func IsCheckboxChecked(view View, subviewID string) bool {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if checked := view.Get(Checked); checked != nil {
|
||||
if b, ok := checked.(bool); ok {
|
||||
return b
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func IsCheckboxChecked(view View, subviewID ...string) bool {
|
||||
return boolStyledProperty(view, subviewID, Checked, false)
|
||||
}
|
||||
|
||||
// GetCheckboxVerticalAlign return the vertical align of a Checkbox subview: TopAlign (0), BottomAlign (1), CenterAlign (2)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned
|
||||
func GetCheckboxVerticalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, LeftAlign, false)
|
||||
}
|
||||
|
||||
// GetCheckboxHorizontalAlign return the vertical align of a Checkbox subview: LeftAlign (0), RightAlign (1), CenterAlign (2)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned
|
||||
func GetCheckboxHorizontalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, TopAlign, false)
|
||||
}
|
||||
|
|
109
colorPicker.go
109
colorPicker.go
|
@ -23,7 +23,7 @@ type colorPickerData struct {
|
|||
// NewColorPicker create new ColorPicker object and return it
|
||||
func NewColorPicker(session Session, params Params) ColorPicker {
|
||||
view := new(colorPickerData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -32,8 +32,8 @@ func newColorPicker(session Session) View {
|
|||
return NewColorPicker(session, nil)
|
||||
}
|
||||
|
||||
func (picker *colorPickerData) Init(session Session) {
|
||||
picker.viewData.Init(session)
|
||||
func (picker *colorPickerData) init(session Session) {
|
||||
picker.viewData.init(session)
|
||||
picker.tag = "ColorPicker"
|
||||
picker.colorChangedListeners = []func(ColorPicker, Color){}
|
||||
picker.properties[Padding] = Px(0)
|
||||
|
@ -66,7 +66,7 @@ func (picker *colorPickerData) remove(tag string) {
|
|||
}
|
||||
|
||||
case ColorPickerValue:
|
||||
oldColor := GetColorPickerValue(picker, "")
|
||||
oldColor := GetColorPickerValue(picker)
|
||||
delete(picker.properties, ColorPickerValue)
|
||||
picker.colorChanged(oldColor)
|
||||
|
||||
|
@ -75,11 +75,11 @@ func (picker *colorPickerData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (picker *colorPickerData) Set(tag string, value interface{}) bool {
|
||||
func (picker *colorPickerData) Set(tag string, value any) bool {
|
||||
return picker.set(picker.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (picker *colorPickerData) set(tag string, value interface{}) bool {
|
||||
func (picker *colorPickerData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
picker.remove(tag)
|
||||
return true
|
||||
|
@ -87,62 +87,19 @@ func (picker *colorPickerData) set(tag string, value interface{}) bool {
|
|||
|
||||
switch tag {
|
||||
case ColorChangedEvent:
|
||||
switch value := value.(type) {
|
||||
case func(ColorPicker, Color):
|
||||
picker.colorChangedListeners = []func(ColorPicker, Color){value}
|
||||
|
||||
case func(Color):
|
||||
fn := func(_ ColorPicker, date Color) {
|
||||
value(date)
|
||||
}
|
||||
picker.colorChangedListeners = []func(ColorPicker, Color){fn}
|
||||
|
||||
case []func(ColorPicker, Color):
|
||||
picker.colorChangedListeners = value
|
||||
|
||||
case []func(Color):
|
||||
listeners := make([]func(ColorPicker, Color), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
listeners, ok := valueToEventListeners[ColorPicker, Color](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(_ ColorPicker, date Color) {
|
||||
val(date)
|
||||
}
|
||||
} else if listeners == nil {
|
||||
listeners = []func(ColorPicker, Color){}
|
||||
}
|
||||
picker.colorChangedListeners = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(ColorPicker, Color), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case func(ColorPicker, Color):
|
||||
listeners[i] = val
|
||||
|
||||
case func(Color):
|
||||
listeners[i] = func(_ ColorPicker, date Color) {
|
||||
val(date)
|
||||
}
|
||||
|
||||
default:
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
}
|
||||
picker.colorChangedListeners = listeners
|
||||
}
|
||||
picker.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
||||
case ColorPickerValue:
|
||||
oldColor := GetColorPickerValue(picker, "")
|
||||
oldColor := GetColorPickerValue(picker)
|
||||
if picker.setColorProperty(ColorPickerValue, value) {
|
||||
picker.colorChanged(oldColor)
|
||||
return true
|
||||
|
@ -155,7 +112,7 @@ func (picker *colorPickerData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
func (picker *colorPickerData) colorChanged(oldColor Color) {
|
||||
if newColor := GetColorPickerValue(picker, ""); oldColor != newColor {
|
||||
if newColor := GetColorPickerValue(picker); oldColor != newColor {
|
||||
if picker.created {
|
||||
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), newColor.rgbString()))
|
||||
}
|
||||
|
@ -166,11 +123,11 @@ func (picker *colorPickerData) colorChanged(oldColor Color) {
|
|||
}
|
||||
}
|
||||
|
||||
func (picker *colorPickerData) Get(tag string) interface{} {
|
||||
func (picker *colorPickerData) Get(tag string) any {
|
||||
return picker.get(picker.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (picker *colorPickerData) get(tag string) interface{} {
|
||||
func (picker *colorPickerData) get(tag string) any {
|
||||
switch tag {
|
||||
case ColorChangedEvent:
|
||||
return picker.colorChangedListeners
|
||||
|
@ -188,7 +145,7 @@ func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder
|
|||
picker.viewData.htmlProperties(self, buffer)
|
||||
|
||||
buffer.WriteString(` type="color" value="`)
|
||||
buffer.WriteString(GetColorPickerValue(picker, "").rgbString())
|
||||
buffer.WriteString(GetColorPickerValue(picker).rgbString())
|
||||
buffer.WriteByte('"')
|
||||
|
||||
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
||||
|
@ -198,7 +155,7 @@ func (picker *colorPickerData) htmlProperties(self View, buffer *strings.Builder
|
|||
}
|
||||
|
||||
func (picker *colorPickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
|
||||
if IsDisabled(self, "") {
|
||||
if IsDisabled(self) {
|
||||
buffer.WriteString(` disabled`)
|
||||
}
|
||||
picker.viewData.htmlDisabledProperties(self, buffer)
|
||||
|
@ -208,7 +165,7 @@ func (picker *colorPickerData) handleCommand(self View, command string, data Dat
|
|||
switch command {
|
||||
case "textChanged":
|
||||
if text, ok := data.PropertyValue("text"); ok {
|
||||
oldColor := GetColorPickerValue(picker, "")
|
||||
oldColor := GetColorPickerValue(picker)
|
||||
if color, ok := StringToColor(text); ok {
|
||||
picker.properties[ColorPickerValue] = color
|
||||
if color != oldColor {
|
||||
|
@ -225,16 +182,16 @@ func (picker *colorPickerData) handleCommand(self View, command string, data Dat
|
|||
}
|
||||
|
||||
// GetColorPickerValue returns the value of ColorPicker subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetColorPickerValue(view View, subviewID string) Color {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetColorPickerValue(view View, subviewID ...string) Color {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := colorStyledProperty(view, ColorPickerValue); ok {
|
||||
return result
|
||||
if value, ok := colorProperty(view, ColorPickerValue, view.Session()); ok {
|
||||
return value
|
||||
}
|
||||
for _, tag := range []string{Value, ColorTag} {
|
||||
for _, tag := range []string{ColorPickerValue, Value, ColorTag} {
|
||||
if value := valueFromStyle(view, tag); value != nil {
|
||||
if result, ok := valueToColor(value, view.Session()); ok {
|
||||
return result
|
||||
|
@ -247,17 +204,7 @@ func GetColorPickerValue(view View, subviewID string) Color {
|
|||
|
||||
// GetColorChangedListeners returns the ColorChangedListener list of an ColorPicker subview.
|
||||
// If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetColorChangedListeners(view View, subviewID string) []func(ColorPicker, Color) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(ColorChangedEvent); value != nil {
|
||||
if listeners, ok := value.([]func(ColorPicker, Color)); ok {
|
||||
return listeners
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(ColorPicker, Color){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetColorChangedListeners(view View, subviewID ...string) []func(ColorPicker, Color) {
|
||||
return getEventListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent)
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ type columnLayoutData struct {
|
|||
// NewColumnLayout create new ColumnLayout object and return it
|
||||
func NewColumnLayout(session Session, params Params) ColumnLayout {
|
||||
view := new(columnLayoutData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ func newColumnLayout(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of ColumnLayout by default values
|
||||
func (ColumnLayout *columnLayoutData) Init(session Session) {
|
||||
ColumnLayout.viewsContainerData.Init(session)
|
||||
func (ColumnLayout *columnLayoutData) init(session Session) {
|
||||
ColumnLayout.viewsContainerData.init(session)
|
||||
ColumnLayout.tag = "ColumnLayout"
|
||||
//ColumnLayout.systemClass = "ruiColumnLayout"
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func (columnLayout *columnLayoutData) normalizeTag(tag string) string {
|
|||
return tag
|
||||
}
|
||||
|
||||
func (columnLayout *columnLayoutData) Get(tag string) interface{} {
|
||||
func (columnLayout *columnLayoutData) Get(tag string) any {
|
||||
return columnLayout.get(columnLayout.normalizeTag(tag))
|
||||
}
|
||||
|
||||
|
@ -97,11 +97,11 @@ func (columnLayout *columnLayoutData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (columnLayout *columnLayoutData) Set(tag string, value interface{}) bool {
|
||||
func (columnLayout *columnLayoutData) Set(tag string, value any) bool {
|
||||
return columnLayout.set(columnLayout.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (columnLayout *columnLayoutData) set(tag string, value interface{}) bool {
|
||||
func (columnLayout *columnLayoutData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
columnLayout.remove(tag)
|
||||
return true
|
||||
|
@ -137,50 +137,26 @@ func (columnLayout *columnLayoutData) set(tag string, value interface{}) bool {
|
|||
// 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
|
||||
// based on the "column-width" property.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnCount(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return 0
|
||||
}
|
||||
result, _ := intStyledProperty(view, ColumnCount, 0)
|
||||
return result
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnCount(view View, subviewID ...string) int {
|
||||
return intStyledProperty(view, subviewID, ColumnCount, 0)
|
||||
}
|
||||
|
||||
// GetColumnWidth returns SizeUnit value which specifies the width of each column of ColumnLayout.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnWidth(view View, subviewID string) SizeUnit {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return AutoSize()
|
||||
}
|
||||
result, _ := sizeStyledProperty(view, ColumnWidth)
|
||||
return result
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnWidth(view View, subviewID ...string) SizeUnit {
|
||||
return sizeStyledProperty(view, subviewID, ColumnWidth, false)
|
||||
}
|
||||
|
||||
// GetColumnGap returns SizeUnit property which specifies the size of the gap (gutter) between columns of ColumnLayout.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnGap(view View, subviewID string) SizeUnit {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return AutoSize()
|
||||
}
|
||||
result, _ := sizeStyledProperty(view, ColumnGap)
|
||||
return result
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnGap(view View, subviewID ...string) SizeUnit {
|
||||
return sizeStyledProperty(view, subviewID, ColumnGap, false)
|
||||
}
|
||||
|
||||
// GetColumnSeparator returns ViewBorder struct which specifies the line drawn between
|
||||
// columns in a multi-column ColumnLayout.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnSeparator(view View, subviewID string) ViewBorder {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
func getColumnSeparator(view View, subviewID []string) ViewBorder {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
|
@ -199,27 +175,34 @@ func GetColumnSeparator(view View, subviewID string) ViewBorder {
|
|||
return ViewBorder{}
|
||||
}
|
||||
|
||||
// GetColumnSeparator returns ViewBorder struct which specifies the line drawn between
|
||||
// columns in a multi-column ColumnLayout.
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnSeparator(view View, subviewID ...string) ViewBorder {
|
||||
return getColumnSeparator(view, subviewID)
|
||||
}
|
||||
|
||||
// ColumnSeparatorStyle returns int value which specifies the style of the line drawn between
|
||||
// columns in a multi-column layout.
|
||||
// Valid values are NoneLine (0), SolidLine (1), DashedLine (2), DottedLine (3), and DoubleLine (4).
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnSeparatorStyle(view View, subviewID string) int {
|
||||
border := GetColumnSeparator(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnSeparatorStyle(view View, subviewID ...string) int {
|
||||
border := getColumnSeparator(view, subviewID)
|
||||
return border.Style
|
||||
}
|
||||
|
||||
// ColumnSeparatorWidth returns SizeUnit value which specifies the width of the line drawn between
|
||||
// columns in a multi-column layout.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnSeparatorWidth(view View, subviewID string) SizeUnit {
|
||||
border := GetColumnSeparator(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnSeparatorWidth(view View, subviewID ...string) SizeUnit {
|
||||
border := getColumnSeparator(view, subviewID)
|
||||
return border.Width
|
||||
}
|
||||
|
||||
// ColumnSeparatorColor returns Color value which specifies the color of the line drawn between
|
||||
// columns in a multi-column layout.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnSeparatorColor(view View, subviewID string) Color {
|
||||
border := GetColumnSeparator(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetColumnSeparatorColor(view View, subviewID ...string) Color {
|
||||
border := getColumnSeparator(view, subviewID)
|
||||
return border.Color
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@ type columnSeparatorProperty struct {
|
|||
propertyList
|
||||
}
|
||||
|
||||
func newColumnSeparatorProperty(value interface{}) ColumnSeparatorProperty {
|
||||
func newColumnSeparatorProperty(value any) ColumnSeparatorProperty {
|
||||
|
||||
if value == nil {
|
||||
separator := new(columnSeparatorProperty)
|
||||
separator.properties = map[string]interface{}{}
|
||||
separator.properties = map[string]any{}
|
||||
return separator
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ func newColumnSeparatorProperty(value interface{}) ColumnSeparatorProperty {
|
|||
|
||||
case DataObject:
|
||||
separator := new(columnSeparatorProperty)
|
||||
separator.properties = map[string]interface{}{}
|
||||
separator.properties = map[string]any{}
|
||||
for _, tag := range []string{Style, Width, ColorTag} {
|
||||
if val, ok := value.PropertyValue(tag); ok && val != "" {
|
||||
separator.set(tag, value)
|
||||
|
@ -42,7 +42,7 @@ func newColumnSeparatorProperty(value interface{}) ColumnSeparatorProperty {
|
|||
|
||||
case ViewBorder:
|
||||
separator := new(columnSeparatorProperty)
|
||||
separator.properties = map[string]interface{}{
|
||||
separator.properties = map[string]any{
|
||||
Style: value.Style,
|
||||
Width: value.Width,
|
||||
ColorTag: value.Color,
|
||||
|
@ -57,7 +57,7 @@ func newColumnSeparatorProperty(value interface{}) ColumnSeparatorProperty {
|
|||
// NewColumnSeparator creates the new ColumnSeparatorProperty
|
||||
func NewColumnSeparator(params Params) ColumnSeparatorProperty {
|
||||
separator := new(columnSeparatorProperty)
|
||||
separator.properties = map[string]interface{}{}
|
||||
separator.properties = map[string]any{}
|
||||
if params != nil {
|
||||
for _, tag := range []string{Style, Width, ColorTag} {
|
||||
if value, ok := params[tag]; ok && value != nil {
|
||||
|
@ -117,7 +117,7 @@ func (separator *columnSeparatorProperty) Remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (separator *columnSeparatorProperty) Set(tag string, value interface{}) bool {
|
||||
func (separator *columnSeparatorProperty) Set(tag string, value any) bool {
|
||||
tag = separator.normalizeTag(tag)
|
||||
|
||||
if value == nil {
|
||||
|
@ -140,7 +140,7 @@ func (separator *columnSeparatorProperty) Set(tag string, value interface{}) boo
|
|||
return false
|
||||
}
|
||||
|
||||
func (separator *columnSeparatorProperty) Get(tag string) interface{} {
|
||||
func (separator *columnSeparatorProperty) Get(tag string) any {
|
||||
tag = separator.normalizeTag(tag)
|
||||
|
||||
if result, ok := separator.properties[tag]; ok {
|
||||
|
@ -167,8 +167,9 @@ func (separator *columnSeparatorProperty) cssValue(session Session) string {
|
|||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
if value.Width.Type != Auto && value.Width.Type != SizeInFraction && value.Width.Value > 0 {
|
||||
buffer.WriteString(value.Width.cssString(""))
|
||||
if value.Width.Type != Auto && value.Width.Type != SizeInFraction &&
|
||||
(value.Width.Value > 0 || value.Width.Type == SizeFunction) {
|
||||
buffer.WriteString(value.Width.cssString("", session))
|
||||
}
|
||||
|
||||
styles := enumProperties[BorderStyle].cssValues
|
||||
|
|
|
@ -45,26 +45,26 @@ func (customView *CustomViewData) setTag(tag string) {
|
|||
|
||||
// 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.
|
||||
func (customView *CustomViewData) Get(tag string) interface{} {
|
||||
func (customView *CustomViewData) Get(tag string) any {
|
||||
return customView.superView.Get(tag)
|
||||
}
|
||||
|
||||
func (customView *CustomViewData) getRaw(tag string) interface{} {
|
||||
func (customView *CustomViewData) getRaw(tag string) any {
|
||||
return customView.superView.getRaw(tag)
|
||||
}
|
||||
|
||||
func (customView *CustomViewData) setRaw(tag string, value interface{}) {
|
||||
func (customView *CustomViewData) setRaw(tag string, value any) {
|
||||
customView.superView.setRaw(tag, value)
|
||||
}
|
||||
|
||||
// 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
|
||||
// a description of the error is written to the log
|
||||
func (customView *CustomViewData) Set(tag string, value interface{}) bool {
|
||||
func (customView *CustomViewData) Set(tag string, value any) bool {
|
||||
return customView.superView.Set(tag, value)
|
||||
}
|
||||
|
||||
func (customView *CustomViewData) SetAnimated(tag string, value interface{}, animation Animation) bool {
|
||||
func (customView *CustomViewData) SetAnimated(tag string, value any, animation Animation) bool {
|
||||
return customView.superView.SetAnimated(tag, value, animation)
|
||||
}
|
||||
|
||||
|
@ -87,10 +87,6 @@ func (customView *CustomViewData) Clear() {
|
|||
customView.superView.Clear()
|
||||
}
|
||||
|
||||
// Init initializes fields of View by default values
|
||||
func (customView *CustomViewData) Init(session Session) {
|
||||
}
|
||||
|
||||
func (customView *CustomViewData) cssViewStyle(buffer cssBuilder, session Session) {
|
||||
customView.superView.cssViewStyle(buffer, session)
|
||||
}
|
||||
|
@ -264,9 +260,22 @@ func (customView *CustomViewData) setScroll(x, y, width, height float64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (customView *CustomViewData) getTransitions() Params {
|
||||
func (customView *CustomViewData) Transition(tag string) Animation {
|
||||
if customView.superView != nil {
|
||||
return customView.superView.getTransitions()
|
||||
return customView.superView.Transition(tag)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (customView *CustomViewData) Transitions() map[string]Animation {
|
||||
if customView.superView != nil {
|
||||
return customView.superView.Transitions()
|
||||
}
|
||||
return map[string]Animation{}
|
||||
}
|
||||
|
||||
func (customView *CustomViewData) SetTransition(tag string, animation Animation) {
|
||||
if customView.superView != nil {
|
||||
customView.superView.SetTransition(tag, animation)
|
||||
}
|
||||
return Params{}
|
||||
}
|
||||
|
|
137
datePicker.go
137
datePicker.go
|
@ -29,7 +29,7 @@ type datePickerData struct {
|
|||
// NewDatePicker create new DatePicker object and return it
|
||||
func NewDatePicker(session Session, params Params) DatePicker {
|
||||
view := new(datePickerData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ func newDatePicker(session Session) View {
|
|||
return NewDatePicker(session, nil)
|
||||
}
|
||||
|
||||
func (picker *datePickerData) Init(session Session) {
|
||||
picker.viewData.Init(session)
|
||||
func (picker *datePickerData) init(session Session) {
|
||||
picker.viewData.init(session)
|
||||
picker.tag = "DatePicker"
|
||||
picker.dateChangedListeners = []func(DatePicker, time.Time){}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ func (picker *datePickerData) remove(tag string) {
|
|||
case DatePickerValue:
|
||||
if _, ok := picker.properties[DatePickerValue]; ok {
|
||||
delete(picker.properties, DatePickerValue)
|
||||
date := GetDatePickerValue(picker, "")
|
||||
date := GetDatePickerValue(picker)
|
||||
if picker.created {
|
||||
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), date.Format(dateFormat)))
|
||||
}
|
||||
|
@ -114,11 +114,11 @@ func (picker *datePickerData) remove(tag string) {
|
|||
picker.propertyChangedEvent(tag)
|
||||
}
|
||||
|
||||
func (picker *datePickerData) Set(tag string, value interface{}) bool {
|
||||
func (picker *datePickerData) Set(tag string, value any) bool {
|
||||
return picker.set(picker.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (picker *datePickerData) set(tag string, value interface{}) bool {
|
||||
func (picker *datePickerData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
picker.remove(tag)
|
||||
return true
|
||||
|
@ -204,9 +204,9 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
case DatePickerStep:
|
||||
oldStep := GetDatePickerStep(picker, "")
|
||||
oldStep := GetDatePickerStep(picker)
|
||||
if picker.setIntProperty(DatePickerStep, value) {
|
||||
if step := GetDatePickerStep(picker, ""); oldStep != step {
|
||||
if step := GetDatePickerStep(picker); oldStep != step {
|
||||
if picker.created {
|
||||
if step > 0 {
|
||||
updateProperty(picker.htmlID(), Step, strconv.Itoa(step), picker.session)
|
||||
|
@ -220,7 +220,7 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
case DatePickerValue:
|
||||
oldDate := GetDatePickerValue(picker, "")
|
||||
oldDate := GetDatePickerValue(picker)
|
||||
if date, ok := setTimeValue(DatePickerValue); ok {
|
||||
if date != oldDate {
|
||||
if picker.created {
|
||||
|
@ -235,57 +235,14 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
case DateChangedEvent:
|
||||
switch value := value.(type) {
|
||||
case func(DatePicker, time.Time):
|
||||
picker.dateChangedListeners = []func(DatePicker, time.Time){value}
|
||||
|
||||
case func(time.Time):
|
||||
fn := func(_ DatePicker, date time.Time) {
|
||||
value(date)
|
||||
}
|
||||
picker.dateChangedListeners = []func(DatePicker, time.Time){fn}
|
||||
|
||||
case []func(DatePicker, time.Time):
|
||||
picker.dateChangedListeners = value
|
||||
|
||||
case []func(time.Time):
|
||||
listeners := make([]func(DatePicker, time.Time), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
listeners, ok := valueToEventListeners[DatePicker, time.Time](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(_ DatePicker, date time.Time) {
|
||||
val(date)
|
||||
}
|
||||
} else if listeners == nil {
|
||||
listeners = []func(DatePicker, time.Time){}
|
||||
}
|
||||
picker.dateChangedListeners = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(DatePicker, time.Time), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case func(DatePicker, time.Time):
|
||||
listeners[i] = val
|
||||
|
||||
case func(time.Time):
|
||||
listeners[i] = func(_ DatePicker, date time.Time) {
|
||||
val(date)
|
||||
}
|
||||
|
||||
default:
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
}
|
||||
picker.dateChangedListeners = listeners
|
||||
}
|
||||
picker.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
||||
|
@ -295,11 +252,11 @@ func (picker *datePickerData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (picker *datePickerData) Get(tag string) interface{} {
|
||||
func (picker *datePickerData) Get(tag string) any {
|
||||
return picker.get(picker.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (picker *datePickerData) get(tag string) interface{} {
|
||||
func (picker *datePickerData) get(tag string) any {
|
||||
switch tag {
|
||||
case DateChangedEvent:
|
||||
return picker.dateChangedListeners
|
||||
|
@ -337,7 +294,7 @@ func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder)
|
|||
}
|
||||
|
||||
buffer.WriteString(` value="`)
|
||||
buffer.WriteString(GetDatePickerValue(picker, "").Format(dateFormat))
|
||||
buffer.WriteString(GetDatePickerValue(picker).Format(dateFormat))
|
||||
buffer.WriteByte('"')
|
||||
|
||||
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
||||
|
@ -347,7 +304,7 @@ func (picker *datePickerData) htmlProperties(self View, buffer *strings.Builder)
|
|||
}
|
||||
|
||||
func (picker *datePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
|
||||
if IsDisabled(self, "") {
|
||||
if IsDisabled(self) {
|
||||
buffer.WriteString(` disabled`)
|
||||
}
|
||||
picker.viewData.htmlDisabledProperties(self, buffer)
|
||||
|
@ -358,7 +315,7 @@ func (picker *datePickerData) handleCommand(self View, command string, data Data
|
|||
case "textChanged":
|
||||
if text, ok := data.PropertyValue("text"); ok {
|
||||
if value, err := time.Parse(dateFormat, text); err == nil {
|
||||
oldValue := GetDatePickerValue(picker, "")
|
||||
oldValue := GetDatePickerValue(picker)
|
||||
picker.properties[DatePickerValue] = value
|
||||
if value != oldValue {
|
||||
for _, listener := range picker.dateChangedListeners {
|
||||
|
@ -374,7 +331,7 @@ func (picker *datePickerData) handleCommand(self View, command string, data Data
|
|||
}
|
||||
|
||||
func getDateProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
||||
valueToTime := func(value interface{}) (time.Time, bool) {
|
||||
valueToTime := func(value any) (time.Time, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case time.Time:
|
||||
|
@ -408,10 +365,10 @@ func getDateProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
|||
|
||||
// GetDatePickerMin returns the min date of DatePicker subview and "true" as the second value if the min date is set,
|
||||
// "false" as the second value otherwise.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetDatePickerMin(view View, subviewID string) (time.Time, bool) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetDatePickerMin(view View, subviewID ...string) (time.Time, bool) {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
return getDateProperty(view, DatePickerMin, Min)
|
||||
|
@ -421,10 +378,10 @@ func GetDatePickerMin(view View, subviewID string) (time.Time, bool) {
|
|||
|
||||
// GetDatePickerMax returns the max date of DatePicker subview and "true" as the second value if the min date is set,
|
||||
// "false" as the second value otherwise.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetDatePickerMax(view View, subviewID string) (time.Time, bool) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetDatePickerMax(view View, subviewID ...string) (time.Time, bool) {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
return getDateProperty(view, DatePickerMax, Max)
|
||||
|
@ -433,24 +390,16 @@ func GetDatePickerMax(view View, subviewID string) (time.Time, bool) {
|
|||
}
|
||||
|
||||
// GetDatePickerStep returns the date changing step in days of DatePicker subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetDatePickerStep(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, _ := intStyledProperty(view, DatePickerStep, 0); result >= 0 {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return 0
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetDatePickerStep(view View, subviewID ...string) int {
|
||||
return intStyledProperty(view, subviewID, DatePickerStep, 0)
|
||||
}
|
||||
|
||||
// GetDatePickerValue returns the date of DatePicker subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetDatePickerValue(view View, subviewID string) time.Time {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetDatePickerValue(view View, subviewID ...string) time.Time {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view == nil {
|
||||
return time.Now()
|
||||
|
@ -461,17 +410,7 @@ func GetDatePickerValue(view View, subviewID string) time.Time {
|
|||
|
||||
// GetDateChangedListeners returns the DateChangedListener list of an DatePicker subview.
|
||||
// If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetDateChangedListeners(view View, subviewID string) []func(DatePicker, time.Time) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(DateChangedEvent); value != nil {
|
||||
if listeners, ok := value.([]func(DatePicker, time.Time)); ok {
|
||||
return listeners
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(DatePicker, time.Time){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetDateChangedListeners(view View, subviewID ...string) []func(DatePicker, time.Time) {
|
||||
return getEventListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent)
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ theme {
|
|||
ruiTabHeight = 32px,
|
||||
ruiTabBarPadding = 2px,
|
||||
ruiTabRadius = 2px,
|
||||
ruiArrowSize = 16px,
|
||||
ruiArrowWidth = 16px,
|
||||
},
|
||||
constants:touch = _{
|
||||
ruiButtonHorizontalPadding = 20px,
|
||||
|
@ -72,6 +74,7 @@ theme {
|
|||
text-size = 10pt,
|
||||
text-color = @ruiTextColor,
|
||||
background-color = @ruiBackgroundColor,
|
||||
accent-color = @ruiHighlightColor,
|
||||
},
|
||||
ruiButton {
|
||||
align = center,
|
||||
|
@ -216,7 +219,6 @@ theme {
|
|||
background-color = @ruiPopupBackgroundColor,
|
||||
text-color = @ruiPopupTextColor,
|
||||
radius = 4px,
|
||||
shadow = _{spread-radius=4px, blur=16px, color=@ruiPopupShadow },
|
||||
},
|
||||
ruiPopupTitle {
|
||||
background-color = @ruiPopupTitleColor,
|
||||
|
|
|
@ -24,7 +24,7 @@ type detailsViewData struct {
|
|||
// NewDetailsView create new DetailsView object and return it
|
||||
func NewDetailsView(session Session, params Params) DetailsView {
|
||||
view := new(detailsViewData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ func newDetailsView(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of DetailsView by default values
|
||||
func (detailsView *detailsViewData) Init(session Session) {
|
||||
detailsView.viewsContainerData.Init(session)
|
||||
func (detailsView *detailsViewData) init(session Session) {
|
||||
detailsView.viewsContainerData.init(session)
|
||||
detailsView.tag = "DetailsView"
|
||||
//detailsView.systemClass = "ruiDetailsView"
|
||||
}
|
||||
|
@ -68,11 +68,11 @@ func (detailsView *detailsViewData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (detailsView *detailsViewData) Set(tag string, value interface{}) bool {
|
||||
func (detailsView *detailsViewData) Set(tag string, value any) bool {
|
||||
return detailsView.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (detailsView *detailsViewData) set(tag string, value interface{}) bool {
|
||||
func (detailsView *detailsViewData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
detailsView.remove(tag)
|
||||
return true
|
||||
|
@ -110,7 +110,7 @@ func (detailsView *detailsViewData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
if detailsView.created {
|
||||
if IsDetailsExpanded(detailsView, "") {
|
||||
if IsDetailsExpanded(detailsView) {
|
||||
updateProperty(detailsView.htmlID(), "open", "", detailsView.Session())
|
||||
} else {
|
||||
removeProperty(detailsView.htmlID(), "open", detailsView.Session())
|
||||
|
@ -133,11 +133,11 @@ func (detailsView *detailsViewData) set(tag string, value interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (detailsView *detailsViewData) Get(tag string) interface{} {
|
||||
func (detailsView *detailsViewData) Get(tag string) any {
|
||||
return detailsView.get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (detailsView *detailsViewData) get(tag string) interface{} {
|
||||
func (detailsView *detailsViewData) get(tag string) any {
|
||||
return detailsView.viewsContainerData.get(tag)
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ func (detailsView *detailsViewData) htmlTag() string {
|
|||
func (detailsView *detailsViewData) htmlProperties(self View, buffer *strings.Builder) {
|
||||
detailsView.viewsContainerData.htmlProperties(self, buffer)
|
||||
buffer.WriteString(` ontoggle="detailsEvent(this)"`)
|
||||
if IsDetailsExpanded(detailsView, "") {
|
||||
if IsDetailsExpanded(detailsView) {
|
||||
buffer.WriteString(` open`)
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ func (detailsView *detailsViewData) htmlSubviews(self View, buffer *strings.Buil
|
|||
if value, ok := detailsView.properties[Summary]; ok {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if !GetNotTranslate(detailsView, "") {
|
||||
if !GetNotTranslate(detailsView) {
|
||||
value, _ = detailsView.session.GetString(value)
|
||||
}
|
||||
buffer.WriteString("<summary>")
|
||||
|
@ -186,10 +186,10 @@ func (detailsView *detailsViewData) handleCommand(self View, command string, dat
|
|||
}
|
||||
|
||||
// GetDetailsSummary returns a value of the Summary property of DetailsView.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetDetailsSummary(view View, subviewID string) View {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetDetailsSummary(view View, subviewID ...string) View {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(Summary); value != nil {
|
||||
|
@ -206,15 +206,7 @@ func GetDetailsSummary(view View, subviewID string) View {
|
|||
}
|
||||
|
||||
// IsDetailsExpanded returns a value of the Expanded property of DetailsView.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func IsDetailsExpanded(view View, subviewID string) bool {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := boolStyledProperty(view, Expanded); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func IsDetailsExpanded(view View, subviewID ...string) bool {
|
||||
return boolStyledProperty(view, subviewID, Expanded, false)
|
||||
}
|
||||
|
|
154
dropDownList.go
154
dropDownList.go
|
@ -6,6 +6,9 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// DropDownEvent is the constant for "drop-down-event" property tag.
|
||||
// The "drop-down-event" event occurs when a list item becomes selected.
|
||||
// The main listener format: func(DropDownList, int), where the second argument is the item index.
|
||||
const DropDownEvent = "drop-down-event"
|
||||
|
||||
// DropDownList - the interface of a drop-down list view
|
||||
|
@ -17,14 +20,14 @@ type DropDownList interface {
|
|||
type dropDownListData struct {
|
||||
viewData
|
||||
items []string
|
||||
disabledItems []interface{}
|
||||
disabledItems []any
|
||||
dropDownListener []func(DropDownList, int)
|
||||
}
|
||||
|
||||
// NewDropDownList create new DropDownList object and return it
|
||||
func NewDropDownList(session Session, params Params) DropDownList {
|
||||
view := new(dropDownListData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -33,11 +36,11 @@ func newDropDownList(session Session) View {
|
|||
return NewDropDownList(session, nil)
|
||||
}
|
||||
|
||||
func (list *dropDownListData) Init(session Session) {
|
||||
list.viewData.Init(session)
|
||||
func (list *dropDownListData) init(session Session) {
|
||||
list.viewData.init(session)
|
||||
list.tag = "DropDownList"
|
||||
list.items = []string{}
|
||||
list.disabledItems = []interface{}{}
|
||||
list.disabledItems = []any{}
|
||||
list.dropDownListener = []func(DropDownList, int){}
|
||||
}
|
||||
|
||||
|
@ -66,7 +69,7 @@ func (list *dropDownListData) remove(tag string) {
|
|||
|
||||
case DisabledItems:
|
||||
if len(list.disabledItems) > 0 {
|
||||
list.disabledItems = []interface{}{}
|
||||
list.disabledItems = []any{}
|
||||
if list.created {
|
||||
updateInnerHTML(list.htmlID(), list.session)
|
||||
}
|
||||
|
@ -80,7 +83,7 @@ func (list *dropDownListData) remove(tag string) {
|
|||
}
|
||||
|
||||
case Current:
|
||||
oldCurrent := GetCurrent(list, "")
|
||||
oldCurrent := GetCurrent(list)
|
||||
delete(list.properties, Current)
|
||||
if oldCurrent != 0 {
|
||||
if list.created {
|
||||
|
@ -95,11 +98,11 @@ func (list *dropDownListData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (list *dropDownListData) Set(tag string, value interface{}) bool {
|
||||
func (list *dropDownListData) Set(tag string, value any) bool {
|
||||
return list.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (list *dropDownListData) set(tag string, value interface{}) bool {
|
||||
func (list *dropDownListData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
list.remove(tag)
|
||||
return true
|
||||
|
@ -113,15 +116,24 @@ func (list *dropDownListData) set(tag string, value interface{}) bool {
|
|||
return list.setDisabledItems(value)
|
||||
|
||||
case DropDownEvent:
|
||||
return list.setDropDownListener(value)
|
||||
listeners, ok := valueToEventListeners[DropDownList, int](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
} else if listeners == nil {
|
||||
listeners = []func(DropDownList, int){}
|
||||
}
|
||||
list.dropDownListener = listeners
|
||||
list.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
||||
case Current:
|
||||
oldCurrent := GetCurrent(list, "")
|
||||
oldCurrent := GetCurrent(list)
|
||||
if !list.setIntProperty(Current, value) {
|
||||
return false
|
||||
}
|
||||
|
||||
if current := GetCurrent(list, ""); oldCurrent != current {
|
||||
if current := GetCurrent(list); oldCurrent != current {
|
||||
if list.created {
|
||||
list.session.runScript(fmt.Sprintf(`selectDropDownListItem('%s', %d)`, list.htmlID(), current))
|
||||
}
|
||||
|
@ -133,7 +145,7 @@ func (list *dropDownListData) set(tag string, value interface{}) bool {
|
|||
return list.viewData.set(tag, value)
|
||||
}
|
||||
|
||||
func (list *dropDownListData) setItems(value interface{}) bool {
|
||||
func (list *dropDownListData) setItems(value any) bool {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
list.items = []string{value}
|
||||
|
@ -155,7 +167,7 @@ func (list *dropDownListData) setItems(value interface{}) bool {
|
|||
list.items[i] = str.String()
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
items := make([]string, 0, len(value))
|
||||
for _, v := range value {
|
||||
switch val := v.(type) {
|
||||
|
@ -206,16 +218,16 @@ func (list *dropDownListData) setItems(value interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (list *dropDownListData) setDisabledItems(value interface{}) bool {
|
||||
func (list *dropDownListData) setDisabledItems(value any) bool {
|
||||
switch value := value.(type) {
|
||||
case []int:
|
||||
list.disabledItems = make([]interface{}, len(value))
|
||||
list.disabledItems = make([]any, len(value))
|
||||
for i, n := range value {
|
||||
list.disabledItems[i] = n
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
disabledItems := make([]interface{}, len(value))
|
||||
case []any:
|
||||
disabledItems := make([]any, len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(DisabledItems, value)
|
||||
|
@ -248,7 +260,7 @@ func (list *dropDownListData) setDisabledItems(value interface{}) bool {
|
|||
|
||||
case string:
|
||||
values := strings.Split(value, ",")
|
||||
disabledItems := make([]interface{}, len(values))
|
||||
disabledItems := make([]any, len(values))
|
||||
for i, str := range values {
|
||||
str = strings.Trim(str, " ")
|
||||
if str == "" {
|
||||
|
@ -291,69 +303,11 @@ func (list *dropDownListData) setDisabledItems(value interface{}) bool {
|
|||
|
||||
}
|
||||
|
||||
func (list *dropDownListData) setDropDownListener(value interface{}) bool {
|
||||
switch value := value.(type) {
|
||||
case func(DropDownList, int):
|
||||
list.dropDownListener = []func(DropDownList, int){value}
|
||||
|
||||
case func(int):
|
||||
list.dropDownListener = []func(DropDownList, int){func(_ DropDownList, index int) {
|
||||
value(index)
|
||||
}}
|
||||
|
||||
case []func(DropDownList, int):
|
||||
list.dropDownListener = value
|
||||
|
||||
case []func(int):
|
||||
listeners := make([]func(DropDownList, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(DropDownEvent, value)
|
||||
return false
|
||||
}
|
||||
listeners[i] = func(_ DropDownList, index int) {
|
||||
val(index)
|
||||
}
|
||||
}
|
||||
list.dropDownListener = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(DropDownList, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(DropDownEvent, value)
|
||||
return false
|
||||
}
|
||||
switch val := val.(type) {
|
||||
case func(DropDownList, int):
|
||||
listeners[i] = val
|
||||
|
||||
case func(int):
|
||||
listeners[i] = func(_ DropDownList, index int) {
|
||||
val(index)
|
||||
}
|
||||
|
||||
default:
|
||||
notCompatibleType(DropDownEvent, value)
|
||||
return false
|
||||
}
|
||||
}
|
||||
list.dropDownListener = listeners
|
||||
|
||||
default:
|
||||
notCompatibleType(DropDownEvent, value)
|
||||
return false
|
||||
}
|
||||
|
||||
list.propertyChangedEvent(DropDownEvent)
|
||||
return true
|
||||
}
|
||||
|
||||
func (list *dropDownListData) Get(tag string) interface{} {
|
||||
func (list *dropDownListData) Get(tag string) any {
|
||||
return list.get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (list *dropDownListData) get(tag string) interface{} {
|
||||
func (list *dropDownListData) get(tag string) any {
|
||||
switch tag {
|
||||
case Items:
|
||||
return list.items
|
||||
|
@ -382,9 +336,9 @@ func (list *dropDownListData) htmlTag() string {
|
|||
|
||||
func (list *dropDownListData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||
if list.items != nil {
|
||||
current := GetCurrent(list, "")
|
||||
notTranslate := GetNotTranslate(list, "")
|
||||
disabledItems := GetDropDownDisabledItems(list, "")
|
||||
current := GetCurrent(list)
|
||||
notTranslate := GetNotTranslate(list)
|
||||
disabledItems := GetDropDownDisabledItems(list)
|
||||
for i, item := range list.items {
|
||||
disabled := false
|
||||
for _, index := range disabledItems {
|
||||
|
@ -418,7 +372,7 @@ func (list *dropDownListData) htmlProperties(self View, buffer *strings.Builder)
|
|||
|
||||
func (list *dropDownListData) htmlDisabledProperties(self View, buffer *strings.Builder) {
|
||||
list.viewData.htmlDisabledProperties(self, buffer)
|
||||
if IsDisabled(list, "") {
|
||||
if IsDisabled(list) {
|
||||
buffer.WriteString(`disabled`)
|
||||
}
|
||||
}
|
||||
|
@ -435,7 +389,7 @@ func (list *dropDownListData) handleCommand(self View, command string, data Data
|
|||
case "itemSelected":
|
||||
if text, ok := data.PropertyValue("number"); ok {
|
||||
if number, err := strconv.Atoi(text); err == nil {
|
||||
if GetCurrent(list, "") != number && number >= 0 && number < len(list.items) {
|
||||
if GetCurrent(list) != number && number >= 0 && number < len(list.items) {
|
||||
list.properties[Current] = number
|
||||
list.onSelectedItemChanged(number)
|
||||
}
|
||||
|
@ -450,19 +404,17 @@ func (list *dropDownListData) handleCommand(self View, command string, data Data
|
|||
return true
|
||||
}
|
||||
|
||||
func GetDropDownListeners(view View) []func(DropDownList, int) {
|
||||
if value := view.Get(DropDownEvent); value != nil {
|
||||
if listeners, ok := value.([]func(DropDownList, int)); ok {
|
||||
return listeners
|
||||
}
|
||||
}
|
||||
return []func(DropDownList, int){}
|
||||
// GetDropDownListeners returns the "drop-down-event" listener 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.
|
||||
func GetDropDownListeners(view View, subviewID ...string) []func(DropDownList, int) {
|
||||
return getEventListeners[DropDownList, int](view, subviewID, DropDownEvent)
|
||||
}
|
||||
|
||||
// func GetDropDownItems return the view items list
|
||||
func GetDropDownItems(view View, subviewID string) []string {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// GetDropDownItems return the DropDownList items list.
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetDropDownItems(view View, subviewID ...string) []string {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
if list, ok := view.(DropDownList); ok {
|
||||
|
@ -472,14 +424,16 @@ func GetDropDownItems(view View, subviewID string) []string {
|
|||
return []string{}
|
||||
}
|
||||
|
||||
// func GetDropDownDisabledItems return the list of disabled item indexes
|
||||
func GetDropDownDisabledItems(view View, subviewID string) []int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// GetDropDownDisabledItems return the list of DropDownList disabled item indexes.
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetDropDownDisabledItems(view View, subviewID ...string) []int {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
if value := view.Get(DisabledItems); value != nil {
|
||||
if values, ok := value.([]interface{}); ok {
|
||||
if values, ok := value.([]any); ok {
|
||||
count := len(values)
|
||||
if count > 0 {
|
||||
result := make([]int, 0, count)
|
||||
|
|
279
editView.go
279
editView.go
|
@ -48,7 +48,7 @@ type editViewData struct {
|
|||
// NewEditView create new EditView object and return it
|
||||
func NewEditView(session Session, params Params) EditView {
|
||||
view := new(editViewData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ func newEditView(session Session) View {
|
|||
return NewEditView(session, nil)
|
||||
}
|
||||
|
||||
func (edit *editViewData) Init(session Session) {
|
||||
edit.viewData.Init(session)
|
||||
func (edit *editViewData) init(session Session) {
|
||||
edit.viewData.init(session)
|
||||
edit.textChangeListeners = []func(EditView, string){}
|
||||
edit.tag = "EditView"
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ func (edit *editViewData) remove(tag string) {
|
|||
|
||||
case Text:
|
||||
if exists {
|
||||
oldText := GetText(edit, "")
|
||||
oldText := GetText(edit)
|
||||
delete(edit.properties, tag)
|
||||
if oldText != "" {
|
||||
edit.textChanged("")
|
||||
|
@ -144,7 +144,7 @@ func (edit *editViewData) remove(tag string) {
|
|||
|
||||
case EditViewPattern:
|
||||
if exists {
|
||||
oldText := GetEditViewPattern(edit, "")
|
||||
oldText := GetEditViewPattern(edit)
|
||||
delete(edit.properties, tag)
|
||||
if oldText != "" {
|
||||
if edit.created {
|
||||
|
@ -156,7 +156,7 @@ func (edit *editViewData) remove(tag string) {
|
|||
|
||||
case EditViewType:
|
||||
if exists {
|
||||
oldType := GetEditViewType(edit, "")
|
||||
oldType := GetEditViewType(edit)
|
||||
delete(edit.properties, tag)
|
||||
if oldType != 0 {
|
||||
if edit.created {
|
||||
|
@ -168,10 +168,10 @@ func (edit *editViewData) remove(tag string) {
|
|||
|
||||
case EditWrap:
|
||||
if exists {
|
||||
oldWrap := IsEditViewWrap(edit, "")
|
||||
oldWrap := IsEditViewWrap(edit)
|
||||
delete(edit.properties, tag)
|
||||
if GetEditViewType(edit, "") == MultiLineText {
|
||||
if wrap := IsEditViewWrap(edit, ""); wrap != oldWrap {
|
||||
if GetEditViewType(edit) == MultiLineText {
|
||||
if wrap := IsEditViewWrap(edit); wrap != oldWrap {
|
||||
if edit.created {
|
||||
if wrap {
|
||||
updateProperty(edit.htmlID(), "wrap", "soft", edit.session)
|
||||
|
@ -190,11 +190,11 @@ func (edit *editViewData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (edit *editViewData) Set(tag string, value interface{}) bool {
|
||||
func (edit *editViewData) Set(tag string, value any) bool {
|
||||
return edit.set(edit.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (edit *editViewData) set(tag string, value interface{}) bool {
|
||||
func (edit *editViewData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
edit.remove(tag)
|
||||
return true
|
||||
|
@ -202,13 +202,13 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
|
|||
|
||||
switch tag {
|
||||
case Text:
|
||||
oldText := GetText(edit, "")
|
||||
oldText := GetText(edit)
|
||||
if text, ok := value.(string); ok {
|
||||
edit.properties[Text] = text
|
||||
if text = GetText(edit, ""); oldText != text {
|
||||
if text = GetText(edit); oldText != text {
|
||||
edit.textChanged(text)
|
||||
if edit.created {
|
||||
if GetEditViewType(edit, "") == MultiLineText {
|
||||
if GetEditViewType(edit) == MultiLineText {
|
||||
updateInnerHTML(edit.htmlID(), edit.Session())
|
||||
} else {
|
||||
text = strings.ReplaceAll(text, `"`, `\"`)
|
||||
|
@ -224,10 +224,10 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
|
||||
case Hint:
|
||||
oldText := GetHint(edit, "")
|
||||
oldText := GetHint(edit)
|
||||
if text, ok := value.(string); ok {
|
||||
edit.properties[Hint] = text
|
||||
if text = GetHint(edit, ""); oldText != text {
|
||||
if text = GetHint(edit); oldText != text {
|
||||
if edit.created {
|
||||
if text != "" {
|
||||
updateProperty(edit.htmlID(), "placeholder", text, edit.session)
|
||||
|
@ -242,9 +242,9 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
|
||||
case MaxLength:
|
||||
oldMaxLength := GetMaxLength(edit, "")
|
||||
oldMaxLength := GetMaxLength(edit)
|
||||
if edit.setIntProperty(MaxLength, value) {
|
||||
if maxLength := GetMaxLength(edit, ""); maxLength != oldMaxLength {
|
||||
if maxLength := GetMaxLength(edit); maxLength != oldMaxLength {
|
||||
if edit.created {
|
||||
if maxLength > 0 {
|
||||
updateProperty(edit.htmlID(), "maxlength", strconv.Itoa(maxLength), edit.session)
|
||||
|
@ -261,7 +261,7 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
|
|||
case ReadOnly:
|
||||
if edit.setBoolProperty(ReadOnly, value) {
|
||||
if edit.created {
|
||||
if IsReadOnly(edit, "") {
|
||||
if IsReadOnly(edit) {
|
||||
updateProperty(edit.htmlID(), ReadOnly, "", edit.session)
|
||||
} else {
|
||||
removeProperty(edit.htmlID(), ReadOnly, edit.session)
|
||||
|
@ -275,7 +275,7 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
|
|||
case Spellcheck:
|
||||
if edit.setBoolProperty(Spellcheck, value) {
|
||||
if edit.created {
|
||||
updateBoolProperty(edit.htmlID(), Spellcheck, IsSpellcheck(edit, ""), edit.session)
|
||||
updateBoolProperty(edit.htmlID(), Spellcheck, IsSpellcheck(edit), edit.session)
|
||||
}
|
||||
edit.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
@ -283,10 +283,10 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
|
||||
case EditViewPattern:
|
||||
oldText := GetEditViewPattern(edit, "")
|
||||
oldText := GetEditViewPattern(edit)
|
||||
if text, ok := value.(string); ok {
|
||||
edit.properties[EditViewPattern] = text
|
||||
if text = GetEditViewPattern(edit, ""); oldText != text {
|
||||
if text = GetEditViewPattern(edit); oldText != text {
|
||||
if edit.created {
|
||||
if text != "" {
|
||||
updateProperty(edit.htmlID(), Pattern, text, edit.session)
|
||||
|
@ -301,9 +301,9 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
|
||||
case EditViewType:
|
||||
oldType := GetEditViewType(edit, "")
|
||||
oldType := GetEditViewType(edit)
|
||||
if edit.setEnumProperty(EditViewType, value, enumProperties[EditViewType].values) {
|
||||
if GetEditViewType(edit, "") != oldType {
|
||||
if GetEditViewType(edit) != oldType {
|
||||
if edit.created {
|
||||
updateInnerHTML(edit.parentHTMLID(), edit.session)
|
||||
}
|
||||
|
@ -314,10 +314,10 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
|
||||
case EditWrap:
|
||||
oldWrap := IsEditViewWrap(edit, "")
|
||||
oldWrap := IsEditViewWrap(edit)
|
||||
if edit.setBoolProperty(EditWrap, value) {
|
||||
if GetEditViewType(edit, "") == MultiLineText {
|
||||
if wrap := IsEditViewWrap(edit, ""); wrap != oldWrap {
|
||||
if GetEditViewType(edit) == MultiLineText {
|
||||
if wrap := IsEditViewWrap(edit); wrap != oldWrap {
|
||||
if edit.created {
|
||||
if wrap {
|
||||
updateProperty(edit.htmlID(), "wrap", "soft", edit.session)
|
||||
|
@ -333,80 +333,34 @@ func (edit *editViewData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
|
||||
case EditTextChangedEvent:
|
||||
ok := edit.setChangeListeners(value)
|
||||
listeners, ok := valueToEventListeners[EditView, string](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
} else if listeners == nil {
|
||||
listeners = []func(EditView, string){}
|
||||
}
|
||||
edit.textChangeListeners = listeners
|
||||
edit.propertyChangedEvent(tag)
|
||||
return ok
|
||||
return true
|
||||
}
|
||||
|
||||
return edit.viewData.set(tag, value)
|
||||
}
|
||||
|
||||
func (edit *editViewData) setChangeListeners(value interface{}) bool {
|
||||
switch value := value.(type) {
|
||||
case func(EditView, string):
|
||||
edit.textChangeListeners = []func(EditView, string){value}
|
||||
|
||||
case func(string):
|
||||
fn := func(_ EditView, text string) {
|
||||
value(text)
|
||||
}
|
||||
edit.textChangeListeners = []func(EditView, string){fn}
|
||||
|
||||
case []func(EditView, string):
|
||||
edit.textChangeListeners = value
|
||||
|
||||
case []func(string):
|
||||
listeners := make([]func(EditView, string), len(value))
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
listeners[i] = func(_ EditView, text string) {
|
||||
v(text)
|
||||
}
|
||||
}
|
||||
edit.textChangeListeners = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(EditView, string), len(value))
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(EditView, string):
|
||||
listeners[i] = v
|
||||
|
||||
case func(string):
|
||||
listeners[i] = func(_ EditView, text string) {
|
||||
v(text)
|
||||
}
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
edit.textChangeListeners = listeners
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (edit *editViewData) Get(tag string) interface{} {
|
||||
func (edit *editViewData) Get(tag string) any {
|
||||
return edit.get(edit.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (edit *editViewData) get(tag string) interface{} {
|
||||
func (edit *editViewData) get(tag string) any {
|
||||
if tag == EditTextChangedEvent {
|
||||
return edit.textChangeListeners
|
||||
}
|
||||
return edit.viewData.get(tag)
|
||||
}
|
||||
|
||||
func (edit *editViewData) AppendText(text string) {
|
||||
if GetEditViewType(edit, "") == MultiLineText {
|
||||
if GetEditViewType(edit) == MultiLineText {
|
||||
if value := edit.getRaw(Text); value != nil {
|
||||
if textValue, ok := value.(string); ok {
|
||||
textValue += text
|
||||
|
@ -425,7 +379,7 @@ func (edit *editViewData) AppendText(text string) {
|
|||
}
|
||||
edit.set(Text, text)
|
||||
} else {
|
||||
edit.set(Text, GetText(edit, "")+text)
|
||||
edit.set(Text, GetText(edit)+text)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,7 +391,7 @@ func (edit *editViewData) textChanged(newText string) {
|
|||
}
|
||||
|
||||
func (edit *editViewData) htmlTag() string {
|
||||
if GetEditViewType(edit, "") == MultiLineText {
|
||||
if GetEditViewType(edit) == MultiLineText {
|
||||
return "textarea"
|
||||
}
|
||||
return "input"
|
||||
|
@ -447,14 +401,14 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
|
|||
edit.viewData.htmlProperties(self, buffer)
|
||||
|
||||
writeSpellcheck := func() {
|
||||
if spellcheck := IsSpellcheck(edit, ""); spellcheck {
|
||||
if spellcheck := IsSpellcheck(edit); spellcheck {
|
||||
buffer.WriteString(` spellcheck="true"`)
|
||||
} else {
|
||||
buffer.WriteString(` spellcheck="false"`)
|
||||
}
|
||||
}
|
||||
|
||||
editType := GetEditViewType(edit, "")
|
||||
editType := GetEditViewType(edit)
|
||||
switch editType {
|
||||
case SingleLineText:
|
||||
buffer.WriteString(` type="text" inputmode="text"`)
|
||||
|
@ -476,7 +430,7 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
|
|||
buffer.WriteString(` type="tel" inputmode="tel"`)
|
||||
|
||||
case MultiLineText:
|
||||
if IsEditViewWrap(edit, "") {
|
||||
if IsEditViewWrap(edit) {
|
||||
buffer.WriteString(` wrap="soft"`)
|
||||
} else {
|
||||
buffer.WriteString(` wrap="off"`)
|
||||
|
@ -484,11 +438,11 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
|
|||
writeSpellcheck()
|
||||
}
|
||||
|
||||
if IsReadOnly(edit, "") {
|
||||
if IsReadOnly(edit) {
|
||||
buffer.WriteString(` readonly`)
|
||||
}
|
||||
|
||||
if maxLength := GetMaxLength(edit, ""); maxLength > 0 {
|
||||
if maxLength := GetMaxLength(edit); maxLength > 0 {
|
||||
buffer.WriteString(` maxlength="`)
|
||||
buffer.WriteString(strconv.Itoa(maxLength))
|
||||
buffer.WriteByte('"')
|
||||
|
@ -501,21 +455,21 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
|
|||
return textToJS(text)
|
||||
}
|
||||
|
||||
if hint := GetHint(edit, ""); hint != "" {
|
||||
if hint := GetHint(edit); hint != "" {
|
||||
buffer.WriteString(` placeholder="`)
|
||||
buffer.WriteString(convertText(hint))
|
||||
buffer.WriteByte('"')
|
||||
}
|
||||
|
||||
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
||||
if pattern := GetEditViewPattern(edit, ""); pattern != "" {
|
||||
if pattern := GetEditViewPattern(edit); pattern != "" {
|
||||
buffer.WriteString(` pattern="`)
|
||||
buffer.WriteString(convertText(pattern))
|
||||
buffer.WriteByte('"')
|
||||
}
|
||||
|
||||
if editType != MultiLineText {
|
||||
if text := GetText(edit, ""); text != "" {
|
||||
if text := GetText(edit); text != "" {
|
||||
buffer.WriteString(` value="`)
|
||||
buffer.WriteString(convertText(text))
|
||||
buffer.WriteByte('"')
|
||||
|
@ -524,25 +478,25 @@ func (edit *editViewData) htmlProperties(self View, buffer *strings.Builder) {
|
|||
}
|
||||
|
||||
func (edit *editViewData) htmlDisabledProperties(self View, buffer *strings.Builder) {
|
||||
if IsDisabled(self, "") {
|
||||
if IsDisabled(self) {
|
||||
buffer.WriteString(` disabled`)
|
||||
}
|
||||
edit.viewData.htmlDisabledProperties(self, buffer)
|
||||
}
|
||||
|
||||
func (edit *editViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||
if GetEditViewType(edit, "") == MultiLineText {
|
||||
buffer.WriteString(textToJS(GetText(edit, "")))
|
||||
if GetEditViewType(edit) == MultiLineText {
|
||||
buffer.WriteString(textToJS(GetText(edit)))
|
||||
}
|
||||
}
|
||||
|
||||
func (edit *editViewData) handleCommand(self View, command string, data DataObject) bool {
|
||||
switch command {
|
||||
case "textChanged":
|
||||
oldText := GetText(edit, "")
|
||||
oldText := GetText(edit)
|
||||
if text, ok := data.PropertyValue("text"); ok {
|
||||
edit.properties[Text] = text
|
||||
if text := GetText(edit, ""); text != oldText {
|
||||
if text := GetText(edit); text != oldText {
|
||||
edit.textChanged(text)
|
||||
}
|
||||
}
|
||||
|
@ -553,10 +507,10 @@ func (edit *editViewData) handleCommand(self View, command string, data DataObje
|
|||
}
|
||||
|
||||
// GetText returns a text of the EditView subview.
|
||||
// If the second argument (subviewID) is "" then a text of the first argument (view) is returned.
|
||||
func GetText(view View, subviewID string) string {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a text of the first argument (view) is returned.
|
||||
func GetText(view View, subviewID ...string) string {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.getRaw(Text); value != nil {
|
||||
|
@ -569,10 +523,10 @@ func GetText(view View, subviewID string) string {
|
|||
}
|
||||
|
||||
// GetHint returns a hint text of the subview.
|
||||
// If the second argument (subviewID) is "" then a text of the first argument (view) is returned.
|
||||
func GetHint(view View, subviewID string) string {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a text of the first argument (view) is returned.
|
||||
func GetHint(view View, subviewID ...string) string {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
if text, ok := stringProperty(view, Hint, view.Session()); ok {
|
||||
|
@ -590,82 +544,41 @@ func GetHint(view View, subviewID string) string {
|
|||
}
|
||||
|
||||
// GetMaxLength returns a maximal lenght of EditView. If a maximal lenght is not limited then 0 is returned
|
||||
// If the second argument (subviewID) is "" then a value of the first argument (view) is returned.
|
||||
func GetMaxLength(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := intStyledProperty(view, MaxLength, 0); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return 0
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value of the first argument (view) is returned.
|
||||
func GetMaxLength(view View, subviewID ...string) int {
|
||||
return intStyledProperty(view, subviewID, MaxLength, 0)
|
||||
}
|
||||
|
||||
// IsReadOnly returns the true if a EditView works in read only mode.
|
||||
// If the second argument (subviewID) is "" then a value of the first argument (view) is returned.
|
||||
func IsReadOnly(view View, subviewID string) bool {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := boolStyledProperty(view, ReadOnly); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value of the first argument (view) is returned.
|
||||
func IsReadOnly(view View, subviewID ...string) bool {
|
||||
return boolStyledProperty(view, subviewID, ReadOnly, false)
|
||||
}
|
||||
|
||||
// IsSpellcheck returns a value of the Spellcheck property of EditView.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func IsSpellcheck(view View, subviewID string) bool {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if spellcheck, ok := boolStyledProperty(view, Spellcheck); ok {
|
||||
return spellcheck
|
||||
}
|
||||
}
|
||||
return false
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func IsSpellcheck(view View, subviewID ...string) bool {
|
||||
return boolStyledProperty(view, subviewID, Spellcheck, false)
|
||||
}
|
||||
|
||||
// GetTextChangedListeners returns the TextChangedListener list of an EditView or MultiLineEditView subview.
|
||||
// If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTextChangedListeners(view View, subviewID string) []func(EditView, string) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(EditTextChangedEvent); value != nil {
|
||||
if result, ok := value.([]func(EditView, string)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(EditView, string){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTextChangedListeners(view View, subviewID ...string) []func(EditView, string) {
|
||||
return getEventListeners[EditView, string](view, subviewID, EditTextChangedEvent)
|
||||
}
|
||||
|
||||
// GetEditViewType returns a value of the Type property of EditView.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetEditViewType(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return SingleLineText
|
||||
}
|
||||
t, _ := enumStyledProperty(view, EditViewType, SingleLineText)
|
||||
return t
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetEditViewType(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, EditViewType, SingleLineText, false)
|
||||
}
|
||||
|
||||
// GetEditViewPattern returns a value of the Pattern property of EditView.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetEditViewPattern(view View, subviewID string) string {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetEditViewPattern(view View, subviewID ...string) string {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
if pattern, ok := stringProperty(view, EditViewPattern, view.Session()); ok {
|
||||
|
@ -683,22 +596,13 @@ func GetEditViewPattern(view View, subviewID string) string {
|
|||
}
|
||||
|
||||
// IsEditViewWrap returns a value of the EditWrap property of MultiLineEditView.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func IsEditViewWrap(view View, subviewID string) bool {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if wrap, ok := boolStyledProperty(view, EditWrap); ok {
|
||||
return wrap
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func IsEditViewWrap(view View, subviewID ...string) bool {
|
||||
return boolStyledProperty(view, subviewID, EditWrap, false)
|
||||
}
|
||||
|
||||
// AppendEditText appends the text to the EditView content.
|
||||
// If the second argument (subviewID) 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 AppendEditText(view View, subviewID string, text string) {
|
||||
if subviewID != "" {
|
||||
if edit := EditViewByID(view, subviewID); edit != nil {
|
||||
|
@ -713,14 +617,7 @@ func AppendEditText(view View, subviewID string, text string) {
|
|||
}
|
||||
|
||||
// GetCaretColor returns the color of the text input carret.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetCaretColor(view View, subviewID string) Color {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return 0
|
||||
}
|
||||
t, _ := colorStyledProperty(view, CaretColor)
|
||||
return t
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetCaretColor(view View, subviewID ...string) Color {
|
||||
return colorStyledProperty(view, subviewID, CaretColor, false)
|
||||
}
|
||||
|
|
116
filePicker.go
116
filePicker.go
|
@ -72,7 +72,7 @@ func (file *FileInfo) initBy(node DataValue) {
|
|||
// NewFilePicker create new FilePicker object and return it
|
||||
func NewFilePicker(session Session, params Params) FilePicker {
|
||||
view := new(filePickerData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -81,8 +81,8 @@ func newFilePicker(session Session) View {
|
|||
return NewFilePicker(session, nil)
|
||||
}
|
||||
|
||||
func (picker *filePickerData) Init(session Session) {
|
||||
picker.viewData.Init(session)
|
||||
func (picker *filePickerData) init(session Session) {
|
||||
picker.viewData.init(session)
|
||||
picker.tag = "FilePicker"
|
||||
picker.files = []FileInfo{}
|
||||
picker.loader = map[int]func(FileInfo, []byte){}
|
||||
|
@ -139,11 +139,11 @@ func (picker *filePickerData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (picker *filePickerData) Set(tag string, value interface{}) bool {
|
||||
func (picker *filePickerData) Set(tag string, value any) bool {
|
||||
return picker.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (picker *filePickerData) set(tag string, value interface{}) bool {
|
||||
func (picker *filePickerData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
picker.remove(tag)
|
||||
return true
|
||||
|
@ -151,57 +151,14 @@ func (picker *filePickerData) set(tag string, value interface{}) bool {
|
|||
|
||||
switch tag {
|
||||
case FileSelectedEvent:
|
||||
switch value := value.(type) {
|
||||
case func(FilePicker, []FileInfo):
|
||||
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){value}
|
||||
|
||||
case func([]FileInfo):
|
||||
fn := func(_ FilePicker, files []FileInfo) {
|
||||
value(files)
|
||||
}
|
||||
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){fn}
|
||||
|
||||
case []func(FilePicker, []FileInfo):
|
||||
picker.fileSelectedListeners = value
|
||||
|
||||
case []func([]FileInfo):
|
||||
listeners := make([]func(FilePicker, []FileInfo), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
listeners, ok := valueToEventListeners[FilePicker, []FileInfo](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(_ FilePicker, files []FileInfo) {
|
||||
val(files)
|
||||
}
|
||||
} else if listeners == nil {
|
||||
listeners = []func(FilePicker, []FileInfo){}
|
||||
}
|
||||
picker.fileSelectedListeners = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(FilePicker, []FileInfo), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case func(FilePicker, []FileInfo):
|
||||
listeners[i] = val
|
||||
|
||||
case func([]FileInfo):
|
||||
listeners[i] = func(_ FilePicker, files []FileInfo) {
|
||||
val(files)
|
||||
}
|
||||
|
||||
default:
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
}
|
||||
picker.fileSelectedListeners = listeners
|
||||
}
|
||||
picker.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
||||
|
@ -294,7 +251,7 @@ func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder)
|
|||
}
|
||||
|
||||
buffer.WriteString(` type="file"`)
|
||||
if multiple, ok := boolStyledProperty(picker, Multiple); ok && multiple {
|
||||
if IsMultipleFilePicker(picker) {
|
||||
buffer.WriteString(` multiple`)
|
||||
}
|
||||
|
||||
|
@ -305,7 +262,7 @@ func (picker *filePickerData) htmlProperties(self View, buffer *strings.Builder)
|
|||
}
|
||||
|
||||
func (picker *filePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
|
||||
if IsDisabled(self, "") {
|
||||
if IsDisabled(self) {
|
||||
buffer.WriteString(` disabled`)
|
||||
}
|
||||
picker.viewData.htmlDisabledProperties(self, buffer)
|
||||
|
@ -377,9 +334,14 @@ func (picker *filePickerData) handleCommand(self View, command string, data Data
|
|||
|
||||
// GetFilePickerFiles returns the list of FilePicker selected files
|
||||
// If there are no files selected then an empty slice is returned (the result is always not nil)
|
||||
// If the second argument (subviewID) is "" then selected files of the first argument (view) is returned
|
||||
func GetFilePickerFiles(view View, subviewID string) []FileInfo {
|
||||
if picker := FilePickerByID(view, subviewID); picker != nil {
|
||||
// If the second argument (subviewID) is not specified or it is "" then selected files of the first argument (view) is returned
|
||||
func GetFilePickerFiles(view View, subviewID ...string) []FileInfo {
|
||||
subview := ""
|
||||
if len(subviewID) > 0 {
|
||||
subview = subviewID[0]
|
||||
}
|
||||
|
||||
if picker := FilePickerByID(view, subview); picker != nil {
|
||||
return picker.Files()
|
||||
}
|
||||
return []FileInfo{}
|
||||
|
@ -395,24 +357,16 @@ func LoadFilePickerFile(view View, subviewID string, file FileInfo, result func(
|
|||
}
|
||||
|
||||
// IsMultipleFilePicker returns "true" if multiple files can be selected in the FilePicker, "false" otherwise.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func IsMultipleFilePicker(view View, subviewID string) bool {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := boolStyledProperty(view, Multiple); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func IsMultipleFilePicker(view View, subviewID ...string) bool {
|
||||
return boolStyledProperty(view, subviewID, Multiple, false)
|
||||
}
|
||||
|
||||
// GetFilePickerAccept returns sets the list of allowed file extensions or MIME types.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetFilePickerAccept(view View, subviewID string) []string {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetFilePickerAccept(view View, subviewID ...string) []string {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
accept, ok := stringProperty(view, Accept, view.Session())
|
||||
|
@ -434,17 +388,7 @@ func GetFilePickerAccept(view View, subviewID string) []string {
|
|||
|
||||
// GetFileSelectedListeners returns the "file-selected-event" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetFileSelectedListeners(view View, subviewID string) []func(FilePicker, []FileInfo) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(FileSelectedEvent); value != nil {
|
||||
if result, ok := value.([]func(FilePicker, []FileInfo)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(FilePicker, []FileInfo){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetFileSelectedListeners(view View, subviewID ...string) []func(FilePicker, []FileInfo) {
|
||||
return getEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent)
|
||||
}
|
||||
|
|
|
@ -20,22 +20,22 @@ const (
|
|||
LostFocusEvent = "lost-focus-event"
|
||||
)
|
||||
|
||||
func valueToFocusListeners(value interface{}) ([]func(View), bool) {
|
||||
func valueToNoParamListeners[V any](value any) ([]func(V), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(View):
|
||||
return []func(View){value}, true
|
||||
case func(V):
|
||||
return []func(V){value}, true
|
||||
|
||||
case func():
|
||||
fn := func(View) {
|
||||
fn := func(V) {
|
||||
value()
|
||||
}
|
||||
return []func(View){fn}, true
|
||||
return []func(V){fn}, true
|
||||
|
||||
case []func(View):
|
||||
case []func(V):
|
||||
if len(value) == 0 {
|
||||
return nil, true
|
||||
}
|
||||
|
@ -51,33 +51,33 @@ func valueToFocusListeners(value interface{}) ([]func(View), bool) {
|
|||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View), count)
|
||||
listeners := make([]func(V), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(View) {
|
||||
listeners[i] = func(V) {
|
||||
v()
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View), count)
|
||||
listeners := make([]func(V), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(View):
|
||||
case func(V):
|
||||
listeners[i] = v
|
||||
|
||||
case func():
|
||||
listeners[i] = func(View) {
|
||||
listeners[i] = func(V) {
|
||||
v()
|
||||
}
|
||||
|
||||
|
@ -96,8 +96,8 @@ var focusEvents = map[string]struct{ jsEvent, jsFunc string }{
|
|||
LostFocusEvent: {jsEvent: "onblur", jsFunc: "blurEvent"},
|
||||
}
|
||||
|
||||
func (view *viewData) setFocusListener(tag string, value interface{}) bool {
|
||||
listeners, ok := valueToFocusListeners(value)
|
||||
func (view *viewData) setFocusListener(tag string, value any) bool {
|
||||
listeners, ok := valueToNoParamListeners[View](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
|
@ -125,10 +125,11 @@ func (view *viewData) removeFocusListener(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func getFocusListeners(view View, subviewID string, tag string) []func(View) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
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 {
|
||||
|
@ -148,13 +149,13 @@ func focusEventsHtml(view View, buffer *strings.Builder) {
|
|||
}
|
||||
|
||||
// GetFocusListeners returns a FocusListener list. If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetFocusListeners(view View, subviewID string) []func(View) {
|
||||
// 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) {
|
||||
return getFocusListeners(view, subviewID, FocusEvent)
|
||||
}
|
||||
|
||||
// GetLostFocusListeners returns a LostFocusListener list. If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetLostFocusListeners(view View, subviewID string) []func(View) {
|
||||
// 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) {
|
||||
return getFocusListeners(view, subviewID, LostFocusEvent)
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,5 +1,5 @@
|
|||
module github.com/anoshenko/rui
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
require github.com/gorilla/websocket v1.5.0
|
||||
|
|
128
gridLayout.go
128
gridLayout.go
|
@ -17,7 +17,7 @@ type gridLayoutData struct {
|
|||
// NewGridLayout create new GridLayout object and return it
|
||||
func NewGridLayout(session Session, params Params) GridLayout {
|
||||
view := new(gridLayoutData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ func newGridLayout(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of GridLayout by default values
|
||||
func (gridLayout *gridLayoutData) Init(session Session) {
|
||||
gridLayout.viewsContainerData.Init(session)
|
||||
func (gridLayout *gridLayoutData) init(session Session) {
|
||||
gridLayout.viewsContainerData.init(session)
|
||||
gridLayout.tag = "GridLayout"
|
||||
gridLayout.systemClass = "ruiGridLayout"
|
||||
}
|
||||
|
@ -37,15 +37,17 @@ func (gridLayout *gridLayoutData) String() string {
|
|||
return getViewString(gridLayout)
|
||||
}
|
||||
|
||||
func (style *viewStyle) setGridCellSize(tag string, value interface{}) bool {
|
||||
func (style *viewStyle) setGridCellSize(tag string, value any) bool {
|
||||
setValues := func(values []string) bool {
|
||||
count := len(values)
|
||||
if count > 1 {
|
||||
sizes := make([]interface{}, count)
|
||||
sizes := make([]any, count)
|
||||
for i, val := range values {
|
||||
val = strings.Trim(val, " \t\n\r")
|
||||
if isConstantName(val) {
|
||||
sizes[i] = val
|
||||
} else if fn := parseSizeFunc(val); fn != nil {
|
||||
sizes[i] = SizeUnit{Type: SizeFunction, Function: fn}
|
||||
} else if size, err := stringToSizeUnit(val); err == nil {
|
||||
sizes[i] = size
|
||||
} else {
|
||||
|
@ -99,13 +101,13 @@ func (style *viewStyle) setGridCellSize(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
invalidPropertyValue(tag, value)
|
||||
return false
|
||||
}
|
||||
sizes := make([]interface{}, count)
|
||||
sizes := make([]any, count)
|
||||
for i, val := range value {
|
||||
switch val := val.(type) {
|
||||
case SizeUnit:
|
||||
|
@ -145,7 +147,7 @@ func (style *viewStyle) gridCellSizesCSS(tag string, session Session) string {
|
|||
|
||||
case 1:
|
||||
if cellSize[0].Type != Auto {
|
||||
return `repeat(auto-fill, ` + cellSize[0].cssString(`auto`) + `)`
|
||||
return `repeat(auto-fill, ` + cellSize[0].cssString(`auto`, session) + `)`
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -161,14 +163,14 @@ func (style *viewStyle) gridCellSizesCSS(tag string, session Session) string {
|
|||
}
|
||||
if !allAuto {
|
||||
if allEqual {
|
||||
return fmt.Sprintf(`repeat(%d, %s)`, len(cellSize), cellSize[0].cssString(`auto`))
|
||||
return fmt.Sprintf(`repeat(%d, %s)`, len(cellSize), cellSize[0].cssString(`auto`, session))
|
||||
}
|
||||
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
for _, size := range cellSize {
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(size.cssString(`auto`))
|
||||
buffer.WriteString(size.cssString(`auto`, session))
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
@ -195,14 +197,14 @@ func (gridLayout *gridLayoutData) normalizeTag(tag string) string {
|
|||
return tag
|
||||
}
|
||||
|
||||
func (gridLayout *gridLayoutData) Get(tag string) interface{} {
|
||||
func (gridLayout *gridLayoutData) Get(tag string) any {
|
||||
return gridLayout.get(gridLayout.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (gridLayout *gridLayoutData) get(tag string) interface{} {
|
||||
func (gridLayout *gridLayoutData) get(tag string) any {
|
||||
if tag == Gap {
|
||||
rowGap := GetGridRowGap(gridLayout, "")
|
||||
columnGap := GetGridColumnGap(gridLayout, "")
|
||||
rowGap := GetGridRowGap(gridLayout)
|
||||
columnGap := GetGridColumnGap(gridLayout)
|
||||
if rowGap.Equal(columnGap) {
|
||||
return rowGap
|
||||
}
|
||||
|
@ -239,22 +241,18 @@ func (gridLayout *gridLayoutData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (gridLayout *gridLayoutData) Set(tag string, value interface{}) bool {
|
||||
func (gridLayout *gridLayoutData) Set(tag string, value any) bool {
|
||||
return gridLayout.set(gridLayout.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (gridLayout *gridLayoutData) set(tag string, value interface{}) bool {
|
||||
func (gridLayout *gridLayoutData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
gridLayout.remove(tag)
|
||||
return true
|
||||
}
|
||||
|
||||
if tag == Gap {
|
||||
if gridLayout.set(GridRowGap, value) && gridLayout.set(GridColumnGap, value) {
|
||||
gridLayout.propertyChangedEvent(Gap)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return gridLayout.set(GridRowGap, value) && gridLayout.set(GridColumnGap, value)
|
||||
}
|
||||
|
||||
if gridLayout.viewsContainerData.set(tag, value) {
|
||||
|
@ -285,7 +283,7 @@ func gridCellSizes(properties Properties, tag string, session Session) []SizeUni
|
|||
case SizeUnit:
|
||||
return []SizeUnit{value}
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
result := make([]SizeUnit, len(value))
|
||||
for i, val := range value {
|
||||
result[i] = AutoSize()
|
||||
|
@ -323,53 +321,29 @@ func (gridLayout *gridLayoutData) cssStyle(self View, builder cssBuilder) {
|
|||
*/
|
||||
|
||||
// GetCellVerticalAlign returns the vertical align of a GridLayout cell content: TopAlign (0), BottomAlign (1), CenterAlign (2), StretchAlign (3)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetCellVerticalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if align, ok := enumStyledProperty(view, CellVerticalAlign, StretchAlign); ok {
|
||||
return align
|
||||
}
|
||||
}
|
||||
return StretchAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetCellVerticalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, CellVerticalAlign, StretchAlign, false)
|
||||
}
|
||||
|
||||
// GetCellHorizontalAlign returns the vertical align of a GridLayout cell content: LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetCellHorizontalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if align, ok := enumStyledProperty(view, CellHorizontalAlign, StretchAlign); ok {
|
||||
return align
|
||||
}
|
||||
}
|
||||
return StretchAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetCellHorizontalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, CellHorizontalAlign, StretchAlign, false)
|
||||
}
|
||||
|
||||
// GetGridAutoFlow returns the value of the "grid-auto-flow" property
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetGridAutoFlow(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if align, ok := enumStyledProperty(view, GridAutoFlow, 0); ok {
|
||||
return align
|
||||
}
|
||||
}
|
||||
return 0
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetGridAutoFlow(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, GridAutoFlow, 0, false)
|
||||
}
|
||||
|
||||
// GetCellWidth returns the width of a GridLayout cell. If the result is an empty array, then the width is not set.
|
||||
// If the result is a single value array, then the width of all cell is equal.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetCellWidth(view View, subviewID string) []SizeUnit {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetCellWidth(view View, subviewID ...string) []SizeUnit {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
return gridCellSizes(view, CellWidth, view.Session())
|
||||
|
@ -379,10 +353,10 @@ func GetCellWidth(view View, subviewID string) []SizeUnit {
|
|||
|
||||
// GetCellHeight returns the height of a GridLayout cell. If the result is an empty array, then the height is not set.
|
||||
// If the result is a single value array, then the height of all cell is equal.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetCellHeight(view View, subviewID string) []SizeUnit {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetCellHeight(view View, subviewID ...string) []SizeUnit {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
return gridCellSizes(view, CellHeight, view.Session())
|
||||
|
@ -391,29 +365,13 @@ func GetCellHeight(view View, subviewID string) []SizeUnit {
|
|||
}
|
||||
|
||||
// GetGridRowGap returns the gap between GridLayout rows.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetGridRowGap(view View, subviewID string) SizeUnit {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := sizeStyledProperty(view, GridRowGap); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return AutoSize()
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetGridRowGap(view View, subviewID ...string) SizeUnit {
|
||||
return sizeStyledProperty(view, subviewID, GridRowGap, false)
|
||||
}
|
||||
|
||||
// GetGridColumnGap returns the gap between GridLayout columns.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetGridColumnGap(view View, subviewID string) SizeUnit {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := sizeStyledProperty(view, GridColumnGap); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return AutoSize()
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetGridColumnGap(view View, subviewID ...string) SizeUnit {
|
||||
return sizeStyledProperty(view, subviewID, GridColumnGap, false)
|
||||
}
|
||||
|
|
150
imageView.go
150
imageView.go
|
@ -54,7 +54,7 @@ type imageViewData struct {
|
|||
// NewImageView create new ImageView object and return it
|
||||
func NewImageView(session Session, params Params) ImageView {
|
||||
view := new(imageViewData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -64,8 +64,8 @@ func newImageView(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of imageView by default values
|
||||
func (imageView *imageViewData) Init(session Session) {
|
||||
imageView.viewData.Init(session)
|
||||
func (imageView *imageViewData) init(session Session) {
|
||||
imageView.viewData.init(session)
|
||||
imageView.tag = "ImageView"
|
||||
//imageView.systemClass = "ruiImageView"
|
||||
|
||||
|
@ -114,82 +114,11 @@ func (imageView *imageViewData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (imageView *imageViewData) Set(tag string, value interface{}) bool {
|
||||
func (imageView *imageViewData) Set(tag string, value any) bool {
|
||||
return imageView.set(imageView.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func valueToImageListeners(value interface{}) ([]func(ImageView), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(ImageView):
|
||||
return []func(ImageView){value}, true
|
||||
|
||||
case func():
|
||||
fn := func(ImageView) {
|
||||
value()
|
||||
}
|
||||
return []func(ImageView){fn}, true
|
||||
|
||||
case []func(ImageView):
|
||||
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(ImageView), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(ImageView) {
|
||||
v()
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(ImageView), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(ImageView):
|
||||
listeners[i] = v
|
||||
|
||||
case func():
|
||||
listeners[i] = func(ImageView) {
|
||||
v()
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (imageView *imageViewData) set(tag string, value interface{}) bool {
|
||||
func (imageView *imageViewData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
imageView.remove(tag)
|
||||
return true
|
||||
|
@ -228,8 +157,12 @@ func (imageView *imageViewData) set(tag string, value interface{}) bool {
|
|||
notCompatibleType(tag, value)
|
||||
|
||||
case LoadedEvent, ErrorEvent:
|
||||
if listeners, ok := valueToImageListeners(value); ok {
|
||||
if listeners, ok := valueToNoParamListeners[ImageView](value); ok {
|
||||
if listeners == nil {
|
||||
delete(imageView.properties, tag)
|
||||
} else {
|
||||
imageView.properties[tag] = listeners
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -248,7 +181,7 @@ func (imageView *imageViewData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (imageView *imageViewData) Get(tag string) interface{} {
|
||||
func (imageView *imageViewData) Get(tag string) any {
|
||||
return imageView.viewData.get(imageView.normalizeTag(tag))
|
||||
}
|
||||
|
||||
|
@ -311,7 +244,7 @@ func (imageView *imageViewData) htmlProperties(self View, buffer *strings.Builde
|
|||
}
|
||||
}
|
||||
|
||||
if text := GetImageViewAltText(imageView, ""); text != "" {
|
||||
if text := GetImageViewAltText(imageView); text != "" {
|
||||
buffer.WriteString(` alt="`)
|
||||
buffer.WriteString(textToJS(text))
|
||||
buffer.WriteString(`"`)
|
||||
|
@ -333,8 +266,8 @@ func (imageView *imageViewData) cssStyle(self View, builder cssBuilder) {
|
|||
builder.add("object-fit", "none")
|
||||
}
|
||||
|
||||
vAlign := GetImageViewVerticalAlign(imageView, "")
|
||||
hAlign := GetImageViewHorizontalAlign(imageView, "")
|
||||
vAlign := GetImageViewVerticalAlign(imageView)
|
||||
hAlign := GetImageViewHorizontalAlign(imageView)
|
||||
if vAlign != CenterAlign || hAlign != CenterAlign {
|
||||
var position string
|
||||
switch hAlign {
|
||||
|
@ -390,10 +323,10 @@ func (imageView *imageViewData) CurrentSource() string {
|
|||
}
|
||||
|
||||
// GetImageViewSource returns the image URL of an ImageView subview.
|
||||
// If the second argument (subviewID) is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewSource(view View, subviewID string) string {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewSource(view View, subviewID ...string) string {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
|
@ -406,10 +339,10 @@ func GetImageViewSource(view View, subviewID string) string {
|
|||
}
|
||||
|
||||
// GetImageViewAltText returns an alternative text description of an ImageView subview.
|
||||
// If the second argument (subviewID) is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewAltText(view View, subviewID string) string {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewAltText(view View, subviewID ...string) string {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
|
@ -425,40 +358,19 @@ func GetImageViewAltText(view View, subviewID string) string {
|
|||
|
||||
// GetImageViewFit returns how the content of a replaced ImageView subview:
|
||||
// NoneFit (0), ContainFit (1), CoverFit (2), FillFit (3), or ScaleDownFit (4).
|
||||
// If the second argument (subviewID) is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewFit(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
|
||||
if value, ok := enumStyledProperty(view, Fit, NoneFit); ok {
|
||||
return value
|
||||
}
|
||||
return 0
|
||||
// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewFit(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, Fit, NoneFit, false)
|
||||
}
|
||||
|
||||
// GetImageViewVerticalAlign return the vertical align of an ImageView subview: TopAlign (0), BottomAlign (1), CenterAlign (2)
|
||||
// If the second argument (subviewID) is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewVerticalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
|
||||
if align, ok := enumStyledProperty(view, ImageVerticalAlign, LeftAlign); ok {
|
||||
return align
|
||||
}
|
||||
return CenterAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewVerticalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, ImageVerticalAlign, LeftAlign, false)
|
||||
}
|
||||
|
||||
// GetImageViewHorizontalAlign return the vertical align of an ImageView subview: LeftAlign (0), RightAlign (1), CenterAlign (2)
|
||||
// If the second argument (subviewID) is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewHorizontalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
|
||||
if align, ok := enumStyledProperty(view, ImageHorizontalAlign, LeftAlign); ok {
|
||||
return align
|
||||
}
|
||||
return CenterAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned
|
||||
func GetImageViewHorizontalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, ImageHorizontalAlign, LeftAlign, false)
|
||||
}
|
||||
|
|
131
keyEvents.go
131
keyEvents.go
|
@ -50,34 +50,52 @@ type KeyEvent struct {
|
|||
MetaKey bool
|
||||
}
|
||||
|
||||
func valueToKeyListeners(value interface{}) ([]func(View, KeyEvent), bool) {
|
||||
func (event *KeyEvent) init(data DataObject) {
|
||||
getBool := func(tag string) bool {
|
||||
if value, ok := data.PropertyValue(tag); ok && value == "1" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
event.Key, _ = data.PropertyValue("key")
|
||||
event.Code, _ = data.PropertyValue("code")
|
||||
event.TimeStamp = getTimeStamp(data)
|
||||
event.Repeat = getBool("repeat")
|
||||
event.CtrlKey = getBool("ctrlKey")
|
||||
event.ShiftKey = getBool("shiftKey")
|
||||
event.AltKey = getBool("altKey")
|
||||
event.MetaKey = getBool("metaKey")
|
||||
}
|
||||
|
||||
func valueToEventListeners[V View, E any](value any) ([]func(V, E), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(View, KeyEvent):
|
||||
return []func(View, KeyEvent){value}, true
|
||||
case func(V, E):
|
||||
return []func(V, E){value}, true
|
||||
|
||||
case func(KeyEvent):
|
||||
fn := func(_ View, event KeyEvent) {
|
||||
case func(E):
|
||||
fn := func(_ V, event E) {
|
||||
value(event)
|
||||
}
|
||||
return []func(View, KeyEvent){fn}, true
|
||||
return []func(V, E){fn}, true
|
||||
|
||||
case func(View):
|
||||
fn := func(view View, _ KeyEvent) {
|
||||
case func(V):
|
||||
fn := func(view V, _ E) {
|
||||
value(view)
|
||||
}
|
||||
return []func(View, KeyEvent){fn}, true
|
||||
return []func(V, E){fn}, true
|
||||
|
||||
case func():
|
||||
fn := func(View, KeyEvent) {
|
||||
fn := func(V, E) {
|
||||
value()
|
||||
}
|
||||
return []func(View, KeyEvent){fn}, true
|
||||
return []func(V, E){fn}, true
|
||||
|
||||
case []func(View, KeyEvent):
|
||||
case []func(V, E):
|
||||
if len(value) == 0 {
|
||||
return nil, true
|
||||
}
|
||||
|
@ -88,33 +106,33 @@ func valueToKeyListeners(value interface{}) ([]func(View, KeyEvent), bool) {
|
|||
}
|
||||
return value, true
|
||||
|
||||
case []func(KeyEvent):
|
||||
case []func(E):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, KeyEvent), count)
|
||||
listeners := make([]func(V, E), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(_ View, event KeyEvent) {
|
||||
listeners[i] = func(_ V, event E) {
|
||||
v(event)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func(View):
|
||||
case []func(V):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, KeyEvent), count)
|
||||
listeners := make([]func(V, E), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(view View, _ KeyEvent) {
|
||||
listeners[i] = func(view V, _ E) {
|
||||
v(view)
|
||||
}
|
||||
}
|
||||
|
@ -125,43 +143,43 @@ func valueToKeyListeners(value interface{}) ([]func(View, KeyEvent), bool) {
|
|||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, KeyEvent), count)
|
||||
listeners := make([]func(V, E), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(View, KeyEvent) {
|
||||
listeners[i] = func(V, E) {
|
||||
v()
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, KeyEvent), count)
|
||||
listeners := make([]func(V, E), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(View, KeyEvent):
|
||||
case func(V, E):
|
||||
listeners[i] = v
|
||||
|
||||
case func(KeyEvent):
|
||||
listeners[i] = func(_ View, event KeyEvent) {
|
||||
case func(E):
|
||||
listeners[i] = func(_ V, event E) {
|
||||
v(event)
|
||||
}
|
||||
|
||||
case func(View):
|
||||
listeners[i] = func(view View, _ KeyEvent) {
|
||||
case func(V):
|
||||
listeners[i] = func(view V, _ E) {
|
||||
v(view)
|
||||
}
|
||||
|
||||
case func():
|
||||
listeners[i] = func(View, KeyEvent) {
|
||||
listeners[i] = func(V, E) {
|
||||
v()
|
||||
}
|
||||
|
||||
|
@ -180,8 +198,8 @@ var keyEvents = map[string]struct{ jsEvent, jsFunc string }{
|
|||
KeyUpEvent: {jsEvent: "onkeyup", jsFunc: "keyUpEvent"},
|
||||
}
|
||||
|
||||
func (view *viewData) setKeyListener(tag string, value interface{}) bool {
|
||||
listeners, ok := valueToKeyListeners(value)
|
||||
func (view *viewData) setKeyListener(tag string, value any) bool {
|
||||
listeners, ok := valueToEventListeners[View, KeyEvent](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
|
@ -209,67 +227,48 @@ func (view *viewData) removeKeyListener(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func getKeyListeners(view View, subviewID string, tag string) []func(View, KeyEvent) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
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(View, KeyEvent)); ok {
|
||||
if result, ok := value.([]func(V, E)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(View, KeyEvent){}
|
||||
return []func(V, E){}
|
||||
}
|
||||
|
||||
func keyEventsHtml(view View, buffer *strings.Builder) {
|
||||
for tag, js := range keyEvents {
|
||||
if listeners := getKeyListeners(view, "", tag); len(listeners) > 0 {
|
||||
if listeners := getEventListeners[View, KeyEvent](view, nil, tag); len(listeners) > 0 {
|
||||
buffer.WriteString(js.jsEvent + `="` + js.jsFunc + `(this, event)" `)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleKeyEvents(view View, tag string, data DataObject) {
|
||||
listeners := getKeyListeners(view, "", tag)
|
||||
if len(listeners) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
getBool := func(tag string) bool {
|
||||
if value, ok := data.PropertyValue(tag); ok && value == "1" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
key, _ := data.PropertyValue("key")
|
||||
code, _ := data.PropertyValue("code")
|
||||
event := KeyEvent{
|
||||
TimeStamp: getTimeStamp(data),
|
||||
Key: key,
|
||||
Code: code,
|
||||
Repeat: getBool("repeat"),
|
||||
CtrlKey: getBool("ctrlKey"),
|
||||
ShiftKey: getBool("shiftKey"),
|
||||
AltKey: getBool("altKey"),
|
||||
MetaKey: getBool("metaKey"),
|
||||
}
|
||||
listeners := getEventListeners[View, KeyEvent](view, nil, tag)
|
||||
if len(listeners) > 0 {
|
||||
var event KeyEvent
|
||||
event.init(data)
|
||||
|
||||
for _, listener := range listeners {
|
||||
listener(view, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetKeyDownListeners returns the "key-down-event" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetKeyDownListeners(view View, subviewID string) []func(View, KeyEvent) {
|
||||
return getKeyListeners(view, subviewID, KeyDownEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetKeyDownListeners(view View, subviewID ...string) []func(View, KeyEvent) {
|
||||
return getEventListeners[View, KeyEvent](view, subviewID, KeyDownEvent)
|
||||
}
|
||||
|
||||
// GetKeyUpListeners returns the "key-up-event" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetKeyUpListeners(view View, subviewID string) []func(View, KeyEvent) {
|
||||
return getKeyListeners(view, subviewID, KeyUpEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetKeyUpListeners(view View, subviewID ...string) []func(View, KeyEvent) {
|
||||
return getEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent)
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ func (adapter *viewListAdapter) ListItem(index int, session Session) View {
|
|||
|
||||
func (adapter *viewListAdapter) IsListItemEnabled(index int) bool {
|
||||
if index >= 0 && index < len(adapter.items) {
|
||||
return !IsDisabled(adapter.items[index], "")
|
||||
return !IsDisabled(adapter.items[index])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
100
listLayout.go
100
listLayout.go
|
@ -33,7 +33,7 @@ type listLayoutData struct {
|
|||
// NewListLayout create new ListLayout object and return it
|
||||
func NewListLayout(session Session, params Params) ListLayout {
|
||||
view := new(listLayoutData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -43,8 +43,8 @@ func newListLayout(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of ViewsAlignContainer by default values
|
||||
func (listLayout *listLayoutData) Init(session Session) {
|
||||
listLayout.viewsContainerData.Init(session)
|
||||
func (listLayout *listLayoutData) init(session Session) {
|
||||
listLayout.viewsContainerData.init(session)
|
||||
listLayout.tag = "ListLayout"
|
||||
listLayout.systemClass = "ruiListLayout"
|
||||
}
|
||||
|
@ -58,19 +58,41 @@ func (listLayout *listLayoutData) normalizeTag(tag string) string {
|
|||
switch tag {
|
||||
case "wrap":
|
||||
tag = ListWrap
|
||||
|
||||
case "row-gap":
|
||||
return ListRowGap
|
||||
|
||||
case ColumnGap:
|
||||
return ListColumnGap
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
func (listLayout *listLayoutData) Get(tag string) interface{} {
|
||||
func (listLayout *listLayoutData) Get(tag string) any {
|
||||
return listLayout.get(listLayout.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (listLayout *listLayoutData) get(tag string) any {
|
||||
if tag == Gap {
|
||||
if rowGap := GetListRowGap(listLayout); rowGap.Equal(GetListColumnGap(listLayout)) {
|
||||
return rowGap
|
||||
}
|
||||
return AutoSize()
|
||||
}
|
||||
|
||||
return listLayout.viewsContainerData.get(tag)
|
||||
}
|
||||
|
||||
func (listLayout *listLayoutData) Remove(tag string) {
|
||||
listLayout.remove(listLayout.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (listLayout *listLayoutData) remove(tag string) {
|
||||
if tag == Gap {
|
||||
listLayout.remove(ListRowGap)
|
||||
listLayout.remove(ListColumnGap)
|
||||
return
|
||||
}
|
||||
listLayout.viewsContainerData.remove(tag)
|
||||
if listLayout.created {
|
||||
switch tag {
|
||||
|
@ -80,16 +102,20 @@ func (listLayout *listLayoutData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (listLayout *listLayoutData) Set(tag string, value interface{}) bool {
|
||||
func (listLayout *listLayoutData) Set(tag string, value any) bool {
|
||||
return listLayout.set(listLayout.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (listLayout *listLayoutData) set(tag string, value interface{}) bool {
|
||||
func (listLayout *listLayoutData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
listLayout.remove(tag)
|
||||
return true
|
||||
}
|
||||
|
||||
if tag == Gap {
|
||||
return listLayout.set(ListRowGap, value) && listLayout.set(ListColumnGap, value)
|
||||
}
|
||||
|
||||
if listLayout.viewsContainerData.set(tag, value) {
|
||||
if listLayout.created {
|
||||
switch tag {
|
||||
|
@ -113,38 +139,24 @@ func (listLayout *listLayoutData) htmlSubviews(self View, buffer *strings.Builde
|
|||
|
||||
// GetListVerticalAlign returns the vertical align of a ListLayout or ListView sibview:
|
||||
// TopAlign (0), BottomAlign (1), CenterAlign (2), or StretchAlign (3)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListVerticalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return LeftAlign
|
||||
}
|
||||
result, _ := enumProperty(view, VerticalAlign, view.Session(), 0)
|
||||
return result
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListVerticalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, VerticalAlign, TopAlign, false)
|
||||
}
|
||||
|
||||
// GetListHorizontalAlign returns the vertical align of a ListLayout or ListView subview:
|
||||
// LeftAlign (0), RightAlign (1), CenterAlign (2), or StretchAlign (3)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListHorizontalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return TopAlign
|
||||
}
|
||||
result, _ := enumProperty(view, HorizontalAlign, view.Session(), 0)
|
||||
return result
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListHorizontalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, HorizontalAlign, LeftAlign, false)
|
||||
}
|
||||
|
||||
// GetListOrientation returns the orientation of a ListLayout or ListView subview:
|
||||
// TopDownOrientation (0), StartToEndOrientation (1), BottomUpOrientation (2), or EndToStartOrientation (3)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListOrientation(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListOrientation(view View, subviewID ...string) int {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
|
@ -163,16 +175,20 @@ func GetListOrientation(view View, subviewID string) int {
|
|||
}
|
||||
|
||||
// GetListWrap returns the wrap type of a ListLayout or ListView subview:
|
||||
// WrapOff (0), WrapOn (1), or WrapReverse (2)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListWrap(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := enumStyledProperty(view, ListWrap, 0); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return ListWrapOff
|
||||
// ListWrapOff (0), ListWrapOn (1), or ListWrapReverse (2)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListWrap(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, ListWrap, ListWrapOff, false)
|
||||
}
|
||||
|
||||
// GetListRowGap returns the gap between ListLayout or ListView rows.
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListRowGap(view View, subviewID ...string) SizeUnit {
|
||||
return sizeStyledProperty(view, subviewID, ListRowGap, false)
|
||||
}
|
||||
|
||||
// GetListColumnGap returns the gap between ListLayout or ListView columns.
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListColumnGap(view View, subviewID ...string) SizeUnit {
|
||||
return sizeStyledProperty(view, subviewID, ListColumnGap, false)
|
||||
}
|
||||
|
|
437
listView.go
437
listView.go
|
@ -69,7 +69,7 @@ type listViewData struct {
|
|||
// NewListView creates the new list view
|
||||
func NewListView(session Session, params Params) ListView {
|
||||
view := new(listViewData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -79,8 +79,8 @@ func newListView(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of ViewsContainer by default values
|
||||
func (listView *listViewData) Init(session Session) {
|
||||
listView.viewData.Init(session)
|
||||
func (listView *listViewData) init(session Session) {
|
||||
listView.viewData.init(session)
|
||||
listView.tag = "ListView"
|
||||
listView.systemClass = "ruiListView"
|
||||
listView.items = []View{}
|
||||
|
@ -110,6 +110,12 @@ func (listView *listViewData) normalizeTag(tag string) string {
|
|||
|
||||
case "wrap":
|
||||
tag = ListWrap
|
||||
|
||||
case "row-gap":
|
||||
return ListRowGap
|
||||
|
||||
case ColumnGap:
|
||||
return ListColumnGap
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
@ -120,6 +126,10 @@ func (listView *listViewData) Remove(tag string) {
|
|||
|
||||
func (listView *listViewData) remove(tag string) {
|
||||
switch tag {
|
||||
case Gap:
|
||||
listView.remove(ListRowGap)
|
||||
listView.remove(ListColumnGap)
|
||||
|
||||
case Checked:
|
||||
if len(listView.checkedItem) > 0 {
|
||||
listView.checkedItem = []int{}
|
||||
|
@ -148,7 +158,7 @@ func (listView *listViewData) remove(tag string) {
|
|||
}
|
||||
|
||||
case Current:
|
||||
current := GetCurrent(listView, "")
|
||||
current := GetCurrent(listView)
|
||||
delete(listView.properties, tag)
|
||||
if listView.created {
|
||||
updateInnerHTML(listView.htmlID(), listView.session)
|
||||
|
@ -193,41 +203,53 @@ func (listView *listViewData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (listView *listViewData) Set(tag string, value interface{}) bool {
|
||||
func (listView *listViewData) Set(tag string, value any) bool {
|
||||
return listView.set(listView.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (listView *listViewData) set(tag string, value interface{}) bool {
|
||||
func (listView *listViewData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
listView.remove(tag)
|
||||
return true
|
||||
}
|
||||
|
||||
switch tag {
|
||||
case Gap:
|
||||
return listView.set(ListRowGap, value) && listView.set(ListColumnGap, value)
|
||||
|
||||
case ListItemClickedEvent:
|
||||
listeners := listView.valueToItemListeners(value)
|
||||
if listeners == nil {
|
||||
listeners, ok := valueToEventListeners[ListView, int](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
} else if listeners == nil {
|
||||
listeners = []func(ListView, int){}
|
||||
}
|
||||
listView.clickedListeners = listeners
|
||||
listView.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
||||
case ListItemSelectedEvent:
|
||||
listeners := listView.valueToItemListeners(value)
|
||||
if listeners == nil {
|
||||
listeners, ok := valueToEventListeners[ListView, int](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
} else if listeners == nil {
|
||||
listeners = []func(ListView, int){}
|
||||
}
|
||||
listView.selectedListeners = listeners
|
||||
listView.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
||||
case ListItemCheckedEvent:
|
||||
if !listView.setItemCheckedEvent(value) {
|
||||
listeners, ok := valueToEventListeners[ListView, []int](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
} else if listeners == nil {
|
||||
listeners = []func(ListView, []int){}
|
||||
}
|
||||
listView.checkedListeners = listeners
|
||||
listView.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
||||
|
@ -242,11 +264,11 @@ func (listView *listViewData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
case Current:
|
||||
oldCurrent := GetCurrent(listView, "")
|
||||
oldCurrent := GetCurrent(listView)
|
||||
if !listView.setIntProperty(Current, value) {
|
||||
return false
|
||||
}
|
||||
current := GetCurrent(listView, "")
|
||||
current := GetCurrent(listView)
|
||||
if oldCurrent == current {
|
||||
return true
|
||||
}
|
||||
|
@ -255,7 +277,7 @@ func (listView *listViewData) set(tag string, value interface{}) bool {
|
|||
listener(listView, current)
|
||||
}
|
||||
|
||||
case Orientation, ListWrap, VerticalAlign, HorizontalAlign, Style, StyleDisabled, ItemWidth, ItemHeight:
|
||||
case Orientation, ListWrap, ListRowGap, ListColumnGap, VerticalAlign, HorizontalAlign, Style, StyleDisabled, ItemWidth, ItemHeight:
|
||||
result := listView.viewData.set(tag, value)
|
||||
if result && listView.created {
|
||||
updateInnerHTML(listView.htmlID(), listView.session)
|
||||
|
@ -288,67 +310,18 @@ func (listView *listViewData) set(tag string, value interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (listView *listViewData) setItemCheckedEvent(value interface{}) bool {
|
||||
switch value := value.(type) {
|
||||
case func(ListView, []int):
|
||||
listView.checkedListeners = []func(ListView, []int){value}
|
||||
|
||||
case func([]int):
|
||||
fn := func(_ ListView, date []int) {
|
||||
value(date)
|
||||
}
|
||||
listView.checkedListeners = []func(ListView, []int){fn}
|
||||
|
||||
case []func(ListView, []int):
|
||||
listView.checkedListeners = value
|
||||
|
||||
case []func([]int):
|
||||
listeners := make([]func(ListView, []int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(ListItemCheckedEvent, val)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(_ ListView, date []int) {
|
||||
val(date)
|
||||
}
|
||||
}
|
||||
listView.checkedListeners = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(ListView, []int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(ListItemCheckedEvent, val)
|
||||
return false
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case func(ListView, []int):
|
||||
listeners[i] = val
|
||||
|
||||
case func([]int):
|
||||
listeners[i] = func(_ ListView, checked []int) {
|
||||
val(checked)
|
||||
}
|
||||
|
||||
default:
|
||||
notCompatibleType(ListItemCheckedEvent, val)
|
||||
return false
|
||||
}
|
||||
}
|
||||
listView.checkedListeners = listeners
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (listView *listViewData) Get(tag string) interface{} {
|
||||
func (listView *listViewData) Get(tag string) any {
|
||||
return listView.get(listView.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (listView *listViewData) get(tag string) interface{} {
|
||||
func (listView *listViewData) get(tag string) any {
|
||||
switch tag {
|
||||
case Gap:
|
||||
if rowGap := GetListRowGap(listView); rowGap.Equal(GetListColumnGap(listView)) {
|
||||
return rowGap
|
||||
}
|
||||
return AutoSize()
|
||||
|
||||
case ListItemClickedEvent:
|
||||
return listView.clickedListeners
|
||||
|
||||
|
@ -376,7 +349,7 @@ func (listView *listViewData) get(tag string) interface{} {
|
|||
return listView.viewData.get(tag)
|
||||
}
|
||||
|
||||
func (listView *listViewData) setItems(value interface{}) bool {
|
||||
func (listView *listViewData) setItems(value any) bool {
|
||||
switch value := value.(type) {
|
||||
case []string:
|
||||
listView.adapter = NewTextListAdapter(value, nil)
|
||||
|
@ -412,7 +385,7 @@ func (listView *listViewData) setItems(value interface{}) bool {
|
|||
listView.adapter = NewTextListAdapter(items, nil)
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
items := make([]View, len(value))
|
||||
for i, val := range value {
|
||||
switch value := val.(type) {
|
||||
|
@ -460,62 +433,7 @@ func (listView *listViewData) setItems(value interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (listView *listViewData) valueToItemListeners(value interface{}) []func(ListView, int) {
|
||||
if value == nil {
|
||||
return []func(ListView, int){}
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(ListView, int):
|
||||
return []func(ListView, int){value}
|
||||
|
||||
case func(int):
|
||||
fn := func(_ ListView, index int) {
|
||||
value(index)
|
||||
}
|
||||
return []func(ListView, int){fn}
|
||||
|
||||
case []func(ListView, int):
|
||||
return value
|
||||
|
||||
case []func(int):
|
||||
listeners := make([]func(ListView, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
listeners[i] = func(_ ListView, index int) {
|
||||
val(index)
|
||||
}
|
||||
}
|
||||
return listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(ListView, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
switch val := val.(type) {
|
||||
case func(ListView, int):
|
||||
listeners[i] = val
|
||||
|
||||
case func(int):
|
||||
listeners[i] = func(_ ListView, index int) {
|
||||
val(index)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return listeners
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (listView *listViewData) setChecked(value interface{}) bool {
|
||||
func (listView *listViewData) setChecked(value any) bool {
|
||||
var checked []int
|
||||
if value == nil {
|
||||
checked = []int{}
|
||||
|
@ -544,7 +462,7 @@ func (listView *listViewData) setChecked(value interface{}) bool {
|
|||
}
|
||||
}
|
||||
|
||||
switch GetListViewCheckbox(listView, "") {
|
||||
switch GetListViewCheckbox(listView) {
|
||||
case SingleCheckbox:
|
||||
count := len(checked)
|
||||
if count > 1 {
|
||||
|
@ -628,14 +546,14 @@ func (listView *listViewData) getItemFrames() []Frame {
|
|||
|
||||
func (listView *listViewData) itemAlign(self View, buffer *strings.Builder) {
|
||||
values := enumProperties[ItemHorizontalAlign].cssValues
|
||||
if hAlign := GetListItemHorizontalAlign(listView, ""); hAlign >= 0 && hAlign < len(values) {
|
||||
if hAlign := GetListItemHorizontalAlign(listView); hAlign >= 0 && hAlign < len(values) {
|
||||
buffer.WriteString(" justify-items: ")
|
||||
buffer.WriteString(values[hAlign])
|
||||
buffer.WriteRune(';')
|
||||
}
|
||||
|
||||
values = enumProperties[ItemVerticalAlign].cssValues
|
||||
if vAlign := GetListItemVerticalAlign(listView, ""); vAlign >= 0 && vAlign < len(values) {
|
||||
if vAlign := GetListItemVerticalAlign(listView); vAlign >= 0 && vAlign < len(values) {
|
||||
buffer.WriteString(" align-items: ")
|
||||
buffer.WriteString(values[vAlign])
|
||||
buffer.WriteRune(';')
|
||||
|
@ -643,15 +561,15 @@ func (listView *listViewData) itemAlign(self View, buffer *strings.Builder) {
|
|||
}
|
||||
|
||||
func (listView *listViewData) itemSize(self View, buffer *strings.Builder) {
|
||||
if itemWidth := GetListItemWidth(listView, ""); itemWidth.Type != Auto {
|
||||
if itemWidth := GetListItemWidth(listView); itemWidth.Type != Auto {
|
||||
buffer.WriteString(` min-width: `)
|
||||
buffer.WriteString(itemWidth.cssString(""))
|
||||
buffer.WriteString(itemWidth.cssString("", listView.Session()))
|
||||
buffer.WriteRune(';')
|
||||
}
|
||||
|
||||
if itemHeight := GetListItemHeight(listView, ""); itemHeight.Type != Auto {
|
||||
if itemHeight := GetListItemHeight(listView); itemHeight.Type != Auto {
|
||||
buffer.WriteString(` min-height: `)
|
||||
buffer.WriteString(itemHeight.cssString(""))
|
||||
buffer.WriteString(itemHeight.cssString("", listView.Session()))
|
||||
buffer.WriteRune(';')
|
||||
}
|
||||
}
|
||||
|
@ -741,7 +659,7 @@ func (listView *listViewData) checkboxItemDiv(self View, checkbox, hCheckboxAlig
|
|||
|
||||
if gap, ok := sizeConstant(listView.session, "ruiCheckboxGap"); ok && gap.Type != Auto {
|
||||
itemStyleBuilder.WriteString(` grid-gap: `)
|
||||
itemStyleBuilder.WriteString(gap.cssString("auto"))
|
||||
itemStyleBuilder.WriteString(gap.cssString("auto", listView.Session()))
|
||||
itemStyleBuilder.WriteRune(';')
|
||||
}
|
||||
|
||||
|
@ -801,14 +719,14 @@ func (listView *listViewData) checkboxSubviews(self View, buffer *strings.Builde
|
|||
count := listView.adapter.ListSize()
|
||||
listViewID := listView.htmlID()
|
||||
|
||||
hCheckboxAlign := GetListViewCheckboxHorizontalAlign(listView, "")
|
||||
vCheckboxAlign := GetListViewCheckboxVerticalAlign(listView, "")
|
||||
hCheckboxAlign := GetListViewCheckboxHorizontalAlign(listView)
|
||||
vCheckboxAlign := GetListViewCheckboxVerticalAlign(listView)
|
||||
|
||||
itemDiv := listView.checkboxItemDiv(self, checkbox, hCheckboxAlign, vCheckboxAlign)
|
||||
onDiv, offDiv, contentDiv := listView.getDivs(self, checkbox, hCheckboxAlign, vCheckboxAlign)
|
||||
|
||||
current := GetCurrent(listView, "")
|
||||
checkedItems := GetListViewCheckedItems(listView, "")
|
||||
current := GetCurrent(listView)
|
||||
checkedItems := GetListViewCheckedItems(listView)
|
||||
for i := 0; i < count; i++ {
|
||||
buffer.WriteString(`<div id="`)
|
||||
buffer.WriteString(listViewID)
|
||||
|
@ -864,7 +782,7 @@ func (listView *listViewData) noneCheckboxSubviews(self View, buffer *strings.Bu
|
|||
itemStyleBuilder.WriteString(`" onclick="listItemClickEvent(this, event)"`)
|
||||
itemStyle := itemStyleBuilder.String()
|
||||
|
||||
current := GetCurrent(listView, "")
|
||||
current := GetCurrent(listView)
|
||||
for i := 0; i < count; i++ {
|
||||
buffer.WriteString(`<div id="`)
|
||||
buffer.WriteString(listViewID)
|
||||
|
@ -893,9 +811,9 @@ func (listView *listViewData) noneCheckboxSubviews(self View, buffer *strings.Bu
|
|||
|
||||
func (listView *listViewData) updateCheckboxItem(index int, checked bool) {
|
||||
|
||||
checkbox := GetListViewCheckbox(listView, "")
|
||||
hCheckboxAlign := GetListViewCheckboxHorizontalAlign(listView, "")
|
||||
vCheckboxAlign := GetListViewCheckboxVerticalAlign(listView, "")
|
||||
checkbox := GetListViewCheckbox(listView)
|
||||
hCheckboxAlign := GetListViewCheckboxHorizontalAlign(listView)
|
||||
vCheckboxAlign := GetListViewCheckboxVerticalAlign(listView)
|
||||
onDiv, offDiv, contentDiv := listView.getDivs(listView, checkbox, hCheckboxAlign, vCheckboxAlign)
|
||||
|
||||
buffer := allocStringBuilder()
|
||||
|
@ -937,7 +855,7 @@ func (listView *listViewData) htmlProperties(self View, buffer *strings.Builder)
|
|||
buffer.WriteString(`" data-bluritemstyle="`)
|
||||
buffer.WriteString(listView.currentInactiveStyle())
|
||||
buffer.WriteString(`"`)
|
||||
current := GetCurrent(listView, "")
|
||||
current := GetCurrent(listView)
|
||||
if listView.adapter != nil && current >= 0 && current < listView.adapter.ListSize() {
|
||||
buffer.WriteString(` data-current="`)
|
||||
buffer.WriteString(listView.htmlID())
|
||||
|
@ -953,8 +871,8 @@ func (listView *listViewData) htmlProperties(self View, buffer *strings.Builder)
|
|||
func (listView *listViewData) cssStyle(self View, builder cssBuilder) {
|
||||
listView.viewData.cssStyle(self, builder)
|
||||
|
||||
if GetListWrap(listView, "") != WrapOff {
|
||||
switch GetListOrientation(listView, "") {
|
||||
if GetListWrap(listView) != WrapOff {
|
||||
switch GetListOrientation(listView) {
|
||||
case TopDownOrientation, BottomUpOrientation:
|
||||
builder.add(`max-height`, `100%`)
|
||||
default:
|
||||
|
@ -976,8 +894,20 @@ func (listView *listViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
|
||||
buffer.WriteString(`<div style="display: flex; align-content: stretch;`)
|
||||
|
||||
wrap := GetListWrap(listView, "")
|
||||
orientation := GetListOrientation(listView, "")
|
||||
if gap := GetListRowGap(listView); gap.Type != Auto {
|
||||
buffer.WriteString(` row-gap: `)
|
||||
buffer.WriteString(gap.cssString("0", listView.Session()))
|
||||
buffer.WriteRune(';')
|
||||
}
|
||||
|
||||
if gap := GetListColumnGap(listView); gap.Type != Auto {
|
||||
buffer.WriteString(` column-gap: `)
|
||||
buffer.WriteString(gap.cssString("0", listView.Session()))
|
||||
buffer.WriteRune(';')
|
||||
}
|
||||
|
||||
wrap := GetListWrap(listView)
|
||||
orientation := GetListOrientation(listView)
|
||||
rows := (orientation == StartToEndOrientation || orientation == EndToStartOrientation)
|
||||
|
||||
if rows {
|
||||
|
@ -1018,8 +948,7 @@ func (listView *listViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
}
|
||||
|
||||
value := ""
|
||||
if align, ok := enumStyledProperty(listView, HorizontalAlign, LeftAlign); ok {
|
||||
switch align {
|
||||
switch GetListHorizontalAlign(listView) {
|
||||
case LeftAlign:
|
||||
if (!rows && wrap == ListWrapReverse) || orientation == EndToStartOrientation {
|
||||
value = `flex-end`
|
||||
|
@ -1042,7 +971,6 @@ func (listView *listViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
value = `stretch`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if value != "" {
|
||||
buffer.WriteRune(' ')
|
||||
|
@ -1053,8 +981,7 @@ func (listView *listViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
}
|
||||
|
||||
value = ""
|
||||
if align, ok := enumStyledProperty(listView, VerticalAlign, TopAlign); ok {
|
||||
switch align {
|
||||
switch GetListVerticalAlign(listView) {
|
||||
case TopAlign:
|
||||
if (rows && wrap == ListWrapReverse) || orientation == BottomUpOrientation {
|
||||
value = `flex-end`
|
||||
|
@ -1077,7 +1004,6 @@ func (listView *listViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
value = `space-between`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if value != "" {
|
||||
buffer.WriteRune(' ')
|
||||
|
@ -1089,7 +1015,7 @@ func (listView *listViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
|
||||
buffer.WriteString(`">`)
|
||||
|
||||
checkbox := GetListViewCheckbox(listView, "")
|
||||
checkbox := GetListViewCheckbox(listView)
|
||||
if checkbox == NoneCheckbox {
|
||||
listView.noneCheckboxSubviews(self, buffer)
|
||||
} else {
|
||||
|
@ -1130,9 +1056,9 @@ func (listView *listViewData) handleCommand(self View, command string, data Data
|
|||
}
|
||||
|
||||
func (listView *listViewData) onItemClick() {
|
||||
current := GetCurrent(listView, "")
|
||||
if current >= 0 && !IsDisabled(listView, "") {
|
||||
checkbox := GetListViewCheckbox(listView, "")
|
||||
current := GetCurrent(listView)
|
||||
if current >= 0 && !IsDisabled(listView) {
|
||||
checkbox := GetListViewCheckbox(listView)
|
||||
m:
|
||||
switch checkbox {
|
||||
case SingleCheckbox:
|
||||
|
@ -1191,121 +1117,67 @@ func (listView *listViewData) onItemResize(self View, index string, x, y, width,
|
|||
}
|
||||
|
||||
// GetVerticalAlign return the vertical align of a list: TopAlign (0), BottomAlign (1), CenterAlign (2), StretchAlign (3)
|
||||
func GetVerticalAlign(view View) int {
|
||||
if align, ok := enumProperty(view, VerticalAlign, view.Session(), TopAlign); ok {
|
||||
return align
|
||||
}
|
||||
return TopAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetVerticalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, VerticalAlign, TopAlign, false)
|
||||
}
|
||||
|
||||
// GetHorizontalAlign return the vertical align of a list: LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
||||
func GetHorizontalAlign(view View) int {
|
||||
if align, ok := enumProperty(view, HorizontalAlign, view.Session(), LeftAlign); ok {
|
||||
return align
|
||||
}
|
||||
return LeftAlign
|
||||
// GetHorizontalAlign return the vertical align of a list/checkbox: LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetHorizontalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, HorizontalAlign, LeftAlign, false)
|
||||
}
|
||||
|
||||
// GetListItemClickedListeners returns a ListItemClickedListener of the ListView.
|
||||
// If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemClickedListeners(view View, subviewID string) []func(ListView, int) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(ListItemClickedEvent); value != nil {
|
||||
if result, ok := value.([]func(ListView, int)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(ListView, int){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemClickedListeners(view View, subviewID ...string) []func(ListView, int) {
|
||||
return getEventListeners[ListView, int](view, subviewID, ListItemClickedEvent)
|
||||
}
|
||||
|
||||
// GetListItemSelectedListeners returns a ListItemSelectedListener of the ListView.
|
||||
// If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemSelectedListeners(view View, subviewID string) []func(ListView, int) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(ListItemSelectedEvent); value != nil {
|
||||
if result, ok := value.([]func(ListView, int)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(ListView, int){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemSelectedListeners(view View, subviewID ...string) []func(ListView, int) {
|
||||
return getEventListeners[ListView, int](view, subviewID, ListItemSelectedEvent)
|
||||
}
|
||||
|
||||
// GetListItemCheckedListeners returns a ListItemCheckedListener of the ListView.
|
||||
// If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemCheckedListeners(view View, subviewID string) []func(ListView, []int) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(ListItemCheckedEvent); value != nil {
|
||||
if result, ok := value.([]func(ListView, []int)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(ListView, []int){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemCheckedListeners(view View, subviewID ...string) []func(ListView, []int) {
|
||||
return getEventListeners[ListView, []int](view, subviewID, ListItemCheckedEvent)
|
||||
}
|
||||
|
||||
// GetListItemWidth returns the width of a ListView item.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemWidth(view View, subviewID string) SizeUnit {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
result, _ := sizeProperty(view, ItemWidth, view.Session())
|
||||
return result
|
||||
}
|
||||
return AutoSize()
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemWidth(view View, subviewID ...string) SizeUnit {
|
||||
return sizeStyledProperty(view, subviewID, ItemWidth, false)
|
||||
}
|
||||
|
||||
// GetListItemHeight returns the height of a ListView item.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemHeight(view View, subviewID string) SizeUnit {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
result, _ := sizeProperty(view, ItemHeight, view.Session())
|
||||
return result
|
||||
}
|
||||
return AutoSize()
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemHeight(view View, subviewID ...string) SizeUnit {
|
||||
return sizeStyledProperty(view, subviewID, ItemHeight, false)
|
||||
}
|
||||
|
||||
// GetListViewCheckbox returns the ListView checkbox type: NoneCheckbox (0), SingleCheckbox (1), or MultipleCheckbox (2).
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewCheckbox(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
result, _ := enumProperty(view, ItemCheckbox, view.Session(), 0)
|
||||
return result
|
||||
}
|
||||
return 0
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewCheckbox(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, ItemCheckbox, 0, false)
|
||||
}
|
||||
|
||||
// GetListViewCheckedItems returns the array of ListView checked items.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewCheckedItems(view View, subviewID string) []int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewCheckedItems(view View, subviewID ...string) []int {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
if listView, ok := view.(ListView); ok {
|
||||
checkedItems := listView.getCheckedItems()
|
||||
switch GetListViewCheckbox(view, "") {
|
||||
switch GetListViewCheckbox(view) {
|
||||
case NoneCheckbox:
|
||||
return []int{}
|
||||
|
||||
|
@ -1334,66 +1206,34 @@ func IsListViewCheckedItem(view View, subviewID string, index int) bool {
|
|||
|
||||
// GetListViewCheckboxVerticalAlign returns the vertical align of the ListView checkbox:
|
||||
// TopAlign (0), BottomAlign (1), CenterAlign (2)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewCheckboxVerticalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if align, ok := enumProperty(view, CheckboxVerticalAlign, view.Session(), TopAlign); ok {
|
||||
return align
|
||||
}
|
||||
}
|
||||
return TopAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewCheckboxVerticalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, TopAlign, false)
|
||||
}
|
||||
|
||||
// GetListViewCheckboxHorizontalAlign returns the horizontal align of the ListView checkbox:
|
||||
// LeftAlign (0), RightAlign (1), CenterAlign (2)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewCheckboxHorizontalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if align, ok := enumProperty(view, CheckboxHorizontalAlign, view.Session(), LeftAlign); ok {
|
||||
return align
|
||||
}
|
||||
}
|
||||
return LeftAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewCheckboxHorizontalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, LeftAlign, false)
|
||||
}
|
||||
|
||||
// GetListItemVerticalAlign returns the vertical align of the ListView item content:
|
||||
// TopAlign (0), BottomAlign (1), CenterAlign (2)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemVerticalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if align, ok := enumProperty(view, ItemVerticalAlign, view.Session(), TopAlign); ok {
|
||||
return align
|
||||
}
|
||||
}
|
||||
return TopAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemVerticalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, ItemVerticalAlign, TopAlign, false)
|
||||
}
|
||||
|
||||
// ItemHorizontalAlign returns the horizontal align of the ListView item content:
|
||||
// LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemHorizontalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if align, ok := enumProperty(view, ItemHorizontalAlign, view.Session(), LeftAlign); ok {
|
||||
return align
|
||||
}
|
||||
}
|
||||
return LeftAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListItemHorizontalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, ItemHorizontalAlign, LeftAlign, false)
|
||||
}
|
||||
|
||||
// GetListItemFrame - returns the location and size of the ListView item in pixels.
|
||||
// If the second argument (subviewID) 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 GetListItemFrame(view View, subviewID string, index int) Frame {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
|
@ -1410,10 +1250,10 @@ func GetListItemFrame(view View, subviewID string, index int) Frame {
|
|||
}
|
||||
|
||||
// GetListViewAdapter - returns the ListView adapter.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewAdapter(view View, subviewID string) ListAdapter {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetListViewAdapter(view View, subviewID ...string) ListAdapter {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(Items); value != nil {
|
||||
|
@ -1426,11 +1266,12 @@ func GetListViewAdapter(view View, subviewID string) ListAdapter {
|
|||
}
|
||||
|
||||
// ReloadListViewData updates ListView content
|
||||
// If the second argument (subviewID) is "" then content the first argument (view) is updated.
|
||||
func ReloadListViewData(view View, subviewID string) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then content the first argument (view) is updated.
|
||||
func ReloadListViewData(view View, subviewID ...string) {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
if listView, ok := view.(ListView); ok {
|
||||
listView.ReloadListViewData()
|
||||
|
|
214
mediaPlayer.go
214
mediaPlayer.go
|
@ -163,8 +163,8 @@ type MediaSource struct {
|
|||
MimeType string
|
||||
}
|
||||
|
||||
func (player *mediaPlayerData) Init(session Session) {
|
||||
player.viewData.Init(session)
|
||||
func (player *mediaPlayerData) init(session Session) {
|
||||
player.viewData.init(session)
|
||||
player.tag = "MediaPlayer"
|
||||
}
|
||||
|
||||
|
@ -185,11 +185,11 @@ func (player *mediaPlayerData) remove(tag string) {
|
|||
player.propertyChanged(tag)
|
||||
}
|
||||
|
||||
func (player *mediaPlayerData) Set(tag string, value interface{}) bool {
|
||||
func (player *mediaPlayerData) Set(tag string, value any) bool {
|
||||
return player.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (player *mediaPlayerData) set(tag string, value interface{}) bool {
|
||||
func (player *mediaPlayerData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
player.remove(tag)
|
||||
return true
|
||||
|
@ -205,7 +205,7 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
|
|||
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, LoadStartEvent,
|
||||
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent,
|
||||
ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent:
|
||||
if listeners, ok := valueToPlayerListeners(value); ok {
|
||||
if listeners, ok := valueToNoParamListeners[MediaPlayer](value); ok {
|
||||
if listeners == nil {
|
||||
delete(player.properties, tag)
|
||||
} else {
|
||||
|
@ -218,7 +218,7 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
|
|||
notCompatibleType(tag, value)
|
||||
|
||||
case DurationChangedEvent, RateChangedEvent, TimeUpdateEvent, VolumeChangedEvent:
|
||||
if listeners, ok := valueToPlayerTimeListeners(value); ok {
|
||||
if listeners, ok := valueToEventListeners[MediaPlayer, float64](value); ok {
|
||||
if listeners == nil {
|
||||
delete(player.properties, tag)
|
||||
} else {
|
||||
|
@ -257,7 +257,7 @@ func (player *mediaPlayerData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (player *mediaPlayerData) setSource(value interface{}) bool {
|
||||
func (player *mediaPlayerData) setSource(value any) bool {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
src := MediaSource{Url: value, MimeType: ""}
|
||||
|
@ -311,203 +311,7 @@ func (player *mediaPlayerData) setSource(value interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func valueToPlayerListeners(value interface{}) ([]func(MediaPlayer), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(MediaPlayer):
|
||||
return []func(MediaPlayer){value}, true
|
||||
|
||||
case func():
|
||||
fn := func(MediaPlayer) {
|
||||
value()
|
||||
}
|
||||
return []func(MediaPlayer){fn}, true
|
||||
|
||||
case []func(MediaPlayer):
|
||||
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(MediaPlayer), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(MediaPlayer) {
|
||||
v()
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(MediaPlayer), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(MediaPlayer):
|
||||
listeners[i] = v
|
||||
|
||||
case func():
|
||||
listeners[i] = func(MediaPlayer) {
|
||||
v()
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func valueToPlayerTimeListeners(value interface{}) ([]func(MediaPlayer, float64), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(MediaPlayer, float64):
|
||||
return []func(MediaPlayer, float64){value}, true
|
||||
|
||||
case func(float64):
|
||||
fn := func(_ MediaPlayer, time float64) {
|
||||
value(time)
|
||||
}
|
||||
return []func(MediaPlayer, float64){fn}, true
|
||||
|
||||
case func(MediaPlayer):
|
||||
fn := func(player MediaPlayer, _ float64) {
|
||||
value(player)
|
||||
}
|
||||
return []func(MediaPlayer, float64){fn}, true
|
||||
|
||||
case func():
|
||||
fn := func(MediaPlayer, float64) {
|
||||
value()
|
||||
}
|
||||
return []func(MediaPlayer, float64){fn}, true
|
||||
|
||||
case []func(MediaPlayer, float64):
|
||||
if len(value) == 0 {
|
||||
return nil, true
|
||||
}
|
||||
for _, fn := range value {
|
||||
if fn == nil {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return value, true
|
||||
|
||||
case []func(float64):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(MediaPlayer, float64), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(_ MediaPlayer, time float64) {
|
||||
v(time)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func(MediaPlayer):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(MediaPlayer, float64), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(player MediaPlayer, _ float64) {
|
||||
v(player)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func():
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(MediaPlayer, float64), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(MediaPlayer, float64) {
|
||||
v()
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(MediaPlayer, float64), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(MediaPlayer, float64):
|
||||
listeners[i] = v
|
||||
|
||||
case func(float64):
|
||||
listeners[i] = func(_ MediaPlayer, time float64) {
|
||||
v(time)
|
||||
}
|
||||
|
||||
case func(MediaPlayer):
|
||||
listeners[i] = func(player MediaPlayer, _ float64) {
|
||||
v(player)
|
||||
}
|
||||
|
||||
case func():
|
||||
listeners[i] = func(MediaPlayer, float64) {
|
||||
v()
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func valueToPlayerErrorListeners(value interface{}) ([]func(MediaPlayer, int, string), bool) {
|
||||
func valueToPlayerErrorListeners(value any) ([]func(MediaPlayer, int, string), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
@ -593,7 +397,7 @@ func valueToPlayerErrorListeners(value interface{}) ([]func(MediaPlayer, int, st
|
|||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
|
|
199
mouseEvents.go
199
mouseEvents.go
|
@ -144,131 +144,6 @@ type MouseEvent struct {
|
|||
MetaKey bool
|
||||
}
|
||||
|
||||
func valueToMouseListeners(value interface{}) ([]func(View, MouseEvent), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(View, MouseEvent):
|
||||
return []func(View, MouseEvent){value}, true
|
||||
|
||||
case func(MouseEvent):
|
||||
fn := func(_ View, event MouseEvent) {
|
||||
value(event)
|
||||
}
|
||||
return []func(View, MouseEvent){fn}, true
|
||||
|
||||
case func(View):
|
||||
fn := func(view View, _ MouseEvent) {
|
||||
value(view)
|
||||
}
|
||||
return []func(View, MouseEvent){fn}, true
|
||||
|
||||
case func():
|
||||
fn := func(View, MouseEvent) {
|
||||
value()
|
||||
}
|
||||
return []func(View, MouseEvent){fn}, true
|
||||
|
||||
case []func(View, MouseEvent):
|
||||
if len(value) == 0 {
|
||||
return nil, true
|
||||
}
|
||||
for _, fn := range value {
|
||||
if fn == nil {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return value, true
|
||||
|
||||
case []func(MouseEvent):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, MouseEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(_ View, event MouseEvent) {
|
||||
v(event)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func(View):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, MouseEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(view View, _ MouseEvent) {
|
||||
v(view)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func():
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, MouseEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(View, MouseEvent) {
|
||||
v()
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, MouseEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(View, MouseEvent):
|
||||
listeners[i] = v
|
||||
|
||||
case func(MouseEvent):
|
||||
listeners[i] = func(_ View, event MouseEvent) {
|
||||
v(event)
|
||||
}
|
||||
|
||||
case func(View):
|
||||
listeners[i] = func(view View, _ MouseEvent) {
|
||||
v(view)
|
||||
}
|
||||
|
||||
case func():
|
||||
listeners[i] = func(View, MouseEvent) {
|
||||
v()
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var mouseEvents = map[string]struct{ jsEvent, jsFunc string }{
|
||||
ClickEvent: {jsEvent: "onclick", jsFunc: "clickEvent"},
|
||||
DoubleClickEvent: {jsEvent: "ondblclick", jsFunc: "doubleClickEvent"},
|
||||
|
@ -280,8 +155,8 @@ var mouseEvents = map[string]struct{ jsEvent, jsFunc string }{
|
|||
ContextMenuEvent: {jsEvent: "oncontextmenu", jsFunc: "contextMenuEvent"},
|
||||
}
|
||||
|
||||
func (view *viewData) setMouseListener(tag string, value interface{}) bool {
|
||||
listeners, ok := valueToMouseListeners(value)
|
||||
func (view *viewData) setMouseListener(tag string, value any) bool {
|
||||
listeners, ok := valueToEventListeners[View, MouseEvent](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
|
@ -309,20 +184,6 @@ func (view *viewData) removeMouseListener(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func getMouseListeners(view View, subviewID string, tag string) []func(View, MouseEvent) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(tag); value != nil {
|
||||
if result, ok := value.([]func(View, MouseEvent)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(View, MouseEvent){}
|
||||
}
|
||||
|
||||
func mouseEventsHtml(view View, buffer *strings.Builder) {
|
||||
for tag, js := range mouseEvents {
|
||||
if value := view.getRaw(tag); value != nil {
|
||||
|
@ -363,64 +224,62 @@ func (event *MouseEvent) init(data DataObject) {
|
|||
}
|
||||
|
||||
func handleMouseEvents(view View, tag string, data DataObject) {
|
||||
listeners := getMouseListeners(view, "", tag)
|
||||
if len(listeners) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
listeners := getEventListeners[View, MouseEvent](view, nil, tag)
|
||||
if len(listeners) > 0 {
|
||||
var event MouseEvent
|
||||
event.init(data)
|
||||
|
||||
for _, listener := range listeners {
|
||||
listener(view, event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetClickListeners returns the "click-event" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetClickListeners(view View, subviewID string) []func(View, MouseEvent) {
|
||||
return getMouseListeners(view, subviewID, ClickEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetClickListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
||||
return getEventListeners[View, MouseEvent](view, subviewID, ClickEvent)
|
||||
}
|
||||
|
||||
// GetDoubleClickListeners returns the "double-click-event" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetDoubleClickListeners(view View, subviewID string) []func(View, MouseEvent) {
|
||||
return getMouseListeners(view, subviewID, DoubleClickEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetDoubleClickListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
||||
return getEventListeners[View, MouseEvent](view, subviewID, DoubleClickEvent)
|
||||
}
|
||||
|
||||
// GetContextMenuListeners returns the "context-menu" listener list.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetContextMenuListeners(view View, subviewID string) []func(View, MouseEvent) {
|
||||
return getMouseListeners(view, subviewID, ContextMenuEvent)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetContextMenuListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
||||
return getEventListeners[View, MouseEvent](view, subviewID, ContextMenuEvent)
|
||||
}
|
||||
|
||||
// GetMouseDownListeners returns the "mouse-down" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseDownListeners(view View, subviewID string) []func(View, MouseEvent) {
|
||||
return getMouseListeners(view, subviewID, MouseDown)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseDownListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
||||
return getEventListeners[View, MouseEvent](view, subviewID, MouseDown)
|
||||
}
|
||||
|
||||
// GetMouseUpListeners returns the "mouse-up" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseUpListeners(view View, subviewID string) []func(View, MouseEvent) {
|
||||
return getMouseListeners(view, subviewID, MouseUp)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseUpListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
||||
return getEventListeners[View, MouseEvent](view, subviewID, MouseUp)
|
||||
}
|
||||
|
||||
// GetMouseMoveListeners returns the "mouse-move" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseMoveListeners(view View, subviewID string) []func(View, MouseEvent) {
|
||||
return getMouseListeners(view, subviewID, MouseMove)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseMoveListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
||||
return getEventListeners[View, MouseEvent](view, subviewID, MouseMove)
|
||||
}
|
||||
|
||||
// GetMouseOverListeners returns the "mouse-over" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseOverListeners(view View, subviewID string) []func(View, MouseEvent) {
|
||||
return getMouseListeners(view, subviewID, MouseOver)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseOverListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
||||
return getEventListeners[View, MouseEvent](view, subviewID, MouseOver)
|
||||
}
|
||||
|
||||
// GetMouseOutListeners returns the "mouse-out" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseOutListeners(view View, subviewID string) []func(View, MouseEvent) {
|
||||
return getMouseListeners(view, subviewID, MouseOut)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetMouseOutListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
||||
return getEventListeners[View, MouseEvent](view, subviewID, MouseOut)
|
||||
}
|
||||
|
|
197
numberPicker.go
197
numberPicker.go
|
@ -36,7 +36,7 @@ type numberPickerData struct {
|
|||
// NewNumberPicker create new NumberPicker object and return it
|
||||
func NewNumberPicker(session Session, params Params) NumberPicker {
|
||||
view := new(numberPickerData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -45,8 +45,8 @@ func newNumberPicker(session Session) View {
|
|||
return NewNumberPicker(session, nil)
|
||||
}
|
||||
|
||||
func (picker *numberPickerData) Init(session Session) {
|
||||
picker.viewData.Init(session)
|
||||
func (picker *numberPickerData) init(session Session) {
|
||||
picker.viewData.init(session)
|
||||
picker.tag = "NumberPicker"
|
||||
picker.numberChangedListeners = []func(NumberPicker, float64){}
|
||||
}
|
||||
|
@ -87,11 +87,11 @@ func (picker *numberPickerData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (picker *numberPickerData) Set(tag string, value interface{}) bool {
|
||||
func (picker *numberPickerData) Set(tag string, value any) bool {
|
||||
return picker.set(picker.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (picker *numberPickerData) set(tag string, value interface{}) bool {
|
||||
func (picker *numberPickerData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
picker.remove(tag)
|
||||
return true
|
||||
|
@ -99,65 +99,28 @@ func (picker *numberPickerData) set(tag string, value interface{}) bool {
|
|||
|
||||
switch tag {
|
||||
case NumberChangedEvent:
|
||||
switch value := value.(type) {
|
||||
case func(NumberPicker, float64):
|
||||
picker.numberChangedListeners = []func(NumberPicker, float64){value}
|
||||
|
||||
case func(float64):
|
||||
fn := func(_ NumberPicker, newValue float64) {
|
||||
value(newValue)
|
||||
}
|
||||
picker.numberChangedListeners = []func(NumberPicker, float64){fn}
|
||||
|
||||
case []func(NumberPicker, float64):
|
||||
picker.numberChangedListeners = value
|
||||
|
||||
case []func(float64):
|
||||
listeners := make([]func(NumberPicker, float64), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
listeners, ok := valueToEventListeners[NumberPicker, float64](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(_ NumberPicker, newValue float64) {
|
||||
val(newValue)
|
||||
}
|
||||
} else if listeners == nil {
|
||||
listeners = []func(NumberPicker, float64){}
|
||||
}
|
||||
picker.numberChangedListeners = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(NumberPicker, float64), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case func(NumberPicker, float64):
|
||||
listeners[i] = val
|
||||
|
||||
default:
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
}
|
||||
picker.numberChangedListeners = listeners
|
||||
}
|
||||
picker.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
||||
case NumberPickerValue:
|
||||
oldValue := GetNumberPickerValue(picker, "")
|
||||
min, max := GetNumberPickerMinMax(picker, "")
|
||||
oldValue := GetNumberPickerValue(picker)
|
||||
min, max := GetNumberPickerMinMax(picker)
|
||||
if picker.setFloatProperty(NumberPickerValue, value, min, max) {
|
||||
if newValue := GetNumberPickerValue(picker, ""); oldValue != newValue {
|
||||
if f, ok := floatProperty(picker, NumberPickerValue, picker.Session(), min); ok && f != oldValue {
|
||||
newValue, _ := floatTextProperty(picker, NumberPickerValue, picker.Session(), min)
|
||||
if picker.created {
|
||||
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), newValue))
|
||||
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), newValue))
|
||||
}
|
||||
for _, listener := range picker.numberChangedListeners {
|
||||
listener(picker, newValue)
|
||||
listener(picker, f)
|
||||
}
|
||||
picker.propertyChangedEvent(tag)
|
||||
}
|
||||
|
@ -177,29 +140,29 @@ func (picker *numberPickerData) propertyChanged(tag string) {
|
|||
if picker.created {
|
||||
switch tag {
|
||||
case NumberPickerType:
|
||||
if GetNumberPickerType(picker, "") == NumberSlider {
|
||||
if GetNumberPickerType(picker) == NumberSlider {
|
||||
updateProperty(picker.htmlID(), "type", "range", picker.session)
|
||||
} else {
|
||||
updateProperty(picker.htmlID(), "type", "number", picker.session)
|
||||
}
|
||||
|
||||
case NumberPickerMin:
|
||||
min, _ := GetNumberPickerMinMax(picker, "")
|
||||
min, _ := GetNumberPickerMinMax(picker)
|
||||
updateProperty(picker.htmlID(), Min, strconv.FormatFloat(min, 'f', -1, 32), picker.session)
|
||||
|
||||
case NumberPickerMax:
|
||||
_, max := GetNumberPickerMinMax(picker, "")
|
||||
_, max := GetNumberPickerMinMax(picker)
|
||||
updateProperty(picker.htmlID(), Max, strconv.FormatFloat(max, 'f', -1, 32), picker.session)
|
||||
|
||||
case NumberPickerStep:
|
||||
if step := GetNumberPickerStep(picker, ""); step > 0 {
|
||||
if step := GetNumberPickerStep(picker); step > 0 {
|
||||
updateProperty(picker.htmlID(), Step, strconv.FormatFloat(step, 'f', -1, 32), picker.session)
|
||||
} else {
|
||||
updateProperty(picker.htmlID(), Step, "any", picker.session)
|
||||
}
|
||||
|
||||
case NumberPickerValue:
|
||||
value := GetNumberPickerValue(picker, "")
|
||||
value := GetNumberPickerValue(picker)
|
||||
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), value))
|
||||
for _, listener := range picker.numberChangedListeners {
|
||||
listener(picker, value)
|
||||
|
@ -208,11 +171,11 @@ func (picker *numberPickerData) propertyChanged(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (picker *numberPickerData) Get(tag string) interface{} {
|
||||
func (picker *numberPickerData) Get(tag string) any {
|
||||
return picker.get(picker.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (picker *numberPickerData) get(tag string) interface{} {
|
||||
func (picker *numberPickerData) get(tag string) any {
|
||||
switch tag {
|
||||
case NumberChangedEvent:
|
||||
return picker.numberChangedListeners
|
||||
|
@ -229,13 +192,13 @@ func (picker *numberPickerData) htmlTag() string {
|
|||
func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builder) {
|
||||
picker.viewData.htmlProperties(self, buffer)
|
||||
|
||||
if GetNumberPickerType(picker, "") == NumberSlider {
|
||||
if GetNumberPickerType(picker) == NumberSlider {
|
||||
buffer.WriteString(` type="range"`)
|
||||
} else {
|
||||
buffer.WriteString(` type="number"`)
|
||||
}
|
||||
|
||||
min, max := GetNumberPickerMinMax(picker, "")
|
||||
min, max := GetNumberPickerMinMax(picker)
|
||||
if min != math.Inf(-1) {
|
||||
buffer.WriteString(` min="`)
|
||||
buffer.WriteString(strconv.FormatFloat(min, 'f', -1, 64))
|
||||
|
@ -248,7 +211,7 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde
|
|||
buffer.WriteByte('"')
|
||||
}
|
||||
|
||||
step := GetNumberPickerStep(picker, "")
|
||||
step := GetNumberPickerStep(picker)
|
||||
if step != 0 {
|
||||
buffer.WriteString(` step="`)
|
||||
buffer.WriteString(strconv.FormatFloat(step, 'f', -1, 64))
|
||||
|
@ -258,14 +221,14 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde
|
|||
}
|
||||
|
||||
buffer.WriteString(` value="`)
|
||||
buffer.WriteString(strconv.FormatFloat(GetNumberPickerValue(picker, ""), 'f', -1, 64))
|
||||
buffer.WriteString(strconv.FormatFloat(GetNumberPickerValue(picker), 'f', -1, 64))
|
||||
buffer.WriteByte('"')
|
||||
|
||||
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
||||
}
|
||||
|
||||
func (picker *numberPickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
|
||||
if IsDisabled(self, "") {
|
||||
if IsDisabled(self) {
|
||||
buffer.WriteString(` disabled`)
|
||||
}
|
||||
picker.viewData.htmlDisabledProperties(self, buffer)
|
||||
|
@ -276,8 +239,8 @@ func (picker *numberPickerData) handleCommand(self View, command string, data Da
|
|||
case "textChanged":
|
||||
if text, ok := data.PropertyValue("text"); ok {
|
||||
if value, err := strconv.ParseFloat(text, 32); err == nil {
|
||||
oldValue := GetNumberPickerValue(picker, "")
|
||||
picker.properties[NumberPickerValue] = value
|
||||
oldValue := GetNumberPickerValue(picker)
|
||||
picker.properties[NumberPickerValue] = text
|
||||
if value != oldValue {
|
||||
for _, listener := range picker.numberChangedListeners {
|
||||
listener(picker, value)
|
||||
|
@ -294,70 +257,50 @@ func (picker *numberPickerData) handleCommand(self View, command string, data Da
|
|||
// GetNumberPickerType returns the type of NumberPicker subview. Valid values:
|
||||
// NumberEditor (0) - NumberPicker is presented by editor (default type);
|
||||
// NumberSlider (1) - NumberPicker is presented by slider.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberPickerType(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
t, _ := enumStyledProperty(view, NumberPickerType, NumberEditor)
|
||||
return t
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberPickerType(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, NumberPickerType, NumberEditor, false)
|
||||
}
|
||||
|
||||
// GetNumberPickerMinMax returns the min and max value of NumberPicker subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberPickerMinMax(view View, subviewID string) (float64, float64) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberPickerMinMax(view View, subviewID ...string) (float64, float64) {
|
||||
var pickerType int
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
pickerType = GetNumberPickerType(view, subviewID[0])
|
||||
} else {
|
||||
pickerType = GetNumberPickerType(view)
|
||||
}
|
||||
if view != nil {
|
||||
t, _ := enumStyledProperty(view, NumberPickerType, NumberEditor)
|
||||
var defMin, defMax float64
|
||||
|
||||
if t == NumberSlider {
|
||||
var defMin, defMax float64
|
||||
if pickerType == NumberSlider {
|
||||
defMin = 0
|
||||
defMax = 1
|
||||
} else {
|
||||
defMin = math.Inf(-1)
|
||||
defMax = math.Inf(1)
|
||||
}
|
||||
min, ok := floatStyledProperty(view, NumberPickerMin, defMin)
|
||||
if !ok {
|
||||
min, _ = floatStyledProperty(view, Min, defMin)
|
||||
}
|
||||
|
||||
max, ok := floatStyledProperty(view, NumberPickerMax, defMax)
|
||||
if !ok {
|
||||
max, _ = floatStyledProperty(view, Max, defMax)
|
||||
}
|
||||
min := floatStyledProperty(view, subviewID, NumberPickerMin, defMin)
|
||||
max := floatStyledProperty(view, subviewID, NumberPickerMax, defMax)
|
||||
|
||||
if min > max {
|
||||
return max, min
|
||||
}
|
||||
return min, max
|
||||
}
|
||||
return 0, 1
|
||||
}
|
||||
|
||||
// GetNumberPickerStep returns the value changing step of NumberPicker subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberPickerStep(view View, subviewID string) float64 {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return 0
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberPickerStep(view View, subviewID ...string) float64 {
|
||||
var max float64
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
_, max = GetNumberPickerMinMax(view, subviewID[0])
|
||||
} else {
|
||||
_, max = GetNumberPickerMinMax(view)
|
||||
}
|
||||
|
||||
result, ok := floatStyledProperty(view, NumberPickerStep, 0)
|
||||
if !ok {
|
||||
result, _ = floatStyledProperty(view, Step, 0)
|
||||
}
|
||||
|
||||
_, max := GetNumberPickerMinMax(view, "")
|
||||
result := floatStyledProperty(view, subviewID, NumberPickerStep, 0)
|
||||
if result > max {
|
||||
return max
|
||||
}
|
||||
|
@ -365,36 +308,22 @@ func GetNumberPickerStep(view View, subviewID string) float64 {
|
|||
}
|
||||
|
||||
// GetNumberPickerValue returns the value of NumberPicker subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberPickerValue(view View, subviewID string) float64 {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return 0
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberPickerValue(view View, subviewID ...string) float64 {
|
||||
var min float64
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
min, _ = GetNumberPickerMinMax(view, subviewID[0])
|
||||
} else {
|
||||
min, _ = GetNumberPickerMinMax(view)
|
||||
}
|
||||
|
||||
min, _ := GetNumberPickerMinMax(view, "")
|
||||
result, ok := floatStyledProperty(view, NumberPickerValue, min)
|
||||
if !ok {
|
||||
result, _ = floatStyledProperty(view, Value, min)
|
||||
}
|
||||
result := floatStyledProperty(view, subviewID, NumberPickerValue, min)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetNumberChangedListeners returns the NumberChangedListener list of an NumberPicker subview.
|
||||
// If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberChangedListeners(view View, subviewID string) []func(NumberPicker, float64) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(NumberChangedEvent); value != nil {
|
||||
if listeners, ok := value.([]func(NumberPicker, float64)); ok {
|
||||
return listeners
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(NumberPicker, float64){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetNumberChangedListeners(view View, subviewID ...string) []func(NumberPicker, float64) {
|
||||
return getEventListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent)
|
||||
}
|
||||
|
|
16
outline.go
16
outline.go
|
@ -18,7 +18,7 @@ type outlinePropertyData struct {
|
|||
|
||||
func NewOutlineProperty(params Params) OutlineProperty {
|
||||
outline := new(outlinePropertyData)
|
||||
outline.properties = map[string]interface{}{}
|
||||
outline.properties = map[string]any{}
|
||||
for tag, value := range params {
|
||||
outline.Set(tag, value)
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func (outline *outlinePropertyData) Remove(tag string) {
|
|||
delete(outline.properties, outline.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (outline *outlinePropertyData) Set(tag string, value interface{}) bool {
|
||||
func (outline *outlinePropertyData) Set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
outline.Remove(tag)
|
||||
return true
|
||||
|
@ -85,7 +85,7 @@ func (outline *outlinePropertyData) Set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (outline *outlinePropertyData) Get(tag string) interface{} {
|
||||
func (outline *outlinePropertyData) Get(tag string) any {
|
||||
return outline.propertyList.Get(outline.normalizeTag(tag))
|
||||
}
|
||||
|
||||
|
@ -103,18 +103,18 @@ type ViewOutline struct {
|
|||
Width SizeUnit
|
||||
}
|
||||
|
||||
func (outline ViewOutline) cssValue(builder cssBuilder) {
|
||||
func (outline ViewOutline) cssValue(builder cssBuilder, session Session) {
|
||||
values := enumProperties[BorderStyle].cssValues
|
||||
if outline.Style > 0 && outline.Style < len(values) && outline.Color.Alpha() > 0 &&
|
||||
outline.Width.Type != Auto && outline.Width.Type != SizeInFraction &&
|
||||
outline.Width.Type != SizeInPercent && outline.Width.Value > 0 {
|
||||
builder.addValues("outline", " ", outline.Width.cssString("0"), values[outline.Style], outline.Color.cssString())
|
||||
builder.addValues("outline", " ", outline.Width.cssString("0", session), values[outline.Style], outline.Color.cssString())
|
||||
}
|
||||
}
|
||||
|
||||
func (outline ViewOutline) cssString() string {
|
||||
func (outline ViewOutline) cssString(session Session) string {
|
||||
var builder cssValueBuilder
|
||||
outline.cssValue(&builder)
|
||||
outline.cssValue(&builder, session)
|
||||
return builder.finish()
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ func getOutline(properties Properties) OutlineProperty {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (style *viewStyle) setOutline(value interface{}) bool {
|
||||
func (style *viewStyle) setOutline(value any) bool {
|
||||
switch value := value.(type) {
|
||||
case OutlineProperty:
|
||||
style.properties[Outline] = value
|
||||
|
|
10
params.go
10
params.go
|
@ -3,25 +3,25 @@ package rui
|
|||
import "sort"
|
||||
|
||||
// Params defines a type of a parameters list
|
||||
type Params map[string]interface{}
|
||||
type Params map[string]any
|
||||
|
||||
func (params Params) Get(tag string) interface{} {
|
||||
func (params Params) Get(tag string) any {
|
||||
return params.getRaw(tag)
|
||||
}
|
||||
|
||||
func (params Params) getRaw(tag string) interface{} {
|
||||
func (params Params) getRaw(tag string) any {
|
||||
if value, ok := params[tag]; ok {
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (params Params) Set(tag string, value interface{}) bool {
|
||||
func (params Params) Set(tag string, value any) bool {
|
||||
params.setRaw(tag, value)
|
||||
return true
|
||||
}
|
||||
|
||||
func (params Params) setRaw(tag string, value interface{}) {
|
||||
func (params Params) setRaw(tag string, value any) {
|
||||
if value != nil {
|
||||
params[tag] = value
|
||||
} else {
|
||||
|
|
181
pointerEvents.go
181
pointerEvents.go
|
@ -87,131 +87,6 @@ type PointerEvent struct {
|
|||
IsPrimary bool
|
||||
}
|
||||
|
||||
func valueToPointerListeners(value interface{}) ([]func(View, PointerEvent), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(View, PointerEvent):
|
||||
return []func(View, PointerEvent){value}, true
|
||||
|
||||
case func(PointerEvent):
|
||||
fn := func(_ View, event PointerEvent) {
|
||||
value(event)
|
||||
}
|
||||
return []func(View, PointerEvent){fn}, true
|
||||
|
||||
case func(View):
|
||||
fn := func(view View, _ PointerEvent) {
|
||||
value(view)
|
||||
}
|
||||
return []func(View, PointerEvent){fn}, true
|
||||
|
||||
case func():
|
||||
fn := func(View, PointerEvent) {
|
||||
value()
|
||||
}
|
||||
return []func(View, PointerEvent){fn}, true
|
||||
|
||||
case []func(View, PointerEvent):
|
||||
if len(value) == 0 {
|
||||
return nil, true
|
||||
}
|
||||
for _, fn := range value {
|
||||
if fn == nil {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return value, true
|
||||
|
||||
case []func(PointerEvent):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, PointerEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(_ View, event PointerEvent) {
|
||||
v(event)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func(View):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, PointerEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(view View, _ PointerEvent) {
|
||||
v(view)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func():
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, PointerEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(View, PointerEvent) {
|
||||
v()
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, PointerEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(View, PointerEvent):
|
||||
listeners[i] = v
|
||||
|
||||
case func(PointerEvent):
|
||||
listeners[i] = func(_ View, event PointerEvent) {
|
||||
v(event)
|
||||
}
|
||||
|
||||
case func(View):
|
||||
listeners[i] = func(view View, _ PointerEvent) {
|
||||
v(view)
|
||||
}
|
||||
|
||||
case func():
|
||||
listeners[i] = func(View, PointerEvent) {
|
||||
v()
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var pointerEvents = map[string]struct{ jsEvent, jsFunc string }{
|
||||
PointerDown: {jsEvent: "onpointerdown", jsFunc: "pointerDownEvent"},
|
||||
PointerUp: {jsEvent: "onpointerup", jsFunc: "pointerUpEvent"},
|
||||
|
@ -221,8 +96,8 @@ var pointerEvents = map[string]struct{ jsEvent, jsFunc string }{
|
|||
PointerOver: {jsEvent: "onpointerover", jsFunc: "pointerOverEvent"},
|
||||
}
|
||||
|
||||
func (view *viewData) setPointerListener(tag string, value interface{}) bool {
|
||||
listeners, ok := valueToPointerListeners(value)
|
||||
func (view *viewData) setPointerListener(tag string, value any) bool {
|
||||
listeners, ok := valueToEventListeners[View, PointerEvent](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
|
@ -250,20 +125,6 @@ func (view *viewData) removePointerListener(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func getPointerListeners(view View, subviewID string, tag string) []func(View, PointerEvent) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(tag); value != nil {
|
||||
if result, ok := value.([]func(View, PointerEvent)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(View, PointerEvent){}
|
||||
}
|
||||
|
||||
func pointerEventsHtml(view View, buffer *strings.Builder) {
|
||||
for tag, js := range pointerEvents {
|
||||
if value := view.getRaw(tag); value != nil {
|
||||
|
@ -291,7 +152,7 @@ func (event *PointerEvent) init(data DataObject) {
|
|||
}
|
||||
|
||||
func handlePointerEvents(view View, tag string, data DataObject) {
|
||||
listeners := getPointerListeners(view, "", tag)
|
||||
listeners := getEventListeners[View, PointerEvent](view, nil, tag)
|
||||
if len(listeners) == 0 {
|
||||
return
|
||||
}
|
||||
|
@ -305,37 +166,37 @@ func handlePointerEvents(view View, tag string, data DataObject) {
|
|||
}
|
||||
|
||||
// GetPointerDownListeners returns the "pointer-down" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerDownListeners(view View, subviewID string) []func(View, PointerEvent) {
|
||||
return getPointerListeners(view, subviewID, PointerDown)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerDownListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
||||
return getEventListeners[View, PointerEvent](view, subviewID, PointerDown)
|
||||
}
|
||||
|
||||
// GetPointerUpListeners returns the "pointer-up" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerUpListeners(view View, subviewID string) []func(View, PointerEvent) {
|
||||
return getPointerListeners(view, subviewID, PointerUp)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerUpListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
||||
return getEventListeners[View, PointerEvent](view, subviewID, PointerUp)
|
||||
}
|
||||
|
||||
// GetPointerMoveListeners returns the "pointer-move" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerMoveListeners(view View, subviewID string) []func(View, PointerEvent) {
|
||||
return getPointerListeners(view, subviewID, PointerMove)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerMoveListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
||||
return getEventListeners[View, PointerEvent](view, subviewID, PointerMove)
|
||||
}
|
||||
|
||||
// GetPointerCancelListeners returns the "pointer-cancel" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerCancelListeners(view View, subviewID string) []func(View, PointerEvent) {
|
||||
return getPointerListeners(view, subviewID, PointerCancel)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerCancelListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
||||
return getEventListeners[View, PointerEvent](view, subviewID, PointerCancel)
|
||||
}
|
||||
|
||||
// GetPointerOverListeners returns the "pointer-over" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerOverListeners(view View, subviewID string) []func(View, PointerEvent) {
|
||||
return getPointerListeners(view, subviewID, PointerOver)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerOverListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
||||
return getEventListeners[View, PointerEvent](view, subviewID, PointerOver)
|
||||
}
|
||||
|
||||
// GetPointerOutListeners returns the "pointer-out" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerOutListeners(view View, subviewID string) []func(View, PointerEvent) {
|
||||
return getPointerListeners(view, subviewID, PointerOut)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetPointerOutListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
||||
return getEventListeners[View, PointerEvent](view, subviewID, PointerOut)
|
||||
}
|
||||
|
|
476
popup.go
476
popup.go
|
@ -1,6 +1,8 @@
|
|||
package rui
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// Title is the constant for the "title" property tag.
|
||||
|
@ -36,6 +38,46 @@ const (
|
|||
// It occurs after the Popup disappears from the screen.
|
||||
// The main listener for this event has the following format: func(Popup)
|
||||
DismissEvent = "dismiss-event"
|
||||
|
||||
// Arrow is the constant for the "arrow" property tag.
|
||||
// Using the "popup-arrow" int property you can add ...
|
||||
Arrow = "arrow"
|
||||
|
||||
// ArrowAlign is the constant for the "arrow-align" property tag.
|
||||
// The "arrow-align" int property is used for set the horizontal alignment of the Popup arrow.
|
||||
// Valid values: LeftAlign (0), RightAlign (1), TopAlign (0), BottomAlign (1), CenterAlign (2)
|
||||
ArrowAlign = "arrow-align"
|
||||
|
||||
// ArrowSize is the constant for the "arrow-size" property tag.
|
||||
// The "arrow-size" SizeUnit property is used for set the size (length) of the Popup arrow.
|
||||
ArrowSize = "arrow-size"
|
||||
|
||||
// ArrowWidth is the constant for the "arrow-width" property tag.
|
||||
// The "arrow-width" SizeUnit property is used for set the width of the Popup arrow.
|
||||
ArrowWidth = "arrow-width"
|
||||
|
||||
// ArrowOffset is the constant for the "arrow-offset" property tag.
|
||||
// The "arrow-offset" SizeUnit property is used for set the offset of the Popup arrow.
|
||||
ArrowOffset = "arrow-offset"
|
||||
|
||||
// NoneArrow is value of the popup "arrow" property: no arrow
|
||||
NoneArrow = 0
|
||||
|
||||
// TopArrow is value of the popup "arrow" property:
|
||||
// Arrow at the top side of the pop-up window
|
||||
TopArrow = 1
|
||||
|
||||
// RightArrow is value of the popup "arrow" property:
|
||||
// Arrow on the right side of the pop-up window
|
||||
RightArrow = 2
|
||||
|
||||
// BottomArrow is value of the popup "arrow" property:
|
||||
// Arrow at the bottom of the pop-up window
|
||||
BottomArrow = 3
|
||||
|
||||
// LeftArrow is value of the popup "arrow" property:
|
||||
// Arrow on the left side of the pop-up window
|
||||
LeftArrow = 4
|
||||
)
|
||||
|
||||
// PopupButton describes a button that will be placed at the bottom of the window.
|
||||
|
@ -65,69 +107,300 @@ type popupManager struct {
|
|||
popups []Popup
|
||||
}
|
||||
|
||||
func (popup *popupData) init(view View, params Params) {
|
||||
type popupArrow struct {
|
||||
column, row int
|
||||
location, align int
|
||||
size, width, off SizeUnit
|
||||
}
|
||||
|
||||
func (arrow *popupArrow) fixOff(popupView View) {
|
||||
if arrow.align == CenterAlign && arrow.off.Type == Auto {
|
||||
r := GetRadius(popupView)
|
||||
switch arrow.location {
|
||||
case TopArrow:
|
||||
switch arrow.align {
|
||||
case LeftAlign:
|
||||
arrow.off = r.TopLeftX
|
||||
|
||||
case RightAlign:
|
||||
arrow.off = r.TopRightX
|
||||
}
|
||||
|
||||
case BottomArrow:
|
||||
switch arrow.align {
|
||||
case LeftAlign:
|
||||
arrow.off = r.BottomLeftX
|
||||
|
||||
case RightAlign:
|
||||
arrow.off = r.BottomRightX
|
||||
}
|
||||
|
||||
case RightArrow:
|
||||
switch arrow.align {
|
||||
case TopAlign:
|
||||
arrow.off = r.TopRightY
|
||||
|
||||
case BottomAlign:
|
||||
arrow.off = r.BottomRightY
|
||||
}
|
||||
|
||||
case LeftArrow:
|
||||
switch arrow.align {
|
||||
case TopAlign:
|
||||
arrow.off = r.TopLeftY
|
||||
|
||||
case BottomAlign:
|
||||
arrow.off = r.BottomLeftY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (arrow *popupArrow) createView(popupView View) View {
|
||||
session := popupView.Session()
|
||||
|
||||
defaultSize := func(constTag string, defValue SizeUnit) SizeUnit {
|
||||
if value, ok := session.Constant(constTag); ok {
|
||||
if size, ok := StringToSizeUnit(value); ok && size.Type != Auto && size.Value != 0 {
|
||||
return size
|
||||
}
|
||||
}
|
||||
return defValue
|
||||
}
|
||||
|
||||
if arrow.size.Type == Auto || arrow.size.Value == 0 {
|
||||
arrow.size = defaultSize("ruiArrowSize", Px(16))
|
||||
}
|
||||
|
||||
if arrow.width.Type == Auto || arrow.width.Value == 0 {
|
||||
arrow.width = defaultSize("ruiArrowWidth", Px(16))
|
||||
}
|
||||
|
||||
params := Params{BackgroundColor: GetBackgroundColor(popupView)}
|
||||
|
||||
if shadow := GetViewShadows(popupView); shadow != nil {
|
||||
params[Shadow] = shadow
|
||||
}
|
||||
|
||||
if filter := GetBackdropFilter(popupView); filter != nil {
|
||||
params[BackdropFilter] = filter
|
||||
}
|
||||
|
||||
switch arrow.location {
|
||||
case TopArrow:
|
||||
params[Row] = 0
|
||||
params[Column] = 1
|
||||
params[Clip] = PolygonClip([]any{"0%", "100%", "50%", "0%", "100%", "100%"})
|
||||
params[Width] = arrow.width
|
||||
params[Height] = arrow.size
|
||||
|
||||
case RightArrow:
|
||||
params[Row] = 1
|
||||
params[Column] = 0
|
||||
params[Clip] = PolygonClip([]any{"0%", "0%", "100%", "50%", "0%", "100%"})
|
||||
params[Width] = arrow.size
|
||||
params[Height] = arrow.width
|
||||
|
||||
case BottomArrow:
|
||||
params[Row] = 0
|
||||
params[Column] = 1
|
||||
params[Clip] = PolygonClip([]any{"0%", "0%", "50%", "100%", "100%", "0%"})
|
||||
params[Width] = arrow.width
|
||||
params[Height] = arrow.size
|
||||
|
||||
case LeftArrow:
|
||||
params[Row] = 1
|
||||
params[Column] = 0
|
||||
params[Clip] = PolygonClip([]any{"100%", "0%", "0%", "50%", "100%", "100%"})
|
||||
params[Width] = arrow.size
|
||||
params[Height] = arrow.width
|
||||
}
|
||||
|
||||
arrowView := NewView(session, params)
|
||||
|
||||
params = Params{
|
||||
Row: arrow.row,
|
||||
Column: arrow.column,
|
||||
Content: arrowView,
|
||||
}
|
||||
|
||||
arrow.fixOff(popupView)
|
||||
|
||||
switch arrow.location {
|
||||
case TopArrow, BottomArrow:
|
||||
cellWidth := make([]SizeUnit, 3)
|
||||
switch arrow.align {
|
||||
case LeftAlign:
|
||||
cellWidth[0] = arrow.off
|
||||
cellWidth[2] = Fr(1)
|
||||
|
||||
case RightAlign:
|
||||
cellWidth[0] = Fr(1)
|
||||
cellWidth[2] = arrow.off
|
||||
|
||||
default:
|
||||
cellWidth[0] = Fr(1)
|
||||
cellWidth[2] = Fr(1)
|
||||
if arrow.off.Type != Auto && arrow.off.Value != 0 {
|
||||
arrowView.Set(MarginLeft, arrow.off)
|
||||
}
|
||||
}
|
||||
params[CellWidth] = cellWidth
|
||||
|
||||
case RightArrow, LeftArrow:
|
||||
cellHeight := make([]SizeUnit, 3)
|
||||
switch arrow.align {
|
||||
case TopAlign:
|
||||
cellHeight[0] = arrow.off
|
||||
cellHeight[2] = Fr(1)
|
||||
|
||||
case BottomAlign:
|
||||
cellHeight[0] = Fr(1)
|
||||
cellHeight[2] = arrow.off
|
||||
|
||||
default:
|
||||
cellHeight[0] = Fr(1)
|
||||
cellHeight[2] = Fr(1)
|
||||
if arrow.off.Type != Auto && arrow.off.Value != 0 {
|
||||
arrowView.Set(MarginTop, arrow.off)
|
||||
}
|
||||
}
|
||||
params[CellHeight] = cellHeight
|
||||
}
|
||||
|
||||
return NewGridLayout(session, params)
|
||||
}
|
||||
|
||||
func (popup *popupData) init(view View, popupParams Params) {
|
||||
popup.view = view
|
||||
session := view.Session()
|
||||
|
||||
if params == nil {
|
||||
params = Params{}
|
||||
columnCount := 3
|
||||
rowCount := 3
|
||||
popupRow := 1
|
||||
popupColumn := 1
|
||||
arrow := popupArrow{
|
||||
row: 1,
|
||||
column: 1,
|
||||
align: CenterAlign,
|
||||
}
|
||||
|
||||
popup.dismissListener = []func(Popup){}
|
||||
if value, ok := params[DismissEvent]; ok && value != nil {
|
||||
switch value := value.(type) {
|
||||
case func(Popup):
|
||||
popup.dismissListener = []func(Popup){value}
|
||||
switch arrow.location, _ = enumProperty(popupParams, Arrow, session, NoneArrow); arrow.location {
|
||||
case TopArrow:
|
||||
rowCount = 4
|
||||
popupRow = 2
|
||||
|
||||
case func():
|
||||
popup.dismissListener = []func(Popup){
|
||||
func(_ Popup) {
|
||||
value()
|
||||
},
|
||||
case BottomArrow:
|
||||
rowCount = 4
|
||||
arrow.row = 2
|
||||
|
||||
case LeftArrow:
|
||||
columnCount = 4
|
||||
popupColumn = 2
|
||||
|
||||
case RightArrow:
|
||||
columnCount = 4
|
||||
arrow.column = 2
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
case []func(Popup):
|
||||
for _, fn := range value {
|
||||
if fn != nil {
|
||||
popup.dismissListener = append(popup.dismissListener, fn)
|
||||
}
|
||||
cellWidth := make([]SizeUnit, columnCount)
|
||||
switch hAlign, _ := enumProperty(popupParams, HorizontalAlign, session, CenterAlign); hAlign {
|
||||
case LeftAlign:
|
||||
cellWidth[columnCount-1] = Fr(1)
|
||||
|
||||
case RightAlign:
|
||||
cellWidth[0] = Fr(1)
|
||||
|
||||
default:
|
||||
cellWidth[0] = Fr(1)
|
||||
cellWidth[columnCount-1] = Fr(1)
|
||||
}
|
||||
|
||||
case []func():
|
||||
for _, fn := range value {
|
||||
if fn != nil {
|
||||
popup.dismissListener = append(popup.dismissListener, func(_ Popup) {
|
||||
fn()
|
||||
})
|
||||
}
|
||||
cellHeight := make([]SizeUnit, rowCount)
|
||||
switch vAlign, _ := enumProperty(popupParams, VerticalAlign, session, CenterAlign); vAlign {
|
||||
case LeftAlign:
|
||||
cellHeight[rowCount-1] = Fr(1)
|
||||
|
||||
case RightAlign:
|
||||
cellHeight[0] = Fr(1)
|
||||
|
||||
default:
|
||||
cellHeight[0] = Fr(1)
|
||||
cellHeight[rowCount-1] = Fr(1)
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
for _, val := range value {
|
||||
if val != nil {
|
||||
switch fn := val.(type) {
|
||||
case func(Popup):
|
||||
popup.dismissListener = append(popup.dismissListener, fn)
|
||||
|
||||
case func():
|
||||
popup.dismissListener = append(popup.dismissListener, func(_ Popup) {
|
||||
fn()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
layerParams := Params{
|
||||
Style: "ruiPopupLayer",
|
||||
MaxWidth: Percent(100),
|
||||
MaxHeight: Percent(100),
|
||||
CellWidth: cellWidth,
|
||||
CellHeight: cellHeight,
|
||||
}
|
||||
|
||||
var title View = nil
|
||||
titleStyle := "ruiPopupTitle"
|
||||
closeButton, _ := boolProperty(params, CloseButton, session)
|
||||
outsideClose, _ := boolProperty(params, OutsideClose, session)
|
||||
vAlign, _ := enumProperty(params, VerticalAlign, session, CenterAlign)
|
||||
hAlign, _ := enumProperty(params, HorizontalAlign, session, CenterAlign)
|
||||
params := Params{
|
||||
Style: "ruiPopup",
|
||||
Row: popupRow,
|
||||
Column: popupColumn,
|
||||
MaxWidth: Percent(100),
|
||||
MaxHeight: Percent(100),
|
||||
CellVerticalAlign: StretchAlign,
|
||||
CellHorizontalAlign: StretchAlign,
|
||||
ClickEvent: func(View) {},
|
||||
Shadow: NewShadowWithParams(Params{
|
||||
SpreadRadius: Px(4),
|
||||
Blur: Px(16),
|
||||
ColorTag: "@ruiPopupShadow",
|
||||
}),
|
||||
}
|
||||
|
||||
var closeButton View = nil
|
||||
outsideClose := false
|
||||
buttons := []PopupButton{}
|
||||
if value, ok := params[Buttons]; ok && value != nil {
|
||||
titleStyle := "ruiPopupTitle"
|
||||
var title View = nil
|
||||
|
||||
for tag, value := range popupParams {
|
||||
if value != nil {
|
||||
switch tag {
|
||||
case VerticalAlign, HorizontalAlign, Arrow, Row, Column:
|
||||
// Do nothing
|
||||
|
||||
case Margin:
|
||||
layerParams[Padding] = value
|
||||
|
||||
case MarginLeft:
|
||||
layerParams[PaddingLeft] = value
|
||||
|
||||
case MarginRight:
|
||||
layerParams[PaddingRight] = value
|
||||
|
||||
case MarginTop:
|
||||
layerParams[PaddingTop] = value
|
||||
|
||||
case MarginBottom:
|
||||
layerParams[PaddingBottom] = value
|
||||
|
||||
case CloseButton:
|
||||
closeButton = NewGridLayout(session, Params{
|
||||
Column: 1,
|
||||
Height: "@ruiPopupTitleHeight",
|
||||
Width: "@ruiPopupTitleHeight",
|
||||
CellHorizontalAlign: CenterAlign,
|
||||
CellVerticalAlign: CenterAlign,
|
||||
TextSize: Px(20),
|
||||
Content: "✕",
|
||||
NotTranslate: true,
|
||||
ClickEvent: func(View) {
|
||||
popup.Dismiss()
|
||||
},
|
||||
})
|
||||
|
||||
case OutsideClose:
|
||||
outsideClose, _ = boolProperty(popupParams, OutsideClose, session)
|
||||
|
||||
case Buttons:
|
||||
switch value := value.(type) {
|
||||
case PopupButton:
|
||||
buttons = []PopupButton{value}
|
||||
|
@ -135,19 +408,7 @@ func (popup *popupData) init(view View, params Params) {
|
|||
case []PopupButton:
|
||||
buttons = value
|
||||
}
|
||||
}
|
||||
|
||||
popupView := NewGridLayout(view.Session(), Params{
|
||||
Style: "ruiPopup",
|
||||
MaxWidth: Percent(100),
|
||||
MaxHeight: Percent(100),
|
||||
CellVerticalAlign: StretchAlign,
|
||||
CellHorizontalAlign: StretchAlign,
|
||||
ClickEvent: func(View) {},
|
||||
})
|
||||
|
||||
for tag, value := range params {
|
||||
switch tag {
|
||||
case Title:
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
|
@ -169,48 +430,65 @@ func (popup *popupData) init(view View, params Params) {
|
|||
notCompatibleType(TitleStyle, value)
|
||||
}
|
||||
|
||||
case CloseButton, OutsideClose, VerticalAlign, HorizontalAlign, Buttons:
|
||||
// do nothing
|
||||
case DismissEvent:
|
||||
if listeners, ok := valueToNoParamListeners[Popup](value); ok {
|
||||
if listeners != nil {
|
||||
popup.dismissListener = listeners
|
||||
}
|
||||
} else {
|
||||
notCompatibleType(tag, value)
|
||||
}
|
||||
|
||||
case ArrowAlign:
|
||||
switch text := value.(type) {
|
||||
case string:
|
||||
switch text {
|
||||
case "top":
|
||||
value = "left"
|
||||
|
||||
case "bottom":
|
||||
value = "right"
|
||||
}
|
||||
}
|
||||
arrow.align, _ = enumProperty(popupParams, ArrowAlign, session, CenterAlign)
|
||||
|
||||
case ArrowSize:
|
||||
arrow.size, _ = sizeProperty(popupParams, ArrowSize, session)
|
||||
|
||||
case ArrowOffset:
|
||||
arrow.off, _ = sizeProperty(popupParams, ArrowOffset, session)
|
||||
|
||||
default:
|
||||
popupView.Set(tag, value)
|
||||
params[tag] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cellHeight []SizeUnit
|
||||
popupView := NewGridLayout(view.Session(), params)
|
||||
|
||||
var popupCellHeight []SizeUnit
|
||||
viewRow := 0
|
||||
if title != nil || closeButton {
|
||||
viewRow = 1
|
||||
titleHeight, _ := sizeConstant(popup.Session(), "ruiPopupTitleHeight")
|
||||
titleView := NewGridLayout(session, Params{
|
||||
if title != nil || closeButton != nil {
|
||||
titleContent := []View{}
|
||||
if title != nil {
|
||||
titleContent = append(titleContent, title)
|
||||
}
|
||||
if closeButton != nil {
|
||||
titleContent = append(titleContent, closeButton)
|
||||
}
|
||||
popupView.Append(NewGridLayout(session, Params{
|
||||
Row: 0,
|
||||
Style: titleStyle,
|
||||
CellWidth: []SizeUnit{Fr(1), titleHeight},
|
||||
CellWidth: []any{Fr(1), AutoSize()},
|
||||
CellVerticalAlign: CenterAlign,
|
||||
PaddingLeft: Px(12),
|
||||
})
|
||||
if title != nil {
|
||||
titleView.Append(title)
|
||||
}
|
||||
if closeButton {
|
||||
titleView.Append(NewGridLayout(session, Params{
|
||||
Column: 1,
|
||||
Height: titleHeight,
|
||||
Width: titleHeight,
|
||||
CellHorizontalAlign: CenterAlign,
|
||||
CellVerticalAlign: CenterAlign,
|
||||
TextSize: Px(20),
|
||||
Content: "✕",
|
||||
ClickEvent: func(View) {
|
||||
popup.Dismiss()
|
||||
},
|
||||
Content: titleContent,
|
||||
}))
|
||||
}
|
||||
|
||||
popupView.Append(titleView)
|
||||
cellHeight = []SizeUnit{AutoSize(), Fr(1)}
|
||||
viewRow = 1
|
||||
popupCellHeight = []SizeUnit{AutoSize(), Fr(1)}
|
||||
} else {
|
||||
cellHeight = []SizeUnit{Fr(1)}
|
||||
popupCellHeight = []SizeUnit{Fr(1)}
|
||||
}
|
||||
|
||||
view.Set(Row, viewRow)
|
||||
|
@ -218,7 +496,7 @@ func (popup *popupData) init(view View, params Params) {
|
|||
|
||||
if buttonCount := len(buttons); buttonCount > 0 {
|
||||
buttonsAlign, _ := enumProperty(params, ButtonsAlign, session, RightAlign)
|
||||
cellHeight = append(cellHeight, AutoSize())
|
||||
popupCellHeight = append(popupCellHeight, AutoSize())
|
||||
gap, _ := sizeConstant(session, "ruiPopupButtonGap")
|
||||
cellWidth := []SizeUnit{}
|
||||
for i := 0; i < buttonCount; i++ {
|
||||
|
@ -256,16 +534,16 @@ func (popup *popupData) init(view View, params Params) {
|
|||
Content: buttonsPanel,
|
||||
}))
|
||||
}
|
||||
popupView.Set(CellHeight, cellHeight)
|
||||
|
||||
popup.layerView = NewGridLayout(session, Params{
|
||||
Style: "ruiPopupLayer",
|
||||
CellVerticalAlign: vAlign,
|
||||
CellHorizontalAlign: hAlign,
|
||||
Content: NewColumnLayout(session, Params{Content: popupView}),
|
||||
MaxWidth: Percent(100),
|
||||
MaxHeight: Percent(100),
|
||||
})
|
||||
popupView.Set(CellHeight, popupCellHeight)
|
||||
|
||||
if arrow.location != NoneArrow {
|
||||
layerParams[Content] = []View{popupView, arrow.createView(popupView)}
|
||||
} else {
|
||||
layerParams[Content] = []View{popupView}
|
||||
}
|
||||
|
||||
popup.layerView = NewGridLayout(session, layerParams)
|
||||
|
||||
if outsideClose {
|
||||
popup.layerView.Set(ClickEvent, func(View) {
|
||||
|
|
|
@ -104,12 +104,14 @@ func ShowCancellableQuestion(title, text string, session Session, onYes func(),
|
|||
|
||||
type popupMenuData struct {
|
||||
items []string
|
||||
disabled []int
|
||||
session Session
|
||||
popup Popup
|
||||
result func(int)
|
||||
}
|
||||
|
||||
func (popup *popupMenuData) itemClick(list ListView, n int) {
|
||||
if popup.IsListItemEnabled(n) {
|
||||
if popup.popup != nil {
|
||||
popup.popup.Dismiss()
|
||||
popup.popup = nil
|
||||
|
@ -117,6 +119,7 @@ func (popup *popupMenuData) itemClick(list ListView, n int) {
|
|||
if popup.result != nil {
|
||||
popup.result(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (popup *popupMenuData) ListSize() int {
|
||||
|
@ -131,6 +134,13 @@ func (popup *popupMenuData) ListItem(index int, session Session) View {
|
|||
}
|
||||
|
||||
func (popup *popupMenuData) IsListItemEnabled(index int) bool {
|
||||
if popup.disabled != nil {
|
||||
for _, n := range popup.disabled {
|
||||
if index == n {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -165,13 +175,18 @@ func ShowMenu(session Session, params Params) Popup {
|
|||
return nil
|
||||
}
|
||||
|
||||
value, ok = params[PopupMenuResult]
|
||||
if ok && value != nil {
|
||||
if value, ok := params[PopupMenuResult]; ok && value != nil {
|
||||
if result, ok := value.(func(int)); ok {
|
||||
data.result = result
|
||||
}
|
||||
}
|
||||
|
||||
if value, ok := params[DisabledItems]; ok && value != nil {
|
||||
if value, ok := value.([]int); ok {
|
||||
data.disabled = value
|
||||
}
|
||||
}
|
||||
|
||||
listView := NewListView(session, Params{
|
||||
Items: adapter,
|
||||
Orientation: TopDownOrientation,
|
||||
|
@ -181,7 +196,7 @@ func ShowMenu(session Session, params Params) Popup {
|
|||
popupParams := Params{}
|
||||
for tag, value := range params {
|
||||
switch tag {
|
||||
case Items, PopupMenuResult:
|
||||
case Items, PopupMenuResult, DisabledItems:
|
||||
// do nothing
|
||||
|
||||
default:
|
||||
|
|
|
@ -22,7 +22,7 @@ type progressBarData struct {
|
|||
// NewProgressBar create new ProgressBar object and return it
|
||||
func NewProgressBar(session Session, params Params) ProgressBar {
|
||||
view := new(progressBarData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ func newProgressBar(session Session) View {
|
|||
return NewProgressBar(session, nil)
|
||||
}
|
||||
|
||||
func (progress *progressBarData) Init(session Session) {
|
||||
progress.viewData.Init(session)
|
||||
func (progress *progressBarData) init(session Session) {
|
||||
progress.viewData.init(session)
|
||||
progress.tag = "ProgressBar"
|
||||
}
|
||||
|
||||
|
@ -65,19 +65,19 @@ func (progress *progressBarData) propertyChanged(tag string) {
|
|||
if progress.created {
|
||||
switch tag {
|
||||
case ProgressBarMax:
|
||||
updateProperty(progress.htmlID(), Max, strconv.FormatFloat(GetProgressBarMax(progress, ""), 'f', -1, 32), progress.session)
|
||||
updateProperty(progress.htmlID(), Max, strconv.FormatFloat(GetProgressBarMax(progress), 'f', -1, 32), progress.session)
|
||||
|
||||
case ProgressBarValue:
|
||||
updateProperty(progress.htmlID(), Value, strconv.FormatFloat(GetProgressBarValue(progress, ""), 'f', -1, 32), progress.session)
|
||||
updateProperty(progress.htmlID(), Value, strconv.FormatFloat(GetProgressBarValue(progress), 'f', -1, 32), progress.session)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (progress *progressBarData) Set(tag string, value interface{}) bool {
|
||||
func (progress *progressBarData) Set(tag string, value any) bool {
|
||||
return progress.set(progress.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (progress *progressBarData) set(tag string, value interface{}) bool {
|
||||
func (progress *progressBarData) set(tag string, value any) bool {
|
||||
if progress.viewData.set(tag, value) {
|
||||
progress.propertyChanged(tag)
|
||||
return true
|
||||
|
@ -85,7 +85,7 @@ func (progress *progressBarData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (progress *progressBarData) Get(tag string) interface{} {
|
||||
func (progress *progressBarData) Get(tag string) any {
|
||||
return progress.get(progress.normalizeTag(tag))
|
||||
}
|
||||
|
||||
|
@ -97,44 +97,22 @@ func (progress *progressBarData) htmlProperties(self View, buffer *strings.Build
|
|||
progress.viewData.htmlProperties(self, buffer)
|
||||
|
||||
buffer.WriteString(` max="`)
|
||||
buffer.WriteString(strconv.FormatFloat(GetProgressBarMax(progress, ""), 'f', -1, 64))
|
||||
buffer.WriteString(strconv.FormatFloat(GetProgressBarMax(progress), 'f', -1, 64))
|
||||
buffer.WriteByte('"')
|
||||
|
||||
buffer.WriteString(` value="`)
|
||||
buffer.WriteString(strconv.FormatFloat(GetProgressBarValue(progress, ""), 'f', -1, 64))
|
||||
buffer.WriteString(strconv.FormatFloat(GetProgressBarValue(progress), 'f', -1, 64))
|
||||
buffer.WriteByte('"')
|
||||
}
|
||||
|
||||
// GetProgressBarMax returns the max value of ProgressBar subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetProgressBarMax(view View, subviewID string) float64 {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
result, ok := floatStyledProperty(view, ProgressBarMax, 1)
|
||||
if !ok {
|
||||
result, _ = floatStyledProperty(view, Max, 1)
|
||||
}
|
||||
return result
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetProgressBarMax(view View, subviewID ...string) float64 {
|
||||
return floatStyledProperty(view, subviewID, ProgressBarMax, 1)
|
||||
}
|
||||
|
||||
// GetProgressBarValue returns the value of ProgressBar subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetProgressBarValue(view View, subviewID string) float64 {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
result, ok := floatStyledProperty(view, ProgressBarValue, 0)
|
||||
if !ok {
|
||||
result, _ = floatStyledProperty(view, Value, 0)
|
||||
}
|
||||
return result
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetProgressBarValue(view View, subviewID ...string) float64 {
|
||||
return floatStyledProperty(view, subviewID, ProgressBarValue, 0)
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@ import (
|
|||
type Properties interface {
|
||||
// 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.
|
||||
Get(tag string) interface{}
|
||||
getRaw(tag string) interface{}
|
||||
Get(tag string) any
|
||||
getRaw(tag string) any
|
||||
// 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
|
||||
// a description of the error is written to the log
|
||||
Set(tag string, value interface{}) bool
|
||||
setRaw(tag string, value interface{})
|
||||
Set(tag string, value any) bool
|
||||
setRaw(tag string, value any)
|
||||
// Remove removes the property with name defined by the argument
|
||||
Remove(tag string)
|
||||
// Clear removes all properties
|
||||
|
@ -25,25 +25,25 @@ type Properties interface {
|
|||
}
|
||||
|
||||
type propertyList struct {
|
||||
properties map[string]interface{}
|
||||
properties map[string]any
|
||||
}
|
||||
|
||||
func (properties *propertyList) init() {
|
||||
properties.properties = map[string]interface{}{}
|
||||
properties.properties = map[string]any{}
|
||||
}
|
||||
|
||||
func (properties *propertyList) Get(tag string) interface{} {
|
||||
func (properties *propertyList) Get(tag string) any {
|
||||
return properties.getRaw(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (properties *propertyList) getRaw(tag string) interface{} {
|
||||
func (properties *propertyList) getRaw(tag string) any {
|
||||
if value, ok := properties.properties[tag]; ok {
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (properties *propertyList) setRaw(tag string, value interface{}) {
|
||||
func (properties *propertyList) setRaw(tag string, value any) {
|
||||
properties.properties[tag] = value
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ func (properties *propertyList) remove(tag string) {
|
|||
}
|
||||
|
||||
func (properties *propertyList) Clear() {
|
||||
properties.properties = map[string]interface{}{}
|
||||
properties.properties = map[string]any{}
|
||||
}
|
||||
|
||||
func (properties *propertyList) AllTags() []string {
|
||||
|
|
|
@ -32,49 +32,49 @@ func TestProperties(t *testing.T) {
|
|||
t.Error(`list.Get("name") is not string`)
|
||||
}
|
||||
|
||||
sizeValues := []interface{}{"@small", "auto", "10px", Pt(20), AutoSize()}
|
||||
sizeValues := []any{"@small", "auto", "10px", Pt(20), AutoSize()}
|
||||
for _, value := range sizeValues {
|
||||
if !list.setSizeProperty("size", value) {
|
||||
t.Errorf(`setSizeProperty("size", %v) fail`, value)
|
||||
}
|
||||
}
|
||||
|
||||
failSizeValues := []interface{}{"@small,big", "abc", "10", Color(20), 100}
|
||||
failSizeValues := []any{"@small,big", "abc", "10", Color(20), 100}
|
||||
for _, value := range failSizeValues {
|
||||
if list.setSizeProperty("size", value) {
|
||||
t.Errorf(`setSizeProperty("size", %v) success`, value)
|
||||
}
|
||||
}
|
||||
|
||||
angleValues := []interface{}{"@angle", "2pi", "π", "3deg", "60°", Rad(1.5), Deg(45), 1, 1.5}
|
||||
angleValues := []any{"@angle", "2pi", "π", "3deg", "60°", Rad(1.5), Deg(45), 1, 1.5}
|
||||
for _, value := range angleValues {
|
||||
if !list.setAngleProperty("angle", value) {
|
||||
t.Errorf(`setAngleProperty("angle", %v) fail`, value)
|
||||
}
|
||||
}
|
||||
|
||||
failAngleValues := []interface{}{"@angle,2", "pi32", "deg", "60°x", Color(0xFFFFFFFF)}
|
||||
failAngleValues := []any{"@angle,2", "pi32", "deg", "60°x", Color(0xFFFFFFFF)}
|
||||
for _, value := range failAngleValues {
|
||||
if list.setAngleProperty("angle", value) {
|
||||
t.Errorf(`setAngleProperty("angle", %v) success`, value)
|
||||
}
|
||||
}
|
||||
|
||||
colorValues := []interface{}{"@color", "#FF234567", "#234567", "rgba(30%, 128, 0.5, .25)", "rgb(30%, 128, 0.5)", Color(0xFFFFFFFF), 0xFFFFFFFF, White}
|
||||
colorValues := []any{"@color", "#FF234567", "#234567", "rgba(30%, 128, 0.5, .25)", "rgb(30%, 128, 0.5)", Color(0xFFFFFFFF), 0xFFFFFFFF, White}
|
||||
for _, color := range colorValues {
|
||||
if !list.setColorProperty("color", color) {
|
||||
t.Errorf(`list.setColorProperty("color", %v) fail`, color)
|
||||
}
|
||||
}
|
||||
|
||||
failColorValues := []interface{}{"@color|2", "#FF234567FF", "#TT234567", "rgba(500%, 128, 10.5, .25)", 10.6}
|
||||
failColorValues := []any{"@color|2", "#FF234567FF", "#TT234567", "rgba(500%, 128, 10.5, .25)", 10.6}
|
||||
for _, color := range failColorValues {
|
||||
if list.setColorProperty("color", color) {
|
||||
t.Errorf(`list.setColorProperty("color", %v) success`, color)
|
||||
}
|
||||
}
|
||||
|
||||
enumValues := []interface{}{"@enum", "inherit", "on", Inherit, 2}
|
||||
enumValues := []any{"@enum", "inherit", "on", Inherit, 2}
|
||||
inheritOffOn := inheritOffOnValues()
|
||||
for _, value := range enumValues {
|
||||
if !list.setEnumProperty("enum", value, inheritOffOn) {
|
||||
|
@ -82,56 +82,56 @@ func TestProperties(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
failEnumValues := []interface{}{"@enum 13", "inherit2", "onn", -1, 10}
|
||||
failEnumValues := []any{"@enum 13", "inherit2", "onn", -1, 10}
|
||||
for _, value := range failEnumValues {
|
||||
if list.setEnumProperty("enum", value, inheritOffOn) {
|
||||
t.Errorf(`list.setEnumProperty("enum", %v, %v) success`, value, inheritOffOn)
|
||||
}
|
||||
}
|
||||
|
||||
boolValues := []interface{}{"@bool", "true", "yes ", "on", " 1", "false", "no", "off", "0", 0, 1, false, true}
|
||||
boolValues := []any{"@bool", "true", "yes ", "on", " 1", "false", "no", "off", "0", 0, 1, false, true}
|
||||
for _, value := range boolValues {
|
||||
if !list.setBoolProperty("bool", value) {
|
||||
t.Errorf(`list.setBoolProperty("bool", %v) fail`, value)
|
||||
}
|
||||
}
|
||||
|
||||
failBoolValues := []interface{}{"@bool,2", "tr", "ys", "10", -1, 10, 0.8}
|
||||
failBoolValues := []any{"@bool,2", "tr", "ys", "10", -1, 10, 0.8}
|
||||
for _, value := range failBoolValues {
|
||||
if list.setBoolProperty("bool", value) {
|
||||
t.Errorf(`list.setBoolProperty("bool", %v) success`, value)
|
||||
}
|
||||
}
|
||||
|
||||
intValues := []interface{}{"@int", " 100", "-10 ", 0, 250}
|
||||
intValues := []any{"@int", " 100", "-10 ", 0, 250}
|
||||
for _, value := range intValues {
|
||||
if !list.setIntProperty("int", value) {
|
||||
t.Errorf(`list.setIntProperty("int", %v) fail`, value)
|
||||
}
|
||||
}
|
||||
|
||||
failIntValues := []interface{}{"@int|10", "100i", "-1.0 ", 0.0}
|
||||
failIntValues := []any{"@int|10", "100i", "-1.0 ", 0.0}
|
||||
for _, value := range failIntValues {
|
||||
if list.setIntProperty("int", value) {
|
||||
t.Errorf(`list.setIntProperty("int", %v) success`, value)
|
||||
}
|
||||
}
|
||||
|
||||
floatValues := []interface{}{"@float", " 100.25", "-1.5e12 ", uint(0), 250, float32(10.2), float64(0)}
|
||||
floatValues := []any{"@float", " 100.25", "-1.5e12 ", uint(0), 250, float32(10.2), float64(0)}
|
||||
for _, value := range floatValues {
|
||||
if !list.setFloatProperty("float", value) {
|
||||
t.Errorf(`list.setFloatProperty("float", %v) fail`, value)
|
||||
}
|
||||
}
|
||||
|
||||
failFloatValues := []interface{}{"@float|2", " 100.25i", "-1.5ee12 ", "abc"}
|
||||
failFloatValues := []any{"@float|2", " 100.25i", "-1.5ee12 ", "abc"}
|
||||
for _, value := range failFloatValues {
|
||||
if list.setFloatProperty("float", value) {
|
||||
t.Errorf(`list.setFloatProperty("float", %v) success`, value)
|
||||
}
|
||||
}
|
||||
|
||||
boundsValues := []interface{}{"@bounds", "10px,20pt,@bottom,0", Em(2), []interface{}{"@top", Px(10), AutoSize(), "14pt"}}
|
||||
boundsValues := []any{"@bounds", "10px,20pt,@bottom,0", Em(2), []any{"@top", Px(10), AutoSize(), "14pt"}}
|
||||
for _, value := range boundsValues {
|
||||
if !list.setBoundsProperty("margin", value) {
|
||||
t.Errorf(`list.setBoundsProperty("margin", %v) fail`, value)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package rui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
@ -31,16 +32,29 @@ func imageProperty(properties Properties, tag string, session Session) (string,
|
|||
return "", false
|
||||
}
|
||||
|
||||
func valueToSizeUnit(value interface{}, session Session) (SizeUnit, bool) {
|
||||
func valueToSizeUnit(value any, session Session) (SizeUnit, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case SizeUnit:
|
||||
return value, true
|
||||
|
||||
case SizeFunc:
|
||||
return SizeUnit{Type: SizeFunction, Function: value}, true
|
||||
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok {
|
||||
return StringToSizeUnit(text)
|
||||
}
|
||||
|
||||
case float64:
|
||||
return Px(value), true
|
||||
|
||||
case float32:
|
||||
return Px(float64(value)), true
|
||||
}
|
||||
|
||||
if n, ok := isInt(value); ok {
|
||||
return Px(float64(n)), true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +81,7 @@ func angleProperty(properties Properties, tag string, session Session) (AngleUni
|
|||
return AngleUnit{Type: 0, Value: 0}, false
|
||||
}
|
||||
|
||||
func valueToColor(value interface{}, session Session) (Color, bool) {
|
||||
func valueToColor(value any, session Session) (Color, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case Color:
|
||||
|
@ -88,7 +102,7 @@ func colorProperty(properties Properties, tag string, session Session) (Color, b
|
|||
return valueToColor(properties.getRaw(tag), session)
|
||||
}
|
||||
|
||||
func valueToEnum(value interface{}, tag string, session Session, defaultValue int) (int, bool) {
|
||||
func valueToEnum(value any, tag string, session Session, defaultValue int) (int, bool) {
|
||||
if value != nil {
|
||||
values := enumProperties[tag].values
|
||||
switch value := value.(type) {
|
||||
|
@ -155,7 +169,7 @@ func enumProperty(properties Properties, tag string, session Session, defaultVal
|
|||
return valueToEnum(properties.getRaw(tag), tag, session, defaultValue)
|
||||
}
|
||||
|
||||
func valueToBool(value interface{}, session Session) (bool, bool) {
|
||||
func valueToBool(value any, session Session) (bool, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case bool:
|
||||
|
@ -184,7 +198,7 @@ func boolProperty(properties Properties, tag string, session Session) (bool, boo
|
|||
return valueToBool(properties.getRaw(tag), session)
|
||||
}
|
||||
|
||||
func valueToInt(value interface{}, session Session, defaultValue int) (int, bool) {
|
||||
func valueToInt(value any, session Session, defaultValue int) (int, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
|
@ -214,7 +228,7 @@ func intProperty(properties Properties, tag string, session Session, defaultValu
|
|||
return valueToInt(properties.getRaw(tag), session, defaultValue)
|
||||
}
|
||||
|
||||
func valueToFloat(value interface{}, session Session, defaultValue float64) (float64, bool) {
|
||||
func valueToFloat(value any, session Session, defaultValue float64) (float64, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case float64:
|
||||
|
@ -238,7 +252,31 @@ func floatProperty(properties Properties, tag string, session Session, defaultVa
|
|||
return valueToFloat(properties.getRaw(tag), session, defaultValue)
|
||||
}
|
||||
|
||||
func valueToRange(value interface{}, session Session) (Range, bool) {
|
||||
func valueToFloatText(value any, session Session, defaultValue float64) (string, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case float64:
|
||||
return fmt.Sprintf("%g", value), true
|
||||
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok {
|
||||
if _, err := strconv.ParseFloat(text, 64); err != nil {
|
||||
ErrorLog(err.Error())
|
||||
return fmt.Sprintf("%g", defaultValue), false
|
||||
}
|
||||
return text, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%g", defaultValue), false
|
||||
}
|
||||
|
||||
func floatTextProperty(properties Properties, tag string, session Session, defaultValue float64) (string, bool) {
|
||||
return valueToFloatText(properties.getRaw(tag), session, defaultValue)
|
||||
}
|
||||
|
||||
func valueToRange(value any, session Session) (Range, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case Range:
|
||||
|
|
|
@ -45,6 +45,12 @@ const (
|
|||
// Opacity is the degree to which content behind an element is hidden, and is the opposite of transparency.
|
||||
Opacity = "opacity"
|
||||
|
||||
// Overflow is the constant for the "overflow" property tag.
|
||||
// The "overflow" int property sets the desired behavior for an element's overflow — i.e.
|
||||
// when an element's content is too big to fit in its block formatting context — in both directions.
|
||||
// Valid values: OverflowHidden (0), OverflowVisible (1), OverflowScroll (2), OverflowAuto (3)
|
||||
Overflow = "overflow"
|
||||
|
||||
// Row is the constant for the "row" property tag.
|
||||
Row = "row"
|
||||
|
||||
|
@ -141,6 +147,10 @@ const (
|
|||
// The "padding-bottom" SizeUnit property sets the height of the padding area to the bottom of a view.
|
||||
PaddingBottom = "padding-bottom"
|
||||
|
||||
// AccentColor is the constant for the "accent-color" property tag.
|
||||
// The "accent-color" property sets sets the accent color for UI controls generated by some elements.
|
||||
AccentColor = "accent-color"
|
||||
|
||||
// BackgroundColor is the constant for the "background-color" property tag.
|
||||
// The "background-color" property sets the background color of a view.
|
||||
BackgroundColor = "background-color"
|
||||
|
@ -314,20 +324,20 @@ const (
|
|||
// This is an inherited property, i.e. if it is not defined, then the value of the parent view is used.
|
||||
Underline = "underline"
|
||||
|
||||
// TextLineThickness is the constant for the "text-decoration-thickness" property tag.
|
||||
// The "text-decoration-thickness" SizeUnit property sets the stroke thickness of the decoration line that
|
||||
// TextLineThickness is the constant for the "text-line-thickness" property tag.
|
||||
// The "text-line-thickness" SizeUnit property sets the stroke thickness of the decoration line that
|
||||
// is used on text in an element, such as a line-through, underline, or overline.
|
||||
// This is an inherited property, i.e. if it is not defined, then the value of the parent view is used.
|
||||
TextLineThickness = "text-line-thickness"
|
||||
|
||||
// TextLineStyle is the constant for the "text-decoration-style" property tag.
|
||||
// The "text-decoration-style" int property sets the style of the lines specified by "text-decoration" property.
|
||||
// TextLineStyle is the constant for the "text-line-style" property tag.
|
||||
// The "text-line-style" int property sets the style of the lines specified by "text-decoration" property.
|
||||
// The style applies to all lines that are set with "text-decoration" property.
|
||||
// This is an inherited property, i.e. if it is not defined, then the value of the parent view is used.
|
||||
TextLineStyle = "text-line-style"
|
||||
|
||||
// TextLineColor is the constant for the "text-decoration-color" property tag.
|
||||
// The "text-decoration-color" Color property sets the color of the lines specified by "text-decoration" property.
|
||||
// TextLineColor is the constant for the "text-line-color" property tag.
|
||||
// The "text-line-color" Color property sets the color of the lines specified by "text-decoration" property.
|
||||
// The color applies to all lines that are set with "text-decoration" property.
|
||||
// This is an inherited property, i.e. if it is not defined, then the value of the parent view is used.
|
||||
TextLineColor = "text-line-color"
|
||||
|
@ -349,6 +359,11 @@ const (
|
|||
// This is an inherited property, i.e. if it is not defined, then the value of the parent view is used.
|
||||
TextShadow = "text-shadow"
|
||||
|
||||
// TabSize is the constant for the "tab-size" property tag.
|
||||
// The "tab-size" int property sets the width of tab characters (U+0009) in spaces.
|
||||
// This is an inherited property, i.e. if it is not defined, then the value of the parent view is used.
|
||||
TabSize = "tab-size"
|
||||
|
||||
// LetterSpacing is the constant for the "letter-spacing" property tag.
|
||||
// The "letter-spacing" SizeUnit property sets the horizontal spacing behavior between text characters.
|
||||
// This value is added to the natural spacing between characters while rendering the text.
|
||||
|
@ -553,9 +568,19 @@ const (
|
|||
// Orientation is the constant for the "orientation" property tag.
|
||||
Orientation = "orientation"
|
||||
|
||||
// Gap is the constant for the "gap" property tag.
|
||||
// Gap is t he constant for the "gap" property tag.
|
||||
Gap = "gap"
|
||||
|
||||
// ListRowGap is the constant for the "list-row-gap" property tag.
|
||||
// The "list-row-gap" SizeUnit properties allow to set the distance between the rows of the ListLayout or ListView.
|
||||
// The default is 0px.
|
||||
ListRowGap = "list-row-gap"
|
||||
|
||||
// ListColumnGap is the constant for the "list-column-gap" property tag.
|
||||
// The "list-column-gap" SizeUnit properties allow to set the distance between the columns of the GridLayout or ListView.
|
||||
// The default is 0px.
|
||||
ListColumnGap = "list-column-gap"
|
||||
|
||||
// Text is the constant for the "text" property tag.
|
||||
Text = "text"
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ var boolProperties = []string{
|
|||
|
||||
var intProperties = []string{
|
||||
ZIndex,
|
||||
TabSize,
|
||||
HeadHeight,
|
||||
FootHeight,
|
||||
RowSpan,
|
||||
|
@ -109,6 +110,8 @@ var sizeProperties = map[string]string{
|
|||
WordSpacing: WordSpacing,
|
||||
LineHeight: LineHeight,
|
||||
TextLineThickness: "text-decoration-thickness",
|
||||
ListRowGap: "row-gap",
|
||||
ListColumnGap: "column-gap",
|
||||
GridRowGap: GridRowGap,
|
||||
GridColumnGap: GridColumnGap,
|
||||
ColumnWidth: ColumnWidth,
|
||||
|
@ -179,6 +182,11 @@ var enumProperties = map[string]struct {
|
|||
"",
|
||||
[]string{"visible", "invisible", "gone"},
|
||||
},
|
||||
Overflow: {
|
||||
[]string{"hidden", "visible", "scroll", "auto"},
|
||||
Overflow,
|
||||
[]string{"hidden", "visible", "scroll", "auto"},
|
||||
},
|
||||
TextAlign: {
|
||||
[]string{"left", "right", "center", "justify"},
|
||||
TextAlign,
|
||||
|
@ -304,6 +312,11 @@ var enumProperties = map[string]struct {
|
|||
"",
|
||||
[]string{"left", "right", "center", "stretch"},
|
||||
},
|
||||
ArrowAlign: {
|
||||
[]string{"left", "right", "center"},
|
||||
"",
|
||||
[]string{"left", "right", "center"},
|
||||
},
|
||||
CellVerticalAlign: {
|
||||
[]string{"top", "bottom", "center", "stretch"},
|
||||
"align-items",
|
||||
|
@ -429,13 +442,18 @@ var enumProperties = map[string]struct {
|
|||
"resize",
|
||||
[]string{"none", "both", "horizontal", "vertical"},
|
||||
},
|
||||
Arrow: {
|
||||
[]string{"none", "top", "right", "bottom", "left"},
|
||||
"",
|
||||
[]string{"none", "top", "right", "bottom", "left"},
|
||||
},
|
||||
}
|
||||
|
||||
func notCompatibleType(tag string, value interface{}) {
|
||||
func notCompatibleType(tag string, value any) {
|
||||
ErrorLogF(`"%T" type not compatible with "%s" property`, value, tag)
|
||||
}
|
||||
|
||||
func invalidPropertyValue(tag string, value interface{}) {
|
||||
func invalidPropertyValue(tag string, value any) {
|
||||
ErrorLogF(`Invalid value "%v" of "%s" property`, value, tag)
|
||||
}
|
||||
|
||||
|
@ -457,7 +475,7 @@ func isConstantName(text string) bool {
|
|||
return !strings.ContainsAny(text, ",;|\"'`+(){}[]<>/\\*&%! \t\n\r")
|
||||
}
|
||||
|
||||
func isInt(value interface{}) (int, bool) {
|
||||
func isInt(value any) (int, bool) {
|
||||
var n int
|
||||
switch value := value.(type) {
|
||||
case int:
|
||||
|
@ -497,7 +515,7 @@ func isInt(value interface{}) (int, bool) {
|
|||
return n, true
|
||||
}
|
||||
|
||||
func (properties *propertyList) setSimpleProperty(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) setSimpleProperty(tag string, value any) bool {
|
||||
if value == nil {
|
||||
delete(properties.properties, tag)
|
||||
return true
|
||||
|
@ -515,19 +533,26 @@ func (properties *propertyList) setSimpleProperty(tag string, value interface{})
|
|||
return false
|
||||
}
|
||||
|
||||
func (properties *propertyList) setSizeProperty(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) setSizeProperty(tag string, value any) bool {
|
||||
if !properties.setSimpleProperty(tag, value) {
|
||||
var size SizeUnit
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
var ok bool
|
||||
if size, ok = StringToSizeUnit(value); !ok {
|
||||
if fn := parseSizeFunc(value); fn != nil {
|
||||
size.Type = SizeFunction
|
||||
size.Function = fn
|
||||
} else if size, ok = StringToSizeUnit(value); !ok {
|
||||
invalidPropertyValue(tag, value)
|
||||
return false
|
||||
}
|
||||
case SizeUnit:
|
||||
size = value
|
||||
|
||||
case SizeFunc:
|
||||
size.Type = SizeFunction
|
||||
size.Function = value
|
||||
|
||||
case float32:
|
||||
size.Type = SizeInPixel
|
||||
size.Value = float64(value)
|
||||
|
@ -556,7 +581,7 @@ func (properties *propertyList) setSizeProperty(tag string, value interface{}) b
|
|||
return true
|
||||
}
|
||||
|
||||
func (properties *propertyList) setAngleProperty(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) setAngleProperty(tag string, value any) bool {
|
||||
if !properties.setSimpleProperty(tag, value) {
|
||||
var angle AngleUnit
|
||||
switch value := value.(type) {
|
||||
|
@ -589,7 +614,7 @@ func (properties *propertyList) setAngleProperty(tag string, value interface{})
|
|||
return true
|
||||
}
|
||||
|
||||
func (properties *propertyList) setColorProperty(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) setColorProperty(tag string, value any) bool {
|
||||
if !properties.setSimpleProperty(tag, value) {
|
||||
var result Color
|
||||
switch value := value.(type) {
|
||||
|
@ -621,7 +646,7 @@ func (properties *propertyList) setColorProperty(tag string, value interface{})
|
|||
return true
|
||||
}
|
||||
|
||||
func (properties *propertyList) setEnumProperty(tag string, value interface{}, values []string) bool {
|
||||
func (properties *propertyList) setEnumProperty(tag string, value any, values []string) bool {
|
||||
if !properties.setSimpleProperty(tag, value) {
|
||||
var n int
|
||||
if text, ok := value.(string); ok {
|
||||
|
@ -646,7 +671,7 @@ func (properties *propertyList) setEnumProperty(tag string, value interface{}, v
|
|||
return true
|
||||
}
|
||||
|
||||
func (properties *propertyList) setBoolProperty(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) setBoolProperty(tag string, value any) bool {
|
||||
if !properties.setSimpleProperty(tag, value) {
|
||||
if text, ok := value.(string); ok {
|
||||
switch strings.ToLower(strings.Trim(text, " \t")) {
|
||||
|
@ -683,7 +708,7 @@ func (properties *propertyList) setBoolProperty(tag string, value interface{}) b
|
|||
return true
|
||||
}
|
||||
|
||||
func (properties *propertyList) setIntProperty(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) setIntProperty(tag string, value any) bool {
|
||||
if !properties.setSimpleProperty(tag, value) {
|
||||
if text, ok := value.(string); ok {
|
||||
n, err := strconv.Atoi(strings.Trim(text, " \t"))
|
||||
|
@ -704,7 +729,7 @@ func (properties *propertyList) setIntProperty(tag string, value interface{}) bo
|
|||
return true
|
||||
}
|
||||
|
||||
func (properties *propertyList) setFloatProperty(tag string, value interface{}, min, max float64) bool {
|
||||
func (properties *propertyList) setFloatProperty(tag string, value any, min, max float64) bool {
|
||||
if !properties.setSimpleProperty(tag, value) {
|
||||
f := float64(0)
|
||||
switch value := value.(type) {
|
||||
|
@ -715,6 +740,12 @@ func (properties *propertyList) setFloatProperty(tag string, value interface{},
|
|||
ErrorLog(err.Error())
|
||||
return false
|
||||
}
|
||||
if f < min || f > max {
|
||||
ErrorLogF(`"%T" out of range of "%s" property`, value, tag)
|
||||
return false
|
||||
}
|
||||
properties.properties[tag] = value
|
||||
return true
|
||||
|
||||
case float32:
|
||||
f = float64(value)
|
||||
|
@ -742,11 +773,11 @@ func (properties *propertyList) setFloatProperty(tag string, value interface{},
|
|||
return true
|
||||
}
|
||||
|
||||
func (properties *propertyList) Set(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) Set(tag string, value any) bool {
|
||||
return properties.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (properties *propertyList) set(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
delete(properties.properties, tag)
|
||||
return true
|
||||
|
|
|
@ -3,29 +3,57 @@ package rui
|
|||
const (
|
||||
// Visible - default value of the view Visibility property: View is visible
|
||||
Visible = 0
|
||||
|
||||
// Invisible - value of the view Visibility property: View is invisible but takes place
|
||||
Invisible = 1
|
||||
|
||||
// Gone - value of the view Visibility property: View is invisible and does not take place
|
||||
Gone = 2
|
||||
|
||||
// OverflowHidden - value of the view "overflow" property:
|
||||
// Content is clipped if necessary to fit the padding box. No scrollbars are provided,
|
||||
// and no support for allowing the user to scroll (such as by dragging or using a scroll wheel) is allowed.
|
||||
// The content can be scrolled programmatically, so the element is still a scroll container.
|
||||
OverflowHidden = 0
|
||||
|
||||
// OverflowVisible - value of the view "overflow" property:
|
||||
// Content is not clipped and may be rendered outside the padding box.
|
||||
OverflowVisible = 1
|
||||
|
||||
// OverflowScroll - value of the view "overflow" property:
|
||||
// Content is clipped if necessary to fit the padding box. Browsers always display scrollbars whether or
|
||||
// not any content is actually clipped, preventing scrollbars from appearing or disappearing as content changes.
|
||||
OverflowScroll = 2
|
||||
|
||||
// OverflowAuto - value of the view "overflow" property:
|
||||
// Depends on the browser user agent. If content fits inside the padding box, it looks the same as OverflowVisible,
|
||||
// but still establishes a new block formatting context. Desktop browsers provide scrollbars if content overflows.
|
||||
OverflowAuto = 3
|
||||
|
||||
// NoneTextTransform - not transform text
|
||||
NoneTextTransform = 0
|
||||
|
||||
// CapitalizeTextTransform - capitalize text
|
||||
CapitalizeTextTransform = 1
|
||||
|
||||
// LowerCaseTextTransform - transform text to lower case
|
||||
LowerCaseTextTransform = 2
|
||||
|
||||
// UpperCaseTextTransform - transform text to upper case
|
||||
UpperCaseTextTransform = 3
|
||||
|
||||
// HorizontalTopToBottom - content flows horizontally from left to right, vertically from top to bottom.
|
||||
// The next horizontal line is positioned below the previous line.
|
||||
HorizontalTopToBottom = 0
|
||||
|
||||
// HorizontalBottomToTop - content flows horizontally from left to right, vertically from bottom to top.
|
||||
// The next horizontal line is positioned above the previous line.
|
||||
HorizontalBottomToTop = 1
|
||||
|
||||
// VerticalRightToLeft - content flows vertically from top to bottom, horizontally from right to left.
|
||||
// The next vertical line is positioned to the left of the previous line.
|
||||
VerticalRightToLeft = 2
|
||||
|
||||
// VerticalLeftToRight - content flows vertically from top to bottom, horizontally from left to right.
|
||||
// The next vertical line is positioned to the right of the previous line.
|
||||
VerticalLeftToRight = 3
|
||||
|
@ -33,6 +61,7 @@ const (
|
|||
// MixedTextOrientation - rotates the characters of horizontal scripts 90° clockwise.
|
||||
// Lays out the characters of vertical scripts naturally. Default value.
|
||||
MixedTextOrientation = 0
|
||||
|
||||
// UprightTextOrientation - lays out the characters of horizontal scripts naturally (upright),
|
||||
// as well as the glyphs for vertical scripts. Note that this keyword causes all characters
|
||||
// to be considered as left-to-right: the used value of "text-direction" is forced to be "left-to-right".
|
||||
|
@ -40,62 +69,84 @@ const (
|
|||
|
||||
// SystemTextDirection - direction of a text and other elements defined by system. This is the default value.
|
||||
SystemTextDirection = 0
|
||||
|
||||
// LeftToRightDirection - text and other elements go from left to right.
|
||||
LeftToRightDirection = 1
|
||||
|
||||
//RightToLeftDirection - text and other elements go from right to left.
|
||||
RightToLeftDirection = 2
|
||||
|
||||
// ThinFont - the value of "text-weight" property: the thin (hairline) text weight
|
||||
ThinFont = 1
|
||||
|
||||
// ExtraLightFont - the value of "text-weight" property: the extra light (ultra light) text weight
|
||||
ExtraLightFont = 2
|
||||
|
||||
// LightFont - the value of "text-weight" property: the light text weight
|
||||
LightFont = 3
|
||||
|
||||
// NormalFont - the value of "text-weight" property (default value): the normal text weight
|
||||
NormalFont = 4
|
||||
|
||||
// MediumFont - the value of "text-weight" property: the medium text weight
|
||||
MediumFont = 5
|
||||
|
||||
// SemiBoldFont - the value of "text-weight" property: the semi bold (demi bold) text weight
|
||||
SemiBoldFont = 6
|
||||
|
||||
// BoldFont - the value of "text-weight" property: the bold text weight
|
||||
BoldFont = 7
|
||||
|
||||
// ExtraBoldFont - the value of "text-weight" property: the extra bold (ultra bold) text weight
|
||||
ExtraBoldFont = 8
|
||||
|
||||
// BlackFont - the value of "text-weight" property: the black (heavy) text weight
|
||||
BlackFont = 9
|
||||
|
||||
// TopAlign - top vertical-align for the "vertical-align" property
|
||||
TopAlign = 0
|
||||
|
||||
// BottomAlign - bottom vertical-align for the "vertical-align" property
|
||||
BottomAlign = 1
|
||||
|
||||
// LeftAlign - the left horizontal-align for the "horizontal-align" property
|
||||
LeftAlign = 0
|
||||
|
||||
// RightAlign - the right horizontal-align for the "horizontal-align" property
|
||||
RightAlign = 1
|
||||
|
||||
// CenterAlign - the center horizontal/vertical-align for the "horizontal-align"/"vertical-align" property
|
||||
CenterAlign = 2
|
||||
|
||||
// StretchAlign - the stretch horizontal/vertical-align for the "horizontal-align"/"vertical-align" property
|
||||
StretchAlign = 3
|
||||
|
||||
// JustifyAlign - the justify text align for "text-align" property
|
||||
JustifyAlign = 3
|
||||
|
||||
// BaselineAlign - the baseline cell-vertical-align for the "cell-vertical-align" property
|
||||
BaselineAlign = 4
|
||||
|
||||
// WhiteSpaceNormal - sequences of white space are collapsed. Newline characters in the source
|
||||
// are handled the same as other white space. Lines are broken as necessary to fill line boxes.
|
||||
WhiteSpaceNormal = 0
|
||||
|
||||
// WhiteSpaceNowrap - collapses white space as for normal, but suppresses line breaks (text wrapping)
|
||||
// within the source.
|
||||
WhiteSpaceNowrap = 1
|
||||
|
||||
// WhiteSpacePre - sequences of white space are preserved. Lines are only broken at newline
|
||||
// characters in the source and at <br> elements.
|
||||
WhiteSpacePre = 2
|
||||
|
||||
// WhiteSpacePreWrap - Sequences of white space are preserved. Lines are broken at newline
|
||||
// characters, at <br>, and as necessary to fill line boxes.
|
||||
WhiteSpacePreWrap = 3
|
||||
|
||||
// WhiteSpacePreLine - sequences of white space are collapsed. Lines are broken at newline characters,
|
||||
// at <br>, and as necessary to fill line boxes.
|
||||
WhiteSpacePreLine = 4
|
||||
|
||||
// WhiteSpaceBreakSpaces - the behavior is identical to that of WhiteSpacePreWrap, except that:
|
||||
// * Any sequence of preserved white space always takes up space, including at the end of the line.
|
||||
// * A line breaking opportunity exists after every preserved white space character, including between white space characters.
|
||||
|
@ -104,12 +155,15 @@ const (
|
|||
|
||||
// WordBreakNormal - use the default line break rule.
|
||||
WordBreakNormal = 0
|
||||
|
||||
// WordBreakAll - to prevent overflow, word breaks should be inserted between any two characters
|
||||
// (excluding Chinese/Japanese/Korean text).
|
||||
WordBreakAll = 1
|
||||
|
||||
// WordBreakKeepAll - word breaks should not be used for Chinese/Japanese/Korean (CJK) text.
|
||||
// Non-CJK text behavior is the same as for normal.
|
||||
WordBreakKeepAll = 2
|
||||
|
||||
// WordBreakWord - when the block boundaries are exceeded, the remaining whole words can be split
|
||||
// in an arbitrary place, unless a more suitable place for the line break is found.
|
||||
WordBreakWord = 3
|
||||
|
@ -117,6 +171,7 @@ const (
|
|||
// TextOverflowClip - truncate the text at the limit of the content area, therefore the truncation
|
||||
// can happen in the middle of a character.
|
||||
TextOverflowClip = 0
|
||||
|
||||
// TextOverflowEllipsis - display an ellipsis ('…', U+2026 HORIZONTAL ELLIPSIS) to represent clipped text.
|
||||
// The ellipsis is displayed inside the content area, decreasing the amount of text displayed.
|
||||
// If there is not enough space to display the ellipsis, it is clipped.
|
||||
|
@ -124,87 +179,111 @@ const (
|
|||
|
||||
// DefaultSemantics - default value of the view Semantic property
|
||||
DefaultSemantics = 0
|
||||
|
||||
// ArticleSemantics - value of the view Semantic property: view represents a self-contained
|
||||
// composition in a document, page, application, or site, which is intended to be
|
||||
// independently distributable or reusable (e.g., in syndication)
|
||||
ArticleSemantics = 1
|
||||
|
||||
// SectionSemantics - value of the view Semantic property: view represents
|
||||
// a generic standalone section of a document, which doesn't have a more specific
|
||||
// semantic element to represent it.
|
||||
SectionSemantics = 2
|
||||
|
||||
// AsideSemantics - value of the view Semantic property: view represents a portion
|
||||
// of a document whose content is only indirectly related to the document's main content.
|
||||
// Asides are frequently presented as sidebars or call-out boxes.
|
||||
AsideSemantics = 3
|
||||
|
||||
// HeaderSemantics - value of the view Semantic property: view represents introductory
|
||||
// content, typically a group of introductory or navigational aids. It may contain
|
||||
// some heading elements but also a logo, a search form, an author name, and other elements.
|
||||
HeaderSemantics = 4
|
||||
|
||||
// MainSemantics - value of the view Semantic property: view represents the dominant content
|
||||
// of the application. The main content area consists of content that is directly related
|
||||
// to or expands upon the central topic of a document, or the central functionality of an application.
|
||||
MainSemantics = 5
|
||||
|
||||
// FooterSemantics - value of the view Semantic property: view represents a footer for its
|
||||
// nearest sectioning content or sectioning root element. A footer view typically contains
|
||||
// information about the author of the section, copyright data or links to related documents.
|
||||
FooterSemantics = 6
|
||||
|
||||
// NavigationSemantics - value of the view Semantic property: view represents a section of
|
||||
// a page whose purpose is to provide navigation links, either within the current document
|
||||
// or to other documents. Common examples of navigation sections are menus, tables of contents,
|
||||
// and indexes.
|
||||
NavigationSemantics = 7
|
||||
|
||||
// FigureSemantics - value of the view Semantic property: view represents self-contained content,
|
||||
// potentially with an optional caption, which is specified using the FigureCaptionSemantics view.
|
||||
FigureSemantics = 8
|
||||
|
||||
// FigureCaptionSemantics - value of the view Semantic property: view represents a caption or
|
||||
// legend describing the rest of the contents of its parent FigureSemantics view.
|
||||
FigureCaptionSemantics = 9
|
||||
|
||||
// ButtonSemantics - value of the view Semantic property: view a clickable button
|
||||
ButtonSemantics = 10
|
||||
|
||||
// ParagraphSemantics - value of the view Semantic property: view represents a paragraph.
|
||||
// Paragraphs are usually represented in visual media as blocks of text separated
|
||||
// from adjacent blocks by blank lines and/or first-line indentation
|
||||
ParagraphSemantics = 11
|
||||
|
||||
// H1Semantics - value of the view Semantic property: view represent of first level section headings.
|
||||
// H1Semantics is the highest section level and H6Semantics is the lowest.
|
||||
H1Semantics = 12
|
||||
|
||||
// H2Semantics - value of the view Semantic property: view represent of second level section headings.
|
||||
// H1Semantics is the highest section level and H6Semantics is the lowest.
|
||||
H2Semantics = 13
|
||||
|
||||
// H3Semantics - value of the view Semantic property: view represent of third level section headings.
|
||||
// H1Semantics is the highest section level and H6Semantics is the lowest.
|
||||
H3Semantics = 14
|
||||
|
||||
// H4Semantics - value of the view Semantic property: view represent of fourth level section headings.
|
||||
// H1Semantics is the highest section level and H6Semantics is the lowest.
|
||||
H4Semantics = 15
|
||||
|
||||
// H5Semantics - value of the view Semantic property: view represent of fifth level section headings.
|
||||
// H1Semantics is the highest section level and H6Semantics is the lowest.
|
||||
H5Semantics = 16
|
||||
|
||||
// H6Semantics - value of the view Semantic property: view represent of sixth level section headings.
|
||||
// H1Semantics is the highest section level and H6Semantics is the lowest.
|
||||
H6Semantics = 17
|
||||
|
||||
// BlockquoteSemantics - value of the view Semantic property: view indicates that
|
||||
// the enclosed text is an extended quotation.
|
||||
BlockquoteSemantics = 18
|
||||
|
||||
// CodeSemantics - value of the view Semantic property: view displays its contents styled
|
||||
// in a fashion intended to indicate that the text is a short fragment of computer code
|
||||
CodeSemantics = 19
|
||||
|
||||
// NoneFloat - value of the view "float" property: the View must not float.
|
||||
NoneFloat = 0
|
||||
|
||||
// LeftFloat - value of the view "float" property: the View must float on the left side of its containing block.
|
||||
LeftFloat = 1
|
||||
|
||||
// RightFloat - value of the view "float" property: the View must float on the right side of its containing block.
|
||||
RightFloat = 2
|
||||
|
||||
// NoneResize - value of the view "resize" property: the View The offers no user-controllable method for resizing it.
|
||||
NoneResize = 0
|
||||
|
||||
// BothResize - value of the view "resize" property: the View displays a mechanism for allowing
|
||||
// the user to resize it, which may be resized both horizontally and vertically.
|
||||
BothResize = 1
|
||||
|
||||
// HorizontalResize - value of the view "resize" property: the View displays a mechanism for allowing
|
||||
// the user to resize it in the horizontal direction.
|
||||
HorizontalResize = 2
|
||||
|
||||
// VerticalResize - value of the view "resize" property: the View displays a mechanism for allowing
|
||||
// the user to resize it in the vertical direction.
|
||||
VerticalResize = 3
|
||||
|
@ -212,14 +291,17 @@ const (
|
|||
// RowAutoFlow - value of the "grid-auto-flow" property of the GridLayout:
|
||||
// Views are placed by filling each row in turn, adding new rows as necessary.
|
||||
RowAutoFlow = 0
|
||||
|
||||
// ColumnAutoFlow - value of the "grid-auto-flow" property of the GridLayout:
|
||||
// Views are placed by filling each column in turn, adding new columns as necessary.
|
||||
ColumnAutoFlow = 1
|
||||
|
||||
// RowDenseAutoFlow - value of the "grid-auto-flow" property of the GridLayout:
|
||||
// Views are placed by filling each row, adding new rows as necessary.
|
||||
// "dense" packing algorithm attempts to fill in holes earlier in the grid, if smaller items come up later.
|
||||
// This may cause views to appear out-of-order, when doing so would fill in holes left by larger views.
|
||||
RowDenseAutoFlow = 2
|
||||
|
||||
// ColumnDenseAutoFlow - value of the "grid-auto-flow" property of the GridLayout:
|
||||
// Views are placed by filling each column, adding new columns as necessary.
|
||||
// "dense" packing algorithm attempts to fill in holes earlier in the grid, if smaller items come up later.
|
||||
|
|
47
radius.go
47
radius.go
|
@ -109,7 +109,7 @@ type radiusPropertyData struct {
|
|||
// NewRadiusProperty creates the new RadiusProperty
|
||||
func NewRadiusProperty(params Params) RadiusProperty {
|
||||
result := new(radiusPropertyData)
|
||||
result.properties = map[string]interface{}{}
|
||||
result.properties = map[string]any{}
|
||||
if params != nil {
|
||||
for _, tag := range []string{X, Y, TopLeft, TopRight, BottomLeft, BottomRight, TopLeftX, TopLeftY,
|
||||
TopRightX, TopRightY, BottomLeftX, BottomLeftY, BottomRightX, BottomRightY} {
|
||||
|
@ -172,7 +172,7 @@ func (radius *radiusPropertyData) deleteUnusedTags() {
|
|||
}
|
||||
}
|
||||
|
||||
equalValue := func(value1, value2 interface{}) bool {
|
||||
equalValue := func(value1, value2 any) bool {
|
||||
switch value1 := value1.(type) {
|
||||
case string:
|
||||
switch value2 := value2.(type) {
|
||||
|
@ -243,7 +243,7 @@ func (radius *radiusPropertyData) Remove(tag string) {
|
|||
|
||||
}
|
||||
|
||||
func (radius *radiusPropertyData) Set(tag string, value interface{}) bool {
|
||||
func (radius *radiusPropertyData) Set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
radius.Remove(tag)
|
||||
return true
|
||||
|
@ -318,7 +318,7 @@ func (radius *radiusPropertyData) Set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (radius *radiusPropertyData) Get(tag string) interface{} {
|
||||
func (radius *radiusPropertyData) Get(tag string) any {
|
||||
tag = radius.normalizeTag(tag)
|
||||
if value, ok := radius.properties[tag]; ok {
|
||||
return value
|
||||
|
@ -455,7 +455,7 @@ func (radius BoxRadius) String() string {
|
|||
return buffer.String()
|
||||
}
|
||||
|
||||
func (radius BoxRadius) cssValue(builder cssBuilder) {
|
||||
func (radius BoxRadius) cssValue(builder cssBuilder, session Session) {
|
||||
|
||||
if (radius.TopLeftX.Type == Auto || radius.TopLeftX.Value == 0) &&
|
||||
(radius.TopLeftY.Type == Auto || radius.TopLeftY.Value == 0) &&
|
||||
|
@ -471,23 +471,23 @@ func (radius BoxRadius) cssValue(builder cssBuilder) {
|
|||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
buffer.WriteString(radius.TopLeftX.cssString("0"))
|
||||
buffer.WriteString(radius.TopLeftX.cssString("0", session))
|
||||
|
||||
if radius.AllAnglesIsEqual() {
|
||||
|
||||
if !radius.TopLeftX.Equal(radius.TopLeftY) {
|
||||
buffer.WriteString(" / ")
|
||||
buffer.WriteString(radius.TopLeftY.cssString("0"))
|
||||
buffer.WriteString(radius.TopLeftY.cssString("0", session))
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(radius.TopRightX.cssString("0"))
|
||||
buffer.WriteString(radius.TopRightX.cssString("0", session))
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(radius.BottomRightX.cssString("0"))
|
||||
buffer.WriteString(radius.BottomRightX.cssString("0", session))
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(radius.BottomLeftX.cssString("0"))
|
||||
buffer.WriteString(radius.BottomLeftX.cssString("0", session))
|
||||
|
||||
if !radius.TopLeftX.Equal(radius.TopLeftY) ||
|
||||
!radius.TopRightX.Equal(radius.TopRightY) ||
|
||||
|
@ -495,22 +495,22 @@ func (radius BoxRadius) cssValue(builder cssBuilder) {
|
|||
!radius.BottomRightX.Equal(radius.BottomRightY) {
|
||||
|
||||
buffer.WriteString(" / ")
|
||||
buffer.WriteString(radius.TopLeftY.cssString("0"))
|
||||
buffer.WriteString(radius.TopLeftY.cssString("0", session))
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(radius.TopRightY.cssString("0"))
|
||||
buffer.WriteString(radius.TopRightY.cssString("0", session))
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(radius.BottomRightY.cssString("0"))
|
||||
buffer.WriteString(radius.BottomRightY.cssString("0", session))
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(radius.BottomLeftY.cssString("0"))
|
||||
buffer.WriteString(radius.BottomLeftY.cssString("0", session))
|
||||
}
|
||||
}
|
||||
|
||||
builder.add("border-radius", buffer.String())
|
||||
}
|
||||
|
||||
func (radius BoxRadius) cssString() string {
|
||||
func (radius BoxRadius) cssString(session Session) string {
|
||||
var builder cssValueBuilder
|
||||
radius.cssValue(&builder)
|
||||
radius.cssValue(&builder, session)
|
||||
return builder.finish()
|
||||
}
|
||||
|
||||
|
@ -570,7 +570,7 @@ func getRadiusProperty(style Properties) RadiusProperty {
|
|||
return NewRadiusProperty(nil)
|
||||
}
|
||||
|
||||
func (properties *propertyList) setRadius(value interface{}) bool {
|
||||
func (properties *propertyList) setRadius(value any) bool {
|
||||
|
||||
if value == nil {
|
||||
delete(properties.properties, Radius)
|
||||
|
@ -645,7 +645,16 @@ func (properties *propertyList) setRadius(value interface{}) bool {
|
|||
properties.properties[Radius] = radius
|
||||
return true
|
||||
|
||||
case float32:
|
||||
return properties.setRadius(Px(float64(value)))
|
||||
|
||||
case float64:
|
||||
return properties.setRadius(Px(value))
|
||||
|
||||
default:
|
||||
if n, ok := isInt(value); ok {
|
||||
return properties.setRadius(Px(float64(n)))
|
||||
}
|
||||
notCompatibleType(Radius, value)
|
||||
}
|
||||
|
||||
|
@ -664,7 +673,7 @@ func (properties *propertyList) removeRadiusElement(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (properties *propertyList) setRadiusElement(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) setRadiusElement(tag string, value any) bool {
|
||||
if value == nil {
|
||||
properties.removeRadiusElement(tag)
|
||||
return true
|
||||
|
@ -679,7 +688,7 @@ func (properties *propertyList) setRadiusElement(tag string, value interface{})
|
|||
return false
|
||||
}
|
||||
|
||||
func getRadiusElement(style Properties, tag string) interface{} {
|
||||
func getRadiusElement(style Properties, tag string) any {
|
||||
value := style.Get(Radius)
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
|
|
18
resizable.go
18
resizable.go
|
@ -45,7 +45,7 @@ type resizableData struct {
|
|||
// NewResizable create new Resizable object and return it
|
||||
func NewResizable(session Session, params Params) Resizable {
|
||||
view := new(resizableData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -54,8 +54,8 @@ func newResizable(session Session) View {
|
|||
return NewResizable(session, nil)
|
||||
}
|
||||
|
||||
func (resizable *resizableData) Init(session Session) {
|
||||
resizable.viewData.Init(session)
|
||||
func (resizable *resizableData) init(session Session) {
|
||||
resizable.viewData.init(session)
|
||||
resizable.tag = "Resizable"
|
||||
resizable.systemClass = "ruiGridLayout"
|
||||
resizable.content = []View{}
|
||||
|
@ -108,11 +108,11 @@ func (resizable *resizableData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (resizable *resizableData) Set(tag string, value interface{}) bool {
|
||||
func (resizable *resizableData) Set(tag string, value any) bool {
|
||||
return resizable.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (resizable *resizableData) set(tag string, value interface{}) bool {
|
||||
func (resizable *resizableData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
resizable.remove(tag)
|
||||
return true
|
||||
|
@ -183,7 +183,7 @@ func (resizable *resizableData) set(tag string, value interface{}) bool {
|
|||
return resizable.viewData.set(tag, value)
|
||||
}
|
||||
|
||||
func (resizable *resizableData) Get(tag string) interface{} {
|
||||
func (resizable *resizableData) Get(tag string) any {
|
||||
return resizable.get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ func (resizable *resizableData) getSide() int {
|
|||
return AllSides
|
||||
}
|
||||
|
||||
func (resizable *resizableData) setSide(value interface{}) bool {
|
||||
func (resizable *resizableData) setSide(value any) bool {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if n, err := strconv.Atoi(value); err == nil {
|
||||
|
@ -340,7 +340,7 @@ func (resizable *resizableData) updateResizeBorderWidth() {
|
|||
}
|
||||
|
||||
func (resizable *resizableData) cellSizeCSS() (string, string) {
|
||||
w := resizable.resizeBorderWidth().cssString("4px")
|
||||
w := resizable.resizeBorderWidth().cssString("4px", resizable.Session())
|
||||
side := resizable.getSide()
|
||||
column := "1fr"
|
||||
row := "1fr"
|
||||
|
@ -384,7 +384,7 @@ func (resizable *resizableData) htmlSubviews(self View, buffer *strings.Builder)
|
|||
top := 1
|
||||
leftSide := (side & LeftSide) != 0
|
||||
rightSide := (side & RightSide) != 0
|
||||
w := resizable.resizeBorderWidth().cssString("4px")
|
||||
w := resizable.resizeBorderWidth().cssString("4px", resizable.Session())
|
||||
|
||||
if leftSide {
|
||||
left = 2
|
||||
|
|
175
resizeEvent.go
175
resizeEvent.go
|
@ -3,8 +3,11 @@ package rui
|
|||
// ResizeEvent is the constant for "resize-event" property tag.
|
||||
// The "resize-event" is fired when the view changes its size.
|
||||
// The main listener format:
|
||||
//
|
||||
// func(View, Frame).
|
||||
//
|
||||
// The additional listener formats:
|
||||
//
|
||||
// func(Frame), func(View), and func().
|
||||
const ResizeEvent = "resize-event"
|
||||
|
||||
|
@ -13,7 +16,7 @@ func (view *viewData) onResize(self View, x, y, width, height float64) {
|
|||
view.frame.Top = y
|
||||
view.frame.Width = width
|
||||
view.frame.Height = height
|
||||
for _, listener := range GetResizeListeners(view, "") {
|
||||
for _, listener := range GetResizeListeners(view) {
|
||||
listener(self, view.frame)
|
||||
}
|
||||
}
|
||||
|
@ -21,147 +24,19 @@ 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) setFrameListener(tag string, value interface{}) bool {
|
||||
if value == nil {
|
||||
delete(view.properties, tag)
|
||||
return true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(View, Frame):
|
||||
view.properties[tag] = []func(View, Frame){value}
|
||||
|
||||
case []func(View, Frame):
|
||||
if len(value) > 0 {
|
||||
view.properties[tag] = value
|
||||
} else {
|
||||
delete(view.properties, tag)
|
||||
return true
|
||||
}
|
||||
|
||||
case func(Frame):
|
||||
fn := func(_ View, frame Frame) {
|
||||
value(frame)
|
||||
}
|
||||
view.properties[tag] = []func(View, Frame){fn}
|
||||
|
||||
case []func(Frame):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
delete(view.properties, tag)
|
||||
return true
|
||||
}
|
||||
|
||||
listeners := make([]func(View, Frame), count)
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(_ View, frame Frame) {
|
||||
val(frame)
|
||||
}
|
||||
}
|
||||
view.properties[tag] = listeners
|
||||
|
||||
case func(View):
|
||||
fn := func(view View, _ Frame) {
|
||||
value(view)
|
||||
}
|
||||
view.properties[tag] = []func(View, Frame){fn}
|
||||
|
||||
case []func(View):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
delete(view.properties, tag)
|
||||
return true
|
||||
}
|
||||
|
||||
listeners := make([]func(View, Frame), count)
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(view View, _ Frame) {
|
||||
val(view)
|
||||
}
|
||||
}
|
||||
view.properties[tag] = listeners
|
||||
|
||||
case func():
|
||||
fn := func(View, Frame) {
|
||||
value()
|
||||
}
|
||||
view.properties[tag] = []func(View, Frame){fn}
|
||||
|
||||
case []func():
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
delete(view.properties, tag)
|
||||
return true
|
||||
}
|
||||
|
||||
listeners := make([]func(View, Frame), count)
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(View, Frame) {
|
||||
val()
|
||||
}
|
||||
}
|
||||
view.properties[tag] = listeners
|
||||
|
||||
case []interface{}:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
delete(view.properties, tag)
|
||||
return true
|
||||
}
|
||||
|
||||
listeners := make([]func(View, Frame), count)
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case func(View, Frame):
|
||||
listeners[i] = val
|
||||
|
||||
case func(Frame):
|
||||
listeners[i] = func(_ View, frame Frame) {
|
||||
val(frame)
|
||||
}
|
||||
|
||||
case func(View):
|
||||
listeners[i] = func(view View, _ Frame) {
|
||||
val(view)
|
||||
}
|
||||
|
||||
case func():
|
||||
listeners[i] = func(View, Frame) {
|
||||
val()
|
||||
}
|
||||
|
||||
default:
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
}
|
||||
view.properties[tag] = listeners
|
||||
|
||||
default:
|
||||
func (view *viewData) setFrameListener(tag string, value any) bool {
|
||||
listeners, ok := valueToEventListeners[View, Frame](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
}
|
||||
|
||||
if listeners == nil {
|
||||
delete(view.properties, tag)
|
||||
} else {
|
||||
view.properties[tag] = listeners
|
||||
}
|
||||
view.propertyChangedEvent(tag)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -190,10 +65,10 @@ func (view *viewData) Frame() Frame {
|
|||
}
|
||||
|
||||
// GetViewFrame returns the size and location of view's viewport.
|
||||
// If the second argument (subviewID) is "" then the value of the first argument (view) is returned
|
||||
func GetViewFrame(view View, subviewID string) Frame {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then the value of the first argument (view) is returned
|
||||
func GetViewFrame(view View, subviewID ...string) Frame {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view == nil {
|
||||
return Frame{}
|
||||
|
@ -202,17 +77,7 @@ func GetViewFrame(view View, subviewID string) Frame {
|
|||
}
|
||||
|
||||
// GetResizeListeners returns the list of "resize-event" listeners. If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then the listeners list of the first argument (view) is returned
|
||||
func GetResizeListeners(view View, subviewID string) []func(View, Frame) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(ResizeEvent); value != nil {
|
||||
if result, ok := value.([]func(View, Frame)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(View, Frame){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then the listeners list of the first argument (view) is returned
|
||||
func GetResizeListeners(view View, subviewID ...string) []func(View, Frame) {
|
||||
return getEventListeners[View, Frame](view, subviewID, ResizeEvent)
|
||||
}
|
||||
|
|
11
resources.go
11
resources.go
|
@ -3,7 +3,6 @@ package rui
|
|||
import (
|
||||
"embed"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -171,7 +170,7 @@ func registerImage(fs *embed.FS, path, filename string) {
|
|||
}
|
||||
|
||||
func scanImagesDirectory(path, filePrefix string) {
|
||||
if files, err := ioutil.ReadDir(path); err == nil {
|
||||
if files, err := os.ReadDir(path); err == nil {
|
||||
for _, file := range files {
|
||||
filename := file.Name()
|
||||
if filename[0] != '.' {
|
||||
|
@ -189,7 +188,7 @@ func scanImagesDirectory(path, filePrefix string) {
|
|||
}
|
||||
|
||||
func scanThemesDir(path string) {
|
||||
if files, err := ioutil.ReadDir(path); err == nil {
|
||||
if files, err := os.ReadDir(path); err == nil {
|
||||
for _, file := range files {
|
||||
filename := file.Name()
|
||||
if filename[0] != '.' {
|
||||
|
@ -197,7 +196,7 @@ func scanThemesDir(path string) {
|
|||
if file.IsDir() {
|
||||
scanThemesDir(newPath)
|
||||
} else if strings.ToLower(filepath.Ext(newPath)) == ".rui" {
|
||||
if data, err := ioutil.ReadFile(newPath); err == nil {
|
||||
if data, err := os.ReadFile(newPath); err == nil {
|
||||
registerThemeText(string(data))
|
||||
} else {
|
||||
ErrorLog(err.Error())
|
||||
|
@ -380,7 +379,7 @@ func AllRawResources() []string {
|
|||
}
|
||||
|
||||
if resources.path != "" {
|
||||
if files, err := ioutil.ReadDir(resources.path + rawDir); err == nil {
|
||||
if files, err := os.ReadDir(resources.path + rawDir); err == nil {
|
||||
for _, file := range files {
|
||||
result = append(result, file.Name())
|
||||
}
|
||||
|
@ -388,7 +387,7 @@ func AllRawResources() []string {
|
|||
}
|
||||
|
||||
if exe, err := os.Executable(); err == nil {
|
||||
if files, err := ioutil.ReadDir(filepath.Dir(exe) + "/resources/" + rawDir); err == nil {
|
||||
if files, err := os.ReadDir(filepath.Dir(exe) + "/resources/" + rawDir); err == nil {
|
||||
for _, file := range files {
|
||||
result = append(result, file.Name())
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ type ruiWriter interface {
|
|||
endObject()
|
||||
startArrayProperty(tag string)
|
||||
endObArray()
|
||||
writeProperty(tag string, value interface{})
|
||||
writeProperty(tag string, value any)
|
||||
finish() string
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ func (writer *ruiWriterData) endObArray() {
|
|||
writer.buffer.WriteString("],\n")
|
||||
}
|
||||
|
||||
func (writer *ruiWriterData) writeValue(value interface{}) {
|
||||
func (writer *ruiWriterData) writeValue(value any) {
|
||||
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
|
@ -175,7 +175,7 @@ func (writer *ruiWriterData) writeValue(value interface{}) {
|
|||
writer.buffer.WriteRune(']')
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
switch len(value) {
|
||||
case 0:
|
||||
writer.buffer.WriteString("[]\n")
|
||||
|
@ -205,7 +205,7 @@ func (writer *ruiWriterData) writeValue(value interface{}) {
|
|||
writer.buffer.WriteString(",\n")
|
||||
}
|
||||
|
||||
func (writer *ruiWriterData) writeProperty(tag string, value interface{}) {
|
||||
func (writer *ruiWriterData) writeProperty(tag string, value any) {
|
||||
writer.writeIndent()
|
||||
writer.writeString(tag)
|
||||
writer.buffer.WriteString(" = ")
|
||||
|
|
|
@ -3,10 +3,13 @@ package rui
|
|||
import "fmt"
|
||||
|
||||
// ScrollEvent is the constant for "scroll-event" property tag.
|
||||
// The "resize-event" is fired when the content of the view is scrolled.
|
||||
// The "scroll-event" is fired when the content of the view is scrolled.
|
||||
// The main listener format:
|
||||
//
|
||||
// func(View, Frame).
|
||||
//
|
||||
// The additional listener formats:
|
||||
//
|
||||
// func(Frame), func(View), and func().
|
||||
const ScrollEvent = "scroll-event"
|
||||
|
||||
|
@ -15,7 +18,7 @@ func (view *viewData) onScroll(self View, x, y, width, height float64) {
|
|||
view.scroll.Top = y
|
||||
view.scroll.Width = width
|
||||
view.scroll.Height = height
|
||||
for _, listener := range GetScrollListeners(view, "") {
|
||||
for _, listener := range GetScrollListeners(view) {
|
||||
listener(self, view.scroll)
|
||||
}
|
||||
}
|
||||
|
@ -32,10 +35,10 @@ func (view *viewData) setScroll(x, y, width, height float64) {
|
|||
}
|
||||
|
||||
// GetViewScroll returns ...
|
||||
// If the second argument (subviewID) is "" then a value of the first argument (view) is returned
|
||||
func GetViewScroll(view View, subviewID string) Frame {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value of the first argument (view) is returned
|
||||
func GetViewScroll(view View, subviewID ...string) Frame {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view == nil {
|
||||
return Frame{}
|
||||
|
@ -44,19 +47,9 @@ func GetViewScroll(view View, subviewID string) Frame {
|
|||
}
|
||||
|
||||
// GetScrollListeners returns the list of "scroll-event" listeners. If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then the listeners list of the first argument (view) is returned
|
||||
func GetScrollListeners(view View, subviewID string) []func(View, Frame) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(ScrollEvent); value != nil {
|
||||
if result, ok := value.([]func(View, Frame)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(View, Frame){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then the listeners list of the first argument (view) is returned
|
||||
func GetScrollListeners(view View, subviewID ...string) []func(View, Frame) {
|
||||
return getEventListeners[View, Frame](view, subviewID, ResizeEvent)
|
||||
}
|
||||
|
||||
// ScrollTo scrolls the view's content to the given position.
|
||||
|
@ -71,10 +64,10 @@ func ScrollViewTo(view View, subviewID string, x, y float64) {
|
|||
}
|
||||
|
||||
// ScrollViewToEnd scrolls the view's content to the start of view.
|
||||
// If the second argument (subviewID) is "" then the first argument (view) is used
|
||||
func ScrollViewToStart(view View, subviewID string) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then the first argument (view) is used
|
||||
func ScrollViewToStart(view View, subviewID ...string) {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
view.Session().runScript(`scrollToStart("` + view.htmlID() + `")`)
|
||||
|
@ -82,10 +75,10 @@ func ScrollViewToStart(view View, subviewID string) {
|
|||
}
|
||||
|
||||
// ScrollViewToEnd scrolls the view's content to the end of view.
|
||||
// If the second argument (subviewID) is "" then the first argument (view) is used
|
||||
func ScrollViewToEnd(view View, subviewID string) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then the first argument (view) is used
|
||||
func ScrollViewToEnd(view View, subviewID ...string) {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
view.Session().runScript(`scrollToEnd("` + view.htmlID() + `")`)
|
||||
|
|
14
session.go
14
session.go
|
@ -60,11 +60,11 @@ type Session interface {
|
|||
RootView() View
|
||||
// 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.
|
||||
Get(viewID, tag string) interface{}
|
||||
Get(viewID, tag string) any
|
||||
// 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
|
||||
// a description of the error is written to the log
|
||||
Set(viewID, tag string, value interface{}) bool
|
||||
Set(viewID, tag string, value any) bool
|
||||
|
||||
// DownloadFile downloads (saves) on the client side the file located at the specified path on the server.
|
||||
DownloadFile(path string)
|
||||
|
@ -83,7 +83,7 @@ type Session interface {
|
|||
|
||||
viewByHTMLID(id string) View
|
||||
nextViewID() string
|
||||
styleProperty(styleTag, property string) interface{}
|
||||
styleProperty(styleTag, property string) any
|
||||
|
||||
setBrige(events chan DataObject, brige WebBrige)
|
||||
writeInitScript(writer *strings.Builder)
|
||||
|
@ -222,7 +222,7 @@ func (session *sessionData) close() {
|
|||
}
|
||||
}
|
||||
|
||||
func (session *sessionData) styleProperty(styleTag, propertyTag string) interface{} {
|
||||
func (session *sessionData) styleProperty(styleTag, propertyTag string) any {
|
||||
if style := session.getCurrentTheme().style(styleTag); style != nil {
|
||||
return style.getRaw(propertyTag)
|
||||
}
|
||||
|
@ -312,14 +312,14 @@ func (session *sessionData) setIgnoreViewUpdates(ignore bool) {
|
|||
session.ignoreUpdates = ignore
|
||||
}
|
||||
|
||||
func (session *sessionData) Get(viewID, tag string) interface{} {
|
||||
func (session *sessionData) Get(viewID, tag string) any {
|
||||
if view := ViewByID(session.RootView(), viewID); view != nil {
|
||||
return view.Get(tag)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (session *sessionData) Set(viewID, tag string, value interface{}) bool {
|
||||
func (session *sessionData) Set(viewID, tag string, value any) bool {
|
||||
if view := ViewByID(session.RootView(), viewID); view != nil {
|
||||
return view.Set(tag, value)
|
||||
}
|
||||
|
@ -434,7 +434,7 @@ func (session *sessionData) handleViewEvent(command string, data DataObject) {
|
|||
if view := session.viewByHTMLID(viewID); view != nil {
|
||||
view.handleCommand(view, command, data)
|
||||
}
|
||||
} else {
|
||||
} else if command != "clickOutsidePopup" {
|
||||
ErrorLog(`"id" property not found. Event: ` + command)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
var stopTestLogFlag = false
|
||||
var testLogDone chan int
|
||||
// var stopTestLogFlag = false
|
||||
// var testLogDone chan int
|
||||
var ignoreTestLog = false
|
||||
|
||||
func createTestLog(t *testing.T, ignore bool) {
|
||||
|
|
20
shadow.go
20
shadow.go
|
@ -111,7 +111,7 @@ func (shadow *viewShadowData) Remove(tag string) {
|
|||
delete(shadow.properties, strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (shadow *viewShadowData) Set(tag string, value interface{}) bool {
|
||||
func (shadow *viewShadowData) Set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
shadow.Remove(tag)
|
||||
return true
|
||||
|
@ -127,7 +127,7 @@ func (shadow *viewShadowData) Set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (shadow *viewShadowData) Get(tag string) interface{} {
|
||||
func (shadow *viewShadowData) Get(tag string) any {
|
||||
return shadow.propertyList.Get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
|
@ -151,13 +151,13 @@ func (shadow *viewShadowData) cssStyle(buffer *strings.Builder, session Session,
|
|||
buffer.WriteString("inset ")
|
||||
}
|
||||
|
||||
buffer.WriteString(offsetX.cssString("0"))
|
||||
buffer.WriteString(offsetX.cssString("0", session))
|
||||
buffer.WriteByte(' ')
|
||||
buffer.WriteString(offsetY.cssString("0"))
|
||||
buffer.WriteString(offsetY.cssString("0", session))
|
||||
buffer.WriteByte(' ')
|
||||
buffer.WriteString(blurRadius.cssString("0"))
|
||||
buffer.WriteString(blurRadius.cssString("0", session))
|
||||
buffer.WriteByte(' ')
|
||||
buffer.WriteString(spreadRadius.cssString("0"))
|
||||
buffer.WriteString(spreadRadius.cssString("0", session))
|
||||
buffer.WriteByte(' ')
|
||||
buffer.WriteString(color.cssString())
|
||||
return true
|
||||
|
@ -177,11 +177,11 @@ func (shadow *viewShadowData) cssTextStyle(buffer *strings.Builder, session Sess
|
|||
}
|
||||
|
||||
buffer.WriteString(lead)
|
||||
buffer.WriteString(offsetX.cssString("0"))
|
||||
buffer.WriteString(offsetX.cssString("0", session))
|
||||
buffer.WriteByte(' ')
|
||||
buffer.WriteString(offsetY.cssString("0"))
|
||||
buffer.WriteString(offsetY.cssString("0", session))
|
||||
buffer.WriteByte(' ')
|
||||
buffer.WriteString(blurRadius.cssString("0"))
|
||||
buffer.WriteString(blurRadius.cssString("0", session))
|
||||
buffer.WriteByte(' ')
|
||||
buffer.WriteString(color.cssString())
|
||||
return true
|
||||
|
@ -225,7 +225,7 @@ func (shadow *viewShadowData) writeString(buffer *strings.Builder, indent string
|
|||
buffer.WriteString(" }")
|
||||
}
|
||||
|
||||
func (properties *propertyList) setShadow(tag string, value interface{}) bool {
|
||||
func (properties *propertyList) setShadow(tag string, value any) bool {
|
||||
|
||||
if value == nil {
|
||||
delete(properties.properties, tag)
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
package rui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SizeFunc describes a function that calculates the SizeUnit size.
|
||||
// Used as the value of the SizeUnit properties.
|
||||
// "min", "max", "clamp", "sum", "sub", "mul", and "div" functions are available.
|
||||
type SizeFunc interface {
|
||||
fmt.Stringer
|
||||
// Name() returns the function name: "min", "max", "clamp", "sum", "sub", "mul", or "div"
|
||||
Name() string
|
||||
// Args() returns a list of function arguments
|
||||
Args() []any
|
||||
cssString(session Session) string
|
||||
writeCSS(topFunc string, buffer *strings.Builder, session Session)
|
||||
writeString(topFunc string, buffer *strings.Builder)
|
||||
}
|
||||
|
||||
type sizeFuncData struct {
|
||||
tag string
|
||||
args []any
|
||||
}
|
||||
|
||||
func parseSizeFunc(text string) SizeFunc {
|
||||
text = strings.Trim(text, " ")
|
||||
|
||||
for _, tag := range []string{"min", "max", "sum", "sub", "mul", "div", "clamp"} {
|
||||
if strings.HasPrefix(text, tag) {
|
||||
text = strings.Trim(strings.TrimPrefix(text, tag), " ")
|
||||
last := len(text) - 1
|
||||
if text[0] == '(' && text[last] == ')' {
|
||||
text = text[1:last]
|
||||
bracket := 0
|
||||
start := 0
|
||||
args := []any{}
|
||||
for i, ch := range text {
|
||||
switch ch {
|
||||
case ',':
|
||||
if bracket == 0 {
|
||||
args = append(args, text[start:i])
|
||||
start = i + 1
|
||||
}
|
||||
|
||||
case '(':
|
||||
bracket++
|
||||
|
||||
case ')':
|
||||
bracket--
|
||||
}
|
||||
}
|
||||
if bracket != 0 {
|
||||
ErrorLogF(`Invalid "%s" function`, tag)
|
||||
return nil
|
||||
}
|
||||
|
||||
args = append(args, text[start:])
|
||||
switch tag {
|
||||
case "sub", "mul", "div":
|
||||
if len(args) != 2 {
|
||||
ErrorLogF(`"%s" function needs 2 arguments`, tag)
|
||||
return nil
|
||||
}
|
||||
case "clamp":
|
||||
if len(args) != 3 {
|
||||
ErrorLog(`"clamp" function needs 3 arguments`)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
data := new(sizeFuncData)
|
||||
data.tag = tag
|
||||
if data.parseArgs(args, tag == "mul" || tag == "div") {
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
ErrorLogF(`Invalid "%s" function`, tag)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (data *sizeFuncData) parseArgs(args []any, allowNumber bool) bool {
|
||||
data.args = []any{}
|
||||
|
||||
numberArg := func(index int, value float64) bool {
|
||||
if allowNumber {
|
||||
if index == 1 {
|
||||
if value == 0 && data.tag == "div" {
|
||||
ErrorLog(`Division by 0 in div function`)
|
||||
return false
|
||||
}
|
||||
data.args = append(data.args, value)
|
||||
return true
|
||||
} else {
|
||||
ErrorLogF(`Only the second %s function argument can be a number`, data.tag)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
ErrorLogF(`The %s function argument cann't be a number`, data.tag)
|
||||
return false
|
||||
}
|
||||
|
||||
for i, arg := range args {
|
||||
switch arg := arg.(type) {
|
||||
case string:
|
||||
if arg = strings.Trim(arg, " \t\n"); arg == "" {
|
||||
ErrorLogF(`Unsupported %s function argument #%d: ""`, data.tag, i)
|
||||
return false
|
||||
}
|
||||
|
||||
if arg[0] == '@' {
|
||||
data.args = append(data.args, arg)
|
||||
} else if val, err := strconv.ParseFloat(arg, 64); err == nil {
|
||||
return numberArg(i, val)
|
||||
} else if fn := parseSizeFunc(arg); fn != nil {
|
||||
data.args = append(data.args, fn)
|
||||
} else if size, err := stringToSizeUnit(arg); err == nil {
|
||||
data.args = append(data.args, size)
|
||||
} else {
|
||||
ErrorLogF(`Unsupported %s function argument #%d: "%s"`, data.tag, i, arg)
|
||||
return false
|
||||
}
|
||||
|
||||
case SizeFunc:
|
||||
data.args = append(data.args, arg)
|
||||
|
||||
case SizeUnit:
|
||||
if arg.Type == Auto {
|
||||
ErrorLogF(`Unsupported %s function argument #%d: "auto"`, data.tag, i)
|
||||
}
|
||||
data.args = append(data.args, arg)
|
||||
|
||||
case float64:
|
||||
return numberArg(i, arg)
|
||||
|
||||
case float32:
|
||||
return numberArg(i, float64(arg))
|
||||
|
||||
default:
|
||||
if n, ok := isInt(arg); ok {
|
||||
return numberArg(i, float64(n))
|
||||
}
|
||||
ErrorLogF(`Unsupported %s function argument #%d: %v`, data.tag, i, arg)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (data *sizeFuncData) String() string {
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
data.writeString("", buffer)
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (data *sizeFuncData) Name() string {
|
||||
return data.tag
|
||||
}
|
||||
|
||||
func (data *sizeFuncData) Args() []any {
|
||||
args := make([]any, len(data.args))
|
||||
copy(args, data.args)
|
||||
return args
|
||||
}
|
||||
|
||||
func (data *sizeFuncData) writeString(topFunc string, buffer *strings.Builder) {
|
||||
buffer.WriteString(data.tag)
|
||||
buffer.WriteRune('(')
|
||||
for i, arg := range data.args {
|
||||
if i > 0 {
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
switch arg := arg.(type) {
|
||||
case string:
|
||||
buffer.WriteString(arg)
|
||||
|
||||
case SizeFunc:
|
||||
arg.writeString(data.tag, buffer)
|
||||
|
||||
case SizeUnit:
|
||||
buffer.WriteString(arg.String())
|
||||
|
||||
case fmt.Stringer:
|
||||
buffer.WriteString(arg.String())
|
||||
|
||||
case float64:
|
||||
buffer.WriteString(fmt.Sprintf("%g", arg))
|
||||
}
|
||||
|
||||
}
|
||||
buffer.WriteRune(')')
|
||||
}
|
||||
|
||||
func (data *sizeFuncData) cssString(session Session) string {
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
data.writeCSS("", buffer, session)
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (data *sizeFuncData) writeCSS(topFunc string, buffer *strings.Builder, session Session) {
|
||||
bracket := true
|
||||
sep := ", "
|
||||
|
||||
mathFunc := func(s string) {
|
||||
sep = s
|
||||
switch topFunc {
|
||||
case "":
|
||||
buffer.WriteString("calc(")
|
||||
|
||||
case "min", "max", "clamp":
|
||||
bracket = false
|
||||
|
||||
default:
|
||||
buffer.WriteRune('(')
|
||||
}
|
||||
}
|
||||
|
||||
switch data.tag {
|
||||
case "min", "max", "clamp":
|
||||
buffer.WriteString(data.tag)
|
||||
buffer.WriteRune('(')
|
||||
|
||||
case "sum":
|
||||
mathFunc(" + ")
|
||||
|
||||
case "sub":
|
||||
mathFunc(" - ")
|
||||
|
||||
case "mul":
|
||||
mathFunc(" * ")
|
||||
|
||||
case "div":
|
||||
mathFunc(" / ")
|
||||
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
for i, arg := range data.args {
|
||||
if i > 0 {
|
||||
buffer.WriteString(sep)
|
||||
}
|
||||
switch arg := arg.(type) {
|
||||
case string:
|
||||
if arg, ok := session.resolveConstants(arg); ok {
|
||||
if fn := parseSizeFunc(arg); fn != nil {
|
||||
fn.writeCSS(data.tag, buffer, session)
|
||||
} else if size, err := stringToSizeUnit(arg); err == nil {
|
||||
buffer.WriteString(size.cssString("0", session))
|
||||
} else {
|
||||
buffer.WriteString("0")
|
||||
}
|
||||
} else {
|
||||
buffer.WriteString("0")
|
||||
}
|
||||
|
||||
case SizeFunc:
|
||||
arg.writeCSS(data.tag, buffer, session)
|
||||
|
||||
case SizeUnit:
|
||||
buffer.WriteString(arg.cssString("0", session))
|
||||
|
||||
case fmt.Stringer:
|
||||
buffer.WriteString(arg.String())
|
||||
|
||||
case float64:
|
||||
buffer.WriteString(fmt.Sprintf("%g", arg))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if bracket {
|
||||
buffer.WriteRune(')')
|
||||
}
|
||||
}
|
||||
|
||||
// MaxSize creates a SizeUnit function that calculates the maximum argument.
|
||||
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc
|
||||
func MaxSize(arg0, arg1 any, args ...any) SizeFunc {
|
||||
data := new(sizeFuncData)
|
||||
data.tag = "max"
|
||||
if !data.parseArgs(append([]any{arg0, arg1}, args...), false) {
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// MinSize creates a SizeUnit function that calculates the minimum argument.
|
||||
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
|
||||
func MinSize(arg0, arg1 any, args ...any) SizeFunc {
|
||||
data := new(sizeFuncData)
|
||||
data.tag = "min"
|
||||
if !data.parseArgs(append([]any{arg0, arg1}, args...), false) {
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// SumSize creates a SizeUnit function that calculates the sum of arguments.
|
||||
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
|
||||
func SumSize(arg0, arg1 any, args ...any) SizeFunc {
|
||||
data := new(sizeFuncData)
|
||||
data.tag = "sum"
|
||||
if !data.parseArgs(append([]any{arg0, arg1}, args...), false) {
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// SumSize creates a SizeUnit function that calculates the result of subtracting the arguments (arg1 - arg2).
|
||||
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
|
||||
func SubSize(arg0, arg1 any) SizeFunc {
|
||||
data := new(sizeFuncData)
|
||||
data.tag = "sub"
|
||||
if !data.parseArgs([]any{arg0, arg1}, false) {
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// MulSize creates a SizeUnit function that calculates the result of multiplying the arguments (arg1 * arg2).
|
||||
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
|
||||
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
|
||||
// or a string which is a text representation of a number.
|
||||
func MulSize(arg0, arg1 any) SizeFunc {
|
||||
data := new(sizeFuncData)
|
||||
data.tag = "mul"
|
||||
if !data.parseArgs([]any{arg0, arg1}, true) {
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// DivSize creates a SizeUnit function that calculates the result of dividing the arguments (arg1 / arg2).
|
||||
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
|
||||
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
|
||||
// or a string which is a text representation of a number.
|
||||
func DivSize(arg0, arg1 any) SizeFunc {
|
||||
data := new(sizeFuncData)
|
||||
data.tag = "div"
|
||||
if !data.parseArgs([]any{arg0, arg1}, true) {
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// ClampSize creates a SizeUnit function whose the result is calculated as follows:
|
||||
//
|
||||
// min ≤ value ≤ max -> value;
|
||||
// value < min -> min;
|
||||
// max < value -> max;
|
||||
//
|
||||
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
|
||||
func ClampSize(min, value, max any) SizeFunc {
|
||||
data := new(sizeFuncData)
|
||||
data.tag = "clamp"
|
||||
if !data.parseArgs([]any{min, value, max}, false) {
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package rui
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSizeFunc(t *testing.T) {
|
||||
session := new(sessionData)
|
||||
session.getCurrentTheme().SetConstant("a1", "120px", "120px")
|
||||
|
||||
SetErrorLog(func(text string) {
|
||||
t.Error(text)
|
||||
})
|
||||
SetDebugLog(func(text string) {
|
||||
t.Log(text)
|
||||
})
|
||||
|
||||
testFunc := func(fn SizeFunc, str, css string) {
|
||||
if fn != nil {
|
||||
if text := fn.String(); str != text {
|
||||
t.Error("String() error.\nResult: \"" + text + "\"\nExpected: \"" + str + `"`)
|
||||
}
|
||||
if text := fn.cssString(session); css != text {
|
||||
t.Error("cssString() error.\nResult: \"" + text + "\"\nExpected: \"" + css + `"`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testFunc(MinSize("100%", Px(10)), `min(100%, 10px)`, `min(100%, 10px)`)
|
||||
testFunc(MaxSize(Percent(100), "@a1"), `max(100%, @a1)`, `max(100%, 120px)`)
|
||||
testFunc(SumSize(Percent(100), "@a1"), `sum(100%, @a1)`, `calc(100% + 120px)`)
|
||||
testFunc(SubSize(Percent(100), "@a1"), `sub(100%, @a1)`, `calc(100% - 120px)`)
|
||||
testFunc(MulSize(Percent(100), "@a1"), `mul(100%, @a1)`, `calc(100% * 120px)`)
|
||||
testFunc(DivSize(Percent(100), "@a1"), `div(100%, @a1)`, `calc(100% / 120px)`)
|
||||
testFunc(ClampSize(Percent(20), "@a1", Percent(40)), `clamp(20%, @a1, 40%)`, `clamp(20%, 120px, 40%)`)
|
||||
|
||||
testFunc(MaxSize(SubSize(Percent(100), "@a1"), "@a1"), `max(sub(100%, @a1), @a1)`, `max(100% - 120px, 120px)`)
|
||||
|
||||
testParse := func(str, css string) {
|
||||
if fn := parseSizeFunc(str); fn != nil {
|
||||
testFunc(fn, str, css)
|
||||
}
|
||||
}
|
||||
|
||||
testParse(`min(100%, 10px)`, `min(100%, 10px)`)
|
||||
testParse(`max(100%, @a1)`, `max(100%, 120px)`)
|
||||
testParse(`max(sub(100%, @a1), @a1)`, `max(100% - 120px, 120px)`)
|
||||
testParse(`mul(sub(100%, @a1), @a1)`, `calc((100% - 120px) * 120px)`)
|
||||
testParse(`mul(sub(100%, @a1), div(mul(@a1, 3), 2))`, `calc((100% - 120px) * ((120px * 3) / 2))`)
|
||||
}
|
70
sizeUnit.go
70
sizeUnit.go
|
@ -14,89 +14,94 @@ import (
|
|||
type SizeUnitType uint8
|
||||
|
||||
const (
|
||||
// Auto - default value.
|
||||
// Auto is the SizeUnit type: default value.
|
||||
Auto SizeUnitType = 0
|
||||
// SizeInPixel - size in pixels.
|
||||
// SizeInPixel is the SizeUnit type: the Value field specifies the size in pixels.
|
||||
SizeInPixel SizeUnitType = 1
|
||||
// SizeInEM - size in em.
|
||||
// SizeInEM is the SizeUnit type: the Value field specifies the size in em.
|
||||
SizeInEM SizeUnitType = 2
|
||||
// SizeInEX - size in em.
|
||||
// SizeInEX is the SizeUnit type: the Value field specifies the size in em.
|
||||
SizeInEX SizeUnitType = 3
|
||||
// SizeInPercent - size in percents of a parant size.
|
||||
// SizeInPercent is the SizeUnit type: the Value field specifies the size in percents of the parent size.
|
||||
SizeInPercent SizeUnitType = 4
|
||||
// SizeInPt - size in pt (1/72 inch).
|
||||
// SizeInPt is the SizeUnit type: the Value field specifies the size in pt (1/72 inch).
|
||||
SizeInPt SizeUnitType = 5
|
||||
// SizeInPc - size in pc (1pc = 12pt).
|
||||
// SizeInPc is the SizeUnit type: the Value field specifies the size in pc (1pc = 12pt).
|
||||
SizeInPc SizeUnitType = 6
|
||||
// SizeInInch - size in inches.
|
||||
// SizeInInch is the SizeUnit type: the Value field specifies the size in inches.
|
||||
SizeInInch SizeUnitType = 7
|
||||
// SizeInMM - size in millimeters.
|
||||
// SizeInMM is the SizeUnit type: the Value field specifies the size in millimeters.
|
||||
SizeInMM SizeUnitType = 8
|
||||
// SizeInCM - size in centimeters.
|
||||
// SizeInCM is the SizeUnit type: the Value field specifies the size in centimeters.
|
||||
SizeInCM SizeUnitType = 9
|
||||
// SizeInFraction - size in fraction. Used only for "cell-width" and "cell-height" property
|
||||
// SizeInFraction is the SizeUnit type: the Value field specifies the size in fraction.
|
||||
// Used only for "cell-width" and "cell-height" property.
|
||||
SizeInFraction SizeUnitType = 10
|
||||
// SizeFunction is the SizeUnit type: the Function field specifies the size function.
|
||||
// "min", "max", "clamp", "sum", "sub", "mul", and "div" functions are available.
|
||||
SizeFunction = 11
|
||||
)
|
||||
|
||||
// SizeUnit describe a size (Value field) and size unit (Type field).
|
||||
type SizeUnit struct {
|
||||
Type SizeUnitType
|
||||
Value float64
|
||||
Function SizeFunc
|
||||
}
|
||||
|
||||
// AutoSize creates SizeUnit with Auto type
|
||||
func AutoSize() SizeUnit {
|
||||
return SizeUnit{Auto, 0}
|
||||
return SizeUnit{Auto, 0, nil}
|
||||
}
|
||||
|
||||
// Px creates SizeUnit with SizeInPixel type
|
||||
func Px(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInPixel, value}
|
||||
return SizeUnit{SizeInPixel, value, nil}
|
||||
}
|
||||
|
||||
// Em creates SizeUnit with SizeInEM type
|
||||
func Em(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInEM, value}
|
||||
return SizeUnit{SizeInEM, value, nil}
|
||||
}
|
||||
|
||||
// Ex creates SizeUnit with SizeInEX type
|
||||
func Ex(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInEX, value}
|
||||
return SizeUnit{SizeInEX, value, nil}
|
||||
}
|
||||
|
||||
// Percent creates SizeUnit with SizeInDIP type
|
||||
func Percent(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInPercent, value}
|
||||
return SizeUnit{SizeInPercent, value, nil}
|
||||
}
|
||||
|
||||
// Pt creates SizeUnit with SizeInPt type
|
||||
func Pt(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInPt, value}
|
||||
return SizeUnit{SizeInPt, value, nil}
|
||||
}
|
||||
|
||||
// Pc creates SizeUnit with SizeInPc type
|
||||
func Pc(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInPc, value}
|
||||
return SizeUnit{SizeInPc, value, nil}
|
||||
}
|
||||
|
||||
// Mm creates SizeUnit with SizeInMM type
|
||||
func Mm(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInMM, value}
|
||||
return SizeUnit{SizeInMM, value, nil}
|
||||
}
|
||||
|
||||
// Cm creates SizeUnit with SizeInCM type
|
||||
func Cm(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInCM, value}
|
||||
return SizeUnit{SizeInCM, value, nil}
|
||||
}
|
||||
|
||||
// Inch creates SizeUnit with SizeInInch type
|
||||
func Inch(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInInch, value}
|
||||
return SizeUnit{SizeInInch, value, nil}
|
||||
}
|
||||
|
||||
// Fr creates SizeUnit with SizeInFraction type
|
||||
func Fr(value float64) SizeUnit {
|
||||
return SizeUnit{SizeInFraction, value}
|
||||
return SizeUnit{SizeInFraction, value, nil}
|
||||
}
|
||||
|
||||
// Equal compare two SizeUnit. Return true if SizeUnit are equal
|
||||
|
@ -152,13 +157,24 @@ func stringToSizeUnit(value string) (SizeUnit, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if val, err := strconv.ParseFloat(value, 64); err == nil {
|
||||
return SizeUnit{Type: SizeInPixel, Value: val}, nil
|
||||
}
|
||||
|
||||
return SizeUnit{Type: Auto, Value: 0}, errors.New(`Invalid SizeUnit value: "` + value + `"`)
|
||||
}
|
||||
|
||||
// String - convert SizeUnit to string
|
||||
func (size SizeUnit) String() string {
|
||||
if size.Type == Auto {
|
||||
switch size.Type {
|
||||
case Auto:
|
||||
return "auto"
|
||||
|
||||
case SizeFunction:
|
||||
if size.Function == nil {
|
||||
return "auto"
|
||||
}
|
||||
return size.Function.String()
|
||||
}
|
||||
if suffix, ok := sizeUnitSuffixes()[size.Type]; ok {
|
||||
return fmt.Sprintf("%g%s", size.Value, suffix)
|
||||
|
@ -167,13 +183,19 @@ func (size SizeUnit) String() string {
|
|||
}
|
||||
|
||||
// cssString - convert SizeUnit to string
|
||||
func (size SizeUnit) cssString(textForAuto string) string {
|
||||
func (size SizeUnit) cssString(textForAuto string, session Session) string {
|
||||
switch size.Type {
|
||||
case Auto:
|
||||
return textForAuto
|
||||
|
||||
case SizeInEM:
|
||||
return fmt.Sprintf("%grem", size.Value)
|
||||
|
||||
case SizeFunction:
|
||||
if size.Function == nil {
|
||||
return textForAuto
|
||||
}
|
||||
return size.Function.cssString(session)
|
||||
}
|
||||
|
||||
if size.Value == 0 {
|
||||
|
|
|
@ -41,7 +41,7 @@ type stackLayoutData struct {
|
|||
// NewStackLayout create new StackLayout object and return it
|
||||
func NewStackLayout(session Session, params Params) StackLayout {
|
||||
view := new(stackLayoutData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ func newStackLayout(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of ViewsContainer by default values
|
||||
func (layout *stackLayoutData) Init(session Session) {
|
||||
layout.viewsContainerData.Init(session)
|
||||
func (layout *stackLayoutData) init(session Session) {
|
||||
layout.viewsContainerData.init(session)
|
||||
layout.tag = "StackLayout"
|
||||
layout.systemClass = "ruiStackLayout"
|
||||
layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished}
|
||||
|
@ -97,11 +97,11 @@ func (layout *stackLayoutData) popFinished(view View, tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (layout *stackLayoutData) Set(tag string, value interface{}) bool {
|
||||
func (layout *stackLayoutData) Set(tag string, value any) bool {
|
||||
return layout.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (layout *stackLayoutData) set(tag string, value interface{}) bool {
|
||||
func (layout *stackLayoutData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
layout.remove(tag)
|
||||
return true
|
||||
|
@ -109,8 +109,8 @@ func (layout *stackLayoutData) set(tag string, value interface{}) bool {
|
|||
|
||||
switch tag {
|
||||
case TransitionEndEvent:
|
||||
listeners, ok := valueToAnimationListeners(value)
|
||||
if ok {
|
||||
listeners, ok := valueToEventListeners[View, string](value)
|
||||
if ok && listeners != nil {
|
||||
listeners = append(listeners, layout.pushFinished)
|
||||
listeners = append(listeners, layout.popFinished)
|
||||
layout.properties[TransitionEndEvent] = listeners
|
||||
|
@ -179,11 +179,11 @@ func (layout *stackLayoutData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (layout *stackLayoutData) Get(tag string) interface{} {
|
||||
func (layout *stackLayoutData) Get(tag string) any {
|
||||
return layout.get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (layout *stackLayoutData) get(tag string) interface{} {
|
||||
func (layout *stackLayoutData) get(tag string) any {
|
||||
if tag == Current {
|
||||
return layout.peek
|
||||
}
|
||||
|
@ -351,6 +351,8 @@ func (layout *stackLayoutData) Pop(animation int, onPopFinished func(View)) bool
|
|||
buffer.WriteString(htmlID)
|
||||
buffer.WriteString(`pop" class="ruiStackPageLayout" ontransitionend="stackTransitionEndEvent(\'`)
|
||||
buffer.WriteString(htmlID)
|
||||
buffer.WriteString(`\', \'ruiPop\', event)" ontransitioncancel="stackTransitionEndEvent(\'`)
|
||||
buffer.WriteString(htmlID)
|
||||
buffer.WriteString(`\', \'ruiPop\', event)" style="transition: transform 1s ease;">`)
|
||||
viewHTML(layout.popView, buffer)
|
||||
buffer.WriteString(`</div>`)
|
||||
|
|
|
@ -2,7 +2,7 @@ package rui
|
|||
|
||||
import (
|
||||
"embed"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
@ -28,7 +28,7 @@ func scanEmbedStringsDir(fs *embed.FS, dir string) {
|
|||
}
|
||||
|
||||
func scanStringsDir(path string) {
|
||||
if files, err := ioutil.ReadDir(path); err == nil {
|
||||
if files, err := os.ReadDir(path); err == nil {
|
||||
for _, file := range files {
|
||||
filename := file.Name()
|
||||
if filename[0] != '.' {
|
||||
|
@ -36,7 +36,7 @@ func scanStringsDir(path string) {
|
|||
if file.IsDir() {
|
||||
scanStringsDir(newPath)
|
||||
} else if strings.ToLower(filepath.Ext(newPath)) == ".rui" {
|
||||
if data, err := ioutil.ReadFile(newPath); err == nil {
|
||||
if data, err := os.ReadFile(newPath); err == nil {
|
||||
loadStringResources(string(data))
|
||||
} else {
|
||||
ErrorLog(err.Error())
|
||||
|
|
|
@ -18,7 +18,7 @@ type TableAdapter interface {
|
|||
// * rui.View
|
||||
// * fmt.Stringer
|
||||
// * rui.VerticalTableJoin, rui.HorizontalTableJoin
|
||||
Cell(row, column int) interface{}
|
||||
Cell(row, column int) any
|
||||
}
|
||||
|
||||
// TableColumnStyle describes the style of TableView columns.
|
||||
|
@ -59,15 +59,15 @@ type TableAllowRowSelection interface {
|
|||
}
|
||||
|
||||
// SimpleTableAdapter is implementation of TableAdapter where the content
|
||||
// defines as [][]interface{}.
|
||||
// When you assign [][]interface{} value to the "content" property, it is converted to SimpleTableAdapter
|
||||
// defines as [][]any.
|
||||
// When you assign [][]any value to the "content" property, it is converted to SimpleTableAdapter
|
||||
type SimpleTableAdapter interface {
|
||||
TableAdapter
|
||||
TableCellStyle
|
||||
}
|
||||
|
||||
type simpleTableAdapter struct {
|
||||
content [][]interface{}
|
||||
content [][]any
|
||||
columnCount int
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ type HorizontalTableJoin struct {
|
|||
}
|
||||
|
||||
// NewSimpleTableAdapter creates the new SimpleTableAdapter
|
||||
func NewSimpleTableAdapter(content [][]interface{}) SimpleTableAdapter {
|
||||
func NewSimpleTableAdapter(content [][]any) SimpleTableAdapter {
|
||||
if content == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ func (adapter *simpleTableAdapter) ColumnCount() int {
|
|||
return adapter.columnCount
|
||||
}
|
||||
|
||||
func (adapter *simpleTableAdapter) Cell(row, column int) interface{} {
|
||||
func (adapter *simpleTableAdapter) Cell(row, column int) any {
|
||||
if adapter.content != nil && row >= 0 && row < len(adapter.content) &&
|
||||
adapter.content[row] != nil && column >= 0 && column < len(adapter.content[row]) {
|
||||
return adapter.content[row][column]
|
||||
|
@ -220,7 +220,7 @@ func (adapter *textTableAdapter) ColumnCount() int {
|
|||
return adapter.columnCount
|
||||
}
|
||||
|
||||
func (adapter *textTableAdapter) Cell(row, column int) interface{} {
|
||||
func (adapter *textTableAdapter) Cell(row, column int) any {
|
||||
if adapter.content != nil && row >= 0 && row < len(adapter.content) &&
|
||||
adapter.content[row] != nil && column >= 0 && column < len(adapter.content[row]) {
|
||||
return adapter.content[row][column]
|
||||
|
@ -242,7 +242,7 @@ func (style *simpleTableRowStyle) RowStyle(row int) Params {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (table *tableViewData) setRowStyle(value interface{}) bool {
|
||||
func (table *tableViewData) setRowStyle(value any) bool {
|
||||
newSimpleTableRowStyle := func(params []Params) TableRowStyle {
|
||||
if len(params) == 0 {
|
||||
return nil
|
||||
|
@ -319,7 +319,7 @@ func (style *simpleTableColumnStyle) ColumnStyle(row int) Params {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (table *tableViewData) setColumnStyle(value interface{}) bool {
|
||||
func (table *tableViewData) setColumnStyle(value any) bool {
|
||||
newSimpleTableColumnStyle := func(params []Params) TableColumnStyle {
|
||||
if len(params) == 0 {
|
||||
return nil
|
||||
|
|
133
tableView.go
133
tableView.go
|
@ -245,7 +245,7 @@ type tableCellView struct {
|
|||
// NewTableView create new TableView object and return it
|
||||
func NewTableView(session Session, params Params) TableView {
|
||||
view := new(tableViewData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -255,8 +255,8 @@ func newTableView(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of TableView by default values
|
||||
func (table *tableViewData) Init(session Session) {
|
||||
table.viewData.Init(session)
|
||||
func (table *tableViewData) init(session Session) {
|
||||
table.viewData.init(session)
|
||||
table.tag = "TableView"
|
||||
table.cellViews = []View{}
|
||||
table.cellFrame = []Frame{}
|
||||
|
@ -290,10 +290,10 @@ func (table *tableViewData) normalizeTag(tag string) string {
|
|||
}
|
||||
|
||||
func (table *tableViewData) Focusable() bool {
|
||||
return GetTableSelectionMode(table, "") != NoneSelection
|
||||
return GetTableSelectionMode(table) != NoneSelection
|
||||
}
|
||||
|
||||
func (table *tableViewData) Get(tag string) interface{} {
|
||||
func (table *tableViewData) Get(tag string) any {
|
||||
return table.get(table.normalizeTag(tag))
|
||||
}
|
||||
|
||||
|
@ -340,11 +340,11 @@ func (table *tableViewData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (table *tableViewData) Set(tag string, value interface{}) bool {
|
||||
func (table *tableViewData) Set(tag string, value any) bool {
|
||||
return table.set(table.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (table *tableViewData) set(tag string, value interface{}) bool {
|
||||
func (table *tableViewData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
table.remove(tag)
|
||||
return true
|
||||
|
@ -356,7 +356,7 @@ func (table *tableViewData) set(tag string, value interface{}) bool {
|
|||
case TableAdapter:
|
||||
table.properties[Content] = value
|
||||
|
||||
case [][]interface{}:
|
||||
case [][]any:
|
||||
table.properties[Content] = NewSimpleTableAdapter(val)
|
||||
|
||||
case [][]string:
|
||||
|
@ -384,20 +384,24 @@ func (table *tableViewData) set(tag string, value interface{}) bool {
|
|||
table.cellSelectedListener = listeners
|
||||
|
||||
case TableRowClickedEvent:
|
||||
listeners := table.valueToRowListeners(value)
|
||||
if listeners == nil {
|
||||
listeners, ok := valueToEventListeners[TableView, int](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
} else if listeners == nil {
|
||||
listeners = []func(TableView, int){}
|
||||
}
|
||||
table.rowClickedListener = listeners
|
||||
|
||||
case TableRowSelectedEvent:
|
||||
listeners := table.valueToRowListeners(value)
|
||||
if listeners == nil {
|
||||
listeners, ok := valueToEventListeners[TableView, int](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
} else if listeners == nil {
|
||||
listeners = []func(TableView, int){}
|
||||
}
|
||||
table.rowSelectedListener = []func(TableView, int){}
|
||||
table.rowSelectedListener = listeners
|
||||
|
||||
case CellStyle:
|
||||
if style, ok := value.(TableCellStyle); ok {
|
||||
|
@ -450,13 +454,10 @@ func (table *tableViewData) set(tag string, value interface{}) bool {
|
|||
delete(table.properties, tag)
|
||||
}
|
||||
|
||||
case DataNode:
|
||||
switch value.Type() {
|
||||
case ObjectNode:
|
||||
obj := value.Object()
|
||||
case DataObject:
|
||||
params := Params{}
|
||||
for k := 0; k < obj.PropertyCount(); k++ {
|
||||
if prop := obj.Property(k); prop != nil && prop.Type() == TextNode {
|
||||
for k := 0; k < value.PropertyCount(); k++ {
|
||||
if prop := value.Property(k); prop != nil && prop.Type() == TextNode {
|
||||
params[prop.Tag()] = prop.Text()
|
||||
}
|
||||
}
|
||||
|
@ -466,6 +467,11 @@ func (table *tableViewData) set(tag string, value interface{}) bool {
|
|||
delete(table.properties, tag)
|
||||
}
|
||||
|
||||
case DataNode:
|
||||
switch value.Type() {
|
||||
case ObjectNode:
|
||||
return table.set(tag, value.Object())
|
||||
|
||||
case TextNode:
|
||||
table.properties[tag] = value.Text()
|
||||
|
||||
|
@ -590,7 +596,7 @@ func (table *tableViewData) propertyChanged(tag string) {
|
|||
updateCSSProperty(htmlID, "border-spacing", "0", session)
|
||||
updateCSSProperty(htmlID, "border-collapse", "collapse", session)
|
||||
} else {
|
||||
updateCSSProperty(htmlID, "border-spacing", gap.cssString("0"), session)
|
||||
updateCSSProperty(htmlID, "border-spacing", gap.cssString("0", session), session)
|
||||
updateCSSProperty(htmlID, "border-collapse", "separate", session)
|
||||
}
|
||||
|
||||
|
@ -598,7 +604,7 @@ func (table *tableViewData) propertyChanged(tag string) {
|
|||
htmlID := table.htmlID()
|
||||
session := table.Session()
|
||||
|
||||
switch GetTableSelectionMode(table, "") {
|
||||
switch GetTableSelectionMode(table) {
|
||||
case CellSelection:
|
||||
updateProperty(htmlID, "tabindex", "0", session)
|
||||
updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)", session)
|
||||
|
@ -676,7 +682,7 @@ func (table *tableViewData) currentInactiveStyle() string {
|
|||
return "ruiCurrentTableCell"
|
||||
}
|
||||
|
||||
func (table *tableViewData) valueToCellListeners(value interface{}) []func(TableView, int, int) {
|
||||
func (table *tableViewData) valueToCellListeners(value any) []func(TableView, int, int) {
|
||||
if value == nil {
|
||||
return []func(TableView, int, int){}
|
||||
}
|
||||
|
@ -706,7 +712,7 @@ func (table *tableViewData) valueToCellListeners(value interface{}) []func(Table
|
|||
}
|
||||
return listeners
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
listeners := make([]func(TableView, int, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
|
@ -731,61 +737,6 @@ func (table *tableViewData) valueToCellListeners(value interface{}) []func(Table
|
|||
return nil
|
||||
}
|
||||
|
||||
func (table *tableViewData) valueToRowListeners(value interface{}) []func(TableView, int) {
|
||||
if value == nil {
|
||||
return []func(TableView, int){}
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(TableView, int):
|
||||
return []func(TableView, int){value}
|
||||
|
||||
case func(int):
|
||||
fn := func(_ TableView, index int) {
|
||||
value(index)
|
||||
}
|
||||
return []func(TableView, int){fn}
|
||||
|
||||
case []func(TableView, int):
|
||||
return value
|
||||
|
||||
case []func(int):
|
||||
listeners := make([]func(TableView, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
listeners[i] = func(_ TableView, index int) {
|
||||
val(index)
|
||||
}
|
||||
}
|
||||
return listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(TableView, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
switch val := val.(type) {
|
||||
case func(TableView, int):
|
||||
listeners[i] = val
|
||||
|
||||
case func(int):
|
||||
listeners[i] = func(_ TableView, index int) {
|
||||
val(index)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return listeners
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (table *tableViewData) htmlTag() string {
|
||||
return "table"
|
||||
}
|
||||
|
@ -808,7 +759,7 @@ func (table *tableViewData) htmlProperties(self View, buffer *strings.Builder) {
|
|||
buffer.WriteRune('"')
|
||||
}
|
||||
|
||||
if selectionMode := GetTableSelectionMode(table, ""); selectionMode != NoneSelection {
|
||||
if selectionMode := GetTableSelectionMode(table); selectionMode != NoneSelection {
|
||||
buffer.WriteString(` onfocus="tableViewFocusEvent(this, event)" onblur="tableViewBlurEvent(this, event)" data-focusitemstyle="`)
|
||||
buffer.WriteString(table.currentStyle())
|
||||
buffer.WriteString(`" data-bluritemstyle="`)
|
||||
|
@ -879,10 +830,10 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
defer freeStringBuilder(cssBuilder.buffer)
|
||||
|
||||
var view tableCellView
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
|
||||
ignorCells := []struct{ row, column int }{}
|
||||
selectionMode := GetTableSelectionMode(table, "")
|
||||
selectionMode := GetTableSelectionMode(table)
|
||||
|
||||
var allowCellSelection TableAllowCellSelection = nil
|
||||
if allow, ok := adapter.(TableAllowCellSelection); ok {
|
||||
|
@ -905,7 +856,7 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
}
|
||||
|
||||
vAlignCss := enumProperties[TableVerticalAlign].cssValues
|
||||
vAlignValue := GetTableVerticalAlign(table, "")
|
||||
vAlignValue := GetTableVerticalAlign(table)
|
||||
if vAlignValue < 0 || vAlignValue >= len(vAlignCss) {
|
||||
vAlignValue = 0
|
||||
}
|
||||
|
@ -1160,8 +1111,8 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
buffer.WriteString("</colgroup>")
|
||||
}
|
||||
|
||||
headHeight := GetTableHeadHeight(table, "")
|
||||
footHeight := GetTableFootHeight(table, "")
|
||||
headHeight := GetTableHeadHeight(table)
|
||||
footHeight := GetTableFootHeight(table)
|
||||
cellBorder := table.getCellBorder()
|
||||
cellPadding := table.boundsProperty(CellPadding)
|
||||
if cellPadding == nil {
|
||||
|
@ -1370,24 +1321,26 @@ func (table *tableViewData) getCurrent() CellIndex {
|
|||
}
|
||||
|
||||
func (table *tableViewData) cssStyle(self View, builder cssBuilder) {
|
||||
table.viewData.cssViewStyle(builder, table.Session())
|
||||
session := table.Session()
|
||||
table.viewData.cssViewStyle(builder, session)
|
||||
|
||||
gap, ok := sizeProperty(table, Gap, table.Session())
|
||||
gap, ok := sizeProperty(table, Gap, session)
|
||||
if !ok || gap.Type == Auto || gap.Value <= 0 {
|
||||
builder.add("border-spacing", "0")
|
||||
builder.add("border-collapse", "collapse")
|
||||
} else {
|
||||
builder.add("border-spacing", gap.cssString("0"))
|
||||
builder.add("border-spacing", gap.cssString("0", session))
|
||||
builder.add("border-collapse", "separate")
|
||||
}
|
||||
}
|
||||
|
||||
func (table *tableViewData) ReloadTableData() {
|
||||
session := table.Session()
|
||||
if content := table.content(); content != nil {
|
||||
updateProperty(table.htmlID(), "data-rows", strconv.Itoa(content.RowCount()), table.Session())
|
||||
updateProperty(table.htmlID(), "data-columns", strconv.Itoa(content.ColumnCount()), table.Session())
|
||||
updateProperty(table.htmlID(), "data-rows", strconv.Itoa(content.RowCount()), session)
|
||||
updateProperty(table.htmlID(), "data-columns", strconv.Itoa(content.ColumnCount()), session)
|
||||
}
|
||||
updateInnerHTML(table.htmlID(), table.Session())
|
||||
updateInnerHTML(table.htmlID(), session)
|
||||
}
|
||||
|
||||
func (table *tableViewData) onItemResize(self View, index string, x, y, width, height float64) {
|
||||
|
|
|
@ -2,11 +2,11 @@ package rui
|
|||
|
||||
import "strings"
|
||||
|
||||
func (cell *tableCellView) Set(tag string, value interface{}) bool {
|
||||
func (cell *tableCellView) Set(tag string, value any) bool {
|
||||
return cell.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (cell *tableCellView) set(tag string, value interface{}) bool {
|
||||
func (cell *tableCellView) set(tag string, value any) bool {
|
||||
switch tag {
|
||||
case VerticalAlign:
|
||||
tag = TableVerticalAlign
|
||||
|
@ -24,10 +24,10 @@ func (cell *tableCellView) cssStyle(self View, builder cssBuilder) {
|
|||
}
|
||||
|
||||
// GetTableContent returns a TableAdapter which defines the TableView content.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableContent(view View, subviewID string) TableAdapter {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableContent(view View, subviewID ...string) TableAdapter {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
|
@ -40,10 +40,10 @@ func GetTableContent(view View, subviewID string) TableAdapter {
|
|||
}
|
||||
|
||||
// GetTableRowStyle returns a TableRowStyle which defines styles of TableView rows.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableRowStyle(view View, subviewID string) TableRowStyle {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableRowStyle(view View, subviewID ...string) TableRowStyle {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
|
@ -56,10 +56,10 @@ func GetTableRowStyle(view View, subviewID string) TableRowStyle {
|
|||
}
|
||||
|
||||
// GetTableColumnStyle returns a TableColumnStyle which defines styles of TableView columns.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableColumnStyle(view View, subviewID string) TableColumnStyle {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableColumnStyle(view View, subviewID ...string) TableColumnStyle {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
|
@ -72,10 +72,10 @@ func GetTableColumnStyle(view View, subviewID string) TableColumnStyle {
|
|||
}
|
||||
|
||||
// GetTableCellStyle returns a TableCellStyle which defines styles of TableView cells.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableCellStyle(view View, subviewID string) TableCellStyle {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableCellStyle(view View, subviewID ...string) TableCellStyle {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
|
@ -89,72 +89,42 @@ func GetTableCellStyle(view View, subviewID string) TableCellStyle {
|
|||
|
||||
// GetTableSelectionMode returns the mode of the TableView elements selection.
|
||||
// Valid values are NoneSelection (0), CellSelection (1), and RowSelection (2).
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableSelectionMode(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := enumStyledProperty(view, SelectionMode, NoneSelection); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return NoneSelection
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableSelectionMode(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, SelectionMode, NoneSelection, false)
|
||||
}
|
||||
|
||||
// GetTableVerticalAlign returns a vertical align in a TavleView cell. Returns one of next values:
|
||||
// TopAlign (0), BottomAlign (1), CenterAlign (2), and BaselineAlign (3)
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableVerticalAlign(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if result, ok := enumStyledProperty(view, TableVerticalAlign, TopAlign); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return TopAlign
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableVerticalAlign(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, TableVerticalAlign, TopAlign, false)
|
||||
}
|
||||
|
||||
// GetTableHeadHeight returns the number of rows in the table header.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableHeadHeight(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
headHeight, _ := intStyledProperty(view, HeadHeight, 0)
|
||||
return headHeight
|
||||
}
|
||||
return 0
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableHeadHeight(view View, subviewID ...string) int {
|
||||
return intStyledProperty(view, subviewID, HeadHeight, 0)
|
||||
}
|
||||
|
||||
// GetTableFootHeight returns the number of rows in the table footer.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableFootHeight(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
headHeight, _ := intStyledProperty(view, FootHeight, 0)
|
||||
return headHeight
|
||||
}
|
||||
return 0
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableFootHeight(view View, subviewID ...string) int {
|
||||
return intStyledProperty(view, subviewID, FootHeight, 0)
|
||||
}
|
||||
|
||||
// GetTableCurrent returns the row and column index of the TableView selected cell/row.
|
||||
// If there is no selected cell/row or the selection mode is NoneSelection (0),
|
||||
// then a value of the row and column index less than 0 is returned.
|
||||
// If the selection mode is RowSelection (2) then the returned column index is less than 0.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableCurrent(view View, subviewID string) CellIndex {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableCurrent(view View, subviewID ...string) CellIndex {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
if selectionMode := GetTableSelectionMode(view, ""); selectionMode != NoneSelection {
|
||||
if selectionMode := GetTableSelectionMode(view); selectionMode != NoneSelection {
|
||||
if tableView, ok := view.(TableView); ok {
|
||||
return tableView.getCurrent()
|
||||
}
|
||||
|
@ -165,10 +135,10 @@ func GetTableCurrent(view View, subviewID string) CellIndex {
|
|||
|
||||
// GetTableCellClickedListeners returns listeners of event which occurs when the user clicks on a table cell.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableCellClickedListeners(view View, subviewID string) []func(TableView, int, int) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// 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) {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(TableCellClickedEvent); value != nil {
|
||||
|
@ -182,10 +152,10 @@ func GetTableCellClickedListeners(view View, subviewID string) []func(TableView,
|
|||
|
||||
// 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 the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableCellSelectedListeners(view View, subviewID string) []func(TableView, int, int) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// 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) {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(TableCellSelectedEvent); value != nil {
|
||||
|
@ -199,43 +169,23 @@ func GetTableCellSelectedListeners(view View, subviewID string) []func(TableView
|
|||
|
||||
// GetTableRowClickedListeners returns listeners of event which occurs when the user clicks on a table row.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableRowClickedListeners(view View, subviewID string) []func(TableView, int) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(TableRowClickedEvent); value != nil {
|
||||
if result, ok := value.([]func(TableView, int)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(TableView, int){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableRowClickedListeners(view View, subviewID ...string) []func(TableView, int) {
|
||||
return getEventListeners[TableView, int](view, subviewID, TableRowClickedEvent)
|
||||
}
|
||||
|
||||
// GetTableRowSelectedListeners returns listeners of event which occurs when a table row becomes selected.
|
||||
// If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTableRowSelectedListeners(view View, subviewID string) []func(TableView, int) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(TableRowSelectedEvent); value != nil {
|
||||
if result, ok := value.([]func(TableView, int)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(TableView, int){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTableRowSelectedListeners(view View, subviewID ...string) []func(TableView, int) {
|
||||
return getEventListeners[TableView, int](view, subviewID, TableRowSelectedEvent)
|
||||
}
|
||||
|
||||
// ReloadTableViewData updates TableView
|
||||
func ReloadTableViewData(view View, subviewID string) bool {
|
||||
func ReloadTableViewData(view View, subviewID ...string) bool {
|
||||
var tableView TableView
|
||||
if subviewID != "" {
|
||||
if tableView = TableViewByID(view, subviewID); tableView == nil {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
if tableView = TableViewByID(view, subviewID[0]); tableView == nil {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -81,7 +81,7 @@ type tabsLayoutData struct {
|
|||
// NewTabsLayout create new TabsLayout object and return it
|
||||
func NewTabsLayout(session Session, params Params) TabsLayout {
|
||||
view := new(tabsLayoutData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -91,8 +91,8 @@ func newTabsLayout(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of ViewsContainer by default values
|
||||
func (tabsLayout *tabsLayoutData) Init(session Session) {
|
||||
tabsLayout.viewsContainerData.Init(session)
|
||||
func (tabsLayout *tabsLayoutData) init(session Session) {
|
||||
tabsLayout.viewsContainerData.init(session)
|
||||
tabsLayout.tag = "TabsLayout"
|
||||
tabsLayout.systemClass = "ruiTabsLayout"
|
||||
tabsLayout.tabListener = []func(TabsLayout, int, int){}
|
||||
|
@ -108,11 +108,11 @@ func (tabsLayout *tabsLayoutData) currentItem(defaultValue int) int {
|
|||
return result
|
||||
}
|
||||
|
||||
func (tabsLayout *tabsLayoutData) Get(tag string) interface{} {
|
||||
func (tabsLayout *tabsLayoutData) Get(tag string) any {
|
||||
return tabsLayout.get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (tabsLayout *tabsLayoutData) get(tag string) interface{} {
|
||||
func (tabsLayout *tabsLayoutData) get(tag string) any {
|
||||
switch tag {
|
||||
case CurrentTabChangedEvent:
|
||||
return tabsLayout.tabListener
|
||||
|
@ -190,11 +190,11 @@ func (tabsLayout *tabsLayoutData) remove(tag string) {
|
|||
tabsLayout.propertyChangedEvent(tag)
|
||||
}
|
||||
|
||||
func (tabsLayout *tabsLayoutData) Set(tag string, value interface{}) bool {
|
||||
func (tabsLayout *tabsLayoutData) Set(tag string, value any) bool {
|
||||
return tabsLayout.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
|
||||
func (tabsLayout *tabsLayoutData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
tabsLayout.remove(tag)
|
||||
return true
|
||||
|
@ -210,10 +210,12 @@ func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
|
|||
tabsLayout.tabListener = listeners
|
||||
|
||||
case TabCloseEvent:
|
||||
listeners := tabsLayout.valueToCloseListeners(value)
|
||||
if listeners == nil {
|
||||
listeners, ok := valueToEventListeners[TabsLayout, int](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
} else if listeners == nil {
|
||||
listeners = []func(TabsLayout, int){}
|
||||
}
|
||||
tabsLayout.tabCloseListener = listeners
|
||||
|
||||
|
@ -286,7 +288,7 @@ func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (tabsLayout *tabsLayoutData) valueToTabListeners(value interface{}) []func(TabsLayout, int, int) {
|
||||
func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayout, int, int) {
|
||||
if value == nil {
|
||||
return []func(TabsLayout, int, int){}
|
||||
}
|
||||
|
@ -388,7 +390,7 @@ func (tabsLayout *tabsLayoutData) valueToTabListeners(value interface{}) []func(
|
|||
}
|
||||
return listeners
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
listeners := make([]func(TabsLayout, int, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
|
@ -433,61 +435,6 @@ func (tabsLayout *tabsLayoutData) valueToTabListeners(value interface{}) []func(
|
|||
return nil
|
||||
}
|
||||
|
||||
func (tabsLayout *tabsLayoutData) valueToCloseListeners(value interface{}) []func(TabsLayout, int) {
|
||||
if value == nil {
|
||||
return []func(TabsLayout, int){}
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(TabsLayout, int):
|
||||
return []func(TabsLayout, int){value}
|
||||
|
||||
case func(int):
|
||||
fn := func(_ TabsLayout, index int) {
|
||||
value(index)
|
||||
}
|
||||
return []func(TabsLayout, int){fn}
|
||||
|
||||
case []func(TabsLayout, int):
|
||||
return value
|
||||
|
||||
case []func(int):
|
||||
listeners := make([]func(TabsLayout, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
listeners[i] = func(_ TabsLayout, index int) {
|
||||
val(index)
|
||||
}
|
||||
}
|
||||
return listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(TabsLayout, int), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
switch val := val.(type) {
|
||||
case func(TabsLayout, int):
|
||||
listeners[i] = val
|
||||
|
||||
case func(int):
|
||||
listeners[i] = func(_ TabsLayout, index int) {
|
||||
val(index)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return listeners
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tabsLayout *tabsLayoutData) tabsLocation() int {
|
||||
tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0)
|
||||
return tabs
|
||||
|
@ -576,7 +523,7 @@ func (tabsLayout *tabsLayoutData) ListItem(index int, session Session) View {
|
|||
if !ok || title == "" {
|
||||
title = "No title"
|
||||
}
|
||||
if !GetNotTranslate(tabsLayout, "") {
|
||||
if !GetNotTranslate(tabsLayout) {
|
||||
title, _ = tabsLayout.Session().GetString(title)
|
||||
}
|
||||
|
||||
|
@ -776,7 +723,7 @@ func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builde
|
|||
inactiveStyle := tabsLayout.inactiveTabStyle()
|
||||
activeStyle := tabsLayout.activeTabStyle()
|
||||
|
||||
notTranslate := GetNotTranslate(tabsLayout, "")
|
||||
notTranslate := GetNotTranslate(tabsLayout)
|
||||
closeButton, _ := boolProperty(tabsLayout, TabCloseButton, tabsLayout.session)
|
||||
|
||||
var tabStyle, titleDiv string
|
||||
|
|
27
textView.go
27
textView.go
|
@ -17,7 +17,7 @@ type textViewData struct {
|
|||
// NewTextView create new TextView object and return it
|
||||
func NewTextView(session Session, params Params) TextView {
|
||||
view := new(textViewData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ func newTextView(session Session) View {
|
|||
}
|
||||
|
||||
// Init initialize fields of TextView by default values
|
||||
func (textView *textViewData) Init(session Session) {
|
||||
textView.viewData.Init(session)
|
||||
func (textView *textViewData) init(session Session) {
|
||||
textView.viewData.init(session)
|
||||
textView.tag = "TextView"
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ func (textView *textViewData) String() string {
|
|||
return getViewString(textView)
|
||||
}
|
||||
|
||||
func (textView *textViewData) Get(tag string) interface{} {
|
||||
func (textView *textViewData) Get(tag string) any {
|
||||
return textView.get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
|
@ -57,11 +57,11 @@ func (textView *textViewData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (textView *textViewData) Set(tag string, value interface{}) bool {
|
||||
func (textView *textViewData) Set(tag string, value any) bool {
|
||||
return textView.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (textView *textViewData) set(tag string, value interface{}) bool {
|
||||
func (textView *textViewData) set(tag string, value any) bool {
|
||||
switch tag {
|
||||
case Text:
|
||||
switch value := value.(type) {
|
||||
|
@ -155,7 +155,7 @@ func textToJS(text string) string {
|
|||
func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||
if value := textView.getRaw(Text); value != nil {
|
||||
if text, ok := value.(string); ok {
|
||||
if !GetNotTranslate(textView, "") {
|
||||
if !GetNotTranslate(textView) {
|
||||
text, _ = textView.session.GetString(text)
|
||||
}
|
||||
buffer.WriteString(textToJS(text))
|
||||
|
@ -165,14 +165,7 @@ func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
|||
|
||||
// GetTextOverflow returns a value of the "text-overflow" property:
|
||||
// TextOverflowClip (0) or TextOverflowEllipsis (1).
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTextOverflow(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return SingleLineText
|
||||
}
|
||||
t, _ := enumStyledProperty(view, TextOverflow, SingleLineText)
|
||||
return t
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTextOverflow(view View, subviewID ...string) int {
|
||||
return enumStyledProperty(view, subviewID, TextOverflow, SingleLineText, false)
|
||||
}
|
||||
|
|
144
timePicker.go
144
timePicker.go
|
@ -29,7 +29,7 @@ type timePickerData struct {
|
|||
// NewTimePicker create new TimePicker object and return it
|
||||
func NewTimePicker(session Session, params Params) TimePicker {
|
||||
view := new(timePickerData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ func newTimePicker(session Session) View {
|
|||
return NewTimePicker(session, nil)
|
||||
}
|
||||
|
||||
func (picker *timePickerData) Init(session Session) {
|
||||
picker.viewData.Init(session)
|
||||
func (picker *timePickerData) init(session Session) {
|
||||
picker.viewData.init(session)
|
||||
picker.tag = "TimePicker"
|
||||
picker.timeChangedListeners = []func(TimePicker, time.Time){}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ func (picker *timePickerData) remove(tag string) {
|
|||
case TimePickerValue:
|
||||
if _, ok := picker.properties[TimePickerValue]; ok {
|
||||
delete(picker.properties, TimePickerValue)
|
||||
time := GetTimePickerValue(picker, "")
|
||||
time := GetTimePickerValue(picker)
|
||||
if picker.created {
|
||||
picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), time.Format(timeFormat)))
|
||||
}
|
||||
|
@ -114,11 +114,11 @@ func (picker *timePickerData) remove(tag string) {
|
|||
picker.propertyChangedEvent(tag)
|
||||
}
|
||||
|
||||
func (picker *timePickerData) Set(tag string, value interface{}) bool {
|
||||
func (picker *timePickerData) Set(tag string, value any) bool {
|
||||
return picker.set(picker.normalizeTag(tag), value)
|
||||
}
|
||||
|
||||
func (picker *timePickerData) set(tag string, value interface{}) bool {
|
||||
func (picker *timePickerData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
picker.remove(tag)
|
||||
return true
|
||||
|
@ -192,9 +192,9 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
case TimePickerStep:
|
||||
oldStep := GetTimePickerStep(picker, "")
|
||||
oldStep := GetTimePickerStep(picker)
|
||||
if picker.setIntProperty(TimePickerStep, value) {
|
||||
if step := GetTimePickerStep(picker, ""); oldStep != step {
|
||||
if step := GetTimePickerStep(picker); oldStep != step {
|
||||
if picker.created {
|
||||
if step > 0 {
|
||||
updateProperty(picker.htmlID(), Step, strconv.Itoa(step), picker.session)
|
||||
|
@ -208,7 +208,7 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
case TimePickerValue:
|
||||
oldTime := GetTimePickerValue(picker, "")
|
||||
oldTime := GetTimePickerValue(picker)
|
||||
if time, ok := setTimeValue(TimePickerValue); ok {
|
||||
if time != oldTime {
|
||||
if picker.created {
|
||||
|
@ -223,57 +223,14 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
case TimeChangedEvent:
|
||||
switch value := value.(type) {
|
||||
case func(TimePicker, time.Time):
|
||||
picker.timeChangedListeners = []func(TimePicker, time.Time){value}
|
||||
|
||||
case func(time.Time):
|
||||
fn := func(_ TimePicker, time time.Time) {
|
||||
value(time)
|
||||
}
|
||||
picker.timeChangedListeners = []func(TimePicker, time.Time){fn}
|
||||
|
||||
case []func(TimePicker, time.Time):
|
||||
picker.timeChangedListeners = value
|
||||
|
||||
case []func(time.Time):
|
||||
listeners := make([]func(TimePicker, time.Time), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
listeners, ok := valueToEventListeners[TimePicker, time.Time](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
}
|
||||
|
||||
listeners[i] = func(_ TimePicker, time time.Time) {
|
||||
val(time)
|
||||
}
|
||||
} else if listeners == nil {
|
||||
listeners = []func(TimePicker, time.Time){}
|
||||
}
|
||||
picker.timeChangedListeners = listeners
|
||||
|
||||
case []interface{}:
|
||||
listeners := make([]func(TimePicker, time.Time), len(value))
|
||||
for i, val := range value {
|
||||
if val == nil {
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case func(TimePicker, time.Time):
|
||||
listeners[i] = val
|
||||
|
||||
case func(time.Time):
|
||||
listeners[i] = func(_ TimePicker, time time.Time) {
|
||||
val(time)
|
||||
}
|
||||
|
||||
default:
|
||||
notCompatibleType(tag, val)
|
||||
return false
|
||||
}
|
||||
}
|
||||
picker.timeChangedListeners = listeners
|
||||
}
|
||||
picker.propertyChangedEvent(tag)
|
||||
return true
|
||||
|
||||
|
@ -283,11 +240,11 @@ func (picker *timePickerData) set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (picker *timePickerData) Get(tag string) interface{} {
|
||||
func (picker *timePickerData) Get(tag string) any {
|
||||
return picker.get(picker.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (picker *timePickerData) get(tag string) interface{} {
|
||||
func (picker *timePickerData) get(tag string) any {
|
||||
switch tag {
|
||||
case TimeChangedEvent:
|
||||
return picker.timeChangedListeners
|
||||
|
@ -325,7 +282,7 @@ func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder)
|
|||
}
|
||||
|
||||
buffer.WriteString(` value="`)
|
||||
buffer.WriteString(GetTimePickerValue(picker, "").Format(timeFormat))
|
||||
buffer.WriteString(GetTimePickerValue(picker).Format(timeFormat))
|
||||
buffer.WriteByte('"')
|
||||
|
||||
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
||||
|
@ -335,7 +292,7 @@ func (picker *timePickerData) htmlProperties(self View, buffer *strings.Builder)
|
|||
}
|
||||
|
||||
func (picker *timePickerData) htmlDisabledProperties(self View, buffer *strings.Builder) {
|
||||
if IsDisabled(self, "") {
|
||||
if IsDisabled(self) {
|
||||
buffer.WriteString(` disabled`)
|
||||
}
|
||||
picker.viewData.htmlDisabledProperties(self, buffer)
|
||||
|
@ -346,7 +303,7 @@ func (picker *timePickerData) handleCommand(self View, command string, data Data
|
|||
case "textChanged":
|
||||
if text, ok := data.PropertyValue("text"); ok {
|
||||
if value, err := time.Parse(timeFormat, text); err == nil {
|
||||
oldValue := GetTimePickerValue(picker, "")
|
||||
oldValue := GetTimePickerValue(picker)
|
||||
picker.properties[TimePickerValue] = value
|
||||
if value != oldValue {
|
||||
for _, listener := range picker.timeChangedListeners {
|
||||
|
@ -362,7 +319,7 @@ func (picker *timePickerData) handleCommand(self View, command string, data Data
|
|||
}
|
||||
|
||||
func getTimeProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
||||
valueToTime := func(value interface{}) (time.Time, bool) {
|
||||
valueToTime := func(value any) (time.Time, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case time.Time:
|
||||
|
@ -396,10 +353,10 @@ func getTimeProperty(view View, mainTag, shortTag string) (time.Time, bool) {
|
|||
|
||||
// GetTimePickerMin returns the min time of TimePicker subview and "true" as the second value if the min time is set,
|
||||
// "false" as the second value otherwise.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTimePickerMin(view View, subviewID string) (time.Time, bool) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTimePickerMin(view View, subviewID ...string) (time.Time, bool) {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
return getTimeProperty(view, TimePickerMin, Min)
|
||||
|
@ -409,10 +366,10 @@ func GetTimePickerMin(view View, subviewID string) (time.Time, bool) {
|
|||
|
||||
// GetTimePickerMax returns the max time of TimePicker subview and "true" as the second value if the min time is set,
|
||||
// "false" as the second value otherwise.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTimePickerMax(view View, subviewID string) (time.Time, bool) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTimePickerMax(view View, subviewID ...string) (time.Time, bool) {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
return getTimeProperty(view, TimePickerMax, Max)
|
||||
|
@ -421,31 +378,16 @@ func GetTimePickerMax(view View, subviewID string) (time.Time, bool) {
|
|||
}
|
||||
|
||||
// GetTimePickerStep returns the time changing step in seconds of TimePicker subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTimePickerStep(view View, subviewID string) int {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view == nil {
|
||||
return 60
|
||||
}
|
||||
|
||||
result, ok := intStyledProperty(view, TimePickerStep, 60)
|
||||
if !ok {
|
||||
result, _ = intStyledProperty(view, Step, 60)
|
||||
}
|
||||
|
||||
if result < 0 {
|
||||
return 60
|
||||
}
|
||||
return result
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTimePickerStep(view View, subviewID ...string) int {
|
||||
return intStyledProperty(view, subviewID, TimePickerStep, 60)
|
||||
}
|
||||
|
||||
// GetTimePickerValue returns the time of TimePicker subview.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTimePickerValue(view View, subviewID string) time.Time {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTimePickerValue(view View, subviewID ...string) time.Time {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view == nil {
|
||||
return time.Now()
|
||||
|
@ -456,17 +398,7 @@ func GetTimePickerValue(view View, subviewID string) time.Time {
|
|||
|
||||
// GetTimeChangedListeners returns the TimeChangedListener list of an TimePicker subview.
|
||||
// If there are no listeners then the empty list is returned
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTimeChangedListeners(view View, subviewID string) []func(TimePicker, time.Time) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(TimeChangedEvent); value != nil {
|
||||
if listeners, ok := value.([]func(TimePicker, time.Time)); ok {
|
||||
return listeners
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(TimePicker, time.Time){}
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTimeChangedListeners(view View, subviewID ...string) []func(TimePicker, time.Time) {
|
||||
return getEventListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent)
|
||||
}
|
||||
|
|
169
touchEvents.go
169
touchEvents.go
|
@ -90,131 +90,6 @@ type TouchEvent struct {
|
|||
MetaKey bool
|
||||
}
|
||||
|
||||
func valueToTouchListeners(value interface{}) ([]func(View, TouchEvent), bool) {
|
||||
if value == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case func(View, TouchEvent):
|
||||
return []func(View, TouchEvent){value}, true
|
||||
|
||||
case func(TouchEvent):
|
||||
fn := func(_ View, event TouchEvent) {
|
||||
value(event)
|
||||
}
|
||||
return []func(View, TouchEvent){fn}, true
|
||||
|
||||
case func(View):
|
||||
fn := func(view View, _ TouchEvent) {
|
||||
value(view)
|
||||
}
|
||||
return []func(View, TouchEvent){fn}, true
|
||||
|
||||
case func():
|
||||
fn := func(View, TouchEvent) {
|
||||
value()
|
||||
}
|
||||
return []func(View, TouchEvent){fn}, true
|
||||
|
||||
case []func(View, TouchEvent):
|
||||
if len(value) == 0 {
|
||||
return nil, true
|
||||
}
|
||||
for _, fn := range value {
|
||||
if fn == nil {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return value, true
|
||||
|
||||
case []func(TouchEvent):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, TouchEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(_ View, event TouchEvent) {
|
||||
v(event)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func(View):
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, TouchEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(view View, _ TouchEvent) {
|
||||
v(view)
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []func():
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, TouchEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
listeners[i] = func(View, TouchEvent) {
|
||||
v()
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
|
||||
case []interface{}:
|
||||
count := len(value)
|
||||
if count == 0 {
|
||||
return nil, true
|
||||
}
|
||||
listeners := make([]func(View, TouchEvent), count)
|
||||
for i, v := range value {
|
||||
if v == nil {
|
||||
return nil, false
|
||||
}
|
||||
switch v := v.(type) {
|
||||
case func(View, TouchEvent):
|
||||
listeners[i] = v
|
||||
|
||||
case func(TouchEvent):
|
||||
listeners[i] = func(_ View, event TouchEvent) {
|
||||
v(event)
|
||||
}
|
||||
|
||||
case func(View):
|
||||
listeners[i] = func(view View, _ TouchEvent) {
|
||||
v(view)
|
||||
}
|
||||
|
||||
case func():
|
||||
listeners[i] = func(View, TouchEvent) {
|
||||
v()
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return listeners, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var touchEvents = map[string]struct{ jsEvent, jsFunc string }{
|
||||
TouchStart: {jsEvent: "ontouchstart", jsFunc: "touchStartEvent"},
|
||||
TouchEnd: {jsEvent: "ontouchend", jsFunc: "touchEndEvent"},
|
||||
|
@ -222,8 +97,8 @@ var touchEvents = map[string]struct{ jsEvent, jsFunc string }{
|
|||
TouchCancel: {jsEvent: "ontouchcancel", jsFunc: "touchCancelEvent"},
|
||||
}
|
||||
|
||||
func (view *viewData) setTouchListener(tag string, value interface{}) bool {
|
||||
listeners, ok := valueToTouchListeners(value)
|
||||
func (view *viewData) setTouchListener(tag string, value any) bool {
|
||||
listeners, ok := valueToEventListeners[View, TouchEvent](value)
|
||||
if !ok {
|
||||
notCompatibleType(tag, value)
|
||||
return false
|
||||
|
@ -251,20 +126,6 @@ func (view *viewData) removeTouchListener(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func getTouchListeners(view View, subviewID string, tag string) []func(View, TouchEvent) {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
}
|
||||
if view != nil {
|
||||
if value := view.Get(tag); value != nil {
|
||||
if result, ok := value.([]func(View, TouchEvent)); ok {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return []func(View, TouchEvent){}
|
||||
}
|
||||
|
||||
func touchEventsHtml(view View, buffer *strings.Builder) {
|
||||
for tag, js := range touchEvents {
|
||||
if value := view.getRaw(tag); value != nil {
|
||||
|
@ -309,7 +170,7 @@ func (event *TouchEvent) init(data DataObject) {
|
|||
}
|
||||
|
||||
func handleTouchEvents(view View, tag string, data DataObject) {
|
||||
listeners := getTouchListeners(view, "", tag)
|
||||
listeners := getEventListeners[View, TouchEvent](view, nil, tag)
|
||||
if len(listeners) == 0 {
|
||||
return
|
||||
}
|
||||
|
@ -323,25 +184,25 @@ func handleTouchEvents(view View, tag string, data DataObject) {
|
|||
}
|
||||
|
||||
// GetTouchStartListeners returns the "touch-start" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTouchStartListeners(view View, subviewID string) []func(View, TouchEvent) {
|
||||
return getTouchListeners(view, subviewID, TouchStart)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTouchStartListeners(view View, subviewID ...string) []func(View, TouchEvent) {
|
||||
return getEventListeners[View, TouchEvent](view, subviewID, TouchStart)
|
||||
}
|
||||
|
||||
// GetTouchEndListeners returns the "touch-end" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTouchEndListeners(view View, subviewID string) []func(View, TouchEvent) {
|
||||
return getTouchListeners(view, subviewID, TouchEnd)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTouchEndListeners(view View, subviewID ...string) []func(View, TouchEvent) {
|
||||
return getEventListeners[View, TouchEvent](view, subviewID, TouchEnd)
|
||||
}
|
||||
|
||||
// GetTouchMoveListeners returns the "touch-move" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTouchMoveListeners(view View, subviewID string) []func(View, TouchEvent) {
|
||||
return getTouchListeners(view, subviewID, TouchMove)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTouchMoveListeners(view View, subviewID ...string) []func(View, TouchEvent) {
|
||||
return getEventListeners[View, TouchEvent](view, subviewID, TouchMove)
|
||||
}
|
||||
|
||||
// GetTouchCancelListeners returns the "touch-cancel" listener list. If there are no listeners then the empty list is returned.
|
||||
// If the second argument (subviewID) is "" then a value from the first argument (view) is returned.
|
||||
func GetTouchCancelListeners(view View, subviewID string) []func(View, TouchEvent) {
|
||||
return getTouchListeners(view, subviewID, TouchCancel)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
||||
func GetTouchCancelListeners(view View, subviewID ...string) []func(View, TouchEvent) {
|
||||
return getEventListeners[View, TouchEvent](view, subviewID, TouchCancel)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package rui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -30,7 +29,7 @@ type videoPlayerData struct {
|
|||
// NewVideoPlayer create new MediaPlayer object and return it
|
||||
func NewVideoPlayer(session Session, params Params) VideoPlayer {
|
||||
view := new(videoPlayerData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
view.tag = "VideoPlayer"
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
|
@ -40,8 +39,8 @@ func newVideoPlayer(session Session) View {
|
|||
return NewVideoPlayer(session, nil)
|
||||
}
|
||||
|
||||
func (player *videoPlayerData) Init(session Session) {
|
||||
player.mediaPlayerData.Init(session)
|
||||
func (player *videoPlayerData) init(session Session) {
|
||||
player.mediaPlayerData.init(session)
|
||||
player.tag = "VideoPlayer"
|
||||
}
|
||||
|
||||
|
@ -77,11 +76,11 @@ func (player *videoPlayerData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (player *videoPlayerData) Set(tag string, value interface{}) bool {
|
||||
func (player *videoPlayerData) Set(tag string, value any) bool {
|
||||
return player.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (player *videoPlayerData) set(tag string, value interface{}) bool {
|
||||
func (player *videoPlayerData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
player.remove(tag)
|
||||
return true
|
||||
|
@ -90,9 +89,9 @@ func (player *videoPlayerData) set(tag string, value interface{}) bool {
|
|||
if player.mediaPlayerData.set(tag, value) {
|
||||
session := player.Session()
|
||||
updateSize := func(cssTag string) {
|
||||
if size, ok := floatProperty(player, tag, session, 0); ok {
|
||||
if size > 0 {
|
||||
updateProperty(player.htmlID(), cssTag, fmt.Sprintf("%g", size), session)
|
||||
if size, ok := floatTextProperty(player, tag, session, 0); ok {
|
||||
if size != "0" {
|
||||
updateProperty(player.htmlID(), cssTag, size, session)
|
||||
} else {
|
||||
removeProperty(player.htmlID(), cssTag, session)
|
||||
}
|
||||
|
@ -122,12 +121,16 @@ func (player *videoPlayerData) htmlProperties(self View, buffer *strings.Builder
|
|||
|
||||
session := player.Session()
|
||||
|
||||
if size, ok := floatProperty(player, VideoWidth, session, 0); ok && size > 0 {
|
||||
buffer.WriteString(fmt.Sprintf(` width="%g"`, size))
|
||||
if size, ok := floatTextProperty(player, VideoWidth, session, 0); ok && size != "0" {
|
||||
buffer.WriteString(` width="`)
|
||||
buffer.WriteString(size)
|
||||
buffer.WriteString(`"`)
|
||||
}
|
||||
|
||||
if size, ok := floatProperty(player, VideoHeight, session, 0); ok && size > 0 {
|
||||
buffer.WriteString(fmt.Sprintf(` height="%g"`, size))
|
||||
if size, ok := floatTextProperty(player, VideoHeight, session, 0); ok && size != "0" {
|
||||
buffer.WriteString(` height="`)
|
||||
buffer.WriteString(size)
|
||||
buffer.WriteString(`"`)
|
||||
}
|
||||
|
||||
if url, ok := stringProperty(player, Poster, session); ok && url != "" {
|
||||
|
|
71
view.go
71
view.go
|
@ -33,14 +33,10 @@ type View interface {
|
|||
ViewStyle
|
||||
fmt.Stringer
|
||||
|
||||
// Init initializes fields of View by default values
|
||||
Init(session Session)
|
||||
// Session returns the current Session interface
|
||||
Session() Session
|
||||
// Parent returns the parent view
|
||||
Parent() View
|
||||
parentHTMLID() string
|
||||
setParentID(parentID string)
|
||||
// Tag returns the tag of View interface
|
||||
Tag() string
|
||||
// ID returns the id of the view
|
||||
|
@ -54,7 +50,7 @@ type View interface {
|
|||
// 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
|
||||
// a description of the error is written to the log
|
||||
SetAnimated(tag string, value interface{}, animation Animation) bool
|
||||
SetAnimated(tag string, value any, animation Animation) bool
|
||||
// SetChangeListener set the function to track the change of the View property
|
||||
SetChangeListener(tag string, listener func(View, string))
|
||||
// HasFocus returns 'true' if the view has focus
|
||||
|
@ -65,14 +61,14 @@ type View interface {
|
|||
htmlTag() string
|
||||
closeHTMLTag() bool
|
||||
htmlID() string
|
||||
parentHTMLID() string
|
||||
setParentID(parentID string)
|
||||
htmlSubviews(self View, buffer *strings.Builder)
|
||||
htmlProperties(self View, buffer *strings.Builder)
|
||||
htmlDisabledProperties(self View, buffer *strings.Builder)
|
||||
cssStyle(self View, builder cssBuilder)
|
||||
addToCSSStyle(addCSS map[string]string)
|
||||
|
||||
getTransitions() Params
|
||||
|
||||
onResize(self View, x, y, width, height float64)
|
||||
onItemResize(self View, index string, x, y, width, height float64)
|
||||
setNoResizeEvent()
|
||||
|
@ -102,7 +98,7 @@ type viewData struct {
|
|||
|
||||
func newView(session Session) View {
|
||||
view := new(viewData)
|
||||
view.Init(session)
|
||||
view.init(session)
|
||||
return view
|
||||
}
|
||||
|
||||
|
@ -124,12 +120,12 @@ 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)
|
||||
view.init(session)
|
||||
setInitParams(view, params)
|
||||
return view
|
||||
}
|
||||
|
||||
func (view *viewData) Init(session Session) {
|
||||
func (view *viewData) init(session Session) {
|
||||
view.viewStyle.init()
|
||||
view.tag = "View"
|
||||
view.session = session
|
||||
|
@ -197,7 +193,7 @@ func (view *viewData) remove(tag string) {
|
|||
case Style, StyleDisabled:
|
||||
if _, ok := view.properties[tag]; ok {
|
||||
delete(view.properties, tag)
|
||||
updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view, "")), view.session)
|
||||
updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)), view.session)
|
||||
}
|
||||
|
||||
case FocusEvent, LostFocusEvent:
|
||||
|
@ -290,11 +286,11 @@ func (view *viewData) propertyChangedEvent(tag string) {
|
|||
|
||||
}
|
||||
|
||||
func (view *viewData) Set(tag string, value interface{}) bool {
|
||||
func (view *viewData) Set(tag string, value any) bool {
|
||||
return view.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (view *viewData) set(tag string, value interface{}) bool {
|
||||
func (view *viewData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
view.remove(tag)
|
||||
return true
|
||||
|
@ -327,7 +323,7 @@ func (view *viewData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
view.properties[tag] = text
|
||||
if view.created {
|
||||
updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view, "")), view.session)
|
||||
updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)), view.session)
|
||||
}
|
||||
|
||||
case FocusEvent, LostFocusEvent:
|
||||
|
@ -381,7 +377,7 @@ func viewPropertyChanged(view *viewData, tag string) {
|
|||
return
|
||||
|
||||
case Visibility:
|
||||
switch GetVisibility(view, "") {
|
||||
switch GetVisibility(view) {
|
||||
case Invisible:
|
||||
updateCSSProperty(htmlID, Visibility, "hidden", session)
|
||||
updateCSSProperty(htmlID, "display", "", session)
|
||||
|
@ -450,7 +446,7 @@ func viewPropertyChanged(view *viewData, tag string) {
|
|||
return
|
||||
|
||||
case Outline, OutlineColor, OutlineStyle, OutlineWidth:
|
||||
updateCSSProperty(htmlID, Outline, GetOutline(view, "").cssString(), session)
|
||||
updateCSSProperty(htmlID, Outline, GetOutline(view).cssString(session), session)
|
||||
return
|
||||
|
||||
case Shadow:
|
||||
|
@ -465,20 +461,20 @@ func viewPropertyChanged(view *viewData, tag string) {
|
|||
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
|
||||
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
|
||||
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
|
||||
radius := GetRadius(view, "")
|
||||
updateCSSProperty(htmlID, "border-radius", radius.cssString(), session)
|
||||
radius := GetRadius(view)
|
||||
updateCSSProperty(htmlID, "border-radius", radius.cssString(session), session)
|
||||
return
|
||||
|
||||
case Margin, MarginTop, MarginRight, MarginBottom, MarginLeft,
|
||||
"top-margin", "right-margin", "bottom-margin", "left-margin":
|
||||
margin := GetMargin(view, "")
|
||||
updateCSSProperty(htmlID, Margin, margin.cssString(), session)
|
||||
margin := GetMargin(view)
|
||||
updateCSSProperty(htmlID, Margin, margin.cssString(session), session)
|
||||
return
|
||||
|
||||
case Padding, PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
|
||||
"top-padding", "right-padding", "bottom-padding", "left-padding":
|
||||
padding := GetPadding(view, "")
|
||||
updateCSSProperty(htmlID, Padding, padding.cssString(), session)
|
||||
padding := GetPadding(view)
|
||||
updateCSSProperty(htmlID, Padding, padding.cssString(session), session)
|
||||
return
|
||||
|
||||
case AvoidBreak:
|
||||
|
@ -593,9 +589,9 @@ func viewPropertyChanged(view *viewData, tag string) {
|
|||
}
|
||||
return
|
||||
|
||||
case ZIndex:
|
||||
if i, ok := intProperty(view, ZIndex, session, 0); ok {
|
||||
updateCSSProperty(htmlID, ZIndex, strconv.Itoa(i), session)
|
||||
case ZIndex, TabSize:
|
||||
if i, ok := intProperty(view, tag, session, 0); ok {
|
||||
updateCSSProperty(htmlID, tag, strconv.Itoa(i), session)
|
||||
}
|
||||
return
|
||||
|
||||
|
@ -630,7 +626,7 @@ func viewPropertyChanged(view *viewData, tag string) {
|
|||
|
||||
if cssTag, ok := sizeProperties[tag]; ok {
|
||||
size, _ := sizeProperty(view, tag, session)
|
||||
updateCSSProperty(htmlID, cssTag, size.cssString(""), session)
|
||||
updateCSSProperty(htmlID, cssTag, size.cssString("", session), session)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -639,6 +635,7 @@ func viewPropertyChanged(view *viewData, tag string) {
|
|||
TextColor: "color",
|
||||
TextLineColor: "text-decoration-color",
|
||||
CaretColor: CaretColor,
|
||||
AccentColor: AccentColor,
|
||||
}
|
||||
if cssTag, ok := colorTags[tag]; ok {
|
||||
if color, ok := colorProperty(view, tag, session); ok {
|
||||
|
@ -657,19 +654,19 @@ func viewPropertyChanged(view *viewData, tag string) {
|
|||
|
||||
for _, floatTag := range []string{Opacity, ScaleX, ScaleY, ScaleZ, RotateX, RotateY, RotateZ} {
|
||||
if tag == floatTag {
|
||||
if f, ok := floatProperty(view, floatTag, session, 0); ok {
|
||||
updateCSSProperty(htmlID, floatTag, strconv.FormatFloat(f, 'g', -1, 64), session)
|
||||
if f, ok := floatTextProperty(view, floatTag, session, 0); ok {
|
||||
updateCSSProperty(htmlID, floatTag, f, session)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (view *viewData) Get(tag string) interface{} {
|
||||
func (view *viewData) Get(tag string) any {
|
||||
return view.get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (view *viewData) get(tag string) interface{} {
|
||||
func (view *viewData) get(tag string) any {
|
||||
if tag == ID {
|
||||
if view.viewID != "" {
|
||||
return view.viewID
|
||||
|
@ -681,7 +678,7 @@ func (view *viewData) get(tag string) interface{} {
|
|||
}
|
||||
|
||||
func (view *viewData) htmlTag() string {
|
||||
if semantics := GetSemantics(view, ""); semantics > DefaultSemantics {
|
||||
if semantics := GetSemantics(view); semantics > DefaultSemantics {
|
||||
values := enumProperties[Semantics].cssValues
|
||||
if semantics < len(values) {
|
||||
return values[semantics]
|
||||
|
@ -710,7 +707,7 @@ func (view *viewData) addToCSSStyle(addCSS map[string]string) {
|
|||
|
||||
func (view *viewData) cssStyle(self View, builder cssBuilder) {
|
||||
view.viewStyle.cssViewStyle(builder, view.session)
|
||||
switch GetVisibility(view, "") {
|
||||
switch GetVisibility(view) {
|
||||
case Invisible:
|
||||
builder.add(`visibility`, `hidden`)
|
||||
|
||||
|
@ -734,7 +731,7 @@ func (view *viewData) htmlProperties(self View, buffer *strings.Builder) {
|
|||
}
|
||||
|
||||
func (view *viewData) htmlDisabledProperties(self View, buffer *strings.Builder) {
|
||||
if IsDisabled(self, "") {
|
||||
if IsDisabled(self) {
|
||||
buffer.WriteString(` data-disabled="1"`)
|
||||
} else {
|
||||
buffer.WriteString(` data-disabled="0"`)
|
||||
|
@ -749,7 +746,7 @@ func viewHTML(view View, buffer *strings.Builder) {
|
|||
buffer.WriteString(view.htmlID())
|
||||
buffer.WriteRune('"')
|
||||
|
||||
disabled := IsDisabled(view, "")
|
||||
disabled := IsDisabled(view)
|
||||
|
||||
if cls := view.htmlClass(disabled); cls != "" {
|
||||
buffer.WriteString(` class="`)
|
||||
|
@ -826,7 +823,7 @@ func (view *viewData) handleCommand(self View, command string, data DataObject)
|
|||
switch command {
|
||||
|
||||
case KeyDownEvent, KeyUpEvent:
|
||||
if !IsDisabled(self, "") {
|
||||
if !IsDisabled(self) {
|
||||
handleKeyEvents(self, command, data)
|
||||
}
|
||||
|
||||
|
@ -841,13 +838,13 @@ func (view *viewData) handleCommand(self View, command string, data DataObject)
|
|||
|
||||
case FocusEvent:
|
||||
view.hasFocus = true
|
||||
for _, listener := range getFocusListeners(view, "", command) {
|
||||
for _, listener := range getFocusListeners(view, nil, command) {
|
||||
listener(self)
|
||||
}
|
||||
|
||||
case LostFocusEvent:
|
||||
view.hasFocus = false
|
||||
for _, listener := range getFocusListeners(view, "", command) {
|
||||
for _, listener := range getFocusListeners(view, nil, command) {
|
||||
listener(self)
|
||||
}
|
||||
|
||||
|
|
76
viewClip.go
76
viewClip.go
|
@ -27,7 +27,7 @@ type circleClip struct {
|
|||
}
|
||||
|
||||
type polygonClip struct {
|
||||
points []interface{}
|
||||
points []any
|
||||
}
|
||||
|
||||
// InsetClip creates a rectangle View clipping area.
|
||||
|
@ -73,9 +73,9 @@ func EllipseClip(x, y, rx, ry SizeUnit) ClipShape {
|
|||
// PolygonClip creates a polygon View clipping area.
|
||||
// The elements of the function argument can be or text constants,
|
||||
// or the text representation of SizeUnit, or elements of SizeUnit type.
|
||||
func PolygonClip(points []interface{}) ClipShape {
|
||||
func PolygonClip(points []any) ClipShape {
|
||||
clip := new(polygonClip)
|
||||
clip.points = []interface{}{}
|
||||
clip.points = []any{}
|
||||
if clip.Set(Points, points) {
|
||||
return clip
|
||||
}
|
||||
|
@ -85,14 +85,14 @@ func PolygonClip(points []interface{}) ClipShape {
|
|||
// PolygonPointsClip creates a polygon View clipping area.
|
||||
func PolygonPointsClip(points []SizeUnit) ClipShape {
|
||||
clip := new(polygonClip)
|
||||
clip.points = []interface{}{}
|
||||
clip.points = []any{}
|
||||
if clip.Set(Points, points) {
|
||||
return clip
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (clip *insetClip) Set(tag string, value interface{}) bool {
|
||||
func (clip *insetClip) Set(tag string, value any) bool {
|
||||
switch strings.ToLower(tag) {
|
||||
case Top, Right, Bottom, Left:
|
||||
if value == nil {
|
||||
|
@ -146,13 +146,13 @@ func (clip *insetClip) cssStyle(session Session) string {
|
|||
for _, tag := range []string{Top, Right, Bottom, Left} {
|
||||
value, _ := sizeProperty(clip, tag, session)
|
||||
buffer.WriteString(leadText)
|
||||
buffer.WriteString(value.cssString("0px"))
|
||||
buffer.WriteString(value.cssString("0px", session))
|
||||
leadText = " "
|
||||
}
|
||||
|
||||
if radius := getRadiusProperty(clip); radius != nil {
|
||||
buffer.WriteString(" round ")
|
||||
buffer.WriteString(radius.BoxRadius(session).cssString())
|
||||
buffer.WriteString(radius.BoxRadius(session).cssString(session))
|
||||
}
|
||||
|
||||
buffer.WriteRune(')')
|
||||
|
@ -168,7 +168,7 @@ func (clip *insetClip) valid(session Session) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (clip *circleClip) Set(tag string, value interface{}) bool {
|
||||
func (clip *circleClip) Set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
clip.Remove(tag)
|
||||
}
|
||||
|
@ -211,15 +211,15 @@ func (clip *circleClip) cssStyle(session Session) string {
|
|||
|
||||
buffer.WriteString("circle(")
|
||||
r, _ := sizeProperty(clip, Radius, session)
|
||||
buffer.WriteString(r.cssString("50%"))
|
||||
buffer.WriteString(r.cssString("50%", session))
|
||||
|
||||
buffer.WriteString(" at ")
|
||||
x, _ := sizeProperty(clip, X, session)
|
||||
buffer.WriteString(x.cssString("50%"))
|
||||
buffer.WriteString(x.cssString("50%", session))
|
||||
buffer.WriteRune(' ')
|
||||
|
||||
y, _ := sizeProperty(clip, Y, session)
|
||||
buffer.WriteString(y.cssString("50%"))
|
||||
buffer.WriteString(y.cssString("50%", session))
|
||||
buffer.WriteRune(')')
|
||||
|
||||
return buffer.String()
|
||||
|
@ -232,7 +232,7 @@ func (clip *circleClip) valid(session Session) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (clip *ellipseClip) Set(tag string, value interface{}) bool {
|
||||
func (clip *ellipseClip) Set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
clip.Remove(tag)
|
||||
}
|
||||
|
@ -280,17 +280,17 @@ func (clip *ellipseClip) cssStyle(session Session) string {
|
|||
rx, _ := sizeProperty(clip, RadiusX, session)
|
||||
ry, _ := sizeProperty(clip, RadiusX, session)
|
||||
buffer.WriteString("ellipse(")
|
||||
buffer.WriteString(rx.cssString("50%"))
|
||||
buffer.WriteString(rx.cssString("50%", session))
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(ry.cssString("50%"))
|
||||
buffer.WriteString(ry.cssString("50%", session))
|
||||
|
||||
buffer.WriteString(" at ")
|
||||
x, _ := sizeProperty(clip, X, session)
|
||||
buffer.WriteString(x.cssString("50%"))
|
||||
buffer.WriteString(x.cssString("50%", session))
|
||||
buffer.WriteRune(' ')
|
||||
|
||||
y, _ := sizeProperty(clip, Y, session)
|
||||
buffer.WriteString(y.cssString("50%"))
|
||||
buffer.WriteString(y.cssString("50%", session))
|
||||
buffer.WriteRune(')')
|
||||
|
||||
return buffer.String()
|
||||
|
@ -302,23 +302,23 @@ func (clip *ellipseClip) valid(session Session) bool {
|
|||
return rx.Value != 0 && ry.Value != 0
|
||||
}
|
||||
|
||||
func (clip *polygonClip) Get(tag string) interface{} {
|
||||
func (clip *polygonClip) Get(tag string) any {
|
||||
if Points == strings.ToLower(tag) {
|
||||
return clip.points
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (clip *polygonClip) getRaw(tag string) interface{} {
|
||||
func (clip *polygonClip) getRaw(tag string) any {
|
||||
return clip.Get(tag)
|
||||
}
|
||||
|
||||
func (clip *polygonClip) Set(tag string, value interface{}) bool {
|
||||
func (clip *polygonClip) Set(tag string, value any) bool {
|
||||
if Points == strings.ToLower(tag) {
|
||||
switch value := value.(type) {
|
||||
case []interface{}:
|
||||
case []any:
|
||||
result := true
|
||||
clip.points = make([]interface{}, len(value))
|
||||
clip.points = make([]any, len(value))
|
||||
for i, val := range value {
|
||||
switch val := val.(type) {
|
||||
case string:
|
||||
|
@ -343,7 +343,7 @@ func (clip *polygonClip) Set(tag string, value interface{}) bool {
|
|||
return result
|
||||
|
||||
case []SizeUnit:
|
||||
clip.points = make([]interface{}, len(value))
|
||||
clip.points = make([]any, len(value))
|
||||
for i, point := range value {
|
||||
clip.points[i] = point
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ func (clip *polygonClip) Set(tag string, value interface{}) bool {
|
|||
case string:
|
||||
result := true
|
||||
values := strings.Split(value, ",")
|
||||
clip.points = make([]interface{}, len(values))
|
||||
clip.points = make([]any, len(values))
|
||||
for i, val := range values {
|
||||
val = strings.Trim(val, " \t\n\r")
|
||||
if isConstantName(val) {
|
||||
|
@ -370,18 +370,18 @@ func (clip *polygonClip) Set(tag string, value interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (clip *polygonClip) setRaw(tag string, value interface{}) {
|
||||
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 = []interface{}{}
|
||||
clip.points = []any{}
|
||||
}
|
||||
}
|
||||
|
||||
func (clip *polygonClip) Clear() {
|
||||
clip.points = []interface{}{}
|
||||
clip.points = []any{}
|
||||
}
|
||||
|
||||
func (clip *polygonClip) AllTags() []string {
|
||||
|
@ -422,18 +422,18 @@ func (clip *polygonClip) cssStyle(session Session) string {
|
|||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
writePoint := func(value interface{}) {
|
||||
writePoint := func(value any) {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if val, ok := session.resolveConstants(value); ok {
|
||||
if size, ok := StringToSizeUnit(val); ok {
|
||||
buffer.WriteString(size.cssString("0px"))
|
||||
buffer.WriteString(size.cssString("0px", session))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case SizeUnit:
|
||||
buffer.WriteString(value.cssString("0px"))
|
||||
buffer.WriteString(value.cssString("0px", session))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -501,7 +501,7 @@ func parseClipShape(obj DataObject) ClipShape {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (style *viewStyle) setClipShape(tag string, value interface{}) bool {
|
||||
func (style *viewStyle) setClipShape(tag string, value any) bool {
|
||||
switch value := value.(type) {
|
||||
case ClipShape:
|
||||
style.properties[tag] = value
|
||||
|
@ -558,10 +558,10 @@ func getClipShape(prop Properties, tag string, session Session) ClipShape {
|
|||
}
|
||||
|
||||
// GetClip returns a View clipping area.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetClip(view View, subviewID string) ClipShape {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetClip(view View, subviewID ...string) ClipShape {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
return getClipShape(view, Clip, view.Session())
|
||||
|
@ -571,10 +571,10 @@ func GetClip(view View, subviewID string) ClipShape {
|
|||
}
|
||||
|
||||
// GetShapeOutside returns a shape around which adjacent inline content.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetShapeOutside(view View, subviewID string) ClipShape {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetShapeOutside(view View, subviewID ...string) ClipShape {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
if view != nil {
|
||||
return getClipShape(view, ShapeOutside, view.Session())
|
||||
|
|
|
@ -130,7 +130,7 @@ func newViewFilter(obj DataObject) ViewFilter {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (filter *viewFilter) Set(tag string, value interface{}) bool {
|
||||
func (filter *viewFilter) Set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
filter.Remove(tag)
|
||||
return true
|
||||
|
@ -180,20 +180,22 @@ func (filter *viewFilter) cssStyle(session Session) string {
|
|||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
if value, ok := floatProperty(filter, Blur, session, 0); ok {
|
||||
size := SizeUnit{Type: SizeInPixel, Value: value}
|
||||
if value, ok := floatTextProperty(filter, Blur, session, 0); ok {
|
||||
buffer.WriteString(Blur)
|
||||
buffer.WriteRune('(')
|
||||
buffer.WriteString(size.cssString("0px"))
|
||||
buffer.WriteRune(')')
|
||||
buffer.WriteString(value)
|
||||
buffer.WriteString("px)")
|
||||
}
|
||||
|
||||
for _, tag := range []string{Brightness, Contrast, Saturate, Grayscale, Invert, Opacity, Sepia} {
|
||||
if value, ok := floatProperty(filter, tag, session, 0); ok {
|
||||
if value, ok := floatTextProperty(filter, tag, session, 0); ok {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteRune(' ')
|
||||
}
|
||||
buffer.WriteString(fmt.Sprintf("%s(%g%%)", tag, value))
|
||||
buffer.WriteString(tag)
|
||||
buffer.WriteRune('(')
|
||||
buffer.WriteString(value)
|
||||
buffer.WriteString("%)")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,7 +226,7 @@ func (filter *viewFilter) cssStyle(session Session) string {
|
|||
return buffer.String()
|
||||
}
|
||||
|
||||
func (style *viewStyle) setFilter(tag string, value interface{}) bool {
|
||||
func (style *viewStyle) setFilter(tag string, value any) bool {
|
||||
switch value := value.(type) {
|
||||
case ViewFilter:
|
||||
style.properties[tag] = value
|
||||
|
@ -257,34 +259,46 @@ func (style *viewStyle) setFilter(tag string, value interface{}) bool {
|
|||
}
|
||||
|
||||
// GetFilter returns a View graphical effects like blur or color shift.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetFilter(view View, subviewID string) ViewFilter {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetFilter(view View, subviewID ...string) ViewFilter {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
if value := view.getRaw(Filter); value != nil {
|
||||
if filter, ok := value.(ViewFilter); ok {
|
||||
return filter
|
||||
}
|
||||
}
|
||||
if value := valueFromStyle(view, Filter); value != nil {
|
||||
if filter, ok := value.(ViewFilter); ok {
|
||||
return filter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBackdropFilter returns the area behind a View graphical effects like blur or color shift.
|
||||
// If the second argument (subviewID) is "" then a top position of the first argument (view) is returned
|
||||
func GetBackdropFilter(view View, subviewID string) ViewFilter {
|
||||
if subviewID != "" {
|
||||
view = ViewByID(view, subviewID)
|
||||
// If the second argument (subviewID) is not specified or it is "" then a top position of the first argument (view) is returned
|
||||
func GetBackdropFilter(view View, subviewID ...string) ViewFilter {
|
||||
if len(subviewID) > 0 && subviewID[0] != "" {
|
||||
view = ViewByID(view, subviewID[0])
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
if value := view.getRaw(BackdropFilter); value != nil {
|
||||
if filter, ok := value.(ViewFilter); ok {
|
||||
return filter
|
||||
}
|
||||
}
|
||||
if value := valueFromStyle(view, BackdropFilter); value != nil {
|
||||
if filter, ok := value.(ViewFilter); ok {
|
||||
return filter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
60
viewStyle.go
60
viewStyle.go
|
@ -10,6 +10,16 @@ import (
|
|||
// ViewStyle interface of the style of view
|
||||
type ViewStyle interface {
|
||||
Properties
|
||||
|
||||
// Transition returns the transition animation of the property. Returns nil is there is no transition animation.
|
||||
Transition(tag string) Animation
|
||||
// Transitions returns the map of transition animations. The result is always non-nil.
|
||||
Transitions() map[string]Animation
|
||||
// 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.
|
||||
// The "tag" argument is the property name.
|
||||
SetTransition(tag string, animation Animation)
|
||||
|
||||
cssViewStyle(buffer cssBuilder, session Session)
|
||||
}
|
||||
|
||||
|
@ -163,11 +173,11 @@ func (style *viewStyle) backgroundCSS(session Session) string {
|
|||
func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
||||
|
||||
if margin, ok := boundsProperty(style, Margin, session); ok {
|
||||
margin.cssValue(Margin, builder)
|
||||
margin.cssValue(Margin, builder, session)
|
||||
}
|
||||
|
||||
if padding, ok := boundsProperty(style, Padding, session); ok {
|
||||
padding.cssValue(Padding, builder)
|
||||
padding.cssValue(Padding, builder, session)
|
||||
}
|
||||
|
||||
if border := getBorder(style, Border); border != nil {
|
||||
|
@ -177,10 +187,10 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
|||
}
|
||||
|
||||
radius := getRadius(style, session)
|
||||
radius.cssValue(builder)
|
||||
radius.cssValue(builder, session)
|
||||
|
||||
if outline := getOutline(style); outline != nil {
|
||||
outline.ViewOutline(session).cssValue(builder)
|
||||
outline.ViewOutline(session).cssValue(builder, session)
|
||||
}
|
||||
|
||||
if z, ok := intProperty(style, ZIndex, session, 0); ok {
|
||||
|
@ -198,14 +208,14 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
|||
for _, tag := range []string{
|
||||
Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight, Left, Right, Top, Bottom,
|
||||
TextSize, TextIndent, LetterSpacing, WordSpacing, LineHeight, TextLineThickness,
|
||||
GridRowGap, GridColumnGap, ColumnGap, ColumnWidth} {
|
||||
ListRowGap, ListColumnGap, GridRowGap, GridColumnGap, ColumnGap, ColumnWidth} {
|
||||
|
||||
if size, ok := sizeProperty(style, tag, session); ok && size.Type != Auto {
|
||||
cssTag, ok := sizeProperties[tag]
|
||||
if !ok {
|
||||
cssTag = tag
|
||||
}
|
||||
builder.add(cssTag, size.cssString(""))
|
||||
builder.add(cssTag, size.cssString("", session))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,6 +224,7 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
|||
{TextColor, "color"},
|
||||
{TextLineColor, "text-decoration-color"},
|
||||
{CaretColor, CaretColor},
|
||||
{AccentColor, AccentColor},
|
||||
}
|
||||
for _, p := range colorProperties {
|
||||
if color, ok := colorProperty(style, p.property, session); ok && color != 0 {
|
||||
|
@ -235,7 +246,7 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
|||
|
||||
writingMode := 0
|
||||
for _, tag := range []string{
|
||||
TextAlign, TextTransform, TextWeight, TextLineStyle, WritingMode, TextDirection,
|
||||
Overflow, TextAlign, TextTransform, TextWeight, TextLineStyle, WritingMode, TextDirection,
|
||||
VerticalTextOrientation, CellVerticalAlign, CellHorizontalAlign, GridAutoFlow, Cursor,
|
||||
WhiteSpace, WordBreak, TextOverflow, Float, TableVerticalAlign, Resize} {
|
||||
|
||||
|
@ -268,6 +279,10 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
|||
}
|
||||
}
|
||||
|
||||
if tabSize, ok := intProperty(style, TabSize, session, 8); ok && tabSize > 0 {
|
||||
builder.add(TabSize, strconv.Itoa(tabSize))
|
||||
}
|
||||
|
||||
if text := style.cssTextDecoration(session); text != "" {
|
||||
builder.add("text-decoration", text)
|
||||
}
|
||||
|
@ -384,12 +399,10 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
|||
}
|
||||
|
||||
if r, ok := rangeProperty(style, Row, session); ok {
|
||||
builder.add("grid-row-start", strconv.Itoa(r.First+1))
|
||||
builder.add("grid-row-end", strconv.Itoa(r.Last+2))
|
||||
builder.add("grid-row", fmt.Sprintf("%d / %d", r.First+1, r.Last+2))
|
||||
}
|
||||
if r, ok := rangeProperty(style, Column, session); ok {
|
||||
builder.add("grid-column-start", strconv.Itoa(r.First+1))
|
||||
builder.add("grid-column-end", strconv.Itoa(r.Last+2))
|
||||
builder.add("grid-column", fmt.Sprintf("%d / %d", r.First+1, r.Last+2))
|
||||
}
|
||||
if text := style.gridCellSizesCSS(CellWidth, session); text != "" {
|
||||
builder.add(`grid-template-columns`, text)
|
||||
|
@ -442,7 +455,7 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
|
|||
}
|
||||
}
|
||||
|
||||
func valueToOrientation(value interface{}, session Session) (int, bool) {
|
||||
func valueToOrientation(value any, session Session) (int, bool) {
|
||||
if value != nil {
|
||||
switch value := value.(type) {
|
||||
case int:
|
||||
|
@ -471,11 +484,11 @@ func valueToOrientation(value interface{}, session Session) (int, bool) {
|
|||
return 0, false
|
||||
}
|
||||
|
||||
func (style *viewStyle) Get(tag string) interface{} {
|
||||
func (style *viewStyle) Get(tag string) any {
|
||||
return style.get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (style *viewStyle) get(tag string) interface{} {
|
||||
func (style *viewStyle) get(tag string) any {
|
||||
switch tag {
|
||||
case Border, CellBorder:
|
||||
return getBorder(&style.propertyList, tag)
|
||||
|
@ -539,7 +552,7 @@ func (style *viewStyle) AllTags() []string {
|
|||
return result
|
||||
}
|
||||
|
||||
func supportedPropertyValue(value interface{}) bool {
|
||||
func supportedPropertyValue(value any) bool {
|
||||
switch value.(type) {
|
||||
case string:
|
||||
case []string:
|
||||
|
@ -551,7 +564,7 @@ func supportedPropertyValue(value interface{}) bool {
|
|||
case fmt.Stringer:
|
||||
case []ViewShadow:
|
||||
case []View:
|
||||
case []interface{}:
|
||||
case []any:
|
||||
case map[string]Animation:
|
||||
default:
|
||||
return false
|
||||
|
@ -559,7 +572,7 @@ func supportedPropertyValue(value interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func writePropertyValue(buffer *strings.Builder, tag string, value interface{}, indent string) {
|
||||
func writePropertyValue(buffer *strings.Builder, tag string, value any, indent string) {
|
||||
|
||||
writeString := func(text string) {
|
||||
simple := (tag != Text && tag != Title && tag != Summary)
|
||||
|
@ -569,7 +582,8 @@ func writePropertyValue(buffer *strings.Builder, tag string, value interface{},
|
|||
} else {
|
||||
for _, ch := range text {
|
||||
if (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
|
||||
ch == '+' || ch == '-' || ch == '@' || ch == '/' || ch == '_' || ch == ':' {
|
||||
ch == '+' || ch == '-' || ch == '@' || ch == '/' || ch == '_' || ch == ':' ||
|
||||
ch == '#' || ch == '%' || ch == 'π' || ch == '°' {
|
||||
} else {
|
||||
simple = false
|
||||
break
|
||||
|
@ -654,7 +668,7 @@ func writePropertyValue(buffer *strings.Builder, tag string, value interface{},
|
|||
value.writeString(buffer, indent+"\t")
|
||||
|
||||
case fmt.Stringer:
|
||||
buffer.WriteString(value.String())
|
||||
writeString(value.String())
|
||||
|
||||
case []ViewShadow:
|
||||
switch len(value) {
|
||||
|
@ -697,7 +711,7 @@ func writePropertyValue(buffer *strings.Builder, tag string, value interface{},
|
|||
buffer.WriteRune(']')
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
switch count := len(value); count {
|
||||
case 0:
|
||||
buffer.WriteString("[]")
|
||||
|
@ -741,7 +755,7 @@ func writePropertyValue(buffer *strings.Builder, tag string, value interface{},
|
|||
if animation := value[tag]; animation != nil {
|
||||
buffer.WriteString(indent2)
|
||||
animation.writeTransitionString(tag, buffer)
|
||||
buffer.WriteString("\n")
|
||||
buffer.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
buffer.WriteString(indent)
|
||||
|
@ -755,7 +769,7 @@ func writeViewStyle(name string, view ViewStyle, buffer *strings.Builder, indent
|
|||
buffer.WriteString(" {\n")
|
||||
indent += "\t"
|
||||
|
||||
writeProperty := func(tag string, value interface{}) {
|
||||
writeProperty := func(tag string, value any) {
|
||||
if supportedPropertyValue(value) {
|
||||
buffer.WriteString(indent)
|
||||
buffer.WriteString(tag)
|
||||
|
@ -786,7 +800,7 @@ func writeViewStyle(name string, view ViewStyle, buffer *strings.Builder, indent
|
|||
Opacity, ZIndex, Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight,
|
||||
Margin, Padding, BackgroundClip, BackgroundColor, Background, Border, Radius, Outline, Shadow,
|
||||
Orientation, ListWrap, VerticalAlign, HorizontalAlign, CellWidth, CellHeight,
|
||||
CellVerticalAlign, CellHorizontalAlign, GridRowGap, GridColumnGap,
|
||||
CellVerticalAlign, CellHorizontalAlign, ListRowGap, ListColumnGap, GridRowGap, GridColumnGap,
|
||||
ColumnCount, ColumnWidth, ColumnSeparator, ColumnGap, AvoidBreak,
|
||||
Current, Expanded, Side, ResizeBorderWidth, EditViewType, MaxLength, Hint, Text, EditWrap,
|
||||
TextOverflow, FontName, TextSize, TextColor, TextWeight, Italic, SmallCaps,
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func (style *viewStyle) setRange(tag string, value interface{}) bool {
|
||||
func (style *viewStyle) setRange(tag string, value any) bool {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if strings.Contains(value, "@") {
|
||||
|
@ -31,7 +31,7 @@ func (style *viewStyle) setRange(tag string, value interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (style *viewStyle) setBackground(value interface{}) bool {
|
||||
func (style *viewStyle) setBackground(value any) bool {
|
||||
switch value := value.(type) {
|
||||
case BackgroundElement:
|
||||
style.properties[Background] = []BackgroundElement{value}
|
||||
|
@ -122,11 +122,11 @@ func (style *viewStyle) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (style *viewStyle) Set(tag string, value interface{}) bool {
|
||||
func (style *viewStyle) Set(tag string, value any) bool {
|
||||
return style.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (style *viewStyle) set(tag string, value interface{}) bool {
|
||||
func (style *viewStyle) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
style.remove(tag)
|
||||
return true
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package rui
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
// Perspective is the name of the SizeUnit property that determines the distance between the z = 0 plane
|
||||
// and the user in order to give a 3D-positioned element some perspective. Each 3D element
|
||||
|
@ -104,20 +100,6 @@ func getTranslate(style Properties, session Session) (SizeUnit, SizeUnit, SizeUn
|
|||
return x, y, z
|
||||
}
|
||||
|
||||
func getScale(style Properties, session Session) (float64, float64, float64, bool) {
|
||||
scaleX, okX := floatProperty(style, ScaleX, session, 1)
|
||||
scaleY, okY := floatProperty(style, ScaleY, session, 1)
|
||||
scaleZ, okZ := floatProperty(style, ScaleZ, session, 1)
|
||||
return scaleX, scaleY, scaleZ, okX || okY || okZ
|
||||
}
|
||||
|
||||
func getRotateVector(style Properties, session Session) (float64, float64, float64) {
|
||||
rotateX, _ := floatProperty(style, RotateX, session, 1)
|
||||
rotateY, _ := floatProperty(style, RotateY, session, 1)
|
||||
rotateZ, _ := floatProperty(style, RotateZ, session, 1)
|
||||
return rotateX, rotateY, rotateZ
|
||||
}
|
||||
|
||||
func (style *viewStyle) transform(session Session) string {
|
||||
|
||||
buffer := allocStringBuilder()
|
||||
|
@ -133,45 +115,52 @@ func (style *viewStyle) transform(session Session) string {
|
|||
}
|
||||
|
||||
x, y, z := getTranslate(style, session)
|
||||
scaleX, scaleY, scaleZ, scaleOK := getScale(style, session)
|
||||
|
||||
scaleX, okScaleX := floatTextProperty(style, ScaleX, session, 1)
|
||||
scaleY, okScaleY := floatTextProperty(style, ScaleY, session, 1)
|
||||
|
||||
if getTransform3D(style, session) {
|
||||
if x.Type != Auto || y.Type != Auto || z.Type != Auto {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteRune(' ')
|
||||
}
|
||||
buffer.WriteString(`translate3d(`)
|
||||
buffer.WriteString(x.cssString("0"))
|
||||
buffer.WriteString(x.cssString("0", session))
|
||||
buffer.WriteRune(',')
|
||||
buffer.WriteString(y.cssString("0"))
|
||||
buffer.WriteString(y.cssString("0", session))
|
||||
buffer.WriteRune(',')
|
||||
buffer.WriteString(z.cssString("0"))
|
||||
buffer.WriteString(z.cssString("0", session))
|
||||
buffer.WriteRune(')')
|
||||
}
|
||||
|
||||
if scaleOK {
|
||||
scaleZ, okScaleZ := floatTextProperty(style, ScaleZ, session, 1)
|
||||
if okScaleX || okScaleY || okScaleZ {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteRune(' ')
|
||||
}
|
||||
buffer.WriteString(`scale3d(`)
|
||||
buffer.WriteString(strconv.FormatFloat(scaleX, 'g', -1, 64))
|
||||
buffer.WriteString(scaleX)
|
||||
buffer.WriteRune(',')
|
||||
buffer.WriteString(strconv.FormatFloat(scaleY, 'g', -1, 64))
|
||||
buffer.WriteString(scaleY)
|
||||
buffer.WriteRune(',')
|
||||
buffer.WriteString(strconv.FormatFloat(scaleZ, 'g', -1, 64))
|
||||
buffer.WriteString(scaleZ)
|
||||
buffer.WriteRune(')')
|
||||
}
|
||||
|
||||
if angle, ok := angleProperty(style, Rotate, session); ok {
|
||||
rotateX, rotateY, rotateZ := getRotateVector(style, session)
|
||||
rotateX, _ := floatTextProperty(style, RotateX, session, 1)
|
||||
rotateY, _ := floatTextProperty(style, RotateY, session, 1)
|
||||
rotateZ, _ := floatTextProperty(style, RotateZ, session, 1)
|
||||
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteRune(' ')
|
||||
}
|
||||
buffer.WriteString(`rotate3d(`)
|
||||
buffer.WriteString(strconv.FormatFloat(rotateX, 'g', -1, 64))
|
||||
buffer.WriteString(rotateX)
|
||||
buffer.WriteRune(',')
|
||||
buffer.WriteString(strconv.FormatFloat(rotateY, 'g', -1, 64))
|
||||
buffer.WriteString(rotateY)
|
||||
buffer.WriteRune(',')
|
||||
buffer.WriteString(strconv.FormatFloat(rotateZ, 'g', -1, 64))
|
||||
buffer.WriteString(rotateZ)
|
||||
buffer.WriteRune(',')
|
||||
buffer.WriteString(angle.cssString())
|
||||
buffer.WriteRune(')')
|
||||
|
@ -183,20 +172,20 @@ func (style *viewStyle) transform(session Session) string {
|
|||
buffer.WriteRune(' ')
|
||||
}
|
||||
buffer.WriteString(`translate(`)
|
||||
buffer.WriteString(x.cssString("0"))
|
||||
buffer.WriteString(x.cssString("0", session))
|
||||
buffer.WriteRune(',')
|
||||
buffer.WriteString(y.cssString("0"))
|
||||
buffer.WriteString(y.cssString("0", session))
|
||||
buffer.WriteRune(')')
|
||||
}
|
||||
|
||||
if scaleOK {
|
||||
if okScaleX || okScaleY {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.WriteRune(' ')
|
||||
}
|
||||
buffer.WriteString(`scale(`)
|
||||
buffer.WriteString(strconv.FormatFloat(scaleX, 'g', -1, 64))
|
||||
buffer.WriteString(scaleX)
|
||||
buffer.WriteRune(',')
|
||||
buffer.WriteString(strconv.FormatFloat(scaleY, 'g', -1, 64))
|
||||
buffer.WriteString(scaleY)
|
||||
buffer.WriteRune(')')
|
||||
}
|
||||
|
||||
|
@ -216,12 +205,12 @@ func (style *viewStyle) transform(session Session) string {
|
|||
func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Session) {
|
||||
if getTransform3D(style, session) {
|
||||
if perspective, ok := sizeProperty(style, Perspective, session); ok && perspective.Type != Auto && perspective.Value != 0 {
|
||||
builder.add(`perspective`, perspective.cssString("0"))
|
||||
builder.add(`perspective`, perspective.cssString("0", session))
|
||||
}
|
||||
|
||||
x, y := getPerspectiveOrigin(style, session)
|
||||
if x.Type != Auto || y.Type != Auto {
|
||||
builder.addValues(`perspective-origin`, ` `, x.cssString("50%"), y.cssString("50%"))
|
||||
builder.addValues(`perspective-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session))
|
||||
}
|
||||
|
||||
if backfaceVisible, ok := boolProperty(style, BackfaceVisible, session); ok {
|
||||
|
@ -234,12 +223,12 @@ func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Sessio
|
|||
|
||||
x, y, z := getOrigin(style, session)
|
||||
if x.Type != Auto || y.Type != Auto || z.Type != Auto {
|
||||
builder.addValues(`transform-origin`, ` `, x.cssString("50%"), y.cssString("50%"), z.cssString("0"))
|
||||
builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session), z.cssString("0", session))
|
||||
}
|
||||
} else {
|
||||
x, y, _ := getOrigin(style, session)
|
||||
if x.Type != Auto || y.Type != Auto {
|
||||
builder.addValues(`transform-origin`, ` `, x.cssString("50%"), y.cssString("50%"))
|
||||
builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,17 +245,17 @@ func (view *viewData) updateTransformProperty(tag string) bool {
|
|||
|
||||
case PerspectiveOriginX, PerspectiveOriginY:
|
||||
if getTransform3D(view, session) {
|
||||
x, y := GetPerspectiveOrigin(view, "")
|
||||
x, y := GetPerspectiveOrigin(view)
|
||||
value := ""
|
||||
if x.Type != Auto || y.Type != Auto {
|
||||
value = x.cssString("50%") + " " + y.cssString("50%")
|
||||
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
|
||||
}
|
||||
updateCSSProperty(htmlID, "perspective-origin", value, session)
|
||||
}
|
||||
|
||||
case BackfaceVisible:
|
||||
if getTransform3D(view, session) {
|
||||
if GetBackfaceVisible(view, "") {
|
||||
if GetBackfaceVisible(view) {
|
||||
updateCSSProperty(htmlID, BackfaceVisible, "visible", session)
|
||||
} else {
|
||||
updateCSSProperty(htmlID, BackfaceVisible, "hidden", session)
|
||||
|
@ -278,11 +267,11 @@ func (view *viewData) updateTransformProperty(tag string) bool {
|
|||
value := ""
|
||||
if getTransform3D(view, session) {
|
||||
if x.Type != Auto || y.Type != Auto || z.Type != Auto {
|
||||
value = x.cssString("50%") + " " + y.cssString("50%") + " " + z.cssString("50%")
|
||||
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%") + " " + y.cssString("50%")
|
||||
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
|
||||
}
|
||||
}
|
||||
updateCSSProperty(htmlID, "transform-origin", value, session)
|
||||
|
|
974
viewUtils.go
974
viewUtils.go
File diff suppressed because it is too large
Load Diff
|
@ -25,8 +25,8 @@ type viewsContainerData struct {
|
|||
}
|
||||
|
||||
// Init initialize fields of ViewsContainer by default values
|
||||
func (container *viewsContainerData) Init(session Session) {
|
||||
container.viewData.Init(session)
|
||||
func (container *viewsContainerData) init(session Session) {
|
||||
container.viewData.init(session)
|
||||
container.tag = "ViewsContainer"
|
||||
container.views = []View{}
|
||||
}
|
||||
|
@ -47,8 +47,7 @@ func (container *viewsContainerData) setParentID(parentID string) {
|
|||
func (container *viewsContainerData) Views() []View {
|
||||
if container.views == nil {
|
||||
container.views = []View{}
|
||||
}
|
||||
if count := len(container.views); count > 0 {
|
||||
} else if count := len(container.views); count > 0 {
|
||||
views := make([]View, count)
|
||||
copy(views, container.views)
|
||||
return views
|
||||
|
@ -172,11 +171,11 @@ func (container *viewsContainerData) remove(tag string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (container *viewsContainerData) Set(tag string, value interface{}) bool {
|
||||
func (container *viewsContainerData) Set(tag string, value any) bool {
|
||||
return container.set(strings.ToLower(tag), value)
|
||||
}
|
||||
|
||||
func (container *viewsContainerData) set(tag string, value interface{}) bool {
|
||||
func (container *viewsContainerData) set(tag string, value any) bool {
|
||||
if value == nil {
|
||||
container.remove(tag)
|
||||
return true
|
||||
|
@ -187,9 +186,9 @@ func (container *viewsContainerData) set(tag string, value interface{}) bool {
|
|||
// do nothing
|
||||
|
||||
case Disabled:
|
||||
oldDisabled := IsDisabled(container, "")
|
||||
oldDisabled := IsDisabled(container)
|
||||
if container.viewData.Set(Disabled, value) {
|
||||
disabled := IsDisabled(container, "")
|
||||
disabled := IsDisabled(container)
|
||||
if oldDisabled != disabled {
|
||||
if container.views != nil {
|
||||
for _, view := range container.views {
|
||||
|
@ -224,7 +223,7 @@ func (container *viewsContainerData) set(tag string, value interface{}) bool {
|
|||
}
|
||||
container.views = views
|
||||
|
||||
case []interface{}:
|
||||
case []any:
|
||||
views := []View{}
|
||||
for _, v := range value {
|
||||
switch v := v.(type) {
|
||||
|
@ -279,11 +278,11 @@ func (container *viewsContainerData) set(tag string, value interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (container *viewsContainerData) Get(tag string) interface{} {
|
||||
func (container *viewsContainerData) Get(tag string) any {
|
||||
return container.get(strings.ToLower(tag))
|
||||
}
|
||||
|
||||
func (container *viewsContainerData) get(tag string) interface{} {
|
||||
func (container *viewsContainerData) get(tag string) any {
|
||||
switch tag {
|
||||
case Content:
|
||||
return container.views
|
||||
|
|
Loading…
Reference in New Issue