Added: "focusable" and "user-data" properties, ConstantTags and ColorTags function to Session, ReloadTableViewData function. Bug fixing

This commit is contained in:
Alexei Anoshenko 2022-04-14 12:05:45 +03:00
parent 1e3c820c61
commit 8a625dcc78
17 changed files with 216 additions and 133 deletions

4
.vscode/launch.json vendored
View File

@ -9,8 +9,8 @@
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"program": "${workspaceRoot}/demo", //"program": "${workspaceRoot}/demo",
//"program": "${workspaceRoot}/editor", "program": "${workspaceRoot}/ruiEditor",
"env": {}, "env": {},
"args": [] "args": []
} }

View File

@ -1,3 +1,9 @@
# v0.6.0
* Added "user-data" property
* Added "focusable" property
* Added ReloadTableViewData function
# v0.5.0 # v0.5.0
* NewApplication function and Start function of the Application interface were replaced by StartApp function * NewApplication function and Start function of the Application interface were replaced by StartApp function

View File

@ -1679,6 +1679,10 @@ radius необходимо передать nil
func GetSkew(view View, subviewID string) (AngleUnit, AngleUnit) func GetSkew(view View, subviewID string) (AngleUnit, AngleUnit)
### Пользовательские данные
Вы можете сохранить любые ваши данные в виде свойства "user-data" (константа UserData)
### События клавиатуры ### События клавиатуры
Для View получившего фокус ввода могут генерироваться два вида событий клавиатуры Для View получившего фокус ввода могут генерироваться два вида событий клавиатуры
@ -2682,16 +2686,16 @@ EditTextChangedEvent). Основной слушатель события име
func NewNumberPicker(session Session, params Params) NumberPicker func NewNumberPicker(session Session, params Params) NumberPicker
NumberPicker может работать в двух режимах: редактор текста и слайдер. NumberPicker может работать в двух режимах: редактор текста и слайдер.
Режим устанавливает int свойство "date-picker-type" (константа NumberPickerType). Режим устанавливает int свойство "number-picker-type" (константа NumberPickerType).
Свойство "date-picker-type" может принимать следующие значения: Свойство "number-picker-type" может принимать следующие значения:
| Значение | Константа | Имя | Тип редактора | | Значение | Константа | Имя | Тип редактора |
|:--------:|--------------|----------|----------------------------------------| |:--------:|--------------|----------|----------------------------------------|
| 0 | NumberEditor | "editor" | Редактор текста. Значение по умолчанию | | 0 | NumberEditor | "editor" | Редактор текста. Значение по умолчанию |
| 1 | NumberSlider | "slider" | Слайдер | | 1 | NumberSlider | "slider" | Слайдер |
Установить/прочитать текущее значение можно с помощью свойства "date-picker-value" Установить/прочитать текущее значение можно с помощью свойства "number-picker-value"
(константа NumberPickerValue). В качестве значения свойству "date-picker-value" могут быть переданы: (константа NumberPickerValue). В качестве значения свойству "number-picker-value" могут быть переданы:
* float64 * float64
* float32 * float32
@ -2702,7 +2706,7 @@ NumberPicker может работать в двух режимах: редак
* текстовое представление любых из выше перечисленых типов * текстовое представление любых из выше перечисленых типов
Все эти типы приводятся к float64. Соответственно функция Get всегда возвращает float64 значение. Все эти типы приводятся к float64. Соответственно функция Get всегда возвращает float64 значение.
Прочитано значение свойства "date-picker-value" может быть также с помощью функции: Прочитано значение свойства "number-picker-value" может быть также с помощью функции:
func GetNumberPickerValue(view View, subviewID string) float64 func GetNumberPickerValue(view View, subviewID string) float64
@ -2710,14 +2714,14 @@ NumberPicker может работать в двух режимах: редак
| Свойство | Константа | Ограничение | | Свойство | Константа | Ограничение |
|----------------------|------------------|------------------------| |----------------------|------------------|------------------------|
| "date-picker-min" | NumberPickerMin | Минимальное значение | | "number-picker-min" | NumberPickerMin | Минимальное значение |
| "date-picker-max" | NumberPickerMax | Максимальное значение | | "number-picker-max" | NumberPickerMax | Максимальное значение |
| "date-picker-step" | NumberPickerStep | Шаг изменения значения | | "number-picker-step" | NumberPickerStep | Шаг изменения значения |
Присвоины данным свойствам могут те же типы значений, что и "date-picker-value". Присвоины данным свойствам могут те же типы значений, что и "number-picker-value".
По умолчанию, в случае если "date-picker-type" равно NumberSlider, минимальное значение равно 0, По умолчанию, в случае если "number-picker-type" равно NumberSlider, минимальное значение равно 0,
максимальное - 1. Если же "date-picker-type" равно NumberEditor то вводимые числа, по умолчанию, максимальное - 1. Если же "number-picker-type" равно NumberEditor то вводимые числа, по умолчанию,
ограничены лишь диапазоном значений float64. ограничены лишь диапазоном значений float64.
Прочитать значения данных свойств можно с помощью функций: Прочитать значения данных свойств можно с помощью функций:
@ -2725,7 +2729,7 @@ NumberPicker может работать в двух режимах: редак
func GetNumberPickerMinMax(view View, subviewID string) (float64, float64) func GetNumberPickerMinMax(view View, subviewID string) (float64, float64)
func GetNumberPickerStep(view View, subviewID string) float64 func GetNumberPickerStep(view View, subviewID string) float64
Для отслеживания изменения вводимого значения используется событие "date-changed" (константа Для отслеживания изменения вводимого значения используется событие "number-changed" (константа
NumberChangedEvent). Основной слушатель события имеет следующий формат: NumberChangedEvent). Основной слушатель события имеет следующий формат:
func(picker NumberPicker, newValue float64) func(picker NumberPicker, newValue float64)

View File

@ -1654,6 +1654,10 @@ You can get the value of these properties using the function
func GetSkew(view View, subviewID string) (AngleUnit, AngleUnit) func GetSkew(view View, subviewID string) (AngleUnit, AngleUnit)
### User data
You can save any of your data as "user-data" property (UserData constant)
### Keyboard events ### Keyboard events
Two kinds of keyboard events can be generated for a View that has received input focus. Two kinds of keyboard events can be generated for a View that has received input focus.
@ -2648,16 +2652,16 @@ To create a NumberPicker, the function is used:
func NewNumberPicker(session Session, params Params) NumberPicker func NewNumberPicker(session Session, params Params) NumberPicker
NumberPicker can work in two modes: text editor and slider. NumberPicker can work in two modes: text editor and slider.
The mode sets the int property "date-picker-type" (NumberPickerType constant). The mode sets the int property "number-picker-type" (NumberPickerType constant).
The "date-picker-type" property can take the following values: The "number-picker-type" property can take the following values:
| Value | Constant | Name | Editor type | | Value | Constant | Name | Editor type |
|:-----:|--------------|----------|----------------------------| |:-----:|--------------|----------|----------------------------|
| 0 | NumberEditor | "editor" | Text editor. Default value | | 0 | NumberEditor | "editor" | Text editor. Default value |
| 1 | NumberSlider | "slider" | Slider | | 1 | NumberSlider | "slider" | Slider |
You can set/get the current value using the "date-picker-value" property (NumberPickerValue constant). You can set/get the current value using the "number-picker-value" property (NumberPickerValue constant).
The following can be passed as a value to the "date-picker-value" property: The following can be passed as a value to the "number-picker-value" property:
* float64 * float64
* float32 * float32
@ -2668,29 +2672,29 @@ The following can be passed as a value to the "date-picker-value" property:
* textual representation of any of the above types * textual representation of any of the above types
All of these types are cast to float64. Accordingly, the Get function always returns a float64 value. All of these types are cast to float64. Accordingly, the Get function always returns a float64 value.
The value of the "date-picker-value" property can also be read using the function: The value of the "number-picker-value" property can also be read using the function:
func GetNumberPickerValue(view View, subviewID string) float64 func GetNumberPickerValue(view View, subviewID string) float64
The entered values may be subject to restrictions. For this, the following properties are used: The entered values may be subject to restrictions. For this, the following properties are used:
| Property | Constant | Restriction | | Property | Constant | Restriction |
|--------------------|------------------|-------------------| |----------------------|------------------|-------------------|
| "date-picker-min" | NumberPickerMin | Minimum value | | "number-picker-min" | NumberPickerMin | Minimum value |
| "date-picker-max" | NumberPickerMax | Maximum value | | "number-picker-max" | NumberPickerMax | Maximum value |
| "date-picker-step" | NumberPickerStep | Value change step | | "number-picker-step" | NumberPickerStep | Value change step |
Assignments to these properties can be the same value types as "date-picker-value". Assignments to these properties can be the same value types as "number-picker-value".
By default, if "date-picker-type" is equal to NumberSlider, the minimum value is 0, maximum is 1. By default, if "number-picker-type" is equal to NumberSlider, the minimum value is 0, maximum is 1.
If "date-picker-type" is equal to NumberEditor, then the entered numbers, by default, are limited only by the range of float64 values. If "number-picker-type" is equal to NumberEditor, then the entered numbers, by default, are limited only by the range of float64 values.
You can read the values of these properties using the functions: You can read the values of these properties using the functions:
func GetNumberPickerMinMax(view View, subviewID string) (float64, float64) func GetNumberPickerMinMax(view View, subviewID string) (float64, float64)
func GetNumberPickerStep(view View, subviewID string) float64 func GetNumberPickerStep(view View, subviewID string) float64
The "date-changed" event (NumberChangedEvent constant) is used to track the change in the entered value. The "number-changed" event (NumberChangedEvent constant) is used to track the change in the entered value.
The main event listener has the following format: The main event listener has the following format:
func(picker NumberPicker, newValue float64) func(picker NumberPicker, newValue float64)

View File

@ -1759,7 +1759,7 @@ function tableRowClickEvent(element, event) {
const table = document.getElementById(tableID); const table = document.getElementById(tableID);
if (table) { if (table) {
const selection = table.getAttribute("data-selection"); const selection = table.getAttribute("data-selection");
if (selection == "cell") { if (selection == "row") {
const currentID = table.getAttribute("data-current"); const currentID = table.getAttribute("data-current");
if (!currentID || currentID != element.ID) { if (!currentID || currentID != element.ID) {
setTableRowCursor(table, row) setTableRowCursor(table, row)

View File

@ -21,13 +21,25 @@ div:focus {
} }
input { input {
padding: 4px; margin: 2px;
overflow: auto; padding: 1px;
font-size: inherit;
}
select {
margin: 2px;
font-size: inherit;
}
button {
font-size: inherit;
} }
textarea { textarea {
padding: 4px; margin: 2px;
padding: 1px;
overflow: auto; overflow: auto;
font-size: inherit;
} }
ul:focus { ul:focus {

View File

@ -65,7 +65,7 @@ theme {
styles = [ styles = [
ruiApp { ruiApp {
font-name = "Arial, Helvetica, sans-serif", font-name = "Arial, Helvetica, sans-serif",
text-size = 12pt, text-size = 10pt,
text-color = @ruiTextColor, text-color = @ruiTextColor,
background-color = @ruiBackgroundColor, background-color = @ruiBackgroundColor,
}, },

View File

@ -9,6 +9,9 @@ const (
StyleDisabled = "style-disabled" StyleDisabled = "style-disabled"
// Disabled is the constant for the "disabled" property tag. // Disabled is the constant for the "disabled" property tag.
Disabled = "disabled" Disabled = "disabled"
// Focusable is the constant for the "disabled" property tag.
// The bool "focusable" determines whether the view will receive focus.
Focusable = "focusable"
// Semantics is the constant for the "semantics" property tag. // Semantics is the constant for the "semantics" property tag.
Semantics = "semantics" Semantics = "semantics"
// Visibility is the constant for the "visibility" property tag. // Visibility is the constant for the "visibility" property tag.
@ -440,4 +443,7 @@ const (
// The "float" property places a View on the left or right side of its container, // The "float" property places a View on the left or right side of its container,
// allowing text and inline Views to wrap around it. // allowing text and inline Views to wrap around it.
Float = "float" Float = "float"
// UsetData is the constant for the "user-data" property tag.
// This property can contain any user data
UserData = "user-data"
) )

View File

@ -37,6 +37,7 @@ var angleProperties = []string{
var boolProperties = []string{ var boolProperties = []string{
Disabled, Disabled,
Focusable,
Inset, Inset,
BackfaceVisible, BackfaceVisible,
ReadOnly, ReadOnly,

View File

@ -29,8 +29,12 @@ type Session interface {
TextDirection() int TextDirection() int
// Constant returns the constant with "tag" name or "" if it is not exists // Constant returns the constant with "tag" name or "" if it is not exists
Constant(tag string) (string, bool) Constant(tag string) (string, bool)
// ConstantTags returns the list of all available constants
ConstantTags() []string
// Color returns the color with "tag" name or 0 if it is not exists // Color returns the color with "tag" name or 0 if it is not exists
Color(tag string) (Color, bool) Color(tag string) (Color, bool)
// ColorTags returns the list of all available color constants
ColorTags() []string
// SetCustomTheme set the custom theme // SetCustomTheme set the custom theme
SetCustomTheme(name string) bool SetCustomTheme(name string) bool
// UserAgent returns the "user-agent" text of the client browser // UserAgent returns the "user-agent" text of the client browser
@ -106,6 +110,7 @@ type Session interface {
type sessionData struct { type sessionData struct {
customTheme *theme customTheme *theme
currentTheme *theme
darkTheme bool darkTheme bool
touchScreen bool touchScreen bool
textDirection int textDirection int
@ -146,6 +151,7 @@ func newSession(app Application, id int, customTheme string, params DataObject)
if customTheme != "" { if customTheme != "" {
if theme, ok := newTheme(customTheme); ok { if theme, ok := newTheme(customTheme); ok {
session.customTheme = theme session.customTheme = theme
session.currentTheme = nil
} }
} }
@ -206,18 +212,11 @@ func (session *sessionData) close() {
} }
func (session *sessionData) styleProperty(styleTag, propertyTag string) (string, bool) { func (session *sessionData) styleProperty(styleTag, propertyTag string) (string, bool) {
var style DataObject if style, ok := session.getCurrentTheme().styles[styleTag]; ok {
ok := false if value, ok := style[propertyTag]; ok {
if session.customTheme != nil { if text, ok := value.(string); ok {
style, ok = session.customTheme.styles[styleTag] return session.resolveConstants(text)
} }
if !ok {
style, ok = defaultTheme.styles[styleTag]
}
if ok {
if node := style.PropertyWithTag(propertyTag); node != nil && node.Type() == TextNode {
return session.resolveConstants(node.Text())
} }
} }
@ -226,17 +225,12 @@ func (session *sessionData) styleProperty(styleTag, propertyTag string) (string,
} }
func (session *sessionData) stylePropertyNode(styleTag, propertyTag string) DataNode { func (session *sessionData) stylePropertyNode(styleTag, propertyTag string) DataNode {
var style DataObject if style, ok := session.getCurrentTheme().styles[styleTag]; ok {
ok := false if value, ok := style[propertyTag]; ok {
if session.customTheme != nil { if node, ok := value.(DataNode); ok {
style, ok = session.customTheme.styles[styleTag] return node
} }
if !ok { }
style, ok = defaultTheme.styles[styleTag]
}
if ok {
return style.PropertyWithTag(propertyTag)
} }
return nil return nil
@ -280,17 +274,7 @@ func (session *sessionData) RootView() View {
} }
func (session *sessionData) writeInitScript(writer *strings.Builder) { func (session *sessionData) writeInitScript(writer *strings.Builder) {
var workTheme *theme if css := session.getCurrentTheme().cssText(session); css != "" {
if session.customTheme == nil {
workTheme = defaultTheme
} else {
workTheme = new(theme)
workTheme.init()
workTheme.concat(defaultTheme)
workTheme.concat(session.customTheme)
}
if css := workTheme.cssText(session); css != "" {
writer.WriteString(`document.querySelector('style').textContent += "`) writer.WriteString(`document.querySelector('style').textContent += "`)
writer.WriteString(css) writer.WriteString(css)
writer.WriteString("\";\n") writer.WriteString("\";\n")

View File

@ -2,24 +2,10 @@ package rui
import ( import (
"fmt" "fmt"
"sort"
"strings" "strings"
) )
/*
type Session struct {
customTheme *theme
darkTheme bool
touchScreen bool
textDirection int
pixelRatio float64
language string
languages []string
checkboxOff string
checkboxOn string
radiobuttonOff string
radiobuttonOn string
}
*/
func (session *sessionData) DarkTheme() bool { func (session *sessionData) DarkTheme() bool {
return session.darkTheme return session.darkTheme
} }
@ -39,27 +25,17 @@ func (session *sessionData) TextDirection() int {
func (session *sessionData) constant(tag string, prevTags []string) (string, bool) { func (session *sessionData) constant(tag string, prevTags []string) (string, bool) {
tags := append(prevTags, tag) tags := append(prevTags, tag)
result := "" result := ""
themes := session.themes() theme := session.getCurrentTheme()
for { for {
ok := false ok := false
if session.touchScreen { if session.touchScreen {
for _, theme := range themes { if theme.touchConstants != nil {
if theme.touchConstants != nil { result, ok = theme.touchConstants[tag]
if result, ok = theme.touchConstants[tag]; ok {
break
}
}
} }
} }
if !ok { if !ok {
for _, theme := range themes { result, ok = theme.constants[tag]
if theme.constants != nil {
if result, ok = theme.constants[tag]; ok {
break
}
}
}
} }
if !ok { if !ok {
@ -149,38 +125,38 @@ func (session *sessionData) Constant(tag string) (string, bool) {
return session.constant(tag, []string{}) return session.constant(tag, []string{})
} }
func (session *sessionData) themes() []*theme { func (session *sessionData) getCurrentTheme() *theme {
if session.customTheme != nil { if session.currentTheme != nil {
return []*theme{session.customTheme, defaultTheme} return session.currentTheme
} }
return []*theme{defaultTheme} if session.customTheme != nil {
session.currentTheme = new(theme)
session.currentTheme.init()
session.currentTheme.concat(defaultTheme)
session.currentTheme.concat(session.customTheme)
return session.currentTheme
}
return defaultTheme
} }
// Color return the color with "tag" name or 0 if it is not exists // Color return the color with "tag" name or 0 if it is not exists
func (session *sessionData) Color(tag string) (Color, bool) { func (session *sessionData) Color(tag string) (Color, bool) {
tags := []string{tag} tags := []string{tag}
result := "" result := ""
themes := session.themes() theme := session.getCurrentTheme()
for { for {
ok := false ok := false
if session.darkTheme { if session.darkTheme {
for _, theme := range themes { if theme.darkColors != nil {
if theme.darkColors != nil { result, ok = theme.darkColors[tag]
if result, ok = theme.darkColors[tag]; ok {
break
}
}
} }
} }
if !ok { if !ok {
for _, theme := range themes { if theme.colors != nil {
if theme.colors != nil { result, ok = theme.colors[tag]
if result, ok = theme.colors[tag]; ok {
break
}
}
} }
} }
@ -217,6 +193,7 @@ func (session *sessionData) SetCustomTheme(name string) bool {
} }
} else if theme, ok := resources.themes[name]; ok { } else if theme, ok := resources.themes[name]; ok {
session.customTheme = theme session.customTheme = theme
session.currentTheme = nil
} else { } else {
return false return false
} }
@ -361,3 +338,39 @@ func (session *sessionData) SetLanguage(lang string) {
} }
} }
} }
func (session *sessionData) ConstantTags() []string {
theme := session.getCurrentTheme()
keys := make([]string, 0, len(theme.constants))
for k := range theme.constants {
keys = append(keys, k)
}
for tag := range theme.touchConstants {
if _, ok := theme.constants[tag]; !ok {
keys = append(keys, tag)
}
}
sort.Strings(keys)
return keys
}
func (session *sessionData) ColorTags() []string {
theme := session.getCurrentTheme()
keys := make([]string, 0, len(theme.colors))
for k := range theme.colors {
keys = append(keys, k)
}
for tag := range theme.darkColors {
if _, ok := theme.colors[tag]; !ok {
keys = append(keys, tag)
}
}
sort.Strings(keys)
return keys
}

View File

@ -230,3 +230,21 @@ func GetTableRowSelectedListeners(view View, subviewID string) []func(TableView,
} }
return []func(TableView, int){} return []func(TableView, int){}
} }
// ReloadTableViewData updates TableView
func ReloadTableViewData(view View, subviewID string) bool {
var tableView TableView
if subviewID != "" {
if tableView = TableViewByID(view, subviewID); tableView == nil {
return false
}
} else {
var ok bool
if tableView, ok = view.(TableView); !ok {
return false
}
}
tableView.ReloadTableData()
return true
}

View File

@ -147,7 +147,7 @@ func (tabsLayout *tabsLayoutData) remove(tag string) {
return return
} }
if tabsLayout.created { if tabsLayout.created {
tabsLayout.session.runScript(fmt.Sprintf("activateTab(%v, %d);", tabsLayout.htmlID(), 0)) tabsLayout.session.runScript(fmt.Sprintf("activateTab('%v', %d);", tabsLayout.htmlID(), 0))
for _, listener := range tabsLayout.tabListener { for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, 0, oldCurrent) listener(tabsLayout, 0, oldCurrent)
} }
@ -224,7 +224,7 @@ func (tabsLayout *tabsLayoutData) set(tag string, value interface{}) bool {
return true return true
} }
if tabsLayout.created { if tabsLayout.created {
tabsLayout.session.runScript(fmt.Sprintf("activateTab(%v, %d);", tabsLayout.htmlID(), current)) tabsLayout.session.runScript(fmt.Sprintf("activateTab('%v', %d);", tabsLayout.htmlID(), current))
for _, listener := range tabsLayout.tabListener { for _, listener := range tabsLayout.tabListener {
listener(tabsLayout, current, oldCurrent) listener(tabsLayout, current, oldCurrent)
} }

View File

@ -16,7 +16,7 @@ type mediaStyle struct {
orientation int orientation int
width int width int
height int height int
styles map[string]DataObject styles map[string]Params
} }
func (rule mediaStyle) cssText() string { func (rule mediaStyle) cssText() string {
@ -47,7 +47,7 @@ func (rule mediaStyle) cssText() string {
} }
func parseMediaRule(text string) (mediaStyle, bool) { func parseMediaRule(text string) (mediaStyle, bool) {
rule := mediaStyle{orientation: defaultMedia, width: 0, height: 0, styles: map[string]DataObject{}} rule := mediaStyle{orientation: defaultMedia, width: 0, height: 0, styles: map[string]Params{}}
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 {
@ -111,7 +111,7 @@ type theme struct {
touchConstants map[string]string touchConstants map[string]string
colors map[string]string colors map[string]string
darkColors map[string]string darkColors map[string]string
styles map[string]DataObject styles map[string]Params
mediaStyles []mediaStyle mediaStyles []mediaStyle
} }
@ -129,7 +129,7 @@ func (theme *theme) init() {
theme.touchConstants = map[string]string{} theme.touchConstants = map[string]string{}
theme.colors = map[string]string{} theme.colors = map[string]string{}
theme.darkColors = map[string]string{} theme.darkColors = map[string]string{}
theme.styles = map[string]DataObject{} theme.styles = map[string]Params{}
theme.mediaStyles = []mediaStyle{} theme.mediaStyles = []mediaStyle{}
} }
@ -189,7 +189,9 @@ func (theme *theme) cssText(session Session) string {
for tag, obj := range theme.styles { for tag, obj := range theme.styles {
var style viewStyle var style viewStyle
style.init() style.init()
parseProperties(&style, obj) 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()
@ -200,7 +202,9 @@ func (theme *theme) cssText(session Session) string {
for tag, obj := range media.styles { for tag, obj := range media.styles {
var style viewStyle var style viewStyle
style.init() style.init()
parseProperties(&style, obj) 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()
@ -234,6 +238,25 @@ func (theme *theme) addData(data DataObject) {
func (theme *theme) parseThemeData(data DataObject) { func (theme *theme) parseThemeData(data DataObject) {
count := data.PropertyCount() count := data.PropertyCount()
objToParams := func(obj DataObject) Params {
params := Params{}
for i := 0; i < obj.PropertyCount(); i++ {
if node := obj.Property(i); node != nil {
switch node.Type() {
case ArrayNode:
params[node.Tag()] = node.ArrayElements()
case ObjectNode:
params[node.Tag()] = node.Object()
default:
params[node.Tag()] = node.Text()
}
}
}
return params
}
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
if d := data.Property(i); d != nil { if d := data.Property(i); d != nil {
switch tag := d.Tag(); tag { switch tag := d.Tag(); tag {
@ -291,7 +314,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 {
theme.styles[obj.Tag()] = obj theme.styles[obj.Tag()] = objToParams(obj)
} }
} }
} }
@ -304,7 +327,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()] = obj rule.styles[obj.Tag()] = objToParams(obj)
} }
} }
} }

View File

@ -177,6 +177,9 @@ func (view *viewData) ViewByID(id string) View {
} }
func (view *viewData) Focusable() bool { func (view *viewData) Focusable() bool {
if focus, ok := boolProperty(view, Focusable, view.session); ok {
return focus
}
return false return false
} }
@ -189,6 +192,9 @@ func (view *viewData) remove(tag string) {
case ID: case ID:
view.viewID = "" view.viewID = ""
case UserData:
delete(view.properties, tag)
case Style, StyleDisabled: case Style, StyleDisabled:
if _, ok := view.properties[tag]; ok { if _, ok := view.properties[tag]; ok {
delete(view.properties, tag) delete(view.properties, tag)
@ -311,6 +317,9 @@ func (view *viewData) set(tag string, value interface{}) bool {
} }
view.viewID = text view.viewID = text
case UserData:
view.properties[tag] = value
case Style, StyleDisabled: case Style, StyleDisabled:
text, ok := value.(string) text, ok := value.(string)
if !ok { if !ok {

View File

@ -1,6 +1,7 @@
package rui package rui
import ( import (
"os"
"path/filepath" "path/filepath"
"strings" "strings"
) )
@ -135,5 +136,13 @@ func CreateViewFromResources(session Session, name string) View {
} }
} }
if resources.path != "" {
if data, err := os.ReadFile(resources.path + viewDir + "/" + name); err == nil {
if data := ParseDataText(string(data)); data != nil {
return CreateViewFromObject(session, data)
}
}
}
return nil return nil
} }

View File

@ -1053,19 +1053,13 @@ func GetCurrent(view View, subviewID string) int {
view = ViewByID(view, subviewID) view = ViewByID(view, subviewID)
} }
var defaultValue int defaultValue := -1
switch view.Tag() {
case "ListView":
defaultValue = -1
default:
defaultValue = 0
}
if view != nil { if view != nil {
if result, ok := intProperty(view, Current, view.Session(), defaultValue); ok { if result, ok := intProperty(view, Current, view.Session(), defaultValue); ok {
return result return result
} else if view.Tag() != "ListView" {
defaultValue = 0
} }
} }
return -1 return defaultValue
} }