forked from mbk-lab/rui_orig
2
0
Fork 0

Bug fixing

This commit is contained in:
Alexei Anoshenko 2022-05-22 12:54:02 +03:00
parent fcea1c89a3
commit 9478b1ee4f
41 changed files with 887 additions and 567 deletions

View File

@ -124,7 +124,7 @@ type animationData struct {
type Animation interface { type Animation interface {
Properties Properties
fmt.Stringer fmt.Stringer
ruiStringer writeTransitionString(tag string, buffer *strings.Builder)
animationCSS(session Session) string animationCSS(session Session) string
transitionCSS(buffer *strings.Builder, session Session) transitionCSS(buffer *strings.Builder, session Session)
hasAnimatedPropery() bool hasAnimatedPropery() bool
@ -176,13 +176,21 @@ func (animation *animationData) animationName() string {
return animation.keyFramesName return animation.keyFramesName
} }
func (animation *animationData) normalizeTag(tag string) string {
tag = strings.ToLower(tag)
if tag == Direction {
return AnimationDirection
}
return tag
}
func (animation *animationData) Set(tag string, value interface{}) bool { func (animation *animationData) Set(tag string, value interface{}) bool {
if value == nil { if value == nil {
animation.Remove(tag) animation.Remove(tag)
return true return true
} }
switch tag = strings.ToLower(tag); tag { switch tag = animation.normalizeTag(tag); tag {
case ID: case ID:
if text, ok := value.(string); ok { if text, ok := value.(string); ok {
text = strings.Trim(text, " \t\n\r") text = strings.Trim(text, " \t\n\r")
@ -337,7 +345,7 @@ func (animation *animationData) Set(tag string, value interface{}) bool {
case IterationCount: case IterationCount:
return animation.setIntProperty(tag, value) return animation.setIntProperty(tag, value)
case AnimationDirection, Direction: case AnimationDirection:
return animation.setEnumProperty(AnimationDirection, value, enumProperties[AnimationDirection].values) return animation.setEnumProperty(AnimationDirection, value, enumProperties[AnimationDirection].values)
default: default:
@ -348,31 +356,23 @@ func (animation *animationData) Set(tag string, value interface{}) bool {
} }
func (animation *animationData) Remove(tag string) { func (animation *animationData) Remove(tag string) {
tag = strings.ToLower(tag) delete(animation.properties, animation.normalizeTag(tag))
if tag == Direction {
tag = AnimationDirection
}
delete(animation.properties, tag)
} }
func (animation *animationData) Get(tag string) interface{} { func (animation *animationData) Get(tag string) interface{} {
tag = strings.ToLower(tag) return animation.getRaw(animation.normalizeTag(tag))
if tag == Direction {
tag = AnimationDirection
}
return animation.getRaw(tag)
} }
func (animation *animationData) String() string { func (animation *animationData) String() string {
writer := newRUIWriter() buffer := allocStringBuilder()
animation.ruiString(writer) defer freeStringBuilder(buffer)
return writer.finish()
} buffer.WriteString("animation {")
func (animation *animationData) ruiString(writer ruiWriter) {
writer.startObject("animation")
// TODO // TODO
writer.endObject()
buffer.WriteString("}")
return buffer.String()
} }
func (animation *animationData) animationCSS(session Session) string { func (animation *animationData) animationCSS(session Session) string {
@ -448,6 +448,46 @@ func (animation *animationData) transitionCSS(buffer *strings.Builder, session S
} }
} }
func (animation *animationData) writeTransitionString(tag string, buffer *strings.Builder) {
buffer.WriteString(tag)
buffer.WriteString("{")
lead := " "
writeFloatProperty := func(name string) bool {
if value := animation.getRaw(name); value != nil {
buffer.WriteString(lead)
buffer.WriteString(name)
buffer.WriteString(" = ")
writePropertyValue(buffer, name, value, "")
lead = ", "
return true
}
return false
}
if !writeFloatProperty(Duration) {
buffer.WriteString(" duration = 1")
lead = ", "
}
writeFloatProperty(Delay)
if value := animation.getRaw(TimingFunction); value != nil {
if timingFunction, ok := value.(string); ok && timingFunction != "" {
buffer.WriteString(lead)
buffer.WriteString(TimingFunction)
buffer.WriteString(" = ")
if strings.ContainsAny(timingFunction, " ,()") {
buffer.WriteRune('"')
buffer.WriteString(timingFunction)
buffer.WriteRune('"')
}
}
}
buffer.WriteString(" }")
}
func (animation *animationData) timingFunctionCSS(session Session) string { func (animation *animationData) timingFunctionCSS(session Session) string {
if timingFunction, ok := stringProperty(animation, TimingFunction, session); ok { if timingFunction, ok := stringProperty(animation, TimingFunction, session); ok {
if timingFunction, ok = session.resolveConstants(timingFunction); ok && validateTimingFunction(timingFunction) { if timingFunction, ok = session.resolveConstants(timingFunction); ok && validateTimingFunction(timingFunction) {

View File

@ -26,6 +26,10 @@ func (player *audioPlayerData) Init(session Session) {
player.tag = "AudioPlayer" player.tag = "AudioPlayer"
} }
func (player *audioPlayerData) String() string {
return getViewString(player)
}
func (player *audioPlayerData) htmlTag() string { func (player *audioPlayerData) htmlTag() string {
return "audio" return "audio"
} }

View File

@ -48,8 +48,8 @@ const (
// BorderProperty is the interface of a view border data // BorderProperty is the interface of a view border data
type BorderProperty interface { type BorderProperty interface {
Properties Properties
ruiStringer
fmt.Stringer fmt.Stringer
stringWriter
ViewBorders(session Session) ViewBorders ViewBorders(session Session) ViewBorders
delete(tag string) delete(tag string)
cssStyle(builder cssBuilder, session Session) cssStyle(builder cssBuilder, session Session)
@ -202,12 +202,23 @@ func (border *borderProperty) normalizeTag(tag string) string {
return tag return tag
} }
func (border *borderProperty) ruiString(writer ruiWriter) { func (border *borderProperty) writeString(buffer *strings.Builder, indent string) {
writer.startObject("_") buffer.WriteString("_{ ")
comma := false
write := func(tag string, value interface{}) {
if comma {
buffer.WriteString(", ")
}
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, BorderStyle, value, indent)
comma = true
}
for _, tag := range []string{Style, Width, ColorTag} { for _, tag := range []string{Style, Width, ColorTag} {
if value, ok := border.properties[tag]; ok { if value, ok := border.properties[tag]; ok {
writer.writeProperty(Style, value) write(tag, value)
} }
} }
@ -216,27 +227,32 @@ func (border *borderProperty) ruiString(writer ruiWriter) {
width, okWidth := border.properties[side+"-"+Width] width, okWidth := border.properties[side+"-"+Width]
color, okColor := border.properties[side+"-"+ColorTag] color, okColor := border.properties[side+"-"+ColorTag]
if okStyle || okWidth || okColor { if okStyle || okWidth || okColor {
writer.startObjectProperty(side, "_") if comma {
buffer.WriteString(", ")
comma = false
}
buffer.WriteString(side)
buffer.WriteString(" = _{ ")
if okStyle { if okStyle {
writer.writeProperty(Style, style) write(Style, style)
} }
if okWidth { if okWidth {
writer.writeProperty(Width, width) write(Width, width)
} }
if okColor { if okColor {
writer.writeProperty(ColorTag, color) write(ColorTag, color)
} }
writer.endObject() buffer.WriteString(" }")
comma = true
} }
} }
// TODO
writer.endObject() buffer.WriteString(" }")
} }
func (border *borderProperty) String() string { func (border *borderProperty) String() string {
writer := newRUIWriter() return runStringWriter(border)
border.ruiString(writer)
return writer.finish()
} }
func (border *borderProperty) setSingleBorderObject(prefix string, obj DataObject) bool { func (border *borderProperty) setSingleBorderObject(prefix string, obj DataObject) bool {

View File

@ -8,8 +8,8 @@ import (
// BorderProperty is the interface of a bounds property data // BorderProperty is the interface of a bounds property data
type BoundsProperty interface { type BoundsProperty interface {
Properties Properties
ruiStringer
fmt.Stringer fmt.Stringer
stringWriter
Bounds(session Session) Bounds Bounds(session Session) Bounds
} }
@ -54,22 +54,25 @@ func (bounds *boundsPropertyData) normalizeTag(tag string) string {
return tag return tag
} }
func (bounds *boundsPropertyData) ruiString(writer ruiWriter) { func (bounds *boundsPropertyData) String() string {
writer.startObject("_") return runStringWriter(bounds)
for _, tag := range []string{Top, Right, Bottom, Left} {
if value, ok := bounds.properties[tag]; ok {
writer.writeProperty(Style, value)
}
}
writer.endObject()
} }
func (bounds *boundsPropertyData) String() string { func (bounds *boundsPropertyData) writeString(buffer *strings.Builder, indent string) {
writer := newRUIWriter() buffer.WriteString("_{ ")
bounds.ruiString(writer) comma := false
return writer.finish() for _, tag := range []string{Top, Right, Bottom, Left} {
if value, ok := bounds.properties[tag]; ok {
if comma {
buffer.WriteString(", ")
}
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, tag, value, indent)
comma = true
}
}
buffer.WriteString(" }")
} }
func (bounds *boundsPropertyData) Remove(tag string) { func (bounds *boundsPropertyData) Remove(tag string) {
@ -135,50 +138,6 @@ func (bounds *Bounds) SetAll(value SizeUnit) {
bounds.Left = value bounds.Left = value
} }
func (bounds *Bounds) parse(value string, session Session) bool {
var ok bool
if value, ok = session.resolveConstants(value); !ok {
return false
}
values := strings.Split(value, ",")
switch len(values) {
case 1:
if bounds.Left, ok = StringToSizeUnit(values[0]); !ok {
return false
}
bounds.Right.Type = bounds.Left.Type
bounds.Right.Value = bounds.Left.Value
bounds.Top.Type = bounds.Left.Type
bounds.Top.Value = bounds.Left.Value
bounds.Bottom.Type = bounds.Left.Type
bounds.Bottom.Value = bounds.Left.Value
return true
case 5:
if values[4] != "" {
ErrorLog("invalid Bounds value '" + value + "' (needs 1 or 4 elements separeted by comma)")
return false
}
fallthrough
case 4:
if bounds.Top, ok = StringToSizeUnit(values[0]); ok {
if bounds.Right, ok = StringToSizeUnit(values[1]); ok {
if bounds.Bottom, ok = StringToSizeUnit(values[2]); ok {
if bounds.Left, ok = StringToSizeUnit(values[3]); ok {
return true
}
}
}
}
return false
}
ErrorLog("invalid Bounds value '" + value + "' (needs 1 or 4 elements separeted by comma)")
return false
}
func (bounds *Bounds) setFromProperties(tag, topTag, rightTag, bottomTag, leftTag string, properties Properties, session Session) { func (bounds *Bounds) setFromProperties(tag, topTag, rightTag, bottomTag, leftTag string, properties Properties, session Session) {
bounds.Top = AutoSize() bounds.Top = AutoSize()
if size, ok := sizeProperty(properties, tag, session); ok { if size, ok := sizeProperty(properties, tag, session); ok {
@ -202,6 +161,7 @@ func (bounds *Bounds) setFromProperties(tag, topTag, rightTag, bottomTag, leftTa
} }
} }
/*
func (bounds *Bounds) allFieldsAuto() bool { func (bounds *Bounds) allFieldsAuto() bool {
return bounds.Left.Type == Auto && return bounds.Left.Type == Auto &&
bounds.Top.Type == Auto && bounds.Top.Type == Auto &&
@ -209,7 +169,6 @@ func (bounds *Bounds) allFieldsAuto() bool {
bounds.Bottom.Type == Auto bounds.Bottom.Type == Auto
} }
/*
func (bounds *Bounds) allFieldsZero() bool { func (bounds *Bounds) allFieldsZero() bool {
return (bounds.Left.Type == Auto || bounds.Left.Value == 0) && return (bounds.Left.Type == Auto || bounds.Left.Value == 0) &&
(bounds.Top.Type == Auto || bounds.Top.Value == 0) && (bounds.Top.Type == Auto || bounds.Top.Value == 0) &&
@ -231,6 +190,7 @@ func (bounds *Bounds) allFieldsEqual() bool {
return false return false
} }
/*
func (bounds Bounds) writeCSSString(buffer *strings.Builder, textForAuto string) { func (bounds Bounds) writeCSSString(buffer *strings.Builder, textForAuto string) {
buffer.WriteString(bounds.Top.cssString(textForAuto)) buffer.WriteString(bounds.Top.cssString(textForAuto))
if !bounds.allFieldsEqual() { if !bounds.allFieldsEqual() {
@ -242,6 +202,7 @@ func (bounds Bounds) writeCSSString(buffer *strings.Builder, textForAuto string)
buffer.WriteString(bounds.Left.cssString(textForAuto)) buffer.WriteString(bounds.Left.cssString(textForAuto))
} }
} }
*/
// String convert Bounds to string // String convert Bounds to string
func (bounds *Bounds) String() string { func (bounds *Bounds) String() string {

View File

@ -36,6 +36,10 @@ func (canvasView *canvasViewData) Init(session Session) {
canvasView.tag = "CanvasView" canvasView.tag = "CanvasView"
} }
func (canvasView *canvasViewData) String() string {
return getViewString(canvasView)
}
func (canvasView *canvasViewData) normalizeTag(tag string) string { func (canvasView *canvasViewData) normalizeTag(tag string) string {
tag = strings.ToLower(tag) tag = strings.ToLower(tag)
switch tag { switch tag {

View File

@ -43,6 +43,10 @@ func (button *checkboxData) Init(session Session) {
button.checkedListeners = []func(Checkbox, bool){} button.checkedListeners = []func(Checkbox, bool){}
} }
func (button *checkboxData) String() string {
return getViewString(button)
}
func (button *checkboxData) Focusable() bool { func (button *checkboxData) Focusable() bool {
return true return true
} }

View File

@ -39,6 +39,10 @@ func (picker *colorPickerData) Init(session Session) {
picker.properties[Padding] = Px(0) picker.properties[Padding] = Px(0)
} }
func (picker *colorPickerData) String() string {
return getViewString(picker)
}
func (picker *colorPickerData) normalizeTag(tag string) string { func (picker *colorPickerData) normalizeTag(tag string) string {
tag = strings.ToLower(tag) tag = strings.ToLower(tag)
switch tag { switch tag {

View File

@ -63,6 +63,10 @@ func (ColumnLayout *columnLayoutData) Init(session Session) {
//ColumnLayout.systemClass = "ruiColumnLayout" //ColumnLayout.systemClass = "ruiColumnLayout"
} }
func (columnLayout *columnLayoutData) String() string {
return getViewString(columnLayout)
}
func (columnLayout *columnLayoutData) normalizeTag(tag string) string { func (columnLayout *columnLayoutData) normalizeTag(tag string) string {
tag = strings.ToLower(tag) tag = strings.ToLower(tag)
switch tag { switch tag {

View File

@ -8,8 +8,8 @@ import (
// ColumnSeparatorProperty is the interface of a view separator data // ColumnSeparatorProperty is the interface of a view separator data
type ColumnSeparatorProperty interface { type ColumnSeparatorProperty interface {
Properties Properties
ruiStringer
fmt.Stringer fmt.Stringer
stringWriter
ViewBorder(session Session) ViewBorder ViewBorder(session Session) ViewBorder
cssValue(session Session) string cssValue(session Session) string
} }
@ -84,20 +84,26 @@ func (separator *columnSeparatorProperty) normalizeTag(tag string) string {
return tag return tag
} }
func (separator *columnSeparatorProperty) ruiString(writer ruiWriter) { func (separator *columnSeparatorProperty) writeString(buffer *strings.Builder, indent string) {
writer.startObject("_") buffer.WriteString("_{ ")
comma := false
for _, tag := range []string{Style, Width, ColorTag} { for _, tag := range []string{Style, Width, ColorTag} {
if value, ok := separator.properties[tag]; ok { if value, ok := separator.properties[tag]; ok {
writer.writeProperty(Style, value) if comma {
buffer.WriteString(", ")
}
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, BorderStyle, value, indent)
comma = true
} }
} }
writer.endObject()
buffer.WriteString(" }")
} }
func (separator *columnSeparatorProperty) String() string { func (separator *columnSeparatorProperty) String() string {
writer := newRUIWriter() return runStringWriter(separator)
separator.ruiString(writer)
return writer.finish()
} }
func (separator *columnSeparatorProperty) Remove(tag string) { func (separator *columnSeparatorProperty) Remove(tag string) {

View File

@ -91,6 +91,10 @@ func (customView *CustomViewData) Clear() {
func (customView *CustomViewData) Init(session Session) { func (customView *CustomViewData) Init(session Session) {
} }
func (customView *CustomViewData) cssViewStyle(buffer cssBuilder, session Session) {
customView.superView.cssViewStyle(buffer, session)
}
// Session returns a current Session interface // Session returns a current Session interface
func (customView *CustomViewData) Session() Session { func (customView *CustomViewData) Session() Session {
return customView.superView.Session() return customView.superView.Session()
@ -249,19 +253,11 @@ func (customView *CustomViewData) RemoveView(index int) View {
func (customView *CustomViewData) String() string { func (customView *CustomViewData) String() string {
if customView.superView != nil { if customView.superView != nil {
writer := newRUIWriter() return getViewString(customView)
customView.ruiString(writer)
return writer.finish()
} }
return customView.tag + " { }" return customView.tag + " { }"
} }
func (customView *CustomViewData) ruiString(writer ruiWriter) {
if customView.superView != nil {
ruiViewString(customView.superView, customView.tag, writer)
}
}
func (customView *CustomViewData) setScroll(x, y, width, height float64) { func (customView *CustomViewData) setScroll(x, y, width, height float64) {
if customView.superView != nil { if customView.superView != nil {
customView.superView.setScroll(x, y, width, height) customView.superView.setScroll(x, y, width, height)

View File

@ -44,6 +44,10 @@ func (picker *datePickerData) Init(session Session) {
picker.dateChangedListeners = []func(DatePicker, time.Time){} picker.dateChangedListeners = []func(DatePicker, time.Time){}
} }
func (picker *datePickerData) String() string {
return getViewString(picker)
}
func (picker *datePickerData) Focusable() bool { func (picker *datePickerData) Focusable() bool {
return true return true
} }

View File

@ -117,6 +117,14 @@ func (detailsView *detailsViewData) set(tag string, value interface{}) bool {
} }
} }
case NotTranslate:
if !detailsView.viewData.set(tag, value) {
return false
}
if detailsView.created {
updateInnerHTML(detailsView.htmlID(), detailsView.Session())
}
default: default:
return detailsView.viewsContainerData.Set(tag, value) return detailsView.viewsContainerData.Set(tag, value)
} }
@ -149,6 +157,9 @@ func (detailsView *detailsViewData) htmlSubviews(self View, buffer *strings.Buil
if value, ok := detailsView.properties[Summary]; ok { if value, ok := detailsView.properties[Summary]; ok {
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if !GetNotTranslate(detailsView, "") {
value, _ = detailsView.session.GetString(value)
}
buffer.WriteString("<summary>") buffer.WriteString("<summary>")
buffer.WriteString(value) buffer.WriteString(value)
buffer.WriteString("</summary>") buffer.WriteString("</summary>")

View File

@ -41,6 +41,10 @@ func (list *dropDownListData) Init(session Session) {
list.dropDownListener = []func(DropDownList, int){} list.dropDownListener = []func(DropDownList, int){}
} }
func (list *dropDownListData) String() string {
return getViewString(list)
}
func (list *dropDownListData) Focusable() bool { func (list *dropDownListData) Focusable() bool {
return true return true
} }

View File

@ -63,6 +63,10 @@ func (edit *editViewData) Init(session Session) {
edit.tag = "EditView" edit.tag = "EditView"
} }
func (edit *editViewData) String() string {
return getViewString(edit)
}
func (edit *editViewData) Focusable() bool { func (edit *editViewData) Focusable() bool {
return true return true
} }

View File

@ -89,6 +89,10 @@ func (picker *filePickerData) Init(session Session) {
picker.fileSelectedListeners = []func(FilePicker, []FileInfo){} picker.fileSelectedListeners = []func(FilePicker, []FileInfo){}
} }
func (picker *filePickerData) String() string {
return getViewString(picker)
}
func (picker *filePickerData) Focusable() bool { func (picker *filePickerData) Focusable() bool {
return true return true
} }

View File

@ -33,6 +33,10 @@ func (gridLayout *gridLayoutData) Init(session Session) {
gridLayout.systemClass = "ruiGridLayout" gridLayout.systemClass = "ruiGridLayout"
} }
func (gridLayout *gridLayoutData) String() string {
return getViewString(gridLayout)
}
func (style *viewStyle) setGridCellSize(tag string, value interface{}) bool { func (style *viewStyle) setGridCellSize(tag string, value interface{}) bool {
setValues := func(values []string) bool { setValues := func(values []string) bool {
count := len(values) count := len(values)

View File

@ -55,6 +55,10 @@ func (imageView *imageViewData) Init(session Session) {
} }
func (imageView *imageViewData) String() string {
return getViewString(imageView)
}
func (imageView *imageViewData) normalizeTag(tag string) string { func (imageView *imageViewData) normalizeTag(tag string) string {
tag = strings.ToLower(tag) tag = strings.ToLower(tag)
switch tag { switch tag {

View File

@ -49,6 +49,10 @@ func (listLayout *listLayoutData) Init(session Session) {
listLayout.systemClass = "ruiListLayout" listLayout.systemClass = "ruiListLayout"
} }
func (listLayout *listLayoutData) String() string {
return getViewString(listLayout)
}
func (listLayout *listLayoutData) Remove(tag string) { func (listLayout *listLayoutData) Remove(tag string) {
listLayout.remove(strings.ToLower(tag)) listLayout.remove(strings.ToLower(tag))
} }

View File

@ -91,6 +91,10 @@ func (listView *listViewData) Init(session Session) {
listView.checkedListeners = []func(ListView, []int){} listView.checkedListeners = []func(ListView, []int){}
} }
func (listView *listViewData) String() string {
return getViewString(listView)
}
func (listView *listViewData) Views() []View { func (listView *listViewData) Views() []View {
return listView.items return listView.items
} }

View File

@ -168,6 +168,10 @@ func (player *mediaPlayerData) Init(session Session) {
player.tag = "MediaPlayer" player.tag = "MediaPlayer"
} }
func (player *mediaPlayerData) String() string {
return getViewString(player)
}
func (player *mediaPlayerData) Focusable() bool { func (player *mediaPlayerData) Focusable() bool {
return true return true
} }

View File

@ -51,6 +51,10 @@ func (picker *numberPickerData) Init(session Session) {
picker.numberChangedListeners = []func(NumberPicker, float64){} picker.numberChangedListeners = []func(NumberPicker, float64){}
} }
func (picker *numberPickerData) String() string {
return getViewString(picker)
}
func (picker *numberPickerData) Focusable() bool { func (picker *numberPickerData) Focusable() bool {
return true return true
} }

View File

@ -7,7 +7,7 @@ import (
type OutlineProperty interface { type OutlineProperty interface {
Properties Properties
ruiStringer stringWriter
fmt.Stringer fmt.Stringer
ViewOutline(session Session) ViewOutline ViewOutline(session Session) ViewOutline
} }
@ -25,22 +25,26 @@ func NewOutlineProperty(params Params) OutlineProperty {
return outline return outline
} }
func (outline *outlinePropertyData) ruiString(writer ruiWriter) { func (outline *outlinePropertyData) writeString(buffer *strings.Builder, indent string) {
writer.startObject("_") buffer.WriteString("_{ ")
comma := false
for _, tag := range []string{Style, Width, ColorTag} { for _, tag := range []string{Style, Width, ColorTag} {
if value, ok := outline.properties[tag]; ok { if value, ok := outline.properties[tag]; ok {
writer.writeProperty(Style, value) if comma {
buffer.WriteString(", ")
}
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, BorderStyle, value, indent)
comma = true
} }
} }
writer.endObject() buffer.WriteString(" }")
} }
func (outline *outlinePropertyData) String() string { func (outline *outlinePropertyData) String() string {
writer := newRUIWriter() return runStringWriter(outline)
outline.ruiString(writer)
return writer.finish()
} }
func (outline *outlinePropertyData) normalizeTag(tag string) string { func (outline *outlinePropertyData) normalizeTag(tag string) string {

View File

@ -36,6 +36,10 @@ func (progress *progressBarData) Init(session Session) {
progress.tag = "ProgressBar" progress.tag = "ProgressBar"
} }
func (progress *progressBarData) String() string {
return getViewString(progress)
}
func (progress *progressBarData) normalizeTag(tag string) string { func (progress *progressBarData) normalizeTag(tag string) string {
tag = strings.ToLower(tag) tag = strings.ToLower(tag)
switch tag { switch tag {

View File

@ -97,7 +97,7 @@ const (
type RadiusProperty interface { type RadiusProperty interface {
Properties Properties
ruiStringer stringWriter
fmt.Stringer fmt.Stringer
BoxRadius(session Session) BoxRadius BoxRadius(session Session) BoxRadius
} }
@ -125,23 +125,27 @@ func (radius *radiusPropertyData) normalizeTag(tag string) string {
return strings.TrimPrefix(strings.ToLower(tag), "radius-") return strings.TrimPrefix(strings.ToLower(tag), "radius-")
} }
func (radius *radiusPropertyData) ruiString(writer ruiWriter) { func (radius *radiusPropertyData) writeString(buffer *strings.Builder, indent string) {
writer.startObject("_") buffer.WriteString("_{ ")
comma := false
for _, tag := range []string{X, Y, TopLeft, TopLeftX, TopLeftY, TopRight, TopRightX, TopRightY, for _, tag := range []string{X, Y, TopLeft, TopLeftX, TopLeftY, TopRight, TopRightX, TopRightY,
BottomLeft, BottomLeftX, BottomLeftY, BottomRight, BottomRightX, BottomRightY} { BottomLeft, BottomLeftX, BottomLeftY, BottomRight, BottomRightX, BottomRightY} {
if value, ok := radius.properties[tag]; ok { if value, ok := radius.properties[tag]; ok {
writer.writeProperty(Style, value) if comma {
buffer.WriteString(", ")
}
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, tag, value, indent)
comma = true
} }
} }
writer.endObject() buffer.WriteString(" }")
} }
func (radius *radiusPropertyData) String() string { func (radius *radiusPropertyData) String() string {
writer := newRUIWriter() return runStringWriter(radius)
radius.ruiString(writer)
return writer.finish()
} }
func (radius *radiusPropertyData) delete(tags []string) { func (radius *radiusPropertyData) delete(tags []string) {

View File

@ -61,6 +61,10 @@ func (resizable *resizableData) Init(session Session) {
resizable.content = []View{} resizable.content = []View{}
} }
func (resizable *resizableData) String() string {
return getViewString(resizable)
}
func (resizable *resizableData) Views() []View { func (resizable *resizableData) Views() []View {
return resizable.content return resizable.content
} }

View File

@ -1,5 +1,6 @@
package rui package rui
/*
import ( import (
"fmt" "fmt"
"strconv" "strconv"
@ -10,6 +11,8 @@ type ruiWriter interface {
startObject(tag string) startObject(tag string)
startObjectProperty(tag, objectTag string) startObjectProperty(tag, objectTag string)
endObject() endObject()
startArrayProperty(tag string)
endObArray()
writeProperty(tag string, value interface{}) writeProperty(tag string, value interface{})
finish() string finish() string
} }
@ -41,23 +44,22 @@ func (writer *ruiWriterData) writeIndent() {
} }
func (writer *ruiWriterData) writeString(str string) { func (writer *ruiWriterData) writeString(str string) {
esc := map[string]string{"\t": `\t`, "\r": `\r`, "\n": `\n`, "\"": `"`} hasEsc := strings.ContainsAny(str, "\t\"\r\n")
hasEsc := false if hasEsc || strings.ContainsAny(str, " ,;'`[]{}()") {
for s := range esc {
if strings.Contains(str, s) {
hasEsc = true
break
}
}
if hasEsc || strings.Contains(str, " ") || strings.Contains(str, ",") {
if !strings.Contains(str, "`") && (hasEsc || strings.Contains(str, `\`)) { if !strings.Contains(str, "`") && (hasEsc || strings.Contains(str, `\`)) {
writer.buffer.WriteRune('`') writer.buffer.WriteRune('`')
writer.buffer.WriteString(str) writer.buffer.WriteString(str)
writer.buffer.WriteRune('`') writer.buffer.WriteRune('`')
} else { } else {
str = strings.Replace(str, `\`, `\\`, -1) replace := []struct{ old, new string }{
for oldStr, newStr := range esc { {old: `\`, new: `\\`},
str = strings.Replace(str, oldStr, newStr, -1) {old: "\t", new: `\t`},
{old: "\r", new: `\r`},
{old: "\n", new: `\n`},
{old: "\"", new: `\"`},
}
for _, s := range replace {
str = strings.Replace(str, s.old, s.new, -1)
} }
writer.buffer.WriteRune('"') writer.buffer.WriteRune('"')
writer.buffer.WriteString(str) writer.buffer.WriteString(str)
@ -80,6 +82,9 @@ func (writer *ruiWriterData) startObjectProperty(tag, objectTag string) {
writer.indent += "\t" writer.indent += "\t"
writer.writeString(tag) writer.writeString(tag)
writer.writeString(" = ") writer.writeString(" = ")
if objectTag == "" {
objectTag = "_"
}
writer.writeString(objectTag) writer.writeString(objectTag)
writer.buffer.WriteString(" {\n") writer.buffer.WriteString(" {\n")
} }
@ -92,6 +97,21 @@ func (writer *ruiWriterData) endObject() {
writer.buffer.WriteRune('}') writer.buffer.WriteRune('}')
} }
func (writer *ruiWriterData) startArrayProperty(tag string) {
writer.writeIndent()
writer.writeString(tag)
writer.buffer.WriteString(" = [\n")
writer.indent += "\t"
}
func (writer *ruiWriterData) endObArray() {
if len(writer.indent) > 0 {
writer.indent = writer.indent[1:]
}
writer.writeIndent()
writer.buffer.WriteString("],\n")
}
func (writer *ruiWriterData) writeValue(value interface{}) { func (writer *ruiWriterData) writeValue(value interface{}) {
switch value := value.(type) { switch value := value.(type) {
@ -201,3 +221,4 @@ func (writer *ruiWriterData) finish() string {
} }
return result return result
} }
*/

View File

@ -31,7 +31,7 @@ const (
type ViewShadow interface { type ViewShadow interface {
Properties Properties
fmt.Stringer fmt.Stringer
ruiStringer stringWriter
cssStyle(buffer *strings.Builder, session Session, lead string) bool cssStyle(buffer *strings.Builder, session Session, lead string) bool
cssTextStyle(buffer *strings.Builder, session Session, lead string) bool cssTextStyle(buffer *strings.Builder, session Session, lead string) bool
visible(session Session) bool visible(session Session) bool
@ -205,19 +205,24 @@ func (shadow *viewShadowData) visible(session Session) bool {
} }
func (shadow *viewShadowData) String() string { func (shadow *viewShadowData) String() string {
writer := newRUIWriter() return runStringWriter(shadow)
shadow.ruiString(writer)
return writer.finish()
} }
func (shadow *viewShadowData) ruiString(writer ruiWriter) { func (shadow *viewShadowData) writeString(buffer *strings.Builder, indent string) {
writer.startObject("_") buffer.WriteString("_{ ")
comma := false
for _, tag := range shadow.AllTags() { for _, tag := range shadow.AllTags() {
if value := shadow.Get(tag); value != nil { if value, ok := shadow.properties[tag]; ok {
writer.writeProperty(tag, value) if comma {
buffer.WriteString(", ")
}
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, tag, value, indent)
comma = true
} }
} }
writer.endObject() buffer.WriteString(" }")
} }
func (properties *propertyList) setShadow(tag string, value interface{}) bool { func (properties *propertyList) setShadow(tag string, value interface{}) bool {

View File

@ -58,6 +58,10 @@ func (layout *stackLayoutData) Init(session Session) {
layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished} layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished}
} }
func (layout *stackLayoutData) String() string {
return getViewString(layout)
}
func (layout *stackLayoutData) pushFinished(view View, tag string) { func (layout *stackLayoutData) pushFinished(view View, tag string) {
if tag == "ruiPush" { if tag == "ruiPush" {
if layout.pushView != nil { if layout.pushView != nil {

View File

@ -268,6 +268,10 @@ func (table *tableViewData) Init(session Session) {
table.current.Column = -1 table.current.Column = -1
} }
func (table *tableViewData) String() string {
return getViewString(table)
}
func (table *tableViewData) normalizeTag(tag string) string { func (table *tableViewData) normalizeTag(tag string) string {
switch tag = strings.ToLower(tag); tag { switch tag = strings.ToLower(tag); tag {
case "top-cell-padding": case "top-cell-padding":

View File

@ -99,6 +99,10 @@ func (tabsLayout *tabsLayoutData) Init(session Session) {
tabsLayout.tabCloseListener = []func(TabsLayout, int){} tabsLayout.tabCloseListener = []func(TabsLayout, int){}
} }
func (tabsLayout *tabsLayoutData) String() string {
return getViewString(tabsLayout)
}
func (tabsLayout *tabsLayoutData) currentItem() int { func (tabsLayout *tabsLayoutData) currentItem() int {
result, _ := intProperty(tabsLayout, Current, tabsLayout.session, 0) result, _ := intProperty(tabsLayout, Current, tabsLayout.session, 0)
return result return result

View File

@ -32,6 +32,10 @@ func (textView *textViewData) Init(session Session) {
textView.tag = "TextView" textView.tag = "TextView"
} }
func (textView *textViewData) String() string {
return getViewString(textView)
}
func (textView *textViewData) Get(tag string) interface{} { func (textView *textViewData) Get(tag string) interface{} {
return textView.get(strings.ToLower(tag)) return textView.get(strings.ToLower(tag))
} }
@ -103,6 +107,14 @@ func (textView *textViewData) set(tag string, value interface{}) bool {
textView.textOverflowUpdated() textView.textOverflowUpdated()
} }
case NotTranslate:
if !textView.viewData.set(tag, value) {
return false
}
if textView.created {
updateInnerHTML(textView.htmlID(), textView.Session())
}
default: default:
return textView.viewData.set(tag, value) return textView.viewData.set(tag, value)
} }
@ -143,7 +155,9 @@ func textToJS(text string) string {
func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) { func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) {
if value := textView.getRaw(Text); value != nil { if value := textView.getRaw(Text); value != nil {
if text, ok := value.(string); ok { if text, ok := value.(string); ok {
text, _ = textView.session.GetString(text) if !GetNotTranslate(textView, "") {
text, _ = textView.session.GetString(text)
}
buffer.WriteString(textToJS(text)) buffer.WriteString(textToJS(text))
} }
} }

View File

@ -44,6 +44,10 @@ func (picker *timePickerData) Init(session Session) {
picker.timeChangedListeners = []func(TimePicker, time.Time){} picker.timeChangedListeners = []func(TimePicker, time.Time){}
} }
func (picker *timePickerData) String() string {
return getViewString(picker)
}
func (picker *timePickerData) Focusable() bool { func (picker *timePickerData) Focusable() bool {
return true return true
} }

View File

@ -45,6 +45,10 @@ func (player *videoPlayerData) Init(session Session) {
player.tag = "VideoPlayer" player.tag = "VideoPlayer"
} }
func (player *videoPlayerData) String() string {
return getViewString(player)
}
func (player *videoPlayerData) htmlTag() string { func (player *videoPlayerData) htmlTag() string {
return "video" return "video"
} }

59
view.go
View File

@ -30,9 +30,8 @@ func (frame Frame) Bottom() float64 {
// View - base view interface // View - base view interface
type View interface { type View interface {
Properties ViewStyle
fmt.Stringer fmt.Stringer
ruiStringer
// Init initializes fields of View by default values // Init initializes fields of View by default values
Init(session Session) Init(session Session)
@ -616,6 +615,13 @@ func (view *viewData) Get(tag string) interface{} {
} }
func (view *viewData) get(tag string) interface{} { func (view *viewData) get(tag string) interface{} {
if tag == ID {
if view.viewID != "" {
return view.viewID
} else {
return nil
}
}
return view.viewStyle.get(tag) return view.viewStyle.get(tag)
} }
@ -834,51 +840,6 @@ func (view *viewData) handleCommand(self View, command string, data DataObject)
} }
func ruiViewString(view View, viewTag string, writer ruiWriter) {
writer.startObject(viewTag)
tags := view.AllTags()
count := len(tags)
if count > 0 {
if count > 1 {
tagToStart := func(tag string) {
for i, t := range tags {
if t == tag {
if i > 0 {
for n := i; n > 0; n-- {
tags[n] = tags[n-1]
}
tags[0] = tag
}
return
}
}
}
tagToStart(StyleDisabled)
tagToStart(Style)
tagToStart(ID)
}
for _, tag := range tags {
if value := view.Get(tag); value != nil {
writer.writeProperty(tag, value)
}
}
}
writer.endObject()
}
func (view *viewData) ruiString(writer ruiWriter) {
ruiViewString(view, view.Tag(), writer)
}
func (view *viewData) String() string {
writer := newRUIWriter()
view.ruiString(writer)
return writer.finish()
}
func (view *viewData) SetChangeListener(tag string, listener func(View, string)) { func (view *viewData) SetChangeListener(tag string, listener func(View, string)) {
if listener == nil { if listener == nil {
delete(view.changeListener, tag) delete(view.changeListener, tag)
@ -890,3 +851,7 @@ func (view *viewData) SetChangeListener(tag string, listener func(View, string))
func (view *viewData) HasFocus() bool { func (view *viewData) HasFocus() bool {
return view.hasFocus return view.hasFocus
} }
func (view *viewData) String() string {
return getViewString(view)
}

View File

@ -9,7 +9,7 @@ import (
type ClipShape interface { type ClipShape interface {
Properties Properties
fmt.Stringer fmt.Stringer
ruiStringer stringWriter
cssStyle(session Session) string cssStyle(session Session) string
valid(session Session) bool valid(session Session) bool
} }
@ -22,6 +22,10 @@ type ellipseClip struct {
propertyList propertyList
} }
type circleClip struct {
propertyList
}
type polygonClip struct { type polygonClip struct {
points []interface{} points []interface{}
} }
@ -47,7 +51,7 @@ func InsetClip(top, right, bottom, left SizeUnit, radius RadiusProperty) ClipSha
// CircleClip creates a circle View clipping area. // CircleClip creates a circle View clipping area.
func CircleClip(x, y, radius SizeUnit) ClipShape { func CircleClip(x, y, radius SizeUnit) ClipShape {
clip := new(ellipseClip) clip := new(circleClip)
clip.init() clip.init()
clip.Set(X, x) clip.Set(X, x)
clip.Set(Y, y) clip.Set(Y, y)
@ -112,39 +116,25 @@ func (clip *insetClip) Set(tag string, value interface{}) bool {
} }
func (clip *insetClip) String() string { func (clip *insetClip) String() string {
writer := newRUIWriter() return runStringWriter(clip)
clip.ruiString(writer)
return writer.finish()
} }
func (clip *insetClip) ruiString(writer ruiWriter) { func (clip *insetClip) writeString(buffer *strings.Builder, indent string) {
writer.startObject("inset") buffer.WriteString("inset { ")
for _, tag := range []string{Top, Right, Bottom, Left} { comma := false
for _, tag := range []string{Top, Right, Bottom, Left, Radius} {
if value, ok := clip.properties[tag]; ok { if value, ok := clip.properties[tag]; ok {
switch value := value.(type) { if comma {
case string: buffer.WriteString(", ")
writer.writeProperty(tag, value)
case fmt.Stringer:
writer.writeProperty(tag, value.String())
} }
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, tag, value, indent)
comma = true
} }
} }
if value := clip.Get(Radius); value != nil { buffer.WriteString(" }")
switch value := value.(type) {
case RadiusProperty:
writer.writeProperty(Radius, value.String())
case SizeUnit:
writer.writeProperty(Radius, value.String())
case string:
writer.writeProperty(Radius, value)
}
}
writer.endObject()
} }
func (clip *insetClip) cssStyle(session Session) string { func (clip *insetClip) cssStyle(session Session) string {
@ -178,83 +168,108 @@ func (clip *insetClip) valid(session Session) bool {
return false return false
} }
func (clip *circleClip) Set(tag string, value interface{}) bool {
if value == nil {
clip.Remove(tag)
}
switch strings.ToLower(tag) {
case X, Y, Radius:
return clip.setSizeProperty(tag, value)
}
ErrorLogF(`"%s" property is not supported by the circle clip shape`, tag)
return false
}
func (clip *circleClip) String() string {
return runStringWriter(clip)
}
func (clip *circleClip) writeString(buffer *strings.Builder, indent string) {
buffer.WriteString("circle { ")
comma := false
for _, tag := range []string{Radius, X, Y} {
if value, ok := clip.properties[tag]; ok {
if comma {
buffer.WriteString(", ")
}
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, tag, value, indent)
comma = true
}
}
buffer.WriteString(" }")
}
func (clip *circleClip) cssStyle(session Session) string {
buffer := allocStringBuilder()
defer freeStringBuilder(buffer)
buffer.WriteString("circle(")
r, _ := sizeProperty(clip, Radius, session)
buffer.WriteString(r.cssString("50%"))
buffer.WriteString(" at ")
x, _ := sizeProperty(clip, X, session)
buffer.WriteString(x.cssString("50%"))
buffer.WriteRune(' ')
y, _ := sizeProperty(clip, Y, session)
buffer.WriteString(y.cssString("50%"))
buffer.WriteRune(')')
return buffer.String()
}
func (clip *circleClip) valid(session Session) bool {
if value, ok := sizeProperty(clip, Radius, session); ok && value.Value == 0 {
return false
}
return true
}
func (clip *ellipseClip) Set(tag string, value interface{}) bool { func (clip *ellipseClip) Set(tag string, value interface{}) bool {
if value == nil { if value == nil {
clip.Remove(tag) clip.Remove(tag)
} }
switch strings.ToLower(tag) { switch strings.ToLower(tag) {
case X, Y: case X, Y, RadiusX, RadiusY:
return clip.setSizeProperty(tag, value) return clip.setSizeProperty(tag, value)
case Radius: case Radius:
result := clip.setSizeProperty(tag, value) return clip.setSizeProperty(RadiusX, value) &&
if result { clip.setSizeProperty(RadiusY, value)
delete(clip.properties, RadiusX)
delete(clip.properties, RadiusY)
}
return result
case RadiusX:
result := clip.setSizeProperty(tag, value)
if result {
if r, ok := clip.properties[Radius]; ok {
clip.properties[RadiusY] = r
delete(clip.properties, Radius)
}
}
return result
case RadiusY:
result := clip.setSizeProperty(tag, value)
if result {
if r, ok := clip.properties[Radius]; ok {
clip.properties[RadiusX] = r
delete(clip.properties, Radius)
}
}
return result
} }
ErrorLogF(`"%s" property is not supported by the inset clip shape`, tag) ErrorLogF(`"%s" property is not supported by the ellipse clip shape`, tag)
return false return false
} }
func (clip *ellipseClip) String() string { func (clip *ellipseClip) String() string {
writer := newRUIWriter() return runStringWriter(clip)
clip.ruiString(writer)
return writer.finish()
} }
func (clip *ellipseClip) ruiString(writer ruiWriter) { func (clip *ellipseClip) writeString(buffer *strings.Builder, indent string) {
writeProperty := func(tag string, value interface{}) { buffer.WriteString("ellipse { ")
switch value := value.(type) { comma := false
case string: for _, tag := range []string{RadiusX, RadiusY, X, Y} {
writer.writeProperty(tag, value)
case fmt.Stringer:
writer.writeProperty(tag, value.String())
}
}
if r, ok := clip.properties[Radius]; ok {
writer.startObject("circle")
writeProperty(Radius, r)
} else {
writer.startObject("ellipse")
for _, tag := range []string{RadiusX, RadiusY} {
if value, ok := clip.properties[tag]; ok {
writeProperty(tag, value)
}
}
}
for _, tag := range []string{X, Y} {
if value, ok := clip.properties[tag]; ok { if value, ok := clip.properties[tag]; ok {
writeProperty(tag, value) if comma {
buffer.WriteString(", ")
}
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, tag, value, indent)
comma = true
} }
} }
writer.endObject()
buffer.WriteString(" }")
} }
func (clip *ellipseClip) cssStyle(session Session) string { func (clip *ellipseClip) cssStyle(session Session) string {
@ -262,38 +277,29 @@ func (clip *ellipseClip) cssStyle(session Session) string {
buffer := allocStringBuilder() buffer := allocStringBuilder()
defer freeStringBuilder(buffer) defer freeStringBuilder(buffer)
if r, ok := sizeProperty(clip, Radius, session); ok { rx, _ := sizeProperty(clip, RadiusX, session)
buffer.WriteString("circle(") ry, _ := sizeProperty(clip, RadiusX, session)
buffer.WriteString(r.cssString("0")) buffer.WriteString("ellipse(")
} else { buffer.WriteString(rx.cssString("50%"))
rx, _ := sizeProperty(clip, RadiusX, session) buffer.WriteRune(' ')
ry, _ := sizeProperty(clip, RadiusX, session) buffer.WriteString(ry.cssString("50%"))
buffer.WriteString("ellipse(")
buffer.WriteString(rx.cssString("0"))
buffer.WriteRune(' ')
buffer.WriteString(ry.cssString("0"))
}
buffer.WriteString(" at ") buffer.WriteString(" at ")
x, _ := sizeProperty(clip, X, session) x, _ := sizeProperty(clip, X, session)
buffer.WriteString(x.cssString("0")) buffer.WriteString(x.cssString("50%"))
buffer.WriteRune(' ') buffer.WriteRune(' ')
y, _ := sizeProperty(clip, Y, session) y, _ := sizeProperty(clip, Y, session)
buffer.WriteString(y.cssString("0")) buffer.WriteString(y.cssString("50%"))
buffer.WriteRune(')') buffer.WriteRune(')')
return buffer.String() return buffer.String()
} }
func (clip *ellipseClip) valid(session Session) bool { func (clip *ellipseClip) valid(session Session) bool {
if value, ok := sizeProperty(clip, Radius, session); ok && value.Type != Auto && value.Value != 0 { rx, _ := sizeProperty(clip, RadiusX, session)
return true ry, _ := sizeProperty(clip, RadiusY, session)
} return rx.Value != 0 && ry.Value != 0
rx, okX := sizeProperty(clip, RadiusX, session)
ry, okY := sizeProperty(clip, RadiusY, session)
return okX && okY && rx.Type != Auto && rx.Value != 0 && ry.Type != Auto && ry.Value != 0
} }
func (clip *polygonClip) Get(tag string) interface{} { func (clip *polygonClip) Get(tag string) interface{} {
@ -383,47 +389,31 @@ func (clip *polygonClip) AllTags() []string {
} }
func (clip *polygonClip) String() string { func (clip *polygonClip) String() string {
writer := newRUIWriter() return runStringWriter(clip)
clip.ruiString(writer)
return writer.finish()
} }
func (clip *polygonClip) ruiString(writer ruiWriter) { func (clip *polygonClip) writeString(buffer *strings.Builder, indent string) {
buffer := allocStringBuilder() buffer.WriteString("inset { ")
defer freeStringBuilder(buffer)
writer.startObject("polygon")
if clip.points != nil { if clip.points != nil {
buffer.WriteString(Points)
buffer.WriteString(` = "`)
for i, value := range clip.points { for i, value := range clip.points {
if i > 0 { if i > 0 {
buffer.WriteString(", ") buffer.WriteString(", ")
} }
switch value := value.(type) { writePropertyValue(buffer, "", value, indent)
case string:
buffer.WriteString(value)
case fmt.Stringer:
buffer.WriteString(value.String())
default:
buffer.WriteString("0px")
}
} }
writer.writeProperty(Points, buffer.String()) buffer.WriteString(`" `)
} }
writer.endObject() buffer.WriteRune('}')
} }
func (clip *polygonClip) cssStyle(session Session) string { func (clip *polygonClip) cssStyle(session Session) string {
if clip.points == nil {
return ""
}
count := len(clip.points) count := len(clip.points)
if count < 2 { if count < 2 {
return "" return ""

View File

@ -77,7 +77,7 @@ const (
type ViewFilter interface { type ViewFilter interface {
Properties Properties
fmt.Stringer fmt.Stringer
ruiStringer stringWriter
cssStyle(session Session) string cssStyle(session Session) string
} }
@ -155,17 +155,25 @@ func (filter *viewFilter) Set(tag string, value interface{}) bool {
} }
func (filter *viewFilter) String() string { func (filter *viewFilter) String() string {
writer := newRUIWriter() return runStringWriter(filter)
filter.ruiString(writer)
return writer.finish()
} }
func (filter *viewFilter) ruiString(writer ruiWriter) { func (filter *viewFilter) writeString(buffer *strings.Builder, indent string) {
writer.startObject("filter") buffer.WriteString("filter { ")
for tag, value := range filter.properties { comma := false
writer.writeProperty(tag, value) tags := filter.AllTags()
for _, tag := range tags {
if value, ok := filter.properties[tag]; ok {
if comma {
buffer.WriteString(", ")
}
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, tag, value, indent)
comma = true
}
} }
writer.endObject() buffer.WriteString(" }")
} }
func (filter *viewFilter) cssStyle(session Session) string { func (filter *viewFilter) cssStyle(session Session) string {

View File

@ -2,6 +2,7 @@ package rui
import ( import (
"fmt" "fmt"
"sort"
"strconv" "strconv"
"strings" "strings"
) )
@ -22,6 +23,10 @@ type Range struct {
First, Last int First, Last int
} }
type stringWriter interface {
writeString(buffer *strings.Builder, indent string)
}
// String returns a string representation of the Range struct // String returns a string representation of the Range struct
func (r Range) String() string { func (r Range) String() string {
if r.First == r.Last { if r.First == r.Last {
@ -416,3 +421,403 @@ func (style *viewStyle) cssViewStyle(builder cssBuilder, session Session) {
} }
} }
} }
func valueToOrientation(value interface{}, session Session) (int, bool) {
if value != nil {
switch value := value.(type) {
case int:
return value, true
case string:
text, ok := session.resolveConstants(value)
if !ok {
return 0, false
}
text = strings.ToLower(strings.Trim(text, " \t\n\r"))
switch text {
case "vertical":
return TopDownOrientation, true
case "horizontal":
return StartToEndOrientation, true
}
if result, ok := enumStringToInt(text, enumProperties[Orientation].values, true); ok {
return result, true
}
}
}
return 0, false
}
func (style *viewStyle) Get(tag string) interface{} {
return style.get(strings.ToLower(tag))
}
func (style *viewStyle) get(tag string) interface{} {
switch tag {
case Border, CellBorder:
return getBorder(&style.propertyList, tag)
case BorderLeft, BorderRight, BorderTop, BorderBottom,
BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle,
BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor,
BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
if border := getBorder(style, Border); border != nil {
return border.Get(tag)
}
return nil
case CellBorderLeft, CellBorderRight, CellBorderTop, CellBorderBottom,
CellBorderStyle, CellBorderLeftStyle, CellBorderRightStyle, CellBorderTopStyle, CellBorderBottomStyle,
CellBorderColor, CellBorderLeftColor, CellBorderRightColor, CellBorderTopColor, CellBorderBottomColor,
CellBorderWidth, CellBorderLeftWidth, CellBorderRightWidth, CellBorderTopWidth, CellBorderBottomWidth:
if border := getBorder(style, CellBorder); border != nil {
return border.Get(tag)
}
return nil
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
return getRadiusElement(style, tag)
case ColumnSeparator:
if val, ok := style.properties[ColumnSeparator]; ok {
return val.(ColumnSeparatorProperty)
}
return nil
case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor:
if val, ok := style.properties[ColumnSeparator]; ok {
separator := val.(ColumnSeparatorProperty)
return separator.Get(tag)
}
return nil
case Transition:
if len(style.transitions) == 0 {
return nil
}
result := map[string]Animation{}
for tag, animation := range style.transitions {
result[tag] = animation
}
return result
}
return style.propertyList.getRaw(tag)
}
func (style *viewStyle) AllTags() []string {
result := style.propertyList.AllTags()
if len(style.transitions) > 0 {
result = append(result, Transition)
}
return result
}
func supportedPropertyValue(value interface{}) bool {
switch value.(type) {
case string:
case []string:
case bool:
case float32:
case float64:
case int:
case stringWriter:
case fmt.Stringer:
case []ViewShadow:
case []View:
case []interface{}:
case map[string]Animation:
default:
return false
}
return true
}
func writePropertyValue(buffer *strings.Builder, tag string, value interface{}, indent string) {
writeString := func(text string) {
simple := (tag != Text && tag != Title && tag != Summary)
if simple {
if len(text) == 1 {
simple = (text[0] >= '0' && text[0] <= '9') || (text[0] >= 'A' && text[0] <= 'Z') || (text[0] >= 'a' && text[0] <= 'z')
} else {
for _, ch := range text {
if (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
ch == '+' || ch == '-' || ch == '@' || ch == '/' || ch == '_' || ch == ':' {
} else {
simple = false
break
}
}
}
}
if !simple {
replace := []struct{ old, new string }{
{old: "\\", new: `\\`},
{old: "\t", new: `\t`},
{old: "\r", new: `\r`},
{old: "\n", new: `\n`},
{old: "\"", new: `\"`},
}
for _, s := range replace {
text = strings.Replace(text, s.old, s.new, -1)
}
buffer.WriteRune('"')
buffer.WriteString(text)
buffer.WriteRune('"')
} else {
buffer.WriteString(text)
}
}
switch value := value.(type) {
case string:
writeString(value)
case []string:
if len(value) == 0 {
buffer.WriteString("[]")
} else {
size := 0
for _, text := range value {
size += len(text) + 2
}
if size < 80 {
lead := "["
for _, text := range value {
buffer.WriteString(lead)
writeString(text)
lead = ", "
}
} else {
buffer.WriteString("[\n")
for _, text := range value {
buffer.WriteString(indent)
buffer.WriteRune('\t')
writeString(text)
buffer.WriteString(",\n")
}
}
buffer.WriteString(indent)
buffer.WriteRune(']')
}
case bool:
if value {
buffer.WriteString("true")
} else {
buffer.WriteString("false")
}
case float32:
buffer.WriteString(fmt.Sprintf("%g", float64(value)))
case float64:
buffer.WriteString(fmt.Sprintf("%g", value))
case int:
if prop, ok := enumProperties[tag]; ok && value >= 0 && value < len(prop.values) {
buffer.WriteString(prop.values[value])
} else {
buffer.WriteString(strconv.Itoa(value))
}
case stringWriter:
value.writeString(buffer, indent+"\t")
case fmt.Stringer:
buffer.WriteString(value.String())
case []ViewShadow:
switch len(value) {
case 0:
// do nothing
case 1:
value[0].writeString(buffer, indent)
default:
buffer.WriteString("[")
indent2 := "\n" + indent + "\t"
for _, shadow := range value {
buffer.WriteString(indent2)
shadow.writeString(buffer, indent)
}
buffer.WriteRune('\n')
buffer.WriteString(indent)
buffer.WriteRune(']')
}
case []View:
switch len(value) {
case 0:
buffer.WriteString("[]\n")
case 1:
writeViewStyle(value[0].Tag(), value[0], buffer, indent)
default:
buffer.WriteString("[\n")
indent2 := indent + "\t"
for _, v := range value {
buffer.WriteString(indent2)
writeViewStyle(v.Tag(), v, buffer, indent2)
buffer.WriteString(",\n")
}
buffer.WriteString(indent)
buffer.WriteRune(']')
}
case []interface{}:
switch count := len(value); count {
case 0:
buffer.WriteString("[]")
case 1:
writePropertyValue(buffer, tag, value[0], indent)
default:
buffer.WriteString("[ ")
comma := false
for _, v := range value {
if comma {
buffer.WriteString(", ")
}
writePropertyValue(buffer, tag, v, indent)
comma = true
}
buffer.WriteString(" ]")
}
case map[string]Animation:
switch count := len(value); count {
case 0:
buffer.WriteString("[]")
case 1:
for tag, animation := range value {
animation.writeTransitionString(tag, buffer)
break
}
default:
tags := make([]string, 0, len(value))
for tag := range value {
tags = append(tags, tag)
}
sort.Strings(tags)
buffer.WriteString("[\n")
indent2 := indent + "\t"
for _, tag := range tags {
if animation := value[tag]; animation != nil {
buffer.WriteString(indent2)
animation.writeTransitionString(tag, buffer)
buffer.WriteString("\n")
}
}
buffer.WriteString(indent)
buffer.WriteRune(']')
}
}
}
func writeViewStyle(name string, view ViewStyle, buffer *strings.Builder, indent string) {
buffer.WriteString(name)
buffer.WriteString(" {\n")
indent += "\t"
writeProperty := func(tag string, value interface{}) {
if supportedPropertyValue(value) {
buffer.WriteString(indent)
buffer.WriteString(tag)
buffer.WriteString(" = ")
writePropertyValue(buffer, tag, value, indent)
buffer.WriteString(",\n")
}
}
tags := view.AllTags()
removeTag := func(tag string) {
for i, t := range tags {
if t == tag {
if i == 0 {
tags = tags[1:]
} else if i == len(tags)-1 {
tags = tags[:i]
} else {
tags = append(tags[:i], tags[i+1:]...)
}
return
}
}
}
tagOrder := []string{
ID, Row, Column, Top, Right, Bottom, Left, Semantics, Cursor, Visibility,
Opacity, ZIndex, Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight,
Margin, Padding, BackgroundClip, BackgroundColor, Background, Border, Radius, Outline, Shadow,
Orientation, Wrap, VerticalAlign, HorizontalAlign, CellWidth, CellHeight,
CellVerticalAlign, CellHorizontalAlign, GridRowGap, GridColumnGap,
ColumnCount, ColumnWidth, ColumnSeparator, ColumnGap, AvoidBreak,
Current, Expanded, Side, ResizeBorderWidth, EditViewType, MaxLength, Hint, Text,
TextOverflow, FontName, TextSize, TextColor, TextWeight, Italic, SmallCaps,
Strikethrough, Overline, Underline, TextLineStyle, TextLineThickness,
TextLineColor, TextTransform, TextAlign, WhiteSpace, WordBreak, TextShadow, TextIndent,
LetterSpacing, WordSpacing, LineHeight, TextDirection, WritingMode, VerticalTextOrientation,
}
for _, tag := range tagOrder {
if value := view.Get(tag); value != nil {
removeTag(tag)
writeProperty(tag, value)
}
}
finalTags := []string{
Perspective, PerspectiveOriginX, PerspectiveOriginY, BackfaceVisible, OriginX, OriginY, OriginZ,
TranslateX, TranslateY, TranslateZ, ScaleX, ScaleY, ScaleZ, Rotate, RotateX, RotateY, RotateZ,
SkewX, SkewY, Clip, Filter, Summary, Content, Transition}
for _, tag := range finalTags {
removeTag(tag)
}
for _, tag := range tags {
if value := view.Get(tag); value != nil {
writeProperty(tag, value)
}
}
for _, tag := range finalTags {
if value := view.Get(tag); value != nil {
writeProperty(tag, value)
}
}
indent = indent[:len(indent)-1]
buffer.WriteString(indent)
buffer.WriteString("}")
}
func getViewString(view View) string {
buffer := allocStringBuilder()
defer freeStringBuilder(buffer)
writeViewStyle(view.Tag(), view, buffer, "")
return buffer.String()
}
func runStringWriter(writer stringWriter) string {
buffer := allocStringBuilder()
defer freeStringBuilder(buffer)
writer.writeString(buffer, "")
return buffer.String()
}

View File

@ -1,89 +0,0 @@
package rui
import (
"strings"
)
func valueToOrientation(value interface{}, session Session) (int, bool) {
if value != nil {
switch value := value.(type) {
case int:
return value, true
case string:
text, ok := session.resolveConstants(value)
if !ok {
return 0, false
}
text = strings.ToLower(strings.Trim(text, " \t\n\r"))
switch text {
case "vertical":
return TopDownOrientation, true
case "horizontal":
return StartToEndOrientation, true
}
if result, ok := enumStringToInt(text, enumProperties[Orientation].values, true); ok {
return result, true
}
}
}
return 0, false
}
/*
func getOrientation(style Properties, session Session) (int, bool) {
return valueToOrientation(style.Get(Orientation), session)
}
*/
func (style *viewStyle) Get(tag string) interface{} {
return style.get(strings.ToLower(tag))
}
func (style *viewStyle) get(tag string) interface{} {
switch tag {
case Border, CellBorder:
return getBorder(&style.propertyList, tag)
case BorderLeft, BorderRight, BorderTop, BorderBottom,
BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle,
BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor,
BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
if border := getBorder(style, Border); border != nil {
return border.Get(tag)
}
return nil
case CellBorderLeft, CellBorderRight, CellBorderTop, CellBorderBottom,
CellBorderStyle, CellBorderLeftStyle, CellBorderRightStyle, CellBorderTopStyle, CellBorderBottomStyle,
CellBorderColor, CellBorderLeftColor, CellBorderRightColor, CellBorderTopColor, CellBorderBottomColor,
CellBorderWidth, CellBorderLeftWidth, CellBorderRightWidth, CellBorderTopWidth, CellBorderBottomWidth:
if border := getBorder(style, CellBorder); border != nil {
return border.Get(tag)
}
return nil
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
return getRadiusElement(style, tag)
case ColumnSeparator:
if val, ok := style.properties[ColumnSeparator]; ok {
return val.(ColumnSeparatorProperty)
}
return nil
case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor:
if val, ok := style.properties[ColumnSeparator]; ok {
separator := val.(ColumnSeparatorProperty)
return separator.Get(tag)
}
return nil
}
return style.propertyList.getRaw(tag)
}

View File

@ -271,12 +271,13 @@ func (style *viewStyle) set(tag string, value interface{}) bool {
case Transition: case Transition:
setObject := func(obj DataObject) bool { setObject := func(obj DataObject) bool {
if obj != nil { if obj != nil {
switch obj.Tag() { tag := strings.ToLower(tag)
switch tag {
case "", "_": case "", "_":
ErrorLog("Invalid transition property name") ErrorLog("Invalid transition property name")
default: default:
style.transitions[obj.Tag()] = parseAnimation(obj) style.transitions[tag] = parseAnimation(obj)
return true return true
} }
} }
@ -285,18 +286,19 @@ func (style *viewStyle) set(tag string, value interface{}) bool {
switch value := value.(type) { switch value := value.(type) {
case Params: case Params:
result := false result := true
for tag, val := range value { for tag, val := range value {
if animation, ok := val.(Animation); ok { tag = strings.ToLower(strings.Trim(tag, " \t"))
tag = strings.ToLower(tag) if tag == "" {
if animation == nil || tag == "" { ErrorLog("Invalid transition property name")
ErrorLog("Invalid transition property name") result = false
} else { } else if val == nil {
style.transitions[tag] = animation delete(style.transitions, tag)
result = true } else if animation, ok := val.(Animation); ok {
} style.transitions[tag] = animation
} else { } else {
notCompatibleType(Transition, val) notCompatibleType(Transition, val)
result = false
} }
} }
return result return result

View File

@ -1,131 +0,0 @@
package rui
/*
import (
"strings"
"testing"
)
func TestViewStyleCreate(t *testing.T) {
app := new(application)
app.init("")
session := newSession(app, 1, "", false, false)
var style viewStyle
style.init()
data := []struct{ property, value string }{
{Width, "100%"},
{Height, "400px"},
{Margin, "4px"},
{Margin + "-bottom", "auto"},
{Padding, "1em"},
{Font, "Arial"},
{BackgroundColor, "#FF008000"},
{TextColor, "#FF000000"},
{TextSize, "1.25em"},
{TextWeight, "bold"},
{TextAlign, "center"},
{TextTransform, "uppercase"},
{TextIndent, "0.25em"},
{LetterSpacing, "1.5em"},
{WordSpacing, "8px"},
{LineHeight, "2em"},
{Italic, "on"},
{TextDecoration, "strikethrough | overline | underline"},
{SmallCaps, "on"},
}
for _, prop := range data {
style.Set(prop.property, prop.value)
}
style.AddShadow(NewViewShadow(SizeUnit{Auto, 0}, SizeUnit{Auto, 0}, Px(4), Px(6), 0xFF808080))
expected := `width: 100%; height: 400px; font-size: 1.25rem; text-indent: 0.25rem; letter-spacing: 1.5rem; word-spacing: 8px; ` +
`line-height: 2rem; padding: 1rem; margin-left: 4px; margin-top: 4px; margin-right: 4px; box-shadow: 0 0 4px 6px rgb(128,128,128); ` +
`background-color: rgb(0,128,0); color: rgb(0,0,0); font-family: Arial; font-weight: bold; font-style: italic; font-variant: small-caps; ` +
`text-align: center; text-decoration: line-through overline underline; text-transform: uppercase;`
buffer := strings.Builder{}
style.cssViewStyle(&buffer, session)
if text := strings.Trim(buffer.String(), " "); text != expected {
t.Error("\nresult : " + text + "\nexpected: " + expected)
}
w := newCompactDataWriter()
w.StartObject("_")
style.writeStyle(w)
w.FinishObject()
expected2 := `_{width=100%,height=400px,margin="4px,4px,auto,4px",padding=1em,background-color=#FF008000,shadow=_{color=#FF808080,blur=4px,spread-radius=6px},font=Arial,text-color=#FF000000,text-size=1.25em,text-weight=bold,italic=on,small-caps=on,text-decoration=strikethrough|overline|underline,text-align=center,text-indent=0.25em,letter-spacing=1.5em,word-spacing=8px,line-height=2em,text-transform=uppercase}`
if text := w.String(); text != expected2 {
t.Error("\n result: " + text + "\nexpected: " + expected2)
}
var style1 viewStyle
style1.init()
if obj, err := ParseDataText(expected2); err == nil {
style1.parseStyle(obj, new(sessionData))
buffer.Reset()
style.cssStyle(&buffer)
if text := buffer.String(); text != expected {
t.Error("\n result: " + text + "\nexpected: " + expected)
}
} else {
t.Error(err)
}
var style2 viewStyle
style2.init()
style2.textWeight = 4
style2.textAlign = RightAlign
style2.textTransform = LowerCaseTextTransform
style2.textDecoration = NoneDecoration
style2.italic = Off
style2.smallCaps = Off
expected = `font-weight: normal; font-style: normal; font-variant: normal; text-align: right; text-decoration: none; text-transform: lowercase; `
buffer.Reset()
style2.cssStyle(&buffer)
if text := buffer.String(); text != expected {
t.Error("\n result: " + text + "\nexpected: " + expected)
}
w.Reset()
w.StartObject("_")
style2.writeStyle(w)
w.FinishObject()
expected = `_{text-weight=normal,italic=off,small-caps=off,text-decoration=none,text-align=right,text-transform=lowercase}`
if text := w.String(); text != expected {
t.Error("\n result: " + text + "\nexpected: " + expected)
}
style2.textWeight = 5
style2.textAlign = JustifyTextAlign
style2.textTransform = CapitalizeTextTransform
style2.textDecoration = Inherit
style2.italic = Inherit
style2.smallCaps = Inherit
expected = `font-weight: 500; text-align: justify; text-transform: capitalize; `
buffer.Reset()
style2.cssStyle(&buffer)
if text := buffer.String(); text != expected {
t.Error("\n result: " + text + "\nexpected: " + expected)
}
w.Reset()
w.StartObject("_")
style2.writeStyle(w)
w.FinishObject()
expected = `_{text-weight=5,text-align=justify,text-transform=capitalize}`
if text := w.String(); text != expected {
t.Error("\n result: " + text + "\nexpected: " + expected)
}
}
*/

View File

@ -31,6 +31,10 @@ func (container *viewsContainerData) Init(session Session) {
container.views = []View{} container.views = []View{}
} }
func (container *viewsContainerData) String() string {
return getViewString(container)
}
func (container *viewsContainerData) setParentID(parentID string) { func (container *viewsContainerData) setParentID(parentID string) {
container.viewData.setParentID(parentID) container.viewData.setParentID(parentID)
htmlID := container.htmlID() htmlID := container.htmlID()