From 371079e27bfc33d5e025b8b85a9bde9cfa99a8c6 Mon Sep 17 00:00:00 2001 From: Alexei Anoshenko Date: Sat, 23 Apr 2022 18:13:35 +0300 Subject: [PATCH] Added "image constants" --- background.go | 2 +- image.go | 5 +++++ imageView.go | 45 +++++++++++++++++++++++++++----------- propertyGet.go | 17 +++++++++++++++ resources.go | 2 ++ session.go | 4 ++++ sessionTheme.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ theme.go | 36 +++++++++++++++++++++++++++++++ 8 files changed, 155 insertions(+), 13 deletions(-) diff --git a/background.go b/background.go index b69b4fd..4d08d0f 100644 --- a/background.go +++ b/background.go @@ -239,7 +239,7 @@ func (image *backgroundImage) Get(tag string) interface{} { } func (image *backgroundImage) cssStyle(session Session) string { - if src, ok := stringProperty(image, Source, session); ok && src != "" { + if src, ok := imageProperty(image, Source, session); ok && src != "" { buffer := allocStringBuilder() defer freeStringBuilder(buffer) diff --git a/image.go b/image.go index 27592e1..ddb935b 100644 --- a/image.go +++ b/image.go @@ -128,5 +128,10 @@ func (manager *imageManager) imageLoadError(obj DataObject, session Session) { // LoadImage starts the async image loading by url func LoadImage(url string, onLoaded func(Image), session Session) Image { + if url != "" && url[0] == '@' { + if image, ok := session.ImageConstant(url[1:]); ok { + url = image + } + } return session.imageManager().loadImage(url, onLoaded, session) } diff --git a/imageView.go b/imageView.go index cfda0fa..9e411fe 100644 --- a/imageView.go +++ b/imageView.go @@ -109,8 +109,12 @@ func (imageView *imageViewData) set(tag string, value interface{}) bool { if text, ok := value.(string); ok { imageView.properties[Source] = text if imageView.created { - updateProperty(imageView.htmlID(), "src", text, imageView.session) - if srcset := imageView.srcSet(text); srcset != "" { + src := text + if src != "" && src[0] == '@' { + src, _ = imageProperty(imageView, Source, imageView.session) + } + updateProperty(imageView.htmlID(), "src", src, imageView.session) + if srcset := imageView.srcSet(src); srcset != "" { updateProperty(imageView.htmlID(), "srcset", srcset, imageView.session) } else { removeProperty(imageView.htmlID(), "srcset", imageView.session) @@ -179,15 +183,25 @@ func (imageView *imageViewData) closeHTMLTag() bool { func (imageView *imageViewData) htmlProperties(self View, buffer *strings.Builder) { imageView.viewData.htmlProperties(self, buffer) - imageResource := GetImageViewSource(imageView, "") - if imageResource != "" { - buffer.WriteString(` src="`) - buffer.WriteString(imageResource) - buffer.WriteString(`"`) - if srcset := imageView.srcSet(imageResource); srcset != "" { - buffer.WriteString(` srcset="`) - buffer.WriteString(srcset) + + if imageResource, ok := imageProperty(imageView, Source, imageView.Session()); ok && imageResource != "" { + if imageResource[0] == '@' { + if image, ok := imageView.Session().ImageConstant(imageResource[1:]); ok { + imageResource = image + } else { + imageResource = "" + } + } + + if imageResource != "" { + buffer.WriteString(` src="`) + buffer.WriteString(imageResource) buffer.WriteString(`"`) + if srcset := imageView.srcSet(imageResource); srcset != "" { + buffer.WriteString(` srcset="`) + buffer.WriteString(srcset) + buffer.WriteString(`"`) + } } } @@ -236,9 +250,16 @@ func (imageView *imageViewData) cssStyle(self View, builder cssBuilder) { // GetImageViewSource returns the image URL of an ImageView subview. // If the second argument (subviewID) is "" then a left position of the first argument (view) is returned func GetImageViewSource(view View, subviewID string) string { - if image, ok := stringProperty(view, Source, view.Session()); ok { - return image + if subviewID != "" { + view = ViewByID(view, subviewID) } + + if view != nil { + if image, ok := imageProperty(view, Source, view.Session()); ok { + return image + } + } + return "" } diff --git a/propertyGet.go b/propertyGet.go index 9f1ddda..6b102d8 100644 --- a/propertyGet.go +++ b/propertyGet.go @@ -14,6 +14,23 @@ func stringProperty(properties Properties, tag string, session Session) (string, return "", false } +func imageProperty(properties Properties, tag string, session Session) (string, bool) { + if value := properties.getRaw(tag); value != nil { + if text, ok := value.(string); ok { + if text != "" && text[0] == '@' { + if image, ok := session.ImageConstant(text[1:]); ok { + return image, true + } else { + return "", false + } + } + + return text, true + } + } + return "", false +} + func valueToSizeUnit(value interface{}, session Session) (SizeUnit, bool) { if value != nil { switch value := value.(type) { diff --git a/resources.go b/resources.go index 6a68687..62312d4 100644 --- a/resources.go +++ b/resources.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "path/filepath" + "sort" "strconv" "strings" ) @@ -422,5 +423,6 @@ func AllImageResources() []string { for image := range resources.images { result = append(result, image) } + sort.Strings(result) return result } diff --git a/session.go b/session.go index e2b2f0f..dd57c19 100644 --- a/session.go +++ b/session.go @@ -35,6 +35,10 @@ type Session interface { Color(tag string) (Color, bool) // ColorTags returns the list of all available color constants ColorTags() []string + // ImageConstant returns the image constant with "tag" name or "" if it is not exists + ImageConstant(tag string) (string, bool) + // ImageConstantTags returns the list of all available image constants + ImageConstantTags() []string // SetCustomTheme set the custom theme SetCustomTheme(name string) bool // UserAgent returns the "user-agent" text of the client browser diff --git a/sessionTheme.go b/sessionTheme.go index 002a459..8279021 100644 --- a/sessionTheme.go +++ b/sessionTheme.go @@ -186,6 +186,45 @@ func (session *sessionData) Color(tag string) (Color, bool) { } } +func (session *sessionData) ImageConstant(tag string) (string, bool) { + tags := []string{tag} + result := "" + theme := session.getCurrentTheme() + for { + ok := false + if session.darkTheme { + if theme.darkImages != nil { + result, ok = theme.darkImages[tag] + } + } + + if !ok { + if theme.images != nil { + result, ok = theme.images[tag] + } + } + + if !ok { + ErrorLogF(`"%v" image not found`, tag) + return "", false + } + + if result == "" || result[0] != '@' { + return result, true + } + + tag = result[1:] + for _, t := range tags { + if t == tag { + ErrorLogF(`"%v" image is cyclic`, tag) + return "", false + } + } + + tags = append(tags, tag) + } +} + func (session *sessionData) SetCustomTheme(name string) bool { if name == "" { if session.customTheme == nil { @@ -374,3 +413,21 @@ func (session *sessionData) ColorTags() []string { sort.Strings(keys) return keys } + +func (session *sessionData) ImageConstantTags() []string { + theme := session.getCurrentTheme() + + keys := make([]string, 0, len(theme.colors)) + for k := range theme.images { + keys = append(keys, k) + } + + for tag := range theme.darkImages { + if _, ok := theme.images[tag]; !ok { + keys = append(keys, tag) + } + } + + sort.Strings(keys) + return keys +} diff --git a/theme.go b/theme.go index e0e942b..04ceb0f 100644 --- a/theme.go +++ b/theme.go @@ -111,6 +111,8 @@ type theme struct { touchConstants map[string]string colors map[string]string darkColors map[string]string + images map[string]string + darkImages map[string]string styles map[string]Params mediaStyles []mediaStyle } @@ -129,6 +131,8 @@ func (theme *theme) init() { theme.touchConstants = map[string]string{} theme.colors = map[string]string{} theme.darkColors = map[string]string{} + theme.images = map[string]string{} + theme.darkImages = map[string]string{} theme.styles = map[string]Params{} theme.mediaStyles = []mediaStyle{} } @@ -154,6 +158,14 @@ func (theme *theme) concat(anotherTheme *theme) { theme.darkColors[tag] = color } + for tag, image := range anotherTheme.images { + theme.images[tag] = image + } + + for tag, image := range anotherTheme.darkImages { + theme.darkImages[tag] = image + } + for tag, style := range anotherTheme.styles { theme.styles[tag] = style } @@ -308,6 +320,30 @@ func (theme *theme) parseThemeData(data DataObject) { } } + case "images": + if d.Type() == ObjectNode { + if obj := d.Object(); obj != nil { + objCount := obj.PropertyCount() + for k := 0; k < objCount; k++ { + if prop := obj.Property(k); prop != nil && prop.Type() == TextNode { + theme.images[prop.Tag()] = prop.Text() + } + } + } + } + + case "images:dark": + if d.Type() == ObjectNode { + if obj := d.Object(); obj != nil { + objCount := obj.PropertyCount() + for k := 0; k < objCount; k++ { + if prop := obj.Property(k); prop != nil && prop.Type() == TextNode { + theme.darkImages[prop.Tag()] = prop.Text() + } + } + } + } + case "styles": if d.Type() == ArrayNode { arraySize := d.ArraySize()