mirror of https://github.com/anoshenko/rui.git
Compare commits
16 Commits
Author | SHA1 | Date |
---|---|---|
|
c3c8b9e858 | |
|
3090a0e94f | |
|
b0185726db | |
|
2dd8d8d256 | |
|
4cec7fef26 | |
|
e618377c11 | |
|
73b14ed78a | |
|
bbbaf28aba | |
|
0433f460e4 | |
|
d633c80155 | |
|
cb4d197bb7 | |
|
2f07584b37 | |
|
24aeeb515b | |
|
f2fb948325 | |
|
4b00299878 | |
|
3c3c09b043 |
|
@ -1,3 +1,9 @@
|
||||||
|
# v0.20.0
|
||||||
|
|
||||||
|
* Added support of binding
|
||||||
|
* Added "binding" argument to CreateViewFromResources, CreateViewFromText, and CreateViewFromObject functions
|
||||||
|
* Changed ParseDataText function return values
|
||||||
|
|
||||||
# v0.19.0
|
# v0.19.0
|
||||||
|
|
||||||
* Added support of drag-and-drop
|
* Added support of drag-and-drop
|
||||||
|
@ -5,7 +11,7 @@
|
||||||
|
|
||||||
# v0.18.2
|
# v0.18.2
|
||||||
|
|
||||||
* fixed typo: GetShadowPropertys -> GetShadowProperty
|
* fixed typo: GetShadowProperties -> GetShadowProperty
|
||||||
|
|
||||||
# v0.18.0
|
# v0.18.0
|
||||||
|
|
||||||
|
|
107
README-ru.md
107
README-ru.md
|
@ -161,8 +161,8 @@ SizeUnit объявлена как
|
||||||
| "sub(<arg1>, <arg2>)" | SubSize(arg0, arg1 any) | находит разность значений аргументов |
|
| "sub(<arg1>, <arg2>)" | SubSize(arg0, arg1 any) | находит разность значений аргументов |
|
||||||
| "mul(<arg1>, <arg2>)" | MulSize(arg0, arg1 any) | находит результат умножения значений аргументов |
|
| "mul(<arg1>, <arg2>)" | MulSize(arg0, arg1 any) | находит результат умножения значений аргументов |
|
||||||
| "div(<arg1>, <arg2>)" | DivSize(arg0, arg1 any) | находит результат деления значений аргументов |
|
| "div(<arg1>, <arg2>)" | DivSize(arg0, arg1 any) | находит результат деления значений аргументов |
|
||||||
| "rem(<arg1>, <arg2>)" | ModSize(arg0, arg1 any) | находит остаток деления значений аргументов, результат имеет тотже знак что и делимое |
|
| "rem(<arg1>, <arg2>)" | ModSize(arg0, arg1 any) | находит остаток деления значений аргументов, результат имеет тот же знак что и делимое |
|
||||||
| "mod(<arg1>, <arg2>)" | ModSize(arg0, arg1 any) | находит остаток деления значений аргументов, результат имеет тотже знак что и делитель |
|
| "mod(<arg1>, <arg2>)" | ModSize(arg0, arg1 any) | находит остаток деления значений аргументов, результат имеет тот же знак что и делитель |
|
||||||
| "round(<arg1>, <arg2>)" | RoundSize(arg0, arg1 any) | округляет первый аргумент до ближайшего целого числа кратного второму аргументу |
|
| "round(<arg1>, <arg2>)" | RoundSize(arg0, arg1 any) | округляет первый аргумент до ближайшего целого числа кратного второму аргументу |
|
||||||
| "round-up(<arg1>, <arg2>)" | RoundUpSize(arg0, arg1 any) | округляет первый аргумент до ближайшего большего целого числа, кратного второму аргументу |
|
| "round-up(<arg1>, <arg2>)" | RoundUpSize(arg0, arg1 any) | округляет первый аргумент до ближайшего большего целого числа, кратного второму аргументу |
|
||||||
| "round-down(<arg1>, <arg2>)" | RoundDownSize(arg0, arg1 any) | округляет первый аргумент до ближайшего меньшего целого числа кратного второму аргументу |
|
| "round-down(<arg1>, <arg2>)" | RoundDownSize(arg0, arg1 any) | округляет первый аргумент до ближайшего меньшего целого числа кратного второму аргументу |
|
||||||
|
@ -1086,7 +1086,7 @@ RadiusProperty, а не структура BoxRadius. Получить стру
|
||||||
|
|
||||||
Получить значение данного свойства можно с помощью функции
|
Получить значение данного свойства можно с помощью функции
|
||||||
|
|
||||||
func GetShadowPropertys(view View, subviewID ...string) []ShadowProperty
|
func GetShadowProperties(view View, subviewID ...string) []ShadowProperty
|
||||||
|
|
||||||
Если тень не задана, то данная функция вернет пустой массив
|
Если тень не задана, то данная функция вернет пустой массив
|
||||||
|
|
||||||
|
@ -2291,14 +2291,14 @@ radius необходимо передать nil
|
||||||
|
|
||||||
#### Свойство "drag-data"
|
#### Свойство "drag-data"
|
||||||
|
|
||||||
Для того чтобы сделать View перетаскиваемым ему неоходимо задать свойство "drag-data" (константа DragData).
|
Для того чтобы сделать View перетаскиваемым ему необходимо задать свойство "drag-data" (константа DragData).
|
||||||
Данное свойство задает множество перетаскиваемых данных в виде ключ:значение и имеет тип:
|
Данное свойство задает множество перетаскиваемых данных в виде ключ:значение и имеет тип:
|
||||||
|
|
||||||
map[string]string
|
map[string]string
|
||||||
|
|
||||||
В качестве ключей рекомендуется использовать mime-тип значения.
|
В качестве ключей рекомендуется использовать mime-тип значения.
|
||||||
Например, если в перетаскиваемыми данными асляется текст, то ключем должен быть "text/plain", если jpeg-изображение, то "image/jpg" и т.п.
|
Например, если в перетаскиваемыми данными является текст, то ключом должен быть "text/plain", если jpeg-изображение, то "image/jpg" и т.п.
|
||||||
Но это только рекомендация, ключем может быть любой текст.
|
Но это только рекомендация, ключом может быть любой текст.
|
||||||
|
|
||||||
Пример
|
Пример
|
||||||
|
|
||||||
|
@ -2318,7 +2318,7 @@ radius необходимо передать nil
|
||||||
По умолчанию при перетаскивании перемещается весь View. Часто это бывает не удобно, например если View очень большой.
|
По умолчанию при перетаскивании перемещается весь View. Часто это бывает не удобно, например если View очень большой.
|
||||||
|
|
||||||
Свойство "drag-image" (константа DragImage) типа string позволяет задать картинку, которая будет отображаться вместо View при перетаскивании.
|
Свойство "drag-image" (константа DragImage) типа string позволяет задать картинку, которая будет отображаться вместо View при перетаскивании.
|
||||||
В качестве значения "drag-image" задаеться:
|
В качестве значения "drag-image" задается:
|
||||||
* Имя изображения в ресурсах приложения
|
* Имя изображения в ресурсах приложения
|
||||||
* Константа изображения
|
* Константа изображения
|
||||||
* URL изображения
|
* URL изображения
|
||||||
|
@ -2442,15 +2442,15 @@ radius необходимо передать nil
|
||||||
|
|
||||||
#### События "drag-enter-event", "drag-leave-event" и "drag-over-event"
|
#### События "drag-enter-event", "drag-leave-event" и "drag-over-event"
|
||||||
|
|
||||||
События "drag-enter-event", "drag-leave-event" и "drag-over-event" генерируются только для View приемника перетескиваемого объекта.
|
События "drag-enter-event", "drag-leave-event" и "drag-over-event" генерируются только для View приемника перетаскиваемого объекта.
|
||||||
|
|
||||||
Событие "drag-enter-event" генерируется когда перетаскиваемый оъект входит в область View приемника.
|
Событие "drag-enter-event" генерируется когда перетаскиваемый объект входит в область View приемника.
|
||||||
|
|
||||||
Событие "drag-leave-event" генерируется когда перетаскиваемый оъект покидает область View приемника.
|
Событие "drag-leave-event" генерируется когда перетаскиваемый объект покидает область View приемника.
|
||||||
|
|
||||||
Событие "drag-over-event" генерируется c определенным интервалом (несколько раз в секунду) пока перетаскиваемый оъект находится область View приемника.
|
Событие "drag-over-event" генерируется c определенным интервалом (несколько раз в секунду) пока перетаскиваемый объект находится область View приемника.
|
||||||
|
|
||||||
Пример, меняем цвет рамки с серой на красную когда перетаскиваемый оъект находится над областью приемника
|
Пример, меняем цвет рамки с серой на красную когда перетаскиваемый объект находится над областью приемника
|
||||||
|
|
||||||
view.SetParams(rui.Params{
|
view.SetParams(rui.Params{
|
||||||
rui.DragEnterEvent: func(view rui.View, event rui.DragAndDropEvent)) {
|
rui.DragEnterEvent: func(view rui.View, event rui.DragAndDropEvent)) {
|
||||||
|
@ -3834,7 +3834,7 @@ float32, float64, int, int8…int64, uint, uint8…uint64.
|
||||||
|
|
||||||
Между пунктами списка можно добавлять разделителями. Для этого используется свойство "item-separators" (константа ItemSeparators).
|
Между пунктами списка можно добавлять разделителями. Для этого используется свойство "item-separators" (константа ItemSeparators).
|
||||||
Данному свойству присваивается массив индексов пунктов после которых необходимо добавить разделители.
|
Данному свойству присваивается массив индексов пунктов после которых необходимо добавить разделители.
|
||||||
Свойству "item-separators" могут присваиваться теже типы данных что и свойству "disabled-items".
|
Свойству "item-separators" могут присваиваться те же типы данных что и свойству "disabled-items".
|
||||||
Прочитать значение свойства "item-separators" можно с помощью функции
|
Прочитать значение свойства "item-separators" можно с помощью функции
|
||||||
|
|
||||||
func GetDropDownItemSeparators(view View, subviewID ...string) []int
|
func GetDropDownItemSeparators(view View, subviewID ...string) []int
|
||||||
|
@ -4085,7 +4085,7 @@ int свойство "current" (константа Current). Значение "c
|
||||||
с помощью int свойств "checkbox-horizontal-align" и "checkbox-vertical-align" (константы
|
с помощью int свойств "checkbox-horizontal-align" и "checkbox-vertical-align" (константы
|
||||||
CheckboxHorizontalAlign и CheckboxVerticalAlign)
|
CheckboxHorizontalAlign и CheckboxVerticalAlign)
|
||||||
|
|
||||||
Свойство "checkbox-horizontal-align" (константа СheckboxHorizontalAlign) может принимать следующие значения:
|
Свойство "checkbox-horizontal-align" (константа CheckboxHorizontalAlign) может принимать следующие значения:
|
||||||
|
|
||||||
| Значение | Константа | Имя | Расположение чекбокса |
|
| Значение | Константа | Имя | Расположение чекбокса |
|
||||||
|:--------:|--------------|----------|-------------------------------------------------|
|
|:--------:|--------------|----------|-------------------------------------------------|
|
||||||
|
@ -4647,7 +4647,7 @@ rotation - угол поворота эллипса относительно ц
|
||||||
Метод NewPath() создает пустую фигуру. Далее вы должны описать фигуру используя методы интерфейса Path
|
Метод NewPath() создает пустую фигуру. Далее вы должны описать фигуру используя методы интерфейса Path
|
||||||
|
|
||||||
Метод NewPathFromSvg(data string) Path создает фигуру описанную в параметре data.
|
Метод NewPathFromSvg(data string) Path создает фигуру описанную в параметре data.
|
||||||
Параметр data является описанием фигуры в формате елемента <path> svg изображения. Например
|
Параметр data является описанием фигуры в формате элемента <path> svg изображения. Например
|
||||||
|
|
||||||
path := canvas.NewPathFromSvg("M 30,0 C 30,0 27,8.6486 17,21.622 7,34.595 0,40 0,40 0,40 6,44.3243 17,58.378 28,72.432 30,80 30,80 30,80 37.8387,65.074 43,58.378 53,45.405 60,40 60,40 60,40 53,34.5946 43,21.622 33,8.649 30,0 30,0 Z")
|
path := canvas.NewPathFromSvg("M 30,0 C 30,0 27,8.6486 17,21.622 7,34.595 0,40 0,40 0,40 6,44.3243 17,58.378 28,72.432 30,80 30,80 30,80 37.8387,65.074 43,58.378 53,45.405 60,40 60,40 60,40 53,34.5946 43,21.622 33,8.649 30,0 30,0 Z")
|
||||||
|
|
||||||
|
@ -4827,7 +4827,7 @@ AudioPlayer и VideoPlayer это элементы которые предназ
|
||||||
|
|
||||||
### Свойство "src"
|
### Свойство "src"
|
||||||
|
|
||||||
Свойство "src" (константа Source) задает один или несколько источников медиафайлов. Свойство "src" может принимать
|
Свойство "src" (константа Source) задает один или несколько источников медиа файлов. Свойство "src" может принимать
|
||||||
значение следующих типов:
|
значение следующих типов:
|
||||||
|
|
||||||
* string,
|
* string,
|
||||||
|
@ -4872,7 +4872,7 @@ AudioPlayer и VideoPlayer это элементы которые предназ
|
||||||
|:--------:|-----------------|------------|----------------------------------------------------------------------------------------|
|
|:--------:|-----------------|------------|----------------------------------------------------------------------------------------|
|
||||||
| 0 | PreloadNone | "none" | Медиа файл не должен быть предварительно загружен |
|
| 0 | PreloadNone | "none" | Медиа файл не должен быть предварительно загружен |
|
||||||
| 1 | PreloadMetadata | "metadata" | Предварительно загружаются только метаданные |
|
| 1 | PreloadMetadata | "metadata" | Предварительно загружаются только метаданные |
|
||||||
| 2 | PreloadAuto | "auto" | Весь медиафайл может быть загружен, даже если пользователь не должен его использовать. |
|
| 2 | PreloadAuto | "auto" | Весь медиа файл может быть загружен, даже если пользователь не должен его использовать.|
|
||||||
|
|
||||||
Значение по умолчанию PreloadAuto (2)
|
Значение по умолчанию PreloadAuto (2)
|
||||||
|
|
||||||
|
@ -5704,6 +5704,79 @@ Safari и Firefox.
|
||||||
Для получения объекта используется метод Object.
|
Для получения объекта используется метод Object.
|
||||||
Для получения элементов массива используются методы ArraySize, ArrayElement и ArrayElements
|
Для получения элементов массива используются методы ArraySize, ArrayElement и ArrayElements
|
||||||
|
|
||||||
|
## Связывание (binding)
|
||||||
|
|
||||||
|
Механизм связывания предназначен для задания обработчиков событий и слушателей изменений в ресурсах приложений.
|
||||||
|
|
||||||
|
Рассмотрим пример:
|
||||||
|
|
||||||
|
Файл ресурсов описывающий кнопку button.rui
|
||||||
|
|
||||||
|
Button {
|
||||||
|
click-event = ButtonClick,
|
||||||
|
}
|
||||||
|
|
||||||
|
Код для создания этой кнопки из ресурсов
|
||||||
|
|
||||||
|
type button struct {
|
||||||
|
view rui.View
|
||||||
|
}
|
||||||
|
|
||||||
|
func createButton(session rui.Session) rui.View {
|
||||||
|
return rui.CreateViewFromResources(session, "button.rui", new(button))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (button *button) OnCreate(view rui.View) {
|
||||||
|
button.view = view
|
||||||
|
}
|
||||||
|
|
||||||
|
func (button *button) ButtonClick() {
|
||||||
|
rui.DebugLog("Button clicked")
|
||||||
|
}
|
||||||
|
|
||||||
|
В данном примере в файле ресурсов указано, что в качестве обработчика клика надо использовать функцию с именем "ButtonClick".
|
||||||
|
При создании View из ресурсов с помощью функции CreateViewFromResources в качестве третьего параметра задается объект связывания.
|
||||||
|
При возникновении события "click-event" система будет искать в связанном объекте один из следующих методов
|
||||||
|
|
||||||
|
ButtonClick()
|
||||||
|
ButtonClick(rui.View)
|
||||||
|
ButtonClick(rui.MouseEvent)
|
||||||
|
ButtonClick(rui.View, rui.MouseEvent)
|
||||||
|
|
||||||
|
Система найдет метод ButtonClick() и вызовет его.
|
||||||
|
|
||||||
|
Также для связанного объекта может задаваться опциональный метод
|
||||||
|
|
||||||
|
OnCreate(view rui.View)
|
||||||
|
|
||||||
|
Данный метод вызывается функциями CreateViewFromText, CreateViewFromResources и CreateViewFromObject после создания View.
|
||||||
|
В данном примере этот метод используется для сохранения указателя на созданный View.
|
||||||
|
|
||||||
|
Теперь рассмотрим как добавить отслеживание изменения свойств.
|
||||||
|
Для этого добавим в пример слушателя изменения свойства "background-color" в свойство "change-listeners"
|
||||||
|
|
||||||
|
Button {
|
||||||
|
click-event = ButtonClick,
|
||||||
|
change-listeners = {
|
||||||
|
background-color = BackgroundColorChanged,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
И добавим соответствующий метод
|
||||||
|
|
||||||
|
func (button *button) BackgroundColorChanged() {
|
||||||
|
rui.DebugLog("Background color changed")
|
||||||
|
}
|
||||||
|
|
||||||
|
Данный метод может иметь одно из следующих описаний
|
||||||
|
|
||||||
|
BackgroundColorChanged()
|
||||||
|
BackgroundColorChanged(rui.View)
|
||||||
|
BackgroundColorChanged(rui.PropertyName)
|
||||||
|
BackgroundColorChanged(rui.View, rui.PropertyName)
|
||||||
|
|
||||||
|
Важное замечание: Все методы вызываемые через связывание должны быть публичными (начинаться с большой буквы)
|
||||||
|
|
||||||
## Ресурсы
|
## Ресурсы
|
||||||
|
|
||||||
Ресурсы (картинки, темы, переводы и т.д.) с которыми работает приложение должны размещаться по
|
Ресурсы (картинки, темы, переводы и т.д.) с которыми работает приложение должны размещаться по
|
||||||
|
|
84
README.md
84
README.md
|
@ -520,7 +520,7 @@ For the "edit-text-changed" event, this
|
||||||
* func(newText string)
|
* func(newText string)
|
||||||
* []func(editor EditView, newText string)
|
* []func(editor EditView, newText string)
|
||||||
* []func(newText string)
|
* []func(newText string)
|
||||||
* []any содержащий только func(editor EditView, newText string) и func(newText string)
|
* []any containing only func(editor EditView, newText string) и func(newText string)
|
||||||
|
|
||||||
And the "edit-text-changed" property always stores and returns []func(EditView, string).
|
And the "edit-text-changed" property always stores and returns []func(EditView, string).
|
||||||
|
|
||||||
|
@ -1062,7 +1062,7 @@ The ShadowProperty text representation has the following format:
|
||||||
|
|
||||||
You can get the value of "shadow" property using the function
|
You can get the value of "shadow" property using the function
|
||||||
|
|
||||||
func GetShadowPropertys(view View, subviewID ...string) []ShadowProperty
|
func GetShadowProperties(view View, subviewID ...string) []ShadowProperty
|
||||||
|
|
||||||
If no shadow is specified, then this function will return an empty array
|
If no shadow is specified, then this function will return an empty array
|
||||||
|
|
||||||
|
@ -2135,7 +2135,7 @@ You can get lists of pointer event listeners using the functions:
|
||||||
|
|
||||||
### Touch events
|
### Touch events
|
||||||
|
|
||||||
These events are used to track multipoint touches. Single touches emulate mouse events.
|
These events are used to track multi point touches. Single touches emulate mouse events.
|
||||||
If you do not need to track multi-point touches, then it is easier to use mouse events
|
If you do not need to track multi-point touches, then it is easier to use mouse events
|
||||||
|
|
||||||
| Event | Constant | Description |
|
| Event | Constant | Description |
|
||||||
|
@ -5720,6 +5720,80 @@ using the SetResourcePath function before creating the Application:
|
||||||
app.Start("localhost:8000")
|
app.Start("localhost:8000")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Binding
|
||||||
|
|
||||||
|
The binding mechanism is designed to set event handlers and listeners for changes in application resources.
|
||||||
|
|
||||||
|
Let's look at an example:
|
||||||
|
|
||||||
|
The resource file ("button.rui") describing the button:
|
||||||
|
|
||||||
|
Button {
|
||||||
|
click-event = ButtonClick,
|
||||||
|
}
|
||||||
|
|
||||||
|
The code to create this button from resources
|
||||||
|
|
||||||
|
type button struct {
|
||||||
|
view rui.View
|
||||||
|
}
|
||||||
|
|
||||||
|
func createButton(session rui.Session) rui.View {
|
||||||
|
return rui.CreateViewFromResources(session, "button.rui", new(button))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (button *button) OnCreate(view rui.View) {
|
||||||
|
button.view = view
|
||||||
|
}
|
||||||
|
|
||||||
|
func (button *button) ButtonClick() {
|
||||||
|
rui.DebugLog("Button clicked")
|
||||||
|
}
|
||||||
|
|
||||||
|
In this example, the resource file specifies that a function named "ButtonClick" should be used as the click handler.
|
||||||
|
When creating a View from resources using the CreateViewFromResources function, the binding object is specified as the third parameter.
|
||||||
|
When a "click-event" occurs, the system will look for one of the following methods in the binding object
|
||||||
|
|
||||||
|
ButtonClick()
|
||||||
|
ButtonClick(rui.View)
|
||||||
|
ButtonClick(rui.MouseEvent)
|
||||||
|
ButtonClick(rui.View, rui.MouseEvent)
|
||||||
|
|
||||||
|
The system will find the ButtonClick() method and call it.
|
||||||
|
|
||||||
|
The optional method OnCreate can also be specified for the associated object
|
||||||
|
|
||||||
|
OnCreate(view rui.View)
|
||||||
|
|
||||||
|
This method is called by the CreateViewFromText, CreateViewFromResources, and CreateViewFromObject functions after the View has been created.
|
||||||
|
In this example, this method is used to save a pointer to the created View.
|
||||||
|
|
||||||
|
Now let's look at how to add property change tracking.
|
||||||
|
|
||||||
|
To do this, let's add a property change listener "background-color" to the property "change-listeners" in the example.
|
||||||
|
|
||||||
|
Button {
|
||||||
|
click-event = ButtonClick,
|
||||||
|
change-listeners = {
|
||||||
|
background-color = BackgroundColorChanged,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
And we will add the corresponding method
|
||||||
|
|
||||||
|
func (button *button) BackgroundColorChanged() {
|
||||||
|
rui.DebugLog("Background color changed")
|
||||||
|
}
|
||||||
|
|
||||||
|
This method can have one of the following descriptions
|
||||||
|
|
||||||
|
BackgroundColorChanged()
|
||||||
|
BackgroundColorChanged(rui.View)
|
||||||
|
BackgroundColorChanged(rui.PropertyName)
|
||||||
|
BackgroundColorChanged(rui.View, rui.PropertyName)
|
||||||
|
|
||||||
|
Important note: All methods called via binding must be public (start with a capital letter)
|
||||||
|
|
||||||
## Images for screens with different pixel densities
|
## Images for screens with different pixel densities
|
||||||
|
|
||||||
If you need to add separate images to the resources for screens with different pixel densities,
|
If you need to add separate images to the resources for screens with different pixel densities,
|
||||||
|
@ -5919,7 +5993,7 @@ The library defines a number of constants and styles. You can override them in y
|
||||||
|
|
||||||
System styles that you can override:
|
System styles that you can override:
|
||||||
|
|
||||||
| Style name | Описание |
|
| Style name | Description |
|
||||||
|---------------------|---------------------------------------------------------------------|
|
|---------------------|---------------------------------------------------------------------|
|
||||||
| ruiApp | This style is used to set the default text style (font, size, etc.) |
|
| ruiApp | This style is used to set the default text style (font, size, etc.) |
|
||||||
| ruiView | Default View Style |
|
| ruiView | Default View Style |
|
||||||
|
@ -6011,7 +6085,7 @@ Translation files must have the "rui" extension and the following format
|
||||||
<text 2> = <translation 2>,
|
<text 2> = <translation 2>,
|
||||||
…
|
…
|
||||||
},
|
},
|
||||||
<язык 2> = _{
|
<language 2> = _{
|
||||||
<text 1> = <translation 1>,
|
<text 1> = <translation 1>,
|
||||||
<text 2> = <translation 2>,
|
<text 2> = <translation 2>,
|
||||||
…
|
…
|
||||||
|
|
24
animation.go
24
animation.go
|
@ -2,6 +2,7 @@ package rui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -209,7 +210,7 @@ type animationData struct {
|
||||||
usageCounter int
|
usageCounter int
|
||||||
view View
|
view View
|
||||||
listener func(view View, animation AnimationProperty, event PropertyName)
|
listener func(view View, animation AnimationProperty, event PropertyName)
|
||||||
oldListeners map[PropertyName][]func(View, PropertyName)
|
oldListeners map[PropertyName][]oneArgListener[View, PropertyName]
|
||||||
oldAnimation []AnimationProperty
|
oldAnimation []AnimationProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,7 +662,7 @@ func (animation *animationData) animationCSS(session Session) string {
|
||||||
buffer.WriteString(animation.keyFramesName)
|
buffer.WriteString(animation.keyFramesName)
|
||||||
|
|
||||||
if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 {
|
if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(" %gs ", duration))
|
fmt.Fprintf(buffer, " %gs ", duration)
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString(" 1s ")
|
buffer.WriteString(" 1s ")
|
||||||
}
|
}
|
||||||
|
@ -669,7 +670,7 @@ func (animation *animationData) animationCSS(session Session) string {
|
||||||
buffer.WriteString(timingFunctionCSS(animation, TimingFunction, session))
|
buffer.WriteString(timingFunctionCSS(animation, TimingFunction, session))
|
||||||
|
|
||||||
if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 {
|
if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(" %gs", delay))
|
fmt.Fprintf(buffer, " %gs", delay)
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString(" 0s")
|
buffer.WriteString(" 0s")
|
||||||
}
|
}
|
||||||
|
@ -678,7 +679,7 @@ func (animation *animationData) animationCSS(session Session) string {
|
||||||
if iterationCount == 0 {
|
if iterationCount == 0 {
|
||||||
iterationCount = 1
|
iterationCount = 1
|
||||||
}
|
}
|
||||||
buffer.WriteString(fmt.Sprintf(" %d ", iterationCount))
|
fmt.Fprintf(buffer, " %d ", iterationCount)
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString(" infinite ")
|
buffer.WriteString(" infinite ")
|
||||||
}
|
}
|
||||||
|
@ -699,7 +700,7 @@ func (animation *animationData) animationCSS(session Session) string {
|
||||||
func (animation *animationData) transitionCSS(buffer *strings.Builder, session Session) {
|
func (animation *animationData) transitionCSS(buffer *strings.Builder, session Session) {
|
||||||
|
|
||||||
if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 {
|
if duration, ok := floatProperty(animation, Duration, session, 1); ok && duration > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(" %gs ", duration))
|
fmt.Fprintf(buffer, " %gs ", duration)
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString(" 1s ")
|
buffer.WriteString(" 1s ")
|
||||||
}
|
}
|
||||||
|
@ -707,7 +708,7 @@ func (animation *animationData) transitionCSS(buffer *strings.Builder, session S
|
||||||
buffer.WriteString(timingFunctionCSS(animation, TimingFunction, session))
|
buffer.WriteString(timingFunctionCSS(animation, TimingFunction, session))
|
||||||
|
|
||||||
if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 {
|
if delay, ok := floatProperty(animation, Delay, session, 0); ok && delay > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(" %gs", delay))
|
fmt.Fprintf(buffer, " %gs", delay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -979,11 +980,10 @@ func (style *viewStyle) Transition(tag PropertyName) AnimationProperty {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) Transitions() map[PropertyName]AnimationProperty {
|
func (style *viewStyle) Transitions() map[PropertyName]AnimationProperty {
|
||||||
result := map[PropertyName]AnimationProperty{}
|
if transitions := getTransitionProperty(style); transitions != nil {
|
||||||
for tag, animation := range getTransitionProperty(style) {
|
return maps.Clone(transitions)
|
||||||
result[tag] = animation
|
|
||||||
}
|
}
|
||||||
return result
|
return map[PropertyName]AnimationProperty{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (style *viewStyle) SetTransition(tag PropertyName, animation AnimationProperty) {
|
func (style *viewStyle) SetTransition(tag PropertyName, animation AnimationProperty) {
|
||||||
|
@ -1083,7 +1083,9 @@ func SetAnimated(rootView View, viewID string, tag PropertyName, value any, anim
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAnimationPaused returns "true" if an animation of the subview is paused, "false" otherwise.
|
// IsAnimationPaused returns "true" if an animation of the subview is paused, "false" otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsAnimationPaused(view View, subviewID ...string) bool {
|
func IsAnimationPaused(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, AnimationPaused, false)
|
return boolStyledProperty(view, subviewID, AnimationPaused, false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,45 +156,6 @@ const (
|
||||||
AnimationIterationEvent PropertyName = "animation-iteration-event"
|
AnimationIterationEvent PropertyName = "animation-iteration-event"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
func setTransitionListener(properties Properties, tag PropertyName, value any) bool {
|
|
||||||
if listeners, ok := valueToOneArgEventListeners[View, string](value); ok {
|
|
||||||
if len(listeners) == 0 {
|
|
||||||
properties.setRaw(tag, nil)
|
|
||||||
} else {
|
|
||||||
properties.setRaw(tag, listeners)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) removeTransitionListener(tag PropertyName) {
|
|
||||||
delete(view.properties, tag)
|
|
||||||
if view.created {
|
|
||||||
if js, ok := eventJsFunc[tag]; ok {
|
|
||||||
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func transitionEventsHtml(view View, buffer *strings.Builder) {
|
|
||||||
for _, tag := range []PropertyName{TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent} {
|
|
||||||
if value := view.getRaw(tag); value != nil {
|
|
||||||
if js, ok := eventJsFunc[tag]; ok {
|
|
||||||
if listeners, ok := value.([]func(View, string)); ok && len(listeners) > 0 {
|
|
||||||
buffer.WriteString(js.jsEvent)
|
|
||||||
buffer.WriteString(`="`)
|
|
||||||
buffer.WriteString(js.jsFunc)
|
|
||||||
buffer.WriteString(`(this, event)" `)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject) {
|
func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject) {
|
||||||
if propertyName, ok := data.PropertyValue("property"); ok {
|
if propertyName, ok := data.PropertyValue("property"); ok {
|
||||||
property := PropertyName(propertyName)
|
property := PropertyName(propertyName)
|
||||||
|
@ -208,50 +169,11 @@ func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, listener := range getOneArgEventListeners[View, PropertyName](view, nil, tag) {
|
for _, listener := range getOneArgEventListeners[View, PropertyName](view, nil, tag) {
|
||||||
listener(view, property)
|
listener.Run(view, property)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func setAnimationListener(properties Properties, tag PropertyName, value any) bool {
|
|
||||||
if listeners, ok := valueToOneArgEventListeners[View, string](value); ok {
|
|
||||||
if len(listeners) == 0 {
|
|
||||||
properties.setRaw(tag, nil)
|
|
||||||
} else {
|
|
||||||
properties.setRaw(tag, listeners)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (view *viewData) removeAnimationListener(tag PropertyName) {
|
|
||||||
delete(view.properties, tag)
|
|
||||||
if view.created {
|
|
||||||
if js, ok := eventJsFunc[tag]; ok {
|
|
||||||
view.session.removeProperty(view.htmlID(), js.jsEvent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func animationEventsHtml(view View, buffer *strings.Builder) {
|
|
||||||
for _, tag := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent} {
|
|
||||||
if value := view.getRaw(tag); value != nil {
|
|
||||||
if js, ok := eventJsFunc[tag]; ok {
|
|
||||||
if listeners, ok := value.([]func(View, string)); ok && len(listeners) > 0 {
|
|
||||||
buffer.WriteString(js.jsEvent)
|
|
||||||
buffer.WriteString(`="`)
|
|
||||||
buffer.WriteString(js.jsFunc)
|
|
||||||
buffer.WriteString(`(this, event)" `)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) {
|
func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) {
|
||||||
if listeners := getOneArgEventListeners[View, string](view, nil, tag); len(listeners) > 0 {
|
if listeners := getOneArgEventListeners[View, string](view, nil, tag); len(listeners) > 0 {
|
||||||
id := ""
|
id := ""
|
||||||
|
@ -263,63 +185,135 @@ func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(view, id)
|
listener.Run(view, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransitionRunListeners returns the "transition-run-event" listener list.
|
// GetTransitionRunListeners returns the "transition-run-event" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTransitionRunListeners(view View, subviewID ...string) []func(View, string) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, string](view, subviewID, TransitionRunEvent)
|
// - func(rui.View, string),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(string),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTransitionRunListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, string](view, subviewID, TransitionRunEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransitionStartListeners returns the "transition-start-event" listener list.
|
// GetTransitionStartListeners returns the "transition-start-event" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTransitionStartListeners(view View, subviewID ...string) []func(View, string) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, string](view, subviewID, TransitionStartEvent)
|
// - func(rui.View, string),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(string),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTransitionStartListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, string](view, subviewID, TransitionStartEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransitionEndListeners returns the "transition-end-event" listener list.
|
// GetTransitionEndListeners returns the "transition-end-event" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTransitionEndListeners(view View, subviewID ...string) []func(View, string) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, string](view, subviewID, TransitionEndEvent)
|
// - func(rui.View, string),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(string),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTransitionEndListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, string](view, subviewID, TransitionEndEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransitionCancelListeners returns the "transition-cancel-event" listener list.
|
// GetTransitionCancelListeners returns the "transition-cancel-event" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTransitionCancelListeners(view View, subviewID ...string) []func(View, string) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, string](view, subviewID, TransitionCancelEvent)
|
// - func(rui.View, string),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(string),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTransitionCancelListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, string](view, subviewID, TransitionCancelEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAnimationStartListeners returns the "animation-start-event" listener list.
|
// GetAnimationStartListeners returns the "animation-start-event" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetAnimationStartListeners(view View, subviewID ...string) []func(View, string) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, string](view, subviewID, AnimationStartEvent)
|
// - func(rui.View, string),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(string),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetAnimationStartListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, string](view, subviewID, AnimationStartEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAnimationEndListeners returns the "animation-end-event" listener list.
|
// GetAnimationEndListeners returns the "animation-end-event" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetAnimationEndListeners(view View, subviewID ...string) []func(View, string) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, string](view, subviewID, AnimationEndEvent)
|
// - func(rui.View, string),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(string),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetAnimationEndListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, string](view, subviewID, AnimationEndEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAnimationCancelListeners returns the "animation-cancel-event" listener list.
|
// GetAnimationCancelListeners returns the "animation-cancel-event" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetAnimationCancelListeners(view View, subviewID ...string) []func(View, string) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, string](view, subviewID, AnimationCancelEvent)
|
// - func(rui.View, string),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(string),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetAnimationCancelListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, string](view, subviewID, AnimationCancelEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAnimationIterationListeners returns the "animation-iteration-event" listener list.
|
// GetAnimationIterationListeners returns the "animation-iteration-event" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetAnimationIterationListeners(view View, subviewID ...string) []func(View, string) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, string](view, subviewID, AnimationIterationEvent)
|
// - func(rui.View, string),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(string),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetAnimationIterationListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, string](view, subviewID, AnimationIterationEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
|
import "slices"
|
||||||
|
|
||||||
func (animation *animationData) Start(view View, listener func(view View, animation AnimationProperty, event PropertyName)) bool {
|
func (animation *animationData) Start(view View, listener func(view View, animation AnimationProperty, event PropertyName)) bool {
|
||||||
if view == nil {
|
if view == nil {
|
||||||
ErrorLog("nil View in animation.Start() function")
|
ErrorLog("nil View in animation.Start() function")
|
||||||
|
@ -13,28 +15,22 @@ func (animation *animationData) Start(view View, listener func(view View, animat
|
||||||
animation.listener = listener
|
animation.listener = listener
|
||||||
|
|
||||||
animation.oldAnimation = nil
|
animation.oldAnimation = nil
|
||||||
|
|
||||||
|
//if getOneArgEventListeners[View, PropertyName](view, nil, Animation)
|
||||||
if value := view.Get(Animation); value != nil {
|
if value := view.Get(Animation); value != nil {
|
||||||
if oldAnimation, ok := value.([]AnimationProperty); ok && len(oldAnimation) > 0 {
|
if oldAnimation, ok := value.([]AnimationProperty); ok && len(oldAnimation) > 0 {
|
||||||
animation.oldAnimation = oldAnimation
|
animation.oldAnimation = oldAnimation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
animation.oldListeners = map[PropertyName][]func(View, PropertyName){}
|
animation.oldListeners = map[PropertyName][]oneArgListener[View, PropertyName]{}
|
||||||
|
|
||||||
setListeners := func(event PropertyName, listener func(View, PropertyName)) {
|
setListeners := func(event PropertyName, listener func(View, PropertyName)) {
|
||||||
var listeners []func(View, PropertyName) = nil
|
listeners := getOneArgEventListeners[View, PropertyName](view, nil, event)
|
||||||
if value := view.Get(event); value != nil {
|
if len(listeners) > 0 {
|
||||||
if oldListeners, ok := value.([]func(View, PropertyName)); ok && len(oldListeners) > 0 {
|
animation.oldListeners[event] = slices.Clone(listeners)
|
||||||
listeners = oldListeners
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if listeners == nil {
|
|
||||||
view.Set(event, listener)
|
|
||||||
} else {
|
|
||||||
animation.oldListeners[event] = listeners
|
|
||||||
view.Set(event, append(listeners, listener))
|
|
||||||
}
|
}
|
||||||
|
view.Set(event, append(listeners, newOneArgListenerVE(listener)))
|
||||||
}
|
}
|
||||||
|
|
||||||
setListeners(AnimationStartEvent, animation.onAnimationStart)
|
setListeners(AnimationStartEvent, animation.onAnimationStart)
|
||||||
|
@ -49,7 +45,7 @@ func (animation *animationData) Start(view View, listener func(view View, animat
|
||||||
func (animation *animationData) finish() {
|
func (animation *animationData) finish() {
|
||||||
if animation.view != nil {
|
if animation.view != nil {
|
||||||
for _, event := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationCancelEvent, AnimationIterationEvent} {
|
for _, event := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationCancelEvent, AnimationIterationEvent} {
|
||||||
if listeners, ok := animation.oldListeners[event]; ok {
|
if listeners, ok := animation.oldListeners[event]; ok && len(listeners) > 0 {
|
||||||
animation.view.Set(event, listeners)
|
animation.view.Set(event, listeners)
|
||||||
} else {
|
} else {
|
||||||
animation.view.Remove(event)
|
animation.view.Remove(event)
|
||||||
|
@ -63,7 +59,7 @@ func (animation *animationData) finish() {
|
||||||
animation.view.Set(Animation, "")
|
animation.view.Set(Animation, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
animation.oldListeners = map[PropertyName][]func(View, PropertyName){}
|
animation.oldListeners = map[PropertyName][]oneArgListener[View, PropertyName]{}
|
||||||
|
|
||||||
animation.view = nil
|
animation.view = nil
|
||||||
animation.listener = nil
|
animation.listener = nil
|
||||||
|
|
201
appServer.go
201
appServer.go
|
@ -164,64 +164,68 @@ func (app *application) postHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
DebugLog(message)
|
DebugLog(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj := ParseDataText(message); obj != nil {
|
obj, err := ParseDataText(message)
|
||||||
var session Session = nil
|
if err != nil {
|
||||||
var response chan string = nil
|
ErrorLog(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if cookie, err := req.Cookie("session"); err == nil {
|
var session Session = nil
|
||||||
sessionID, err := strconv.Atoi(cookie.Value)
|
var response chan string = nil
|
||||||
if err != nil {
|
|
||||||
ErrorLog(err.Error())
|
if cookie, err := req.Cookie("session"); err == nil {
|
||||||
} else if info, ok := app.sessions[sessionID]; ok && info.response != nil {
|
sessionID, err := strconv.Atoi(cookie.Value)
|
||||||
response = info.response
|
if err != nil {
|
||||||
session = info.session
|
ErrorLog(err.Error())
|
||||||
}
|
} else if info, ok := app.sessions[sessionID]; ok && info.response != nil {
|
||||||
}
|
response = info.response
|
||||||
|
session = info.session
|
||||||
command := obj.Tag()
|
}
|
||||||
startSession := false
|
}
|
||||||
|
|
||||||
if session == nil || command == "startSession" {
|
command := obj.Tag()
|
||||||
events := make(chan DataObject, 1024)
|
startSession := false
|
||||||
bridge := createHttpBridge(req)
|
|
||||||
response = bridge.response
|
if session == nil || command == "startSession" {
|
||||||
answer := ""
|
events := make(chan DataObject, 1024)
|
||||||
session, answer = app.startSession(obj, events, bridge, response)
|
bridge := createHttpBridge(req)
|
||||||
|
response = bridge.response
|
||||||
bridge.writeMessage(answer)
|
answer := ""
|
||||||
session.onStart()
|
session, answer = app.startSession(obj, events, bridge, response)
|
||||||
if command == "session-resume" {
|
|
||||||
session.onResume()
|
bridge.writeMessage(answer)
|
||||||
}
|
session.onStart()
|
||||||
bridge.sendResponse()
|
if command == "session-resume" {
|
||||||
|
session.onResume()
|
||||||
setSessionIDCookie(w, session.ID())
|
}
|
||||||
startSession = true
|
bridge.sendResponse()
|
||||||
|
|
||||||
go sessionEventHandler(session, events, bridge)
|
setSessionIDCookie(w, session.ID())
|
||||||
}
|
startSession = true
|
||||||
|
|
||||||
if !startSession {
|
go sessionEventHandler(session, events, bridge)
|
||||||
switch command {
|
}
|
||||||
case "nop":
|
|
||||||
session.sendResponse()
|
if !startSession {
|
||||||
|
switch command {
|
||||||
case "session-close":
|
case "nop":
|
||||||
session.onFinish()
|
session.sendResponse()
|
||||||
session.App().removeSession(session.ID())
|
|
||||||
return
|
case "session-close":
|
||||||
|
session.onFinish()
|
||||||
default:
|
session.App().removeSession(session.ID())
|
||||||
if !session.handleAnswer(command, obj) {
|
return
|
||||||
session.addToEventsQueue(obj)
|
|
||||||
}
|
default:
|
||||||
|
if !session.handleAnswer(command, obj) {
|
||||||
|
session.addToEventsQueue(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
io.WriteString(w, <-response)
|
||||||
|
for len(response) > 0 {
|
||||||
io.WriteString(w, <-response)
|
io.WriteString(w, <-response)
|
||||||
for len(response) > 0 {
|
|
||||||
io.WriteString(w, <-response)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,58 +245,61 @@ func (app *application) socketReader(bridge *wsBridge) {
|
||||||
DebugLog("🖥️ -> " + message)
|
DebugLog("🖥️ -> " + message)
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj := ParseDataText(message); obj != nil {
|
obj, err := ParseDataText(message)
|
||||||
command := obj.Tag()
|
if err != nil {
|
||||||
switch command {
|
ErrorLog(err.Error())
|
||||||
case "startSession":
|
return
|
||||||
answer := ""
|
}
|
||||||
|
|
||||||
|
switch command := obj.Tag(); command {
|
||||||
|
case "startSession":
|
||||||
|
answer := ""
|
||||||
|
if session, answer = app.startSession(obj, events, bridge, nil); session != nil {
|
||||||
|
if !bridge.writeMessage(answer) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
session.onStart()
|
||||||
|
go sessionEventHandler(session, events, bridge)
|
||||||
|
}
|
||||||
|
|
||||||
|
case "reconnect":
|
||||||
|
session = nil
|
||||||
|
if sessionText, ok := obj.PropertyValue("session"); ok {
|
||||||
|
if sessionID, err := strconv.Atoi(sessionText); err == nil {
|
||||||
|
if info, ok := app.sessions[sessionID]; ok {
|
||||||
|
session = info.session
|
||||||
|
session.setBridge(events, bridge)
|
||||||
|
|
||||||
|
go sessionEventHandler(session, events, bridge)
|
||||||
|
session.onReconnect()
|
||||||
|
} else {
|
||||||
|
DebugLogF("Session #%d not exists", sessionID)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLog(`strconv.Atoi(sessionText) error: ` + err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorLog(`"session" key not found`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if session == nil {
|
||||||
|
/* answer := ""
|
||||||
if session, answer = app.startSession(obj, events, bridge, nil); session != nil {
|
if session, answer = app.startSession(obj, events, bridge, nil); session != nil {
|
||||||
if !bridge.writeMessage(answer) {
|
if !bridge.writeMessage(answer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session.onStart()
|
session.onStart()
|
||||||
go sessionEventHandler(session, events, bridge)
|
go sessionEventHandler(session, events, bridge)
|
||||||
|
bridge.writeMessage("restartSession();")
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
bridge.writeMessage("reloadPage();")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
case "reconnect":
|
default:
|
||||||
session = nil
|
if !session.handleAnswer(command, obj) {
|
||||||
if sessionText, ok := obj.PropertyValue("session"); ok {
|
events <- obj
|
||||||
if sessionID, err := strconv.Atoi(sessionText); err == nil {
|
|
||||||
if info, ok := app.sessions[sessionID]; ok {
|
|
||||||
session = info.session
|
|
||||||
session.setBridge(events, bridge)
|
|
||||||
|
|
||||||
go sessionEventHandler(session, events, bridge)
|
|
||||||
session.onReconnect()
|
|
||||||
} else {
|
|
||||||
DebugLogF("Session #%d not exists", sessionID)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ErrorLog(`strconv.Atoi(sessionText) error: ` + err.Error())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ErrorLog(`"session" key not found`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if session == nil {
|
|
||||||
/* answer := ""
|
|
||||||
if session, answer = app.startSession(obj, events, bridge, nil); session != nil {
|
|
||||||
if !bridge.writeMessage(answer) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
session.onStart()
|
|
||||||
go sessionEventHandler(session, events, bridge)
|
|
||||||
bridge.writeMessage("restartSession();")
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
bridge.writeMessage("reloadPage();")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
if !session.handleAnswer(command, obj) {
|
|
||||||
events <- obj
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,16 @@ func createBackground(obj DataObject) BackgroundElement {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseBackgroundText(text string) BackgroundElement {
|
||||||
|
obj, err := ParseDataText(text)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return createBackground(obj)
|
||||||
|
}
|
||||||
|
|
||||||
func parseBackgroundValue(value any) []BackgroundElement {
|
func parseBackgroundValue(value any) []BackgroundElement {
|
||||||
|
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
|
@ -96,12 +106,8 @@ func parseBackgroundValue(value any) []BackgroundElement {
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else if obj := ParseDataText(el.Value()); obj != nil {
|
} else if element := parseBackgroundText(el.Value()); element != nil {
|
||||||
if element := createBackground(obj); element != nil {
|
background = append(background, element)
|
||||||
background = append(background, element)
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -125,21 +131,15 @@ func parseBackgroundValue(value any) []BackgroundElement {
|
||||||
return background
|
return background
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if obj := ParseDataText(value); obj != nil {
|
if element := parseBackgroundText(value); element != nil {
|
||||||
if element := createBackground(obj); element != nil {
|
return []BackgroundElement{element}
|
||||||
return []BackgroundElement{element}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case []string:
|
case []string:
|
||||||
elements := make([]BackgroundElement, 0, len(value))
|
elements := make([]BackgroundElement, 0, len(value))
|
||||||
for _, element := range value {
|
for _, text := range value {
|
||||||
if obj := ParseDataText(element); obj != nil {
|
if element := parseBackgroundText(text); element != nil {
|
||||||
if element := createBackground(obj); element != nil {
|
elements = append(elements, element)
|
||||||
elements = append(elements, element)
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -148,18 +148,14 @@ func parseBackgroundValue(value any) []BackgroundElement {
|
||||||
|
|
||||||
case []any:
|
case []any:
|
||||||
elements := make([]BackgroundElement, 0, len(value))
|
elements := make([]BackgroundElement, 0, len(value))
|
||||||
for _, element := range value {
|
for _, val := range value {
|
||||||
switch element := element.(type) {
|
switch val := val.(type) {
|
||||||
case BackgroundElement:
|
case BackgroundElement:
|
||||||
elements = append(elements, element)
|
elements = append(elements, val)
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if obj := ParseDataText(element); obj != nil {
|
if element := parseBackgroundText(val); element != nil {
|
||||||
if element := createBackground(obj); element != nil {
|
elements = append(elements, element)
|
||||||
elements = append(elements, element)
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -268,14 +264,16 @@ func backgroundStyledPropery(view View, subviewID []string, tag PropertyName) []
|
||||||
|
|
||||||
// GetBackground returns the view background.
|
// GetBackground returns the view background.
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetBackground(view View, subviewID ...string) []BackgroundElement {
|
func GetBackground(view View, subviewID ...string) []BackgroundElement {
|
||||||
return backgroundStyledPropery(view, subviewID, Background)
|
return backgroundStyledPropery(view, subviewID, Background)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMask returns the view mask.
|
// GetMask returns the view mask.
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetMask(view View, subviewID ...string) []BackgroundElement {
|
func GetMask(view View, subviewID ...string) []BackgroundElement {
|
||||||
return backgroundStyledPropery(view, subviewID, Mask)
|
return backgroundStyledPropery(view, subviewID, Mask)
|
||||||
}
|
}
|
||||||
|
@ -284,7 +282,8 @@ func GetMask(view View, subviewID ...string) []BackgroundElement {
|
||||||
//
|
//
|
||||||
// BorderBox (0), PaddingBox (1), ContentBox (2)
|
// BorderBox (0), PaddingBox (1), ContentBox (2)
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetBackgroundClip(view View, subviewID ...string) int {
|
func GetBackgroundClip(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, BackgroundClip, 0, false)
|
return enumStyledProperty(view, subviewID, BackgroundClip, 0, false)
|
||||||
}
|
}
|
||||||
|
@ -293,7 +292,8 @@ func GetBackgroundClip(view View, subviewID ...string) int {
|
||||||
//
|
//
|
||||||
// BorderBox (0), PaddingBox (1), ContentBox (2)
|
// BorderBox (0), PaddingBox (1), ContentBox (2)
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetBackgroundOrigin(view View, subviewID ...string) int {
|
func GetBackgroundOrigin(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, BackgroundOrigin, 0, false)
|
return enumStyledProperty(view, subviewID, BackgroundOrigin, 0, false)
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,8 @@ func GetBackgroundOrigin(view View, subviewID ...string) int {
|
||||||
//
|
//
|
||||||
// BorderBox (0), PaddingBox (1), ContentBox (2)
|
// BorderBox (0), PaddingBox (1), ContentBox (2)
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetMaskClip(view View, subviewID ...string) int {
|
func GetMaskClip(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, MaskClip, 0, false)
|
return enumStyledProperty(view, subviewID, MaskClip, 0, false)
|
||||||
}
|
}
|
||||||
|
@ -311,7 +312,8 @@ func GetMaskClip(view View, subviewID ...string) int {
|
||||||
//
|
//
|
||||||
// BorderBox (0), PaddingBox (1), ContentBox (2)
|
// BorderBox (0), PaddingBox (1), ContentBox (2)
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetMaskOrigin(view View, subviewID ...string) int {
|
func GetMaskOrigin(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, MaskOrigin, 0, false)
|
return enumStyledProperty(view, subviewID, MaskOrigin, 0, false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ type backgroundRadialGradient struct {
|
||||||
//
|
//
|
||||||
// The following properties can be used:
|
// The following properties can be used:
|
||||||
// - "gradient" (Gradient) - Describes gradient stop points. This is a mandatory property while describing background gradients.
|
// - "gradient" (Gradient) - Describes gradient stop points. This is a mandatory property while describing background gradients.
|
||||||
// - "center-x" (CenterX), "center-y" (CenterY) - Defines the gradient center point cooordinates.
|
// - "center-x" (CenterX), "center-y" (CenterY) - Defines the gradient center point coordinates.
|
||||||
// - "radial-gradient-radius" (RadialGradientRadius) - Defines radius of the radial gradient.
|
// - "radial-gradient-radius" (RadialGradientRadius) - Defines radius of the radial gradient.
|
||||||
// - "radial-gradient-shape" (RadialGradientShape) - Defines shape of the radial gradient.
|
// - "radial-gradient-shape" (RadialGradientShape) - Defines shape of the radial gradient.
|
||||||
// - "repeating" (Repeating) - Defines whether stop points needs to be repeated after the last one.
|
// - "repeating" (Repeating) - Defines whether stop points needs to be repeated after the last one.
|
||||||
|
|
|
@ -610,7 +610,10 @@ func borderSet(properties Properties, tag PropertyName, value any) []PropertyNam
|
||||||
case Left, Right, Top, Bottom:
|
case Left, Right, Top, Bottom:
|
||||||
switch value := value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if obj := ParseDataText(value); obj != nil {
|
obj, err := ParseDataText(value)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
return setSingleBorderObject(tag, obj)
|
return setSingleBorderObject(tag, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,7 +201,7 @@ type Canvas interface {
|
||||||
|
|
||||||
// SetConicGradientFillStyle sets a conic gradient around a point
|
// SetConicGradientFillStyle sets a conic gradient around a point
|
||||||
// to use inside shapes
|
// to use inside shapes
|
||||||
// * x, y - coordinates of the center of the conic gradient in pilels;
|
// * x, y - coordinates of the center of the conic gradient in piles;
|
||||||
// * startAngle - the angle at which to begin the gradient, in radians. The angle starts from a line going horizontally right from the center, and proceeds clockwise.
|
// * startAngle - the angle at which to begin the gradient, in radians. The angle starts from a line going horizontally right from the center, and proceeds clockwise.
|
||||||
// * startColor - the start color;
|
// * startColor - the start color;
|
||||||
// * endColor - the end color;
|
// * endColor - the end color;
|
||||||
|
@ -210,7 +210,7 @@ type Canvas interface {
|
||||||
|
|
||||||
// SetConicGradientFillStyle sets a conic gradient around a point
|
// SetConicGradientFillStyle sets a conic gradient around a point
|
||||||
// to use inside shapes
|
// to use inside shapes
|
||||||
// * x, y - coordinates of the center of the conic gradient in pilels;
|
// * x, y - coordinates of the center of the conic gradient in piles;
|
||||||
// * startAngle - the angle at which to begin the gradient, in radians. The angle starts from a line going horizontally right from the center, and proceeds clockwise.
|
// * startAngle - the angle at which to begin the gradient, in radians. The angle starts from a line going horizontally right from the center, and proceeds clockwise.
|
||||||
// * startColor - the start color;
|
// * startColor - the start color;
|
||||||
// * endColor - the end color;
|
// * endColor - the end color;
|
||||||
|
@ -575,7 +575,7 @@ func (canvas *canvasData) SetLineDash(dash []float64, offset float64) {
|
||||||
for _, val := range dash {
|
for _, val := range dash {
|
||||||
buffer.WriteRune(lead)
|
buffer.WriteRune(lead)
|
||||||
lead = ','
|
lead = ','
|
||||||
buffer.WriteString(fmt.Sprintf("%g", val))
|
fmt.Fprintf(buffer, "%g", val))
|
||||||
}
|
}
|
||||||
buffer.WriteRune(']')
|
buffer.WriteRune(']')
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
// DrawFunction is the constant for "draw-function" property tag.
|
// DrawFunction is the constant for "draw-function" property tag.
|
||||||
//
|
//
|
||||||
// Used by `CanvasView`.
|
// Used by `CanvasView`.
|
||||||
|
@ -55,7 +57,7 @@ func (canvasView *canvasViewData) removeFunc(tag PropertyName) []PropertyName {
|
||||||
if tag == DrawFunction {
|
if tag == DrawFunction {
|
||||||
if canvasView.getRaw(DrawFunction) != nil {
|
if canvasView.getRaw(DrawFunction) != nil {
|
||||||
canvasView.setRaw(DrawFunction, nil)
|
canvasView.setRaw(DrawFunction, nil)
|
||||||
canvasView.Redraw()
|
//canvasView.Redraw()
|
||||||
return []PropertyName{DrawFunction}
|
return []PropertyName{DrawFunction}
|
||||||
}
|
}
|
||||||
return []PropertyName{}
|
return []PropertyName{}
|
||||||
|
@ -66,9 +68,14 @@ func (canvasView *canvasViewData) removeFunc(tag PropertyName) []PropertyName {
|
||||||
|
|
||||||
func (canvasView *canvasViewData) setFunc(tag PropertyName, value any) []PropertyName {
|
func (canvasView *canvasViewData) setFunc(tag PropertyName, value any) []PropertyName {
|
||||||
if tag == DrawFunction {
|
if tag == DrawFunction {
|
||||||
if fn, ok := value.(func(Canvas)); ok {
|
switch value := value.(type) {
|
||||||
canvasView.setRaw(DrawFunction, fn)
|
case func(Canvas):
|
||||||
} else {
|
canvasView.setRaw(DrawFunction, value)
|
||||||
|
|
||||||
|
case string:
|
||||||
|
canvasView.setRaw(DrawFunction, value)
|
||||||
|
|
||||||
|
default:
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -94,8 +101,30 @@ func (canvasView *canvasViewData) Redraw() {
|
||||||
canvas := newCanvas(canvasView)
|
canvas := newCanvas(canvasView)
|
||||||
canvas.ClearRect(0, 0, canvasView.frame.Width, canvasView.frame.Height)
|
canvas.ClearRect(0, 0, canvasView.frame.Width, canvasView.frame.Height)
|
||||||
if value := canvasView.getRaw(DrawFunction); value != nil {
|
if value := canvasView.getRaw(DrawFunction); value != nil {
|
||||||
if drawer, ok := value.(func(Canvas)); ok {
|
switch drawer := value.(type) {
|
||||||
|
case func(Canvas):
|
||||||
drawer(canvas)
|
drawer(canvas)
|
||||||
|
|
||||||
|
case string:
|
||||||
|
bind := canvasView.binding()
|
||||||
|
if bind == nil {
|
||||||
|
ErrorLogF(`There is no a binding object for call "%s"`, drawer)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(bind)
|
||||||
|
method := val.MethodByName(drawer)
|
||||||
|
if !method.IsValid() {
|
||||||
|
ErrorLogF(`The "%s" method is not valid`, drawer)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
methodType := method.Type()
|
||||||
|
if methodType.NumIn() == 1 && equalType(methodType.In(0), reflect.TypeOf(canvas)) {
|
||||||
|
method.Call([]reflect.Value{reflect.ValueOf(canvas)})
|
||||||
|
} else {
|
||||||
|
ErrorLogF(`Unsupported prototype of "%s" method`, drawer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
canvas.finishDraw()
|
canvas.finishDraw()
|
||||||
|
|
59
checkbox.go
59
checkbox.go
|
@ -53,8 +53,8 @@ func (button *checkboxData) init(session Session) {
|
||||||
button.remove = button.removeFunc
|
button.remove = button.removeFunc
|
||||||
button.changed = button.propertyChanged
|
button.changed = button.propertyChanged
|
||||||
|
|
||||||
button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener})
|
button.setRaw(ClickEvent, []oneArgListener[View, MouseEvent]{newOneArgListenerVE(checkboxClickListener)})
|
||||||
button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener})
|
button.setRaw(KeyDownEvent, []oneArgListener[View, KeyEvent]{newOneArgListenerVE(checkboxKeyListener)})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (button *checkboxData) Focusable() bool {
|
func (button *checkboxData) Focusable() bool {
|
||||||
|
@ -67,9 +67,9 @@ func (button *checkboxData) propertyChanged(tag PropertyName) {
|
||||||
case Checked:
|
case Checked:
|
||||||
session := button.Session()
|
session := button.Session()
|
||||||
checked := IsCheckboxChecked(button)
|
checked := IsCheckboxChecked(button)
|
||||||
if listeners := GetCheckboxChangedListeners(button); len(listeners) > 0 {
|
if listeners := getOneArgEventListeners[Checkbox, bool](button, nil, CheckboxChangedEvent); len(listeners) > 0 {
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(button, checked)
|
listener.Run(button, checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ func (button *checkboxData) setFunc(tag PropertyName, value any) []PropertyName
|
||||||
switch tag {
|
switch tag {
|
||||||
case ClickEvent:
|
case ClickEvent:
|
||||||
if listeners, ok := valueToOneArgEventListeners[View, MouseEvent](value); ok && listeners != nil {
|
if listeners, ok := valueToOneArgEventListeners[View, MouseEvent](value); ok && listeners != nil {
|
||||||
listeners = append(listeners, checkboxClickListener)
|
listeners = append(listeners, newOneArgListenerVE(checkboxClickListener))
|
||||||
button.setRaw(tag, listeners)
|
button.setRaw(tag, listeners)
|
||||||
return []PropertyName{tag}
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ func (button *checkboxData) setFunc(tag PropertyName, value any) []PropertyName
|
||||||
|
|
||||||
case KeyDownEvent:
|
case KeyDownEvent:
|
||||||
if listeners, ok := valueToOneArgEventListeners[View, KeyEvent](value); ok && listeners != nil {
|
if listeners, ok := valueToOneArgEventListeners[View, KeyEvent](value); ok && listeners != nil {
|
||||||
listeners = append(listeners, checkboxKeyListener)
|
listeners = append(listeners, newOneArgListenerVE(checkboxKeyListener))
|
||||||
button.setRaw(tag, listeners)
|
button.setRaw(tag, listeners)
|
||||||
return []PropertyName{tag}
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
@ -134,31 +134,17 @@ func (button *checkboxData) setFunc(tag PropertyName, value any) []PropertyName
|
||||||
func (button *checkboxData) removeFunc(tag PropertyName) []PropertyName {
|
func (button *checkboxData) removeFunc(tag PropertyName) []PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case ClickEvent:
|
case ClickEvent:
|
||||||
button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener})
|
button.setRaw(ClickEvent, []oneArgListener[View, MouseEvent]{newOneArgListenerVE(checkboxClickListener)})
|
||||||
return []PropertyName{ClickEvent}
|
return []PropertyName{ClickEvent}
|
||||||
|
|
||||||
case KeyDownEvent:
|
case KeyDownEvent:
|
||||||
button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener})
|
button.setRaw(KeyDownEvent, []oneArgListener[View, KeyEvent]{newOneArgListenerVE(checkboxKeyListener)})
|
||||||
return []PropertyName{ClickEvent}
|
return []PropertyName{ClickEvent}
|
||||||
}
|
}
|
||||||
|
|
||||||
return button.viewsContainerData.removeFunc(tag)
|
return button.viewsContainerData.removeFunc(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func (button *checkboxData) changedCheckboxState(state bool) {
|
|
||||||
for _, listener := range GetCheckboxChangedListeners(button) {
|
|
||||||
listener(button, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer := allocStringBuilder()
|
|
||||||
defer freeStringBuilder(buffer)
|
|
||||||
|
|
||||||
button.htmlCheckbox(buffer, state)
|
|
||||||
button.Session().updateInnerHTML(button.htmlID()+"checkbox", buffer.String())
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func checkboxClickListener(view View, _ MouseEvent) {
|
func checkboxClickListener(view View, _ MouseEvent) {
|
||||||
view.Set(Checked, !IsCheckboxChecked(view))
|
view.Set(Checked, !IsCheckboxChecked(view))
|
||||||
BlurView(view)
|
BlurView(view)
|
||||||
|
@ -302,26 +288,41 @@ func checkboxVerticalAlignCSS(view View) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsCheckboxChecked returns true if the Checkbox is checked, false otherwise.
|
// IsCheckboxChecked returns true if the Checkbox is checked, false otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsCheckboxChecked(view View, subviewID ...string) bool {
|
func IsCheckboxChecked(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, Checked, false)
|
return boolStyledProperty(view, subviewID, Checked, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCheckboxVerticalAlign return the vertical align of a Checkbox subview: TopAlign (0), BottomAlign (1), CenterAlign (2)
|
// GetCheckboxVerticalAlign return the vertical align of a Checkbox subview: TopAlign (0), BottomAlign (1), CenterAlign (2)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetCheckboxVerticalAlign(view View, subviewID ...string) int {
|
func GetCheckboxVerticalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, LeftAlign, false)
|
return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, LeftAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCheckboxHorizontalAlign return the vertical align of a Checkbox subview: LeftAlign (0), RightAlign (1), CenterAlign (2)
|
// GetCheckboxHorizontalAlign return the vertical align of a Checkbox subview: LeftAlign (0), RightAlign (1), CenterAlign (2)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetCheckboxHorizontalAlign(view View, subviewID ...string) int {
|
func GetCheckboxHorizontalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, TopAlign, false)
|
return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, TopAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCheckboxChangedListeners returns the CheckboxChangedListener list of an Checkbox subview.
|
// GetCheckboxChangedListeners returns the CheckboxChangedListener list of an Checkbox subview.
|
||||||
// If there are no listeners then the empty list is returned
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetCheckboxChangedListeners(view View, subviewID ...string) []func(Checkbox, bool) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[Checkbox, bool](view, subviewID, CheckboxChangedEvent)
|
// - func(Checkbox, bool),
|
||||||
|
// - func(Checkbox),
|
||||||
|
// - func(bool),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetCheckboxChangedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[Checkbox, bool](view, subviewID, CheckboxChangedEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,13 +106,13 @@ func (picker *colorPickerData) propertyChanged(tag PropertyName) {
|
||||||
color := GetColorPickerValue(picker)
|
color := GetColorPickerValue(picker)
|
||||||
picker.Session().callFunc("setInputValue", picker.htmlID(), color.rgbString())
|
picker.Session().callFunc("setInputValue", picker.htmlID(), color.rgbString())
|
||||||
|
|
||||||
if listeners := GetColorChangedListeners(picker); len(listeners) > 0 {
|
if listeners := getTwoArgEventListeners[ColorPicker, Color](picker, nil, ColorChangedEvent); len(listeners) > 0 {
|
||||||
oldColor := Color(0)
|
oldColor := Color(0)
|
||||||
if value := picker.getRaw("old-color"); value != nil {
|
if value := picker.getRaw("old-color"); value != nil {
|
||||||
oldColor = value.(Color)
|
oldColor = value.(Color)
|
||||||
}
|
}
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(picker, color, oldColor)
|
listener.Run(picker, color, oldColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,11 +156,11 @@ func (picker *colorPickerData) handleCommand(self View, command PropertyName, da
|
||||||
oldColor := GetColorPickerValue(picker)
|
oldColor := GetColorPickerValue(picker)
|
||||||
picker.properties[ColorPickerValue] = color
|
picker.properties[ColorPickerValue] = color
|
||||||
if color != oldColor {
|
if color != oldColor {
|
||||||
for _, listener := range GetColorChangedListeners(picker) {
|
for _, listener := range getTwoArgEventListeners[ColorPicker, Color](picker, nil, ColorChangedEvent) {
|
||||||
listener(picker, color, oldColor)
|
listener.Run(picker, color, oldColor)
|
||||||
}
|
}
|
||||||
if listener, ok := picker.changeListener[ColorPickerValue]; ok {
|
if listener, ok := picker.changeListener[ColorPickerValue]; ok {
|
||||||
listener(picker, ColorPickerValue)
|
listener.Run(picker, ColorPickerValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,9 @@ func (picker *colorPickerData) handleCommand(self View, command PropertyName, da
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetColorPickerValue returns the value of ColorPicker subview.
|
// GetColorPickerValue returns the value of ColorPicker subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetColorPickerValue(view View, subviewID ...string) Color {
|
func GetColorPickerValue(view View, subviewID ...string) Color {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if value, ok := colorProperty(view, ColorPickerValue, view.Session()); ok {
|
if value, ok := colorProperty(view, ColorPickerValue, view.Session()); ok {
|
||||||
|
@ -191,7 +193,18 @@ func GetColorPickerValue(view View, subviewID ...string) Color {
|
||||||
|
|
||||||
// GetColorChangedListeners returns the ColorChangedListener list of an ColorPicker subview.
|
// GetColorChangedListeners returns the ColorChangedListener list of an ColorPicker subview.
|
||||||
// If there are no listeners then the empty list is returned
|
// If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetColorChangedListeners(view View, subviewID ...string) []func(ColorPicker, Color, Color) {
|
// Result elements can be of the following types:
|
||||||
return getTwoArgEventListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent)
|
// - func(rui.ColorPicker, rui.Color, rui.Color),
|
||||||
|
// - func(rui.ColorPicker, rui.Color),
|
||||||
|
// - func(rui.ColorPicker),
|
||||||
|
// - func(rui.Color, rui.Color),
|
||||||
|
// - func(rui.Color),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetColorChangedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getTwoArgEventRawListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,13 +249,17 @@ func GetColumnSeparatorColor(view View, subviewID ...string) Color {
|
||||||
|
|
||||||
// GetColumnFill returns a "column-fill" property value of the subview.
|
// GetColumnFill returns a "column-fill" property value of the subview.
|
||||||
// Returns one of next values: ColumnFillBalance (0) or ColumnFillAuto (1)
|
// Returns one of next values: ColumnFillBalance (0) or ColumnFillAuto (1)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetColumnFill(view View, subviewID ...string) int {
|
func GetColumnFill(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, ColumnFill, ColumnFillBalance, true)
|
return enumStyledProperty(view, subviewID, ColumnFill, ColumnFillBalance, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsColumnSpanAll returns a "column-span-all" property value of the subview.
|
// IsColumnSpanAll returns a "column-span-all" property value of the subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsColumnSpanAll(view View, subviewID ...string) bool {
|
func IsColumnSpanAll(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, ColumnSpanAll, false)
|
return boolStyledProperty(view, subviewID, ColumnSpanAll, false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,12 +93,12 @@ func NewColumnSeparator(style int, color Color, width SizeUnit) ColumnSeparatorP
|
||||||
|
|
||||||
func (separator *columnSeparatorProperty) init() {
|
func (separator *columnSeparatorProperty) init() {
|
||||||
separator.dataProperty.init()
|
separator.dataProperty.init()
|
||||||
separator.normalize = normalizeVolumnSeparatorTag
|
separator.normalize = normalizeColumnSeparatorTag
|
||||||
separator.set = columnSeparatorSet
|
separator.set = columnSeparatorSet
|
||||||
separator.supportedProperties = []PropertyName{Style, Width, ColorTag}
|
separator.supportedProperties = []PropertyName{Style, Width, ColorTag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeVolumnSeparatorTag(tag PropertyName) PropertyName {
|
func normalizeColumnSeparatorTag(tag PropertyName) PropertyName {
|
||||||
tag = defaultNormalize(tag)
|
tag = defaultNormalize(tag)
|
||||||
switch tag {
|
switch tag {
|
||||||
case ColumnSeparatorStyle, "separator-style":
|
case ColumnSeparatorStyle, "separator-style":
|
||||||
|
|
|
@ -98,8 +98,8 @@ func (customView *CustomViewData) SetParams(params Params) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetChangeListener set the function to track the change of the View property
|
// SetChangeListener set the function to track the change of the View property
|
||||||
func (customView *CustomViewData) SetChangeListener(tag PropertyName, listener func(View, PropertyName)) {
|
func (customView *CustomViewData) SetChangeListener(tag PropertyName, listener any) bool {
|
||||||
customView.superView.SetChangeListener(tag, listener)
|
return customView.superView.SetChangeListener(tag, listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes the property with name defined by the argument
|
// Remove removes the property with name defined by the argument
|
||||||
|
@ -292,15 +292,15 @@ func (customView *CustomViewData) ViewIndex(view View) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (customView *CustomViewData) exscludeTags() []PropertyName {
|
func (customView *CustomViewData) excludeTags() []PropertyName {
|
||||||
if customView.superView != nil {
|
if customView.superView != nil {
|
||||||
exsclude := []PropertyName{}
|
exclude := []PropertyName{}
|
||||||
for tag, value := range customView.defaultParams {
|
for tag, value := range customView.defaultParams {
|
||||||
if value == customView.superView.getRaw(tag) {
|
if value == customView.superView.getRaw(tag) {
|
||||||
exsclude = append(exsclude, tag)
|
exclude = append(exclude, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return exsclude
|
return exclude
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ func (customView *CustomViewData) String() string {
|
||||||
if customView.superView != nil {
|
if customView.superView != nil {
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
writeViewStyle(customView.tag, customView, buffer, "", customView.exscludeTags())
|
writeViewStyle(customView.tag, customView, buffer, "", customView.excludeTags())
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
return customView.tag + " { }"
|
return customView.tag + " { }"
|
||||||
|
@ -352,3 +352,10 @@ func (customView *CustomViewData) LoadFile(file FileInfo, result func(FileInfo,
|
||||||
customView.superView.LoadFile(file, result)
|
customView.superView.LoadFile(file, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (customView *CustomViewData) binding() any {
|
||||||
|
if customView.superView != nil {
|
||||||
|
return customView.superView.binding()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
774
data.go
774
data.go
|
@ -1,6 +1,9 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
@ -47,16 +50,22 @@ type DataObject interface {
|
||||||
|
|
||||||
// ToParams create a params(map) representation of a data object
|
// ToParams create a params(map) representation of a data object
|
||||||
ToParams() Params
|
ToParams() Params
|
||||||
|
|
||||||
|
// PropertyByTag removes a data node corresponding to a property tag and returns it
|
||||||
|
RemovePropertyByTag(tag string) DataNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DataNodeType defines the type of DataNode
|
||||||
|
type DataNodeType int
|
||||||
|
|
||||||
// Constants which are used to describe a node type, see [DataNode]
|
// Constants which are used to describe a node type, see [DataNode]
|
||||||
const (
|
const (
|
||||||
// TextNode - node is the pair "tag - text value". Syntax: <tag> = <text>
|
// TextNode - node is the pair "tag - text value". Syntax: <tag> = <text>
|
||||||
TextNode = 0
|
TextNode DataNodeType = 0
|
||||||
// ObjectNode - node is the pair "tag - object". Syntax: <tag> = <object name>{...}
|
// ObjectNode - node is the pair "tag - object". Syntax: <tag> = <object name>{...}
|
||||||
ObjectNode = 1
|
ObjectNode DataNodeType = 1
|
||||||
// ArrayNode - node is the pair "tag - object". Syntax: <tag> = [...]
|
// ArrayNode - node is the pair "tag - object". Syntax: <tag> = [...]
|
||||||
ArrayNode = 2
|
ArrayNode DataNodeType = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// DataNode interface of a data node
|
// DataNode interface of a data node
|
||||||
|
@ -65,7 +74,7 @@ type DataNode interface {
|
||||||
Tag() string
|
Tag() string
|
||||||
|
|
||||||
// Type returns a node type. Possible values are TextNode, ObjectNode and ArrayNode
|
// Type returns a node type. Possible values are TextNode, ObjectNode and ArrayNode
|
||||||
Type() int
|
Type() DataNodeType
|
||||||
|
|
||||||
// Text returns node text
|
// Text returns node text
|
||||||
Text() string
|
Text() string
|
||||||
|
@ -158,6 +167,28 @@ func (object *dataObject) PropertyByTag(tag string) DataNode {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (object *dataObject) RemovePropertyByTag(tag string) DataNode {
|
||||||
|
if object.property != nil {
|
||||||
|
for i, node := range object.property {
|
||||||
|
if node.Tag() == tag {
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
object.property = object.property[1:]
|
||||||
|
|
||||||
|
case len(object.property) - 1:
|
||||||
|
object.property = object.property[:len(object.property)-1]
|
||||||
|
|
||||||
|
default:
|
||||||
|
object.property = append(object.property[:i], object.property[i+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (object *dataObject) PropertyValue(tag string) (string, bool) {
|
func (object *dataObject) PropertyValue(tag string) (string, bool) {
|
||||||
if node := object.PropertyByTag(tag); node != nil && node.Type() == TextNode {
|
if node := object.PropertyByTag(tag); node != nil && node.Type() == TextNode {
|
||||||
return node.Text(), true
|
return node.Text(), true
|
||||||
|
@ -253,7 +284,7 @@ func (node *dataNode) Tag() string {
|
||||||
return node.tag
|
return node.tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *dataNode) Type() int {
|
func (node *dataNode) Type() DataNodeType {
|
||||||
if node.array != nil {
|
if node.array != nil {
|
||||||
return ArrayNode
|
return ArrayNode
|
||||||
}
|
}
|
||||||
|
@ -314,411 +345,402 @@ func (node *dataNode) ArrayAsParams() []Params {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseDataText - parse text and return DataNode
|
type dataParser struct {
|
||||||
func ParseDataText(text string) DataObject {
|
data []rune
|
||||||
|
size int
|
||||||
|
pos int
|
||||||
|
line int
|
||||||
|
lineStart int
|
||||||
|
}
|
||||||
|
|
||||||
if strings.ContainsAny(text, "\r") {
|
func (parser *dataParser) skipSpaces(skipNewLine bool) {
|
||||||
text = strings.Replace(text, "\r\n", "\n", -1)
|
for parser.pos < parser.size {
|
||||||
text = strings.Replace(text, "\r", "\n", -1)
|
switch parser.data[parser.pos] {
|
||||||
}
|
case '\n':
|
||||||
data := append([]rune(text), rune(0))
|
if !skipNewLine {
|
||||||
pos := 0
|
return
|
||||||
size := len(data) - 1
|
}
|
||||||
line := 1
|
parser.line++
|
||||||
lineStart := 0
|
parser.lineStart = parser.pos + 1
|
||||||
|
|
||||||
skipSpaces := func(skipNewLine bool) {
|
case '/':
|
||||||
for pos < size {
|
if parser.pos+1 < parser.size {
|
||||||
switch data[pos] {
|
switch parser.data[parser.pos+1] {
|
||||||
case '\n':
|
case '/':
|
||||||
if !skipNewLine {
|
parser.pos += 2
|
||||||
return
|
for parser.pos < parser.size && parser.data[parser.pos] != '\n' {
|
||||||
}
|
parser.pos++
|
||||||
line++
|
|
||||||
lineStart = pos + 1
|
|
||||||
|
|
||||||
case '/':
|
|
||||||
if pos+1 < size {
|
|
||||||
switch data[pos+1] {
|
|
||||||
case '/':
|
|
||||||
pos += 2
|
|
||||||
for pos < size && data[pos] != '\n' {
|
|
||||||
pos++
|
|
||||||
}
|
|
||||||
pos--
|
|
||||||
|
|
||||||
case '*':
|
|
||||||
pos += 3
|
|
||||||
for {
|
|
||||||
if pos >= size {
|
|
||||||
ErrorLog("Unexpected end of file")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if data[pos-1] == '*' && data[pos] == '/' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if data[pos-1] == '\n' {
|
|
||||||
line++
|
|
||||||
lineStart = pos
|
|
||||||
}
|
|
||||||
pos++
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
parser.pos--
|
||||||
|
|
||||||
case ' ', '\t':
|
case '*':
|
||||||
// do nothing
|
parser.pos += 3
|
||||||
|
for {
|
||||||
|
if parser.pos >= parser.size {
|
||||||
|
ErrorLog("Unexpected end of file")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if parser.data[parser.pos-1] == '*' && parser.data[parser.pos] == '/' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if parser.data[parser.pos-1] == '\n' {
|
||||||
|
parser.line++
|
||||||
|
parser.lineStart = parser.pos
|
||||||
|
}
|
||||||
|
parser.pos++
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if !unicode.IsSpace(data[pos]) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parseTag := func() (string, bool) {
|
case ' ', '\t':
|
||||||
skipSpaces(true)
|
// do nothing
|
||||||
startPos := pos
|
|
||||||
if data[pos] == '`' {
|
|
||||||
pos++
|
|
||||||
startPos++
|
|
||||||
for data[pos] != '`' {
|
|
||||||
pos++
|
|
||||||
if pos >= size {
|
|
||||||
ErrorLog("Unexpected end of text")
|
|
||||||
return string(data[startPos:size]), false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
str := string(data[startPos:pos])
|
|
||||||
pos++
|
|
||||||
return str, true
|
|
||||||
|
|
||||||
} else if data[pos] == '\'' || data[pos] == '"' {
|
|
||||||
|
|
||||||
stopSymbol := data[pos]
|
|
||||||
pos++
|
|
||||||
startPos++
|
|
||||||
slash := false
|
|
||||||
for stopSymbol != data[pos] {
|
|
||||||
if data[pos] == '\\' {
|
|
||||||
pos += 2
|
|
||||||
slash = true
|
|
||||||
} else {
|
|
||||||
pos++
|
|
||||||
}
|
|
||||||
if pos >= size {
|
|
||||||
ErrorLog("Unexpected end of text")
|
|
||||||
return string(data[startPos:size]), false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !slash {
|
|
||||||
str := string(data[startPos:pos])
|
|
||||||
pos++
|
|
||||||
skipSpaces(false)
|
|
||||||
return str, true
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer := make([]rune, pos-startPos+1)
|
|
||||||
n1 := 0
|
|
||||||
n2 := startPos
|
|
||||||
|
|
||||||
invalidEscape := func() (string, bool) {
|
|
||||||
str := string(data[startPos:pos])
|
|
||||||
pos++
|
|
||||||
ErrorLogF("Invalid escape sequence in \"%s\" (position %d)", str, n2-2-startPos)
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
|
|
||||||
for n2 < pos {
|
|
||||||
if data[n2] != '\\' {
|
|
||||||
buffer[n1] = data[n2]
|
|
||||||
n2++
|
|
||||||
} else {
|
|
||||||
n2 += 2
|
|
||||||
switch data[n2-1] {
|
|
||||||
case 'n':
|
|
||||||
buffer[n1] = '\n'
|
|
||||||
|
|
||||||
case 'r':
|
|
||||||
buffer[n1] = '\r'
|
|
||||||
|
|
||||||
case 't':
|
|
||||||
buffer[n1] = '\t'
|
|
||||||
|
|
||||||
case '"':
|
|
||||||
buffer[n1] = '"'
|
|
||||||
|
|
||||||
case '\'':
|
|
||||||
buffer[n1] = '\''
|
|
||||||
|
|
||||||
case '\\':
|
|
||||||
buffer[n1] = '\\'
|
|
||||||
|
|
||||||
case 'x', 'X':
|
|
||||||
if n2+2 > pos {
|
|
||||||
return invalidEscape()
|
|
||||||
}
|
|
||||||
x := 0
|
|
||||||
for range 2 {
|
|
||||||
ch := data[n2]
|
|
||||||
if ch >= '0' && ch <= '9' {
|
|
||||||
x = x*16 + int(ch-'0')
|
|
||||||
} else if ch >= 'a' && ch <= 'f' {
|
|
||||||
x = x*16 + int(ch-'a'+10)
|
|
||||||
} else if ch >= 'A' && ch <= 'F' {
|
|
||||||
x = x*16 + int(ch-'A'+10)
|
|
||||||
} else {
|
|
||||||
return invalidEscape()
|
|
||||||
}
|
|
||||||
n2++
|
|
||||||
}
|
|
||||||
buffer[n1] = rune(x)
|
|
||||||
|
|
||||||
case 'u', 'U':
|
|
||||||
if n2+4 > pos {
|
|
||||||
return invalidEscape()
|
|
||||||
}
|
|
||||||
x := 0
|
|
||||||
for range 4 {
|
|
||||||
ch := data[n2]
|
|
||||||
if ch >= '0' && ch <= '9' {
|
|
||||||
x = x*16 + int(ch-'0')
|
|
||||||
} else if ch >= 'a' && ch <= 'f' {
|
|
||||||
x = x*16 + int(ch-'a'+10)
|
|
||||||
} else if ch >= 'A' && ch <= 'F' {
|
|
||||||
x = x*16 + int(ch-'A'+10)
|
|
||||||
} else {
|
|
||||||
return invalidEscape()
|
|
||||||
}
|
|
||||||
n2++
|
|
||||||
}
|
|
||||||
buffer[n1] = rune(x)
|
|
||||||
|
|
||||||
default:
|
|
||||||
str := string(data[startPos:pos])
|
|
||||||
ErrorLogF("Invalid escape sequence in \"%s\" (position %d)", str, n2-2-startPos)
|
|
||||||
return str, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n1++
|
|
||||||
}
|
|
||||||
|
|
||||||
pos++
|
|
||||||
skipSpaces(false)
|
|
||||||
return string(buffer[0:n1]), true
|
|
||||||
}
|
|
||||||
|
|
||||||
stopSymbol := func(symbol rune) bool {
|
|
||||||
if unicode.IsSpace(symbol) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, sym := range []rune{'=', '{', '}', '[', ']', ',', ' ', '\t', '\n', '\'', '"', '`', '/'} {
|
|
||||||
if sym == symbol {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for pos < size && !stopSymbol(data[pos]) {
|
|
||||||
pos++
|
|
||||||
}
|
|
||||||
|
|
||||||
endPos := pos
|
|
||||||
skipSpaces(false)
|
|
||||||
if startPos == endPos {
|
|
||||||
//ErrorLog("empty tag")
|
|
||||||
return "", true
|
|
||||||
}
|
|
||||||
return string(data[startPos:endPos]), true
|
|
||||||
}
|
|
||||||
|
|
||||||
var parseObject func(tag string) DataObject
|
|
||||||
var parseArray func() []DataValue
|
|
||||||
|
|
||||||
parseNode := func() DataNode {
|
|
||||||
var tag string
|
|
||||||
var ok bool
|
|
||||||
|
|
||||||
if tag, ok = parseTag(); !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
skipSpaces(true)
|
|
||||||
if data[pos] != '=' {
|
|
||||||
ErrorLogF("expected '=' after a tag name (line: %d, position: %d)", line, pos-lineStart)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pos++
|
|
||||||
skipSpaces(true)
|
|
||||||
switch data[pos] {
|
|
||||||
case '[':
|
|
||||||
node := new(dataNode)
|
|
||||||
node.tag = tag
|
|
||||||
|
|
||||||
if node.array = parseArray(); node.array == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return node
|
|
||||||
|
|
||||||
case '{':
|
|
||||||
node := new(dataNode)
|
|
||||||
node.tag = tag
|
|
||||||
if node.value = parseObject("_"); node.value == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return node
|
|
||||||
|
|
||||||
case '}', ']', '=':
|
|
||||||
ErrorLogF("Expected '[', '{' or a tag name after '=' (line: %d, position: %d)", line, pos-lineStart)
|
|
||||||
return nil
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var str string
|
if !unicode.IsSpace(parser.data[parser.pos]) {
|
||||||
if str, ok = parseTag(); !ok {
|
return
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
parser.pos++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node := new(dataNode)
|
func (parser *dataParser) parseTag() (string, error) {
|
||||||
node.tag = tag
|
parser.skipSpaces(true)
|
||||||
|
startPos := parser.pos
|
||||||
|
switch parser.data[parser.pos] {
|
||||||
|
case '`':
|
||||||
|
parser.pos++
|
||||||
|
startPos++
|
||||||
|
for parser.data[parser.pos] != '`' {
|
||||||
|
parser.pos++
|
||||||
|
if parser.pos >= parser.size {
|
||||||
|
return string(parser.data[startPos:parser.size]), errors.New("unexpected end of text")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str := string(parser.data[startPos:parser.pos])
|
||||||
|
parser.pos++
|
||||||
|
return str, nil
|
||||||
|
|
||||||
if data[pos] == '{' {
|
case '\'', '"':
|
||||||
if node.value = parseObject(str); node.value == nil {
|
stopSymbol := parser.data[parser.pos]
|
||||||
return nil
|
parser.pos++
|
||||||
}
|
startPos++
|
||||||
|
slash := false
|
||||||
|
for stopSymbol != parser.data[parser.pos] {
|
||||||
|
if parser.data[parser.pos] == '\\' {
|
||||||
|
parser.pos += 2
|
||||||
|
slash = true
|
||||||
} else {
|
} else {
|
||||||
val := new(dataStringValue)
|
parser.pos++
|
||||||
val.value = str
|
|
||||||
node.value = val
|
|
||||||
}
|
}
|
||||||
|
if parser.pos >= parser.size {
|
||||||
|
return string(parser.data[startPos:parser.size]), errors.New("unexpected end of text")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return node
|
if !slash {
|
||||||
|
str := string(parser.data[startPos:parser.pos])
|
||||||
|
parser.pos++
|
||||||
|
parser.skipSpaces(false)
|
||||||
|
return str, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := make([]rune, parser.pos-startPos+1)
|
||||||
|
n1 := 0
|
||||||
|
n2 := startPos
|
||||||
|
|
||||||
|
invalidEscape := func() (string, error) {
|
||||||
|
str := string(parser.data[startPos:parser.pos])
|
||||||
|
parser.pos++
|
||||||
|
return str, fmt.Errorf(`invalid escape sequence in "%s" (position %d)`, str, n2-2-startPos)
|
||||||
|
}
|
||||||
|
|
||||||
|
for n2 < parser.pos {
|
||||||
|
if parser.data[n2] != '\\' {
|
||||||
|
buffer[n1] = parser.data[n2]
|
||||||
|
n2++
|
||||||
|
} else {
|
||||||
|
n2 += 2
|
||||||
|
switch parser.data[n2-1] {
|
||||||
|
case 'n':
|
||||||
|
buffer[n1] = '\n'
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
buffer[n1] = '\r'
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
buffer[n1] = '\t'
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
buffer[n1] = '"'
|
||||||
|
|
||||||
|
case '\'':
|
||||||
|
buffer[n1] = '\''
|
||||||
|
|
||||||
|
case '\\':
|
||||||
|
buffer[n1] = '\\'
|
||||||
|
|
||||||
|
case 'x', 'X':
|
||||||
|
if n2+2 > parser.pos {
|
||||||
|
return invalidEscape()
|
||||||
|
}
|
||||||
|
x := 0
|
||||||
|
for range 2 {
|
||||||
|
ch := parser.data[n2]
|
||||||
|
if ch >= '0' && ch <= '9' {
|
||||||
|
x = x*16 + int(ch-'0')
|
||||||
|
} else if ch >= 'a' && ch <= 'f' {
|
||||||
|
x = x*16 + int(ch-'a'+10)
|
||||||
|
} else if ch >= 'A' && ch <= 'F' {
|
||||||
|
x = x*16 + int(ch-'A'+10)
|
||||||
|
} else {
|
||||||
|
return invalidEscape()
|
||||||
|
}
|
||||||
|
n2++
|
||||||
|
}
|
||||||
|
buffer[n1] = rune(x)
|
||||||
|
|
||||||
|
case 'u', 'U':
|
||||||
|
if n2+4 > parser.pos {
|
||||||
|
return invalidEscape()
|
||||||
|
}
|
||||||
|
x := 0
|
||||||
|
for range 4 {
|
||||||
|
ch := parser.data[n2]
|
||||||
|
if ch >= '0' && ch <= '9' {
|
||||||
|
x = x*16 + int(ch-'0')
|
||||||
|
} else if ch >= 'a' && ch <= 'f' {
|
||||||
|
x = x*16 + int(ch-'a'+10)
|
||||||
|
} else if ch >= 'A' && ch <= 'F' {
|
||||||
|
x = x*16 + int(ch-'A'+10)
|
||||||
|
} else {
|
||||||
|
return invalidEscape()
|
||||||
|
}
|
||||||
|
n2++
|
||||||
|
}
|
||||||
|
buffer[n1] = rune(x)
|
||||||
|
|
||||||
|
default:
|
||||||
|
str := string(parser.data[startPos:parser.pos])
|
||||||
|
return str, fmt.Errorf(`invalid escape sequence in "%s" (position %d)`, str, n2-2-startPos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n1++
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.pos++
|
||||||
|
parser.skipSpaces(false)
|
||||||
|
return string(buffer[0:n1]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for parser.pos < parser.size && !parser.stopSymbol(parser.data[parser.pos]) {
|
||||||
|
parser.pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
endPos := parser.pos
|
||||||
|
parser.skipSpaces(false)
|
||||||
|
if startPos == endPos {
|
||||||
|
//ErrorLog("empty tag")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return string(parser.data[startPos:endPos]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (parser *dataParser) stopSymbol(symbol rune) bool {
|
||||||
|
return unicode.IsSpace(symbol) ||
|
||||||
|
slices.Contains([]rune{'=', '{', '}', '[', ']', ',', ' ', '\t', '\n', '\'', '"', '`', '/'}, symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (parser *dataParser) parseNode() (DataNode, error) {
|
||||||
|
var tag string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if tag, err = parser.parseTag(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.skipSpaces(true)
|
||||||
|
if parser.data[parser.pos] != '=' {
|
||||||
|
return nil, fmt.Errorf("expected '=' after a tag name (line: %d, position: %d)", parser.line, parser.pos-parser.lineStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.pos++
|
||||||
|
parser.skipSpaces(true)
|
||||||
|
switch parser.data[parser.pos] {
|
||||||
|
case '[':
|
||||||
|
node := new(dataNode)
|
||||||
|
node.tag = tag
|
||||||
|
|
||||||
|
if node.array, err = parser.parseArray(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
node := new(dataNode)
|
||||||
|
node.tag = tag
|
||||||
|
if node.value, err = parser.parseObject("_"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
|
||||||
|
case '}', ']', '=':
|
||||||
|
return nil, fmt.Errorf(`expected '[', '{' or a tag name after '=' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
|
|
||||||
|
default:
|
||||||
|
var str string
|
||||||
|
if str, err = parser.parseTag(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
node := new(dataNode)
|
||||||
|
node.tag = tag
|
||||||
|
|
||||||
|
if parser.data[parser.pos] == '{' {
|
||||||
|
if node.value, err = parser.parseObject(str); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val := new(dataStringValue)
|
||||||
|
val.value = str
|
||||||
|
node.value = val
|
||||||
|
}
|
||||||
|
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (parser *dataParser) parseObject(tag string) (DataObject, error) {
|
||||||
|
if parser.data[parser.pos] != '{' {
|
||||||
|
return nil, fmt.Errorf(`expected '{' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
|
}
|
||||||
|
parser.pos++
|
||||||
|
|
||||||
|
obj := new(dataObject)
|
||||||
|
obj.tag = tag
|
||||||
|
obj.property = []DataNode{}
|
||||||
|
|
||||||
|
for parser.pos < parser.size {
|
||||||
|
parser.skipSpaces(true)
|
||||||
|
if parser.data[parser.pos] == '}' {
|
||||||
|
parser.pos++
|
||||||
|
parser.skipSpaces(false)
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := parser.parseNode()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.property = append(obj.property, node)
|
||||||
|
if parser.data[parser.pos] == '}' {
|
||||||
|
parser.pos++
|
||||||
|
parser.skipSpaces(true)
|
||||||
|
return obj, nil
|
||||||
|
} else if parser.data[parser.pos] != ',' && parser.data[parser.pos] != '\n' {
|
||||||
|
return nil, fmt.Errorf(`expected '}', '\n' or ',' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
if parser.data[parser.pos] != '\n' {
|
||||||
|
parser.pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.skipSpaces(true)
|
||||||
|
for parser.data[parser.pos] == ',' {
|
||||||
|
parser.pos++
|
||||||
|
parser.skipSpaces(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parseObject = func(tag string) DataObject {
|
return nil, errors.New("unexpected end of text")
|
||||||
if data[pos] != '{' {
|
}
|
||||||
ErrorLogF("Expected '{' (line: %d, position: %d)", line, pos-lineStart)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
pos++
|
|
||||||
|
|
||||||
obj := new(dataObject)
|
func (parser *dataParser) parseArray() ([]DataValue, error) {
|
||||||
obj.tag = tag
|
parser.pos++
|
||||||
obj.property = []DataNode{}
|
parser.skipSpaces(true)
|
||||||
|
|
||||||
for pos < size {
|
array := []DataValue{}
|
||||||
var node DataNode
|
|
||||||
|
|
||||||
skipSpaces(true)
|
for parser.pos < parser.size {
|
||||||
if data[pos] == '}' {
|
parser.skipSpaces(true)
|
||||||
pos++
|
for parser.data[parser.pos] == ',' && parser.pos < parser.size {
|
||||||
skipSpaces(false)
|
parser.pos++
|
||||||
return obj
|
parser.skipSpaces(true)
|
||||||
}
|
|
||||||
|
|
||||||
if node = parseNode(); node == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
obj.property = append(obj.property, node)
|
|
||||||
if data[pos] == '}' {
|
|
||||||
pos++
|
|
||||||
skipSpaces(true)
|
|
||||||
return obj
|
|
||||||
} else if data[pos] != ',' && data[pos] != '\n' {
|
|
||||||
ErrorLogF(`Expected '}', '\n' or ',' (line: %d, position: %d)`, line, pos-lineStart)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if data[pos] != '\n' {
|
|
||||||
pos++
|
|
||||||
}
|
|
||||||
skipSpaces(true)
|
|
||||||
for data[pos] == ',' {
|
|
||||||
pos++
|
|
||||||
skipSpaces(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLog("Unexpected end of text")
|
if parser.pos >= parser.size {
|
||||||
return nil
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
parseArray = func() []DataValue {
|
if parser.data[parser.pos] == ']' {
|
||||||
pos++
|
parser.pos++
|
||||||
skipSpaces(true)
|
parser.skipSpaces(true)
|
||||||
|
return array, nil
|
||||||
|
}
|
||||||
|
|
||||||
array := []DataValue{}
|
tag, err := parser.parseTag()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
for pos < size {
|
if parser.data[parser.pos] == '{' {
|
||||||
var tag string
|
obj, err := parser.parseObject(tag)
|
||||||
var ok bool
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
skipSpaces(true)
|
|
||||||
for data[pos] == ',' && pos < size {
|
|
||||||
pos++
|
|
||||||
skipSpaces(true)
|
|
||||||
}
|
}
|
||||||
|
array = append(array, obj)
|
||||||
|
} else {
|
||||||
|
val := new(dataStringValue)
|
||||||
|
val.value = tag
|
||||||
|
array = append(array, val)
|
||||||
|
}
|
||||||
|
|
||||||
if pos >= size {
|
switch parser.data[parser.pos] {
|
||||||
break
|
case ']', ',', '\n':
|
||||||
}
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf(`expected ']' or ',' (line: %d, position: %d)`, parser.line, parser.pos-parser.lineStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if data[pos] == ']' {
|
if data[pos] == ']' {
|
||||||
pos++
|
|
||||||
skipSpaces(true)
|
|
||||||
return array
|
|
||||||
}
|
|
||||||
|
|
||||||
if tag, ok = parseTag(); !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if data[pos] == '{' {
|
|
||||||
obj := parseObject(tag)
|
|
||||||
if obj == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
array = append(array, obj)
|
|
||||||
} else {
|
|
||||||
val := new(dataStringValue)
|
|
||||||
val.value = tag
|
|
||||||
array = append(array, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch data[pos] {
|
|
||||||
case ']', ',', '\n':
|
|
||||||
|
|
||||||
default:
|
|
||||||
ErrorLogF("Expected ']' or ',' (line: %d, position: %d)", line, pos-lineStart)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if data[pos] == ']' {
|
|
||||||
pos++
|
|
||||||
skipSpaces()
|
|
||||||
return array, nil
|
|
||||||
} else if data[pos] != ',' {
|
|
||||||
return nil, fmt.Errorf("Expected ']' or ',' (line: %d, position: %d)", line, pos-lineStart)
|
|
||||||
}
|
|
||||||
pos++
|
pos++
|
||||||
skipSpaces()
|
skipSpaces()
|
||||||
*/
|
return array, nil
|
||||||
}
|
} else if data[pos] != ',' {
|
||||||
|
return nil, fmt.Errorf("Expected ']' or ',' (line: %d, position: %d)", line, pos-lineStart)
|
||||||
ErrorLog("Unexpected end of text")
|
}
|
||||||
return nil
|
pos++
|
||||||
|
skipSpaces()
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if tag, ok := parseTag(); ok {
|
return nil, errors.New("unexpected end of text")
|
||||||
return parseObject(tag)
|
}
|
||||||
}
|
|
||||||
return nil
|
// ParseDataText - parse text and return DataNode
|
||||||
|
func ParseDataText(text string) (DataObject, error) {
|
||||||
|
|
||||||
|
if strings.ContainsAny(text, "\r") {
|
||||||
|
text = strings.ReplaceAll(text, "\r\n", "\n")
|
||||||
|
text = strings.ReplaceAll(text, "\r", "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
parser := dataParser{
|
||||||
|
data: append([]rune(text), rune(0)),
|
||||||
|
pos: 0,
|
||||||
|
line: 1,
|
||||||
|
lineStart: 0,
|
||||||
|
}
|
||||||
|
parser.size = len(parser.data) - 1
|
||||||
|
|
||||||
|
tag, err := parser.parseTag()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return parser.parseObject(tag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,7 +312,9 @@ func dataListHtmlProperties(view View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDataList returns the data list of an editor.
|
// GetDataList returns the data list of an editor.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDataList(view View, subviewID ...string) []string {
|
func GetDataList(view View, subviewID ...string) []string {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
return getDataListProperty(view)
|
return getDataListProperty(view)
|
||||||
|
|
19
data_test.go
19
data_test.go
|
@ -6,10 +6,6 @@ import (
|
||||||
|
|
||||||
func TestParseDataText(t *testing.T) {
|
func TestParseDataText(t *testing.T) {
|
||||||
|
|
||||||
SetErrorLog(func(text string) {
|
|
||||||
t.Error(text)
|
|
||||||
})
|
|
||||||
|
|
||||||
text := `obj1 {
|
text := `obj1 {
|
||||||
key1 = val1,
|
key1 = val1,
|
||||||
key2=obj2{
|
key2=obj2{
|
||||||
|
@ -27,8 +23,10 @@ func TestParseDataText(t *testing.T) {
|
||||||
key3 = "\n \t \\ \r \" ' \X4F\x4e \U01Ea",` +
|
key3 = "\n \t \\ \r \" ' \X4F\x4e \U01Ea",` +
|
||||||
"key4=`" + `\n \t \\ \r \" ' \x8F \UF80a` + "`\r}"
|
"key4=`" + `\n \t \\ \r \" ' \x8F \UF80a` + "`\r}"
|
||||||
|
|
||||||
obj := ParseDataText(text)
|
obj, err := ParseDataText(text)
|
||||||
if obj != nil {
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else {
|
||||||
if obj.Tag() != "obj1" {
|
if obj.Tag() != "obj1" {
|
||||||
t.Error(`obj.Tag() != "obj1"`)
|
t.Error(`obj.Tag() != "obj1"`)
|
||||||
}
|
}
|
||||||
|
@ -75,7 +73,7 @@ func TestParseDataText(t *testing.T) {
|
||||||
t.Errorf(`obj.PropertyValue("key5") result: ("%s",%v)`, val, ok)
|
t.Errorf(`obj.PropertyValue("key5") result: ("%s",%v)`, val, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
testKey := func(obj DataObject, index int, tag string, nodeType int) DataNode {
|
testKey := func(obj DataObject, index int, tag string, nodeType DataNodeType) DataNode {
|
||||||
key := obj.Property(index)
|
key := obj.Property(index)
|
||||||
if key == nil {
|
if key == nil {
|
||||||
t.Errorf(`%s.Property(%d) == nil`, obj.Tag(), index)
|
t.Errorf(`%s.Property(%d) == nil`, obj.Tag(), index)
|
||||||
|
@ -118,7 +116,7 @@ func TestParseDataText(t *testing.T) {
|
||||||
|
|
||||||
type testKeyData struct {
|
type testKeyData struct {
|
||||||
tag string
|
tag string
|
||||||
nodeType int
|
nodeType DataNodeType
|
||||||
}
|
}
|
||||||
|
|
||||||
data := []testKeyData{
|
data := []testKeyData{
|
||||||
|
@ -173,9 +171,6 @@ func TestParseDataText(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetErrorLog(func(text string) {
|
|
||||||
})
|
|
||||||
|
|
||||||
failText := []string{
|
failText := []string{
|
||||||
" ",
|
" ",
|
||||||
"obj[]",
|
"obj[]",
|
||||||
|
@ -204,7 +199,7 @@ func TestParseDataText(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, txt := range failText {
|
for _, txt := range failText {
|
||||||
if obj := ParseDataText(txt); obj != nil {
|
if _, err := ParseDataText(txt); err == nil {
|
||||||
t.Errorf("result ParseDataText(\"%s\") must be fail", txt)
|
t.Errorf("result ParseDataText(\"%s\") must be fail", txt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,7 +274,7 @@ func (picker *datePickerData) propertyChanged(tag PropertyName) {
|
||||||
date := GetDatePickerValue(picker)
|
date := GetDatePickerValue(picker)
|
||||||
session.callFunc("setInputValue", picker.htmlID(), date.Format(dateFormat))
|
session.callFunc("setInputValue", picker.htmlID(), date.Format(dateFormat))
|
||||||
|
|
||||||
if listeners := GetDateChangedListeners(picker); len(listeners) > 0 {
|
if listeners := getTwoArgEventListeners[DatePicker, time.Time](picker, nil, DateChangedEvent); len(listeners) > 0 {
|
||||||
oldDate := time.Now()
|
oldDate := time.Now()
|
||||||
if value := picker.getRaw("old-date"); value != nil {
|
if value := picker.getRaw("old-date"); value != nil {
|
||||||
if date, ok := value.(time.Time); ok {
|
if date, ok := value.(time.Time); ok {
|
||||||
|
@ -282,7 +282,7 @@ func (picker *datePickerData) propertyChanged(tag PropertyName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(picker, date, oldDate)
|
listener.Run(picker, date, oldDate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,11 +348,11 @@ func (picker *datePickerData) handleCommand(self View, command PropertyName, dat
|
||||||
oldValue := GetDatePickerValue(picker)
|
oldValue := GetDatePickerValue(picker)
|
||||||
picker.properties[DatePickerValue] = value
|
picker.properties[DatePickerValue] = value
|
||||||
if value != oldValue {
|
if value != oldValue {
|
||||||
for _, listener := range GetDateChangedListeners(picker) {
|
for _, listener := range getTwoArgEventListeners[DatePicker, time.Time](picker, nil, DateChangedEvent) {
|
||||||
listener(picker, value, oldValue)
|
listener.Run(picker, value, oldValue)
|
||||||
}
|
}
|
||||||
if listener, ok := picker.changeListener[DatePickerValue]; ok {
|
if listener, ok := picker.changeListener[DatePickerValue]; ok {
|
||||||
listener(picker, DatePickerValue)
|
listener.Run(picker, DatePickerValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,7 +400,9 @@ func getDateProperty(view View, mainTag, shortTag PropertyName) (time.Time, bool
|
||||||
|
|
||||||
// GetDatePickerMin returns the min date of DatePicker subview and "true" as the second value if the min date is set,
|
// GetDatePickerMin returns the min date of DatePicker subview and "true" as the second value if the min date is set,
|
||||||
// "false" as the second value otherwise.
|
// "false" as the second value otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDatePickerMin(view View, subviewID ...string) (time.Time, bool) {
|
func GetDatePickerMin(view View, subviewID ...string) (time.Time, bool) {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
return getDateProperty(view, DatePickerMin, Min)
|
return getDateProperty(view, DatePickerMin, Min)
|
||||||
|
@ -410,7 +412,9 @@ func GetDatePickerMin(view View, subviewID ...string) (time.Time, bool) {
|
||||||
|
|
||||||
// GetDatePickerMax returns the max date of DatePicker subview and "true" as the second value if the min date is set,
|
// GetDatePickerMax returns the max date of DatePicker subview and "true" as the second value if the min date is set,
|
||||||
// "false" as the second value otherwise.
|
// "false" as the second value otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDatePickerMax(view View, subviewID ...string) (time.Time, bool) {
|
func GetDatePickerMax(view View, subviewID ...string) (time.Time, bool) {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
return getDateProperty(view, DatePickerMax, Max)
|
return getDateProperty(view, DatePickerMax, Max)
|
||||||
|
@ -419,13 +423,17 @@ func GetDatePickerMax(view View, subviewID ...string) (time.Time, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDatePickerStep returns the date changing step in days of DatePicker subview.
|
// GetDatePickerStep returns the date changing step in days of DatePicker subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDatePickerStep(view View, subviewID ...string) int {
|
func GetDatePickerStep(view View, subviewID ...string) int {
|
||||||
return intStyledProperty(view, subviewID, DatePickerStep, 0)
|
return intStyledProperty(view, subviewID, DatePickerStep, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDatePickerValue returns the date of DatePicker subview.
|
// GetDatePickerValue returns the date of DatePicker subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDatePickerValue(view View, subviewID ...string) time.Time {
|
func GetDatePickerValue(view View, subviewID ...string) time.Time {
|
||||||
if view = getSubview(view, subviewID); view == nil {
|
if view = getSubview(view, subviewID); view == nil {
|
||||||
return time.Now()
|
return time.Now()
|
||||||
|
@ -436,7 +444,18 @@ func GetDatePickerValue(view View, subviewID ...string) time.Time {
|
||||||
|
|
||||||
// GetDateChangedListeners returns the DateChangedListener list of an DatePicker subview.
|
// GetDateChangedListeners returns the DateChangedListener list of an DatePicker subview.
|
||||||
// If there are no listeners then the empty list is returned
|
// If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetDateChangedListeners(view View, subviewID ...string) []func(DatePicker, time.Time, time.Time) {
|
// Result elements can be of the following types:
|
||||||
return getTwoArgEventListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent)
|
// - func(rui.DatePicker, time.Time, time.Time),
|
||||||
|
// - func(rui.DatePicker, time.Time),
|
||||||
|
// - func(rui.DatePicker),
|
||||||
|
// - func(time.Time, time.Time),
|
||||||
|
// - func(time.Time),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetDateChangedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getTwoArgEventRawListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (detailsView *detailsViewData) setFunc(tag PropertyName, value any) []Prope
|
||||||
value.setParentID(detailsView.htmlID())
|
value.setParentID(detailsView.htmlID())
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
if view := CreateViewFromObject(detailsView.Session(), value); view != nil {
|
if view := CreateViewFromObject(detailsView.Session(), value, nil); view != nil {
|
||||||
detailsView.setRaw(Summary, view)
|
detailsView.setRaw(Summary, view)
|
||||||
view.setParentID(detailsView.htmlID())
|
view.setParentID(detailsView.htmlID())
|
||||||
} else {
|
} else {
|
||||||
|
@ -193,7 +193,7 @@ func (detailsView *detailsViewData) handleCommand(self View, command PropertyNam
|
||||||
if n, ok := dataIntProperty(data, "open"); ok {
|
if n, ok := dataIntProperty(data, "open"); ok {
|
||||||
detailsView.properties[Expanded] = (n != 0)
|
detailsView.properties[Expanded] = (n != 0)
|
||||||
if listener, ok := detailsView.changeListener[Expanded]; ok {
|
if listener, ok := detailsView.changeListener[Expanded]; ok {
|
||||||
listener(detailsView, Expanded)
|
listener.Run(detailsView, Expanded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -202,7 +202,9 @@ func (detailsView *detailsViewData) handleCommand(self View, command PropertyNam
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDetailsSummary returns a value of the Summary property of DetailsView.
|
// GetDetailsSummary returns a value of the Summary property of DetailsView.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDetailsSummary(view View, subviewID ...string) View {
|
func GetDetailsSummary(view View, subviewID ...string) View {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if value := view.Get(Summary); value != nil {
|
if value := view.Get(Summary); value != nil {
|
||||||
|
@ -219,13 +221,17 @@ func GetDetailsSummary(view View, subviewID ...string) View {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDetailsExpanded returns a value of the Expanded property of DetailsView.
|
// IsDetailsExpanded returns a value of the Expanded property of DetailsView.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsDetailsExpanded(view View, subviewID ...string) bool {
|
func IsDetailsExpanded(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, Expanded, false)
|
return boolStyledProperty(view, subviewID, Expanded, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDetailsExpanded returns a value of the HideSummaryMarker property of DetailsView.
|
// IsDetailsExpanded returns a value of the HideSummaryMarker property of DetailsView.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsSummaryMarkerHidden(view View, subviewID ...string) bool {
|
func IsSummaryMarkerHidden(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, HideSummaryMarker, false)
|
return boolStyledProperty(view, subviewID, HideSummaryMarker, false)
|
||||||
}
|
}
|
||||||
|
|
180
dragAndDrop.go
180
dragAndDrop.go
|
@ -49,7 +49,7 @@ const (
|
||||||
// Supported types: int, string.
|
// Supported types: int, string.
|
||||||
//
|
//
|
||||||
// Values:
|
// Values:
|
||||||
// - 0 (DropEffectUndefined) or "undefined" - The property value is not defined (defaut value).
|
// - 0 (DropEffectUndefined) or "undefined" - The property value is not defined (default value).
|
||||||
// - 1 (DropEffectCopy) or "copy" - A copy of the source item may be made at the new location.
|
// - 1 (DropEffectCopy) or "copy" - A copy of the source item may be made at the new location.
|
||||||
// - 2 (DropEffectMove) or "move" - An item may be moved to a new location.
|
// - 2 (DropEffectMove) or "move" - An item may be moved to a new location.
|
||||||
// - 4 (DropEffectLink) or "link" - A link may be established to the source at the new location.
|
// - 4 (DropEffectLink) or "link" - A link may be established to the source at the new location.
|
||||||
|
@ -68,7 +68,7 @@ const (
|
||||||
// Supported types: int, string.
|
// Supported types: int, string.
|
||||||
//
|
//
|
||||||
// Values:
|
// Values:
|
||||||
// - 0 (DropEffectUndefined) or "undefined" - The property value is not defined (defaut value). Equivalent to DropEffectAll
|
// - 0 (DropEffectUndefined) or "undefined" - The property value is not defined (default value). Equivalent to DropEffectAll
|
||||||
// - 1 (DropEffectCopy) or "copy" - A copy of the source item may be made at the new location.
|
// - 1 (DropEffectCopy) or "copy" - A copy of the source item may be made at the new location.
|
||||||
// - 2 (DropEffectMove) or "move" - An item may be moved to a new location.
|
// - 2 (DropEffectMove) or "move" - An item may be moved to a new location.
|
||||||
// - 3 (DropEffectLink) or "link" - A link may be established to the source at the new location.
|
// - 3 (DropEffectLink) or "link" - A link may be established to the source at the new location.
|
||||||
|
@ -84,7 +84,16 @@ const (
|
||||||
// Fired when the user starts dragging an element or text selection.
|
// Fired when the user starts dragging an element or text selection.
|
||||||
//
|
//
|
||||||
// General listener format:
|
// General listener format:
|
||||||
|
// func(view rui.View, event rui.DragAndDropEvent).
|
||||||
//
|
//
|
||||||
|
// where:
|
||||||
|
// - view - Interface of a view which generated this event,
|
||||||
|
// - event - event parameters.
|
||||||
|
//
|
||||||
|
// Allowed listener formats:
|
||||||
|
// func(view rui.View)
|
||||||
|
// func(rui.DragAndDropEvent)
|
||||||
|
// func()
|
||||||
DragStartEvent PropertyName = "drag-start-event"
|
DragStartEvent PropertyName = "drag-start-event"
|
||||||
|
|
||||||
// DragEndEvent is the constant for "drag-end-event" property tag.
|
// DragEndEvent is the constant for "drag-end-event" property tag.
|
||||||
|
@ -93,7 +102,16 @@ const (
|
||||||
// Fired when a drag operation ends (by releasing a mouse button or hitting the escape key).
|
// Fired when a drag operation ends (by releasing a mouse button or hitting the escape key).
|
||||||
//
|
//
|
||||||
// General listener format:
|
// General listener format:
|
||||||
|
// func(view rui.View, event rui.DragAndDropEvent).
|
||||||
//
|
//
|
||||||
|
// where:
|
||||||
|
// - view - Interface of a view which generated this event,
|
||||||
|
// - event - event parameters.
|
||||||
|
//
|
||||||
|
// Allowed listener formats:
|
||||||
|
// func(view rui.View)
|
||||||
|
// func(rui.DragAndDropEvent)
|
||||||
|
// func()
|
||||||
DragEndEvent PropertyName = "drag-end-event"
|
DragEndEvent PropertyName = "drag-end-event"
|
||||||
|
|
||||||
// DragEnterEvent is the constant for "drag-enter-event" property tag.
|
// DragEnterEvent is the constant for "drag-enter-event" property tag.
|
||||||
|
@ -102,7 +120,16 @@ const (
|
||||||
// Fired when a dragged element or text selection enters a valid drop target.
|
// Fired when a dragged element or text selection enters a valid drop target.
|
||||||
//
|
//
|
||||||
// General listener format:
|
// General listener format:
|
||||||
|
// func(view rui.View, event rui.DragAndDropEvent).
|
||||||
//
|
//
|
||||||
|
// where:
|
||||||
|
// - view - Interface of a view which generated this event,
|
||||||
|
// - event - event parameters.
|
||||||
|
//
|
||||||
|
// Allowed listener formats:
|
||||||
|
// func(view rui.View)
|
||||||
|
// func(rui.DragAndDropEvent)
|
||||||
|
// func()
|
||||||
DragEnterEvent PropertyName = "drag-enter-event"
|
DragEnterEvent PropertyName = "drag-enter-event"
|
||||||
|
|
||||||
// DragLeaveEvent is the constant for "drag-leave-event" property tag.
|
// DragLeaveEvent is the constant for "drag-leave-event" property tag.
|
||||||
|
@ -111,7 +138,16 @@ const (
|
||||||
// Fired when a dragged element or text selection leaves a valid drop target.
|
// Fired when a dragged element or text selection leaves a valid drop target.
|
||||||
//
|
//
|
||||||
// General listener format:
|
// General listener format:
|
||||||
|
// func(view rui.View, event rui.DragAndDropEvent).
|
||||||
//
|
//
|
||||||
|
// where:
|
||||||
|
// - view - Interface of a view which generated this event,
|
||||||
|
// - event - event parameters.
|
||||||
|
//
|
||||||
|
// Allowed listener formats:
|
||||||
|
// func(view rui.View)
|
||||||
|
// func(rui.DragAndDropEvent)
|
||||||
|
// func()
|
||||||
DragLeaveEvent PropertyName = "drag-leave-event"
|
DragLeaveEvent PropertyName = "drag-leave-event"
|
||||||
|
|
||||||
// DragOverEvent is the constant for "drag-over-event" property tag.
|
// DragOverEvent is the constant for "drag-over-event" property tag.
|
||||||
|
@ -120,7 +156,16 @@ const (
|
||||||
// Fired when an element or text selection is being dragged over a valid drop target (every few hundred milliseconds).
|
// Fired when an element or text selection is being dragged over a valid drop target (every few hundred milliseconds).
|
||||||
//
|
//
|
||||||
// General listener format:
|
// General listener format:
|
||||||
|
// func(view rui.View, event rui.DragAndDropEvent).
|
||||||
//
|
//
|
||||||
|
// where:
|
||||||
|
// - view - Interface of a view which generated this event,
|
||||||
|
// - event - event parameters.
|
||||||
|
//
|
||||||
|
// Allowed listener formats:
|
||||||
|
// func(view rui.View)
|
||||||
|
// func(rui.DragAndDropEvent)
|
||||||
|
// func()
|
||||||
DragOverEvent PropertyName = "drag-over-event"
|
DragOverEvent PropertyName = "drag-over-event"
|
||||||
|
|
||||||
// DropEvent is the constant for "drop-event" property tag.
|
// DropEvent is the constant for "drop-event" property tag.
|
||||||
|
@ -129,7 +174,16 @@ const (
|
||||||
// Fired when an element or text selection is dropped on a valid drop target.
|
// Fired when an element or text selection is dropped on a valid drop target.
|
||||||
//
|
//
|
||||||
// General listener format:
|
// General listener format:
|
||||||
|
// func(view rui.View, event rui.DragAndDropEvent).
|
||||||
//
|
//
|
||||||
|
// where:
|
||||||
|
// - view - Interface of a view which generated this event,
|
||||||
|
// - event - event parameters.
|
||||||
|
//
|
||||||
|
// Allowed listener formats:
|
||||||
|
// func(view rui.View)
|
||||||
|
// func(rui.DragAndDropEvent)
|
||||||
|
// func()
|
||||||
DropEvent PropertyName = "drop-event"
|
DropEvent PropertyName = "drop-event"
|
||||||
|
|
||||||
// DropEffectUndefined - the value of the "drop-effect" and "drop-effect-allowed" properties: the value is not defined (default value).
|
// DropEffectUndefined - the value of the "drop-effect" and "drop-effect-allowed" properties: the value is not defined (default value).
|
||||||
|
@ -156,7 +210,7 @@ const (
|
||||||
// DropEffectLinkMove - the value of the "drop-effect-allowed" property: a link or move operation is permitted.
|
// DropEffectLinkMove - the value of the "drop-effect-allowed" property: a link or move operation is permitted.
|
||||||
DropEffectLinkMove = DropEffectLink + DropEffectMove
|
DropEffectLinkMove = DropEffectLink + DropEffectMove
|
||||||
|
|
||||||
// DropEffectAll - the value of the "drop-effect-allowed" property: all operations (copy, move, and link) are permitted (defaut value).
|
// DropEffectAll - the value of the "drop-effect-allowed" property: all operations (copy, move, and link) are permitted (default value).
|
||||||
DropEffectAll = DropEffectCopy + DropEffectMove + DropEffectLink
|
DropEffectAll = DropEffectCopy + DropEffectMove + DropEffectLink
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -336,7 +390,7 @@ func handleDragAndDropEvents(view View, tag PropertyName, data DataObject) {
|
||||||
event.init(view.Session(), data)
|
event.init(view.Session(), data)
|
||||||
|
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(view, event)
|
listener.Run(view, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -408,17 +462,17 @@ func dragAndDropHtml(view View, buffer *strings.Builder) {
|
||||||
|
|
||||||
if f := GetDragImageXOffset(view); f != 0 {
|
if f := GetDragImageXOffset(view); f != 0 {
|
||||||
buffer.WriteString(` data-drag-image-x="`)
|
buffer.WriteString(` data-drag-image-x="`)
|
||||||
buffer.WriteString(fmt.Sprintf("%g", f))
|
fmt.Fprintf(buffer, "%g", f)
|
||||||
buffer.WriteString(`" `)
|
buffer.WriteString(`" `)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f := GetDragImageYOffset(view); f != 0 {
|
if f := GetDragImageYOffset(view); f != 0 {
|
||||||
buffer.WriteString(` data-drag-image-y="`)
|
buffer.WriteString(` data-drag-image-y="`)
|
||||||
buffer.WriteString(fmt.Sprintf("%g", f))
|
fmt.Fprintf(buffer, "%g", f)
|
||||||
buffer.WriteString(`" `)
|
buffer.WriteString(`" `)
|
||||||
}
|
}
|
||||||
|
|
||||||
effects := []string{"undifined", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"}
|
effects := []string{"undefined", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"}
|
||||||
if n := GetDropEffectAllowed(view); n > 0 && n < len(effects) {
|
if n := GetDropEffectAllowed(view); n > 0 && n < len(effects) {
|
||||||
buffer.WriteString(` data-drop-effect-allowed="`)
|
buffer.WriteString(` data-drop-effect-allowed="`)
|
||||||
buffer.WriteString(effects[n])
|
buffer.WriteString(effects[n])
|
||||||
|
@ -434,41 +488,99 @@ func (view *viewData) LoadFile(file FileInfo, result func(FileInfo, []byte)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDragStartEventListeners returns the "drag-start-event" listener list. If there are no listeners then the empty list is returned.
|
// GetDragStartEventListeners returns the "drag-start-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetDragStartEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragStartEvent)
|
// - func(rui.View, rui.DragAndDropEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.DragAndDropEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetDragStartEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragStartEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDragEndEventListeners returns the "drag-end-event" listener list. If there are no listeners then the empty list is returned.
|
// GetDragEndEventListeners returns the "drag-end-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetDragEndEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragEndEvent)
|
// - func(rui.View, rui.DragAndDropEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.DragAndDropEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetDragEndEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragEndEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDragEnterEventListeners returns the "drag-enter-event" listener list. If there are no listeners then the empty list is returned.
|
// GetDragEnterEventListeners returns the "drag-enter-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetDragEnterEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragEnterEvent)
|
// - func(rui.View, rui.DragAndDropEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.DragAndDropEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetDragEnterEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragEnterEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDragLeaveEventListeners returns the "drag-leave-event" listener list. If there are no listeners then the empty list is returned.
|
// GetDragLeaveEventListeners returns the "drag-leave-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetDragLeaveEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragLeaveEvent)
|
// - func(rui.View, rui.DragAndDropEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.DragAndDropEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetDragLeaveEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragLeaveEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDragOverEventListeners returns the "drag-over-event" listener list. If there are no listeners then the empty list is returned.
|
// GetDragOverEventListeners returns the "drag-over-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetDragOverEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DragOverEvent)
|
// - func(rui.View, rui.DragAndDropEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.DragAndDropEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetDragOverEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DragOverEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDropEventListeners returns the "drag-start-event" listener list. If there are no listeners then the empty list is returned.
|
// GetDropEventListeners returns the "drag-start-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetDropEventListeners(view View, subviewID ...string) []func(View, DragAndDropEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, DragAndDropEvent](view, subviewID, DropEvent)
|
// - func(rui.View, rui.DragAndDropEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.DragAndDropEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetDropEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, DragAndDropEvent](view, subviewID, DropEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDropEventListeners returns the "drag-data" data.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDragData(view View, subviewID ...string) map[string]string {
|
func GetDragData(view View, subviewID ...string) map[string]string {
|
||||||
result := map[string]string{}
|
result := map[string]string{}
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
|
@ -483,7 +595,9 @@ func GetDragData(view View, subviewID ...string) map[string]string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDragImage returns the drag feedback image.
|
// GetDragImage returns the drag feedback image.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDragImage(view View, subviewID ...string) string {
|
func GetDragImage(view View, subviewID ...string) string {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
value := view.getRaw(DragImage)
|
value := view.getRaw(DragImage)
|
||||||
|
@ -508,13 +622,17 @@ func GetDragImage(view View, subviewID ...string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDragImageXOffset returns the horizontal offset in pixels within the drag feedback image.
|
// GetDragImageXOffset returns the horizontal offset in pixels within the drag feedback image.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDragImageXOffset(view View, subviewID ...string) float64 {
|
func GetDragImageXOffset(view View, subviewID ...string) float64 {
|
||||||
return floatStyledProperty(view, subviewID, DragImageXOffset, 0)
|
return floatStyledProperty(view, subviewID, DragImageXOffset, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDragImageYOffset returns the vertical offset in pixels within the drag feedback image.
|
// GetDragImageYOffset returns the vertical offset in pixels within the drag feedback image.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDragImageYOffset(view View, subviewID ...string) float64 {
|
func GetDragImageYOffset(view View, subviewID ...string) float64 {
|
||||||
return floatStyledProperty(view, subviewID, DragImageYOffset, 0)
|
return floatStyledProperty(view, subviewID, DragImageYOffset, 0)
|
||||||
}
|
}
|
||||||
|
@ -529,7 +647,8 @@ func GetDragImageYOffset(view View, subviewID ...string) float64 {
|
||||||
// - 2 (DropEffectMove) - An item may be moved to a new location.
|
// - 2 (DropEffectMove) - An item may be moved to a new location.
|
||||||
// - 4 (DropEffectLink) - A link may be established to the source at the new location.
|
// - 4 (DropEffectLink) - A link may be established to the source at the new location.
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDropEffect(view View, subviewID ...string) int {
|
func GetDropEffect(view View, subviewID ...string) int {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
value := view.getRaw(DropEffect)
|
value := view.getRaw(DropEffect)
|
||||||
|
@ -573,7 +692,8 @@ func GetDropEffect(view View, subviewID ...string) int {
|
||||||
// - 6 (DropEffectLinkMove) - A link or move operation is permitted.
|
// - 6 (DropEffectLinkMove) - A link or move operation is permitted.
|
||||||
// - 7 (DropEffectAll) - All operations are permitted.
|
// - 7 (DropEffectAll) - All operations are permitted.
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDropEffectAllowed(view View, subviewID ...string) int {
|
func GetDropEffectAllowed(view View, subviewID ...string) int {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
value := view.getRaw(DropEffectAllowed)
|
value := view.getRaw(DropEffectAllowed)
|
||||||
|
|
|
@ -104,8 +104,8 @@ func (list *dropDownListData) propertyChanged(tag PropertyName) {
|
||||||
list.Session().callFunc("selectDropDownListItem", list.htmlID(), current)
|
list.Session().callFunc("selectDropDownListItem", list.htmlID(), current)
|
||||||
|
|
||||||
oldCurrent, _ := intProperty(list, "old-current", list.Session(), -1)
|
oldCurrent, _ := intProperty(list, "old-current", list.Session(), -1)
|
||||||
for _, listener := range GetDropDownListeners(list) {
|
for _, listener := range getTwoArgEventListeners[DropDownList, int](list, nil, DropDownEvent) {
|
||||||
listener(list, current, oldCurrent)
|
listener.Run(list, current, oldCurrent)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -245,11 +245,11 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat
|
||||||
if GetCurrent(list) != number && number >= 0 && number < len(items) {
|
if GetCurrent(list) != number && number >= 0 && number < len(items) {
|
||||||
old := GetCurrent(list)
|
old := GetCurrent(list)
|
||||||
list.properties[Current] = number
|
list.properties[Current] = number
|
||||||
for _, listener := range GetDropDownListeners(list) {
|
for _, listener := range getTwoArgEventListeners[DropDownList, int](list, nil, DropDownEvent) {
|
||||||
listener(list, number, old)
|
listener.Run(list, number, old)
|
||||||
}
|
}
|
||||||
if listener, ok := list.changeListener[Current]; ok {
|
if listener, ok := list.changeListener[Current]; ok {
|
||||||
listener(list, Current)
|
listener.Run(list, Current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -264,13 +264,26 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDropDownListeners returns the "drop-down-event" listener list. If there are no listeners then the empty list is returned.
|
// GetDropDownListeners returns the "drop-down-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetDropDownListeners(view View, subviewID ...string) []func(DropDownList, int, int) {
|
// Result elements can be of the following types:
|
||||||
return getTwoArgEventListeners[DropDownList, int](view, subviewID, DropDownEvent)
|
// - func(rui.DropDownList, int, int),
|
||||||
|
// - func(rui.DropDownList, int),
|
||||||
|
// - func(rui.DropDownList),
|
||||||
|
// - func(int, int),
|
||||||
|
// - func(int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetDropDownListeners(view View, subviewID ...string) []any {
|
||||||
|
return getTwoArgEventRawListeners[DropDownList, int](view, subviewID, DropDownEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDropDownItems return the DropDownList items list.
|
// GetDropDownItems return the DropDownList items list.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDropDownItems(view View, subviewID ...string) []string {
|
func GetDropDownItems(view View, subviewID ...string) []string {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if value := view.Get(Items); value != nil {
|
if value := view.Get(Items); value != nil {
|
||||||
|
@ -313,14 +326,18 @@ func getIndicesArray(view View, tag PropertyName) []int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDropDownDisabledItems return an array of disabled(non selectable) items indices of DropDownList.
|
// GetDropDownDisabledItems return an array of disabled(non selectable) items indices of DropDownList.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDropDownDisabledItems(view View, subviewID ...string) []int {
|
func GetDropDownDisabledItems(view View, subviewID ...string) []int {
|
||||||
view = getSubview(view, subviewID)
|
view = getSubview(view, subviewID)
|
||||||
return getIndicesArray(view, DisabledItems)
|
return getIndicesArray(view, DisabledItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDropDownItemSeparators return an array of indices of DropDownList items after which a separator should be added.
|
// GetDropDownItemSeparators return an array of indices of DropDownList items after which a separator should be added.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetDropDownItemSeparators(view View, subviewID ...string) []int {
|
func GetDropDownItemSeparators(view View, subviewID ...string) []int {
|
||||||
view = getSubview(view, subviewID)
|
view = getSubview(view, subviewID)
|
||||||
return getIndicesArray(view, ItemSeparators)
|
return getIndicesArray(view, ItemSeparators)
|
||||||
|
|
47
editView.go
47
editView.go
|
@ -268,11 +268,11 @@ func (edit *editViewData) AppendText(text string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (edit *editViewData) textChanged(newText, oldText string) {
|
func (edit *editViewData) textChanged(newText, oldText string) {
|
||||||
for _, listener := range GetTextChangedListeners(edit) {
|
for _, listener := range getTwoArgEventListeners[EditView, string](edit, nil, EditTextChangedEvent) {
|
||||||
listener(edit, newText, oldText)
|
listener.Run(edit, newText, oldText)
|
||||||
}
|
}
|
||||||
if listener, ok := edit.changeListener[Text]; ok {
|
if listener, ok := edit.changeListener[Text]; ok {
|
||||||
listener(edit, Text)
|
listener.Run(edit, Text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,26 +451,43 @@ func IsReadOnly(view View, subviewID ...string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSpellcheck returns a value of the Spellcheck property of EditView.
|
// IsSpellcheck returns a value of the Spellcheck property of EditView.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsSpellcheck(view View, subviewID ...string) bool {
|
func IsSpellcheck(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, Spellcheck, false)
|
return boolStyledProperty(view, subviewID, Spellcheck, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTextChangedListeners returns the TextChangedListener list of an EditView or MultiLineEditView subview.
|
// GetTextChangedListeners returns the TextChangedListener list of an EditView or MultiLineEditView subview.
|
||||||
// If there are no listeners then the empty list is returned
|
// If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTextChangedListeners(view View, subviewID ...string) []func(EditView, string, string) {
|
// Result elements can be of the following types:
|
||||||
return getTwoArgEventListeners[EditView, string](view, subviewID, EditTextChangedEvent)
|
// - func(rui.EditView, string, string),
|
||||||
|
// - func(rui.EditView, string),
|
||||||
|
// - func(rui.EditView),
|
||||||
|
// - func(string, string),
|
||||||
|
// - func(string),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTextChangedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getTwoArgEventRawListeners[EditView, string](view, subviewID, EditTextChangedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEditViewType returns a value of the Type property of EditView.
|
// GetEditViewType returns a value of the Type property of EditView.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetEditViewType(view View, subviewID ...string) int {
|
func GetEditViewType(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, EditViewType, SingleLineText, false)
|
return enumStyledProperty(view, subviewID, EditViewType, SingleLineText, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEditViewPattern returns a value of the Pattern property of EditView.
|
// GetEditViewPattern returns a value of the Pattern property of EditView.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetEditViewPattern(view View, subviewID ...string) string {
|
func GetEditViewPattern(view View, subviewID ...string) string {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if pattern, ok := stringProperty(view, EditViewPattern, view.Session()); ok {
|
if pattern, ok := stringProperty(view, EditViewPattern, view.Session()); ok {
|
||||||
|
@ -488,13 +505,17 @@ func GetEditViewPattern(view View, subviewID ...string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEditViewWrap returns a value of the EditWrap property of MultiLineEditView.
|
// IsEditViewWrap returns a value of the EditWrap property of MultiLineEditView.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsEditViewWrap(view View, subviewID ...string) bool {
|
func IsEditViewWrap(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, EditWrap, false)
|
return boolStyledProperty(view, subviewID, EditWrap, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendEditText appends the text to the EditView content.
|
// AppendEditText appends the text to the EditView content.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func AppendEditText(view View, subviewID string, text string) {
|
func AppendEditText(view View, subviewID string, text string) {
|
||||||
if subviewID != "" {
|
if subviewID != "" {
|
||||||
if edit := EditViewByID(view, subviewID); edit != nil {
|
if edit := EditViewByID(view, subviewID); edit != nil {
|
||||||
|
@ -509,7 +530,9 @@ func AppendEditText(view View, subviewID string, text string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCaretColor returns the color of the text input caret.
|
// GetCaretColor returns the color of the text input caret.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetCaretColor(view View, subviewID ...string) Color {
|
func GetCaretColor(view View, subviewID ...string) Color {
|
||||||
return colorStyledProperty(view, subviewID, CaretColor, false)
|
return colorStyledProperty(view, subviewID, CaretColor, false)
|
||||||
}
|
}
|
||||||
|
|
666
events.go
666
events.go
|
@ -1,6 +1,9 @@
|
||||||
package rui
|
package rui
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
var eventJsFunc = map[PropertyName]struct{ jsEvent, jsFunc string }{
|
var eventJsFunc = map[PropertyName]struct{ jsEvent, jsFunc string }{
|
||||||
FocusEvent: {jsEvent: "onfocus", jsFunc: "focusEvent"},
|
FocusEvent: {jsEvent: "onfocus", jsFunc: "focusEvent"},
|
||||||
|
@ -38,469 +41,14 @@ var eventJsFunc = map[PropertyName]struct{ jsEvent, jsFunc string }{
|
||||||
DragLeaveEvent: {jsEvent: "ondragleave", jsFunc: "dragLeaveEvent"},
|
DragLeaveEvent: {jsEvent: "ondragleave", jsFunc: "dragLeaveEvent"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func valueToNoArgEventListeners[V any](value any) ([]func(V), bool) {
|
|
||||||
if value == nil {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case func(V):
|
|
||||||
return []func(V){value}, true
|
|
||||||
|
|
||||||
case func():
|
|
||||||
fn := func(V) {
|
|
||||||
value()
|
|
||||||
}
|
|
||||||
return []func(V){fn}, true
|
|
||||||
|
|
||||||
case []func(V):
|
|
||||||
if len(value) == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
for _, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case []func():
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(V) {
|
|
||||||
v()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
switch v := v.(type) {
|
|
||||||
case func(V):
|
|
||||||
listeners[i] = v
|
|
||||||
|
|
||||||
case func():
|
|
||||||
listeners[i] = func(V) {
|
|
||||||
v()
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func valueToOneArgEventListeners[V View, E any](value any) ([]func(V, E), bool) {
|
|
||||||
if value == nil {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case func(V, E):
|
|
||||||
return []func(V, E){value}, true
|
|
||||||
|
|
||||||
case func(E):
|
|
||||||
fn := func(_ V, event E) {
|
|
||||||
value(event)
|
|
||||||
}
|
|
||||||
return []func(V, E){fn}, true
|
|
||||||
|
|
||||||
case func(V):
|
|
||||||
fn := func(view V, _ E) {
|
|
||||||
value(view)
|
|
||||||
}
|
|
||||||
return []func(V, E){fn}, true
|
|
||||||
|
|
||||||
case func():
|
|
||||||
fn := func(V, E) {
|
|
||||||
value()
|
|
||||||
}
|
|
||||||
return []func(V, E){fn}, true
|
|
||||||
|
|
||||||
case []func(V, E):
|
|
||||||
if len(value) == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
for _, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case []func(E):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ V, event E) {
|
|
||||||
v(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func(V):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(view V, _ E) {
|
|
||||||
v(view)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func():
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(V, E) {
|
|
||||||
v()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
switch v := v.(type) {
|
|
||||||
case func(V, E):
|
|
||||||
listeners[i] = v
|
|
||||||
|
|
||||||
case func(E):
|
|
||||||
listeners[i] = func(_ V, event E) {
|
|
||||||
v(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(V):
|
|
||||||
listeners[i] = func(view V, _ E) {
|
|
||||||
v(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func():
|
|
||||||
listeners[i] = func(V, E) {
|
|
||||||
v()
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func valueToTwoArgEventListeners[V View, E any](value any) ([]func(V, E, E), bool) {
|
|
||||||
if value == nil {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case func(V, E, E):
|
|
||||||
return []func(V, E, E){value}, true
|
|
||||||
|
|
||||||
case func(V, E):
|
|
||||||
fn := func(v V, val, _ E) {
|
|
||||||
value(v, val)
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case func(E, E):
|
|
||||||
fn := func(_ V, val, old E) {
|
|
||||||
value(val, old)
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case func(E):
|
|
||||||
fn := func(_ V, val, _ E) {
|
|
||||||
value(val)
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case func(V):
|
|
||||||
fn := func(v V, _, _ E) {
|
|
||||||
value(v)
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case func():
|
|
||||||
fn := func(V, E, E) {
|
|
||||||
value()
|
|
||||||
}
|
|
||||||
return []func(V, E, E){fn}, true
|
|
||||||
|
|
||||||
case []func(V, E, E):
|
|
||||||
if len(value) == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
for _, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case []func(V, E):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(view V, val, _ E) {
|
|
||||||
fn(view, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func(E):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ V, val, _ E) {
|
|
||||||
fn(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func(E, E):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ V, val, old E) {
|
|
||||||
fn(val, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func(V):
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(view V, _, _ E) {
|
|
||||||
fn(view)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func():
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(V, E, E) {
|
|
||||||
fn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
count := len(value)
|
|
||||||
if count == 0 {
|
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(V, E, E), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
switch fn := v.(type) {
|
|
||||||
case func(V, E, E):
|
|
||||||
listeners[i] = fn
|
|
||||||
|
|
||||||
case func(V, E):
|
|
||||||
listeners[i] = func(view V, val, _ E) {
|
|
||||||
fn(view, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(E, E):
|
|
||||||
listeners[i] = func(_ V, val, old E) {
|
|
||||||
fn(val, old)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(E):
|
|
||||||
listeners[i] = func(_ V, val, _ E) {
|
|
||||||
fn(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(V):
|
|
||||||
listeners[i] = func(view V, _, _ E) {
|
|
||||||
fn(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func():
|
|
||||||
listeners[i] = func(V, E, E) {
|
|
||||||
fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNoArgEventListeners[V View](view View, subviewID []string, tag PropertyName) []func(V) {
|
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
|
||||||
if value := view.Get(tag); value != nil {
|
|
||||||
if result, ok := value.([]func(V)); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []func(V){}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOneArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E) {
|
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
|
||||||
if value := view.Get(tag); value != nil {
|
|
||||||
if result, ok := value.([]func(V, E)); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []func(V, E){}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTwoArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E, E) {
|
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
|
||||||
if value := view.Get(tag); value != nil {
|
|
||||||
if result, ok := value.([]func(V, E, E)); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return []func(V, E, E){}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setNoArgEventListener[V View](properties Properties, tag PropertyName, value any) []PropertyName {
|
|
||||||
if listeners, ok := valueToNoArgEventListeners[V](value); ok {
|
|
||||||
if len(listeners) > 0 {
|
|
||||||
properties.setRaw(tag, listeners)
|
|
||||||
} else if properties.getRaw(tag) != nil {
|
|
||||||
properties.setRaw(tag, nil)
|
|
||||||
} else {
|
|
||||||
return []PropertyName{}
|
|
||||||
}
|
|
||||||
return []PropertyName{tag}
|
|
||||||
}
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setOneArgEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName {
|
|
||||||
if listeners, ok := valueToOneArgEventListeners[V, T](value); ok {
|
|
||||||
if len(listeners) > 0 {
|
|
||||||
properties.setRaw(tag, listeners)
|
|
||||||
} else if properties.getRaw(tag) != nil {
|
|
||||||
properties.setRaw(tag, nil)
|
|
||||||
} else {
|
|
||||||
return []PropertyName{}
|
|
||||||
}
|
|
||||||
return []PropertyName{tag}
|
|
||||||
}
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTwoArgEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName {
|
|
||||||
listeners, ok := valueToTwoArgEventListeners[V, T](value)
|
|
||||||
if !ok {
|
|
||||||
notCompatibleType(tag, value)
|
|
||||||
return nil
|
|
||||||
} else if len(listeners) > 0 {
|
|
||||||
properties.setRaw(tag, listeners)
|
|
||||||
} else if properties.getRaw(tag) != nil {
|
|
||||||
properties.setRaw(tag, nil)
|
|
||||||
} else {
|
|
||||||
return []PropertyName{}
|
|
||||||
}
|
|
||||||
return []PropertyName{tag}
|
|
||||||
}
|
|
||||||
|
|
||||||
func viewEventsHtml[T any](view View, events []PropertyName, buffer *strings.Builder) {
|
func viewEventsHtml[T any](view View, events []PropertyName, buffer *strings.Builder) {
|
||||||
for _, tag := range events {
|
for _, tag := range events {
|
||||||
if value := view.getRaw(tag); value != nil {
|
if js, ok := eventJsFunc[tag]; ok {
|
||||||
if js, ok := eventJsFunc[tag]; ok {
|
if value := getOneArgEventListeners[View, T](view, nil, tag); len(value) > 0 {
|
||||||
if listeners, ok := value.([]func(View, T)); ok && len(listeners) > 0 {
|
buffer.WriteString(js.jsEvent)
|
||||||
buffer.WriteString(js.jsEvent)
|
buffer.WriteString(`="`)
|
||||||
buffer.WriteString(`="`)
|
buffer.WriteString(js.jsFunc)
|
||||||
buffer.WriteString(js.jsFunc)
|
buffer.WriteString(`(this, event)" `)
|
||||||
buffer.WriteString(`(this, event)" `)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,3 +66,197 @@ func updateEventListenerHtml(view View, tag PropertyName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type noArgListener[V View] interface {
|
||||||
|
Run(V)
|
||||||
|
rawListener() any
|
||||||
|
}
|
||||||
|
|
||||||
|
type noArgListener0[V View] struct {
|
||||||
|
fn func()
|
||||||
|
}
|
||||||
|
|
||||||
|
type noArgListenerV[V View] struct {
|
||||||
|
fn func(V)
|
||||||
|
}
|
||||||
|
|
||||||
|
type noArgListenerBinding[V View] struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNoArgListener0[V View](fn func()) noArgListener[V] {
|
||||||
|
obj := new(noArgListener0[V])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *noArgListener0[V]) Run(_ V) {
|
||||||
|
data.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *noArgListener0[V]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNoArgListenerV[V View](fn func(V)) noArgListener[V] {
|
||||||
|
obj := new(noArgListenerV[V])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *noArgListenerV[V]) Run(view V) {
|
||||||
|
data.fn(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *noArgListenerV[V]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNoArgListenerBinding[V View](name string) noArgListener[V] {
|
||||||
|
obj := new(noArgListenerBinding[V])
|
||||||
|
obj.name = name
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *noArgListenerBinding[V]) Run(view V) {
|
||||||
|
bind := view.binding()
|
||||||
|
if bind == nil {
|
||||||
|
ErrorLogF(`There is no a binding object for call "%s"`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(bind)
|
||||||
|
method := val.MethodByName(data.name)
|
||||||
|
if !method.IsValid() {
|
||||||
|
ErrorLogF(`The "%s" method is not valid`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
methodType := method.Type()
|
||||||
|
var args []reflect.Value = nil
|
||||||
|
switch methodType.NumIn() {
|
||||||
|
case 0:
|
||||||
|
args = []reflect.Value{}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if equalType(methodType.In(0), reflect.TypeOf(view)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(view)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if args != nil {
|
||||||
|
method.Call(args)
|
||||||
|
} else {
|
||||||
|
ErrorLogF(`Unsupported prototype of "%s" method`, data.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalType(inType reflect.Type, argType reflect.Type) bool {
|
||||||
|
return inType == argType || (inType.Kind() == reflect.Interface && argType.Implements(inType))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *noArgListenerBinding[V]) rawListener() any {
|
||||||
|
return data.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToNoArgEventListeners[V View](value any) ([]noArgListener[V], bool) {
|
||||||
|
if value == nil {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case []noArgListener[V]:
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case noArgListener[V]:
|
||||||
|
return []noArgListener[V]{value}, true
|
||||||
|
|
||||||
|
case string:
|
||||||
|
return []noArgListener[V]{newNoArgListenerBinding[V](value)}, true
|
||||||
|
|
||||||
|
case func(V):
|
||||||
|
return []noArgListener[V]{newNoArgListenerV(value)}, true
|
||||||
|
|
||||||
|
case func():
|
||||||
|
return []noArgListener[V]{newNoArgListener0[V](value)}, true
|
||||||
|
|
||||||
|
case []func(V):
|
||||||
|
result := make([]noArgListener[V], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newNoArgListenerV(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func():
|
||||||
|
result := make([]noArgListener[V], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newNoArgListener0[V](fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
result := make([]noArgListener[V], 0, len(value))
|
||||||
|
for _, v := range value {
|
||||||
|
if v != nil {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case func(V):
|
||||||
|
result = append(result, newNoArgListenerV(v))
|
||||||
|
|
||||||
|
case func():
|
||||||
|
result = append(result, newNoArgListener0[V](v))
|
||||||
|
|
||||||
|
case string:
|
||||||
|
result = append(result, newNoArgListenerBinding[V](v))
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNoArgEventListener[V View](view View, tag PropertyName, value any) []PropertyName {
|
||||||
|
if listeners, ok := valueToNoArgEventListeners[V](value); ok {
|
||||||
|
return setArrayPropertyValue(view, tag, listeners)
|
||||||
|
}
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNoArgEventListeners[V View](view View, subviewID []string, tag PropertyName) []noArgListener[V] {
|
||||||
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
|
if value := view.Get(tag); value != nil {
|
||||||
|
if result, ok := value.([]noArgListener[V]); ok {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []noArgListener[V]{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNoArgEventRawListeners[V View](view View, subviewID []string, tag PropertyName) []any {
|
||||||
|
listeners := getNoArgEventListeners[V](view, subviewID, tag)
|
||||||
|
result := make([]any, len(listeners))
|
||||||
|
for i, l := range listeners {
|
||||||
|
result[i] = l.rawListener()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNoArgBinding[V View](listeners []noArgListener[V]) string {
|
||||||
|
for _, listener := range listeners {
|
||||||
|
raw := listener.rawListener()
|
||||||
|
if text, ok := raw.(string); ok && text != "" {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,271 @@
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type oneArgListener[V View, E any] interface {
|
||||||
|
Run(V, E)
|
||||||
|
rawListener() any
|
||||||
|
}
|
||||||
|
|
||||||
|
type oneArgListener0[V View, E any] struct {
|
||||||
|
fn func()
|
||||||
|
}
|
||||||
|
|
||||||
|
type oneArgListenerV[V View, E any] struct {
|
||||||
|
fn func(V)
|
||||||
|
}
|
||||||
|
|
||||||
|
type oneArgListenerE[V View, E any] struct {
|
||||||
|
fn func(E)
|
||||||
|
}
|
||||||
|
|
||||||
|
type oneArgListenerVE[V View, E any] struct {
|
||||||
|
fn func(V, E)
|
||||||
|
}
|
||||||
|
|
||||||
|
type oneArgListenerBinding[V View, E any] struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOneArgListener0[V View, E any](fn func()) oneArgListener[V, E] {
|
||||||
|
obj := new(oneArgListener0[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListener0[V, E]) Run(_ V, _ E) {
|
||||||
|
data.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListener0[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOneArgListenerV[V View, E any](fn func(V)) oneArgListener[V, E] {
|
||||||
|
obj := new(oneArgListenerV[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListenerV[V, E]) Run(view V, _ E) {
|
||||||
|
data.fn(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListenerV[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOneArgListenerE[V View, E any](fn func(E)) oneArgListener[V, E] {
|
||||||
|
obj := new(oneArgListenerE[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListenerE[V, E]) Run(_ V, event E) {
|
||||||
|
data.fn(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListenerE[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOneArgListenerVE[V View, E any](fn func(V, E)) oneArgListener[V, E] {
|
||||||
|
obj := new(oneArgListenerVE[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListenerVE[V, E]) Run(view V, arg E) {
|
||||||
|
data.fn(view, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListenerVE[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOneArgListenerBinding[V View, E any](name string) oneArgListener[V, E] {
|
||||||
|
obj := new(oneArgListenerBinding[V, E])
|
||||||
|
obj.name = name
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListenerBinding[V, E]) Run(view V, event E) {
|
||||||
|
bind := view.binding()
|
||||||
|
if bind == nil {
|
||||||
|
ErrorLogF(`There is no a binding object for call "%s"`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(bind)
|
||||||
|
method := val.MethodByName(data.name)
|
||||||
|
if !method.IsValid() {
|
||||||
|
ErrorLogF(`The "%s" method is not valid`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
methodType := method.Type()
|
||||||
|
|
||||||
|
var args []reflect.Value = nil
|
||||||
|
switch methodType.NumIn() {
|
||||||
|
case 0:
|
||||||
|
args = []reflect.Value{}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
inType := methodType.In(0)
|
||||||
|
if equalType(inType, reflect.TypeOf(event)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(event)}
|
||||||
|
} else if equalType(inType, reflect.TypeOf(view)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(view)}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if equalType(methodType.In(0), reflect.TypeOf(view)) &&
|
||||||
|
equalType(methodType.In(1), reflect.TypeOf(event)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(event)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if args != nil {
|
||||||
|
method.Call(args)
|
||||||
|
} else {
|
||||||
|
ErrorLogF(`Unsupported prototype of "%s" method`, data.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *oneArgListenerBinding[V, E]) rawListener() any {
|
||||||
|
return data.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToOneArgEventListeners[V View, E any](value any) ([]oneArgListener[V, E], bool) {
|
||||||
|
if value == nil {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case []oneArgListener[V, E]:
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case oneArgListener[V, E]:
|
||||||
|
return []oneArgListener[V, E]{value}, true
|
||||||
|
|
||||||
|
case string:
|
||||||
|
return []oneArgListener[V, E]{newOneArgListenerBinding[V, E](value)}, true
|
||||||
|
|
||||||
|
case func(V, E):
|
||||||
|
return []oneArgListener[V, E]{newOneArgListenerVE(value)}, true
|
||||||
|
|
||||||
|
case func(V):
|
||||||
|
return []oneArgListener[V, E]{newOneArgListenerV[V, E](value)}, true
|
||||||
|
|
||||||
|
case func(E):
|
||||||
|
return []oneArgListener[V, E]{newOneArgListenerE[V](value)}, true
|
||||||
|
|
||||||
|
case func():
|
||||||
|
return []oneArgListener[V, E]{newOneArgListener0[V, E](value)}, true
|
||||||
|
|
||||||
|
case []func(V, E):
|
||||||
|
result := make([]oneArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newOneArgListenerVE(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(E):
|
||||||
|
result := make([]oneArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newOneArgListenerE[V](fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(V):
|
||||||
|
result := make([]oneArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newOneArgListenerV[V, E](fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func():
|
||||||
|
result := make([]oneArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newOneArgListener0[V, E](fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
result := make([]oneArgListener[V, E], 0, len(value))
|
||||||
|
for _, v := range value {
|
||||||
|
if v != nil {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case func(V, E):
|
||||||
|
result = append(result, newOneArgListenerVE(v))
|
||||||
|
|
||||||
|
case func(E):
|
||||||
|
result = append(result, newOneArgListenerE[V](v))
|
||||||
|
|
||||||
|
case func(V):
|
||||||
|
result = append(result, newOneArgListenerV[V, E](v))
|
||||||
|
|
||||||
|
case func():
|
||||||
|
result = append(result, newOneArgListener0[V, E](v))
|
||||||
|
|
||||||
|
case string:
|
||||||
|
result = append(result, newOneArgListenerBinding[V, E](v))
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func setOneArgEventListener[V View, T any](view View, tag PropertyName, value any) []PropertyName {
|
||||||
|
if listeners, ok := valueToOneArgEventListeners[V, T](value); ok {
|
||||||
|
return setArrayPropertyValue(view, tag, listeners)
|
||||||
|
}
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOneArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []oneArgListener[V, E] {
|
||||||
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
|
if value := view.Get(tag); value != nil {
|
||||||
|
if result, ok := value.([]oneArgListener[V, E]); ok {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []oneArgListener[V, E]{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOneArgEventRawListeners[V View, E any](view View, subviewID []string, tag PropertyName) []any {
|
||||||
|
listeners := getOneArgEventListeners[V, E](view, subviewID, tag)
|
||||||
|
result := make([]any, len(listeners))
|
||||||
|
for i, l := range listeners {
|
||||||
|
result[i] = l.rawListener()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOneArgBinding[V View, E any](listeners []oneArgListener[V, E]) string {
|
||||||
|
for _, listener := range listeners {
|
||||||
|
raw := listener.rawListener()
|
||||||
|
if text, ok := raw.(string); ok && text != "" {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
|
@ -0,0 +1,345 @@
|
||||||
|
package rui
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
type twoArgListener[V View, E any] interface {
|
||||||
|
Run(V, E, E)
|
||||||
|
rawListener() any
|
||||||
|
}
|
||||||
|
|
||||||
|
type twoArgListener0[V View, E any] struct {
|
||||||
|
fn func()
|
||||||
|
}
|
||||||
|
|
||||||
|
type twoArgListenerV[V View, E any] struct {
|
||||||
|
fn func(V)
|
||||||
|
}
|
||||||
|
|
||||||
|
type twoArgListenerE[V View, E any] struct {
|
||||||
|
fn func(E)
|
||||||
|
}
|
||||||
|
|
||||||
|
type twoArgListenerVE[V View, E any] struct {
|
||||||
|
fn func(V, E)
|
||||||
|
}
|
||||||
|
|
||||||
|
type twoArgListenerEE[V View, E any] struct {
|
||||||
|
fn func(E, E)
|
||||||
|
}
|
||||||
|
|
||||||
|
type twoArgListenerVEE[V View, E any] struct {
|
||||||
|
fn func(V, E, E)
|
||||||
|
}
|
||||||
|
|
||||||
|
type twoArgListenerBinding[V View, E any] struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTwoArgListener0[V View, E any](fn func()) twoArgListener[V, E] {
|
||||||
|
obj := new(twoArgListener0[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListener0[V, E]) Run(_ V, _ E, _ E) {
|
||||||
|
data.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListener0[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTwoArgListenerV[V View, E any](fn func(V)) twoArgListener[V, E] {
|
||||||
|
obj := new(twoArgListenerV[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerV[V, E]) Run(view V, _ E, _ E) {
|
||||||
|
data.fn(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerV[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTwoArgListenerE[V View, E any](fn func(E)) twoArgListener[V, E] {
|
||||||
|
obj := new(twoArgListenerE[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerE[V, E]) Run(_ V, arg E, _ E) {
|
||||||
|
data.fn(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerE[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTwoArgListenerVE[V View, E any](fn func(V, E)) twoArgListener[V, E] {
|
||||||
|
obj := new(twoArgListenerVE[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerVE[V, E]) Run(view V, arg E, _ E) {
|
||||||
|
data.fn(view, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerVE[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTwoArgListenerEE[V View, E any](fn func(E, E)) twoArgListener[V, E] {
|
||||||
|
obj := new(twoArgListenerEE[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerEE[V, E]) Run(_ V, arg1 E, arg2 E) {
|
||||||
|
data.fn(arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerEE[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTwoArgListenerVEE[V View, E any](fn func(V, E, E)) twoArgListener[V, E] {
|
||||||
|
obj := new(twoArgListenerVEE[V, E])
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerVEE[V, E]) Run(view V, arg1 E, arg2 E) {
|
||||||
|
data.fn(view, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerVEE[V, E]) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTwoArgListenerBinding[V View, E any](name string) twoArgListener[V, E] {
|
||||||
|
obj := new(twoArgListenerBinding[V, E])
|
||||||
|
obj.name = name
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerBinding[V, E]) Run(view V, arg1 E, arg2 E) {
|
||||||
|
bind := view.binding()
|
||||||
|
if bind == nil {
|
||||||
|
ErrorLogF(`There is no a binding object for call "%s"`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(bind)
|
||||||
|
method := val.MethodByName(data.name)
|
||||||
|
if !method.IsValid() {
|
||||||
|
ErrorLogF(`The "%s" method is not valid`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
methodType := method.Type()
|
||||||
|
|
||||||
|
var args []reflect.Value = nil
|
||||||
|
switch methodType.NumIn() {
|
||||||
|
case 0:
|
||||||
|
args = []reflect.Value{}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
inType := methodType.In(0)
|
||||||
|
if equalType(inType, reflect.TypeOf(arg1)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(arg1)}
|
||||||
|
} else if equalType(inType, reflect.TypeOf(view)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(view)}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
inType0 := methodType.In(0)
|
||||||
|
inType1 := methodType.In(1)
|
||||||
|
if equalType(inType0, reflect.TypeOf(view)) && equalType(inType1, reflect.TypeOf(arg1)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(arg1)}
|
||||||
|
} else if equalType(inType0, reflect.TypeOf(arg1)) && equalType(inType1, reflect.TypeOf(arg2)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(arg1), reflect.ValueOf(arg2)}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
if equalType(methodType.In(0), reflect.TypeOf(view)) &&
|
||||||
|
equalType(methodType.In(1), reflect.TypeOf(arg1)) &&
|
||||||
|
equalType(methodType.In(2), reflect.TypeOf(arg2)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(view), reflect.ValueOf(arg1), reflect.ValueOf(arg2)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if args != nil {
|
||||||
|
method.Call(args)
|
||||||
|
} else {
|
||||||
|
ErrorLogF(`Unsupported prototype of "%s" method`, data.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *twoArgListenerBinding[V, E]) rawListener() any {
|
||||||
|
return data.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToTwoArgEventListeners[V View, E any](value any) ([]twoArgListener[V, E], bool) {
|
||||||
|
if value == nil {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case []twoArgListener[V, E]:
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case twoArgListener[V, E]:
|
||||||
|
return []twoArgListener[V, E]{value}, true
|
||||||
|
|
||||||
|
case string:
|
||||||
|
return []twoArgListener[V, E]{newTwoArgListenerBinding[V, E](value)}, true
|
||||||
|
|
||||||
|
case func(V, E):
|
||||||
|
return []twoArgListener[V, E]{newTwoArgListenerVE(value)}, true
|
||||||
|
|
||||||
|
case func(V):
|
||||||
|
return []twoArgListener[V, E]{newTwoArgListenerV[V, E](value)}, true
|
||||||
|
|
||||||
|
case func(E):
|
||||||
|
return []twoArgListener[V, E]{newTwoArgListenerE[V](value)}, true
|
||||||
|
|
||||||
|
case func():
|
||||||
|
return []twoArgListener[V, E]{newTwoArgListener0[V, E](value)}, true
|
||||||
|
|
||||||
|
case func(E, E):
|
||||||
|
return []twoArgListener[V, E]{newTwoArgListenerEE[V](value)}, true
|
||||||
|
|
||||||
|
case func(V, E, E):
|
||||||
|
return []twoArgListener[V, E]{newTwoArgListenerVEE(value)}, true
|
||||||
|
|
||||||
|
case []func(V, E):
|
||||||
|
result := make([]twoArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newTwoArgListenerVE(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(E):
|
||||||
|
result := make([]twoArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newTwoArgListenerE[V](fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(V):
|
||||||
|
result := make([]twoArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newTwoArgListenerV[V, E](fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func():
|
||||||
|
result := make([]twoArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newTwoArgListener0[V, E](fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(E, E):
|
||||||
|
result := make([]twoArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newTwoArgListenerEE[V](fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(V, E, E):
|
||||||
|
result := make([]twoArgListener[V, E], 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newTwoArgListenerVEE(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
result := make([]twoArgListener[V, E], 0, len(value))
|
||||||
|
for _, v := range value {
|
||||||
|
if v != nil {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case func(V, E):
|
||||||
|
result = append(result, newTwoArgListenerVE(v))
|
||||||
|
|
||||||
|
case func(E):
|
||||||
|
result = append(result, newTwoArgListenerE[V](v))
|
||||||
|
|
||||||
|
case func(V):
|
||||||
|
result = append(result, newTwoArgListenerV[V, E](v))
|
||||||
|
|
||||||
|
case func():
|
||||||
|
result = append(result, newTwoArgListener0[V, E](v))
|
||||||
|
|
||||||
|
case func(E, E):
|
||||||
|
result = append(result, newTwoArgListenerEE[V](v))
|
||||||
|
|
||||||
|
case func(V, E, E):
|
||||||
|
result = append(result, newTwoArgListenerVEE(v))
|
||||||
|
|
||||||
|
case string:
|
||||||
|
result = append(result, newTwoArgListenerBinding[V, E](v))
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTwoArgEventListener[V View, T any](view View, tag PropertyName, value any) []PropertyName {
|
||||||
|
if listeners, ok := valueToTwoArgEventListeners[V, T](value); ok {
|
||||||
|
return setArrayPropertyValue(view, tag, listeners)
|
||||||
|
}
|
||||||
|
notCompatibleType(tag, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTwoArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []twoArgListener[V, E] {
|
||||||
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
|
if value := view.Get(tag); value != nil {
|
||||||
|
if result, ok := value.([]twoArgListener[V, E]); ok {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []twoArgListener[V, E]{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTwoArgEventRawListeners[V View, E any](view View, subviewID []string, tag PropertyName) []any {
|
||||||
|
listeners := getTwoArgEventListeners[V, E](view, subviewID, tag)
|
||||||
|
result := make([]any, len(listeners))
|
||||||
|
for i, l := range listeners {
|
||||||
|
result[i] = l.rawListener()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTwoArgBinding[V View, E any](listeners []twoArgListener[V, E]) string {
|
||||||
|
for _, listener := range listeners {
|
||||||
|
raw := listener.rawListener()
|
||||||
|
if text, ok := raw.(string); ok && text != "" {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
|
@ -147,7 +147,7 @@ func (picker *filePickerData) Files() []FileInfo {
|
||||||
func (picker *filePickerData) LoadFile(file FileInfo, result func(FileInfo, []byte)) {
|
func (picker *filePickerData) LoadFile(file FileInfo, result func(FileInfo, []byte)) {
|
||||||
if result != nil {
|
if result != nil {
|
||||||
for i, info := range picker.files {
|
for i, info := range picker.files {
|
||||||
if info.Name == file.Name && info.Size == file.Size && info.LastModified == file.LastModified {
|
if info.Name == file.Name && info.Size == file.Size && info.LastModified.Equal(file.LastModified) {
|
||||||
if info.data != nil {
|
if info.data != nil {
|
||||||
result(info, info.data)
|
result(info, info.data)
|
||||||
} else {
|
} else {
|
||||||
|
@ -282,8 +282,8 @@ func (picker *filePickerData) handleCommand(self View, command PropertyName, dat
|
||||||
case "fileSelected":
|
case "fileSelected":
|
||||||
if files := parseFilesTag(data); files != nil {
|
if files := parseFilesTag(data); files != nil {
|
||||||
picker.files = files
|
picker.files = files
|
||||||
for _, listener := range GetFileSelectedListeners(picker) {
|
for _, listener := range getOneArgEventListeners[FilePicker, []FileInfo](picker, nil, FileSelectedEvent) {
|
||||||
listener(picker, files)
|
listener.Run(picker, files)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -317,13 +317,17 @@ func LoadFilePickerFile(view View, subviewID string, file FileInfo, result func(
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsMultipleFilePicker returns "true" if multiple files can be selected in the FilePicker, "false" otherwise.
|
// IsMultipleFilePicker returns "true" if multiple files can be selected in the FilePicker, "false" otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsMultipleFilePicker(view View, subviewID ...string) bool {
|
func IsMultipleFilePicker(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, Multiple, false)
|
return boolStyledProperty(view, subviewID, Multiple, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFilePickerAccept returns sets the list of allowed file extensions or MIME types.
|
// GetFilePickerAccept returns sets the list of allowed file extensions or MIME types.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetFilePickerAccept(view View, subviewID ...string) []string {
|
func GetFilePickerAccept(view View, subviewID ...string) []string {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
accept, ok := stringProperty(view, Accept, view.Session())
|
accept, ok := stringProperty(view, Accept, view.Session())
|
||||||
|
@ -345,7 +349,16 @@ func GetFilePickerAccept(view View, subviewID ...string) []string {
|
||||||
|
|
||||||
// GetFileSelectedListeners returns the "file-selected-event" listener list.
|
// GetFileSelectedListeners returns the "file-selected-event" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetFileSelectedListeners(view View, subviewID ...string) []func(FilePicker, []FileInfo) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent)
|
// - func(rui.View, []rui.FileInfo),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func([]rui.FileInfo),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetFileSelectedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,13 +49,27 @@ func focusEventsHtml(view View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFocusListeners returns a FocusListener list. If there are no listeners then the empty list is returned
|
// GetFocusListeners returns a FocusListener list. If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetFocusListeners(view View, subviewID ...string) []func(View) {
|
// Result elements can be of the following types:
|
||||||
return getNoArgEventListeners[View](view, subviewID, FocusEvent)
|
// - func(rui.View),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetFocusListeners(view View, subviewID ...string) []any {
|
||||||
|
return getNoArgEventRawListeners[View](view, subviewID, FocusEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLostFocusListeners returns a LostFocusListener list. If there are no listeners then the empty list is returned
|
// GetLostFocusListeners returns a LostFocusListener list. If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetLostFocusListeners(view View, subviewID ...string) []func(View) {
|
// Result elements can be of the following types:
|
||||||
return getNoArgEventListeners[View](view, subviewID, LostFocusEvent)
|
// - func(rui.View),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetLostFocusListeners(view View, subviewID ...string) []any {
|
||||||
|
return getNoArgEventRawListeners[View](view, subviewID, LostFocusEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -458,10 +458,7 @@ func (gridLayout *gridLayoutData) UpdateGridContent() {
|
||||||
if gridLayout.created {
|
if gridLayout.created {
|
||||||
updateInnerHTML(gridLayout.htmlID(), gridLayout.session)
|
updateInnerHTML(gridLayout.htmlID(), gridLayout.session)
|
||||||
}
|
}
|
||||||
|
gridLayout.contentChanged()
|
||||||
if listener, ok := gridLayout.changeListener[Content]; ok {
|
|
||||||
listener(gridLayout, Content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,26 +503,34 @@ func gridCellSizes(properties Properties, tag PropertyName, session Session) []S
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCellVerticalAlign returns the vertical align of a GridLayout cell content: TopAlign (0), BottomAlign (1), CenterAlign (2), StretchAlign (3)
|
// GetCellVerticalAlign returns the vertical align of a GridLayout cell content: TopAlign (0), BottomAlign (1), CenterAlign (2), StretchAlign (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetCellVerticalAlign(view View, subviewID ...string) int {
|
func GetCellVerticalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, CellVerticalAlign, StretchAlign, false)
|
return enumStyledProperty(view, subviewID, CellVerticalAlign, StretchAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCellHorizontalAlign returns the vertical align of a GridLayout cell content: LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
// GetCellHorizontalAlign returns the vertical align of a GridLayout cell content: LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetCellHorizontalAlign(view View, subviewID ...string) int {
|
func GetCellHorizontalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, CellHorizontalAlign, StretchAlign, false)
|
return enumStyledProperty(view, subviewID, CellHorizontalAlign, StretchAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGridAutoFlow returns the value of the "grid-auto-flow" property
|
// GetGridAutoFlow returns the value of the "grid-auto-flow" property
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetGridAutoFlow(view View, subviewID ...string) int {
|
func GetGridAutoFlow(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, GridAutoFlow, 0, false)
|
return enumStyledProperty(view, subviewID, GridAutoFlow, 0, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCellWidth returns the width of a GridLayout cell. If the result is an empty array, then the width is not set.
|
// GetCellWidth returns the width of a GridLayout cell. If the result is an empty array, then the width is not set.
|
||||||
// If the result is a single value array, then the width of all cell is equal.
|
// If the result is a single value array, then the width of all cell is equal.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetCellWidth(view View, subviewID ...string) []SizeUnit {
|
func GetCellWidth(view View, subviewID ...string) []SizeUnit {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
return gridCellSizes(view, CellWidth, view.Session())
|
return gridCellSizes(view, CellWidth, view.Session())
|
||||||
|
@ -535,7 +540,9 @@ func GetCellWidth(view View, subviewID ...string) []SizeUnit {
|
||||||
|
|
||||||
// GetCellHeight returns the height of a GridLayout cell. If the result is an empty array, then the height is not set.
|
// GetCellHeight returns the height of a GridLayout cell. If the result is an empty array, then the height is not set.
|
||||||
// If the result is a single value array, then the height of all cell is equal.
|
// If the result is a single value array, then the height of all cell is equal.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetCellHeight(view View, subviewID ...string) []SizeUnit {
|
func GetCellHeight(view View, subviewID ...string) []SizeUnit {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
return gridCellSizes(view, CellHeight, view.Session())
|
return gridCellSizes(view, CellHeight, view.Session())
|
||||||
|
@ -544,13 +551,17 @@ func GetCellHeight(view View, subviewID ...string) []SizeUnit {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGridRowGap returns the gap between GridLayout rows.
|
// GetGridRowGap returns the gap between GridLayout rows.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetGridRowGap(view View, subviewID ...string) SizeUnit {
|
func GetGridRowGap(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, GridRowGap, false)
|
return sizeStyledProperty(view, subviewID, GridRowGap, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGridColumnGap returns the gap between GridLayout columns.
|
// GetGridColumnGap returns the gap between GridLayout columns.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetGridColumnGap(view View, subviewID ...string) SizeUnit {
|
func GetGridColumnGap(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, GridColumnGap, false)
|
return sizeStyledProperty(view, subviewID, GridColumnGap, false)
|
||||||
}
|
}
|
||||||
|
|
24
image.go
24
image.go
|
@ -4,34 +4,44 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ImageLoadingStatus defines type of status of the image loading
|
||||||
|
type ImageLoadingStatus int
|
||||||
|
|
||||||
// Constants which represent return values of the LoadingStatus function of an [Image] view
|
// Constants which represent return values of the LoadingStatus function of an [Image] view
|
||||||
const (
|
const (
|
||||||
// ImageLoading is the image loading status: in the process of loading
|
// ImageLoading is the image loading status: in the process of loading
|
||||||
ImageLoading = 0
|
ImageLoading ImageLoadingStatus = 0
|
||||||
// ImageReady is the image loading status: the image is loaded successfully
|
// ImageReady is the image loading status: the image is loaded successfully
|
||||||
ImageReady = 1
|
ImageReady ImageLoadingStatus = 1
|
||||||
// ImageLoadingError is the image loading status: an error occurred while loading
|
// ImageLoadingError is the image loading status: an error occurred while loading
|
||||||
ImageLoadingError = 2
|
ImageLoadingError ImageLoadingStatus = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// Image defines the image that is used for drawing operations on the Canvas.
|
// Image defines the image that is used for drawing operations on the Canvas.
|
||||||
type Image interface {
|
type Image interface {
|
||||||
// URL returns the url of the image
|
// URL returns the url of the image
|
||||||
URL() string
|
URL() string
|
||||||
// LoadingStatus returns the status of the image loading: ImageLoading (0), ImageReady (1), ImageLoadingError (2)
|
|
||||||
LoadingStatus() int
|
// LoadingStatus returns the status of the image loading:
|
||||||
|
// - ImageLoading (0) - in the process of loading;
|
||||||
|
// - ImageReady (1) - the image is loaded successfully;
|
||||||
|
// - ImageLoadingError (2) - an error occurred while loading.
|
||||||
|
LoadingStatus() ImageLoadingStatus
|
||||||
|
|
||||||
// LoadingError: if LoadingStatus() == ImageLoadingError then returns the error text, "" otherwise
|
// LoadingError: if LoadingStatus() == ImageLoadingError then returns the error text, "" otherwise
|
||||||
LoadingError() string
|
LoadingError() string
|
||||||
setLoadingError(err string)
|
setLoadingError(err string)
|
||||||
|
|
||||||
// Width returns the width of the image in pixels. While LoadingStatus() != ImageReady returns 0
|
// Width returns the width of the image in pixels. While LoadingStatus() != ImageReady returns 0
|
||||||
Width() float64
|
Width() float64
|
||||||
|
|
||||||
// Height returns the height of the image in pixels. While LoadingStatus() != ImageReady returns 0
|
// Height returns the height of the image in pixels. While LoadingStatus() != ImageReady returns 0
|
||||||
Height() float64
|
Height() float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type imageData struct {
|
type imageData struct {
|
||||||
url string
|
url string
|
||||||
loadingStatus int
|
loadingStatus ImageLoadingStatus
|
||||||
loadingError string
|
loadingError string
|
||||||
width, height float64
|
width, height float64
|
||||||
listener func(Image)
|
listener func(Image)
|
||||||
|
@ -45,7 +55,7 @@ func (image *imageData) URL() string {
|
||||||
return image.url
|
return image.url
|
||||||
}
|
}
|
||||||
|
|
||||||
func (image *imageData) LoadingStatus() int {
|
func (image *imageData) LoadingStatus() ImageLoadingStatus {
|
||||||
return image.loadingStatus
|
return image.loadingStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
imageView.go
34
imageView.go
|
@ -205,7 +205,7 @@ func imageViewSrcSet(view View, path string) string {
|
||||||
buffer.WriteString(", ")
|
buffer.WriteString(", ")
|
||||||
}
|
}
|
||||||
buffer.WriteString(src.path)
|
buffer.WriteString(src.path)
|
||||||
buffer.WriteString(fmt.Sprintf(" %gx", src.scale))
|
fmt.Fprintf(buffer, " %gx", src.scale)
|
||||||
}
|
}
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ func (imageView *imageViewData) handleCommand(self View, command PropertyName, d
|
||||||
switch command {
|
switch command {
|
||||||
case "imageViewError":
|
case "imageViewError":
|
||||||
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, ErrorEvent) {
|
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, ErrorEvent) {
|
||||||
listener(imageView)
|
listener.Run(imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "imageViewLoaded":
|
case "imageViewLoaded":
|
||||||
|
@ -309,7 +309,7 @@ func (imageView *imageViewData) handleCommand(self View, command PropertyName, d
|
||||||
imageView.currentSrc, _ = data.PropertyValue("current-src")
|
imageView.currentSrc, _ = data.PropertyValue("current-src")
|
||||||
|
|
||||||
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, LoadedEvent) {
|
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, LoadedEvent) {
|
||||||
listener(imageView)
|
listener.Run(imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -370,3 +370,31 @@ func GetImageViewVerticalAlign(view View, subviewID ...string) int {
|
||||||
func GetImageViewHorizontalAlign(view View, subviewID ...string) int {
|
func GetImageViewHorizontalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, ImageHorizontalAlign, LeftAlign, false)
|
return enumStyledProperty(view, subviewID, ImageHorizontalAlign, LeftAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetImageViewErrorEventListeners returns the list of "error-event" event listeners.
|
||||||
|
// If there are no listeners then the empty list is returned
|
||||||
|
//
|
||||||
|
// Result elements can be of the following types:
|
||||||
|
// - func(rui.ImageView)
|
||||||
|
// - func()
|
||||||
|
// - string
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetImageViewErrorEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getNoArgEventRawListeners[View](view, subviewID, ErrorEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetImageViewLoadedEventListeners returns the list of "loaded-event" event listeners.
|
||||||
|
// If there are no listeners then the empty list is returned
|
||||||
|
//
|
||||||
|
// Result elements can be of the following types:
|
||||||
|
// - func(rui.ImageView)
|
||||||
|
// - func()
|
||||||
|
// - string
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetImageViewLoadedEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getNoArgEventRawListeners[View](view, subviewID, LoadedEvent)
|
||||||
|
}
|
||||||
|
|
44
keyEvents.go
44
keyEvents.go
|
@ -434,15 +434,13 @@ func (event *KeyEvent) init(data DataObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func keyEventsHtml(view View, buffer *strings.Builder) {
|
func keyEventsHtml(view View, buffer *strings.Builder) {
|
||||||
if len(getOneArgEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 {
|
if len(getOneArgEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 ||
|
||||||
|
(view.Focusable() && len(getOneArgEventListeners[View, MouseEvent](view, nil, ClickEvent)) > 0) {
|
||||||
|
|
||||||
buffer.WriteString(`onkeydown="keyDownEvent(this, event)" `)
|
buffer.WriteString(`onkeydown="keyDownEvent(this, event)" `)
|
||||||
} else if view.Focusable() {
|
|
||||||
if len(getOneArgEventListeners[View, MouseEvent](view, nil, ClickEvent)) > 0 {
|
|
||||||
buffer.WriteString(`onkeydown="keyDownEvent(this, event)" `)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if listeners := getOneArgEventListeners[View, KeyEvent](view, nil, KeyUpEvent); len(listeners) > 0 {
|
if len(getOneArgEventListeners[View, KeyEvent](view, nil, KeyUpEvent)) > 0 {
|
||||||
buffer.WriteString(`onkeyup="keyUpEvent(this, event)" `)
|
buffer.WriteString(`onkeyup="keyUpEvent(this, event)" `)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,7 +452,7 @@ func handleKeyEvents(view View, tag PropertyName, data DataObject) {
|
||||||
|
|
||||||
if len(listeners) > 0 {
|
if len(listeners) > 0 {
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(view, event)
|
listener.Run(view, event)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -477,20 +475,38 @@ func handleKeyEvents(view View, tag PropertyName, data DataObject) {
|
||||||
ScreenY: view.Frame().Top + view.Frame().Height/2,
|
ScreenY: view.Frame().Top + view.Frame().Height/2,
|
||||||
}
|
}
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(view, clickEvent)
|
listener.Run(view, clickEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKeyDownListeners returns the "key-down-event" listener list. If there are no listeners then the empty list is returned.
|
// GetKeyDownListeners returns the "key-down-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetKeyDownListeners(view View, subviewID ...string) []func(View, KeyEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, KeyEvent](view, subviewID, KeyDownEvent)
|
// - func(rui.View, rui.KeyEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.KeyEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetKeyDownListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, KeyEvent](view, subviewID, KeyDownEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKeyUpListeners returns the "key-up-event" listener list. If there are no listeners then the empty list is returned.
|
// GetKeyUpListeners returns the "key-up-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetKeyUpListeners(view View, subviewID ...string) []func(View, KeyEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent)
|
// - func(rui.View, rui.KeyEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.KeyEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetKeyUpListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, KeyEvent](view, subviewID, KeyUpEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,30 +196,33 @@ func (listLayout *listLayoutData) UpdateContent() {
|
||||||
if listLayout.created {
|
if listLayout.created {
|
||||||
updateInnerHTML(listLayout.htmlID(), listLayout.session)
|
updateInnerHTML(listLayout.htmlID(), listLayout.session)
|
||||||
}
|
}
|
||||||
|
listLayout.contentChanged()
|
||||||
if listener, ok := listLayout.changeListener[Content]; ok {
|
|
||||||
listener(listLayout, Content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListVerticalAlign returns the vertical align of a ListLayout or ListView sibview:
|
// GetListVerticalAlign returns the vertical align of a ListLayout or ListView subview:
|
||||||
// TopAlign (0), BottomAlign (1), CenterAlign (2), or StretchAlign (3)
|
// TopAlign (0), BottomAlign (1), CenterAlign (2), or StretchAlign (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListVerticalAlign(view View, subviewID ...string) int {
|
func GetListVerticalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, VerticalAlign, TopAlign, false)
|
return enumStyledProperty(view, subviewID, VerticalAlign, TopAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListHorizontalAlign returns the vertical align of a ListLayout or ListView subview:
|
// GetListHorizontalAlign returns the vertical align of a ListLayout or ListView subview:
|
||||||
// LeftAlign (0), RightAlign (1), CenterAlign (2), or StretchAlign (3)
|
// LeftAlign (0), RightAlign (1), CenterAlign (2), or StretchAlign (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListHorizontalAlign(view View, subviewID ...string) int {
|
func GetListHorizontalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, HorizontalAlign, LeftAlign, false)
|
return enumStyledProperty(view, subviewID, HorizontalAlign, LeftAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListOrientation returns the orientation of a ListLayout or ListView subview:
|
// GetListOrientation returns the orientation of a ListLayout or ListView subview:
|
||||||
// TopDownOrientation (0), StartToEndOrientation (1), BottomUpOrientation (2), or EndToStartOrientation (3)
|
// TopDownOrientation (0), StartToEndOrientation (1), BottomUpOrientation (2), or EndToStartOrientation (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListOrientation(view View, subviewID ...string) int {
|
func GetListOrientation(view View, subviewID ...string) int {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if orientation, ok := valueToOrientation(view.Get(Orientation), view.Session()); ok {
|
if orientation, ok := valueToOrientation(view.Get(Orientation), view.Session()); ok {
|
||||||
|
@ -238,19 +241,25 @@ func GetListOrientation(view View, subviewID ...string) int {
|
||||||
|
|
||||||
// GetListWrap returns the wrap type of a ListLayout or ListView subview:
|
// GetListWrap returns the wrap type of a ListLayout or ListView subview:
|
||||||
// ListWrapOff (0), ListWrapOn (1), or ListWrapReverse (2)
|
// ListWrapOff (0), ListWrapOn (1), or ListWrapReverse (2)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListWrap(view View, subviewID ...string) int {
|
func GetListWrap(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, ListWrap, ListWrapOff, false)
|
return enumStyledProperty(view, subviewID, ListWrap, ListWrapOff, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListRowGap returns the gap between ListLayout or ListView rows.
|
// GetListRowGap returns the gap between ListLayout or ListView rows.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListRowGap(view View, subviewID ...string) SizeUnit {
|
func GetListRowGap(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, ListRowGap, false)
|
return sizeStyledProperty(view, subviewID, ListRowGap, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListColumnGap returns the gap between ListLayout or ListView columns.
|
// GetListColumnGap returns the gap between ListLayout or ListView columns.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListColumnGap(view View, subviewID ...string) SizeUnit {
|
func GetListColumnGap(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, ListColumnGap, false)
|
return sizeStyledProperty(view, subviewID, ListColumnGap, false)
|
||||||
}
|
}
|
||||||
|
|
121
listView.go
121
listView.go
|
@ -122,19 +122,13 @@ type ListView interface {
|
||||||
// ReloadListViewData updates ListView content
|
// ReloadListViewData updates ListView content
|
||||||
ReloadListViewData()
|
ReloadListViewData()
|
||||||
|
|
||||||
//getCheckedItems() []int
|
|
||||||
getItemFrames() []Frame
|
getItemFrames() []Frame
|
||||||
}
|
}
|
||||||
|
|
||||||
type listViewData struct {
|
type listViewData struct {
|
||||||
viewData
|
viewData
|
||||||
//adapter ListAdapter
|
|
||||||
//clickedListeners []func(ListView, int)
|
|
||||||
//selectedListeners []func(ListView, int)
|
|
||||||
//checkedListeners []func(ListView, []int)
|
|
||||||
items []View
|
items []View
|
||||||
itemFrame []Frame
|
itemFrame []Frame
|
||||||
//checkedItem []int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewListView creates the new list view
|
// NewListView creates the new list view
|
||||||
|
@ -279,7 +273,7 @@ func (listView *listViewData) propertyChanged(tag PropertyName) {
|
||||||
if listeners := getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent); len(listeners) > 0 {
|
if listeners := getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent); len(listeners) > 0 {
|
||||||
current := GetCurrent(listView)
|
current := GetCurrent(listView)
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(listView, current)
|
listener.Run(listView, current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +282,7 @@ func (listView *listViewData) propertyChanged(tag PropertyName) {
|
||||||
if listeners := getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent); len(listeners) > 0 {
|
if listeners := getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent); len(listeners) > 0 {
|
||||||
checked := GetListViewCheckedItems(listView)
|
checked := GetListViewCheckedItems(listView)
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(listView, checked)
|
listener.Run(listView, checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +336,7 @@ func (listView *listViewData) setItems(value any) []PropertyName {
|
||||||
items := make([]View, len(value))
|
items := make([]View, len(value))
|
||||||
for i, val := range value {
|
for i, val := range value {
|
||||||
if val.IsObject() {
|
if val.IsObject() {
|
||||||
if view := CreateViewFromObject(session, val.Object()); view != nil {
|
if view := CreateViewFromObject(session, val.Object(), nil); view != nil {
|
||||||
items[i] = view
|
items[i] = view
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -540,7 +534,7 @@ func (listView *listViewData) getDivs(checkbox, hCheckboxAlign, vCheckboxAlign i
|
||||||
return onDivBuilder.String(), offDivBuilder.String(), contentBuilder.String()
|
return onDivBuilder.String(), offDivBuilder.String(), contentBuilder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (listView *listViewData) checkboxItemDiv(checkbox, hCheckboxAlign, vCheckboxAlign int) string {
|
func (listView *listViewData) checkboxItemDiv(hCheckboxAlign, vCheckboxAlign int) string {
|
||||||
itemStyleBuilder := allocStringBuilder()
|
itemStyleBuilder := allocStringBuilder()
|
||||||
defer freeStringBuilder(itemStyleBuilder)
|
defer freeStringBuilder(itemStyleBuilder)
|
||||||
|
|
||||||
|
@ -627,7 +621,7 @@ func (listView *listViewData) checkboxSubviews(adapter ListAdapter, buffer *stri
|
||||||
hCheckboxAlign := GetListViewCheckboxHorizontalAlign(listView)
|
hCheckboxAlign := GetListViewCheckboxHorizontalAlign(listView)
|
||||||
vCheckboxAlign := GetListViewCheckboxVerticalAlign(listView)
|
vCheckboxAlign := GetListViewCheckboxVerticalAlign(listView)
|
||||||
|
|
||||||
itemDiv := listView.checkboxItemDiv(checkbox, hCheckboxAlign, vCheckboxAlign)
|
itemDiv := listView.checkboxItemDiv(hCheckboxAlign, vCheckboxAlign)
|
||||||
onDiv, offDiv, contentDiv := listView.getDivs(checkbox, hCheckboxAlign, vCheckboxAlign)
|
onDiv, offDiv, contentDiv := listView.getDivs(checkbox, hCheckboxAlign, vCheckboxAlign)
|
||||||
|
|
||||||
current := GetCurrent(listView)
|
current := GetCurrent(listView)
|
||||||
|
@ -734,7 +728,7 @@ func (listView *listViewData) updateCheckboxItem(index int, checked bool) {
|
||||||
buffer := allocStringBuilder()
|
buffer := allocStringBuilder()
|
||||||
defer freeStringBuilder(buffer)
|
defer freeStringBuilder(buffer)
|
||||||
|
|
||||||
buffer.WriteString(listView.checkboxItemDiv(checkbox, hCheckboxAlign, vCheckboxAlign))
|
buffer.WriteString(listView.checkboxItemDiv(hCheckboxAlign, vCheckboxAlign))
|
||||||
if checked {
|
if checked {
|
||||||
buffer.WriteString(onDiv)
|
buffer.WriteString(onDiv)
|
||||||
} else {
|
} else {
|
||||||
|
@ -966,10 +960,10 @@ func (listView *listViewData) handleCommand(self View, command PropertyName, dat
|
||||||
func (listView *listViewData) handleCurrent(number int) {
|
func (listView *listViewData) handleCurrent(number int) {
|
||||||
listView.properties[Current] = number
|
listView.properties[Current] = number
|
||||||
for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) {
|
for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) {
|
||||||
listener(listView, number)
|
listener.Run(listView, number)
|
||||||
}
|
}
|
||||||
if listener, ok := listView.changeListener[Current]; ok {
|
if listener, ok := listView.changeListener[Current]; ok {
|
||||||
listener(listView, Current)
|
listener.Run(listView, Current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1028,16 +1022,16 @@ func (listView *listViewData) onItemClick(number int) {
|
||||||
|
|
||||||
setArrayPropertyValue(listView, Checked, checkedItem)
|
setArrayPropertyValue(listView, Checked, checkedItem)
|
||||||
if listener, ok := listView.changeListener[Checked]; ok {
|
if listener, ok := listView.changeListener[Checked]; ok {
|
||||||
listener(listView, Checked)
|
listener.Run(listView, Checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, listener := range getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) {
|
for _, listener := range getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) {
|
||||||
listener(listView, checkedItem)
|
listener.Run(listView, checkedItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemClickedEvent) {
|
for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemClickedEvent) {
|
||||||
listener(listView, number)
|
listener.Run(listView, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1054,58 +1048,97 @@ func (listView *listViewData) onItemResize(self View, index string, x, y, width,
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVerticalAlign return the vertical align of a list: TopAlign (0), BottomAlign (1), CenterAlign (2), StretchAlign (3)
|
// GetVerticalAlign return the vertical align of a list: TopAlign (0), BottomAlign (1), CenterAlign (2), StretchAlign (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetVerticalAlign(view View, subviewID ...string) int {
|
func GetVerticalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, VerticalAlign, TopAlign, false)
|
return enumStyledProperty(view, subviewID, VerticalAlign, TopAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHorizontalAlign return the vertical align of a list/checkbox: LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
// GetHorizontalAlign return the vertical align of a list/checkbox: LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetHorizontalAlign(view View, subviewID ...string) int {
|
func GetHorizontalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, HorizontalAlign, LeftAlign, false)
|
return enumStyledProperty(view, subviewID, HorizontalAlign, LeftAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListItemClickedListeners returns a ListItemClickedListener of the ListView.
|
// GetListItemClickedListeners returns a ListItemClickedListener of the ListView.
|
||||||
// If there are no listeners then the empty list is returned
|
// If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetListItemClickedListeners(view View, subviewID ...string) []func(ListView, int) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[ListView, int](view, subviewID, ListItemClickedEvent)
|
// - func(rui.ListView, int),
|
||||||
|
// - func(rui.ListView),
|
||||||
|
// - func(int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetListItemClickedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[ListView, int](view, subviewID, ListItemClickedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListItemSelectedListeners returns a ListItemSelectedListener of the ListView.
|
// GetListItemSelectedListeners returns a ListItemSelectedListener of the ListView.
|
||||||
// If there are no listeners then the empty list is returned
|
// If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetListItemSelectedListeners(view View, subviewID ...string) []func(ListView, int) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[ListView, int](view, subviewID, ListItemSelectedEvent)
|
// - func(rui.ListView, int),
|
||||||
|
// - func(rui.ListView),
|
||||||
|
// - func(int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetListItemSelectedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[ListView, int](view, subviewID, ListItemSelectedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListItemCheckedListeners returns a ListItemCheckedListener of the ListView.
|
// GetListItemCheckedListeners returns a ListItemCheckedListener of the ListView.
|
||||||
// If there are no listeners then the empty list is returned
|
// If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetListItemCheckedListeners(view View, subviewID ...string) []func(ListView, []int) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[ListView, []int](view, subviewID, ListItemCheckedEvent)
|
// - func(rui.ListView, []int),
|
||||||
|
// - func(rui.ListView),
|
||||||
|
// - func([]int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetListItemCheckedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[ListView, []int](view, subviewID, ListItemCheckedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListItemWidth returns the width of a ListView item.
|
// GetListItemWidth returns the width of a ListView item.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListItemWidth(view View, subviewID ...string) SizeUnit {
|
func GetListItemWidth(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, ItemWidth, false)
|
return sizeStyledProperty(view, subviewID, ItemWidth, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListItemHeight returns the height of a ListView item.
|
// GetListItemHeight returns the height of a ListView item.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListItemHeight(view View, subviewID ...string) SizeUnit {
|
func GetListItemHeight(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, ItemHeight, false)
|
return sizeStyledProperty(view, subviewID, ItemHeight, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListViewCheckbox returns the ListView checkbox type: NoneCheckbox (0), SingleCheckbox (1), or MultipleCheckbox (2).
|
// GetListViewCheckbox returns the ListView checkbox type: NoneCheckbox (0), SingleCheckbox (1), or MultipleCheckbox (2).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListViewCheckbox(view View, subviewID ...string) int {
|
func GetListViewCheckbox(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, ItemCheckbox, 0, false)
|
return enumStyledProperty(view, subviewID, ItemCheckbox, 0, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListViewCheckedItems returns the array of ListView checked items.
|
// GetListViewCheckedItems returns the array of ListView checked items.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListViewCheckedItems(view View, subviewID ...string) []int {
|
func GetListViewCheckedItems(view View, subviewID ...string) []int {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if value := view.getRaw(Checked); value != nil {
|
if value := view.getRaw(Checked); value != nil {
|
||||||
|
@ -1138,34 +1171,44 @@ func IsListViewCheckedItem(view View, subviewID string, index int) bool {
|
||||||
|
|
||||||
// GetListViewCheckboxVerticalAlign returns the vertical align of the ListView checkbox:
|
// GetListViewCheckboxVerticalAlign returns the vertical align of the ListView checkbox:
|
||||||
// TopAlign (0), BottomAlign (1), CenterAlign (2)
|
// TopAlign (0), BottomAlign (1), CenterAlign (2)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListViewCheckboxVerticalAlign(view View, subviewID ...string) int {
|
func GetListViewCheckboxVerticalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, TopAlign, false)
|
return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, TopAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListViewCheckboxHorizontalAlign returns the horizontal align of the ListView checkbox:
|
// GetListViewCheckboxHorizontalAlign returns the horizontal align of the ListView checkbox:
|
||||||
// LeftAlign (0), RightAlign (1), CenterAlign (2)
|
// LeftAlign (0), RightAlign (1), CenterAlign (2)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListViewCheckboxHorizontalAlign(view View, subviewID ...string) int {
|
func GetListViewCheckboxHorizontalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, LeftAlign, false)
|
return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, LeftAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListItemVerticalAlign returns the vertical align of the ListView item content:
|
// GetListItemVerticalAlign returns the vertical align of the ListView item content:
|
||||||
// TopAlign (0), BottomAlign (1), CenterAlign (2)
|
// TopAlign (0), BottomAlign (1), CenterAlign (2)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListItemVerticalAlign(view View, subviewID ...string) int {
|
func GetListItemVerticalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, ItemVerticalAlign, TopAlign, false)
|
return enumStyledProperty(view, subviewID, ItemVerticalAlign, TopAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ItemHorizontalAlign returns the horizontal align of the ListView item content:
|
// ItemHorizontalAlign returns the horizontal align of the ListView item content:
|
||||||
// LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
// LeftAlign (0), RightAlign (1), CenterAlign (2), StretchAlign (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListItemHorizontalAlign(view View, subviewID ...string) int {
|
func GetListItemHorizontalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, ItemHorizontalAlign, LeftAlign, false)
|
return enumStyledProperty(view, subviewID, ItemHorizontalAlign, LeftAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListItemFrame - returns the location and size of the ListView item in pixels.
|
// GetListItemFrame - returns the location and size of the ListView item in pixels.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListItemFrame(view View, subviewID string, index int) Frame {
|
func GetListItemFrame(view View, subviewID string, index int) Frame {
|
||||||
if subviewID != "" {
|
if subviewID != "" {
|
||||||
view = ViewByID(view, subviewID)
|
view = ViewByID(view, subviewID)
|
||||||
|
@ -1182,7 +1225,9 @@ func GetListItemFrame(view View, subviewID string, index int) Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListViewAdapter - returns the ListView adapter.
|
// GetListViewAdapter - returns the ListView adapter.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetListViewAdapter(view View, subviewID ...string) ListAdapter {
|
func GetListViewAdapter(view View, subviewID ...string) ListAdapter {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if value := view.Get(Items); value != nil {
|
if value := view.Get(Items); value != nil {
|
||||||
|
|
620
mediaPlayer.go
620
mediaPlayer.go
|
@ -3,6 +3,7 @@ package rui
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -488,7 +489,7 @@ const (
|
||||||
// - player - Interface of a player which generated this event,
|
// - player - Interface of a player which generated this event,
|
||||||
// - code - Error code. See below,
|
// - code - Error code. See below,
|
||||||
// - message - Error message,
|
// - message - Error message,
|
||||||
|
//
|
||||||
// Error codes:
|
// Error codes:
|
||||||
// - 0 (PlayerErrorUnknown) - Unknown error,
|
// - 0 (PlayerErrorUnknown) - Unknown error,
|
||||||
// - 1 (PlayerErrorAborted) - Fetching the associated resource was interrupted by a user request,
|
// - 1 (PlayerErrorAborted) - Fetching the associated resource was interrupted by a user request,
|
||||||
|
@ -610,7 +611,7 @@ func (player *mediaPlayerData) setFunc(tag PropertyName, value any) []PropertyNa
|
||||||
return setOneArgEventListener[MediaPlayer, float64](player, tag, value)
|
return setOneArgEventListener[MediaPlayer, float64](player, tag, value)
|
||||||
|
|
||||||
case PlayerErrorEvent:
|
case PlayerErrorEvent:
|
||||||
if listeners, ok := valueToPlayerErrorListeners(value); ok {
|
if listeners, ok := valueToMediaPlayerErrorListeners(value); ok {
|
||||||
return setArrayPropertyValue(player, tag, listeners)
|
return setArrayPropertyValue(player, tag, listeners)
|
||||||
}
|
}
|
||||||
notCompatibleType(tag, value)
|
notCompatibleType(tag, value)
|
||||||
|
@ -677,131 +678,132 @@ func setMediaPlayerSource(properties Properties, value any) []PropertyName {
|
||||||
return []PropertyName{Source}
|
return []PropertyName{Source}
|
||||||
}
|
}
|
||||||
|
|
||||||
func valueToPlayerErrorListeners(value any) ([]func(MediaPlayer, int, string), bool) {
|
/*
|
||||||
if value == nil {
|
func valueToPlayerErrorListeners(value any) ([]func(MediaPlayer, int, string), bool) {
|
||||||
return nil, true
|
if value == nil {
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case func(MediaPlayer, int, string):
|
|
||||||
return []func(MediaPlayer, int, string){value}, true
|
|
||||||
|
|
||||||
case func(int, string):
|
|
||||||
fn := func(_ MediaPlayer, code int, message string) {
|
|
||||||
value(code, message)
|
|
||||||
}
|
|
||||||
return []func(MediaPlayer, int, string){fn}, true
|
|
||||||
|
|
||||||
case func(MediaPlayer):
|
|
||||||
fn := func(player MediaPlayer, _ int, _ string) {
|
|
||||||
value(player)
|
|
||||||
}
|
|
||||||
return []func(MediaPlayer, int, string){fn}, true
|
|
||||||
|
|
||||||
case func():
|
|
||||||
fn := func(MediaPlayer, int, string) {
|
|
||||||
value()
|
|
||||||
}
|
|
||||||
return []func(MediaPlayer, int, string){fn}, true
|
|
||||||
|
|
||||||
case []func(MediaPlayer, int, string):
|
|
||||||
if len(value) == 0 {
|
|
||||||
return nil, true
|
return nil, true
|
||||||
}
|
}
|
||||||
for _, fn := range value {
|
|
||||||
if fn == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value, true
|
|
||||||
|
|
||||||
case []func(int, string):
|
switch value := value.(type) {
|
||||||
count := len(value)
|
case func(MediaPlayer, int, string):
|
||||||
if count == 0 {
|
return []func(MediaPlayer, int, string){value}, true
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(MediaPlayer, int, string), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ MediaPlayer, code int, message string) {
|
|
||||||
v(code, message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func(MediaPlayer):
|
case func(int, string):
|
||||||
count := len(value)
|
fn := func(_ MediaPlayer, code int, message string) {
|
||||||
if count == 0 {
|
value(code, message)
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(MediaPlayer, int, string), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
listeners[i] = func(player MediaPlayer, _ int, _ string) {
|
return []func(MediaPlayer, int, string){fn}, true
|
||||||
v(player)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []func():
|
case func(MediaPlayer):
|
||||||
count := len(value)
|
fn := func(player MediaPlayer, _ int, _ string) {
|
||||||
if count == 0 {
|
value(player)
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(MediaPlayer, int, string), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
listeners[i] = func(MediaPlayer, int, string) {
|
return []func(MediaPlayer, int, string){fn}, true
|
||||||
v()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners, true
|
|
||||||
|
|
||||||
case []any:
|
case func():
|
||||||
count := len(value)
|
fn := func(MediaPlayer, int, string) {
|
||||||
if count == 0 {
|
value()
|
||||||
return nil, true
|
|
||||||
}
|
|
||||||
listeners := make([]func(MediaPlayer, int, string), count)
|
|
||||||
for i, v := range value {
|
|
||||||
if v == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
switch v := v.(type) {
|
return []func(MediaPlayer, int, string){fn}, true
|
||||||
case func(MediaPlayer, int, string):
|
|
||||||
listeners[i] = v
|
|
||||||
|
|
||||||
case func(int, string):
|
case []func(MediaPlayer, int, string):
|
||||||
|
if len(value) == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case []func(int, string):
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(MediaPlayer, int, string), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
listeners[i] = func(_ MediaPlayer, code int, message string) {
|
listeners[i] = func(_ MediaPlayer, code int, message string) {
|
||||||
v(code, message)
|
v(code, message)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
case func(MediaPlayer):
|
case []func(MediaPlayer):
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(MediaPlayer, int, string), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
listeners[i] = func(player MediaPlayer, _ int, _ string) {
|
listeners[i] = func(player MediaPlayer, _ int, _ string) {
|
||||||
v(player)
|
v(player)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
case func():
|
case []func():
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(MediaPlayer, int, string), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
listeners[i] = func(MediaPlayer, int, string) {
|
listeners[i] = func(MediaPlayer, int, string) {
|
||||||
v()
|
v()
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
|
return listeners, true
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
count := len(value)
|
||||||
|
if count == 0 {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
listeners := make([]func(MediaPlayer, int, string), count)
|
||||||
|
for i, v := range value {
|
||||||
|
if v == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
switch v := v.(type) {
|
||||||
|
case func(MediaPlayer, int, string):
|
||||||
|
listeners[i] = v
|
||||||
|
|
||||||
|
case func(int, string):
|
||||||
|
listeners[i] = func(_ MediaPlayer, code int, message string) {
|
||||||
|
v(code, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
case func(MediaPlayer):
|
||||||
|
listeners[i] = func(player MediaPlayer, _ int, _ string) {
|
||||||
|
v(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
case func():
|
||||||
|
listeners[i] = func(MediaPlayer, int, string) {
|
||||||
|
v()
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return listeners, true
|
||||||
}
|
}
|
||||||
return listeners, true
|
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func mediaPlayerEvents() map[PropertyName]string {
|
func mediaPlayerEvents() map[PropertyName]string {
|
||||||
return map[PropertyName]string{
|
return map[PropertyName]string{
|
||||||
AbortEvent: "onabort",
|
AbortEvent: "onabort",
|
||||||
|
@ -981,31 +983,23 @@ func (player *mediaPlayerData) handleCommand(self View, command PropertyName, da
|
||||||
PlayingEvent, ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent,
|
PlayingEvent, ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent,
|
||||||
WaitingEvent:
|
WaitingEvent:
|
||||||
|
|
||||||
if value := player.getRaw(command); value != nil {
|
for _, listener := range getNoArgEventListeners[MediaPlayer](player, nil, command) {
|
||||||
if listeners, ok := value.([]func(MediaPlayer)); ok {
|
listener.Run(player)
|
||||||
for _, listener := range listeners {
|
|
||||||
listener(player)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case TimeUpdateEvent, DurationChangedEvent, RateChangedEvent, VolumeChangedEvent:
|
case TimeUpdateEvent, DurationChangedEvent, RateChangedEvent, VolumeChangedEvent:
|
||||||
if value := player.getRaw(command); value != nil {
|
time := dataFloatProperty(data, "value")
|
||||||
if listeners, ok := value.([]func(MediaPlayer, float64)); ok {
|
for _, listener := range getOneArgEventListeners[MediaPlayer, float64](player, nil, command) {
|
||||||
time := dataFloatProperty(data, "value")
|
listener.Run(player, time)
|
||||||
for _, listener := range listeners {
|
|
||||||
listener(player, time)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case PlayerErrorEvent:
|
case PlayerErrorEvent:
|
||||||
if value := player.getRaw(command); value != nil {
|
if value := player.getRaw(command); value != nil {
|
||||||
if listeners, ok := value.([]func(MediaPlayer, int, string)); ok {
|
if listeners, ok := value.([]mediaPlayerErrorListener); ok {
|
||||||
code, _ := dataIntProperty(data, "code")
|
code, _ := dataIntProperty(data, "code")
|
||||||
message, _ := data.PropertyValue("message")
|
message, _ := data.PropertyValue("message")
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(player, code, message)
|
listener.Run(player, code, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1254,3 +1248,393 @@ func IsMediaPlayerPaused(view View, playerID string) bool {
|
||||||
ErrorLog(`The found View is not MediaPlayer`)
|
ErrorLog(`The found View is not MediaPlayer`)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListener interface {
|
||||||
|
Run(MediaPlayer, int, string)
|
||||||
|
rawListener() any
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListener0 struct {
|
||||||
|
fn func()
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListenerP struct {
|
||||||
|
fn func(MediaPlayer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListenerI struct {
|
||||||
|
fn func(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListenerS struct {
|
||||||
|
fn func(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListenerPI struct {
|
||||||
|
fn func(MediaPlayer, int)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListenerPS struct {
|
||||||
|
fn func(MediaPlayer, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListenerIS struct {
|
||||||
|
fn func(int, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListenerPIS struct {
|
||||||
|
fn func(MediaPlayer, int, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type mediaPlayerErrorListenerBinding struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMediaPlayerErrorListener0(fn func()) mediaPlayerErrorListener {
|
||||||
|
obj := new(mediaPlayerErrorListener0)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListener0) Run(_ MediaPlayer, _ int, _ string) {
|
||||||
|
data.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListener0) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMediaPlayerErrorListenerP(fn func(MediaPlayer)) mediaPlayerErrorListener {
|
||||||
|
obj := new(mediaPlayerErrorListenerP)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerP) Run(player MediaPlayer, _ int, _ string) {
|
||||||
|
data.fn(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerP) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMediaPlayerErrorListenerI(fn func(int)) mediaPlayerErrorListener {
|
||||||
|
obj := new(mediaPlayerErrorListenerI)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerI) Run(_ MediaPlayer, code int, _ string) {
|
||||||
|
data.fn(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerI) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMediaPlayerErrorListenerS(fn func(string)) mediaPlayerErrorListener {
|
||||||
|
obj := new(mediaPlayerErrorListenerS)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerS) Run(_ MediaPlayer, _ int, message string) {
|
||||||
|
data.fn(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerS) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMediaPlayerErrorListenerPI(fn func(MediaPlayer, int)) mediaPlayerErrorListener {
|
||||||
|
obj := new(mediaPlayerErrorListenerPI)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerPI) Run(player MediaPlayer, code int, _ string) {
|
||||||
|
data.fn(player, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerPI) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMediaPlayerErrorListenerPS(fn func(MediaPlayer, string)) mediaPlayerErrorListener {
|
||||||
|
obj := new(mediaPlayerErrorListenerPS)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerPS) Run(player MediaPlayer, _ int, message string) {
|
||||||
|
data.fn(player, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerPS) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMediaPlayerErrorListenerIS(fn func(int, string)) mediaPlayerErrorListener {
|
||||||
|
obj := new(mediaPlayerErrorListenerIS)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerIS) Run(_ MediaPlayer, code int, message string) {
|
||||||
|
data.fn(code, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerIS) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMediaPlayerErrorListenerPIS(fn func(MediaPlayer, int, string)) mediaPlayerErrorListener {
|
||||||
|
obj := new(mediaPlayerErrorListenerPIS)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerPIS) Run(player MediaPlayer, code int, message string) {
|
||||||
|
data.fn(player, code, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerPIS) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMediaPlayerErrorListenerBinding(name string) mediaPlayerErrorListener {
|
||||||
|
obj := new(mediaPlayerErrorListenerBinding)
|
||||||
|
obj.name = name
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerBinding) Run(player MediaPlayer, code int, message string) {
|
||||||
|
bind := player.binding()
|
||||||
|
if bind == nil {
|
||||||
|
ErrorLogF(`There is no a binding object for call "%s"`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(bind)
|
||||||
|
method := val.MethodByName(data.name)
|
||||||
|
if !method.IsValid() {
|
||||||
|
ErrorLogF(`The "%s" method is not valid`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
methodType := method.Type()
|
||||||
|
var args []reflect.Value = nil
|
||||||
|
|
||||||
|
switch methodType.NumIn() {
|
||||||
|
case 0:
|
||||||
|
args = []reflect.Value{}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
inType := methodType.In(0)
|
||||||
|
if equalType(inType, reflect.TypeOf(player)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(player)}
|
||||||
|
} else if equalType(inType, reflect.TypeOf(code)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(code)}
|
||||||
|
} else if equalType(inType, reflect.TypeOf(message)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(message)}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
in0 := methodType.In(0)
|
||||||
|
in1 := methodType.In(1)
|
||||||
|
if equalType(in0, reflect.TypeOf(player)) {
|
||||||
|
if equalType(in1, reflect.TypeOf(code)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(player), reflect.ValueOf(code)}
|
||||||
|
} else if equalType(in1, reflect.TypeOf(message)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(player), reflect.ValueOf(message)}
|
||||||
|
}
|
||||||
|
} else if equalType(in0, reflect.TypeOf(code)) && equalType(in1, reflect.TypeOf(message)) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(code), reflect.ValueOf(message)}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
if equalType(methodType.In(0), reflect.TypeOf(player)) &&
|
||||||
|
equalType(methodType.In(1), reflect.TypeOf(code)) &&
|
||||||
|
equalType(methodType.In(2), reflect.TypeOf(message)) {
|
||||||
|
args = []reflect.Value{
|
||||||
|
reflect.ValueOf(player),
|
||||||
|
reflect.ValueOf(code),
|
||||||
|
reflect.ValueOf(message),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if args != nil {
|
||||||
|
method.Call(args)
|
||||||
|
} else {
|
||||||
|
ErrorLogF(`Unsupported prototype of "%s" method`, data.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *mediaPlayerErrorListenerBinding) rawListener() any {
|
||||||
|
return data.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToMediaPlayerErrorListeners(value any) ([]mediaPlayerErrorListener, bool) {
|
||||||
|
if value == nil {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case []mediaPlayerErrorListener:
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case mediaPlayerErrorListener:
|
||||||
|
return []mediaPlayerErrorListener{value}, true
|
||||||
|
|
||||||
|
case string:
|
||||||
|
return []mediaPlayerErrorListener{newMediaPlayerErrorListenerBinding(value)}, true
|
||||||
|
|
||||||
|
case func():
|
||||||
|
return []mediaPlayerErrorListener{newMediaPlayerErrorListener0(value)}, true
|
||||||
|
|
||||||
|
case func(MediaPlayer):
|
||||||
|
return []mediaPlayerErrorListener{newMediaPlayerErrorListenerP(value)}, true
|
||||||
|
|
||||||
|
case func(int):
|
||||||
|
return []mediaPlayerErrorListener{newMediaPlayerErrorListenerI(value)}, true
|
||||||
|
|
||||||
|
case func(string):
|
||||||
|
return []mediaPlayerErrorListener{newMediaPlayerErrorListenerS(value)}, true
|
||||||
|
|
||||||
|
case func(MediaPlayer, int):
|
||||||
|
return []mediaPlayerErrorListener{newMediaPlayerErrorListenerPI(value)}, true
|
||||||
|
|
||||||
|
case func(MediaPlayer, string):
|
||||||
|
return []mediaPlayerErrorListener{newMediaPlayerErrorListenerPS(value)}, true
|
||||||
|
|
||||||
|
case func(int, string):
|
||||||
|
return []mediaPlayerErrorListener{newMediaPlayerErrorListenerIS(value)}, true
|
||||||
|
|
||||||
|
case func(MediaPlayer, int, string):
|
||||||
|
return []mediaPlayerErrorListener{newMediaPlayerErrorListenerPIS(value)}, true
|
||||||
|
|
||||||
|
case []func():
|
||||||
|
result := make([]mediaPlayerErrorListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newMediaPlayerErrorListener0(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(MediaPlayer):
|
||||||
|
result := make([]mediaPlayerErrorListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newMediaPlayerErrorListenerP(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(int):
|
||||||
|
result := make([]mediaPlayerErrorListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newMediaPlayerErrorListenerI(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(string):
|
||||||
|
result := make([]mediaPlayerErrorListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newMediaPlayerErrorListenerS(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(MediaPlayer, int):
|
||||||
|
result := make([]mediaPlayerErrorListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newMediaPlayerErrorListenerPI(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(MediaPlayer, string):
|
||||||
|
result := make([]mediaPlayerErrorListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newMediaPlayerErrorListenerPS(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(int, string):
|
||||||
|
result := make([]mediaPlayerErrorListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newMediaPlayerErrorListenerIS(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func(MediaPlayer, int, string):
|
||||||
|
result := make([]mediaPlayerErrorListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newMediaPlayerErrorListenerPIS(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
result := make([]mediaPlayerErrorListener, 0, len(value))
|
||||||
|
for _, v := range value {
|
||||||
|
if v != nil {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case func():
|
||||||
|
result = append(result, newMediaPlayerErrorListener0(v))
|
||||||
|
|
||||||
|
case func(MediaPlayer):
|
||||||
|
result = append(result, newMediaPlayerErrorListenerP(v))
|
||||||
|
|
||||||
|
case func(int):
|
||||||
|
result = append(result, newMediaPlayerErrorListenerI(v))
|
||||||
|
|
||||||
|
case func(string):
|
||||||
|
result = append(result, newMediaPlayerErrorListenerS(v))
|
||||||
|
|
||||||
|
case func(MediaPlayer, int):
|
||||||
|
result = append(result, newMediaPlayerErrorListenerPI(v))
|
||||||
|
|
||||||
|
case func(MediaPlayer, string):
|
||||||
|
result = append(result, newMediaPlayerErrorListenerPS(v))
|
||||||
|
|
||||||
|
case func(int, string):
|
||||||
|
result = append(result, newMediaPlayerErrorListenerIS(v))
|
||||||
|
|
||||||
|
case func(MediaPlayer, int, string):
|
||||||
|
result = append(result, newMediaPlayerErrorListenerPIS(v))
|
||||||
|
|
||||||
|
case string:
|
||||||
|
result = append(result, newMediaPlayerErrorListenerBinding(v))
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMediaPlayerErrorListenerBinding(listeners []mediaPlayerErrorListener) string {
|
||||||
|
for _, listener := range listeners {
|
||||||
|
raw := listener.rawListener()
|
||||||
|
if text, ok := raw.(string); ok && text != "" {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
122
mouseEvents.go
122
mouseEvents.go
|
@ -280,56 +280,128 @@ func handleMouseEvents(view View, tag PropertyName, data DataObject) {
|
||||||
event.init(data)
|
event.init(data)
|
||||||
|
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(view, event)
|
listener.Run(view, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClickListeners returns the "click-event" listener list. If there are no listeners then the empty list is returned.
|
// GetClickListeners returns the "click-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetClickListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, MouseEvent](view, subviewID, ClickEvent)
|
// - func(View, MouseEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(MouseEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetClickListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, MouseEvent](view, subviewID, ClickEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDoubleClickListeners returns the "double-click-event" listener list. If there are no listeners then the empty list is returned.
|
// GetDoubleClickListeners returns the "double-click-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetDoubleClickListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, MouseEvent](view, subviewID, DoubleClickEvent)
|
// - func(View, MouseEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(MouseEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetDoubleClickListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, MouseEvent](view, subviewID, DoubleClickEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContextMenuListeners returns the "context-menu" listener list.
|
// GetContextMenuListeners returns the "context-menu" listener list.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetContextMenuListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, MouseEvent](view, subviewID, ContextMenuEvent)
|
// - func(View, MouseEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(MouseEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetContextMenuListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, MouseEvent](view, subviewID, ContextMenuEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMouseDownListeners returns the "mouse-down" listener list. If there are no listeners then the empty list is returned.
|
// GetMouseDownListeners returns the "mouse-down" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetMouseDownListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseDown)
|
// - func(View, MouseEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(MouseEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetMouseDownListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, MouseEvent](view, subviewID, MouseDown)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMouseUpListeners returns the "mouse-up" listener list. If there are no listeners then the empty list is returned.
|
// GetMouseUpListeners returns the "mouse-up" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetMouseUpListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseUp)
|
// - func(View, MouseEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(MouseEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetMouseUpListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, MouseEvent](view, subviewID, MouseUp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMouseMoveListeners returns the "mouse-move" listener list. If there are no listeners then the empty list is returned.
|
// GetMouseMoveListeners returns the "mouse-move" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetMouseMoveListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseMove)
|
// - func(View, MouseEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(MouseEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetMouseMoveListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, MouseEvent](view, subviewID, MouseMove)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMouseOverListeners returns the "mouse-over" listener list. If there are no listeners then the empty list is returned.
|
// GetMouseOverListeners returns the "mouse-over" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetMouseOverListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseOver)
|
// - func(View, MouseEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(MouseEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetMouseOverListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, MouseEvent](view, subviewID, MouseOver)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMouseOutListeners returns the "mouse-out" listener list. If there are no listeners then the empty list is returned.
|
// GetMouseOutListeners returns the "mouse-out" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetMouseOutListeners(view View, subviewID ...string) []func(View, MouseEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseOut)
|
// - func(View, MouseEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(MouseEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetMouseOutListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, MouseEvent](view, subviewID, MouseOut)
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,8 +166,8 @@ func (picker *numberPickerData) setFunc(tag PropertyName, value any) []PropertyN
|
||||||
}
|
}
|
||||||
|
|
||||||
func (picker *numberPickerData) numberFormat() string {
|
func (picker *numberPickerData) numberFormat() string {
|
||||||
if precission := GetNumberPickerPrecision(picker); precission > 0 {
|
if precision := GetNumberPickerPrecision(picker); precision > 0 {
|
||||||
return fmt.Sprintf("%%.%df", precission)
|
return fmt.Sprintf("%%.%df", precision)
|
||||||
}
|
}
|
||||||
return "%g"
|
return "%g"
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ func (picker *numberPickerData) propertyChanged(tag PropertyName) {
|
||||||
format := picker.numberFormat()
|
format := picker.numberFormat()
|
||||||
picker.Session().callFunc("setInputValue", picker.htmlID(), fmt.Sprintf(format, value))
|
picker.Session().callFunc("setInputValue", picker.htmlID(), fmt.Sprintf(format, value))
|
||||||
|
|
||||||
if listeners := GetNumberChangedListeners(picker); len(listeners) > 0 {
|
if listeners := getTwoArgEventListeners[NumberPicker, float64](picker, nil, NumberChangedEvent); len(listeners) > 0 {
|
||||||
old := 0.0
|
old := 0.0
|
||||||
if val := picker.getRaw("old-number"); val != nil {
|
if val := picker.getRaw("old-number"); val != nil {
|
||||||
if n, ok := val.(float64); ok {
|
if n, ok := val.(float64); ok {
|
||||||
|
@ -210,7 +210,7 @@ func (picker *numberPickerData) propertyChanged(tag PropertyName) {
|
||||||
}
|
}
|
||||||
if old != value {
|
if old != value {
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(picker, value, old)
|
listener.Run(picker, value, old)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,27 +244,27 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde
|
||||||
min, max := GetNumberPickerMinMax(picker)
|
min, max := GetNumberPickerMinMax(picker)
|
||||||
if min != math.Inf(-1) {
|
if min != math.Inf(-1) {
|
||||||
buffer.WriteString(` min="`)
|
buffer.WriteString(` min="`)
|
||||||
buffer.WriteString(fmt.Sprintf(format, min))
|
fmt.Fprintf(buffer, format, min)
|
||||||
buffer.WriteByte('"')
|
buffer.WriteByte('"')
|
||||||
}
|
}
|
||||||
|
|
||||||
if max != math.Inf(1) {
|
if max != math.Inf(1) {
|
||||||
buffer.WriteString(` max="`)
|
buffer.WriteString(` max="`)
|
||||||
buffer.WriteString(fmt.Sprintf(format, max))
|
fmt.Fprintf(buffer, format, max)
|
||||||
buffer.WriteByte('"')
|
buffer.WriteByte('"')
|
||||||
}
|
}
|
||||||
|
|
||||||
step := GetNumberPickerStep(picker)
|
step := GetNumberPickerStep(picker)
|
||||||
if step != 0 {
|
if step != 0 {
|
||||||
buffer.WriteString(` step="`)
|
buffer.WriteString(` step="`)
|
||||||
buffer.WriteString(fmt.Sprintf(format, step))
|
fmt.Fprintf(buffer, format, step)
|
||||||
buffer.WriteByte('"')
|
buffer.WriteByte('"')
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString(` step="any"`)
|
buffer.WriteString(` step="any"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(` value="`)
|
buffer.WriteString(` value="`)
|
||||||
buffer.WriteString(fmt.Sprintf(format, GetNumberPickerValue(picker)))
|
fmt.Fprintf(buffer, format, GetNumberPickerValue(picker))
|
||||||
buffer.WriteByte('"')
|
buffer.WriteByte('"')
|
||||||
|
|
||||||
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
|
||||||
|
@ -280,11 +280,11 @@ func (picker *numberPickerData) handleCommand(self View, command PropertyName, d
|
||||||
oldValue := GetNumberPickerValue(picker)
|
oldValue := GetNumberPickerValue(picker)
|
||||||
picker.properties[NumberPickerValue] = text
|
picker.properties[NumberPickerValue] = text
|
||||||
if value != oldValue {
|
if value != oldValue {
|
||||||
for _, listener := range GetNumberChangedListeners(picker) {
|
for _, listener := range getTwoArgEventListeners[NumberPicker, float64](picker, nil, NumberChangedEvent) {
|
||||||
listener(picker, value, oldValue)
|
listener.Run(picker, value, oldValue)
|
||||||
}
|
}
|
||||||
if listener, ok := picker.changeListener[NumberPickerValue]; ok {
|
if listener, ok := picker.changeListener[NumberPickerValue]; ok {
|
||||||
listener(picker, NumberPickerValue)
|
listener.Run(picker, NumberPickerValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,13 +298,17 @@ func (picker *numberPickerData) handleCommand(self View, command PropertyName, d
|
||||||
// GetNumberPickerType returns the type of NumberPicker subview. Valid values:
|
// GetNumberPickerType returns the type of NumberPicker subview. Valid values:
|
||||||
// NumberEditor (0) - NumberPicker is presented by editor (default type);
|
// NumberEditor (0) - NumberPicker is presented by editor (default type);
|
||||||
// NumberSlider (1) - NumberPicker is presented by slider.
|
// NumberSlider (1) - NumberPicker is presented by slider.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetNumberPickerType(view View, subviewID ...string) int {
|
func GetNumberPickerType(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, NumberPickerType, NumberEditor, false)
|
return enumStyledProperty(view, subviewID, NumberPickerType, NumberEditor, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNumberPickerMinMax returns the min and max value of NumberPicker subview.
|
// GetNumberPickerMinMax returns the min and max value of NumberPicker subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetNumberPickerMinMax(view View, subviewID ...string) (float64, float64) {
|
func GetNumberPickerMinMax(view View, subviewID ...string) (float64, float64) {
|
||||||
view = getSubview(view, subviewID)
|
view = getSubview(view, subviewID)
|
||||||
pickerType := GetNumberPickerType(view)
|
pickerType := GetNumberPickerType(view)
|
||||||
|
@ -328,7 +332,9 @@ func GetNumberPickerMinMax(view View, subviewID ...string) (float64, float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNumberPickerStep returns the value changing step of NumberPicker subview.
|
// GetNumberPickerStep returns the value changing step of NumberPicker subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetNumberPickerStep(view View, subviewID ...string) float64 {
|
func GetNumberPickerStep(view View, subviewID ...string) float64 {
|
||||||
view = getSubview(view, subviewID)
|
view = getSubview(view, subviewID)
|
||||||
_, max := GetNumberPickerMinMax(view)
|
_, max := GetNumberPickerMinMax(view)
|
||||||
|
@ -341,7 +347,9 @@ func GetNumberPickerStep(view View, subviewID ...string) float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNumberPickerValue returns the value of NumberPicker subview.
|
// GetNumberPickerValue returns the value of NumberPicker subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetNumberPickerValue(view View, subviewID ...string) float64 {
|
func GetNumberPickerValue(view View, subviewID ...string) float64 {
|
||||||
view = getSubview(view, subviewID)
|
view = getSubview(view, subviewID)
|
||||||
min, _ := GetNumberPickerMinMax(view)
|
min, _ := GetNumberPickerMinMax(view)
|
||||||
|
@ -350,13 +358,26 @@ func GetNumberPickerValue(view View, subviewID ...string) float64 {
|
||||||
|
|
||||||
// GetNumberChangedListeners returns the NumberChangedListener list of an NumberPicker subview.
|
// GetNumberChangedListeners returns the NumberChangedListener list of an NumberPicker subview.
|
||||||
// If there are no listeners then the empty list is returned
|
// If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetNumberChangedListeners(view View, subviewID ...string) []func(NumberPicker, float64, float64) {
|
// Result elements can be of the following types:
|
||||||
return getTwoArgEventListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent)
|
// - func(rui.NumberPicker, float64, float64),
|
||||||
|
// - func(rui.NumberPicker, float64),
|
||||||
|
// - func(rui.NumberPicker),
|
||||||
|
// - func(float64, float64),
|
||||||
|
// - func(float64),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetNumberChangedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getTwoArgEventRawListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNumberPickerPrecision returns the precision of displaying fractional part in editor of NumberPicker subview.
|
// GetNumberPickerPrecision returns the precision of displaying fractional part in editor of NumberPicker subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetNumberPickerPrecision(view View, subviewID ...string) int {
|
func GetNumberPickerPrecision(view View, subviewID ...string) int {
|
||||||
return intStyledProperty(view, subviewID, NumberPickerPrecision, 0)
|
return intStyledProperty(view, subviewID, NumberPickerPrecision, 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,42 +192,96 @@ func handlePointerEvents(view View, tag PropertyName, data DataObject) {
|
||||||
event.init(data)
|
event.init(data)
|
||||||
|
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(view, event)
|
listener.Run(view, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPointerDownListeners returns the "pointer-down" listener list. If there are no listeners then the empty list is returned.
|
// GetPointerDownListeners returns the "pointer-down" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetPointerDownListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerDown)
|
// - func(View, PointerEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(PointerEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetPointerDownListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, PointerEvent](view, subviewID, PointerDown)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPointerUpListeners returns the "pointer-up" listener list. If there are no listeners then the empty list is returned.
|
// GetPointerUpListeners returns the "pointer-up" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetPointerUpListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerUp)
|
// - func(View, PointerEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(PointerEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetPointerUpListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, PointerEvent](view, subviewID, PointerUp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPointerMoveListeners returns the "pointer-move" listener list. If there are no listeners then the empty list is returned.
|
// GetPointerMoveListeners returns the "pointer-move" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetPointerMoveListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerMove)
|
// - func(View, PointerEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(PointerEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetPointerMoveListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, PointerEvent](view, subviewID, PointerMove)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPointerCancelListeners returns the "pointer-cancel" listener list. If there are no listeners then the empty list is returned.
|
// GetPointerCancelListeners returns the "pointer-cancel" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetPointerCancelListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerCancel)
|
// - func(View, PointerEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(PointerEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetPointerCancelListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, PointerEvent](view, subviewID, PointerCancel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPointerOverListeners returns the "pointer-over" listener list. If there are no listeners then the empty list is returned.
|
// GetPointerOverListeners returns the "pointer-over" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetPointerOverListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerOver)
|
// - func(View, PointerEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(PointerEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetPointerOverListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, PointerEvent](view, subviewID, PointerOver)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPointerOutListeners returns the "pointer-out" listener list. If there are no listeners then the empty list is returned.
|
// GetPointerOutListeners returns the "pointer-out" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetPointerOutListeners(view View, subviewID ...string) []func(View, PointerEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerOut)
|
// - func(View, PointerEvent),
|
||||||
|
// - func(View),
|
||||||
|
// - func(PointerEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetPointerOutListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, PointerEvent](view, subviewID, PointerOut)
|
||||||
}
|
}
|
||||||
|
|
200
popup.go
200
popup.go
|
@ -2,6 +2,7 @@ package rui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -150,7 +151,7 @@ const (
|
||||||
//
|
//
|
||||||
// Used by Popup.
|
// Used by Popup.
|
||||||
// Specify start translation, scale and rotation over x, y and z axes as well as a distortion
|
// Specify start translation, scale and rotation over x, y and z axes as well as a distortion
|
||||||
// for an animated Popup showing/hidding.
|
// for an animated Popup showing/hiding.
|
||||||
//
|
//
|
||||||
// Supported types: TransformProperty, string.
|
// Supported types: TransformProperty, string.
|
||||||
//
|
//
|
||||||
|
@ -278,7 +279,24 @@ type Popup interface {
|
||||||
viewByHTMLID(id string) View
|
viewByHTMLID(id string) View
|
||||||
keyEvent(event KeyEvent) bool
|
keyEvent(event KeyEvent) bool
|
||||||
showAnimation()
|
showAnimation()
|
||||||
dissmissAnimation(listener func(PropertyName)) bool
|
dismissAnimation(listener func(PropertyName)) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type popupListener interface {
|
||||||
|
Run(Popup)
|
||||||
|
rawListener() any
|
||||||
|
}
|
||||||
|
|
||||||
|
type popupListener0 struct {
|
||||||
|
fn func()
|
||||||
|
}
|
||||||
|
|
||||||
|
type popupListener1 struct {
|
||||||
|
fn func(Popup)
|
||||||
|
}
|
||||||
|
|
||||||
|
type popupListenerBinding struct {
|
||||||
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
type popupData struct {
|
type popupData struct {
|
||||||
|
@ -287,7 +305,7 @@ type popupData struct {
|
||||||
contentView View
|
contentView View
|
||||||
buttons []PopupButton
|
buttons []PopupButton
|
||||||
cancelable bool
|
cancelable bool
|
||||||
dismissListener []func(Popup)
|
dismissListener []popupListener
|
||||||
showTransform TransformProperty
|
showTransform TransformProperty
|
||||||
showOpacity float64
|
showOpacity float64
|
||||||
showDuration float64
|
showDuration float64
|
||||||
|
@ -649,7 +667,7 @@ func (popup *popupData) init(view View, popupParams Params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case DismissEvent:
|
case DismissEvent:
|
||||||
if listeners, ok := valueToNoArgEventListeners[Popup](value); ok {
|
if listeners, ok := valueToPopupEventListeners(value); ok {
|
||||||
if listeners != nil {
|
if listeners != nil {
|
||||||
popup.dismissListener = listeners
|
popup.dismissListener = listeners
|
||||||
}
|
}
|
||||||
|
@ -831,7 +849,7 @@ func (popup *popupData) showAnimation() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (popup *popupData) dissmissAnimation(listener func(PropertyName)) bool {
|
func (popup *popupData) dismissAnimation(listener func(PropertyName)) bool {
|
||||||
if popup.showOpacity != 1 || popup.showTransform != nil {
|
if popup.showOpacity != 1 || popup.showTransform != nil {
|
||||||
session := popup.Session()
|
session := popup.Session()
|
||||||
popup.popupView.Set(TransitionEndEvent, listener)
|
popup.popupView.Set(TransitionEndEvent, listener)
|
||||||
|
@ -887,7 +905,7 @@ func (popup *popupData) onDismiss() {
|
||||||
popup.Session().callFunc("removeView", popup.layerView.htmlID())
|
popup.Session().callFunc("removeView", popup.layerView.htmlID())
|
||||||
|
|
||||||
for _, listener := range popup.dismissListener {
|
for _, listener := range popup.dismissListener {
|
||||||
listener(popup)
|
listener.Run(popup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -923,6 +941,25 @@ func NewPopup(view View, param Params) Popup {
|
||||||
return popup
|
return popup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func CreatePopupFromObject(session Session, object DataObject, binding any) Popup {
|
||||||
|
node := object.RemovePropertyByTag(string(Content))
|
||||||
|
if node == nil {
|
||||||
|
ErrorLog(`"content" property not found`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch node.Type() {
|
||||||
|
case ObjectNode:
|
||||||
|
|
||||||
|
case TextNode:
|
||||||
|
|
||||||
|
default:
|
||||||
|
ErrorLog(`Unsupported data of "content" property`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
// ShowPopup creates a new Popup and shows it
|
// ShowPopup creates a new Popup and shows it
|
||||||
func ShowPopup(view View, param Params) Popup {
|
func ShowPopup(view View, param Params) Popup {
|
||||||
popup := NewPopup(view, param)
|
popup := NewPopup(view, param)
|
||||||
|
@ -994,23 +1031,162 @@ func (manager *popupManager) dismissPopup(popup Popup) {
|
||||||
|
|
||||||
session := popup.Session()
|
session := popup.Session()
|
||||||
listener := func(PropertyName) {
|
listener := func(PropertyName) {
|
||||||
if index == count-1 {
|
switch index {
|
||||||
|
case 0:
|
||||||
if count == 1 {
|
if count == 1 {
|
||||||
manager.popups = []Popup{}
|
manager.popups = []Popup{}
|
||||||
session.updateCSSProperty("ruiRoot", "pointer-events", "auto")
|
session.updateCSSProperty("ruiRoot", "pointer-events", "auto")
|
||||||
session.updateCSSProperty("ruiPopupLayer", "visibility", "hidden")
|
session.updateCSSProperty("ruiPopupLayer", "visibility", "hidden")
|
||||||
} else {
|
} else {
|
||||||
manager.popups = manager.popups[:count-1]
|
manager.popups = manager.popups[1:]
|
||||||
}
|
}
|
||||||
} else if index == 0 {
|
|
||||||
manager.popups = manager.popups[1:]
|
case count - 1:
|
||||||
} else {
|
manager.popups = manager.popups[:count-1]
|
||||||
|
|
||||||
|
default:
|
||||||
manager.popups = append(manager.popups[:index], manager.popups[index+1:]...)
|
manager.popups = append(manager.popups[:index], manager.popups[index+1:]...)
|
||||||
}
|
}
|
||||||
popup.onDismiss()
|
popup.onDismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !popup.dissmissAnimation(listener) {
|
if !popup.dismissAnimation(listener) {
|
||||||
listener("")
|
listener("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newPopupListener0(fn func()) popupListener {
|
||||||
|
obj := new(popupListener0)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *popupListener0) Run(_ Popup) {
|
||||||
|
data.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *popupListener0) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPopupListener1(fn func(Popup)) popupListener {
|
||||||
|
obj := new(popupListener1)
|
||||||
|
obj.fn = fn
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *popupListener1) Run(popup Popup) {
|
||||||
|
data.fn(popup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *popupListener1) rawListener() any {
|
||||||
|
return data.fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPopupListenerBinding(name string) popupListener {
|
||||||
|
obj := new(popupListenerBinding)
|
||||||
|
obj.name = name
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *popupListenerBinding) Run(popup Popup) {
|
||||||
|
bind := popup.View().binding()
|
||||||
|
if bind == nil {
|
||||||
|
ErrorLogF(`There is no a binding object for call "%s"`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(bind)
|
||||||
|
method := val.MethodByName(data.name)
|
||||||
|
if !method.IsValid() {
|
||||||
|
ErrorLogF(`The "%s" method is not valid`, data.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
methodType := method.Type()
|
||||||
|
var args []reflect.Value = nil
|
||||||
|
switch methodType.NumIn() {
|
||||||
|
case 0:
|
||||||
|
args = []reflect.Value{}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
inType := methodType.In(0)
|
||||||
|
if inType == reflect.TypeOf(popup) {
|
||||||
|
args = []reflect.Value{reflect.ValueOf(popup)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if args != nil {
|
||||||
|
method.Call(args)
|
||||||
|
} else {
|
||||||
|
ErrorLogF(`Unsupported prototype of "%s" method`, data.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *popupListenerBinding) rawListener() any {
|
||||||
|
return data.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToPopupEventListeners(value any) ([]popupListener, bool) {
|
||||||
|
if value == nil {
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case []popupListener:
|
||||||
|
return value, true
|
||||||
|
|
||||||
|
case popupListener:
|
||||||
|
return []popupListener{value}, true
|
||||||
|
|
||||||
|
case string:
|
||||||
|
return []popupListener{newPopupListenerBinding(value)}, true
|
||||||
|
|
||||||
|
case func(Popup):
|
||||||
|
return []popupListener{newPopupListener1(value)}, true
|
||||||
|
|
||||||
|
case func():
|
||||||
|
return []popupListener{newPopupListener0(value)}, true
|
||||||
|
|
||||||
|
case []func(Popup):
|
||||||
|
result := make([]popupListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newPopupListener1(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []func():
|
||||||
|
result := make([]popupListener, 0, len(value))
|
||||||
|
for _, fn := range value {
|
||||||
|
if fn != nil {
|
||||||
|
result = append(result, newPopupListener0(fn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
result := make([]popupListener, 0, len(value))
|
||||||
|
for _, v := range value {
|
||||||
|
if v != nil {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case func(Popup):
|
||||||
|
result = append(result, newPopupListener1(v))
|
||||||
|
|
||||||
|
case func():
|
||||||
|
result = append(result, newPopupListener0(v))
|
||||||
|
|
||||||
|
case string:
|
||||||
|
result = append(result, newPopupListenerBinding(v))
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, len(result) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
|
@ -101,13 +101,17 @@ func (progress *progressBarData) htmlProperties(self View, buffer *strings.Build
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProgressBarMax returns the max value of ProgressBar subview.
|
// GetProgressBarMax returns the max value of ProgressBar subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetProgressBarMax(view View, subviewID ...string) float64 {
|
func GetProgressBarMax(view View, subviewID ...string) float64 {
|
||||||
return floatStyledProperty(view, subviewID, ProgressBarMax, 1)
|
return floatStyledProperty(view, subviewID, ProgressBarMax, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProgressBarValue returns the value of ProgressBar subview.
|
// GetProgressBarValue returns the value of ProgressBar subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetProgressBarValue(view View, subviewID ...string) float64 {
|
func GetProgressBarValue(view View, subviewID ...string) float64 {
|
||||||
return floatStyledProperty(view, subviewID, ProgressBarValue, 0)
|
return floatStyledProperty(view, subviewID, ProgressBarValue, 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2723,4 +2723,6 @@ const (
|
||||||
//
|
//
|
||||||
// Supported types: string.
|
// Supported types: string.
|
||||||
Tooltip PropertyName = "tooltip"
|
Tooltip PropertyName = "tooltip"
|
||||||
|
|
||||||
|
Binding PropertyName = "binding"
|
||||||
)
|
)
|
||||||
|
|
|
@ -118,7 +118,7 @@ func (resizable *resizableData) setFunc(tag PropertyName, value any) []PropertyN
|
||||||
newContent = value
|
newContent = value
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
if newContent = CreateViewFromObject(resizable.Session(), value); newContent == nil {
|
if newContent = CreateViewFromObject(resizable.Session(), value, nil); newContent == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ func (resizable *resizableData) htmlSubviews(self View, buffer *strings.Builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
writePos := func(x1, x2, y1, y2 int) {
|
writePos := func(x1, x2, y1, y2 int) {
|
||||||
buffer.WriteString(fmt.Sprintf(` grid-column-start: %d; grid-column-end: %d; grid-row-start: %d; grid-row-end: %d;"></div>`, x1, x2, y1, y2))
|
fmt.Fprintf(buffer, ` grid-column-start: %d; grid-column-end: %d; grid-row-start: %d; grid-row-end: %d;"></div>`, x1, x2, y1, y2)
|
||||||
}
|
}
|
||||||
//htmlID := resizable.htmlID()
|
//htmlID := resizable.htmlID()
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ func (view *viewData) onResize(self View, x, y, width, height float64) {
|
||||||
view.frame.Top = y
|
view.frame.Top = y
|
||||||
view.frame.Width = width
|
view.frame.Width = width
|
||||||
view.frame.Height = height
|
view.frame.Height = height
|
||||||
for _, listener := range GetResizeListeners(view) {
|
for _, listener := range getOneArgEventListeners[View, Frame](view, nil, ResizeEvent) {
|
||||||
listener(self, view.frame)
|
listener.Run(self, view.frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,9 @@ func (view *viewData) Frame() Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetViewFrame returns the size and location of view's viewport.
|
// GetViewFrame returns the size and location of view's viewport.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then the value of the first argument (view) is returned
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetViewFrame(view View, subviewID ...string) Frame {
|
func GetViewFrame(view View, subviewID ...string) Frame {
|
||||||
view = getSubview(view, subviewID)
|
view = getSubview(view, subviewID)
|
||||||
if view == nil {
|
if view == nil {
|
||||||
|
@ -83,7 +85,16 @@ func GetViewFrame(view View, subviewID ...string) Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetResizeListeners returns the list of "resize-event" listeners. If there are no listeners then the empty list is returned
|
// GetResizeListeners returns the list of "resize-event" listeners. If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then the listeners list of the first argument (view) is returned
|
//
|
||||||
func GetResizeListeners(view View, subviewID ...string) []func(View, Frame) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, Frame](view, subviewID, ResizeEvent)
|
// - func(rui.View, rui.Frame),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.Frame),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetResizeListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, Frame](view, subviewID, ResizeEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -401,7 +401,7 @@ func OpenRawResource(filename string) fs.File {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllRawResources returns the list of all raw resouces
|
// AllRawResources returns the list of all raw resources
|
||||||
func AllRawResources() []string {
|
func AllRawResources() []string {
|
||||||
result := []string{}
|
result := []string{}
|
||||||
|
|
||||||
|
@ -448,7 +448,7 @@ func AllRawResources() []string {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllImageResources returns the list of all image resouces
|
// AllImageResources returns the list of all image resources
|
||||||
func AllImageResources() []string {
|
func AllImageResources() []string {
|
||||||
result := make([]string, 0, len(resources.images))
|
result := make([]string, 0, len(resources.images))
|
||||||
for image := range resources.images {
|
for image := range resources.images {
|
||||||
|
|
|
@ -25,8 +25,8 @@ func (view *viewData) onScroll(self View, x, y, width, height float64) {
|
||||||
view.scroll.Top = y
|
view.scroll.Top = y
|
||||||
view.scroll.Width = width
|
view.scroll.Width = width
|
||||||
view.scroll.Height = height
|
view.scroll.Height = height
|
||||||
for _, listener := range GetScrollListeners(view) {
|
for _, listener := range getOneArgEventListeners[View, Frame](view, nil, ScrollEvent) {
|
||||||
listener(self, view.scroll)
|
listener.Run(self, view.scroll)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,9 @@ func (view *viewData) setScroll(x, y, width, height float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetViewScroll returns ...
|
// GetViewScroll returns ...
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value of the first argument (view) is returned
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetViewScroll(view View, subviewID ...string) Frame {
|
func GetViewScroll(view View, subviewID ...string) Frame {
|
||||||
view = getSubview(view, subviewID)
|
view = getSubview(view, subviewID)
|
||||||
if view == nil {
|
if view == nil {
|
||||||
|
@ -52,13 +54,24 @@ func GetViewScroll(view View, subviewID ...string) Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetScrollListeners returns the list of "scroll-event" listeners. If there are no listeners then the empty list is returned
|
// GetScrollListeners returns the list of "scroll-event" listeners. If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then the listeners list of the first argument (view) is returned
|
//
|
||||||
func GetScrollListeners(view View, subviewID ...string) []func(View, Frame) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, Frame](view, subviewID, ResizeEvent)
|
// - func(rui.View, rui.Frame),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.Frame),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetScrollListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, Frame](view, subviewID, ScrollEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScrollTo scrolls the view's content to the given position.
|
// ScrollTo scrolls the view's content to the given position.
|
||||||
// If the second argument (subviewID) is "" then the first argument (view) is used
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func ScrollViewTo(view View, subviewID string, x, y float64) {
|
func ScrollViewTo(view View, subviewID string, x, y float64) {
|
||||||
if subviewID != "" {
|
if subviewID != "" {
|
||||||
view = ViewByID(view, subviewID)
|
view = ViewByID(view, subviewID)
|
||||||
|
@ -69,7 +82,9 @@ func ScrollViewTo(view View, subviewID string, x, y float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScrollViewToEnd scrolls the view's content to the start of view.
|
// ScrollViewToEnd scrolls the view's content to the start of view.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then the first argument (view) is used
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func ScrollViewToStart(view View, subviewID ...string) {
|
func ScrollViewToStart(view View, subviewID ...string) {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
view.Session().callFunc("scrollToStart", view.htmlID())
|
view.Session().callFunc("scrollToStart", view.htmlID())
|
||||||
|
@ -77,7 +92,9 @@ func ScrollViewToStart(view View, subviewID ...string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScrollViewToEnd scrolls the view's content to the end of view.
|
// ScrollViewToEnd scrolls the view's content to the end of view.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then the first argument (view) is used
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func ScrollViewToEnd(view View, subviewID ...string) {
|
func ScrollViewToEnd(view View, subviewID ...string) {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
view.Session().callFunc("scrollToEnd", view.htmlID())
|
view.Session().callFunc("scrollToEnd", view.htmlID())
|
||||||
|
|
|
@ -266,7 +266,8 @@ func (session *sessionData) setBridge(events chan DataObject, bridge bridge) {
|
||||||
|
|
||||||
func (session *sessionData) close() {
|
func (session *sessionData) close() {
|
||||||
if session.events != nil {
|
if session.events != nil {
|
||||||
session.events <- ParseDataText(`session-close{session="` + strconv.Itoa(session.sessionID) + `"}`)
|
obj, _ := ParseDataText(`session-close{session="` + strconv.Itoa(session.sessionID) + `"}`)
|
||||||
|
session.events <- obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,7 @@ func (data *sizeFuncData) writeString(topFunc string, buffer *strings.Builder) {
|
||||||
buffer.WriteString(arg.String())
|
buffer.WriteString(arg.String())
|
||||||
|
|
||||||
case float64:
|
case float64:
|
||||||
buffer.WriteString(fmt.Sprintf("%g", arg))
|
fmt.Fprintf(buffer, "%g", arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,7 @@ func (data *sizeFuncData) writeCSS(topFunc string, buffer *strings.Builder, sess
|
||||||
buffer.WriteString(arg.String())
|
buffer.WriteString(arg.String())
|
||||||
|
|
||||||
case float64:
|
case float64:
|
||||||
buffer.WriteString(fmt.Sprintf("%g", arg))
|
fmt.Fprintf(buffer, "%g", arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,7 +334,9 @@ func (layout *stackLayoutData) init(session Session) {
|
||||||
layout.remove = layout.removeFunc
|
layout.remove = layout.removeFunc
|
||||||
layout.changed = layout.propertyChanged
|
layout.changed = layout.propertyChanged
|
||||||
|
|
||||||
layout.setRaw(TransitionEndEvent, []func(View, PropertyName){layout.transitionFinished})
|
layout.setRaw(TransitionEndEvent, []oneArgListener[View, PropertyName]{
|
||||||
|
newOneArgListenerVE(layout.transitionFinished),
|
||||||
|
})
|
||||||
if session.TextDirection() == RightToLeftDirection {
|
if session.TextDirection() == RightToLeftDirection {
|
||||||
layout.setRaw(PushTransform, NewTransformProperty(Params{TranslateX: Percent(-100)}))
|
layout.setRaw(PushTransform, NewTransformProperty(Params{TranslateX: Percent(-100)}))
|
||||||
} else {
|
} else {
|
||||||
|
@ -434,7 +436,7 @@ func (layout *stackLayoutData) setFunc(tag PropertyName, value any) []PropertyNa
|
||||||
// TODO
|
// TODO
|
||||||
listeners, ok := valueToOneArgEventListeners[View, PropertyName](value)
|
listeners, ok := valueToOneArgEventListeners[View, PropertyName](value)
|
||||||
if ok && listeners != nil {
|
if ok && listeners != nil {
|
||||||
listeners = append(listeners, layout.transitionFinished)
|
listeners = append(listeners, newOneArgListenerVE(layout.transitionFinished))
|
||||||
layout.setRaw(TransitionEndEvent, listeners)
|
layout.setRaw(TransitionEndEvent, listeners)
|
||||||
return []PropertyName{tag}
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +466,9 @@ func (layout *stackLayoutData) propertyChanged(tag PropertyName) {
|
||||||
func (layout *stackLayoutData) removeFunc(tag PropertyName) []PropertyName {
|
func (layout *stackLayoutData) removeFunc(tag PropertyName) []PropertyName {
|
||||||
switch tag {
|
switch tag {
|
||||||
case TransitionEndEvent:
|
case TransitionEndEvent:
|
||||||
layout.setRaw(TransitionEndEvent, []func(View, PropertyName){layout.transitionFinished})
|
layout.setRaw(TransitionEndEvent, []oneArgListener[View, PropertyName]{
|
||||||
|
newOneArgListenerVE(layout.transitionFinished),
|
||||||
|
})
|
||||||
return []PropertyName{tag}
|
return []PropertyName{tag}
|
||||||
}
|
}
|
||||||
return layout.viewsContainerData.removeFunc(tag)
|
return layout.viewsContainerData.removeFunc(tag)
|
||||||
|
@ -606,12 +610,6 @@ func (layout *stackLayoutData) moveToFrontByIndex(index int, onShow []func(View)
|
||||||
session.updateCSSProperty(peekPageID, "transform", transformCSS)
|
session.updateCSSProperty(peekPageID, "transform", transformCSS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (layout *stackLayoutData) contentChanged() {
|
|
||||||
if listener, ok := layout.changeListener[Content]; ok {
|
|
||||||
listener(layout, Content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (layout *stackLayoutData) RemovePeek() View {
|
func (layout *stackLayoutData) RemovePeek() View {
|
||||||
return layout.RemoveView(len(layout.views) - 1)
|
return layout.RemoveView(len(layout.views) - 1)
|
||||||
}
|
}
|
||||||
|
@ -679,9 +677,7 @@ func (layout *stackLayoutData) Append(view View) {
|
||||||
}
|
}
|
||||||
session.appendToInnerHTML(stackID, buffer.String())
|
session.appendToInnerHTML(stackID, buffer.String())
|
||||||
|
|
||||||
if listener, ok := layout.changeListener[Content]; ok {
|
layout.contentChanged()
|
||||||
listener(layout, Content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,9 +713,7 @@ func (layout *stackLayoutData) Insert(view View, index int) {
|
||||||
session := layout.Session()
|
session := layout.Session()
|
||||||
session.appendToInnerHTML(stackID, buffer.String())
|
session.appendToInnerHTML(stackID, buffer.String())
|
||||||
|
|
||||||
if listener, ok := layout.changeListener[Content]; ok {
|
layout.contentChanged()
|
||||||
listener(layout, Content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes view from list and return it
|
// Remove removes view from list and return it
|
||||||
|
@ -750,10 +744,7 @@ func (layout *stackLayoutData) RemoveView(index int) View {
|
||||||
}
|
}
|
||||||
|
|
||||||
layout.Session().callFunc("removeView", view.htmlID()+"page")
|
layout.Session().callFunc("removeView", view.htmlID()+"page")
|
||||||
|
layout.contentChanged()
|
||||||
if listener, ok := layout.changeListener[Content]; ok {
|
|
||||||
listener(layout, Content)
|
|
||||||
}
|
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -914,7 +905,9 @@ func (layout *stackLayoutData) htmlSubviews(self View, buffer *strings.Builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsMoveToFrontAnimation returns "true" if an animation is used when calling the MoveToFront/MoveToFrontByID method of StackLayout interface.
|
// IsMoveToFrontAnimation returns "true" if an animation is used when calling the MoveToFront/MoveToFrontByID method of StackLayout interface.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsMoveToFrontAnimation(view View, subviewID ...string) bool {
|
func IsMoveToFrontAnimation(view View, subviewID ...string) bool {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if value, ok := boolProperty(view, MoveToFrontAnimation, view.Session()); ok {
|
if value, ok := boolProperty(view, MoveToFrontAnimation, view.Session()); ok {
|
||||||
|
@ -950,7 +943,9 @@ func GetPushTiming(view View, subviewID ...string) string {
|
||||||
// GetPushTransform returns the start transform (translation, scale and rotation over x, y and z axes as well as a distortion)
|
// GetPushTransform returns the start transform (translation, scale and rotation over x, y and z axes as well as a distortion)
|
||||||
// for an animated pushing of a child view.
|
// for an animated pushing of a child view.
|
||||||
// The default value is nil (no transform).
|
// The default value is nil (no transform).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetPushTransform(view View, subviewID ...string) TransformProperty {
|
func GetPushTransform(view View, subviewID ...string) TransformProperty {
|
||||||
return transformStyledProperty(view, subviewID, PushTransform)
|
return transformStyledProperty(view, subviewID, PushTransform)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,9 @@ func (resources *resourceManager) scanStringsDir(path string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadStringResources(text string) {
|
func loadStringResources(text string) {
|
||||||
data := ParseDataText(text)
|
data, err := ParseDataText(text)
|
||||||
if data == nil {
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
110
tableView.go
110
tableView.go
|
@ -592,14 +592,6 @@ func (table *tableViewData) init(session Session) {
|
||||||
table.tag = "TableView"
|
table.tag = "TableView"
|
||||||
table.cellViews = []View{}
|
table.cellViews = []View{}
|
||||||
table.cellFrame = []Frame{}
|
table.cellFrame = []Frame{}
|
||||||
/*
|
|
||||||
table.cellSelectedListener = []func(TableView, int, int){}
|
|
||||||
table.cellClickedListener = []func(TableView, int, int){}
|
|
||||||
table.rowSelectedListener = []func(TableView, int){}
|
|
||||||
table.rowClickedListener = []func(TableView, int){}
|
|
||||||
table.current.Row = -1
|
|
||||||
table.current.Column = -1
|
|
||||||
*/
|
|
||||||
table.normalize = normalizeTableViewTag
|
table.normalize = normalizeTableViewTag
|
||||||
table.set = table.setFunc
|
table.set = table.setFunc
|
||||||
table.changed = table.propertyChanged
|
table.changed = table.propertyChanged
|
||||||
|
@ -853,8 +845,17 @@ func (table *tableViewData) propertyChanged(tag PropertyName) {
|
||||||
current := tableViewCurrent(table)
|
current := tableViewCurrent(table)
|
||||||
session.callFunc("setTableCellCursorByID", htmlID, current.Row, current.Column)
|
session.callFunc("setTableCellCursorByID", htmlID, current.Row, current.Column)
|
||||||
|
|
||||||
|
for _, listener := range getTwoArgEventListeners[TableView, int](table, nil, TableCellSelectedEvent) {
|
||||||
|
listener.Run(table, current.Row, current.Column)
|
||||||
|
}
|
||||||
|
|
||||||
case RowSelection:
|
case RowSelection:
|
||||||
session.callFunc("setTableRowCursorByID", htmlID, tableViewCurrent(table).Row)
|
current := tableViewCurrent(table)
|
||||||
|
session.callFunc("setTableRowCursorByID", htmlID, current.Row)
|
||||||
|
|
||||||
|
for _, listener := range getOneArgEventListeners[TableView, int](table, nil, TableRowSelectedEvent) {
|
||||||
|
listener.Run(table, current.Row)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case Gap:
|
case Gap:
|
||||||
|
@ -955,63 +956,6 @@ func tableViewCurrentInactiveStyle(view View) string {
|
||||||
return "ruiCurrentTableCell"
|
return "ruiCurrentTableCell"
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func (table *tableViewData) valueToCellListeners(value any) []func(TableView, int, int) {
|
|
||||||
if value == nil {
|
|
||||||
return []func(TableView, int, int){}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case func(TableView, int, int):
|
|
||||||
return []func(TableView, int, int){value}
|
|
||||||
|
|
||||||
case func(int, int):
|
|
||||||
fn := func(_ TableView, row, column int) {
|
|
||||||
value(row, column)
|
|
||||||
}
|
|
||||||
return []func(TableView, int, int){fn}
|
|
||||||
|
|
||||||
case []func(TableView, int, int):
|
|
||||||
return value
|
|
||||||
|
|
||||||
case []func(int, int):
|
|
||||||
listeners := make([]func(TableView, int, int), len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
if val == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ TableView, row, column int) {
|
|
||||||
val(row, column)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
listeners := make([]func(TableView, int, int), len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
if val == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
switch val := val.(type) {
|
|
||||||
case func(TableView, int, int):
|
|
||||||
listeners[i] = val
|
|
||||||
|
|
||||||
case func(int, int):
|
|
||||||
listeners[i] = func(_ TableView, row, column int) {
|
|
||||||
val(row, column)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (table *tableViewData) htmlTag() string {
|
func (table *tableViewData) htmlTag() string {
|
||||||
return "table"
|
return "table"
|
||||||
}
|
}
|
||||||
|
@ -1326,10 +1270,10 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
buffer.WriteString(string(value))
|
buffer.WriteString(string(value))
|
||||||
|
|
||||||
case float32:
|
case float32:
|
||||||
buffer.WriteString(fmt.Sprintf("%g", float64(value)))
|
fmt.Fprintf(buffer, "%g", float64(value))
|
||||||
|
|
||||||
case float64:
|
case float64:
|
||||||
buffer.WriteString(fmt.Sprintf("%g", value))
|
fmt.Fprintf(buffer, "%g", value)
|
||||||
|
|
||||||
case bool:
|
case bool:
|
||||||
if value {
|
if value {
|
||||||
|
@ -1340,7 +1284,7 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if n, ok := isInt(value); ok {
|
if n, ok := isInt(value); ok {
|
||||||
buffer.WriteString(fmt.Sprintf("%d", n))
|
fmt.Fprintf(buffer, "%d", n)
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString("<Unsupported value>")
|
buffer.WriteString("<Unsupported value>")
|
||||||
}
|
}
|
||||||
|
@ -1359,7 +1303,7 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
|
|
||||||
if columnStyle := GetTableColumnStyle(table); columnStyle != nil {
|
if columnStyle := GetTableColumnStyle(table); columnStyle != nil {
|
||||||
buffer.WriteString("<colgroup>")
|
buffer.WriteString("<colgroup>")
|
||||||
for column := 0; column < columnCount; column++ {
|
for column := range columnCount {
|
||||||
cssBuilder.buffer.Reset()
|
cssBuilder.buffer.Reset()
|
||||||
if styles := columnStyle.ColumnStyle(column); styles != nil {
|
if styles := columnStyle.ColumnStyle(column); styles != nil {
|
||||||
view.Clear()
|
view.Clear()
|
||||||
|
@ -1593,10 +1537,10 @@ func (table *tableViewData) writeCellHtml(adapter TableAdapter, row, column int,
|
||||||
buffer.WriteString(string(value))
|
buffer.WriteString(string(value))
|
||||||
|
|
||||||
case float32:
|
case float32:
|
||||||
buffer.WriteString(fmt.Sprintf("%g", float64(value)))
|
fmt.Fprintf(buffer, "%g", float64(value))
|
||||||
|
|
||||||
case float64:
|
case float64:
|
||||||
buffer.WriteString(fmt.Sprintf("%g", value))
|
fmt.Fprintf(buffer, "%g", value)
|
||||||
|
|
||||||
case bool:
|
case bool:
|
||||||
accentColor := Color(0)
|
accentColor := Color(0)
|
||||||
|
@ -1611,7 +1555,7 @@ func (table *tableViewData) writeCellHtml(adapter TableAdapter, row, column int,
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if n, ok := isInt(value); ok {
|
if n, ok := isInt(value); ok {
|
||||||
buffer.WriteString(fmt.Sprintf("%d", n))
|
fmt.Fprintf(buffer, "%d", n)
|
||||||
} else {
|
} else {
|
||||||
buffer.WriteString("<Unsupported value>")
|
buffer.WriteString("<Unsupported value>")
|
||||||
}
|
}
|
||||||
|
@ -1732,11 +1676,11 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data
|
||||||
current.Row = row
|
current.Row = row
|
||||||
table.setRaw(Current, current.Row)
|
table.setRaw(Current, current.Row)
|
||||||
if listener, ok := table.changeListener[Current]; ok {
|
if listener, ok := table.changeListener[Current]; ok {
|
||||||
listener(table, Current)
|
listener.Run(table, Current)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, listener := range GetTableRowSelectedListeners(table) {
|
for _, listener := range getOneArgEventListeners[TableView, int](table, nil, TableRowSelectedEvent) {
|
||||||
listener(table, row)
|
listener.Run(table, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1749,11 +1693,11 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data
|
||||||
current.Column = column
|
current.Column = column
|
||||||
table.setRaw(Current, current.Row)
|
table.setRaw(Current, current.Row)
|
||||||
if listener, ok := table.changeListener[Current]; ok {
|
if listener, ok := table.changeListener[Current]; ok {
|
||||||
listener(table, Current)
|
listener.Run(table, Current)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, listener := range GetTableCellSelectedListeners(table) {
|
for _, listener := range getTwoArgEventListeners[TableView, int](table, nil, TableCellSelectedEvent) {
|
||||||
listener(table, row, column)
|
listener.Run(table, row, column)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1761,16 +1705,16 @@ func (table *tableViewData) handleCommand(self View, command PropertyName, data
|
||||||
|
|
||||||
case "rowClick":
|
case "rowClick":
|
||||||
if row, ok := dataIntProperty(data, "row"); ok {
|
if row, ok := dataIntProperty(data, "row"); ok {
|
||||||
for _, listener := range GetTableRowClickedListeners(table) {
|
for _, listener := range getOneArgEventListeners[TableView, int](table, nil, TableRowClickedEvent) {
|
||||||
listener(table, row)
|
listener.Run(table, row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "cellClick":
|
case "cellClick":
|
||||||
if row, ok := dataIntProperty(data, "row"); ok {
|
if row, ok := dataIntProperty(data, "row"); ok {
|
||||||
if column, ok := dataIntProperty(data, "column"); ok {
|
if column, ok := dataIntProperty(data, "column"); ok {
|
||||||
for _, listener := range GetTableCellClickedListeners(table) {
|
for _, listener := range getTwoArgEventListeners[TableView, int](table, nil, TableCellClickedEvent) {
|
||||||
listener(table, row, column)
|
listener.Run(table, row, column)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@ func (cell *tableCellView) cssStyle(self View, builder cssBuilder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableContent returns a TableAdapter which defines the TableView content.
|
// GetTableContent returns a TableAdapter which defines the TableView content.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTableContent(view View, subviewID ...string) TableAdapter {
|
func GetTableContent(view View, subviewID ...string) TableAdapter {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if content := view.getRaw(Content); content != nil {
|
if content := view.getRaw(Content); content != nil {
|
||||||
|
@ -40,7 +42,9 @@ func GetTableContent(view View, subviewID ...string) TableAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableRowStyle returns a TableRowStyle which defines styles of TableView rows.
|
// GetTableRowStyle returns a TableRowStyle which defines styles of TableView rows.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTableRowStyle(view View, subviewID ...string) TableRowStyle {
|
func GetTableRowStyle(view View, subviewID ...string) TableRowStyle {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
for _, tag := range []PropertyName{RowStyle, Content} {
|
for _, tag := range []PropertyName{RowStyle, Content} {
|
||||||
|
@ -56,7 +60,9 @@ func GetTableRowStyle(view View, subviewID ...string) TableRowStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableColumnStyle returns a TableColumnStyle which defines styles of TableView columns.
|
// GetTableColumnStyle returns a TableColumnStyle which defines styles of TableView columns.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTableColumnStyle(view View, subviewID ...string) TableColumnStyle {
|
func GetTableColumnStyle(view View, subviewID ...string) TableColumnStyle {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
for _, tag := range []PropertyName{ColumnStyle, Content} {
|
for _, tag := range []PropertyName{ColumnStyle, Content} {
|
||||||
|
@ -72,7 +78,9 @@ func GetTableColumnStyle(view View, subviewID ...string) TableColumnStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableCellStyle returns a TableCellStyle which defines styles of TableView cells.
|
// GetTableCellStyle returns a TableCellStyle which defines styles of TableView cells.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTableCellStyle(view View, subviewID ...string) TableCellStyle {
|
func GetTableCellStyle(view View, subviewID ...string) TableCellStyle {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
for _, tag := range []PropertyName{CellStyle, Content} {
|
for _, tag := range []PropertyName{CellStyle, Content} {
|
||||||
|
@ -90,26 +98,34 @@ func GetTableCellStyle(view View, subviewID ...string) TableCellStyle {
|
||||||
|
|
||||||
// GetTableSelectionMode returns the mode of the TableView elements selection.
|
// GetTableSelectionMode returns the mode of the TableView elements selection.
|
||||||
// Valid values are NoneSelection (0), CellSelection (1), and RowSelection (2).
|
// Valid values are NoneSelection (0), CellSelection (1), and RowSelection (2).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTableSelectionMode(view View, subviewID ...string) int {
|
func GetTableSelectionMode(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, SelectionMode, NoneSelection, false)
|
return enumStyledProperty(view, subviewID, SelectionMode, NoneSelection, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableVerticalAlign returns a vertical align in a TableView cell. Returns one of next values:
|
// GetTableVerticalAlign returns a vertical align in a TableView cell. Returns one of next values:
|
||||||
// TopAlign (0), BottomAlign (1), CenterAlign (2), and BaselineAlign (3)
|
// TopAlign (0), BottomAlign (1), CenterAlign (2), and BaselineAlign (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTableVerticalAlign(view View, subviewID ...string) int {
|
func GetTableVerticalAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, TableVerticalAlign, TopAlign, false)
|
return enumStyledProperty(view, subviewID, TableVerticalAlign, TopAlign, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableHeadHeight returns the number of rows in the table header.
|
// GetTableHeadHeight returns the number of rows in the table header.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTableHeadHeight(view View, subviewID ...string) int {
|
func GetTableHeadHeight(view View, subviewID ...string) int {
|
||||||
return intStyledProperty(view, subviewID, HeadHeight, 0)
|
return intStyledProperty(view, subviewID, HeadHeight, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableFootHeight returns the number of rows in the table footer.
|
// GetTableFootHeight returns the number of rows in the table footer.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTableFootHeight(view View, subviewID ...string) int {
|
func GetTableFootHeight(view View, subviewID ...string) int {
|
||||||
return intStyledProperty(view, subviewID, FootHeight, 0)
|
return intStyledProperty(view, subviewID, FootHeight, 0)
|
||||||
}
|
}
|
||||||
|
@ -118,7 +134,9 @@ func GetTableFootHeight(view View, subviewID ...string) int {
|
||||||
// If there is no selected cell/row or the selection mode is NoneSelection (0),
|
// If there is no selected cell/row or the selection mode is NoneSelection (0),
|
||||||
// then a value of the row and column index less than 0 is returned.
|
// then a value of the row and column index less than 0 is returned.
|
||||||
// If the selection mode is RowSelection (2) then the returned column index is less than 0.
|
// If the selection mode is RowSelection (2) then the returned column index is less than 0.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTableCurrent(view View, subviewID ...string) CellIndex {
|
func GetTableCurrent(view View, subviewID ...string) CellIndex {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if selectionMode := GetTableSelectionMode(view); selectionMode != NoneSelection {
|
if selectionMode := GetTableSelectionMode(view); selectionMode != NoneSelection {
|
||||||
|
@ -130,30 +148,70 @@ func GetTableCurrent(view View, subviewID ...string) CellIndex {
|
||||||
|
|
||||||
// GetTableCellClickedListeners returns listeners of event which occurs when the user clicks on a table cell.
|
// GetTableCellClickedListeners returns listeners of event which occurs when the user clicks on a table cell.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTableCellClickedListeners(view View, subviewID ...string) []func(TableView, int, int) {
|
// Result elements can be of the following types:
|
||||||
return getTwoArgEventListeners[TableView, int](view, subviewID, TableCellClickedEvent)
|
// - func(rui.TableView, int, int),
|
||||||
|
// - func(rui.TableView, int),
|
||||||
|
// - func(rui.TableView),
|
||||||
|
// - func(int, int),
|
||||||
|
// - func(int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTableCellClickedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getTwoArgEventRawListeners[TableView, int](view, subviewID, TableCellClickedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableCellSelectedListeners returns listeners of event which occurs when a table cell becomes selected.
|
// GetTableCellSelectedListeners returns listeners of event which occurs when a table cell becomes selected.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTableCellSelectedListeners(view View, subviewID ...string) []func(TableView, int, int) {
|
// Result elements can be of the following types:
|
||||||
return getTwoArgEventListeners[TableView, int](view, subviewID, TableCellSelectedEvent)
|
// - func(rui.TableView, int, int),
|
||||||
|
// - func(rui.TableView, int),
|
||||||
|
// - func(rui.TableView),
|
||||||
|
// - func(int, int),
|
||||||
|
// - func(int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTableCellSelectedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getTwoArgEventRawListeners[TableView, int](view, subviewID, TableCellSelectedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableRowClickedListeners returns listeners of event which occurs when the user clicks on a table row.
|
// GetTableRowClickedListeners returns listeners of event which occurs when the user clicks on a table row.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTableRowClickedListeners(view View, subviewID ...string) []func(TableView, int) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[TableView, int](view, subviewID, TableRowClickedEvent)
|
// - func(rui.TableView, int),
|
||||||
|
// - func(rui.TableView),
|
||||||
|
// - func(int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTableRowClickedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[TableView, int](view, subviewID, TableRowClickedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTableRowSelectedListeners returns listeners of event which occurs when a table row becomes selected.
|
// GetTableRowSelectedListeners returns listeners of event which occurs when a table row becomes selected.
|
||||||
// If there are no listeners then the empty list is returned.
|
// If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTableRowSelectedListeners(view View, subviewID ...string) []func(TableView, int) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[TableView, int](view, subviewID, TableRowSelectedEvent)
|
// - func(rui.TableView, int),
|
||||||
|
// - func(rui.TableView),
|
||||||
|
// - func(int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTableRowSelectedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[TableView, int](view, subviewID, TableRowSelectedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReloadTableViewData updates TableView
|
// ReloadTableViewData updates TableView
|
||||||
|
|
201
tabsLayout.go
201
tabsLayout.go
|
@ -211,7 +211,7 @@ func (tabsLayout *tabsLayoutData) propertyChanged(tag PropertyName) {
|
||||||
if listeners := getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent); len(listeners) > 0 {
|
if listeners := getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent); len(listeners) > 0 {
|
||||||
oldCurrent, _ := intProperty(tabsLayout, "old-current", session, -1)
|
oldCurrent, _ := intProperty(tabsLayout, "old-current", session, -1)
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(tabsLayout, current, oldCurrent)
|
listener.Run(tabsLayout, current, oldCurrent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,155 +238,6 @@ func (tabsLayout *tabsLayoutData) propertyChanged(tag PropertyName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayout, int, int) {
|
|
||||||
if value == nil {
|
|
||||||
return []func(TabsLayout, int, int){}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch value := value.(type) {
|
|
||||||
case func(TabsLayout, int, int):
|
|
||||||
return []func(TabsLayout, int, int){value}
|
|
||||||
|
|
||||||
case func(TabsLayout, int):
|
|
||||||
fn := func(view TabsLayout, current, _ int) {
|
|
||||||
value(view, current)
|
|
||||||
}
|
|
||||||
return []func(TabsLayout, int, int){fn}
|
|
||||||
|
|
||||||
case func(TabsLayout):
|
|
||||||
fn := func(view TabsLayout, _, _ int) {
|
|
||||||
value(view)
|
|
||||||
}
|
|
||||||
return []func(TabsLayout, int, int){fn}
|
|
||||||
|
|
||||||
case func(int, int):
|
|
||||||
fn := func(_ TabsLayout, current, old int) {
|
|
||||||
value(current, old)
|
|
||||||
}
|
|
||||||
return []func(TabsLayout, int, int){fn}
|
|
||||||
|
|
||||||
case func(int):
|
|
||||||
fn := func(_ TabsLayout, current, _ int) {
|
|
||||||
value(current)
|
|
||||||
}
|
|
||||||
return []func(TabsLayout, int, int){fn}
|
|
||||||
|
|
||||||
case func():
|
|
||||||
fn := func(TabsLayout, int, int) {
|
|
||||||
value()
|
|
||||||
}
|
|
||||||
return []func(TabsLayout, int, int){fn}
|
|
||||||
|
|
||||||
case []func(TabsLayout, int, int):
|
|
||||||
return value
|
|
||||||
|
|
||||||
case []func(TabsLayout, int):
|
|
||||||
listeners := make([]func(TabsLayout, int, int), len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
if val == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
listeners[i] = func(view TabsLayout, current, _ int) {
|
|
||||||
val(view, current)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners
|
|
||||||
|
|
||||||
case []func(TabsLayout):
|
|
||||||
listeners := make([]func(TabsLayout, int, int), len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
if val == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
listeners[i] = func(view TabsLayout, _, _ int) {
|
|
||||||
val(view)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners
|
|
||||||
|
|
||||||
case []func(int, int):
|
|
||||||
listeners := make([]func(TabsLayout, int, int), len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
if val == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ TabsLayout, current, old int) {
|
|
||||||
val(current, old)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners
|
|
||||||
|
|
||||||
case []func(int):
|
|
||||||
listeners := make([]func(TabsLayout, int, int), len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
if val == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
listeners[i] = func(_ TabsLayout, current, _ int) {
|
|
||||||
val(current)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners
|
|
||||||
|
|
||||||
case []func():
|
|
||||||
listeners := make([]func(TabsLayout, int, int), len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
if val == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
listeners[i] = func(TabsLayout, int, int) {
|
|
||||||
val()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners
|
|
||||||
|
|
||||||
case []any:
|
|
||||||
listeners := make([]func(TabsLayout, int, int), len(value))
|
|
||||||
for i, val := range value {
|
|
||||||
if val == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
switch val := val.(type) {
|
|
||||||
case func(TabsLayout, int, int):
|
|
||||||
listeners[i] = val
|
|
||||||
|
|
||||||
case func(TabsLayout, int):
|
|
||||||
listeners[i] = func(view TabsLayout, current, _ int) {
|
|
||||||
val(view, current)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(TabsLayout):
|
|
||||||
listeners[i] = func(view TabsLayout, _, _ int) {
|
|
||||||
val(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(int, int):
|
|
||||||
listeners[i] = func(_ TabsLayout, current, old int) {
|
|
||||||
val(current, old)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func(int):
|
|
||||||
listeners[i] = func(_ TabsLayout, current, _ int) {
|
|
||||||
val(current)
|
|
||||||
}
|
|
||||||
|
|
||||||
case func():
|
|
||||||
listeners[i] = func(TabsLayout, int, int) {
|
|
||||||
val()
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listeners
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) tabsLocation() int {
|
func (tabsLayout *tabsLayoutData) tabsLocation() int {
|
||||||
tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0)
|
tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0)
|
||||||
return tabs
|
return tabs
|
||||||
|
@ -504,7 +355,7 @@ func (tabsLayout *tabsLayoutData) ListItem(index int, session Session) View {
|
||||||
Content: "✕",
|
Content: "✕",
|
||||||
ClickEvent: func() {
|
ClickEvent: func() {
|
||||||
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
|
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
|
||||||
listener(tabsLayout, index)
|
listener.Run(tabsLayout, index)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
@ -552,9 +403,7 @@ func (tabsLayout *tabsLayoutData) Append(view View) {
|
||||||
view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton)
|
view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton)
|
||||||
if tabsLayout.created {
|
if tabsLayout.created {
|
||||||
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
|
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
|
||||||
if listener, ok := tabsLayout.changeListener[Content]; ok {
|
tabsLayout.contentChanged()
|
||||||
listener(tabsLayout, Content)
|
|
||||||
}
|
|
||||||
tabsLayout.Set(Current, len(tabsLayout.views)-1)
|
tabsLayout.Set(Current, len(tabsLayout.views)-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -576,11 +425,9 @@ func (tabsLayout *tabsLayoutData) Insert(view View, index int) {
|
||||||
|
|
||||||
func (tabsLayout *tabsLayoutData) currentChanged(newCurrent, oldCurrent int) {
|
func (tabsLayout *tabsLayoutData) currentChanged(newCurrent, oldCurrent int) {
|
||||||
for _, listener := range getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) {
|
for _, listener := range getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) {
|
||||||
listener(tabsLayout, newCurrent, oldCurrent)
|
listener.Run(tabsLayout, newCurrent, oldCurrent)
|
||||||
}
|
|
||||||
if listener, ok := tabsLayout.changeListener[Current]; ok {
|
|
||||||
listener(tabsLayout, Current)
|
|
||||||
}
|
}
|
||||||
|
tabsLayout.contentChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes view from list and return it
|
// Remove removes view from list and return it
|
||||||
|
@ -606,9 +453,7 @@ func (tabsLayout *tabsLayoutData) RemoveView(index int) View {
|
||||||
tabsLayout.Set(Current, newCurrent)
|
tabsLayout.Set(Current, newCurrent)
|
||||||
}
|
}
|
||||||
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
|
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
|
||||||
if listener, ok := tabsLayout.changeListener[Content]; ok {
|
tabsLayout.contentChanged()
|
||||||
listener(tabsLayout, Content)
|
|
||||||
}
|
|
||||||
} else if newCurrent != oldCurrent {
|
} else if newCurrent != oldCurrent {
|
||||||
tabsLayout.setRaw(Current, newCurrent)
|
tabsLayout.setRaw(Current, newCurrent)
|
||||||
}
|
}
|
||||||
|
@ -892,7 +737,7 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName,
|
||||||
if numberText, ok := data.PropertyValue("number"); ok {
|
if numberText, ok := data.PropertyValue("number"); ok {
|
||||||
if number, err := strconv.Atoi(numberText); err == nil {
|
if number, err := strconv.Atoi(numberText); err == nil {
|
||||||
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
|
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
|
||||||
listener(tabsLayout, number)
|
listener.Run(tabsLayout, number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -900,3 +745,35 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName,
|
||||||
}
|
}
|
||||||
return tabsLayout.viewsContainerData.handleCommand(self, command, data)
|
return tabsLayout.viewsContainerData.handleCommand(self, command, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTabCloseEventListeners returns the "tab-close-event" listener list. If there are no listeners then the empty list is returned.
|
||||||
|
//
|
||||||
|
// Result elements can be of the following types:
|
||||||
|
// - func(rui.TabsLayout, int),
|
||||||
|
// - func(rui.TabsLayout),
|
||||||
|
// - func(int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTabCloseEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[TabsLayout, int](view, subviewID, TabCloseEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentTabChangedEventListeners returns the "current-tab-changed" listener list. If there are no listeners then the empty list is returned.
|
||||||
|
//
|
||||||
|
// Result elements can be of the following types:
|
||||||
|
// - func(rui.TabsLayout, int, int),
|
||||||
|
// - func(rui.TabsLayout, int),
|
||||||
|
// - func(rui.TabsLayout),
|
||||||
|
// - func(int, int),
|
||||||
|
// - func(int),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetCurrentTabChangedEventListeners(view View, subviewID ...string) []any {
|
||||||
|
return getTwoArgEventRawListeners[TabsLayout, int](view, subviewID, CurrentTabChangedEvent)
|
||||||
|
}
|
||||||
|
|
|
@ -111,7 +111,9 @@ func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) {
|
||||||
|
|
||||||
// GetTextOverflow returns a value of the "text-overflow" property:
|
// GetTextOverflow returns a value of the "text-overflow" property:
|
||||||
// TextOverflowClip (0) or TextOverflowEllipsis (1).
|
// TextOverflowClip (0) or TextOverflowEllipsis (1).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextOverflow(view View, subviewID ...string) int {
|
func GetTextOverflow(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, TextOverflow, SingleLineText, false)
|
return enumStyledProperty(view, subviewID, TextOverflow, SingleLineText, false)
|
||||||
}
|
}
|
||||||
|
|
19
theme.go
19
theme.go
|
@ -686,8 +686,11 @@ func (theme *theme) addText(themeText string) bool {
|
||||||
theme.init()
|
theme.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
data := ParseDataText(themeText)
|
data, err := ParseDataText(themeText)
|
||||||
if data == nil || !data.IsObject() || data.Tag() != "theme" {
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return false
|
||||||
|
} else if !data.IsObject() || data.Tag() != "theme" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,10 +978,10 @@ func (theme *theme) String() string {
|
||||||
buffer.WriteString(":landscape")
|
buffer.WriteString(":landscape")
|
||||||
}
|
}
|
||||||
if maxWidth > 0 {
|
if maxWidth > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(":width%d", maxWidth))
|
fmt.Fprintf(buffer, ":width%d", maxWidth)
|
||||||
}
|
}
|
||||||
if maxHeight > 0 {
|
if maxHeight > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(":height%d", maxHeight))
|
fmt.Fprintf(buffer, ":height%d", maxHeight)
|
||||||
}
|
}
|
||||||
buffer.WriteString(" = [\n")
|
buffer.WriteString(" = [\n")
|
||||||
|
|
||||||
|
@ -1014,21 +1017,21 @@ func (theme *theme) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if media.MinWidth > 0 {
|
if media.MinWidth > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(":width%d-", media.MinWidth))
|
fmt.Fprintf(buffer, ":width%d-", media.MinWidth)
|
||||||
if media.MaxWidth > 0 {
|
if media.MaxWidth > 0 {
|
||||||
buffer.WriteString(strconv.Itoa(media.MaxWidth))
|
buffer.WriteString(strconv.Itoa(media.MaxWidth))
|
||||||
}
|
}
|
||||||
} else if media.MaxWidth > 0 {
|
} else if media.MaxWidth > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(":width%d", media.MaxWidth))
|
fmt.Fprintf(buffer, ":width%d", media.MaxWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
if media.MinHeight > 0 {
|
if media.MinHeight > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(":height%d-", media.MinHeight))
|
fmt.Fprintf(buffer, ":height%d-", media.MinHeight)
|
||||||
if media.MaxHeight > 0 {
|
if media.MaxHeight > 0 {
|
||||||
buffer.WriteString(strconv.Itoa(media.MaxHeight))
|
buffer.WriteString(strconv.Itoa(media.MaxHeight))
|
||||||
}
|
}
|
||||||
} else if media.MaxHeight > 0 {
|
} else if media.MaxHeight > 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(":height%d", media.MaxHeight))
|
fmt.Fprintf(buffer, ":height%d", media.MaxHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(" = [\n")
|
buffer.WriteString(" = [\n")
|
||||||
|
|
|
@ -246,7 +246,7 @@ func (picker *timePickerData) propertyChanged(tag PropertyName) {
|
||||||
value := GetTimePickerValue(picker)
|
value := GetTimePickerValue(picker)
|
||||||
session.callFunc("setInputValue", picker.htmlID(), value.Format(timeFormat))
|
session.callFunc("setInputValue", picker.htmlID(), value.Format(timeFormat))
|
||||||
|
|
||||||
if listeners := GetTimeChangedListeners(picker); len(listeners) > 0 {
|
if listeners := getTwoArgEventListeners[TimePicker, time.Time](picker, nil, TimeChangedEvent); len(listeners) > 0 {
|
||||||
oldTime := time.Now()
|
oldTime := time.Now()
|
||||||
if val := picker.getRaw("old-time"); val != nil {
|
if val := picker.getRaw("old-time"); val != nil {
|
||||||
if time, ok := val.(time.Time); ok {
|
if time, ok := val.(time.Time); ok {
|
||||||
|
@ -254,7 +254,7 @@ func (picker *timePickerData) propertyChanged(tag PropertyName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(picker, value, oldTime)
|
listener.Run(picker, value, oldTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,11 +320,11 @@ func (picker *timePickerData) handleCommand(self View, command PropertyName, dat
|
||||||
oldValue := GetTimePickerValue(picker)
|
oldValue := GetTimePickerValue(picker)
|
||||||
picker.properties[TimePickerValue] = value
|
picker.properties[TimePickerValue] = value
|
||||||
if value != oldValue {
|
if value != oldValue {
|
||||||
for _, listener := range GetTimeChangedListeners(picker) {
|
for _, listener := range getTwoArgEventListeners[TimePicker, time.Time](picker, nil, TimeChangedEvent) {
|
||||||
listener(picker, value, oldValue)
|
listener.Run(picker, value, oldValue)
|
||||||
}
|
}
|
||||||
if listener, ok := picker.changeListener[TimePickerValue]; ok {
|
if listener, ok := picker.changeListener[TimePickerValue]; ok {
|
||||||
listener(picker, TimePickerValue)
|
listener.Run(picker, TimePickerValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -373,7 +373,9 @@ func getTimeProperty(view View, mainTag, shortTag PropertyName) (time.Time, bool
|
||||||
|
|
||||||
// GetTimePickerMin returns the min time of TimePicker subview and "true" as the second value if the min time is set,
|
// GetTimePickerMin returns the min time of TimePicker subview and "true" as the second value if the min time is set,
|
||||||
// "false" as the second value otherwise.
|
// "false" as the second value otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTimePickerMin(view View, subviewID ...string) (time.Time, bool) {
|
func GetTimePickerMin(view View, subviewID ...string) (time.Time, bool) {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
return getTimeProperty(view, TimePickerMin, Min)
|
return getTimeProperty(view, TimePickerMin, Min)
|
||||||
|
@ -383,7 +385,9 @@ func GetTimePickerMin(view View, subviewID ...string) (time.Time, bool) {
|
||||||
|
|
||||||
// GetTimePickerMax returns the max time of TimePicker subview and "true" as the second value if the min time is set,
|
// GetTimePickerMax returns the max time of TimePicker subview and "true" as the second value if the min time is set,
|
||||||
// "false" as the second value otherwise.
|
// "false" as the second value otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTimePickerMax(view View, subviewID ...string) (time.Time, bool) {
|
func GetTimePickerMax(view View, subviewID ...string) (time.Time, bool) {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
return getTimeProperty(view, TimePickerMax, Max)
|
return getTimeProperty(view, TimePickerMax, Max)
|
||||||
|
@ -392,13 +396,17 @@ func GetTimePickerMax(view View, subviewID ...string) (time.Time, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTimePickerStep returns the time changing step in seconds of TimePicker subview.
|
// GetTimePickerStep returns the time changing step in seconds of TimePicker subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTimePickerStep(view View, subviewID ...string) int {
|
func GetTimePickerStep(view View, subviewID ...string) int {
|
||||||
return intStyledProperty(view, subviewID, TimePickerStep, 60)
|
return intStyledProperty(view, subviewID, TimePickerStep, 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTimePickerValue returns the time of TimePicker subview.
|
// GetTimePickerValue returns the time of TimePicker subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTimePickerValue(view View, subviewID ...string) time.Time {
|
func GetTimePickerValue(view View, subviewID ...string) time.Time {
|
||||||
if view = getSubview(view, subviewID); view == nil {
|
if view = getSubview(view, subviewID); view == nil {
|
||||||
return time.Now()
|
return time.Now()
|
||||||
|
@ -409,7 +417,18 @@ func GetTimePickerValue(view View, subviewID ...string) time.Time {
|
||||||
|
|
||||||
// GetTimeChangedListeners returns the TimeChangedListener list of an TimePicker subview.
|
// GetTimeChangedListeners returns the TimeChangedListener list of an TimePicker subview.
|
||||||
// If there are no listeners then the empty list is returned
|
// If there are no listeners then the empty list is returned
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTimeChangedListeners(view View, subviewID ...string) []func(TimePicker, time.Time, time.Time) {
|
// Result elements can be of the following types:
|
||||||
return getTwoArgEventListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent)
|
// - func(rui.TimePicker, time.Time, time.Time),
|
||||||
|
// - func(rui.TimePicker, time.Time),
|
||||||
|
// - func(rui.TimePicker),
|
||||||
|
// - func(time.Time, time.Time),
|
||||||
|
// - func(time.Time),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTimeChangedListeners(view View, subviewID ...string) []any {
|
||||||
|
return getTwoArgEventRawListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,30 +193,66 @@ func handleTouchEvents(view View, tag PropertyName, data DataObject) {
|
||||||
event.init(data)
|
event.init(data)
|
||||||
|
|
||||||
for _, listener := range listeners {
|
for _, listener := range listeners {
|
||||||
listener(view, event)
|
listener.Run(view, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTouchStartListeners returns the "touch-start" listener list. If there are no listeners then the empty list is returned.
|
// GetTouchStartListeners returns the "touch-start" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTouchStartListeners(view View, subviewID ...string) []func(View, TouchEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchStart)
|
// - func(rui.View, rui.TouchEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.TouchEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTouchStartListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, TouchEvent](view, subviewID, TouchStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTouchEndListeners returns the "touch-end" listener list. If there are no listeners then the empty list is returned.
|
// GetTouchEndListeners returns the "touch-end" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTouchEndListeners(view View, subviewID ...string) []func(View, TouchEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchEnd)
|
// - func(rui.View, rui.TouchEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.TouchEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTouchEndListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, TouchEvent](view, subviewID, TouchEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTouchMoveListeners returns the "touch-move" listener list. If there are no listeners then the empty list is returned.
|
// GetTouchMoveListeners returns the "touch-move" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTouchMoveListeners(view View, subviewID ...string) []func(View, TouchEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchMove)
|
// - func(rui.View, rui.TouchEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.TouchEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTouchMoveListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, TouchEvent](view, subviewID, TouchMove)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTouchCancelListeners returns the "touch-cancel" listener list. If there are no listeners then the empty list is returned.
|
// GetTouchCancelListeners returns the "touch-cancel" listener list. If there are no listeners then the empty list is returned.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
func GetTouchCancelListeners(view View, subviewID ...string) []func(View, TouchEvent) {
|
// Result elements can be of the following types:
|
||||||
return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchCancel)
|
// - func(rui.View, rui.TouchEvent),
|
||||||
|
// - func(rui.View),
|
||||||
|
// - func(rui.TouchEvent),
|
||||||
|
// - func(),
|
||||||
|
// - string.
|
||||||
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
|
func GetTouchCancelListeners(view View, subviewID ...string) []any {
|
||||||
|
return getOneArgEventRawListeners[View, TouchEvent](view, subviewID, TouchCancel)
|
||||||
}
|
}
|
||||||
|
|
41
transform.go
41
transform.go
|
@ -398,7 +398,10 @@ func valueToTransformProperty(value any) TransformProperty {
|
||||||
}
|
}
|
||||||
|
|
||||||
case string:
|
case string:
|
||||||
if obj := ParseDataText(value); obj != nil {
|
obj, err := ParseDataText(value)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
return parseObject(obj)
|
return parseObject(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,7 +650,9 @@ func transformOriginCSS(x, y, z SizeUnit, session Session) string {
|
||||||
|
|
||||||
// GetTransform returns a view transform: translation, scale and rotation over x, y and z axes as well as a distortion of a view along x and y axes.
|
// GetTransform returns a view transform: translation, scale and rotation over x, y and z axes as well as a distortion of a view along x and y axes.
|
||||||
// The default value is nil (no transform)
|
// The default value is nil (no transform)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTransform(view View, subviewID ...string) TransformProperty {
|
func GetTransform(view View, subviewID ...string) TransformProperty {
|
||||||
return transformStyledProperty(view, subviewID, Transform)
|
return transformStyledProperty(view, subviewID, Transform)
|
||||||
}
|
}
|
||||||
|
@ -655,14 +660,18 @@ func GetTransform(view View, subviewID ...string) TransformProperty {
|
||||||
// GetPerspective returns a distance between the z = 0 plane and the user in order to give a 3D-positioned
|
// GetPerspective returns a distance between the z = 0 plane and the user in order to give a 3D-positioned
|
||||||
// element some perspective. Each 3D element with z > 0 becomes larger; each 3D-element with z < 0 becomes smaller.
|
// element some perspective. Each 3D element with z > 0 becomes larger; each 3D-element with z < 0 becomes smaller.
|
||||||
// The default value is 0 (no 3D effects).
|
// The default value is 0 (no 3D effects).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetPerspective(view View, subviewID ...string) SizeUnit {
|
func GetPerspective(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, Perspective, false)
|
return sizeStyledProperty(view, subviewID, Perspective, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPerspectiveOrigin returns a x- and y-coordinate of the position at which the viewer is looking.
|
// GetPerspectiveOrigin returns a x- and y-coordinate of the position at which the viewer is looking.
|
||||||
// It is used as the vanishing point by the Perspective property. The default value is (50%, 50%).
|
// It is used as the vanishing point by the Perspective property. The default value is (50%, 50%).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetPerspectiveOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit) {
|
func GetPerspectiveOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit) {
|
||||||
view = getSubview(view, subviewID)
|
view = getSubview(view, subviewID)
|
||||||
if view == nil {
|
if view == nil {
|
||||||
|
@ -675,14 +684,18 @@ func GetPerspectiveOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit) {
|
||||||
// visible when turned towards the user. Values:
|
// visible when turned towards the user. Values:
|
||||||
// true - the back face is visible when turned towards the user (default value).
|
// true - the back face is visible when turned towards the user (default value).
|
||||||
// false - the back face is hidden, effectively making the element invisible when turned away from the user.
|
// false - the back face is hidden, effectively making the element invisible when turned away from the user.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetBackfaceVisible(view View, subviewID ...string) bool {
|
func GetBackfaceVisible(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, BackfaceVisible, false)
|
return boolStyledProperty(view, subviewID, BackfaceVisible, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransformOrigin returns a x-, y-, and z-coordinate of the point around which a view transformation is applied.
|
// GetTransformOrigin returns a x-, y-, and z-coordinate of the point around which a view transformation is applied.
|
||||||
// The default value is (50%, 50%, 50%).
|
// The default value is (50%, 50%, 50%).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTransformOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) {
|
func GetTransformOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) {
|
||||||
view = getSubview(view, subviewID)
|
view = getSubview(view, subviewID)
|
||||||
if view == nil {
|
if view == nil {
|
||||||
|
@ -692,7 +705,9 @@ func GetTransformOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit, Siz
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTranslate returns a x-, y-, and z-axis translation value of a 2D/3D translation
|
// GetTranslate returns a x-, y-, and z-axis translation value of a 2D/3D translation
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTranslate(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) {
|
func GetTranslate(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) {
|
||||||
if transform := GetTransform(view, subviewID...); transform != nil {
|
if transform := GetTransform(view, subviewID...); transform != nil {
|
||||||
return transform.getTranslate(view.Session())
|
return transform.getTranslate(view.Session())
|
||||||
|
@ -702,7 +717,9 @@ func GetTranslate(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit)
|
||||||
|
|
||||||
// GetSkew returns a angles to use to distort the element along the abscissa (x-axis)
|
// GetSkew returns a angles to use to distort the element along the abscissa (x-axis)
|
||||||
// and the ordinate (y-axis). The default value is 0.
|
// and the ordinate (y-axis). The default value is 0.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetSkew(view View, subviewID ...string) (AngleUnit, AngleUnit) {
|
func GetSkew(view View, subviewID ...string) (AngleUnit, AngleUnit) {
|
||||||
if transform := GetTransform(view, subviewID...); transform != nil {
|
if transform := GetTransform(view, subviewID...); transform != nil {
|
||||||
x, y, _ := transform.getSkew(view.Session())
|
x, y, _ := transform.getSkew(view.Session())
|
||||||
|
@ -712,7 +729,9 @@ func GetSkew(view View, subviewID ...string) (AngleUnit, AngleUnit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetScale returns a x-, y-, and z-axis scaling value of a 2D/3D scale. The default value is 1.
|
// GetScale returns a x-, y-, and z-axis scaling value of a 2D/3D scale. The default value is 1.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetScale(view View, subviewID ...string) (float64, float64, float64) {
|
func GetScale(view View, subviewID ...string) (float64, float64, float64) {
|
||||||
if transform := GetTransform(view, subviewID...); transform != nil {
|
if transform := GetTransform(view, subviewID...); transform != nil {
|
||||||
session := view.Session()
|
session := view.Session()
|
||||||
|
@ -725,7 +744,9 @@ func GetScale(view View, subviewID ...string) (float64, float64, float64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRotate returns a x-, y, z-coordinate of the vector denoting the axis of rotation, and the angle of the view rotation
|
// GetRotate returns a x-, y, z-coordinate of the vector denoting the axis of rotation, and the angle of the view rotation
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetRotate(view View, subviewID ...string) (float64, float64, float64, AngleUnit) {
|
func GetRotate(view View, subviewID ...string) (float64, float64, float64, AngleUnit) {
|
||||||
if transform := GetTransform(view, subviewID...); transform != nil {
|
if transform := GetTransform(view, subviewID...); transform != nil {
|
||||||
session := view.Session()
|
session := view.Session()
|
||||||
|
|
141
view.go
141
view.go
|
@ -30,6 +30,8 @@ func (frame Frame) Bottom() float64 {
|
||||||
return frame.Top + frame.Height
|
return frame.Top + frame.Height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changeListeners PropertyName = "change-listeners"
|
||||||
|
|
||||||
// View represents a base view interface
|
// View represents a base view interface
|
||||||
type View interface {
|
type View interface {
|
||||||
ViewStyle
|
ViewStyle
|
||||||
|
@ -66,8 +68,18 @@ type View interface {
|
||||||
// a description of the error is written to the log
|
// a description of the error is written to the log
|
||||||
SetAnimated(tag PropertyName, value any, animation AnimationProperty) bool
|
SetAnimated(tag PropertyName, value any, animation AnimationProperty) bool
|
||||||
|
|
||||||
// SetChangeListener set the function to track the change of the View property
|
// SetChangeListener set the function (the second argument) to track the change of the View property (the first argument).
|
||||||
SetChangeListener(tag PropertyName, listener func(View, PropertyName))
|
//
|
||||||
|
// Allowed listener function formats:
|
||||||
|
//
|
||||||
|
// func(view rui.View, property rui.PropertyName)
|
||||||
|
// func(view rui.View)
|
||||||
|
// func(property rui.PropertyName)
|
||||||
|
// func()
|
||||||
|
// string
|
||||||
|
//
|
||||||
|
// If the second argument is given as a string, it specifies the name of the binding function.
|
||||||
|
SetChangeListener(tag PropertyName, listener any) bool
|
||||||
|
|
||||||
// HasFocus returns 'true' if the view has focus
|
// HasFocus returns 'true' if the view has focus
|
||||||
HasFocus() bool
|
HasFocus() bool
|
||||||
|
@ -90,8 +102,9 @@ type View interface {
|
||||||
htmlProperties(self View, buffer *strings.Builder)
|
htmlProperties(self View, buffer *strings.Builder)
|
||||||
cssStyle(self View, builder cssBuilder)
|
cssStyle(self View, builder cssBuilder)
|
||||||
addToCSSStyle(addCSS map[string]string)
|
addToCSSStyle(addCSS map[string]string)
|
||||||
exscludeTags() []PropertyName
|
excludeTags() []PropertyName
|
||||||
htmlDisabledProperty() bool
|
htmlDisabledProperty() bool
|
||||||
|
binding() any
|
||||||
|
|
||||||
onResize(self View, x, y, width, height float64)
|
onResize(self View, x, y, width, height float64)
|
||||||
onItemResize(self View, index string, x, y, width, height float64)
|
onItemResize(self View, index string, x, y, width, height float64)
|
||||||
|
@ -109,7 +122,7 @@ type viewData struct {
|
||||||
_htmlID string
|
_htmlID string
|
||||||
parentID string
|
parentID string
|
||||||
systemClass string
|
systemClass string
|
||||||
changeListener map[PropertyName]func(View, PropertyName)
|
changeListener map[PropertyName]oneArgListener[View, PropertyName]
|
||||||
singleTransition map[PropertyName]AnimationProperty
|
singleTransition map[PropertyName]AnimationProperty
|
||||||
addCSS map[string]string
|
addCSS map[string]string
|
||||||
frame Frame
|
frame Frame
|
||||||
|
@ -161,7 +174,7 @@ func (view *viewData) init(session Session) {
|
||||||
view.changed = view.propertyChanged
|
view.changed = view.propertyChanged
|
||||||
view.tag = "View"
|
view.tag = "View"
|
||||||
view.session = session
|
view.session = session
|
||||||
view.changeListener = map[PropertyName]func(View, PropertyName){}
|
view.changeListener = map[PropertyName]oneArgListener[View, PropertyName]{}
|
||||||
view.addCSS = map[string]string{}
|
view.addCSS = map[string]string{}
|
||||||
//view.animation = map[string]AnimationEndListener{}
|
//view.animation = map[string]AnimationEndListener{}
|
||||||
view.singleTransition = map[PropertyName]AnimationProperty{}
|
view.singleTransition = map[PropertyName]AnimationProperty{}
|
||||||
|
@ -195,6 +208,18 @@ func (view *viewData) ID() string {
|
||||||
return view.viewID
|
return view.viewID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (view *viewData) binding() any {
|
||||||
|
if result := view.getRaw(Binding); result != nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
if parent := view.Parent(); parent != nil {
|
||||||
|
return parent.binding()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (view *viewData) ViewByID(id string) View {
|
func (view *viewData) ViewByID(id string) View {
|
||||||
if id == view.ID() {
|
if id == view.ID() {
|
||||||
if v := view.session.viewByHTMLID(view.htmlID()); v != nil {
|
if v := view.session.viewByHTMLID(view.htmlID()); v != nil {
|
||||||
|
@ -229,11 +254,8 @@ func (view *viewData) Remove(tag PropertyName) {
|
||||||
if view.created && len(changedTags) > 0 {
|
if view.created && len(changedTags) > 0 {
|
||||||
for _, tag := range changedTags {
|
for _, tag := range changedTags {
|
||||||
view.changed(tag)
|
view.changed(tag)
|
||||||
}
|
|
||||||
|
|
||||||
for _, tag := range changedTags {
|
|
||||||
if listener, ok := view.changeListener[tag]; ok {
|
if listener, ok := view.changeListener[tag]; ok {
|
||||||
listener(view, tag)
|
listener.Run(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,11 +282,8 @@ func (view *viewData) Set(tag PropertyName, value any) bool {
|
||||||
if view.created && len(changedTags) > 0 {
|
if view.created && len(changedTags) > 0 {
|
||||||
for _, tag := range changedTags {
|
for _, tag := range changedTags {
|
||||||
view.changed(tag)
|
view.changed(tag)
|
||||||
}
|
|
||||||
|
|
||||||
for _, tag := range changedTags {
|
|
||||||
if listener, ok := view.changeListener[tag]; ok {
|
if listener, ok := view.changeListener[tag]; ok {
|
||||||
listener(view, tag)
|
listener.Run(view, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,7 +301,8 @@ func normalizeViewTag(tag PropertyName) PropertyName {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) getFunc(tag PropertyName) any {
|
func (view *viewData) getFunc(tag PropertyName) any {
|
||||||
if tag == ID {
|
switch tag {
|
||||||
|
case ID:
|
||||||
if id := view.ID(); id != "" {
|
if id := view.ID(); id != "" {
|
||||||
return id
|
return id
|
||||||
} else {
|
} else {
|
||||||
|
@ -304,6 +324,14 @@ func (view *viewData) removeFunc(tag PropertyName) []PropertyName {
|
||||||
changedTags = []PropertyName{}
|
changedTags = []PropertyName{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Binding:
|
||||||
|
if view.getRaw(Binding) != nil {
|
||||||
|
view.setRaw(Binding, nil)
|
||||||
|
changedTags = []PropertyName{Binding}
|
||||||
|
} else {
|
||||||
|
changedTags = []PropertyName{}
|
||||||
|
}
|
||||||
|
|
||||||
case Animation:
|
case Animation:
|
||||||
if val := view.getRaw(Animation); val != nil {
|
if val := view.getRaw(Animation); val != nil {
|
||||||
if animations, ok := val.([]AnimationProperty); ok {
|
if animations, ok := val.([]AnimationProperty); ok {
|
||||||
|
@ -336,6 +364,33 @@ func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName {
|
||||||
notCompatibleType(ID, value)
|
notCompatibleType(ID, value)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
case Binding:
|
||||||
|
view.setRaw(Binding, value)
|
||||||
|
return []PropertyName{Binding}
|
||||||
|
|
||||||
|
case changeListeners:
|
||||||
|
switch value := value.(type) {
|
||||||
|
case DataObject:
|
||||||
|
for i := range value.PropertyCount() {
|
||||||
|
node := value.Property(i)
|
||||||
|
if node.Type() == TextNode {
|
||||||
|
if text := node.Text(); text != "" {
|
||||||
|
view.changeListener[PropertyName(node.Tag())] = newOneArgListenerBinding[View, PropertyName](text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(view.changeListener) > 0 {
|
||||||
|
view.setRaw(changeListeners, view.changeListener)
|
||||||
|
}
|
||||||
|
return []PropertyName{tag}
|
||||||
|
|
||||||
|
case DataNode:
|
||||||
|
if value.Type() == ObjectNode {
|
||||||
|
return view.setFunc(tag, value.Object())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []PropertyName{}
|
||||||
|
|
||||||
case Animation:
|
case Animation:
|
||||||
oldAnimations := []AnimationProperty{}
|
oldAnimations := []AnimationProperty{}
|
||||||
if val := view.getRaw(Animation); val != nil {
|
if val := view.getRaw(Animation); val != nil {
|
||||||
|
@ -386,20 +441,15 @@ func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName {
|
||||||
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
|
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
|
||||||
result := setOneArgEventListener[View, PropertyName](view, tag, value)
|
result := setOneArgEventListener[View, PropertyName](view, tag, value)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
result = setOneArgEventListener[View, string](view, tag, value)
|
if listeners, ok := valueToOneArgEventListeners[View, string](view); ok && len(listeners) > 0 {
|
||||||
if result != nil {
|
newListeners := make([]oneArgListener[View, PropertyName], len(listeners))
|
||||||
if listeners, ok := view.getRaw(tag).([]func(View, string)); ok {
|
for i, listener := range listeners {
|
||||||
newListeners := make([]func(View, PropertyName), len(listeners))
|
newListeners[i] = newOneArgListenerVE(func(view View, name PropertyName) {
|
||||||
for i, listener := range listeners {
|
listener.Run(view, string(name))
|
||||||
newListeners[i] = func(view View, name PropertyName) {
|
})
|
||||||
listener(view, string(name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
view.setRaw(tag, newListeners)
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
view.setRaw(tag, nil)
|
view.setRaw(tag, newListeners)
|
||||||
return nil
|
result = []PropertyName{tag}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
@ -909,7 +959,7 @@ func (view *viewData) propertyChanged(tag PropertyName) {
|
||||||
case DropEffectAllowed:
|
case DropEffectAllowed:
|
||||||
effect := GetDropEffectAllowed(view)
|
effect := GetDropEffectAllowed(view)
|
||||||
if effect >= DropEffectCopy && effect >= DropEffectAll {
|
if effect >= DropEffectCopy && effect >= DropEffectAll {
|
||||||
values := []string{"undifined", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"}
|
values := []string{"undefined", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"}
|
||||||
session.updateProperty(htmlID, "data-drop-effect-allowed", values[effect])
|
session.updateProperty(htmlID, "data-drop-effect-allowed", values[effect])
|
||||||
} else {
|
} else {
|
||||||
session.removeProperty(htmlID, "data-drop-effect-allowed")
|
session.removeProperty(htmlID, "data-drop-effect-allowed")
|
||||||
|
@ -1016,8 +1066,8 @@ func (view *viewData) htmlProperties(self View, buffer *strings.Builder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if view.frame.Left != 0 || view.frame.Top != 0 || view.frame.Width != 0 || view.frame.Height != 0 {
|
if view.frame.Left != 0 || view.frame.Top != 0 || view.frame.Width != 0 || view.frame.Height != 0 {
|
||||||
buffer.WriteString(fmt.Sprintf(` data-left="%g" data-top="%g" data-width="%g" data-height="%g"`,
|
fmt.Fprintf(buffer, ` data-left="%g" data-top="%g" data-width="%g" data-height="%g"`,
|
||||||
view.frame.Left, view.frame.Top, view.frame.Width, view.frame.Height))
|
view.frame.Left, view.frame.Top, view.frame.Width, view.frame.Height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1142,13 +1192,13 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb
|
||||||
case FocusEvent:
|
case FocusEvent:
|
||||||
view.hasFocus = true
|
view.hasFocus = true
|
||||||
for _, listener := range getNoArgEventListeners[View](view, nil, command) {
|
for _, listener := range getNoArgEventListeners[View](view, nil, command) {
|
||||||
listener(self)
|
listener.Run(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
case LostFocusEvent:
|
case LostFocusEvent:
|
||||||
view.hasFocus = false
|
view.hasFocus = false
|
||||||
for _, listener := range getNoArgEventListeners[View](view, nil, command) {
|
for _, listener := range getNoArgEventListeners[View](view, nil, command) {
|
||||||
listener(self)
|
listener.Run(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
|
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
|
||||||
|
@ -1231,12 +1281,33 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) SetChangeListener(tag PropertyName, listener func(View, PropertyName)) {
|
func (view *viewData) SetChangeListener(tag PropertyName, listener any) bool {
|
||||||
if listener == nil {
|
if listener == nil {
|
||||||
delete(view.changeListener, tag)
|
delete(view.changeListener, tag)
|
||||||
} else {
|
} else {
|
||||||
view.changeListener[tag] = listener
|
switch listener := listener.(type) {
|
||||||
|
case func():
|
||||||
|
view.changeListener[tag] = newOneArgListener0[View, PropertyName](listener)
|
||||||
|
|
||||||
|
case func(View):
|
||||||
|
view.changeListener[tag] = newOneArgListenerV[View, PropertyName](listener)
|
||||||
|
|
||||||
|
case func(PropertyName):
|
||||||
|
view.changeListener[tag] = newOneArgListenerE[View](listener)
|
||||||
|
|
||||||
|
case func(View, PropertyName):
|
||||||
|
view.changeListener[tag] = newOneArgListenerVE(listener)
|
||||||
|
|
||||||
|
case string:
|
||||||
|
view.changeListener[tag] = newOneArgListenerBinding[View, PropertyName](listener)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
view.setRaw(changeListeners, view.changeListener)
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) HasFocus() bool {
|
func (view *viewData) HasFocus() bool {
|
||||||
|
@ -1250,6 +1321,6 @@ func (view *viewData) String() string {
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (view *viewData) exscludeTags() []PropertyName {
|
func (view *viewData) excludeTags() []PropertyName {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
170
viewFactory.go
170
viewFactory.go
|
@ -6,7 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var viewCreators = map[string]func(Session) View{
|
var systemViewCreators = map[string]func(Session) View{
|
||||||
"View": newView,
|
"View": newView,
|
||||||
"ColumnLayout": newColumnLayout,
|
"ColumnLayout": newColumnLayout,
|
||||||
"ListLayout": newListLayout,
|
"ListLayout": newListLayout,
|
||||||
|
@ -36,84 +36,117 @@ var viewCreators = map[string]func(Session) View{
|
||||||
"VideoPlayer": newVideoPlayer,
|
"VideoPlayer": newVideoPlayer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ViewCreateListener is the listener interface of a view create event
|
||||||
|
type ViewCreateListener interface {
|
||||||
|
// OnCreate is a function of binding object that is called by the CreateViewFromText, CreateViewFromResources,
|
||||||
|
// and CreateViewFromObject functions after the creation of a view
|
||||||
|
OnCreate(view View)
|
||||||
|
}
|
||||||
|
|
||||||
|
var viewCreate map[string]func(Session) View = nil
|
||||||
|
|
||||||
|
func viewCreators() map[string]func(Session) View {
|
||||||
|
if viewCreate == nil {
|
||||||
|
viewCreate = map[string]func(Session) View{}
|
||||||
|
for tag, fn := range systemViewCreators {
|
||||||
|
viewCreate[strings.ToLower(tag)] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return viewCreate
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterViewCreator register function of creating view
|
// RegisterViewCreator register function of creating view
|
||||||
func RegisterViewCreator(tag string, creator func(Session) View) bool {
|
func RegisterViewCreator(tag string, creator func(Session) View) bool {
|
||||||
builtinViews := []string{
|
loTag := strings.ToLower(tag)
|
||||||
"View",
|
for name := range systemViewCreators {
|
||||||
"ViewsContainer",
|
if name == loTag {
|
||||||
"ColumnLayout",
|
ErrorLog(`It is forbidden to override the function of ` + tag + ` creating`)
|
||||||
"ListLayout",
|
|
||||||
"GridLayout",
|
|
||||||
"StackLayout",
|
|
||||||
"TabsLayout",
|
|
||||||
"AbsoluteLayout",
|
|
||||||
"Resizable",
|
|
||||||
"DetailsView",
|
|
||||||
"TextView",
|
|
||||||
"Button",
|
|
||||||
"Checkbox",
|
|
||||||
"DropDownList",
|
|
||||||
"ProgressBar",
|
|
||||||
"NumberPicker",
|
|
||||||
"ColorPicker",
|
|
||||||
"DatePicker",
|
|
||||||
"TimePicker",
|
|
||||||
"EditView",
|
|
||||||
"ListView",
|
|
||||||
"CanvasView",
|
|
||||||
"ImageView",
|
|
||||||
"TableView",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, name := range builtinViews {
|
|
||||||
if name == tag {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewCreators[tag] = creator
|
viewCreators()[loTag] = creator
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateViewFromObject create new View and initialize it by Node data
|
// CreateViewFromObject create new View and initialize it by DataObject data. Parameters:
|
||||||
func CreateViewFromObject(session Session, object DataObject) View {
|
// - session - the session to which the view will be attached (should not be nil);
|
||||||
tag := object.Tag()
|
// - object - data describing View;
|
||||||
|
// - binding - object assigned to the Binding property (may be nil).
|
||||||
if creator, ok := viewCreators[tag]; ok {
|
//
|
||||||
if !session.ignoreViewUpdates() {
|
// If the function fails, it returns nil and an error message is written to the log.
|
||||||
session.setIgnoreViewUpdates(true)
|
func CreateViewFromObject(session Session, object DataObject, binding any) View {
|
||||||
defer session.setIgnoreViewUpdates(false)
|
if session == nil {
|
||||||
}
|
ErrorLog(`Session must not be nil`)
|
||||||
view := creator(session)
|
return nil
|
||||||
view.init(session)
|
|
||||||
if customView, ok := view.(CustomView); ok {
|
|
||||||
if !InitCustomView(customView, tag, session, nil) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parseProperties(view, object)
|
|
||||||
return view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorLog(`Unknown view type "` + object.Tag() + `"`)
|
tag := object.Tag()
|
||||||
return nil
|
creator, ok := viewCreators()[strings.ToLower(tag)]
|
||||||
|
if !ok {
|
||||||
|
ErrorLog(`Unknown view type "` + tag + `"`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !session.ignoreViewUpdates() {
|
||||||
|
session.setIgnoreViewUpdates(true)
|
||||||
|
defer session.setIgnoreViewUpdates(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
view := creator(session)
|
||||||
|
view.init(session)
|
||||||
|
if customView, ok := view.(CustomView); ok {
|
||||||
|
if !InitCustomView(customView, tag, session, nil) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parseProperties(view, object)
|
||||||
|
if binding != nil {
|
||||||
|
view.setRaw(Binding, binding)
|
||||||
|
if listener, ok := binding.(ViewCreateListener); ok {
|
||||||
|
listener.OnCreate(view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateViewFromText create new View and initialize it by content of text
|
// CreateViewFromText create new View and initialize it by content of text. Parameters:
|
||||||
func CreateViewFromText(session Session, text string) View {
|
// - session - the session to which the view will be attached (should not be nil);
|
||||||
if data := ParseDataText(text); data != nil {
|
// - text - text describing View;
|
||||||
return CreateViewFromObject(session, data)
|
// - binding - object assigned to the Binding property (optional parameter).
|
||||||
|
//
|
||||||
|
// If the function fails, it returns nil and an error message is written to the log.
|
||||||
|
func CreateViewFromText(session Session, text string, binding ...any) View {
|
||||||
|
data, err := ParseDataText(text)
|
||||||
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
var b any = nil
|
||||||
|
if len(binding) > 0 {
|
||||||
|
b = binding[0]
|
||||||
|
}
|
||||||
|
return CreateViewFromObject(session, data, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateViewFromResources create new View and initialize it by the content of
|
// CreateViewFromResources create new View and initialize it by the content of
|
||||||
// the resource file from "views" directory
|
// the resource file from "views" directory. Parameters:
|
||||||
func CreateViewFromResources(session Session, name string) View {
|
// - session - the session to which the view will be attached (should not be nil);
|
||||||
|
// - name - file name in the views folder of the application resources (it is not necessary to specify the .rui extension, it is added automatically);
|
||||||
|
// - binding - object assigned to the Binding property (optional parameter).
|
||||||
|
//
|
||||||
|
// If the function fails, it returns nil and an error message is written to the log.
|
||||||
|
func CreateViewFromResources(session Session, name string, binding ...any) View {
|
||||||
if strings.ToLower(filepath.Ext(name)) != ".rui" {
|
if strings.ToLower(filepath.Ext(name)) != ".rui" {
|
||||||
name += ".rui"
|
name += ".rui"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var b any = nil
|
||||||
|
if len(binding) > 0 {
|
||||||
|
b = binding[0]
|
||||||
|
}
|
||||||
|
|
||||||
for _, fs := range resources.embedFS {
|
for _, fs := range resources.embedFS {
|
||||||
rootDirs := resources.embedRootDirs(fs)
|
rootDirs := resources.embedRootDirs(fs)
|
||||||
for _, dir := range rootDirs {
|
for _, dir := range rootDirs {
|
||||||
|
@ -123,15 +156,21 @@ func CreateViewFromResources(session Session, name string) View {
|
||||||
|
|
||||||
case viewDir:
|
case viewDir:
|
||||||
if data, err := fs.ReadFile(dir + "/" + name); err == nil {
|
if data, err := fs.ReadFile(dir + "/" + name); err == nil {
|
||||||
if data := ParseDataText(string(data)); data != nil {
|
data, err := ParseDataText(string(data))
|
||||||
return CreateViewFromObject(session, data)
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
|
return CreateViewFromObject(session, data, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if data, err := fs.ReadFile(dir + "/" + viewDir + "/" + name); err == nil {
|
if data, err := fs.ReadFile(dir + "/" + viewDir + "/" + name); err == nil {
|
||||||
if data := ParseDataText(string(data)); data != nil {
|
data, err := ParseDataText(string(data))
|
||||||
return CreateViewFromObject(session, data)
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
|
return CreateViewFromObject(session, data, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,8 +179,11 @@ func CreateViewFromResources(session Session, name string) View {
|
||||||
|
|
||||||
if resources.path != "" {
|
if resources.path != "" {
|
||||||
if data, err := os.ReadFile(resources.path + viewDir + "/" + name); err == nil {
|
if data, err := os.ReadFile(resources.path + viewDir + "/" + name); err == nil {
|
||||||
if data := ParseDataText(string(data)); data != nil {
|
data, err := ParseDataText(string(data))
|
||||||
return CreateViewFromObject(session, data)
|
if err != nil {
|
||||||
|
ErrorLog(err.Error())
|
||||||
|
} else {
|
||||||
|
return CreateViewFromObject(session, data, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
251
viewStyle.go
251
viewStyle.go
|
@ -2,9 +2,10 @@ package rui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ViewStyle interface of the style of view
|
// ViewStyle interface of the style of view
|
||||||
|
@ -551,26 +552,126 @@ func viewStyleGet(style Properties, tag PropertyName) any {
|
||||||
}
|
}
|
||||||
|
|
||||||
func supportedPropertyValue(value any) bool {
|
func supportedPropertyValue(value any) bool {
|
||||||
switch value.(type) {
|
switch value := value.(type) {
|
||||||
case string:
|
case string, bool, float32, float64, int, stringWriter, fmt.Stringer:
|
||||||
|
return true
|
||||||
|
|
||||||
case []string:
|
case []string:
|
||||||
case bool:
|
return len(value) > 0
|
||||||
case float32:
|
|
||||||
case float64:
|
|
||||||
case int:
|
|
||||||
case stringWriter:
|
|
||||||
case fmt.Stringer:
|
|
||||||
case []ShadowProperty:
|
case []ShadowProperty:
|
||||||
|
return len(value) > 0
|
||||||
|
|
||||||
case []View:
|
case []View:
|
||||||
|
return len(value) > 0
|
||||||
|
|
||||||
case []any:
|
case []any:
|
||||||
|
return len(value) > 0
|
||||||
|
|
||||||
case []BackgroundElement:
|
case []BackgroundElement:
|
||||||
|
return len(value) > 0
|
||||||
|
|
||||||
case []BackgroundGradientPoint:
|
case []BackgroundGradientPoint:
|
||||||
|
return len(value) > 0
|
||||||
|
|
||||||
case []BackgroundGradientAngle:
|
case []BackgroundGradientAngle:
|
||||||
|
return len(value) > 0
|
||||||
|
|
||||||
case map[PropertyName]AnimationProperty:
|
case map[PropertyName]AnimationProperty:
|
||||||
|
return len(value) > 0
|
||||||
|
|
||||||
|
case []noArgListener[View]:
|
||||||
|
return getNoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []noArgListener[ImageView]:
|
||||||
|
return getNoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []noArgListener[MediaPlayer]:
|
||||||
|
return getNoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[View, KeyEvent]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[View, MouseEvent]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[View, TouchEvent]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[View, PointerEvent]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[View, PropertyName]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[View, string]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[View, Frame]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[View, DragAndDropEvent]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[Checkbox, bool]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[FilePicker, []FileInfo]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[ListView, int]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[ListView, []int]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[MediaPlayer, float64]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[TableView, int]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []oneArgListener[TabsLayout, int]:
|
||||||
|
return getOneArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []twoArgListener[ColorPicker, Color]:
|
||||||
|
return getTwoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []twoArgListener[DatePicker, time.Time]:
|
||||||
|
return getTwoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []twoArgListener[TimePicker, time.Time]:
|
||||||
|
return getTwoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []twoArgListener[DropDownList, int]:
|
||||||
|
return getTwoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []twoArgListener[EditView, string]:
|
||||||
|
return getTwoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []twoArgListener[NumberPicker, float64]:
|
||||||
|
return getTwoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []twoArgListener[TableView, int]:
|
||||||
|
return getTwoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []twoArgListener[TabsLayout, int]:
|
||||||
|
return getTwoArgBinding(value) != ""
|
||||||
|
|
||||||
|
case []mediaPlayerErrorListener:
|
||||||
|
return getMediaPlayerErrorListenerBinding(value) != ""
|
||||||
|
|
||||||
|
case map[PropertyName]oneArgListener[View, PropertyName]:
|
||||||
|
for _, listener := range value {
|
||||||
|
if text, ok := listener.rawListener().(string); ok && text != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, indent string) {
|
func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, indent string) {
|
||||||
|
@ -640,8 +741,8 @@ func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, in
|
||||||
writeString(text)
|
writeString(text)
|
||||||
buffer.WriteString(",\n")
|
buffer.WriteString(",\n")
|
||||||
}
|
}
|
||||||
|
buffer.WriteString(indent)
|
||||||
}
|
}
|
||||||
buffer.WriteString(indent)
|
|
||||||
buffer.WriteRune(']')
|
buffer.WriteRune(']')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,10 +754,10 @@ func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, in
|
||||||
}
|
}
|
||||||
|
|
||||||
case float32:
|
case float32:
|
||||||
buffer.WriteString(fmt.Sprintf("%g", float64(value)))
|
fmt.Fprintf(buffer, "%g", float64(value))
|
||||||
|
|
||||||
case float64:
|
case float64:
|
||||||
buffer.WriteString(fmt.Sprintf("%g", value))
|
fmt.Fprintf(buffer, "%g", value)
|
||||||
|
|
||||||
case int:
|
case int:
|
||||||
if prop, ok := enumProperties[tag]; ok && value >= 0 && value < len(prop.values) {
|
if prop, ok := enumProperties[tag]; ok && value >= 0 && value < len(prop.values) {
|
||||||
|
@ -698,14 +799,14 @@ func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, in
|
||||||
buffer.WriteString("[]")
|
buffer.WriteString("[]")
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
writeViewStyle(value[0].Tag(), value[0], buffer, indent, value[0].exscludeTags())
|
writeViewStyle(value[0].Tag(), value[0], buffer, indent, value[0].excludeTags())
|
||||||
|
|
||||||
default:
|
default:
|
||||||
buffer.WriteString("[\n")
|
buffer.WriteString("[\n")
|
||||||
indent2 := indent + "\t"
|
indent2 := indent + "\t"
|
||||||
for _, v := range value {
|
for _, v := range value {
|
||||||
buffer.WriteString(indent2)
|
buffer.WriteString(indent2)
|
||||||
writeViewStyle(v.Tag(), v, buffer, indent2, v.exscludeTags())
|
writeViewStyle(v.Tag(), v, buffer, indent2, v.excludeTags())
|
||||||
buffer.WriteString(",\n")
|
buffer.WriteString(",\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,9 +892,7 @@ func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, in
|
||||||
for tag := range value {
|
for tag := range value {
|
||||||
tags = append(tags, tag)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
sort.Slice(tags, func(i, j int) bool {
|
slices.Sort(tags)
|
||||||
return tags[i] < tags[j]
|
|
||||||
})
|
|
||||||
buffer.WriteString("[\n")
|
buffer.WriteString("[\n")
|
||||||
indent2 := indent + "\t"
|
indent2 := indent + "\t"
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
|
@ -806,6 +905,104 @@ func writePropertyValue(buffer *strings.Builder, tag PropertyName, value any, in
|
||||||
buffer.WriteString(indent)
|
buffer.WriteString(indent)
|
||||||
buffer.WriteRune(']')
|
buffer.WriteRune(']')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case []noArgListener[View]:
|
||||||
|
buffer.WriteString(getNoArgBinding(value))
|
||||||
|
|
||||||
|
case []noArgListener[ImageView]:
|
||||||
|
buffer.WriteString(getNoArgBinding(value))
|
||||||
|
|
||||||
|
case []noArgListener[MediaPlayer]:
|
||||||
|
buffer.WriteString(getNoArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[View, KeyEvent]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[View, MouseEvent]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[View, TouchEvent]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[View, PointerEvent]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[View, PropertyName]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[View, string]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[View, Frame]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[View, DragAndDropEvent]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[Checkbox, bool]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[FilePicker, []FileInfo]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[ListView, int]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[ListView, []int]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[MediaPlayer, float64]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[TableView, int]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []oneArgListener[TabsLayout, int]:
|
||||||
|
buffer.WriteString(getOneArgBinding(value))
|
||||||
|
|
||||||
|
case []twoArgListener[ColorPicker, Color]:
|
||||||
|
buffer.WriteString(getTwoArgBinding(value))
|
||||||
|
|
||||||
|
case []twoArgListener[DatePicker, time.Time]:
|
||||||
|
buffer.WriteString(getTwoArgBinding(value))
|
||||||
|
|
||||||
|
case []twoArgListener[TimePicker, time.Time]:
|
||||||
|
buffer.WriteString(getTwoArgBinding(value))
|
||||||
|
|
||||||
|
case []twoArgListener[DropDownList, int]:
|
||||||
|
buffer.WriteString(getTwoArgBinding(value))
|
||||||
|
|
||||||
|
case []twoArgListener[EditView, string]:
|
||||||
|
buffer.WriteString(getTwoArgBinding(value))
|
||||||
|
|
||||||
|
case []twoArgListener[NumberPicker, float64]:
|
||||||
|
buffer.WriteString(getTwoArgBinding(value))
|
||||||
|
|
||||||
|
case []twoArgListener[TableView, int]:
|
||||||
|
buffer.WriteString(getTwoArgBinding(value))
|
||||||
|
|
||||||
|
case []twoArgListener[TabsLayout, int]:
|
||||||
|
buffer.WriteString(getTwoArgBinding(value))
|
||||||
|
|
||||||
|
case []mediaPlayerErrorListener:
|
||||||
|
buffer.WriteString(getMediaPlayerErrorListenerBinding(value))
|
||||||
|
|
||||||
|
case map[PropertyName]oneArgListener[View, PropertyName]:
|
||||||
|
buffer.WriteString("_{")
|
||||||
|
for key, listener := range value {
|
||||||
|
if text, ok := listener.rawListener().(string); ok && text != "" {
|
||||||
|
buffer.WriteRune('\n')
|
||||||
|
buffer.WriteString(indent)
|
||||||
|
buffer.WriteRune('\t')
|
||||||
|
writeString(string(key))
|
||||||
|
buffer.WriteString(" = ")
|
||||||
|
writeString(text)
|
||||||
|
buffer.WriteRune(',')
|
||||||
|
}
|
||||||
|
buffer.WriteRune('\n')
|
||||||
|
buffer.WriteString(indent)
|
||||||
|
buffer.WriteRune('}')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,19 +1012,15 @@ func writeViewStyle(name string, view Properties, buffer *strings.Builder, inden
|
||||||
indent += "\t"
|
indent += "\t"
|
||||||
|
|
||||||
writeProperty := func(tag PropertyName, value any) {
|
writeProperty := func(tag PropertyName, value any) {
|
||||||
for _, exclude := range excludeTags {
|
if !slices.Contains(excludeTags, tag) {
|
||||||
if exclude == tag {
|
if supportedPropertyValue(value) {
|
||||||
return
|
buffer.WriteString(indent)
|
||||||
|
buffer.WriteString(string(tag))
|
||||||
|
buffer.WriteString(" = ")
|
||||||
|
writePropertyValue(buffer, tag, value, indent)
|
||||||
|
buffer.WriteString(",\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if supportedPropertyValue(value) {
|
|
||||||
buffer.WriteString(indent)
|
|
||||||
buffer.WriteString(string(tag))
|
|
||||||
buffer.WriteString(" = ")
|
|
||||||
writePropertyValue(buffer, tag, value, indent)
|
|
||||||
buffer.WriteString(",\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := view.AllTags()
|
tags := view.AllTags()
|
||||||
|
|
112
viewUtils.go
112
viewUtils.go
|
@ -355,31 +355,41 @@ func GetTextShadows(view View, subviewID ...string) []ShadowProperty {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBackgroundColor returns a background color of the subview.
|
// GetBackgroundColor returns a background color of the subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetBackgroundColor(view View, subviewID ...string) Color {
|
func GetBackgroundColor(view View, subviewID ...string) Color {
|
||||||
return colorStyledProperty(view, subviewID, BackgroundColor, false)
|
return colorStyledProperty(view, subviewID, BackgroundColor, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAccentColor returns the accent color for UI controls generated by some elements.
|
// GetAccentColor returns the accent color for UI controls generated by some elements.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetAccentColor(view View, subviewID ...string) Color {
|
func GetAccentColor(view View, subviewID ...string) Color {
|
||||||
return colorStyledProperty(view, subviewID, AccentColor, false)
|
return colorStyledProperty(view, subviewID, AccentColor, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFontName returns the subview font.
|
// GetFontName returns the subview font.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetFontName(view View, subviewID ...string) string {
|
func GetFontName(view View, subviewID ...string) string {
|
||||||
return stringStyledProperty(view, nil, FontName, true)
|
return stringStyledProperty(view, nil, FontName, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTextColor returns a text color of the subview.
|
// GetTextColor returns a text color of the subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextColor(view View, subviewID ...string) Color {
|
func GetTextColor(view View, subviewID ...string) Color {
|
||||||
return colorStyledProperty(view, subviewID, TextColor, true)
|
return colorStyledProperty(view, subviewID, TextColor, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTextSize returns a text size of the subview.
|
// GetTextSize returns a text size of the subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextSize(view View, subviewID ...string) SizeUnit {
|
func GetTextSize(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, TextSize, true)
|
return sizeStyledProperty(view, subviewID, TextSize, true)
|
||||||
}
|
}
|
||||||
|
@ -392,7 +402,9 @@ func GetTabSize(view View, subviewID ...string) int {
|
||||||
|
|
||||||
// GetTextWeight returns a text weight of the subview. Returns one of next values:
|
// GetTextWeight returns a text weight of the subview. Returns one of next values:
|
||||||
// 1, 2, 3, 4 (normal text), 5, 6, 7 (bold text), 8 and 9
|
// 1, 2, 3, 4 (normal text), 5, 6, 7 (bold text), 8 and 9
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextWeight(view View, subviewID ...string) int {
|
func GetTextWeight(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, TextWeight, NormalFont, true)
|
return enumStyledProperty(view, subviewID, TextWeight, NormalFont, true)
|
||||||
}
|
}
|
||||||
|
@ -401,7 +413,8 @@ func GetTextWeight(view View, subviewID ...string) int {
|
||||||
//
|
//
|
||||||
// LeftAlign = 0, RightAlign = 1, CenterAlign = 2, JustifyAlign = 3
|
// LeftAlign = 0, RightAlign = 1, CenterAlign = 2, JustifyAlign = 3
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextAlign(view View, subviewID ...string) int {
|
func GetTextAlign(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, TextAlign, LeftAlign, true)
|
return enumStyledProperty(view, subviewID, TextAlign, LeftAlign, true)
|
||||||
}
|
}
|
||||||
|
@ -410,89 +423,116 @@ func GetTextAlign(view View, subviewID ...string) int {
|
||||||
//
|
//
|
||||||
// TextWrapOn = 0, TextWrapOff = 1, TextWrapBalance = 3
|
// TextWrapOn = 0, TextWrapOff = 1, TextWrapBalance = 3
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextWrap(view View, subviewID ...string) int {
|
func GetTextWrap(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, TextWrap, TextWrapOn, true)
|
return enumStyledProperty(view, subviewID, TextWrap, TextWrapOn, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTextIndent returns a text indent of the subview.
|
// GetTextIndent returns a text indent of the subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextIndent(view View, subviewID ...string) SizeUnit {
|
func GetTextIndent(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, TextIndent, true)
|
return sizeStyledProperty(view, subviewID, TextIndent, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLetterSpacing returns a letter spacing of the subview.
|
// GetLetterSpacing returns a letter spacing of the subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetLetterSpacing(view View, subviewID ...string) SizeUnit {
|
func GetLetterSpacing(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, LetterSpacing, true)
|
return sizeStyledProperty(view, subviewID, LetterSpacing, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWordSpacing returns a word spacing of the subview.
|
// GetWordSpacing returns a word spacing of the subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetWordSpacing(view View, subviewID ...string) SizeUnit {
|
func GetWordSpacing(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, WordSpacing, true)
|
return sizeStyledProperty(view, subviewID, WordSpacing, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLineHeight returns a height of a text line of the subview.
|
// GetLineHeight returns a height of a text line of the subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetLineHeight(view View, subviewID ...string) SizeUnit {
|
func GetLineHeight(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, LineHeight, true)
|
return sizeStyledProperty(view, subviewID, LineHeight, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsItalic returns "true" if a text font of the subview is displayed in italics, "false" otherwise.
|
// IsItalic returns "true" if a text font of the subview is displayed in italics, "false" otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsItalic(view View, subviewID ...string) bool {
|
func IsItalic(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, Italic, true)
|
return boolStyledProperty(view, subviewID, Italic, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSmallCaps returns "true" if a text font of the subview is displayed in small caps, "false" otherwise.
|
// IsSmallCaps returns "true" if a text font of the subview is displayed in small caps, "false" otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsSmallCaps(view View, subviewID ...string) bool {
|
func IsSmallCaps(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, SmallCaps, true)
|
return boolStyledProperty(view, subviewID, SmallCaps, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsStrikethrough returns "true" if a text font of the subview is displayed strikethrough, "false" otherwise.
|
// IsStrikethrough returns "true" if a text font of the subview is displayed strikethrough, "false" otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsStrikethrough(view View, subviewID ...string) bool {
|
func IsStrikethrough(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, Strikethrough, true)
|
return boolStyledProperty(view, subviewID, Strikethrough, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOverline returns "true" if a text font of the subview is displayed overlined, "false" otherwise.
|
// IsOverline returns "true" if a text font of the subview is displayed overlined, "false" otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsOverline(view View, subviewID ...string) bool {
|
func IsOverline(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, Overline, true)
|
return boolStyledProperty(view, subviewID, Overline, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsUnderline returns "true" if a text font of the subview is displayed underlined, "false" otherwise.
|
// IsUnderline returns "true" if a text font of the subview is displayed underlined, "false" otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsUnderline(view View, subviewID ...string) bool {
|
func IsUnderline(view View, subviewID ...string) bool {
|
||||||
return boolStyledProperty(view, subviewID, Underline, true)
|
return boolStyledProperty(view, subviewID, Underline, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTextLineThickness returns the stroke thickness of the decoration line that
|
// GetTextLineThickness returns the stroke thickness of the decoration line that
|
||||||
// is used on text in an element, such as a line-through, underline, or overline.
|
// is used on text in an element, such as a line-through, underline, or overline.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextLineThickness(view View, subviewID ...string) SizeUnit {
|
func GetTextLineThickness(view View, subviewID ...string) SizeUnit {
|
||||||
return sizeStyledProperty(view, subviewID, TextLineThickness, true)
|
return sizeStyledProperty(view, subviewID, TextLineThickness, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTextLineStyle returns the stroke style of the decoration line that
|
// GetTextLineStyle returns the stroke style of the decoration line that
|
||||||
// is used on text in an element, such as a line-through, underline, or overline.
|
// is used on text in an element, such as a line-through, underline, or overline.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextLineStyle(view View, subviewID ...string) int {
|
func GetTextLineStyle(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, TextLineStyle, SolidLine, true)
|
return enumStyledProperty(view, subviewID, TextLineStyle, SolidLine, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTextLineColor returns the stroke color of the decoration line that
|
// GetTextLineColor returns the stroke color of the decoration line that
|
||||||
// is used on text in an element, such as a line-through, underline, or overline.
|
// is used on text in an element, such as a line-through, underline, or overline.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextLineColor(view View, subviewID ...string) Color {
|
func GetTextLineColor(view View, subviewID ...string) Color {
|
||||||
return colorStyledProperty(view, subviewID, TextLineColor, true)
|
return colorStyledProperty(view, subviewID, TextLineColor, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTextTransform returns a text transform of the subview. Return one of next values:
|
// GetTextTransform returns a text transform of the subview. Return one of next values:
|
||||||
// NoneTextTransform (0), CapitalizeTextTransform (1), LowerCaseTextTransform (2) or UpperCaseTextTransform (3)
|
// NoneTextTransform (0), CapitalizeTextTransform (1), LowerCaseTextTransform (2) or UpperCaseTextTransform (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextTransform(view View, subviewID ...string) int {
|
func GetTextTransform(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, TextTransform, NoneTextTransform, true)
|
return enumStyledProperty(view, subviewID, TextTransform, NoneTextTransform, true)
|
||||||
}
|
}
|
||||||
|
@ -500,14 +540,18 @@ func GetTextTransform(view View, subviewID ...string) int {
|
||||||
// GetWritingMode returns whether lines of text are laid out horizontally or vertically, as well as
|
// GetWritingMode returns whether lines of text are laid out horizontally or vertically, as well as
|
||||||
// the direction in which blocks progress. Valid values are HorizontalTopToBottom (0),
|
// the direction in which blocks progress. Valid values are HorizontalTopToBottom (0),
|
||||||
// HorizontalBottomToTop (1), VerticalRightToLeft (2) and VerticalLeftToRight (3)
|
// HorizontalBottomToTop (1), VerticalRightToLeft (2) and VerticalLeftToRight (3)
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetWritingMode(view View, subviewID ...string) int {
|
func GetWritingMode(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, WritingMode, HorizontalTopToBottom, true)
|
return enumStyledProperty(view, subviewID, WritingMode, HorizontalTopToBottom, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTextDirection - returns a direction of text, table columns, and horizontal overflow.
|
// GetTextDirection - returns a direction of text, table columns, and horizontal overflow.
|
||||||
// Valid values are SystemTextDirection (0), LeftToRightDirection (1), and RightToLeftDirection (2).
|
// Valid values are SystemTextDirection (0), LeftToRightDirection (1), and RightToLeftDirection (2).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTextDirection(view View, subviewID ...string) int {
|
func GetTextDirection(view View, subviewID ...string) int {
|
||||||
if view == nil {
|
if view == nil {
|
||||||
return SystemTextDirection
|
return SystemTextDirection
|
||||||
|
@ -519,7 +563,9 @@ func GetTextDirection(view View, subviewID ...string) int {
|
||||||
// GetVerticalTextOrientation returns a orientation of the text characters in a line. It only affects text
|
// GetVerticalTextOrientation returns a orientation of the text characters in a line. It only affects text
|
||||||
// in vertical mode (when "writing-mode" is "vertical-right-to-left" or "vertical-left-to-right").
|
// in vertical mode (when "writing-mode" is "vertical-right-to-left" or "vertical-left-to-right").
|
||||||
// Valid values are MixedTextOrientation (0), UprightTextOrientation (1), and SidewaysTextOrientation (2).
|
// Valid values are MixedTextOrientation (0), UprightTextOrientation (1), and SidewaysTextOrientation (2).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetVerticalTextOrientation(view View, subviewID ...string) int {
|
func GetVerticalTextOrientation(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, VerticalTextOrientation, MixedTextOrientation, true)
|
return enumStyledProperty(view, subviewID, VerticalTextOrientation, MixedTextOrientation, true)
|
||||||
}
|
}
|
||||||
|
@ -761,7 +807,9 @@ func BlurViewByID(viewID string, session Session) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrent returns the index of the selected item (<0 if there is no a selected item) or the current view index (StackLayout, TabsLayout).
|
// GetCurrent returns the index of the selected item (<0 if there is no a selected item) or the current view index (StackLayout, TabsLayout).
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetCurrent(view View, subviewID ...string) int {
|
func GetCurrent(view View, subviewID ...string) int {
|
||||||
defaultValue := -1
|
defaultValue := -1
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
|
@ -775,7 +823,9 @@ func GetCurrent(view View, subviewID ...string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsUserSelect returns "true" if the user can select text, "false" otherwise.
|
// IsUserSelect returns "true" if the user can select text, "false" otherwise.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func IsUserSelect(view View, subviewID ...string) bool {
|
func IsUserSelect(view View, subviewID ...string) bool {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
value, _ := isUserSelect(view)
|
value, _ := isUserSelect(view)
|
||||||
|
@ -821,7 +871,8 @@ func isUserSelect(view View) (bool, bool) {
|
||||||
// BlendSoftLight (9), BlendDifference (10), BlendExclusion (11), BlendHue (12),
|
// BlendSoftLight (9), BlendDifference (10), BlendExclusion (11), BlendHue (12),
|
||||||
// BlendSaturation (13), BlendColor (14), BlendLuminosity (15)
|
// BlendSaturation (13), BlendColor (14), BlendLuminosity (15)
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetMixBlendMode(view View, subviewID ...string) int {
|
func GetMixBlendMode(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, MixBlendMode, BlendNormal, true)
|
return enumStyledProperty(view, subviewID, MixBlendMode, BlendNormal, true)
|
||||||
}
|
}
|
||||||
|
@ -833,13 +884,16 @@ func GetMixBlendMode(view View, subviewID ...string) int {
|
||||||
// BlendSoftLight (9), BlendDifference (10), BlendExclusion (11), BlendHue (12),
|
// BlendSoftLight (9), BlendDifference (10), BlendExclusion (11), BlendHue (12),
|
||||||
// BlendSaturation (13), BlendColor (14), BlendLuminosity (15)
|
// BlendSaturation (13), BlendColor (14), BlendLuminosity (15)
|
||||||
//
|
//
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetBackgroundBlendMode(view View, subviewID ...string) int {
|
func GetBackgroundBlendMode(view View, subviewID ...string) int {
|
||||||
return enumStyledProperty(view, subviewID, BackgroundBlendMode, BlendNormal, true)
|
return enumStyledProperty(view, subviewID, BackgroundBlendMode, BlendNormal, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTooltip returns a tooltip text of the subview.
|
// GetTooltip returns a tooltip text of the subview.
|
||||||
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
|
//
|
||||||
|
// The second argument (subviewID) specifies the path to the child element whose value needs to be returned.
|
||||||
|
// If it is not specified then a value from the first argument (view) is returned.
|
||||||
func GetTooltip(view View, subviewID ...string) string {
|
func GetTooltip(view View, subviewID ...string) string {
|
||||||
if view = getSubview(view, subviewID); view != nil {
|
if view = getSubview(view, subviewID); view != nil {
|
||||||
if value := view.Get(Tooltip); value != nil {
|
if value := view.Get(Tooltip); value != nil {
|
||||||
|
|
|
@ -85,10 +85,13 @@ func (container *viewsContainerData) Append(view View) {
|
||||||
|
|
||||||
viewHTML(view, buffer, "")
|
viewHTML(view, buffer, "")
|
||||||
container.Session().appendToInnerHTML(container.htmlID(), buffer.String())
|
container.Session().appendToInnerHTML(container.htmlID(), buffer.String())
|
||||||
|
container.contentChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if listener, ok := container.changeListener[Content]; ok {
|
func (container *viewsContainerData) contentChanged() {
|
||||||
listener(container, Content)
|
if listener, ok := container.changeListener[Content]; ok {
|
||||||
}
|
listener.Run(container, Content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,9 +116,7 @@ func (container *viewsContainerData) insert(view View, index int) bool {
|
||||||
func (container *viewsContainerData) Insert(view View, index int) {
|
func (container *viewsContainerData) Insert(view View, index int) {
|
||||||
if container.insert(view, index) && container.created {
|
if container.insert(view, index) && container.created {
|
||||||
updateInnerHTML(container.htmlID(), container.Session())
|
updateInnerHTML(container.htmlID(), container.Session())
|
||||||
if listener, ok := container.changeListener[Content]; ok {
|
container.contentChanged()
|
||||||
listener(container, Content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,11 +132,12 @@ func (container *viewsContainerData) removeView(index int) View {
|
||||||
}
|
}
|
||||||
|
|
||||||
view := container.views[index]
|
view := container.views[index]
|
||||||
if index == 0 {
|
switch index {
|
||||||
|
case 0:
|
||||||
container.views = container.views[1:]
|
container.views = container.views[1:]
|
||||||
} else if index == count-1 {
|
case count - 1:
|
||||||
container.views = container.views[:index]
|
container.views = container.views[:index]
|
||||||
} else {
|
default:
|
||||||
container.views = append(container.views[:index], container.views[index+1:]...)
|
container.views = append(container.views[:index], container.views[index+1:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,9 +150,7 @@ func (container *viewsContainerData) RemoveView(index int) View {
|
||||||
view := container.removeView(index)
|
view := container.removeView(index)
|
||||||
if view != nil && container.created {
|
if view != nil && container.created {
|
||||||
container.Session().callFunc("removeView", view.htmlID())
|
container.Session().callFunc("removeView", view.htmlID())
|
||||||
if listener, ok := container.changeListener[Content]; ok {
|
container.contentChanged()
|
||||||
listener(container, Content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
@ -173,12 +173,9 @@ func (container *viewsContainerData) htmlSubviews(self View, buffer *strings.Bui
|
||||||
}
|
}
|
||||||
|
|
||||||
func viewFromTextValue(text string, session Session) View {
|
func viewFromTextValue(text string, session Session) View {
|
||||||
if strings.Contains(text, "{") && strings.Contains(text, "}") {
|
if data, err := ParseDataText(text); err == nil {
|
||||||
data := ParseDataText(text)
|
if view := CreateViewFromObject(session, data, nil); view != nil {
|
||||||
if data != nil {
|
return view
|
||||||
if view := CreateViewFromObject(session, data); view != nil {
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NewTextView(session, Params{Text: text})
|
return NewTextView(session, Params{Text: text})
|
||||||
|
@ -277,7 +274,7 @@ func (container *viewsContainerData) setContent(value any) bool {
|
||||||
container.views = views
|
container.views = views
|
||||||
|
|
||||||
case DataObject:
|
case DataObject:
|
||||||
if view := CreateViewFromObject(session, value); view != nil {
|
if view := CreateViewFromObject(session, value, nil); view != nil {
|
||||||
container.views = []View{view}
|
container.views = []View{view}
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
@ -287,7 +284,7 @@ func (container *viewsContainerData) setContent(value any) bool {
|
||||||
views := []View{}
|
views := []View{}
|
||||||
for _, data := range value {
|
for _, data := range value {
|
||||||
if data.IsObject() {
|
if data.IsObject() {
|
||||||
if view := CreateViewFromObject(session, data.Object()); view != nil {
|
if view := CreateViewFromObject(session, data.Object(), nil); view != nil {
|
||||||
views = append(views, view)
|
views = append(views, view)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -190,7 +190,7 @@ func (bridge *webBridge) argToString(arg any) (string, bool) {
|
||||||
for _, val := range arg {
|
for _, val := range arg {
|
||||||
buffer.WriteRune(lead)
|
buffer.WriteRune(lead)
|
||||||
lead = ','
|
lead = ','
|
||||||
buffer.WriteString(fmt.Sprintf("%g", val))
|
fmt.Fprintf(buffer, "%g", val)
|
||||||
}
|
}
|
||||||
buffer.WriteRune(']')
|
buffer.WriteRune(']')
|
||||||
return buffer.String(), true
|
return buffer.String(), true
|
||||||
|
|
Loading…
Reference in New Issue