rui_orig/view.go

1078 lines
30 KiB
Go

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 represents a base view interface
type View interface {
ViewStyle
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
// Scroll returns the location size of the scrollable view in pixels
Scroll() Frame
// SetParams sets properties with name "tag" of the "rootView" subview. Result:
// * true - all properties were set successful,
// * false - error (incompatible type or invalid format of a string value, see AppLog).
SetParams(params Params) bool
// 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 PropertyName, value any, animation Animation) bool
// SetChangeListener set the function to track the change of the View property
SetChangeListener(tag PropertyName, listener func(View, PropertyName))
// HasFocus returns 'true' if the view has focus
HasFocus() bool
init(session Session)
handleCommand(self View, command PropertyName, data DataObject) bool
htmlClass(disabled bool) string
htmlTag() string
closeHTMLTag() bool
htmlID() string
parentHTMLID() string
setParentID(parentID string)
htmlSubviews(self View, buffer *strings.Builder)
htmlProperties(self View, buffer *strings.Builder)
cssStyle(self View, builder cssBuilder)
addToCSSStyle(addCSS map[string]string)
exscludeTags() []PropertyName
htmlDisabledProperty() bool
onResize(self View, x, y, width, height float64)
onItemResize(self View, index string, x, y, width, height float64)
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[PropertyName]func(View, PropertyName)
singleTransition map[PropertyName]Animation
addCSS map[string]string
frame Frame
scroll Frame
noResizeEvent bool
created bool
hasFocus bool
hasHtmlDisabled bool
getFunc func(view View, tag PropertyName) any
set func(view View, tag PropertyName, value any) []PropertyName
remove func(view View, tag PropertyName) []PropertyName
changed func(view View, tag PropertyName)
}
func newView(session Session) View {
return new(viewData)
}
// NewView create new View object and return it
func NewView(session Session, params Params) View {
view := new(viewData)
view.init(session)
setInitParams(view, params)
return view
}
func 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)
}
}
}
}
func (view *viewData) init(session Session) {
view.viewStyle.init()
view.getFunc = viewGet
view.set = viewSet
view.normalize = normalizeViewTag
view.changed = viewPropertyChanged
view.tag = "View"
view.session = session
view.changeListener = map[PropertyName]func(View, PropertyName){}
view.addCSS = map[string]string{}
//view.animation = map[string]AnimationEndListener{}
view.singleTransition = map[PropertyName]Animation{}
view.noResizeEvent = false
view.created = false
view.hasHtmlDisabled = 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
}
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
}
}
}
}
return false
}
func (view *viewData) Remove(tag PropertyName) {
tag = view.normalize(tag)
var changedTags []PropertyName = nil
switch tag {
case ID:
if view.viewID != "" {
view.viewID = ""
changedTags = []PropertyName{ID}
}
case AnimationTag:
if val := view.getRaw(AnimationTag); val != nil {
if animations, ok := val.([]Animation); ok {
for _, animation := range animations {
animation.unused(view.session)
}
}
view.setRaw(AnimationTag, nil)
changedTags = []PropertyName{AnimationTag}
}
default:
changedTags = view.remove(view, tag)
}
if view.created && len(changedTags) > 0 {
for _, tag := range changedTags {
view.changed(view, tag)
}
for _, tag := range changedTags {
if listener, ok := view.changeListener[tag]; ok {
listener(view, tag)
}
}
}
}
func (view *viewData) Set(tag PropertyName, value any) bool {
if value == nil {
view.Remove(tag)
return true
}
tag = view.normalize(tag)
var changedTags []PropertyName = nil
switch tag {
case ID:
text, ok := value.(string)
if !ok {
notCompatibleType(ID, value)
return false
}
view.viewID = text
changedTags = []PropertyName{ID}
case AnimationTag:
oldAnimations := []Animation{}
if val := view.getRaw(AnimationTag); val != nil {
if animation, ok := val.([]Animation); ok {
oldAnimations = animation
}
}
if !setAnimationProperty(view, tag, value) {
return false
}
for _, animation := range oldAnimations {
animation.unused(view.session)
}
changedTags = []PropertyName{AnimationTag}
default:
changedTags = viewSet(view, tag, value)
}
if view.created && len(changedTags) > 0 {
for _, tag := range changedTags {
view.changed(view, tag)
}
for _, tag := range changedTags {
if listener, ok := view.changeListener[tag]; ok {
listener(view, tag)
}
}
}
return changedTags != nil
}
func normalizeViewTag(tag PropertyName) PropertyName {
tag = normalizeViewStyleTag(tag)
switch tag {
case "tab-index":
return TabIndex
}
return tag
}
/*
func (view *viewData) propertyChangedEvent(tag PropertyName) {
if listener, ok := view.changeListener[tag]; ok {
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)
}
}
*/
func viewRemove(properties Properties, tag PropertyName) []PropertyName {
return viewStyleRemove(properties, tag)
}
func viewSet(view View, tag PropertyName, value any) []PropertyName {
switch tag {
case TabIndex, "tab-index":
return setIntProperty(view, TabIndex, value)
case UserData:
view.setRaw(tag, value)
return []PropertyName{UserData}
case Style, StyleDisabled:
if text, ok := value.(string); ok {
view.setRaw(tag, text)
return []PropertyName{tag}
}
notCompatibleType(ID, value)
return nil
case FocusEvent, LostFocusEvent:
return setNoParamEventListener[View](view, tag, value)
case KeyDownEvent, KeyUpEvent:
return setViewEventListener[View, KeyEvent](view, tag, value)
case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent:
return setViewEventListener[View, MouseEvent](view, tag, value)
case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel:
return setViewEventListener[View, PointerEvent](view, tag, value)
case TouchStart, TouchEnd, TouchMove, TouchCancel:
return setViewEventListener[View, TouchEvent](view, tag, value)
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent,
AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
return setViewEventListener[View, string](view, tag, value)
//return setTransitionListener(view, tag, value), tag
//return setAnimationListener(view, tag, value), tag
case ResizeEvent, ScrollEvent:
return setViewEventListener[View, Frame](view, tag, value)
//return setFrameListener(view, tag, value), tag
}
return viewStyleSet(view, tag, value)
}
func (view *viewData) SetParams(params Params) bool {
if params == nil {
errorLog("Argument of function SetParams is nil")
return false
}
session := view.Session()
session.startUpdateScript(view.htmlID())
result := true
for _, tag := range params.AllTags() {
if value, ok := params[tag]; ok {
result = view.Set(tag, value) && result
}
}
session.finishUpdateScript(view.htmlID())
return result
}
func viewPropertyChanged(view View, tag PropertyName) {
/*
if view.updateTransformProperty(tag) {
return
}
*/
htmlID := view.htmlID()
session := view.Session()
switch tag {
case TabIndex:
if value, ok := intProperty(view, TabIndex, view.Session(), 0); ok {
session.updateProperty(view.htmlID(), "tabindex", strconv.Itoa(value))
} else if view.Focusable() {
session.updateProperty(view.htmlID(), "tabindex", "0")
} else {
session.updateProperty(view.htmlID(), "tabindex", "-1")
}
case Style, StyleDisabled:
session.updateProperty(view.htmlID(), "class", view.htmlClass(IsDisabled(view)))
case Disabled:
tabIndex := GetTabIndex(view, htmlID)
enabledClass := view.htmlClass(false)
disabledClass := view.htmlClass(true)
session.startUpdateScript(htmlID)
if IsDisabled(view) {
session.updateProperty(htmlID, "data-disabled", "1")
if view.htmlDisabledProperty() {
session.updateProperty(htmlID, "disabled", true)
}
if tabIndex >= 0 {
session.updateProperty(htmlID, "tabindex", -1)
}
if enabledClass != disabledClass {
session.updateProperty(htmlID, "class", disabledClass)
}
} else {
session.updateProperty(htmlID, "data-disabled", "0")
if view.htmlDisabledProperty() {
session.removeProperty(htmlID, "disabled")
}
if tabIndex >= 0 {
session.updateProperty(htmlID, "tabindex", tabIndex)
}
if enabledClass != disabledClass {
session.updateProperty(htmlID, "class", enabledClass)
}
}
session.finishUpdateScript(htmlID)
updateInnerHTML(htmlID, session)
case Visibility:
switch GetVisibility(view) {
case Invisible:
session.updateCSSProperty(htmlID, string(Visibility), "hidden")
session.updateCSSProperty(htmlID, "display", "")
session.callFunc("hideTooltip")
case Gone:
session.updateCSSProperty(htmlID, string(Visibility), "hidden")
session.updateCSSProperty(htmlID, "display", "none")
session.callFunc("hideTooltip")
default:
session.updateCSSProperty(htmlID, string(Visibility), "visible")
session.updateCSSProperty(htmlID, "display", "")
}
case Background:
session.updateCSSProperty(htmlID, string(Background), backgroundCSS(view, session))
case Border, BorderLeft, BorderRight, BorderTop, BorderBottom:
cssWidth := ""
cssColor := ""
cssStyle := "none"
if border := getBorderProperty(view, Border); border != nil {
cssWidth = border.cssWidthValue(session)
cssColor = border.cssColorValue(session)
cssStyle = border.cssStyleValue(session)
}
session.updateCSSProperty(htmlID, string(BorderWidth), cssWidth)
session.updateCSSProperty(htmlID, string(BorderColor), cssColor)
session.updateCSSProperty(htmlID, string(BorderStyle), cssStyle)
case BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle:
if border := getBorderProperty(view, Border); border != nil {
session.updateCSSProperty(htmlID, string(BorderStyle), border.cssStyleValue(session))
}
case BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor:
if border := getBorderProperty(view, Border); border != nil {
session.updateCSSProperty(htmlID, string(BorderColor), border.cssColorValue(session))
}
case BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
if border := getBorderProperty(view, Border); border != nil {
session.updateCSSProperty(htmlID, string(BorderWidth), border.cssWidthValue(session))
}
case Outline, OutlineColor, OutlineStyle, OutlineWidth:
session.updateCSSProperty(htmlID, string(Outline), GetOutline(view).cssString(session))
case Shadow:
session.updateCSSProperty(htmlID, "box-shadow", shadowCSS(view, Shadow, session))
case TextShadow:
session.updateCSSProperty(htmlID, "text-shadow", shadowCSS(view, TextShadow, session))
case Radius, RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
radius := GetRadius(view)
session.updateCSSProperty(htmlID, "border-radius", radius.cssString(session))
case Margin, MarginTop, MarginRight, MarginBottom, MarginLeft,
"top-margin", "right-margin", "bottom-margin", "left-margin":
margin := GetMargin(view)
session.updateCSSProperty(htmlID, string(Margin), margin.cssString(session))
case Padding, PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
"top-padding", "right-padding", "bottom-padding", "left-padding":
padding := GetPadding(view)
session.updateCSSProperty(htmlID, string(Padding), padding.cssString(session))
case AvoidBreak:
if avoid, ok := boolProperty(view, AvoidBreak, session); ok {
if avoid {
session.updateCSSProperty(htmlID, "break-inside", "avoid")
} else {
session.updateCSSProperty(htmlID, "break-inside", "auto")
}
}
case Clip:
if clip := getClipShape(view, Clip, session); clip != nil && clip.valid(session) {
session.updateCSSProperty(htmlID, `clip-path`, clip.cssStyle(session))
} else {
session.updateCSSProperty(htmlID, `clip-path`, "none")
}
case ShapeOutside:
if clip := getClipShape(view, ShapeOutside, session); clip != nil && clip.valid(session) {
session.updateCSSProperty(htmlID, string(ShapeOutside), clip.cssStyle(session))
} else {
session.updateCSSProperty(htmlID, string(ShapeOutside), "none")
}
case Filter:
text := ""
if value := view.getRaw(Filter); value != nil {
if filter, ok := value.(ViewFilter); ok {
text = filter.cssStyle(session)
}
}
session.updateCSSProperty(htmlID, string(Filter), text)
case BackdropFilter:
text := ""
if value := view.getRaw(BackdropFilter); value != nil {
if filter, ok := value.(ViewFilter); ok {
text = filter.cssStyle(session)
}
}
if session.startUpdateScript(htmlID) {
defer session.finishUpdateScript(htmlID)
}
session.updateCSSProperty(htmlID, "-webkit-backdrop-filter", text)
session.updateCSSProperty(htmlID, string(BackdropFilter), text)
case FontName:
if font, ok := stringProperty(view, FontName, session); ok {
session.updateCSSProperty(htmlID, "font-family", font)
} else {
session.updateCSSProperty(htmlID, "font-family", "")
}
case Italic:
if state, ok := boolProperty(view, tag, session); ok {
if state {
session.updateCSSProperty(htmlID, "font-style", "italic")
} else {
session.updateCSSProperty(htmlID, "font-style", "normal")
}
} else {
session.updateCSSProperty(htmlID, "font-style", "")
}
case SmallCaps:
if state, ok := boolProperty(view, tag, session); ok {
if state {
session.updateCSSProperty(htmlID, "font-variant", "small-caps")
} else {
session.updateCSSProperty(htmlID, "font-variant", "normal")
}
} else {
session.updateCSSProperty(htmlID, "font-variant", "")
}
case Strikethrough, Overline, Underline:
session.updateCSSProperty(htmlID, "text-decoration", textDecorationCSS(view, session))
for _, tag2 := range []PropertyName{TextLineColor, TextLineStyle, TextLineThickness} {
viewPropertyChanged(view, tag2)
}
case Transition:
session.updateCSSProperty(htmlID, "transition", transitionCSS(view, session))
case AnimationTag:
session.updateCSSProperty(htmlID, "animation", animationCSS(view, session))
case AnimationPaused:
paused, ok := boolProperty(view, AnimationPaused, session)
if !ok {
session.updateCSSProperty(htmlID, `animation-play-state`, ``)
} else if paused {
session.updateCSSProperty(htmlID, `animation-play-state`, `paused`)
} else {
session.updateCSSProperty(htmlID, `animation-play-state`, `running`)
}
case ZIndex, Order, TabSize:
if i, ok := intProperty(view, tag, session, 0); ok {
session.updateCSSProperty(htmlID, string(tag), strconv.Itoa(i))
} else {
session.updateCSSProperty(htmlID, string(tag), "")
}
case Row, Column:
if parentID := view.parentHTMLID(); parentID != "" {
updateInnerHTML(parentID, session)
}
case UserSelect:
if session.startUpdateScript(htmlID) {
defer session.finishUpdateScript(htmlID)
}
if userSelect, ok := boolProperty(view, UserSelect, session); ok {
if userSelect {
session.updateCSSProperty(htmlID, "-webkit-user-select", "auto")
session.updateCSSProperty(htmlID, "user-select", "auto")
} else {
session.updateCSSProperty(htmlID, "-webkit-user-select", "none")
session.updateCSSProperty(htmlID, "user-select", "none")
}
} else {
session.updateCSSProperty(htmlID, "-webkit-user-select", "")
session.updateCSSProperty(htmlID, "user-select", "")
}
case ColumnSpanAll:
if spanAll, ok := boolProperty(view, ColumnSpanAll, session); ok && spanAll {
session.updateCSSProperty(htmlID, `column-span`, `all`)
} else {
session.updateCSSProperty(htmlID, `column-span`, `none`)
}
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)")
}
case PerspectiveOriginX, PerspectiveOriginY:
if getTransform3D(view, session) {
x, y := GetPerspectiveOrigin(view)
value := ""
if x.Type != Auto || y.Type != Auto {
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
}
session.updateCSSProperty(htmlID, "perspective-origin", value)
}
case BackfaceVisible:
if getTransform3D(view, session) {
if GetBackfaceVisible(view) {
session.updateCSSProperty(htmlID, string(BackfaceVisible), "visible")
} else {
session.updateCSSProperty(htmlID, string(BackfaceVisible), "hidden")
}
}
case OriginX, OriginY, OriginZ:
x, y, z := getOrigin(view, session)
value := ""
if z.Type != Auto {
value = x.cssString("50%", session) + " " + y.cssString("50%", session) + " " + z.cssString("50%", session)
} else if x.Type != Auto || y.Type != Auto {
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
}
session.updateCSSProperty(htmlID, "transform-origin", value)
case TransformTag, Perspective, SkewX, SkewY, TranslateX, TranslateY, TranslateZ,
ScaleX, ScaleY, ScaleZ, Rotate, RotateX, RotateY, RotateZ:
css := ""
if transform := getTransformProperty(view); transform != nil {
css = transform.transformCSS(session)
}
session.updateCSSProperty(htmlID, "transform", css)
case FocusEvent, LostFocusEvent, ResizeEvent, ScrollEvent, KeyDownEvent, KeyUpEvent,
ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent,
PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel,
TouchStart, TouchEnd, TouchMove, TouchCancel,
TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent,
AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
updateEventListenerHtml(view, tag)
case DataList:
updateInnerHTML(view.htmlID(), view.Session())
default:
if cssTag, ok := sizeProperties[tag]; ok {
if size, ok := sizeProperty(view, tag, session); ok {
session.updateCSSProperty(htmlID, cssTag, size.cssString("", session))
} else {
session.updateCSSProperty(htmlID, cssTag, "")
}
return
}
colorTags := map[PropertyName]string{
BackgroundColor: string(BackgroundColor),
TextColor: "color",
TextLineColor: "text-decoration-color",
CaretColor: string(CaretColor),
AccentColor: string(AccentColor),
}
if cssTag, ok := colorTags[tag]; ok {
if color, ok := colorProperty(view, tag, session); ok {
session.updateCSSProperty(htmlID, cssTag, color.cssString())
} else {
session.updateCSSProperty(htmlID, cssTag, "")
}
return
}
if valuesData, ok := enumProperties[tag]; ok && valuesData.cssTag != "" {
if n, ok := enumProperty(view, tag, session, 0); ok {
session.updateCSSProperty(htmlID, valuesData.cssTag, valuesData.cssValues[n])
} else {
session.updateCSSProperty(htmlID, valuesData.cssTag, "")
}
return
}
if f, ok := floatTextProperty(view, Opacity, session, 0); ok {
session.updateCSSProperty(htmlID, string(Opacity), f)
} else {
session.updateCSSProperty(htmlID, string(Opacity), "")
}
}
}
func viewGet(view View, tag PropertyName) any {
if tag == ID {
if id := view.ID(); id != "" {
return id
} else {
return nil
}
}
return viewStyleGet(view, tag)
}
func (view *viewData) htmlTag() string {
if semantics := GetSemantics(view); semantics > DefaultSemantics {
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) {
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) htmlDisabledProperty() bool {
return view.hasHtmlDisabled
}
func (view *viewData) htmlProperties(self View, buffer *strings.Builder) {
view.created = true
if IsDisabled(self) {
buffer.WriteString(` data-disabled="1"`)
if view.hasHtmlDisabled {
buffer.WriteString(` disabled`)
}
} else {
buffer.WriteString(` data-disabled="0"`)
}
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 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)
if cls := view.htmlClass(disabled); cls != "" {
buffer.WriteString(` class="`)
buffer.WriteString(cls)
buffer.WriteRune('"')
}
cssBuilder := viewCSSBuilder{buffer: allocStringBuilder()}
view.cssStyle(view, &cssBuilder)
if style := cssBuilder.finish(); style != "" {
buffer.WriteString(` style="`)
buffer.WriteString(style)
buffer.WriteRune('"')
}
buffer.WriteRune(' ')
view.htmlProperties(view, buffer)
if view.isNoResizeEvent() {
buffer.WriteString(` data-noresize="1" `)
} else {
buffer.WriteRune(' ')
}
if !disabled {
if tabIndex := GetTabIndex(view); tabIndex >= 0 {
buffer.WriteString(`tabindex="`)
buffer.WriteString(strconv.Itoa(tabIndex))
buffer.WriteString(`" `)
}
}
if tooltip := GetTooltip(view); tooltip != "" {
buffer.WriteString(`data-tooltip=" `)
buffer.WriteString(tooltip)
buffer.WriteString(`" onmouseenter="mouseEnterEvent(this, event)" onmouseleave="mouseLeaveEvent(this, event)" `)
}
buffer.WriteString(`onscroll="scrollEvent(this, event)" `)
focusEventsHtml(view, buffer)
keyEventsHtml(view, buffer)
viewEventsHtml[MouseEvent](view, []PropertyName{ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent}, buffer)
//mouseEventsHtml(view, buffer, hasTooltip)
viewEventsHtml[PointerEvent](view, []PropertyName{PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel}, buffer)
//pointerEventsHtml(view, buffer)
viewEventsHtml[TouchEvent](view, []PropertyName{TouchStart, TouchEnd, TouchMove, TouchCancel}, buffer)
//touchEventsHtml(view, buffer)
viewEventsHtml[string](view, []PropertyName{TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent,
AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent}, buffer)
//transitionEventsHtml(view, buffer)
//animationEventsHtml(view, buffer)
buffer.WriteRune('>')
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 PropertyName, data DataObject) bool {
switch command {
case KeyDownEvent, KeyUpEvent:
if !IsDisabled(self) {
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 getNoParamEventListeners[View](view, nil, command) {
listener(self)
}
case LostFocusEvent:
view.hasFocus = false
for _, listener := range getNoParamEventListeners[View](view, nil, command) {
listener(self)
}
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
view.handleTransitionEvents(command, data)
case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
view.handleAnimationEvents(command, data)
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 PropertyName, listener func(View, PropertyName)) {
if listener == nil {
delete(view.changeListener, tag)
} else {
view.changeListener[tag] = listener
}
}
func (view *viewData) HasFocus() bool {
return view.hasFocus
}
func (view *viewData) String() string {
buffer := allocStringBuilder()
defer freeStringBuilder(buffer)
writeViewStyle(view.tag, view, buffer, "", nil)
return buffer.String()
}
func (view *viewData) exscludeTags() []PropertyName {
return nil
}