From 7c860c54b985d3aaed8e83985c505cf43412df54 Mon Sep 17 00:00:00 2001 From: Alexei Anoshenko Date: Thu, 18 Aug 2022 18:18:36 +0300 Subject: [PATCH] Added OpenURL function, optimisation --- CHANGELOG.md | 3 ++- animation.go | 8 ++++---- numberPicker.go | 9 +++++---- propertyGet.go | 25 ++++++++++++++++++++++++ propertySet.go | 6 ++++++ session.go | 11 +++++++++++ tableView.go | 2 +- videoPlayer.go | 19 +++++++++++-------- view.go | 4 ++-- viewFilter.go | 14 ++++++++------ viewTransform.go | 49 +++++++++++++++++++----------------------------- viewUtils.go | 15 ++++++++++++--- 12 files changed, 106 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e48df6c..cc36a77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,13 @@ # v0.9.0 -* Requared go 1.18 +* Requires go 1.18 or higher * The "interface{}" type replaced by "any" * Added "overflow", "arrow", "arrow-align", "arrow-size", "arrow-width", and "arrow-offset" properties * Added "@ruiArrowSize" and "@ruiArrowWidth" constants to the default theme * Added Transition, Transitions, and SetTransition functions to the ViewStyle interface * Added GetOverflow, IsTimingFunctionValid, and GetTransitions functions * Changed GetTransition functions +* Added the OpenURL function to the Session interface # v0.8.0 diff --git a/animation.go b/animation.go index 4a592ec..5578118 100644 --- a/animation.go +++ b/animation.go @@ -400,7 +400,7 @@ func (animation *animationData) animationCSS(session Session) string { buffer.WriteString(animation.keyFramesName) - if duration, _ := floatProperty(animation, Duration, session, 1); duration > 0 { + if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 { buffer.WriteString(fmt.Sprintf(" %gs ", duration)) } else { buffer.WriteString(" 1s ") @@ -408,7 +408,7 @@ func (animation *animationData) animationCSS(session Session) string { buffer.WriteString(animation.timingFunctionCSS(session)) - if delay, _ := floatProperty(animation, Delay, session, 0); delay > 0 { + if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 { buffer.WriteString(fmt.Sprintf(" %gs", delay)) } else { buffer.WriteString(" 0s") @@ -438,7 +438,7 @@ func (animation *animationData) animationCSS(session Session) string { func (animation *animationData) transitionCSS(buffer *strings.Builder, session Session) { - if duration, _ := floatProperty(animation, Duration, session, 1); duration > 0 { + if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 { buffer.WriteString(fmt.Sprintf(" %gs ", duration)) } else { buffer.WriteString(" 1s ") @@ -446,7 +446,7 @@ func (animation *animationData) transitionCSS(buffer *strings.Builder, session S buffer.WriteString(animation.timingFunctionCSS(session)) - if delay, _ := floatProperty(animation, Delay, session, 0); delay > 0 { + if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 { buffer.WriteString(fmt.Sprintf(" %gs", delay)) } } diff --git a/numberPicker.go b/numberPicker.go index c84eaa2..258ffef 100644 --- a/numberPicker.go +++ b/numberPicker.go @@ -114,12 +114,13 @@ func (picker *numberPickerData) set(tag string, value any) bool { oldValue := GetNumberPickerValue(picker, "") min, max := GetNumberPickerMinMax(picker, "") if picker.setFloatProperty(NumberPickerValue, value, min, max) { - if newValue := GetNumberPickerValue(picker, ""); oldValue != newValue { + if f, ok := floatProperty(picker, NumberPickerValue, picker.Session(), min); ok && f != oldValue { + newValue, _ := floatTextProperty(picker, NumberPickerValue, picker.Session(), min) if picker.created { - picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%f')`, picker.htmlID(), newValue)) + picker.session.runScript(fmt.Sprintf(`setInputValue('%s', '%s')`, picker.htmlID(), newValue)) } for _, listener := range picker.numberChangedListeners { - listener(picker, newValue) + listener(picker, f) } picker.propertyChangedEvent(tag) } @@ -239,7 +240,7 @@ func (picker *numberPickerData) handleCommand(self View, command string, data Da if text, ok := data.PropertyValue("text"); ok { if value, err := strconv.ParseFloat(text, 32); err == nil { oldValue := GetNumberPickerValue(picker, "") - picker.properties[NumberPickerValue] = value + picker.properties[NumberPickerValue] = text if value != oldValue { for _, listener := range picker.numberChangedListeners { listener(picker, value) diff --git a/propertyGet.go b/propertyGet.go index eb51f16..f800ce8 100644 --- a/propertyGet.go +++ b/propertyGet.go @@ -1,6 +1,7 @@ package rui import ( + "fmt" "strconv" "strings" ) @@ -238,6 +239,30 @@ func floatProperty(properties Properties, tag string, session Session, defaultVa return valueToFloat(properties.getRaw(tag), session, defaultValue) } +func valueToFloatText(value any, session Session, defaultValue float64) (string, bool) { + if value != nil { + switch value := value.(type) { + case float64: + return fmt.Sprintf("%g", value), true + + case string: + if text, ok := session.resolveConstants(value); ok { + if _, err := strconv.ParseFloat(text, 64); err != nil { + ErrorLog(err.Error()) + return fmt.Sprintf("%g", defaultValue), false + } + return text, true + } + } + } + + return fmt.Sprintf("%g", defaultValue), false +} + +func floatTextProperty(properties Properties, tag string, session Session, defaultValue float64) (string, bool) { + return valueToFloatText(properties.getRaw(tag), session, defaultValue) +} + func valueToRange(value any, session Session) (Range, bool) { if value != nil { switch value := value.(type) { diff --git a/propertySet.go b/propertySet.go index fb07ea6..f16ce05 100644 --- a/propertySet.go +++ b/propertySet.go @@ -730,6 +730,12 @@ func (properties *propertyList) setFloatProperty(tag string, value any, min, max ErrorLog(err.Error()) return false } + if f < min || f > max { + ErrorLogF(`"%T" out of range of "%s" property`, value, tag) + return false + } + properties.properties[tag] = value + return true case float32: f = float64(value) diff --git a/session.go b/session.go index ed8b90b..38fe98f 100644 --- a/session.go +++ b/session.go @@ -2,6 +2,7 @@ package rui import ( "fmt" + "net/url" "strconv" "strings" ) @@ -69,6 +70,8 @@ type Session interface { DownloadFile(path string) //DownloadFileData downloads (saves) on the client side a file with a specified name and specified content. DownloadFileData(filename string, data []byte) + // OpenURL opens the url in the new browser tab + OpenURL(url string) registerAnimation(props []AnimatedProperty) string @@ -448,3 +451,11 @@ func (session *sessionData) SetTitleColor(color Color) { func (session *sessionData) RemoteAddr() string { return session.brige.remoteAddr() } + +func (session *sessionData) OpenURL(urlStr string) { + if _, err := url.ParseRequestURI(urlStr); err != nil { + ErrorLog(err.Error()) + return + } + session.runScript(`window.open("` + urlStr + `", "_blank");`) +} diff --git a/tableView.go b/tableView.go index e57105d..82870e5 100644 --- a/tableView.go +++ b/tableView.go @@ -622,7 +622,7 @@ func (table *tableViewData) propertyChanged(tag string) { updateProperty(htmlID, "tabindex", "0", session) updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)", session) updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)", session) - updateProperty(htmlID, "data-selection", "cell", session) + updateProperty(htmlID, "data-selection", "row", session) updateProperty(htmlID, "data-focusitemstyle", table.currentStyle(), session) updateProperty(htmlID, "data-bluritemstyle", table.currentInactiveStyle(), session) diff --git a/videoPlayer.go b/videoPlayer.go index 813997a..b9db00e 100644 --- a/videoPlayer.go +++ b/videoPlayer.go @@ -1,7 +1,6 @@ package rui import ( - "fmt" "strings" ) @@ -90,9 +89,9 @@ func (player *videoPlayerData) set(tag string, value any) bool { if player.mediaPlayerData.set(tag, value) { session := player.Session() updateSize := func(cssTag string) { - if size, ok := floatProperty(player, tag, session, 0); ok { - if size > 0 { - updateProperty(player.htmlID(), cssTag, fmt.Sprintf("%g", size), session) + if size, ok := floatTextProperty(player, tag, session, 0); ok { + if size != "0" { + updateProperty(player.htmlID(), cssTag, size, session) } else { removeProperty(player.htmlID(), cssTag, session) } @@ -122,12 +121,16 @@ func (player *videoPlayerData) htmlProperties(self View, buffer *strings.Builder session := player.Session() - if size, ok := floatProperty(player, VideoWidth, session, 0); ok && size > 0 { - buffer.WriteString(fmt.Sprintf(` width="%g"`, size)) + if size, ok := floatTextProperty(player, VideoWidth, session, 0); ok && size != "0" { + buffer.WriteString(` width="`) + buffer.WriteString(size) + buffer.WriteString(`"`) } - if size, ok := floatProperty(player, VideoHeight, session, 0); ok && size > 0 { - buffer.WriteString(fmt.Sprintf(` height="%g"`, size)) + if size, ok := floatTextProperty(player, VideoHeight, session, 0); ok && size != "0" { + buffer.WriteString(` height="`) + buffer.WriteString(size) + buffer.WriteString(`"`) } if url, ok := stringProperty(player, Poster, session); ok && url != "" { diff --git a/view.go b/view.go index cf4380a..81c8b5f 100644 --- a/view.go +++ b/view.go @@ -655,8 +655,8 @@ func viewPropertyChanged(view *viewData, tag string) { for _, floatTag := range []string{Opacity, ScaleX, ScaleY, ScaleZ, RotateX, RotateY, RotateZ} { if tag == floatTag { - if f, ok := floatProperty(view, floatTag, session, 0); ok { - updateCSSProperty(htmlID, floatTag, strconv.FormatFloat(f, 'g', -1, 64), session) + if f, ok := floatTextProperty(view, floatTag, session, 0); ok { + updateCSSProperty(htmlID, floatTag, f, session) } return } diff --git a/viewFilter.go b/viewFilter.go index 734aabb..a19cd52 100644 --- a/viewFilter.go +++ b/viewFilter.go @@ -180,20 +180,22 @@ func (filter *viewFilter) cssStyle(session Session) string { buffer := allocStringBuilder() defer freeStringBuilder(buffer) - if value, ok := floatProperty(filter, Blur, session, 0); ok { - size := SizeUnit{Type: SizeInPixel, Value: value} + if value, ok := floatTextProperty(filter, Blur, session, 0); ok { buffer.WriteString(Blur) buffer.WriteRune('(') - buffer.WriteString(size.cssString("0px")) - buffer.WriteRune(')') + buffer.WriteString(value) + buffer.WriteString("px)") } for _, tag := range []string{Brightness, Contrast, Saturate, Grayscale, Invert, Opacity, Sepia} { - if value, ok := floatProperty(filter, tag, session, 0); ok { + if value, ok := floatTextProperty(filter, tag, session, 0); ok { if buffer.Len() > 0 { buffer.WriteRune(' ') } - buffer.WriteString(fmt.Sprintf("%s(%g%%)", tag, value)) + buffer.WriteString(tag) + buffer.WriteRune('(') + buffer.WriteString(value) + buffer.WriteString("%)") } } diff --git a/viewTransform.go b/viewTransform.go index a69e876..af0adbd 100644 --- a/viewTransform.go +++ b/viewTransform.go @@ -1,9 +1,5 @@ package rui -import ( - "strconv" -) - const ( // Perspective is the name of the SizeUnit property that determines the distance between the z = 0 plane // and the user in order to give a 3D-positioned element some perspective. Each 3D element @@ -104,20 +100,6 @@ func getTranslate(style Properties, session Session) (SizeUnit, SizeUnit, SizeUn return x, y, z } -func getScale(style Properties, session Session) (float64, float64, float64, bool) { - scaleX, okX := floatProperty(style, ScaleX, session, 1) - scaleY, okY := floatProperty(style, ScaleY, session, 1) - scaleZ, okZ := floatProperty(style, ScaleZ, session, 1) - return scaleX, scaleY, scaleZ, okX || okY || okZ -} - -func getRotateVector(style Properties, session Session) (float64, float64, float64) { - rotateX, _ := floatProperty(style, RotateX, session, 1) - rotateY, _ := floatProperty(style, RotateY, session, 1) - rotateZ, _ := floatProperty(style, RotateZ, session, 1) - return rotateX, rotateY, rotateZ -} - func (style *viewStyle) transform(session Session) string { buffer := allocStringBuilder() @@ -133,7 +115,10 @@ func (style *viewStyle) transform(session Session) string { } x, y, z := getTranslate(style, session) - scaleX, scaleY, scaleZ, scaleOK := getScale(style, session) + + scaleX, okScaleX := floatTextProperty(style, ScaleX, session, 1) + scaleY, okScaleY := floatTextProperty(style, ScaleY, session, 1) + if getTransform3D(style, session) { if x.Type != Auto || y.Type != Auto || z.Type != Auto { if buffer.Len() > 0 { @@ -148,30 +133,34 @@ func (style *viewStyle) transform(session Session) string { buffer.WriteRune(')') } - if scaleOK { + scaleZ, okScaleZ := floatTextProperty(style, ScaleZ, session, 1) + if okScaleX || okScaleY || okScaleZ { if buffer.Len() > 0 { buffer.WriteRune(' ') } buffer.WriteString(`scale3d(`) - buffer.WriteString(strconv.FormatFloat(scaleX, 'g', -1, 64)) + buffer.WriteString(scaleX) buffer.WriteRune(',') - buffer.WriteString(strconv.FormatFloat(scaleY, 'g', -1, 64)) + buffer.WriteString(scaleY) buffer.WriteRune(',') - buffer.WriteString(strconv.FormatFloat(scaleZ, 'g', -1, 64)) + buffer.WriteString(scaleZ) buffer.WriteRune(')') } if angle, ok := angleProperty(style, Rotate, session); ok { - rotateX, rotateY, rotateZ := getRotateVector(style, session) + rotateX, _ := floatTextProperty(style, RotateX, session, 1) + rotateY, _ := floatTextProperty(style, RotateY, session, 1) + rotateZ, _ := floatTextProperty(style, RotateZ, session, 1) + if buffer.Len() > 0 { buffer.WriteRune(' ') } buffer.WriteString(`rotate3d(`) - buffer.WriteString(strconv.FormatFloat(rotateX, 'g', -1, 64)) + buffer.WriteString(rotateX) buffer.WriteRune(',') - buffer.WriteString(strconv.FormatFloat(rotateY, 'g', -1, 64)) + buffer.WriteString(rotateY) buffer.WriteRune(',') - buffer.WriteString(strconv.FormatFloat(rotateZ, 'g', -1, 64)) + buffer.WriteString(rotateZ) buffer.WriteRune(',') buffer.WriteString(angle.cssString()) buffer.WriteRune(')') @@ -189,14 +178,14 @@ func (style *viewStyle) transform(session Session) string { buffer.WriteRune(')') } - if scaleOK { + if okScaleX || okScaleY { if buffer.Len() > 0 { buffer.WriteRune(' ') } buffer.WriteString(`scale(`) - buffer.WriteString(strconv.FormatFloat(scaleX, 'g', -1, 64)) + buffer.WriteString(scaleX) buffer.WriteRune(',') - buffer.WriteString(strconv.FormatFloat(scaleY, 'g', -1, 64)) + buffer.WriteString(scaleY) buffer.WriteRune(')') } diff --git a/viewUtils.go b/viewUtils.go index aafe275..ace84a7 100644 --- a/viewUtils.go +++ b/viewUtils.go @@ -368,7 +368,9 @@ func GetTextWeight(view View, subviewID string) int { } // GetTextAlign returns a text align of the subview. Returns one of next values: -// LeftAlign = 0, RightAlign = 1, CenterAlign = 2, JustifyAlign = 3 +// +// LeftAlign = 0, RightAlign = 1, CenterAlign = 2, JustifyAlign = 3 +// // If the second argument (subviewID) is "" then a value from the first argument (view) is returned. func GetTextAlign(view View, subviewID string) int { return enumStyledProperty(view, subviewID, TextAlign, LeftAlign, true) @@ -601,7 +603,11 @@ func GetScale(view View, subviewID string) (float64, float64, float64) { if view == nil { return 1, 1, 1 } - x, y, z, _ := getScale(view, view.Session()) + + session := view.Session() + x, _ := floatProperty(view, ScaleX, session, 1) + y, _ := floatProperty(view, ScaleY, session, 1) + z, _ := floatProperty(view, ScaleZ, session, 1) return x, y, z } @@ -615,8 +621,11 @@ func GetRotate(view View, subviewID string) (float64, float64, float64, AngleUni return 0, 0, 0, AngleUnit{Value: 0, Type: Radian} } + session := view.Session() angle, _ := angleProperty(view, Rotate, view.Session()) - rotateX, rotateY, rotateZ := getRotateVector(view, view.Session()) + rotateX, _ := floatProperty(view, RotateX, session, 1) + rotateY, _ := floatProperty(view, RotateY, session, 1) + rotateZ, _ := floatProperty(view, RotateZ, session, 1) return rotateX, rotateY, rotateZ, angle }