forked from mbk-lab/rui_orig
2
0
Fork 0

Added Style functions to Theme

This commit is contained in:
Alexei Anoshenko 2022-05-25 20:03:32 +03:00
parent be2701e59d
commit 9c236ae102
1 changed files with 201 additions and 64 deletions

265
theme.go
View File

@ -13,11 +13,11 @@ const (
LandscapeMedia = 2 LandscapeMedia = 2
) )
type MediaStyle struct { type mediaStyle struct {
Orientation int orientation int
MaxWidth int maxWidth int
MaxHeight int maxHeight int
Styles map[string]ViewStyle styles map[string]ViewStyle
} }
type theme struct { type theme struct {
@ -29,7 +29,7 @@ type theme struct {
images map[string]string images map[string]string
darkImages map[string]string darkImages map[string]string
styles map[string]ViewStyle styles map[string]ViewStyle
mediaStyles []MediaStyle mediaStyles []mediaStyle
} }
type Theme interface { type Theme interface {
@ -47,6 +47,11 @@ type Theme interface {
SetImage(tag, image, darkUIImage string) SetImage(tag, image, darkUIImage string)
// ImageConstantTags returns the list of all available image constants // ImageConstantTags returns the list of all available image constants
ImageConstantTags() []string ImageConstantTags() []string
Style(tag string) ViewStyle
SetStyle(tag string, style ViewStyle)
MediaStyle(tag string, orientation, maxWidth, maxHeight int) ViewStyle
SetMediaStyle(tag string, orientation, maxWidth, maxHeight int, style ViewStyle)
StyleTags() []string
Append(anotherTheme Theme) Append(anotherTheme Theme)
constant(tag string, touchUI bool) string constant(tag string, touchUI bool) string
@ -57,11 +62,11 @@ type Theme interface {
data() *theme data() *theme
} }
func (rule MediaStyle) cssText() string { func (rule mediaStyle) cssText() string {
builder := allocStringBuilder() builder := allocStringBuilder()
defer freeStringBuilder(builder) defer freeStringBuilder(builder)
switch rule.Orientation { switch rule.orientation {
case PortraitMedia: case PortraitMedia:
builder.WriteString(" and (orientation: portrait)") builder.WriteString(" and (orientation: portrait)")
@ -69,45 +74,45 @@ func (rule MediaStyle) cssText() string {
builder.WriteString(" and (orientation: landscape)") builder.WriteString(" and (orientation: landscape)")
} }
if rule.MaxWidth > 0 { if rule.maxWidth > 0 {
builder.WriteString(" and (max-width: ") builder.WriteString(" and (max-width: ")
builder.WriteString(strconv.Itoa(rule.MaxWidth)) builder.WriteString(strconv.Itoa(rule.maxWidth))
builder.WriteString("px)") builder.WriteString("px)")
} }
if rule.MaxHeight > 0 { if rule.maxHeight > 0 {
builder.WriteString(" and (max-height: ") builder.WriteString(" and (max-height: ")
builder.WriteString(strconv.Itoa(rule.MaxHeight)) builder.WriteString(strconv.Itoa(rule.maxHeight))
builder.WriteString("px)") builder.WriteString("px)")
} }
return builder.String() return builder.String()
} }
func parseMediaRule(text string) (MediaStyle, bool) { func parseMediaRule(text string) (mediaStyle, bool) {
rule := MediaStyle{ rule := mediaStyle{
Orientation: DefaultMedia, orientation: DefaultMedia,
MaxWidth: 0, maxWidth: 0,
MaxHeight: 0, maxHeight: 0,
Styles: map[string]ViewStyle{}, styles: map[string]ViewStyle{},
} }
elements := strings.Split(text, ":") elements := strings.Split(text, ":")
for i := 1; i < len(elements); i++ { for i := 1; i < len(elements); i++ {
switch element := elements[i]; element { switch element := elements[i]; element {
case "portrait": case "portrait":
if rule.Orientation != DefaultMedia { if rule.orientation != DefaultMedia {
ErrorLog(`Duplicate orientation tag in the style section "` + text + `"`) ErrorLog(`Duplicate orientation tag in the style section "` + text + `"`)
return rule, false return rule, false
} }
rule.Orientation = PortraitMedia rule.orientation = PortraitMedia
case "landscape": case "landscape":
if rule.Orientation != DefaultMedia { if rule.orientation != DefaultMedia {
ErrorLog(`Duplicate orientation tag in the style section "` + text + `"`) ErrorLog(`Duplicate orientation tag in the style section "` + text + `"`)
return rule, false return rule, false
} }
rule.Orientation = LandscapeMedia rule.orientation = LandscapeMedia
default: default:
elementSize := func(name string) (int, bool) { elementSize := func(name string) (int, bool) {
@ -126,20 +131,20 @@ func parseMediaRule(text string) (MediaStyle, bool) {
if !ok { if !ok {
return rule, false return rule, false
} }
if rule.MaxWidth != 0 { if rule.maxWidth != 0 {
ErrorLog(`Duplicate "width" tag in the style section "` + text + `"`) ErrorLog(`Duplicate "width" tag in the style section "` + text + `"`)
return rule, false return rule, false
} }
rule.MaxWidth = size rule.maxWidth = size
} else if size, ok := elementSize("height"); !ok || size > 0 { } else if size, ok := elementSize("height"); !ok || size > 0 {
if !ok { if !ok {
return rule, false return rule, false
} }
if rule.MaxHeight != 0 { if rule.maxHeight != 0 {
ErrorLog(`Duplicate "height" tag in the style section "` + text + `"`) ErrorLog(`Duplicate "height" tag in the style section "` + text + `"`)
return rule, false return rule, false
} }
rule.MaxHeight = size rule.maxHeight = size
} else { } else {
ErrorLogF(`Unknown elemnet "%s" in the style section name "%s"`, element, text) ErrorLogF(`Unknown elemnet "%s" in the style section name "%s"`, element, text)
return rule, false return rule, false
@ -173,7 +178,7 @@ func (theme *theme) init() {
theme.images = map[string]string{} theme.images = map[string]string{}
theme.darkImages = map[string]string{} theme.darkImages = map[string]string{}
theme.styles = map[string]ViewStyle{} theme.styles = map[string]ViewStyle{}
theme.mediaStyles = []MediaStyle{} theme.mediaStyles = []mediaStyle{}
} }
func (theme *theme) Name() string { func (theme *theme) Name() string {
@ -240,6 +245,67 @@ func (theme *theme) SetImage(tag, image, darkUIImage string) {
} }
} }
func (theme *theme) Style(tag string) ViewStyle {
if style, ok := theme.styles[tag]; ok {
return style
}
return nil
}
func (theme *theme) SetStyle(tag string, style ViewStyle) {
if style != nil {
theme.styles[tag] = style
} else {
delete(theme.styles, tag)
}
}
func (theme *theme) MediaStyle(tag string, orientation, maxWidth, maxHeight int) ViewStyle {
for _, styles := range theme.mediaStyles {
if styles.orientation == orientation && styles.maxWidth == maxWidth && styles.maxHeight == maxHeight {
if style, ok := styles.styles[tag]; ok {
return style
}
}
}
return nil
}
func (theme *theme) SetMediaStyle(tag string, orientation, maxWidth, maxHeight int, style ViewStyle) {
if maxWidth < 0 {
maxWidth = 0
}
if maxHeight < 0 {
maxHeight = 0
}
if orientation == DefaultMedia && maxWidth == 0 && maxHeight == 0 {
theme.SetStyle(tag, style)
return
}
for i, styles := range theme.mediaStyles {
if styles.orientation == orientation && styles.maxWidth == maxWidth && styles.maxHeight == maxHeight {
if style != nil {
theme.mediaStyles[i].styles[tag] = style
} else {
delete(theme.mediaStyles[i].styles, tag)
}
break
}
}
if style != nil {
theme.mediaStyles = append(theme.mediaStyles, mediaStyle{
orientation: orientation,
maxWidth: maxWidth,
maxHeight: maxHeight,
styles: map[string]ViewStyle{tag: style},
})
theme.sortMediaStyles()
}
}
func (theme *theme) ConstantTags() []string { func (theme *theme) ConstantTags() []string {
keys := make([]string, 0, len(theme.constants)) keys := make([]string, 0, len(theme.constants))
for k := range theme.constants { for k := range theme.constants {
@ -288,6 +354,49 @@ func (theme *theme) ImageConstantTags() []string {
return keys return keys
} }
func (theme *theme) StyleTags() []string {
keys := make([]string, 0, len(theme.styles)*2)
appendTag := func(k string) {
n := sort.SearchStrings(keys, k)
if n >= len(keys) {
keys = append(keys, k)
} else if keys[n] != k {
if n == 0 {
keys = append([]string{k}, keys...)
} else {
keys = append(keys[:n+1], keys[n:]...)
keys[n] = k
}
}
}
for k := range theme.styles {
if index := strings.IndexRune(k, ':'); index < 0 {
keys = append(keys, k)
}
}
sort.Strings(keys)
for k := range theme.styles {
if index := strings.IndexRune(k, ':'); index > 0 {
appendTag(k[:index])
}
}
for _, media := range theme.mediaStyles {
for k := range media.styles {
index := strings.IndexRune(k, ':')
if index > 0 {
appendTag(k[:index])
} else if index < 0 {
appendTag(k)
}
}
}
return keys
}
func (theme *theme) data() *theme { func (theme *theme) data() *theme {
return theme return theme
} }
@ -329,11 +438,11 @@ func (theme *theme) Append(anotherTheme Theme) {
for _, anotherMedia := range another.mediaStyles { for _, anotherMedia := range another.mediaStyles {
exists := false exists := false
for _, media := range theme.mediaStyles { for _, media := range theme.mediaStyles {
if anotherMedia.MaxHeight == media.MaxHeight && if anotherMedia.maxHeight == media.maxHeight &&
anotherMedia.MaxWidth == media.MaxWidth && anotherMedia.maxWidth == media.maxWidth &&
anotherMedia.Orientation == media.Orientation { anotherMedia.orientation == media.orientation {
for tag, style := range anotherMedia.Styles { for tag, style := range anotherMedia.styles {
media.Styles[tag] = style media.styles[tag] = style
} }
exists = true exists = true
break break
@ -355,11 +464,6 @@ func (theme *theme) cssText(session Session) string {
builder.init() builder.init()
for tag, style := range theme.styles { for tag, style := range theme.styles {
/*var style viewStyle
style.init()
for tag, value := range obj {
style.Set(tag, value)
}*/
builder.startStyle(tag) builder.startStyle(tag)
style.cssViewStyle(&builder, session) style.cssViewStyle(&builder, session)
builder.endStyle() builder.endStyle()
@ -367,12 +471,7 @@ func (theme *theme) cssText(session Session) string {
for _, media := range theme.mediaStyles { for _, media := range theme.mediaStyles {
builder.startMedia(media.cssText()) builder.startMedia(media.cssText())
for tag, style := range media.Styles { for tag, style := range media.styles {
/*var style viewStyle
style.init()
for tag, value := range obj {
style.Set(tag, value)
}*/
builder.startStyle(tag) builder.startStyle(tag)
style.cssViewStyle(&builder, session) style.cssViewStyle(&builder, session)
builder.endStyle() builder.endStyle()
@ -384,26 +483,15 @@ func (theme *theme) cssText(session Session) string {
} }
func (theme *theme) addText(themeText string) bool { func (theme *theme) addText(themeText string) bool {
data := ParseDataText(themeText)
if data == nil {
return false
}
theme.addData(data)
return true
}
func (theme *theme) addData(data DataObject) {
if theme.constants == nil { if theme.constants == nil {
theme.init() theme.init()
} }
if data.IsObject() && data.Tag() == "theme" { data := ParseDataText(themeText)
theme.parseThemeData(data) if data == nil || !data.IsObject() || data.Tag() != "theme" {
return false
} }
}
func (theme *theme) parseThemeData(data DataObject) {
count := data.PropertyCount() count := data.PropertyCount()
objToStyle := func(obj DataObject) ViewStyle { objToStyle := func(obj DataObject) ViewStyle {
@ -519,7 +607,7 @@ func (theme *theme) parseThemeData(data DataObject) {
for k := 0; k < arraySize; k++ { for k := 0; k < arraySize; k++ {
if element := d.ArrayElement(k); element != nil && element.IsObject() { if element := d.ArrayElement(k); element != nil && element.IsObject() {
if obj := element.Object(); obj != nil { if obj := element.Object(); obj != nil {
rule.Styles[obj.Tag()] = objToStyle(obj) rule.styles[obj.Tag()] = objToStyle(obj)
} }
} }
} }
@ -530,15 +618,20 @@ func (theme *theme) parseThemeData(data DataObject) {
} }
} }
if len(theme.mediaStyles) > 0 { theme.sortMediaStyles()
return true
}
func (theme *theme) sortMediaStyles() {
if len(theme.mediaStyles) > 1 {
sort.SliceStable(theme.mediaStyles, func(i, j int) bool { sort.SliceStable(theme.mediaStyles, func(i, j int) bool {
if theme.mediaStyles[i].Orientation != theme.mediaStyles[j].Orientation { if theme.mediaStyles[i].orientation != theme.mediaStyles[j].orientation {
return theme.mediaStyles[i].Orientation < theme.mediaStyles[j].Orientation return theme.mediaStyles[i].orientation < theme.mediaStyles[j].orientation
} }
if theme.mediaStyles[i].MaxWidth != theme.mediaStyles[j].MaxWidth { if theme.mediaStyles[i].maxWidth != theme.mediaStyles[j].maxWidth {
return theme.mediaStyles[i].MaxWidth < theme.mediaStyles[j].MaxWidth return theme.mediaStyles[i].maxWidth < theme.mediaStyles[j].maxWidth
} }
return theme.mediaStyles[i].MaxHeight < theme.mediaStyles[j].MaxHeight return theme.mediaStyles[i].maxHeight < theme.mediaStyles[j].maxHeight
}) })
} }
} }
@ -656,6 +749,50 @@ func (theme *theme) String() string {
writeConstants("constants", theme.constants) writeConstants("constants", theme.constants)
writeConstants("constants:touch", theme.touchConstants) writeConstants("constants:touch", theme.touchConstants)
writeStyles := func(orientation, maxWidth, maxHeihgt int, styles map[string]ViewStyle) bool {
count := len(styles)
if count == 0 {
return false
}
tags := make([]string, 0, count)
for name := range styles {
tags = append(tags, name)
}
sort.Strings(tags)
buffer.WriteString("\tstyles")
switch orientation {
case PortraitMedia:
buffer.WriteString(":portrait")
case LandscapeMedia:
buffer.WriteString(":landscape")
}
if maxWidth > 0 {
buffer.WriteString(fmt.Sprintf(":width%d", maxWidth))
}
if maxHeihgt > 0 {
buffer.WriteString(fmt.Sprintf(":heihgt%d", maxHeihgt))
}
buffer.WriteString(" = [\n")
for _, tag := range tags {
if style, ok := styles[tag]; ok {
buffer.WriteString("\t\t")
writeViewStyle(tag, style, buffer, "\t\t")
buffer.WriteString(",")
}
}
buffer.WriteString("\t],\n")
return true
}
writeStyles(0, 0, 0, theme.styles)
for _, media := range theme.mediaStyles {
writeStyles(media.orientation, media.maxWidth, media.maxHeight, media.styles)
}
buffer.WriteString("}\n") buffer.WriteString("}\n")
return buffer.String() return buffer.String()
} }