rui_orig/view.go

957 lines
26 KiB
Go
Raw Normal View History

2021-09-07 17:36:50 +03:00
package rui
import (
"fmt"
"strconv"
"strings"
)
// Frame - the location and size of a rectangle area
type Frame struct {
// Left - the left border
Left float64
// Top - the top border
Top float64
// Width - the width of a rectangle area
Width float64
// Height - the height of a rectangle area
Height float64
}
// Right returns the right border
func (frame Frame) Right() float64 {
return frame.Left + frame.Width
}
// Bottom returns the bottom border
func (frame Frame) Bottom() float64 {
return frame.Top + frame.Height
}
// View - base view interface
type View interface {
2022-05-22 12:54:02 +03:00
ViewStyle
2021-09-07 17:36:50 +03:00
fmt.Stringer
// Session returns the current Session interface
Session() Session
// Parent returns the parent view
Parent() View
// Tag returns the tag of View interface
Tag() string
// ID returns the id of the view
ID() string
// Focusable returns true if the view receives the focus
Focusable() bool
// Frame returns the location and size of the view in pixels
Frame() Frame
2022-11-23 15:10:29 +03:00
// Scroll returns the location size of the scrollable view in pixels
2021-09-07 17:36:50 +03:00
Scroll() Frame
// 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
2022-07-26 18:36:00 +03:00
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
HasFocus() bool
2021-09-07 17:36:50 +03:00
handleCommand(self View, command string, data DataObject) bool
htmlClass(disabled bool) string
htmlTag() string
closeHTMLTag() bool
htmlID() string
parentHTMLID() string
setParentID(parentID string)
2021-09-07 17:36:50 +03:00
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)
onResize(self View, x, y, width, height float64)
onItemResize(self View, index string, x, y, width, height float64)
2021-09-07 17:36:50 +03:00
setNoResizeEvent()
isNoResizeEvent() bool
setScroll(x, y, width, height float64)
}
// viewData - base implementation of View interface
type viewData struct {
viewStyle
session Session
tag string
viewID string
_htmlID string
parentID string
systemClass string
changeListener map[string]func(View, string)
singleTransition map[string]Animation
addCSS map[string]string
frame Frame
scroll Frame
noResizeEvent bool
created bool
hasFocus bool
2021-09-07 17:36:50 +03:00
//animation map[string]AnimationEndListener
}
func newView(session Session) View {
view := new(viewData)
view.init(session)
2021-09-07 17:36:50 +03:00
return view
}
func setInitParams(view View, params Params) {
if params != nil {
session := view.Session()
if !session.ignoreViewUpdates() {
session.setIgnoreViewUpdates(true)
defer session.setIgnoreViewUpdates(false)
}
for _, tag := range params.AllTags() {
if value, ok := params[tag]; ok {
view.Set(tag, value)
}
}
}
}
// NewView create new View object and return it
func NewView(session Session, params Params) View {
view := new(viewData)
view.init(session)
2021-09-07 17:36:50 +03:00
setInitParams(view, params)
return view
}
func (view *viewData) init(session Session) {
2021-09-07 17:36:50 +03:00
view.viewStyle.init()
view.tag = "View"
view.session = session
view.changeListener = map[string]func(View, string){}
2021-09-07 17:36:50 +03:00
view.addCSS = map[string]string{}
//view.animation = map[string]AnimationEndListener{}
view.singleTransition = map[string]Animation{}
2021-09-07 17:36:50 +03:00
view.noResizeEvent = false
view.created = false
}
func (view *viewData) Session() Session {
return view.session
}
func (view *viewData) Parent() View {
return view.session.viewByHTMLID(view.parentID)
}
func (view *viewData) parentHTMLID() string {
return view.parentID
}
func (view *viewData) setParentID(parentID string) {
view.parentID = parentID
}
func (view *viewData) Tag() string {
return view.tag
}
func (view *viewData) ID() string {
return view.viewID
}
func (view *viewData) ViewByID(id string) View {
if id == view.ID() {
if v := view.session.viewByHTMLID(view.htmlID()); v != nil {
return v
}
return view
}
return nil
}
func (view *viewData) Focusable() bool {
if focus, ok := boolProperty(view, Focusable, view.session); ok {
return focus
}
2023-05-02 14:49:35 +03:00
if style, ok := stringProperty(view, Style, view.session); ok {
if style, ok := view.session.resolveConstants(style); ok {
if value := view.session.styleProperty(style, Focusable); ok {
if focus, ok := valueToBool(value, view.Session()); ok {
return focus
}
}
}
}
2021-09-07 17:36:50 +03:00
return false
}
func (view *viewData) Remove(tag string) {
view.remove(strings.ToLower(tag))
}
func (view *viewData) remove(tag string) {
switch tag {
case ID:
view.viewID = ""
2022-12-20 18:38:39 +03:00
case TabIndex, "tab-index":
delete(view.properties, tag)
if view.Focusable() {
view.session.updateProperty(view.htmlID(), "tabindex", "0")
} else {
view.session.updateProperty(view.htmlID(), "tabindex", "-1")
}
case UserData:
delete(view.properties, tag)
2021-09-07 17:36:50 +03:00
case Style, StyleDisabled:
if _, ok := view.properties[tag]; ok {
delete(view.properties, tag)
2022-10-30 17:22:33 +03:00
view.session.updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)))
2021-09-07 17:36:50 +03:00
}
case FocusEvent, LostFocusEvent:
view.removeFocusListener(tag)
case KeyDownEvent, KeyUpEvent:
view.removeKeyListener(tag)
case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent:
view.removeMouseListener(tag)
case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel:
view.removePointerListener(tag)
case TouchStart, TouchEnd, TouchMove, TouchCancel:
view.removeTouchListener(tag)
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
view.removeTransitionListener(tag)
case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
view.removeAnimationListener(tag)
2021-09-07 17:36:50 +03:00
case ResizeEvent, ScrollEvent:
delete(view.properties, tag)
case Content:
if _, ok := view.properties[Content]; ok {
delete(view.properties, Content)
updateInnerHTML(view.htmlID(), view.session)
}
default:
view.viewStyle.remove(tag)
viewPropertyChanged(view, tag)
}
view.propertyChangedEvent(tag)
}
func (view *viewData) propertyChangedEvent(tag string) {
if listener, ok := view.changeListener[tag]; ok {
listener(view, tag)
}
switch tag {
case BorderLeft, BorderRight, BorderTop, BorderBottom,
BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle,
BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor,
BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
tag = Border
case CellBorderStyle, CellBorderColor, CellBorderWidth,
CellBorderLeft, CellBorderLeftStyle, CellBorderLeftColor, CellBorderLeftWidth,
CellBorderRight, CellBorderRightStyle, CellBorderRightColor, CellBorderRightWidth,
CellBorderTop, CellBorderTopStyle, CellBorderTopColor, CellBorderTopWidth,
CellBorderBottom, CellBorderBottomStyle, CellBorderBottomColor, CellBorderBottomWidth:
tag = CellBorder
case OutlineColor, OutlineStyle, OutlineWidth:
tag = Outline
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
tag = Radius
case MarginTop, MarginRight, MarginBottom, MarginLeft,
"top-margin", "right-margin", "bottom-margin", "left-margin":
tag = Margin
case PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
"top-padding", "right-padding", "bottom-padding", "left-padding":
tag = Padding
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
tag = CellPadding
case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor:
tag = ColumnSeparator
default:
return
}
if listener, ok := view.changeListener[tag]; ok {
listener(view, tag)
2021-09-07 17:36:50 +03:00
}
2021-09-07 17:36:50 +03:00
}
2022-07-26 18:36:00 +03:00
func (view *viewData) Set(tag string, value any) bool {
2021-09-07 17:36:50 +03:00
return view.set(strings.ToLower(tag), value)
}
2022-07-26 18:36:00 +03:00
func (view *viewData) set(tag string, value any) bool {
2021-09-07 17:36:50 +03:00
if value == nil {
view.remove(tag)
return true
}
result := func(res bool) bool {
if res {
view.propertyChangedEvent(tag)
}
return res
}
2021-09-07 17:36:50 +03:00
switch tag {
case ID:
text, ok := value.(string)
if !ok {
notCompatibleType(ID, value)
return false
2021-09-07 17:36:50 +03:00
}
view.viewID = text
2021-09-07 17:36:50 +03:00
2022-12-20 18:38:39 +03:00
case TabIndex, "tab-index":
if !view.setIntProperty(tag, value) {
return false
}
if value, ok := intProperty(view, TabIndex, view.Session(), 0); ok {
view.session.updateProperty(view.htmlID(), "tabindex", strconv.Itoa(value))
} else if view.Focusable() {
view.session.updateProperty(view.htmlID(), "tabindex", "0")
} else {
view.session.updateProperty(view.htmlID(), "tabindex", "-1")
}
case UserData:
view.properties[tag] = value
2021-09-07 17:36:50 +03:00
case Style, StyleDisabled:
text, ok := value.(string)
if !ok {
notCompatibleType(ID, value)
return false
}
view.properties[tag] = text
if view.created {
2022-10-30 17:22:33 +03:00
view.session.updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)))
2021-09-07 17:36:50 +03:00
}
case FocusEvent, LostFocusEvent:
return result(view.setFocusListener(tag, value))
2021-09-07 17:36:50 +03:00
case KeyDownEvent, KeyUpEvent:
return result(view.setKeyListener(tag, value))
2021-09-07 17:36:50 +03:00
case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent:
return result(view.setMouseListener(tag, value))
2021-09-07 17:36:50 +03:00
case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel:
return result(view.setPointerListener(tag, value))
2021-09-07 17:36:50 +03:00
case TouchStart, TouchEnd, TouchMove, TouchCancel:
return result(view.setTouchListener(tag, value))
2021-09-07 17:36:50 +03:00
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
return result(view.setTransitionListener(tag, value))
case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
return result(view.setAnimationListener(tag, value))
2021-09-07 17:36:50 +03:00
case ResizeEvent, ScrollEvent:
return result(view.setFrameListener(tag, value))
2021-09-07 17:36:50 +03:00
default:
if !view.viewStyle.set(tag, value) {
return false
}
2021-09-07 17:36:50 +03:00
if view.created {
viewPropertyChanged(view, tag)
2021-09-07 17:36:50 +03:00
}
}
view.propertyChangedEvent(tag)
return true
2021-09-07 17:36:50 +03:00
}
func viewPropertyChanged(view *viewData, tag string) {
2021-09-07 17:36:50 +03:00
if view.updateTransformProperty(tag) {
return
}
htmlID := view.htmlID()
session := view.session
switch tag {
case Disabled:
updateInnerHTML(view.parentHTMLID(), session)
2022-03-31 19:59:10 +03:00
return
case Visibility:
switch GetVisibility(view) {
2022-03-31 19:59:10 +03:00
case Invisible:
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, Visibility, "hidden")
session.updateCSSProperty(htmlID, "display", "")
2022-03-31 19:59:10 +03:00
case Gone:
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, Visibility, "hidden")
session.updateCSSProperty(htmlID, "display", "none")
2022-03-31 19:59:10 +03:00
default:
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, Visibility, "visible")
session.updateCSSProperty(htmlID, "display", "")
2022-03-31 19:59:10 +03:00
}
return
2021-09-07 17:36:50 +03:00
case Background:
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, Background, view.backgroundCSS(session))
2021-09-07 17:36:50 +03:00
return
case Border:
if getBorder(view, Border) == nil {
2022-10-31 16:07:59 +03:00
if session.startUpdateScript(htmlID) {
defer session.finishUpdateScript(htmlID)
2022-07-22 13:10:55 +03:00
}
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, BorderWidth, "")
session.updateCSSProperty(htmlID, BorderColor, "")
session.updateCSSProperty(htmlID, BorderStyle, "none")
2021-09-07 17:36:50 +03:00
return
}
fallthrough
case BorderLeft, BorderRight, BorderTop, BorderBottom:
if border := getBorder(view, Border); border != nil {
2022-10-31 16:07:59 +03:00
if session.startUpdateScript(htmlID) {
defer session.finishUpdateScript(htmlID)
2022-07-22 13:10:55 +03:00
}
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, BorderWidth, border.cssWidthValue(session))
session.updateCSSProperty(htmlID, BorderColor, border.cssColorValue(session))
session.updateCSSProperty(htmlID, BorderStyle, border.cssStyleValue(session))
2021-09-07 17:36:50 +03:00
}
return
case BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle:
if border := getBorder(view, Border); border != nil {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, BorderStyle, border.cssStyleValue(session))
2021-09-07 17:36:50 +03:00
}
return
case BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor:
if border := getBorder(view, Border); border != nil {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, BorderColor, border.cssColorValue(session))
2021-09-07 17:36:50 +03:00
}
return
case BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
if border := getBorder(view, Border); border != nil {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, BorderWidth, border.cssWidthValue(session))
2021-09-07 17:36:50 +03:00
}
return
case Outline, OutlineColor, OutlineStyle, OutlineWidth:
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, Outline, GetOutline(view).cssString(session))
2021-09-07 17:36:50 +03:00
return
case Shadow:
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "box-shadow", shadowCSS(view, Shadow, session))
2021-09-07 17:36:50 +03:00
return
case TextShadow:
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "text-shadow", shadowCSS(view, TextShadow, session))
2021-09-07 17:36:50 +03:00
return
case Radius, RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
radius := GetRadius(view)
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "border-radius", radius.cssString(session))
2021-09-07 17:36:50 +03:00
return
case Margin, MarginTop, MarginRight, MarginBottom, MarginLeft,
"top-margin", "right-margin", "bottom-margin", "left-margin":
margin := GetMargin(view)
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, Margin, margin.cssString(session))
2021-09-07 17:36:50 +03:00
return
case Padding, PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
"top-padding", "right-padding", "bottom-padding", "left-padding":
padding := GetPadding(view)
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, Padding, padding.cssString(session))
2021-09-07 17:36:50 +03:00
return
case AvoidBreak:
if avoid, ok := boolProperty(view, AvoidBreak, session); ok {
if avoid {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "break-inside", "avoid")
2021-09-07 17:36:50 +03:00
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "break-inside", "auto")
2021-09-07 17:36:50 +03:00
}
}
return
case Clip:
if clip := getClipShape(view, Clip, session); clip != nil && clip.valid(session) {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, `clip-path`, clip.cssStyle(session))
2021-09-07 17:36:50 +03:00
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, `clip-path`, "none")
2021-09-07 17:36:50 +03:00
}
return
case ShapeOutside:
if clip := getClipShape(view, ShapeOutside, session); clip != nil && clip.valid(session) {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, ShapeOutside, clip.cssStyle(session))
2021-09-07 17:36:50 +03:00
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, ShapeOutside, "none")
2021-09-07 17:36:50 +03:00
}
return
case Filter:
text := ""
if value := view.getRaw(tag); value != nil {
2021-09-07 17:36:50 +03:00
if filter, ok := value.(ViewFilter); ok {
text = filter.cssStyle(session)
}
}
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, tag, text)
return
case BackdropFilter:
text := ""
if value := view.getRaw(tag); value != nil {
if filter, ok := value.(ViewFilter); ok {
text = filter.cssStyle(session)
}
}
2022-10-31 16:07:59 +03:00
if session.startUpdateScript(htmlID) {
defer session.finishUpdateScript(htmlID)
2022-07-22 13:10:55 +03:00
}
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "-webkit-backdrop-filter", text)
session.updateCSSProperty(htmlID, tag, text)
2021-09-07 17:36:50 +03:00
return
case FontName:
if font, ok := stringProperty(view, FontName, session); ok {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "font-family", font)
2021-09-07 17:36:50 +03:00
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "font-family", "")
2021-09-07 17:36:50 +03:00
}
return
case Italic:
if state, ok := boolProperty(view, tag, session); ok {
if state {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "font-style", "italic")
2021-09-07 17:36:50 +03:00
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "font-style", "normal")
2021-09-07 17:36:50 +03:00
}
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "font-style", "")
2021-09-07 17:36:50 +03:00
}
return
2021-09-07 17:36:50 +03:00
case SmallCaps:
if state, ok := boolProperty(view, tag, session); ok {
if state {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "font-variant", "small-caps")
2021-09-07 17:36:50 +03:00
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "font-variant", "normal")
2021-09-07 17:36:50 +03:00
}
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "font-variant", "")
2021-09-07 17:36:50 +03:00
}
return
2021-09-07 17:36:50 +03:00
case Strikethrough, Overline, Underline:
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "text-decoration", view.cssTextDecoration(session))
2021-09-07 17:36:50 +03:00
for _, tag2 := range []string{TextLineColor, TextLineStyle, TextLineThickness} {
viewPropertyChanged(view, tag2)
2021-09-07 17:36:50 +03:00
}
return
2021-09-07 17:36:50 +03:00
case Transition:
view.updateTransitionCSS()
return
case AnimationTag:
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, AnimationTag, view.animationCSS(session))
return
case AnimationPaused:
paused, ok := boolProperty(view, AnimationPaused, session)
if !ok {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, `animation-play-state`, ``)
} else if paused {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, `animation-play-state`, `paused`)
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, `animation-play-state`, `running`)
}
return
2022-04-21 18:22:17 +03:00
2022-12-18 18:37:36 +03:00
case ZIndex, Order, TabSize:
2022-08-20 20:05:56 +03:00
if i, ok := intProperty(view, tag, session, 0); ok {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, tag, strconv.Itoa(i))
2022-04-21 18:22:17 +03:00
}
return
2022-05-03 12:12:57 +03:00
case Row, Column:
2022-10-30 17:22:33 +03:00
if parentID := view.parentHTMLID(); parentID != "" {
updateInnerHTML(parentID, session)
2022-05-03 12:12:57 +03:00
}
return
case UserSelect:
2022-10-31 16:07:59 +03:00
if session.startUpdateScript(htmlID) {
defer session.finishUpdateScript(htmlID)
2022-07-22 13:10:55 +03:00
}
if userSelect, ok := boolProperty(view, UserSelect, session); ok {
if userSelect {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "-webkit-user-select", "auto")
session.updateCSSProperty(htmlID, "user-select", "auto")
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "-webkit-user-select", "none")
session.updateCSSProperty(htmlID, "user-select", "none")
}
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, "-webkit-user-select", "")
session.updateCSSProperty(htmlID, "user-select", "")
}
return
2023-01-03 14:56:57 +03:00
case ColumnSpanAll:
if spanAll, ok := boolProperty(view, ColumnSpanAll, session); ok && spanAll {
session.updateCSSProperty(htmlID, `column-span`, `all`)
} else {
session.updateCSSProperty(htmlID, `column-span`, `none`)
}
return
2023-04-25 17:20:47 +03:00
case Tooltip:
if tooltip := GetTooltip(view); tooltip == "" {
session.removeProperty(htmlID, "data-tooltip")
} else {
session.updateProperty(htmlID, "data-tooltip", tooltip)
session.updateProperty(htmlID, "onmouseenter", "mouseEnterEvent(this, event)")
session.updateProperty(htmlID, "onmouseleave", "mouseLeaveEvent(this, event)")
}
return
2021-09-07 17:36:50 +03:00
}
if cssTag, ok := sizeProperties[tag]; ok {
size, _ := sizeProperty(view, tag, session)
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, cssTag, size.cssString("", session))
2021-09-07 17:36:50 +03:00
return
}
colorTags := map[string]string{
BackgroundColor: BackgroundColor,
TextColor: "color",
TextLineColor: "text-decoration-color",
CaretColor: CaretColor,
2022-08-20 19:13:51 +03:00
AccentColor: AccentColor,
2021-09-07 17:36:50 +03:00
}
if cssTag, ok := colorTags[tag]; ok {
if color, ok := colorProperty(view, tag, session); ok {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, cssTag, color.cssString())
2021-09-07 17:36:50 +03:00
} else {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, cssTag, "")
2021-09-07 17:36:50 +03:00
}
return
}
if valuesData, ok := enumProperties[tag]; ok && valuesData.cssTag != "" {
n, _ := enumProperty(view, tag, session, 0)
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, valuesData.cssTag, valuesData.cssValues[n])
2021-09-07 17:36:50 +03:00
return
}
2022-04-21 18:22:17 +03:00
for _, floatTag := range []string{Opacity, ScaleX, ScaleY, ScaleZ, RotateX, RotateY, RotateZ} {
2021-09-07 17:36:50 +03:00
if tag == floatTag {
2022-08-18 18:18:36 +03:00
if f, ok := floatTextProperty(view, floatTag, session, 0); ok {
2022-10-30 17:22:33 +03:00
session.updateCSSProperty(htmlID, floatTag, f)
2021-09-07 17:36:50 +03:00
}
return
}
}
}
2022-07-26 18:36:00 +03:00
func (view *viewData) Get(tag string) any {
2021-09-07 17:36:50 +03:00
return view.get(strings.ToLower(tag))
}
2022-07-26 18:36:00 +03:00
func (view *viewData) get(tag string) any {
2022-05-22 12:54:02 +03:00
if tag == ID {
if view.viewID != "" {
return view.viewID
} else {
return nil
}
}
2021-09-07 17:36:50 +03:00
return view.viewStyle.get(tag)
}
func (view *viewData) htmlTag() string {
if semantics := GetSemantics(view); semantics > DefaultSemantics {
2021-09-07 17:36:50 +03:00
values := enumProperties[Semantics].cssValues
if semantics < len(values) {
return values[semantics]
}
}
return "div"
}
func (view *viewData) closeHTMLTag() bool {
return true
}
func (view *viewData) htmlID() string {
if view._htmlID == "" {
view._htmlID = view.session.nextViewID()
}
return view._htmlID
}
func (view *viewData) htmlSubviews(self View, buffer *strings.Builder) {
}
func (view *viewData) addToCSSStyle(addCSS map[string]string) {
view.addCSS = addCSS
}
func (view *viewData) cssStyle(self View, builder cssBuilder) {
view.viewStyle.cssViewStyle(builder, view.session)
switch GetVisibility(view) {
2021-09-07 17:36:50 +03:00
case Invisible:
builder.add(`visibility`, `hidden`)
case Gone:
builder.add(`display`, `none`)
}
if view.addCSS != nil {
for tag, value := range view.addCSS {
builder.add(tag, value)
}
}
}
func (view *viewData) htmlProperties(self View, buffer *strings.Builder) {
view.created = true
if view.frame.Left != 0 || view.frame.Top != 0 || view.frame.Width != 0 || view.frame.Height != 0 {
buffer.WriteString(fmt.Sprintf(` data-left="%g" data-top="%g" data-width="%g" data-height="%g"`,
view.frame.Left, view.frame.Top, view.frame.Width, view.frame.Height))
}
}
func (view *viewData) htmlDisabledProperties(self View, buffer *strings.Builder) {
if IsDisabled(self) {
2021-09-07 17:36:50 +03:00
buffer.WriteString(` data-disabled="1"`)
} else {
buffer.WriteString(` data-disabled="0"`)
}
}
func viewHTML(view View, buffer *strings.Builder) {
viewHTMLTag := view.htmlTag()
buffer.WriteRune('<')
buffer.WriteString(viewHTMLTag)
buffer.WriteString(` id="`)
buffer.WriteString(view.htmlID())
buffer.WriteRune('"')
disabled := IsDisabled(view)
2021-09-07 17:36:50 +03:00
if cls := view.htmlClass(disabled); cls != "" {
buffer.WriteString(` class="`)
buffer.WriteString(cls)
buffer.WriteRune('"')
}
2022-10-29 20:16:40 +03:00
cssBuilder := viewCSSBuilder{buffer: allocStringBuilder()}
2021-09-07 17:36:50 +03:00
view.cssStyle(view, &cssBuilder)
if style := cssBuilder.finish(); style != "" {
buffer.WriteString(` style="`)
buffer.WriteString(style)
buffer.WriteRune('"')
}
buffer.WriteRune(' ')
view.htmlProperties(view, buffer)
buffer.WriteRune(' ')
view.htmlDisabledProperties(view, buffer)
if view.isNoResizeEvent() {
buffer.WriteString(` data-noresize="1" `)
} else {
buffer.WriteRune(' ')
}
2022-12-20 18:38:39 +03:00
if !disabled {
if value, ok := intProperty(view, TabIndex, view.Session(), -1); ok {
buffer.WriteString(`tabindex="`)
buffer.WriteString(strconv.Itoa(value))
buffer.WriteString(`" `)
} else if view.Focusable() {
buffer.WriteString(`tabindex="0" `)
}
2021-09-07 17:36:50 +03:00
}
2023-04-25 17:20:47 +03:00
hasTooltip := false
if tooltip := GetTooltip(view); tooltip != "" {
buffer.WriteString(`data-tooltip=" `)
buffer.WriteString(tooltip)
buffer.WriteString(`" `)
hasTooltip = true
}
2021-09-07 17:36:50 +03:00
buffer.WriteString(`onscroll="scrollEvent(this, event)" `)
keyEventsHtml(view, buffer)
2023-04-25 17:20:47 +03:00
mouseEventsHtml(view, buffer, hasTooltip)
2021-09-07 17:36:50 +03:00
pointerEventsHtml(view, buffer)
touchEventsHtml(view, buffer)
focusEventsHtml(view, buffer)
transitionEventsHtml(view, buffer)
animationEventsHtml(view, buffer)
2021-09-07 17:36:50 +03:00
buffer.WriteRune('>')
view.htmlSubviews(view, buffer)
if view.closeHTMLTag() {
buffer.WriteString(`</`)
buffer.WriteString(viewHTMLTag)
buffer.WriteRune('>')
}
}
func (view *viewData) htmlClass(disabled bool) string {
cls := "ruiView"
disabledStyle := false
if disabled {
if value, ok := stringProperty(view, StyleDisabled, view.Session()); ok && value != "" {
cls += " " + value
disabledStyle = true
}
}
if !disabledStyle {
if value, ok := stringProperty(view, Style, view.Session()); ok {
cls += " " + value
}
}
if view.systemClass != "" {
cls = view.systemClass + " " + cls
}
return cls
}
func (view *viewData) handleCommand(self View, command string, data DataObject) bool {
switch command {
case KeyDownEvent, KeyUpEvent:
if !IsDisabled(self) {
2021-09-07 17:36:50 +03:00
handleKeyEvents(self, command, data)
}
case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent:
handleMouseEvents(self, command, data)
case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel:
handlePointerEvents(self, command, data)
case TouchStart, TouchEnd, TouchMove, TouchCancel:
handleTouchEvents(self, command, data)
case FocusEvent:
view.hasFocus = true
for _, listener := range getFocusListeners(view, nil, command) {
listener(self)
}
case LostFocusEvent:
view.hasFocus = false
for _, listener := range getFocusListeners(view, nil, command) {
2021-09-07 17:36:50 +03:00
listener(self)
}
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
view.handleTransitionEvents(command, data)
case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
view.handleAnimationEvents(command, data)
2021-09-07 17:36:50 +03:00
case "scroll":
view.onScroll(view, dataFloatProperty(data, "x"), dataFloatProperty(data, "y"), dataFloatProperty(data, "width"), dataFloatProperty(data, "height"))
case "widthChanged":
if value, ok := data.PropertyValue("width"); ok {
if width, ok := StringToSizeUnit(value); ok {
self.setRaw(Width, width)
}
}
case "heightChanged":
if value, ok := data.PropertyValue("height"); ok {
if height, ok := StringToSizeUnit(value); ok {
self.setRaw(Height, height)
}
}
/*
case "resize":
floatProperty := func(tag string) float64 {
if value, ok := data.PropertyValue(tag); ok {
if result, err := strconv.ParseFloat(value, 64); err == nil {
return result
}
}
return 0
}
self.onResize(self, floatProperty("x"), floatProperty("y"), floatProperty("width"), floatProperty("height"))
return true
*/
default:
return false
}
return true
}
func (view *viewData) SetChangeListener(tag string, listener func(View, string)) {
if listener == nil {
delete(view.changeListener, tag)
} else {
view.changeListener[tag] = listener
2021-09-07 17:36:50 +03:00
}
}
func (view *viewData) HasFocus() bool {
return view.hasFocus
}
2022-05-22 12:54:02 +03:00
func (view *viewData) String() string {
return getViewString(view)
}