@@ -27,4 +27,7 @@ utf8.upper(text: str) -> str
|
|||||||
|
|
||||||
-- Converts a string to lowercase
|
-- Converts a string to lowercase
|
||||||
utf8.lower(text: str) -> str
|
utf8.lower(text: str) -> str
|
||||||
|
|
||||||
|
-- Escapes a string
|
||||||
|
utf8.escape(text: str) -> str
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -78,14 +78,18 @@ Properties:
|
|||||||
| caret | int | yes | yes | carriage position. `textbox.caret = -1` will set the position to the end of the text |
|
| caret | int | yes | yes | carriage position. `textbox.caret = -1` will set the position to the end of the text |
|
||||||
| editable | bool | yes | yes | text mutability |
|
| editable | bool | yes | yes | text mutability |
|
||||||
| multiline | bool | yes | yes | multiline support |
|
| multiline | bool | yes | yes | multiline support |
|
||||||
|
| lineNumbers | bool | yes | yes | display line numbers |
|
||||||
| textWrap | bool | yes | yes | automatic text wrapping (only with multiline: "true") |
|
| textWrap | bool | yes | yes | automatic text wrapping (only with multiline: "true") |
|
||||||
| valid | bool | yes | no | is the entered text correct |
|
| valid | bool | yes | no | is the entered text correct |
|
||||||
|
| textColor | vec4 | yes | yes | text color |
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
| Method | Description |
|
| Method | Description |
|
||||||
| ----------- | ------------------------------------------------ |
|
| ------------------------- | ---------------------------------------------------------------- |
|
||||||
| paste(text) | inserts the specified text at the caret position |
|
| paste(text: str) | inserts the specified text at the caret position |
|
||||||
|
| lineAt(pos: int) -> int | determines the line number by position in the text |
|
||||||
|
| linePos(line: int) -> int | determines the position of the beginning of the line in the text |
|
||||||
|
|
||||||
## Slider (trackbar)
|
## Slider (trackbar)
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ Buttons and panels are also containers.
|
|||||||
|
|
||||||
- `padding` - element padding. Type: 4D vector.
|
- `padding` - element padding. Type: 4D vector.
|
||||||
*left, top, right, bottom*
|
*left, top, right, bottom*
|
||||||
`scrollable` - element scrollability. Works on panels only. Type: boolean
|
- `scrollable` - element scrollability. Type: boolean.
|
||||||
|
- `scroll-step` - scrolling step. Type: integer.
|
||||||
|
|
||||||
# Common *panel* attributes
|
# Common *panel* attributes
|
||||||
|
|
||||||
@@ -104,7 +105,9 @@ Inner text - initially entered text
|
|||||||
- `multiline` - allows display of multiline text.
|
- `multiline` - allows display of multiline text.
|
||||||
- `text-wrap` - allows automatic text wrapping (works only with multiline: "true")
|
- `text-wrap` - allows automatic text wrapping (works only with multiline: "true")
|
||||||
- `editable` - determines whether the text can be edited.
|
- `editable` - determines whether the text can be edited.
|
||||||
|
- `line-numbers` - enables line numbers display.
|
||||||
- `error-color` - color when entering incorrect data (the text does not pass the validator check). Type: RGBA color.
|
- `error-color` - color when entering incorrect data (the text does not pass the validator check). Type: RGBA color.
|
||||||
|
- `text-color` - text color. Type: RGBA color.
|
||||||
- `validator` - lua function that checks text for correctness. Takes a string as input, returns true if the text is correct.
|
- `validator` - lua function that checks text for correctness. Takes a string as input, returns true if the text is correct.
|
||||||
- `onup` - lua function called when the up arrow is pressed.
|
- `onup` - lua function called when the up arrow is pressed.
|
||||||
- `ondown` - lua function called when the down arrow is pressed.
|
- `ondown` - lua function called when the down arrow is pressed.
|
||||||
|
|||||||
@@ -27,4 +27,7 @@ utf8.upper(text: str) -> str
|
|||||||
|
|
||||||
-- Переводит строку в нижний регистр
|
-- Переводит строку в нижний регистр
|
||||||
utf8.lower(text: str) -> str
|
utf8.lower(text: str) -> str
|
||||||
|
|
||||||
|
-- Экранирует строку
|
||||||
|
utf8.escape(text: str) -> str
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -4,92 +4,109 @@
|
|||||||
|
|
||||||
## Расширения для table
|
## Расширения для table
|
||||||
|
|
||||||
Создаёт и возвращает копию переданной таблицы путём создания новой и копирования в неё всех элементов из переданной
|
|
||||||
```lua
|
```lua
|
||||||
function table.copy(t: table) -> table
|
table.copy(t: table) -> table
|
||||||
```
|
```
|
||||||
|
|
||||||
Возвращает количество пар в переданной таблице
|
Создаёт и возвращает копию переданной таблицы путём создания новой и копирования в неё всех элементов из переданной.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function table.count_pairs(t: table) -> integer
|
table.count_pairs(t: table) -> integer
|
||||||
```
|
```
|
||||||
|
|
||||||
Возвращает один элемент из переданной таблицы на случайной позиции
|
Возвращает количество пар в переданной таблице.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function table.random(t: table) -> object
|
table.random(t: table) -> object
|
||||||
```
|
```
|
||||||
|
|
||||||
Возвращает **true**, если **x** содержится в **t**
|
Возвращает один элемент из переданной таблицы на случайной позиции.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function table.has(t: table, x: object) -> bool
|
table.has(t: table, x: object) -> bool
|
||||||
```
|
```
|
||||||
|
|
||||||
Возвращает индекс обьекта **x** в **t**. Если переданный обьект не содержится в таблице, то функция вернёт значение **-1**
|
Возвращает **true**, если **x** содержится в **t**.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function table.index(t: table, x: object) -> integer
|
table.index(t: table, x: object) -> integer
|
||||||
```
|
```
|
||||||
|
|
||||||
Удаляет элемент **x** из **t**
|
Возвращает индекс обьекта **x** в **t**. Если переданный обьект не содержится в таблице, то функция вернёт значение **-1**.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function table.remove_value(t: table, x: object)
|
table.remove_value(t: table, x: object)
|
||||||
```
|
```
|
||||||
|
|
||||||
Конвертирует переданную таблицу в строку
|
Удаляет элемент **x** из **t**.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function table.tostring(t: table) -> string
|
table.tostring(t: table) -> string
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Конвертирует переданную таблицу в строку.
|
||||||
|
|
||||||
## Расширения для string
|
## Расширения для string
|
||||||
|
|
||||||
Разбивает строку **str** на части по указанному разделителю/выражению **separator** и возвращает результат ввиде таблицы из строк. Если **withpattern** равен **true**, то параметр **separator** будет определяться как регулярное выражение
|
|
||||||
```lua
|
```lua
|
||||||
function string.explode(separator: string, str: string, withpattern: bool) -> table[string]
|
string.explode(separator: string, str: string, withpattern: bool) -> table[string]
|
||||||
```
|
```
|
||||||
|
|
||||||
Разбивает строку **str** на части по указанному разделителю **delimiter** и возвращает результат ввиде таблицы из строк
|
Разбивает строку **str** на части по указанному разделителю/выражению **separator** и возвращает результат ввиде таблицы из строк. Если **withpattern** равен **true**, то параметр **separator** будет определяться как регулярное выражение.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function string.split(str: string, delimiter: string) -> table[string]
|
string.split(str: string, delimiter: string) -> table[string]
|
||||||
```
|
```
|
||||||
|
|
||||||
Экранирует специальные символы в строке, такие как `()[]+-.$%^?*` в формате `%символ`. Символ `NUL` (`\0`) будет преобразован в `%z`
|
Разбивает строку **str** на части по указанному разделителю **delimiter** и возвращает результат ввиде таблицы из строк.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function string.pattern_safe(str: string)
|
string.pattern_safe(str: string)
|
||||||
```
|
```
|
||||||
|
|
||||||
Разбивает секунды на часы, минуты и миллисекунды и форматирует в **format** с следующим порядком параметров: `минуты, секунды, миллисекунды` и после возвращает результат. Если **format** не указан, то возвращает таблицу, где: **h** - hours, **m** - minutes, **s** - seconds, **ms** - milliseconds
|
Экранирует специальные символы в строке, такие как `()[]+-.$%^?*` в формате `%символ`. Символ `NUL` (`\0`) будет преобразован в `%z`.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function string.formatted_time(seconds: number, format: string) -> string | table
|
string.formatted_time(seconds: number, format: string) -> string | table
|
||||||
```
|
```
|
||||||
|
|
||||||
Заменяет все подстроки в **str**, равные **tofind** на **toreplace** и возвращает строку со всеми измененными подстроками
|
Разбивает секунды на часы, минуты и миллисекунды и форматирует в **format** с следующим порядком параметров: `минуты, секунды, миллисекунды` и после возвращает результат. Если **format** не указан, то возвращает таблицу, где: **h** - hours, **m** - minutes, **s** - seconds, **ms** - milliseconds.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function string.replace(str: string, tofind: string, toreplace: string) -> string
|
string.replace(str: string, tofind: string, toreplace: string) -> string
|
||||||
|
```
|
||||||
|
|
||||||
|
Заменяет все подстроки в **str**, равные **tofind** на **toreplace** и возвращает строку со всеми измененными подстроками.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
string.trim(str: string, char: string) -> string
|
||||||
```
|
```
|
||||||
|
|
||||||
Удаляет все символы, равные **char** из строки **str** с левого и правого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы.
|
Удаляет все символы, равные **char** из строки **str** с левого и правого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function string.trim(str: string, char: string) -> string
|
string.trim_left(str: string, char: string) -> string
|
||||||
```
|
```
|
||||||
|
|
||||||
Удаляет все символы, равные **char** из строки **str** с левого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы.
|
Удаляет все символы, равные **char** из строки **str** с левого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function string.trim_left(str: string, char: string) -> string
|
string.trim_right(str: string, char: string) -> string
|
||||||
```
|
```
|
||||||
|
|
||||||
Удаляет все символы, равные **char** из строки **str** с правого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы.
|
Удаляет все символы, равные **char** из строки **str** с правого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function string.trim_right(str: string, char: string) -> string
|
string.starts_with(str: string, start: string) -> bool
|
||||||
```
|
```
|
||||||
|
|
||||||
Возвращает **true**, если строка **str** начинается на подстроку **start**
|
Возвращает **true**, если строка **str** начинается на подстроку **start**
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function string.starts_with(str: string, start: string) -> bool
|
string.ends_with(str: string, endStr: string) -> bool
|
||||||
```
|
```
|
||||||
|
|
||||||
Возвращает **true**, если строка **str** заканчивается на подстроку **endStr**
|
Возвращает **true**, если строка **str** заканчивается на подстроку **endStr**
|
||||||
```lua
|
|
||||||
function string.ends_with(str: string, endStr: string) -> bool
|
|
||||||
```
|
|
||||||
|
|
||||||
Также важно подметить, что все выше перечисленные функции, расширяющие **string** можно использовать как мета-методы на экземплярах строк, т.е.:
|
Также важно подметить, что все выше перечисленные функции, расширяющие **string** можно использовать как мета-методы на экземплярах строк, т.е.:
|
||||||
|
|
||||||
@@ -103,39 +120,51 @@ end
|
|||||||
|
|
||||||
Также функции `string.lower` и `string.upper` переопределены на `utf8.lower` и `utf8.upper`
|
Также функции `string.lower` и `string.upper` переопределены на `utf8.lower` и `utf8.upper`
|
||||||
|
|
||||||
|
```lua
|
||||||
|
string.escape(str: string) -> string
|
||||||
|
```
|
||||||
|
|
||||||
|
Экранирует строку. Является псевдонимом `utf8.escape`.
|
||||||
|
|
||||||
## Расширения для math
|
## Расширения для math
|
||||||
|
|
||||||
Ограничивает число **_in** по лимитам **low** и **high**. Т.е.: Если **_in** больше чем **high** - вернётся **high**, если **_in** меньше чем **low** - вернётся **low**. В противном случае вернётся само число
|
|
||||||
```lua
|
```lua
|
||||||
function math.clamp(_in, low, high)
|
math.clamp(_in, low, high)
|
||||||
```
|
```
|
||||||
|
|
||||||
Возвращает случайное дробное число в диапазоне от **low** до **high**
|
Ограничивает число **_in** по лимитам **low** и **high**. Т.е.: Если **_in** больше чем **high** - вернётся **high**, если **_in** меньше чем **low** - вернётся **low**. В противном случае вернётся само число.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function math.rand(low, high)
|
math.rand(low, high)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Возвращает случайное дробное число в диапазоне от **low** до **high**.
|
||||||
|
|
||||||
## Дополнительные глобальные функции
|
## Дополнительные глобальные функции
|
||||||
|
|
||||||
В этом же скрипте также определены и другие глобальные функции которые доступны для использования. Ниже их список
|
В этом же скрипте также определены и другие глобальные функции которые доступны для использования. Ниже их список
|
||||||
|
|
||||||
|
|
||||||
Возвращает **true**, если переданная таблица является массивом, тоесть если каждый ключ это целое число больше или равное единице и если каждый ключ следует за прошлым
|
|
||||||
```lua
|
```lua
|
||||||
function is_array(x: table) -> bool
|
is_array(x: table) -> bool
|
||||||
```
|
```
|
||||||
|
|
||||||
Разбивает путь на две части и возвращает их: входную точку и путь к файлу
|
Возвращает **true**, если переданная таблица является массивом, тоесть если каждый ключ это целое число больше или равное единице и если каждый ключ следует за прошлым.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function parse_path(path: string) -> string, string
|
function parse_path(path: string) -> string, string
|
||||||
```
|
```
|
||||||
|
|
||||||
Вызывает функцию **func** **iters** раз, передавая ей аргументы `...`, а после выводит в консоль время в микросекундах, которое прошло с момента вызова **timeit**
|
Разбивает путь на две части и возвращает их: входную точку и путь к файлу.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function timeit(iters: integer, func: func, ...)
|
function timeit(iters: integer, func: func, ...)
|
||||||
```
|
```
|
||||||
|
|
||||||
Вызывает остановку корутины до тех пор, пока не пройдёт количество секунд, указанное в **timesec**. Функция может быть использована только внутри корутины
|
Вызывает функцию **func** **iters** раз, передавая ей аргументы `...`, а после выводит в консоль время в микросекундах, которое прошло с момента вызова **timeit**.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function sleep(timesec: number)
|
function sleep(timesec: number)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Вызывает остановку корутины до тех пор, пока не пройдёт количество секунд, указанное в **timesec**. Функция может быть использована только внутри корутины.
|
||||||
|
|||||||
@@ -78,14 +78,18 @@ document["worlds-panel"]:clear()
|
|||||||
| caret | int | да | да | позиция каретки. `textbox.caret = -1` установит позицию в конец текста |
|
| caret | int | да | да | позиция каретки. `textbox.caret = -1` установит позицию в конец текста |
|
||||||
| editable | bool | да | да | изменяемость текста |
|
| editable | bool | да | да | изменяемость текста |
|
||||||
| multiline | bool | да | да | поддержка многострочности |
|
| multiline | bool | да | да | поддержка многострочности |
|
||||||
|
| lineNumbers | bool | да | да | отображение номеров строк |
|
||||||
| textWrap | bool | да | да | автоматический перенос текста (только при multiline: "true") |
|
| textWrap | bool | да | да | автоматический перенос текста (только при multiline: "true") |
|
||||||
| valid | bool | да | нет | является ли введенный текст корректным |
|
| valid | bool | да | нет | является ли введенный текст корректным |
|
||||||
|
| textColor | vec4 | да | да | цвет текста |
|
||||||
|
|
||||||
Методы:
|
Методы:
|
||||||
|
|
||||||
| Метод | Описание |
|
| Метод | Описание |
|
||||||
| ----------- | -------------------------------------------- |
|
| ------------------------- | -------------------------------------------- |
|
||||||
| paste(text) | вставляет указанный текст на позицию каретки |
|
| paste(text: str) | вставляет указанный текст на позицию каретки |
|
||||||
|
| lineAt(pos: int) -> int | определяет номер строки по позиции в тексте |
|
||||||
|
| linePos(line: int) -> int | определяет позицию начала строки в тексте |
|
||||||
|
|
||||||
## Ползунок (trackbar)
|
## Ползунок (trackbar)
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,8 @@
|
|||||||
В число контейнеров также входят панели и кнопки.
|
В число контейнеров также входят панели и кнопки.
|
||||||
- `padding` - внутренний отступ элемента. Тип: 4D вектор.
|
- `padding` - внутренний отступ элемента. Тип: 4D вектор.
|
||||||
Порядок: `"left,top,right,bottom"`
|
Порядок: `"left,top,right,bottom"`
|
||||||
- `scrollable` - возможность скроллинга. Работает только у Panel. Тип: логический.
|
- `scrollable` - возможность скроллинга. Тип: логический.
|
||||||
|
- `scroll-step` - шаг скроллинга. Тип: целочисленный.
|
||||||
|
|
||||||
# Общие атрибуты панелей
|
# Общие атрибуты панелей
|
||||||
|
|
||||||
@@ -105,7 +106,9 @@
|
|||||||
- `multiline` - разрешает отображение многострочного текста.
|
- `multiline` - разрешает отображение многострочного текста.
|
||||||
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
||||||
- `editable`- определяет возможность редактирования текста.
|
- `editable`- определяет возможность редактирования текста.
|
||||||
|
- `line-numbers` - включает отображение номеров строк.
|
||||||
- `error-color` - цвет при вводе некорректных данных (текст не проходит проверку валидатора). Тип: RGBA цвет.
|
- `error-color` - цвет при вводе некорректных данных (текст не проходит проверку валидатора). Тип: RGBA цвет.
|
||||||
|
- `text-color` - цвет текста. Тип: RGBA цвет.
|
||||||
- `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен.
|
- `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен.
|
||||||
- `onup` - lua функция вызываемая при нажатии стрелки вверх.
|
- `onup` - lua функция вызываемая при нажатии стрелки вверх.
|
||||||
- `ondown` - lua функция вызываемая при нажатии стрелки вниз.
|
- `ondown` - lua функция вызываемая при нажатии стрелки вниз.
|
||||||
|
|||||||
+37
-3
@@ -1,5 +1,18 @@
|
|||||||
<container color='#00000080' size='400' size-func="unpack(gui.get_viewport())">
|
<container color='#00000080' size='400' size-func="unpack(gui.get_viewport())">
|
||||||
<container size-func="gui.get_viewport()[1],gui.get_viewport()[2]-40">
|
<panel interval="0"
|
||||||
|
orientation="horizontal"
|
||||||
|
color="#00000010"
|
||||||
|
size-func="gui.get_viewport()[1]-350,30">
|
||||||
|
<button id="s_chat" size="110,30" onclick="modes:set('chat')">@Chat</button>
|
||||||
|
<button id="s_console" size="110,30" onclick="modes:set('console')">@Console</button>
|
||||||
|
<button id="s_debug" size="110,30" onclick="modes:set('debug')">@Debug</button>
|
||||||
|
</panel>
|
||||||
|
<container pos="0,30" size-func="gui.get_viewport()[1]-350,30" color="#00000020">
|
||||||
|
<label id="title" pos="8,8"></label>
|
||||||
|
</container>
|
||||||
|
|
||||||
|
<container id="logContainer" pos="0,60"
|
||||||
|
size-func="unpack(vec2.add(gui.get_viewport(), {0,-100}))">
|
||||||
<textbox
|
<textbox
|
||||||
id='log'
|
id='log'
|
||||||
color='0'
|
color='0'
|
||||||
@@ -11,12 +24,33 @@
|
|||||||
gravity="bottom-left"
|
gravity="bottom-left"
|
||||||
></textbox>
|
></textbox>
|
||||||
</container>
|
</container>
|
||||||
|
<container id="editorContainer" pos="0,60" color="#00000080"
|
||||||
|
size-func="unpack(vec2.add(gui.get_viewport(), {-350,-230}))">
|
||||||
|
<textbox
|
||||||
|
id='editor'
|
||||||
|
color='0'
|
||||||
|
autoresize='true'
|
||||||
|
margin='0'
|
||||||
|
padding='5'
|
||||||
|
editable='false'
|
||||||
|
multiline='true'
|
||||||
|
line-numbers='true'
|
||||||
|
text-color="#FFFFFFA0"
|
||||||
|
size-func="gui.get_viewport()[1]-350,40"
|
||||||
|
gravity="top-left"
|
||||||
|
text-wrap='false'
|
||||||
|
scroll-step='50'
|
||||||
|
></textbox>
|
||||||
|
</container>
|
||||||
|
<panel id="traceback" gravity="bottom-left" padding="4" color="#000000A0"
|
||||||
|
max-length="170" size-func="gui.get_viewport()[1]-350,170">
|
||||||
|
</panel>
|
||||||
<panel id="problemsLog"
|
<panel id="problemsLog"
|
||||||
color="#00000010"
|
color="#00000010"
|
||||||
position-func="gui.get_viewport()[1]-350,0"
|
position-func="gui.get_viewport()[1]-350,0"
|
||||||
size-func="351,gui.get_viewport()[2]-40"
|
size-func="350,gui.get_viewport()[2]-40"
|
||||||
padding="5,15,5,15">
|
padding="5,15,5,15">
|
||||||
<label>@Problems</label>
|
<label margin="0,0,0,5">@Problems</label>
|
||||||
</panel>
|
</panel>
|
||||||
<textbox id='prompt'
|
<textbox id='prompt'
|
||||||
consumer='submit'
|
consumer='submit'
|
||||||
|
|||||||
+126
-5
@@ -1,21 +1,101 @@
|
|||||||
|
console_mode = "console"
|
||||||
|
|
||||||
history = session.get_entry("commands_history")
|
history = session.get_entry("commands_history")
|
||||||
history_pointer = #history
|
history_pointer = #history
|
||||||
|
|
||||||
local warnings_all = {}
|
local warnings_all = {}
|
||||||
|
local errors_all = {}
|
||||||
|
|
||||||
local warning_id = 0
|
local warning_id = 0
|
||||||
events.on("core:warning", function (wtype, text)
|
local error_id = 0
|
||||||
|
|
||||||
|
events.on("core:warning", function (wtype, text, traceback)
|
||||||
local full = wtype..": "..text
|
local full = wtype..": "..text
|
||||||
if table.has(warnings_all, full) then
|
if table.has(warnings_all, full) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
local encoded = base64.encode(bjson.tobytes({frames=traceback}))
|
||||||
document.problemsLog:add(gui.template("problem", {
|
document.problemsLog:add(gui.template("problem", {
|
||||||
type="warning", text=full, id=tostring(warning_id)
|
type="warning",
|
||||||
|
text=full,
|
||||||
|
traceback=encoded,
|
||||||
|
id=tostring(warning_id)
|
||||||
}))
|
}))
|
||||||
warning_id = warning_id + 1
|
warning_id = warning_id + 1
|
||||||
table.insert(warnings_all, full)
|
table.insert(warnings_all, full)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
events.on("core:error", function (msg, traceback)
|
||||||
|
local _, endindex = string.find(msg, ": ")
|
||||||
|
local full = ""
|
||||||
|
for i,frame in ipairs(traceback) do
|
||||||
|
full = full..frame.source..tostring(frame.currentline)
|
||||||
|
end
|
||||||
|
if table.has(errors_all, full) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local encoded = base64.encode(bjson.tobytes({frames=traceback}))
|
||||||
|
document.problemsLog:add(gui.template("problem", {
|
||||||
|
type="error",
|
||||||
|
text=msg:sub(endindex),
|
||||||
|
traceback=encoded,
|
||||||
|
id=tostring(error_id)
|
||||||
|
}))
|
||||||
|
error_id = error_id + 1
|
||||||
|
table.insert(errors_all, full)
|
||||||
|
end)
|
||||||
|
|
||||||
|
events.on("core:open_traceback", function(traceback_b64)
|
||||||
|
local traceback = bjson.frombytes(base64.decode(traceback_b64))
|
||||||
|
modes:set('debug')
|
||||||
|
|
||||||
|
local tb_list = document.traceback
|
||||||
|
local srcsize = tb_list.size
|
||||||
|
tb_list:clear()
|
||||||
|
tb_list:add("<label enabled='false' margin='2'>@devtools.traceback</label>")
|
||||||
|
for _, frame in ipairs(traceback.frames) do
|
||||||
|
local callback = ""
|
||||||
|
local framestr = ""
|
||||||
|
if frame.what == "C" then
|
||||||
|
framestr = "C/C++ "
|
||||||
|
else
|
||||||
|
framestr = frame.source..":"..tostring(frame.currentline).." "
|
||||||
|
if file.exists(frame.source) then
|
||||||
|
callback = string.format(
|
||||||
|
"local editor = document.editor "..
|
||||||
|
"local source = file.read('%s') "..
|
||||||
|
"editor.text = source "..
|
||||||
|
"editor.focused = true "..
|
||||||
|
"time.post_runnable(function()"..
|
||||||
|
"editor.caret = editor:linePos(%s) "..
|
||||||
|
"end)",
|
||||||
|
frame.source, frame.currentline-1
|
||||||
|
)
|
||||||
|
else
|
||||||
|
callback = "document.editor.text = 'Could not open source file'"
|
||||||
|
end
|
||||||
|
callback = string.format(
|
||||||
|
"%s document.title.text = gui.str('File')..' - %s'",
|
||||||
|
callback,
|
||||||
|
frame.source
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if frame.name then
|
||||||
|
framestr = framestr.."("..tostring(frame.name)..")"
|
||||||
|
end
|
||||||
|
local color = "#FFFFFF"
|
||||||
|
if frame.source:starts_with("core:") then
|
||||||
|
color = "#C0D0C5"
|
||||||
|
end
|
||||||
|
tb_list:add(gui.template("stack_frame", {
|
||||||
|
location=framestr,
|
||||||
|
color=color,
|
||||||
|
callback=callback
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
tb_list.size = srcsize
|
||||||
|
end)
|
||||||
|
|
||||||
function setup_variables()
|
function setup_variables()
|
||||||
local pid = hud.get_player()
|
local pid = hud.get_player()
|
||||||
local x,y,z = player.get_pos(pid)
|
local x,y,z = player.get_pos(pid)
|
||||||
@@ -56,10 +136,19 @@ function add_to_history(text)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function submit(text)
|
function submit(text)
|
||||||
|
text = text:trim()
|
||||||
add_to_history(text)
|
add_to_history(text)
|
||||||
|
|
||||||
|
if console_mode == "chat" then
|
||||||
|
if not text:starts_with("/") then
|
||||||
|
text = "chat "..string.escape(text)
|
||||||
|
else
|
||||||
|
text = text:sub(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
setup_variables()
|
setup_variables()
|
||||||
|
|
||||||
text = text:trim()
|
|
||||||
local name
|
local name
|
||||||
for s in text:gmatch("%S+") do
|
for s in text:gmatch("%S+") do
|
||||||
name = s
|
name = s
|
||||||
@@ -84,6 +173,38 @@ function submit(text)
|
|||||||
document.prompt.focused = true
|
document.prompt.focused = true
|
||||||
end
|
end
|
||||||
|
|
||||||
function on_open()
|
function set_mode(mode)
|
||||||
document.prompt.focused = true
|
local show_prompt = mode == 'chat' or mode == 'console'
|
||||||
|
|
||||||
|
document.title.text = ""
|
||||||
|
document.editorContainer.visible = mode == 'debug'
|
||||||
|
document.logContainer.visible = mode ~= 'debug'
|
||||||
|
|
||||||
|
if mode == 'debug' then
|
||||||
|
document.root.color = {16, 18, 20, 220}
|
||||||
|
else
|
||||||
|
document.root.color = {0, 0, 0, 128}
|
||||||
|
end
|
||||||
|
|
||||||
|
document.traceback.visible = mode == 'debug'
|
||||||
|
document.prompt.visible = show_prompt
|
||||||
|
if show_prompt then
|
||||||
|
document.prompt.focused = true
|
||||||
|
end
|
||||||
|
console_mode = mode
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_open(mode)
|
||||||
|
if modes == nil then
|
||||||
|
modes = RadioGroup({
|
||||||
|
chat=document.s_chat,
|
||||||
|
console=document.s_console,
|
||||||
|
debug=document.s_debug
|
||||||
|
}, function (mode)
|
||||||
|
set_mode(mode)
|
||||||
|
end, "console")
|
||||||
|
end
|
||||||
|
if mode then
|
||||||
|
modes:set(mode)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<container size='668,418' color='#0F1E2DB2' context='menu'>
|
<container size='668,418' color='#0F1E2DB2' context='menu'>
|
||||||
<panel pos='6' size='250' color='0' interval='1'>
|
<panel pos='6' size='250' color='0' interval='1'>
|
||||||
<button id='s_aud' onclick='set_page("s_aud", "settings_audio")'>@Audio</button>
|
<button id='s_aud' onclick='sections:set("audio")'>@Audio</button>
|
||||||
<button id='s_dsp' onclick='set_page("s_dsp", "settings_display")'>@Display</button>
|
<button id='s_dsp' onclick='sections:set("display")'>@Display</button>
|
||||||
<button id='s_gfx' onclick='set_page("s_gfx", "settings_graphics")'>@Graphics</button>
|
<button id='s_gfx' onclick='sections:set("graphics")'>@Graphics</button>
|
||||||
<button id='s_ctl' onclick='set_page("s_ctl", "settings_controls")'>@Controls</button>
|
<button id='s_ctl' onclick='sections:set("controls")'>@Controls</button>
|
||||||
</panel>
|
</panel>
|
||||||
<pagebox id='menu' pos='260,6' size='400'>
|
<pagebox id='menu' pos='260,6' size='400'>
|
||||||
</pagebox>
|
</pagebox>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<panel margin='6' gravity='bottom-left' size='250' color='0' interval='1'>
|
<panel margin='6' gravity='bottom-left' size='250' color='0' interval='1'>
|
||||||
<button onclick='menu.page="languages"' id='langs_btn'>-</button>
|
<button onclick='menu.page="languages"' id='langs_btn'>-</button>
|
||||||
<button onclick='core.open_folder("user:")'>@Open data folder</button>
|
<button onclick='core.open_folder("user:")'>@Open data folder</button>
|
||||||
<button id='s_rst' onclick='set_page("s_rst", "settings_reset")'>@Reset settings</button>
|
<button id='s_rst' onclick='sections:set("reset")'>@Reset settings</button>
|
||||||
<button onclick='menu:back()'>@Back</button>
|
<button onclick='menu:back()'>@Back</button>
|
||||||
</panel>
|
</panel>
|
||||||
</container>
|
</container>
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ function on_open()
|
|||||||
"%s: %s", gui.str("Language", "settings"),
|
"%s: %s", gui.str("Language", "settings"),
|
||||||
gui.get_locales_info()[core.get_setting("ui.language")].name
|
gui.get_locales_info()[core.get_setting("ui.language")].name
|
||||||
)
|
)
|
||||||
set_page("s_gfx", "settings_graphics")
|
sections = RadioGroup({
|
||||||
end
|
audio=document.s_aud,
|
||||||
|
display=document.s_dsp,
|
||||||
function set_page(btn, page)
|
graphics=document.s_gfx,
|
||||||
document.s_aud.enabled = true
|
controls=document.s_ctl,
|
||||||
document.s_dsp.enabled = true
|
reset=document.s_rst
|
||||||
document.s_gfx.enabled = true
|
}, function (page)
|
||||||
document.s_ctl.enabled = true
|
document.menu.page = "settings_"..page
|
||||||
document.s_rst.enabled = true
|
end, "graphics")
|
||||||
document[btn].enabled = false
|
|
||||||
document.menu.page = page
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<container id="%{id}" size="32" tooltip="%{text}">
|
<container id="%{id}" size="32" tooltip="%{text}"
|
||||||
|
onclick="events.emit('core:open_traceback', '%{traceback}')">
|
||||||
<image src="gui/%{type}" size="32"/>
|
<image src="gui/%{type}" size="32"/>
|
||||||
<label pos="36,2">%{text}</label>
|
<label pos="36,2">%{text}</label>
|
||||||
<image src="gui/cross" interactive="true" size="16" gravity="top-right"
|
<image src="gui/cross" interactive="true" size="16" gravity="top-right"
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<label hover-color="#A0A0FF" interactive="true" onclick="%{callback}" color="%{color}">
|
||||||
|
%{location}
|
||||||
|
</label>
|
||||||
@@ -256,6 +256,14 @@ console.add_command(
|
|||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
console.add_command(
|
||||||
|
"chat text:str",
|
||||||
|
"Send chat message",
|
||||||
|
function (args, kwargs)
|
||||||
|
console.log("[you] "..args[1])
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
console.cheats = {
|
console.cheats = {
|
||||||
"blocks.fill",
|
"blocks.fill",
|
||||||
"tp",
|
"tp",
|
||||||
|
|||||||
@@ -84,6 +84,32 @@ function Document.new(docname)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local _RadioGroup = {}
|
||||||
|
function _RadioGroup.set(self, key)
|
||||||
|
if type(self) ~= 'table' then
|
||||||
|
error("called as non-OOP via '.', use radiogroup:set")
|
||||||
|
end
|
||||||
|
if self.current then
|
||||||
|
self.elements[self.current].enabled = true
|
||||||
|
end
|
||||||
|
self.elements[key].enabled = false
|
||||||
|
self.current = key
|
||||||
|
if self.callback then
|
||||||
|
self.callback(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function _RadioGroup.__call(self, elements, onset, default)
|
||||||
|
local group = setmetatable({
|
||||||
|
elements=elements,
|
||||||
|
callback=onset,
|
||||||
|
current=nil
|
||||||
|
}, {__index=_RadioGroup})
|
||||||
|
group:set(default)
|
||||||
|
return group
|
||||||
|
end
|
||||||
|
setmetatable(_RadioGroup, _RadioGroup)
|
||||||
|
RadioGroup = _RadioGroup
|
||||||
|
|
||||||
_GUI_ROOT = Document.new("core:root")
|
_GUI_ROOT = Document.new("core:root")
|
||||||
_MENU = _GUI_ROOT.menu
|
_MENU = _GUI_ROOT.menu
|
||||||
menu = _MENU
|
menu = _MENU
|
||||||
|
|||||||
+24
-2
@@ -162,6 +162,7 @@ end
|
|||||||
|
|
||||||
string.lower = utf8.lower
|
string.lower = utf8.lower
|
||||||
string.upper = utf8.upper
|
string.upper = utf8.upper
|
||||||
|
string.escape = utf8.escape
|
||||||
|
|
||||||
local meta = getmetatable("")
|
local meta = getmetatable("")
|
||||||
|
|
||||||
@@ -227,8 +228,22 @@ function file.readlines(path)
|
|||||||
return lines
|
return lines
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function debug.get_traceback(start)
|
||||||
|
local frames = {}
|
||||||
|
local n = 2 + (start or 0)
|
||||||
|
while true do
|
||||||
|
local info = debug.getinfo(n)
|
||||||
|
if info then
|
||||||
|
table.insert(frames, info)
|
||||||
|
else
|
||||||
|
return frames
|
||||||
|
end
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
package = {
|
package = {
|
||||||
loaded={}
|
loaded = {}
|
||||||
}
|
}
|
||||||
local __cached_scripts = {}
|
local __cached_scripts = {}
|
||||||
local __warnings_hidden = {}
|
local __warnings_hidden = {}
|
||||||
@@ -238,7 +253,7 @@ function on_deprecated_call(name, alternatives)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
__warnings_hidden[name] = true
|
__warnings_hidden[name] = true
|
||||||
events.emit("core:warning", "deprecated call", name)
|
events.emit("core:warning", "deprecated call", name, debug.get_traceback(2))
|
||||||
if alternatives then
|
if alternatives then
|
||||||
debug.warning("deprecated function called ("..name.."), use "..
|
debug.warning("deprecated function called ("..name.."), use "..
|
||||||
alternatives.." instead\n"..debug.traceback())
|
alternatives.." instead\n"..debug.traceback())
|
||||||
@@ -292,3 +307,10 @@ function __scripts_cleanup()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function __vc__error(msg, frame)
|
||||||
|
if events then
|
||||||
|
events.emit("core:error", msg, debug.get_traceback(1))
|
||||||
|
end
|
||||||
|
return debug.traceback(msg, frame)
|
||||||
|
end
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ world.delete-confirm=Do you want to delete world forever?
|
|||||||
world.generators.default=Default
|
world.generators.default=Default
|
||||||
world.generators.flat=Flat
|
world.generators.flat=Flat
|
||||||
|
|
||||||
|
devtools.traceback=Traceback (most recent call first)
|
||||||
|
|
||||||
# Tooltips
|
# Tooltips
|
||||||
graphics.gamma.tooltip=Lighting brightness curve
|
graphics.gamma.tooltip=Lighting brightness curve
|
||||||
graphics.backlight.tooltip=Backlight to prevent total darkness
|
graphics.backlight.tooltip=Backlight to prevent total darkness
|
||||||
|
|||||||
@@ -12,7 +12,15 @@ Dependencies=Зависимости
|
|||||||
Description=Описание
|
Description=Описание
|
||||||
Converting world...=Выполняется конвертация мира...
|
Converting world...=Выполняется конвертация мира...
|
||||||
Unlimited=Неограниченно
|
Unlimited=Неограниченно
|
||||||
|
Chat=Чат
|
||||||
|
Console=Консоль
|
||||||
|
Log=Лог
|
||||||
|
Problems=Проблемы
|
||||||
|
Monitor=Мониторинг
|
||||||
|
Debug=Отладка
|
||||||
|
File=Файл
|
||||||
|
|
||||||
|
devtools.traceback=Стек вызовов (от последнего)
|
||||||
error.pack-not-found=Не удалось найти пакет
|
error.pack-not-found=Не удалось найти пакет
|
||||||
error.dependency-not-found=Используемая зависимость не найдена
|
error.dependency-not-found=Используемая зависимость не найдена
|
||||||
pack.remove-confirm=Удалить весь поставляемый паком/паками контент из мира (безвозвратно)?
|
pack.remove-confirm=Удалить весь поставляемый паком/паками контент из мира (безвозвратно)?
|
||||||
|
|||||||
@@ -172,7 +172,9 @@ assetload::postfunc assetload::layout(
|
|||||||
return [=](auto assets) {
|
return [=](auto assets) {
|
||||||
try {
|
try {
|
||||||
auto cfg = std::dynamic_pointer_cast<LayoutCfg>(config);
|
auto cfg = std::dynamic_pointer_cast<LayoutCfg>(config);
|
||||||
assets->store(UiDocument::read(cfg->env, name, file), name);
|
assets->store(
|
||||||
|
UiDocument::read(cfg->env, name, file, "abs:" + file), name
|
||||||
|
);
|
||||||
} catch (const parsing_error& err) {
|
} catch (const parsing_error& err) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"failed to parse layout XML '" + file + "':\n" + err.errorLog()
|
"failed to parse layout XML '" + file + "':\n" + err.errorLog()
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ std::string BasicParser::parseString(char quote, bool closeRequired) {
|
|||||||
case 'b': ss << '\b'; break;
|
case 'b': ss << '\b'; break;
|
||||||
case 't': ss << '\t'; break;
|
case 't': ss << '\t'; break;
|
||||||
case 'f': ss << '\f'; break;
|
case 'f': ss << '\f'; break;
|
||||||
case '\'': ss << '\\'; break;
|
case '\'': ss << '\''; break;
|
||||||
case '"': ss << '"'; break;
|
case '"': ss << '"'; break;
|
||||||
case '\\': ss << '\\'; break;
|
case '\\': ss << '\\'; break;
|
||||||
case '/': ss << '/'; break;
|
case '/': ss << '/'; break;
|
||||||
|
|||||||
+3
-2
@@ -250,7 +250,8 @@ std::string Parser::parseText() {
|
|||||||
}
|
}
|
||||||
nextChar();
|
nextChar();
|
||||||
}
|
}
|
||||||
return std::string(source.substr(start, pos - start));
|
return Parser("<string>", std::string(source.substr(start, pos - start)))
|
||||||
|
.parseString('\0', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_xml_identifier_start(char c) {
|
inline bool is_xml_identifier_start(char c) {
|
||||||
@@ -336,7 +337,7 @@ xmldocument Parser::parse() {
|
|||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmldocument xml::parse(const std::string& filename, const std::string& source) {
|
xmldocument xml::parse(std::string_view filename, std::string_view source) {
|
||||||
Parser parser(filename, source);
|
Parser parser(filename, source);
|
||||||
return parser.parse();
|
return parser.parse();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -140,6 +140,6 @@ namespace xml {
|
|||||||
/// @param source xml source code string
|
/// @param source xml source code string
|
||||||
/// @return xml document
|
/// @return xml document
|
||||||
extern xmldocument parse(
|
extern xmldocument parse(
|
||||||
const std::string& filename, const std::string& source
|
std::string_view filename, std::string_view source
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -485,7 +485,13 @@ void ContentLoader::loadBlock(
|
|||||||
|
|
||||||
auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua");
|
auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua");
|
||||||
if (fs::is_regular_file(scriptfile)) {
|
if (fs::is_regular_file(scriptfile)) {
|
||||||
scripting::load_block_script(env, full, scriptfile, def.rt.funcsset);
|
scripting::load_block_script(
|
||||||
|
env,
|
||||||
|
full,
|
||||||
|
scriptfile,
|
||||||
|
pack->id + ":scripts/" + def.scriptName + ".lua",
|
||||||
|
def.rt.funcsset
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!def.hidden) {
|
if (!def.hidden) {
|
||||||
auto& item = builder.items.create(full + BLOCK_ITEM_SUFFIX);
|
auto& item = builder.items.create(full + BLOCK_ITEM_SUFFIX);
|
||||||
@@ -511,7 +517,13 @@ void ContentLoader::loadItem(
|
|||||||
|
|
||||||
auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua");
|
auto scriptfile = folder / fs::path("scripts/" + def.scriptName + ".lua");
|
||||||
if (fs::is_regular_file(scriptfile)) {
|
if (fs::is_regular_file(scriptfile)) {
|
||||||
scripting::load_item_script(env, full, scriptfile, def.rt.funcsset);
|
scripting::load_item_script(
|
||||||
|
env,
|
||||||
|
full,
|
||||||
|
scriptfile,
|
||||||
|
pack->id + ":scripts/" + def.scriptName + ".lua",
|
||||||
|
def.rt.funcsset
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,7 +732,11 @@ void ContentLoader::load() {
|
|||||||
fs::path scriptFile = folder / fs::path("scripts/world.lua");
|
fs::path scriptFile = folder / fs::path("scripts/world.lua");
|
||||||
if (fs::is_regular_file(scriptFile)) {
|
if (fs::is_regular_file(scriptFile)) {
|
||||||
scripting::load_world_script(
|
scripting::load_world_script(
|
||||||
env, pack->id, scriptFile, runtime->worldfuncsset
|
env,
|
||||||
|
pack->id,
|
||||||
|
scriptFile,
|
||||||
|
pack->id + ":scripts/world.lua",
|
||||||
|
runtime->worldfuncsset
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,7 +811,11 @@ void ContentLoader::load() {
|
|||||||
fs::path componentsDir = folder / fs::u8path("scripts/components");
|
fs::path componentsDir = folder / fs::u8path("scripts/components");
|
||||||
foreach_file(componentsDir, [this](const fs::path& file) {
|
foreach_file(componentsDir, [this](const fs::path& file) {
|
||||||
auto name = pack->id + ":" + file.stem().u8string();
|
auto name = pack->id + ":" + file.stem().u8string();
|
||||||
scripting::load_entity_component(name, file);
|
scripting::load_entity_component(
|
||||||
|
name,
|
||||||
|
file,
|
||||||
|
pack->id + ":scripts/components/" + file.filename().u8string()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Process content.json and load defined content units
|
// Process content.json and load defined content units
|
||||||
|
|||||||
@@ -53,7 +53,12 @@ scriptenv UiDocument::getEnvironment() const {
|
|||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<UiDocument> UiDocument::read(const scriptenv& penv, const std::string& name, const fs::path& file) {
|
std::unique_ptr<UiDocument> UiDocument::read(
|
||||||
|
const scriptenv& penv,
|
||||||
|
const std::string& name,
|
||||||
|
const fs::path& file,
|
||||||
|
const std::string& fileName
|
||||||
|
) {
|
||||||
const std::string text = files::read_string(file);
|
const std::string text = files::read_string(file);
|
||||||
auto xmldoc = xml::parse(file.u8string(), text);
|
auto xmldoc = xml::parse(file.u8string(), text);
|
||||||
|
|
||||||
@@ -69,12 +74,16 @@ std::unique_ptr<UiDocument> UiDocument::read(const scriptenv& penv, const std::s
|
|||||||
uidocscript script {};
|
uidocscript script {};
|
||||||
auto scriptFile = fs::path(file.u8string()+".lua");
|
auto scriptFile = fs::path(file.u8string()+".lua");
|
||||||
if (fs::is_regular_file(scriptFile)) {
|
if (fs::is_regular_file(scriptFile)) {
|
||||||
scripting::load_layout_script(env, name, scriptFile, script);
|
scripting::load_layout_script(
|
||||||
|
env, name, scriptFile, fileName + ".lua", script
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return std::make_unique<UiDocument>(name, script, view, env);
|
return std::make_unique<UiDocument>(name, script, view, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<gui::UINode> UiDocument::readElement(const fs::path& file) {
|
std::shared_ptr<gui::UINode> UiDocument::readElement(
|
||||||
auto document = read(nullptr, file.filename().u8string(), file);
|
const fs::path& file, const std::string& fileName
|
||||||
|
) {
|
||||||
|
auto document = read(nullptr, file.filename().u8string(), file, fileName);
|
||||||
return document->getRoot();
|
return document->getRoot();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,13 @@ public:
|
|||||||
const uidocscript& getScript() const;
|
const uidocscript& getScript() const;
|
||||||
scriptenv getEnvironment() const;
|
scriptenv getEnvironment() const;
|
||||||
|
|
||||||
static std::unique_ptr<UiDocument> read(const scriptenv& parent_env, const std::string& name, const fs::path& file);
|
static std::unique_ptr<UiDocument> read(
|
||||||
static std::shared_ptr<gui::UINode> readElement(const fs::path& file);
|
const scriptenv& parent_env,
|
||||||
|
const std::string& name,
|
||||||
|
const fs::path& file,
|
||||||
|
const std::string& fileName
|
||||||
|
);
|
||||||
|
static std::shared_ptr<gui::UINode> readElement(
|
||||||
|
const fs::path& file, const std::string& fileName
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+17
-7
@@ -230,7 +230,11 @@ void Hud::processInput(bool visible) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!pause && Events::jactive(BIND_DEVTOOLS_CONSOLE)) {
|
if (!pause && Events::jactive(BIND_DEVTOOLS_CONSOLE)) {
|
||||||
showOverlay(assets->get<UiDocument>("core:console"), false);
|
showOverlay(
|
||||||
|
assets->get<UiDocument>("core:console"),
|
||||||
|
false,
|
||||||
|
std::string("console")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!Window::isFocused() && !pause && !isInventoryOpen()) {
|
if (!Window::isFocused() && !pause && !isInventoryOpen()) {
|
||||||
setPause(true);
|
setPause(true);
|
||||||
@@ -465,7 +469,9 @@ void Hud::showExchangeSlot() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hud::showOverlay(UiDocument* doc, bool playerInventory) {
|
void Hud::showOverlay(
|
||||||
|
UiDocument* doc, bool playerInventory, const dv::value& arg
|
||||||
|
) {
|
||||||
if (isInventoryOpen()) {
|
if (isInventoryOpen()) {
|
||||||
closeInventory();
|
closeInventory();
|
||||||
}
|
}
|
||||||
@@ -476,7 +482,8 @@ void Hud::showOverlay(UiDocument* doc, bool playerInventory) {
|
|||||||
showExchangeSlot();
|
showExchangeSlot();
|
||||||
inventoryOpen = true;
|
inventoryOpen = true;
|
||||||
}
|
}
|
||||||
add(HudElement(hud_element_mode::inventory_bound, doc, secondUI, false));
|
add(HudElement(hud_element_mode::inventory_bound, doc, secondUI, false),
|
||||||
|
arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hud::openPermanent(UiDocument* doc) {
|
void Hud::openPermanent(UiDocument* doc) {
|
||||||
@@ -508,13 +515,13 @@ void Hud::closeInventory() {
|
|||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hud::add(const HudElement& element) {
|
void Hud::add(const HudElement& element, const dv::value& arg) {
|
||||||
gui->add(element.getNode());
|
gui->add(element.getNode());
|
||||||
auto document = element.getDocument();
|
auto document = element.getDocument();
|
||||||
if (document) {
|
if (document) {
|
||||||
auto invview = std::dynamic_pointer_cast<InventoryView>(element.getNode());
|
auto invview = std::dynamic_pointer_cast<InventoryView>(element.getNode());
|
||||||
auto inventory = invview ? invview->getInventory() : nullptr;
|
auto inventory = invview ? invview->getInventory() : nullptr;
|
||||||
std::vector<dv::value> args;
|
std::vector<dv::value> args {arg};
|
||||||
args.emplace_back(inventory ? inventory.get()->getId() : 0);
|
args.emplace_back(inventory ? inventory.get()->getId() : 0);
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
args.emplace_back(static_cast<integer_t>(blockPos[i]));
|
args.emplace_back(static_cast<integer_t>(blockPos[i]));
|
||||||
@@ -615,8 +622,11 @@ void Hud::updateElementsPosition(const Viewport& viewport) {
|
|||||||
}
|
}
|
||||||
if (secondUI->getPositionFunc() == nullptr) {
|
if (secondUI->getPositionFunc() == nullptr) {
|
||||||
secondUI->setPos(glm::vec2(
|
secondUI->setPos(glm::vec2(
|
||||||
glm::min(width/2-invwidth/2, width-caWidth-(inventoryView ? 10 : 0)-invwidth),
|
glm::min(
|
||||||
height/2-totalHeight/2
|
width / 2.f - invwidth / 2.f,
|
||||||
|
width - caWidth - (inventoryView ? 10 : 0) - invwidth
|
||||||
|
),
|
||||||
|
height / 2.f - totalHeight / 2.f
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "typedefs.hpp"
|
#include "typedefs.hpp"
|
||||||
#include "util/ObjectsKeeper.hpp"
|
#include "util/ObjectsKeeper.hpp"
|
||||||
|
#include "data/dv.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -173,7 +174,10 @@ public:
|
|||||||
/// @brief Show element in inventory-mode
|
/// @brief Show element in inventory-mode
|
||||||
/// @param doc element layout
|
/// @param doc element layout
|
||||||
/// @param playerInventory show player inventory too
|
/// @param playerInventory show player inventory too
|
||||||
void showOverlay(UiDocument* doc, bool playerInventory);
|
/// @param arg first argument passing to on_open
|
||||||
|
void showOverlay(
|
||||||
|
UiDocument* doc, bool playerInventory, const dv::value& arg = nullptr
|
||||||
|
);
|
||||||
|
|
||||||
/// @brief Close all open inventories and overlay
|
/// @brief Close all open inventories and overlay
|
||||||
void closeInventory();
|
void closeInventory();
|
||||||
@@ -182,7 +186,7 @@ public:
|
|||||||
/// @param doc element layout
|
/// @param doc element layout
|
||||||
void openPermanent(UiDocument* doc);
|
void openPermanent(UiDocument* doc);
|
||||||
|
|
||||||
void add(const HudElement& element);
|
void add(const HudElement& element, const dv::value& arg=nullptr);
|
||||||
void onRemove(const HudElement& element);
|
void onRemove(const HudElement& element);
|
||||||
void remove(const std::shared_ptr<gui::UINode>& node);
|
void remove(const std::shared_ptr<gui::UINode>& node);
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,10 @@ gui::page_loader_func menus::create_page_loader(Engine* engine) {
|
|||||||
auto fullname = "core:pages/"+name;
|
auto fullname = "core:pages/"+name;
|
||||||
|
|
||||||
auto document_ptr = UiDocument::read(
|
auto document_ptr = UiDocument::read(
|
||||||
scripting::get_root_environment(), fullname, file
|
scripting::get_root_environment(),
|
||||||
|
fullname,
|
||||||
|
file,
|
||||||
|
"core:layout/pages/" + name
|
||||||
);
|
);
|
||||||
auto document = document_ptr.get();
|
auto document = document_ptr.get();
|
||||||
engine->getAssets()->store(std::move(document_ptr), fullname);
|
engine->getAssets()->store(std::move(document_ptr), fullname);
|
||||||
@@ -110,7 +113,7 @@ UiDocument* menus::show(Engine* engine, const std::string& name, std::vector<dv:
|
|||||||
auto fullname = "core:layouts/"+name;
|
auto fullname = "core:layouts/"+name;
|
||||||
|
|
||||||
auto document_ptr = UiDocument::read(
|
auto document_ptr = UiDocument::read(
|
||||||
scripting::get_root_environment(), fullname, file
|
scripting::get_root_environment(), fullname, file, "core:layouts/"+name
|
||||||
);
|
);
|
||||||
auto document = document_ptr.get();
|
auto document = document_ptr.get();
|
||||||
engine->getAssets()->store(std::move(document_ptr), fullname);
|
engine->getAssets()->store(std::move(document_ptr), fullname);
|
||||||
|
|||||||
@@ -83,7 +83,12 @@ void LevelScreen::initializePack(ContentPackRuntime* pack) {
|
|||||||
const ContentPack& info = pack->getInfo();
|
const ContentPack& info = pack->getInfo();
|
||||||
fs::path scriptFile = info.folder/fs::path("scripts/hud.lua");
|
fs::path scriptFile = info.folder/fs::path("scripts/hud.lua");
|
||||||
if (fs::is_regular_file(scriptFile)) {
|
if (fs::is_regular_file(scriptFile)) {
|
||||||
scripting::load_hud_script(pack->getEnvironment(), info.id, scriptFile);
|
scripting::load_hud_script(
|
||||||
|
pack->getEnvironment(),
|
||||||
|
info.id,
|
||||||
|
scriptFile,
|
||||||
|
pack->getId() + ":scripts/hud.lua"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ DrawContext DrawContext::sub(Flushable* flushable) const {
|
|||||||
auto ctx = DrawContext(*this);
|
auto ctx = DrawContext(*this);
|
||||||
ctx.parent = this;
|
ctx.parent = this;
|
||||||
ctx.flushable = flushable;
|
ctx.flushable = flushable;
|
||||||
|
ctx.scissorsCount = 0;
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +149,7 @@ void DrawContext::setBlendMode(BlendMode mode) {
|
|||||||
set_blend_mode(mode);
|
set_blend_mode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawContext::setScissors(glm::vec4 area) {
|
void DrawContext::setScissors(const glm::vec4& area) {
|
||||||
Window::pushScissor(area);
|
Window::pushScissor(area);
|
||||||
scissorsCount++;
|
scissorsCount++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,6 @@ public:
|
|||||||
void setDepthTest(bool flag);
|
void setDepthTest(bool flag);
|
||||||
void setCullFace(bool flag);
|
void setCullFace(bool flag);
|
||||||
void setBlendMode(BlendMode mode);
|
void setBlendMode(BlendMode mode);
|
||||||
void setScissors(glm::vec4 area);
|
void setScissors(const glm::vec4& area);
|
||||||
void setLineWidth(float width);
|
void setLineWidth(float width);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ void Container::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
if (!nodes.empty()) {
|
if (!nodes.empty()) {
|
||||||
batch->flush();
|
batch->flush();
|
||||||
DrawContext ctx = pctx->sub();
|
DrawContext ctx = pctx->sub();
|
||||||
ctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y));
|
ctx.setScissors(glm::vec4(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y)));
|
||||||
for (const auto& node : nodes) {
|
for (const auto& node : nodes) {
|
||||||
if (node->isVisible())
|
if (node->isVisible())
|
||||||
node->draw(pctx, assets);
|
node->draw(pctx, assets);
|
||||||
@@ -108,7 +108,7 @@ void Container::drawBackground(const DrawContext* pctx, Assets*) {
|
|||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx->getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
batch->setColor(color);
|
batch->setColor(color);
|
||||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
batch->rect(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::add(const std::shared_ptr<UINode> &node) {
|
void Container::add(const std::shared_ptr<UINode> &node) {
|
||||||
@@ -165,6 +165,14 @@ void Container::setSize(glm::vec2 size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Container::getScrollStep() const {
|
||||||
|
return scrollStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Container::setScrollStep(int step) {
|
||||||
|
scrollStep = step;
|
||||||
|
}
|
||||||
|
|
||||||
void Container::refresh() {
|
void Container::refresh() {
|
||||||
std::stable_sort(nodes.begin(), nodes.end(), [](const auto& a, const auto& b) {
|
std::stable_sort(nodes.begin(), nodes.end(), [](const auto& a, const auto& b) {
|
||||||
return a->getZIndex() < b->getZIndex();
|
return a->getZIndex() < b->getZIndex();
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ namespace gui {
|
|||||||
void listenInterval(float interval, ontimeout callback, int repeat=-1);
|
void listenInterval(float interval, ontimeout callback, int repeat=-1);
|
||||||
virtual glm::vec2 getContentOffset() override {return glm::vec2(0.0f, scroll);};
|
virtual glm::vec2 getContentOffset() override {return glm::vec2(0.0f, scroll);};
|
||||||
virtual void setSize(glm::vec2 size) override;
|
virtual void setSize(glm::vec2 size) override;
|
||||||
|
virtual int getScrollStep() const;
|
||||||
|
virtual void setScrollStep(int step);
|
||||||
virtual void refresh() override;
|
virtual void refresh() override;
|
||||||
|
|
||||||
const std::vector<std::shared_ptr<UINode>>& getNodes() const;
|
const std::vector<std::shared_ptr<UINode>>& getNodes() const;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "TextBox.hpp"
|
#include "TextBox.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -14,24 +15,39 @@
|
|||||||
|
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
|
inline constexpr int LINE_NUMBERS_PANE_WIDTH = 40;
|
||||||
|
|
||||||
TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
|
TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
|
||||||
: Panel(glm::vec2(200,32), padding, 0),
|
: Container(glm::vec2(200,32)),
|
||||||
|
padding(padding),
|
||||||
input(L""),
|
input(L""),
|
||||||
placeholder(std::move(placeholder))
|
placeholder(std::move(placeholder))
|
||||||
{
|
{
|
||||||
setOnUpPressed(nullptr);
|
setOnUpPressed(nullptr);
|
||||||
setOnDownPressed(nullptr);
|
setOnDownPressed(nullptr);
|
||||||
|
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f));
|
||||||
label = std::make_shared<Label>(L"");
|
label = std::make_shared<Label>(L"");
|
||||||
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
||||||
|
label->setPos(glm::vec2(
|
||||||
|
padding.x + LINE_NUMBERS_PANE_WIDTH * showLineNumbers, padding.y
|
||||||
|
));
|
||||||
add(label);
|
add(label);
|
||||||
|
|
||||||
|
lineNumbersLabel = std::make_shared<Label>(L"");
|
||||||
|
lineNumbersLabel->setMultiline(true);
|
||||||
|
lineNumbersLabel->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
||||||
|
lineNumbersLabel->setVerticalAlign(Align::top);
|
||||||
|
add(lineNumbersLabel);
|
||||||
|
|
||||||
setHoverColor(glm::vec4(0.05f, 0.1f, 0.2f, 0.75f));
|
setHoverColor(glm::vec4(0.05f, 0.1f, 0.2f, 0.75f));
|
||||||
|
|
||||||
textInitX = label->getPos().x;
|
textInitX = label->getPos().x;
|
||||||
scrollable = true;
|
scrollable = true;
|
||||||
|
scrollStep = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::draw(const DrawContext* pctx, Assets* assets) {
|
void TextBox::draw(const DrawContext* pctx, Assets* assets) {
|
||||||
Panel::draw(pctx, assets);
|
Container::draw(pctx, assets);
|
||||||
|
|
||||||
font = assets->get<Font>(label->getFontName());
|
font = assets->get<Font>(label->getFontName());
|
||||||
|
|
||||||
@@ -76,6 +92,44 @@ void TextBox::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
batch->rect(lcoord.x, lcoord.y+label->getLineYOffset(endLine), end, lineHeight);
|
batch->rect(lcoord.x, lcoord.y+label->getLineYOffset(endLine), end, lineHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isFocused() && multiline) {
|
||||||
|
auto selectionCtx = subctx.sub(batch);
|
||||||
|
selectionCtx.setBlendMode(BlendMode::addition);
|
||||||
|
|
||||||
|
batch->setColor(glm::vec4(1, 1, 1, 0.1f));
|
||||||
|
|
||||||
|
uint line = label->getLineByTextIndex(caret);
|
||||||
|
while (label->isFakeLine(line)) {
|
||||||
|
line--;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
int lineY = label->getLineYOffset(line);
|
||||||
|
int lineHeight = font->getLineHeight() * label->getLineInterval();
|
||||||
|
|
||||||
|
batch->setColor(glm::vec4(1, 1, 1, 0.05f));
|
||||||
|
if (showLineNumbers) {
|
||||||
|
batch->rect(
|
||||||
|
lcoord.x - 8,
|
||||||
|
lcoord.y + lineY,
|
||||||
|
label->getSize().x,
|
||||||
|
lineHeight
|
||||||
|
);
|
||||||
|
batch->setColor(glm::vec4(1, 1, 1, 0.10f));
|
||||||
|
batch->rect(
|
||||||
|
lcoord.x - LINE_NUMBERS_PANE_WIDTH,
|
||||||
|
lcoord.y + lineY,
|
||||||
|
LINE_NUMBERS_PANE_WIDTH - 8,
|
||||||
|
lineHeight
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
batch->rect(
|
||||||
|
lcoord.x, lcoord.y + lineY, label->getSize().x, lineHeight
|
||||||
|
);
|
||||||
|
}
|
||||||
|
line++;
|
||||||
|
} while (line < label->getLinesNumber() && label->isFakeLine(line));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::drawBackground(const DrawContext* pctx, Assets*) {
|
void TextBox::drawBackground(const DrawContext* pctx, Assets*) {
|
||||||
@@ -103,32 +157,32 @@ void TextBox::drawBackground(const DrawContext* pctx, Assets*) {
|
|||||||
if (!isFocused() && supplier) {
|
if (!isFocused() && supplier) {
|
||||||
input = supplier();
|
input = supplier();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFocused() && multiline) {
|
|
||||||
batch->setColor(glm::vec4(1, 1, 1, 0.1f));
|
|
||||||
glm::vec2 lcoord = label->calcPos();
|
|
||||||
lcoord.y -= 2;
|
|
||||||
|
|
||||||
uint line = label->getLineByTextIndex(caret);
|
|
||||||
while (label->isFakeLine(line)) {
|
|
||||||
line--;
|
|
||||||
}
|
|
||||||
batch->setColor(glm::vec4(1, 1, 1, 0.05f));
|
|
||||||
do {
|
|
||||||
int lineY = label->getLineYOffset(line);
|
|
||||||
int lineHeight = font->getLineHeight() * label->getLineInterval();
|
|
||||||
|
|
||||||
batch->rect(lcoord.x, lcoord.y+lineY, label->getSize().x, lineHeight);
|
|
||||||
line++;
|
|
||||||
} while (line < label->getLinesNumber() && label->isFakeLine(line));
|
|
||||||
}
|
|
||||||
refreshLabel();
|
refreshLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::refreshLabel() {
|
void TextBox::refreshLabel() {
|
||||||
label->setColor(glm::vec4(input.empty() ? 0.5f : 1.0f));
|
label->setColor(textColor * glm::vec4(input.empty() ? 0.5f : 1.0f));
|
||||||
label->setText(input.empty() && !hint.empty() ? hint : getText());
|
label->setText(input.empty() && !hint.empty() ? hint : getText());
|
||||||
|
|
||||||
|
if (showLineNumbers) {
|
||||||
|
if (lineNumbersLabel->getLinesNumber() != label->getLinesNumber()) {
|
||||||
|
std::wstringstream ss;
|
||||||
|
int n = 1;
|
||||||
|
for (int i = 1; i <= label->getLinesNumber(); i++) {
|
||||||
|
if (!label->isFakeLine(i-1)) {
|
||||||
|
ss << n;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if (i + 1 <= label->getLinesNumber()) {
|
||||||
|
ss << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineNumbersLabel->setText(ss.str());
|
||||||
|
}
|
||||||
|
lineNumbersLabel->setPos(padding);
|
||||||
|
lineNumbersLabel->setColor(glm::vec4(1, 1, 1, 0.25f));
|
||||||
|
}
|
||||||
|
|
||||||
if (autoresize && font) {
|
if (autoresize && font) {
|
||||||
auto size = getSize();
|
auto size = getSize();
|
||||||
int newy = glm::min(static_cast<int>(parent->getSize().y),
|
int newy = glm::min(static_cast<int>(parent->getSize().y),
|
||||||
@@ -293,7 +347,7 @@ bool TextBox::isAutoResize() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::onFocus(GUI* gui) {
|
void TextBox::onFocus(GUI* gui) {
|
||||||
Panel::onFocus(gui);
|
Container::onFocus(gui);
|
||||||
if (onEditStart){
|
if (onEditStart){
|
||||||
setCaret(input.size());
|
setCaret(input.size());
|
||||||
onEditStart();
|
onEditStart();
|
||||||
@@ -302,8 +356,11 @@ void TextBox::onFocus(GUI* gui) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::refresh() {
|
void TextBox::refresh() {
|
||||||
Panel::refresh();
|
Container::refresh();
|
||||||
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
||||||
|
label->setPos(glm::vec2(
|
||||||
|
padding.x + LINE_NUMBERS_PANE_WIDTH * showLineNumbers, padding.y
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Clamp index to range [0, input.length()]
|
/// @brief Clamp index to range [0, input.length()]
|
||||||
@@ -567,6 +624,14 @@ void TextBox::select(int start, int end) {
|
|||||||
setCaret(selectionEnd);
|
setCaret(selectionEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint TextBox::getLineAt(size_t position) const {
|
||||||
|
return label->getLineByTextIndex(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t TextBox::getLinePos(uint line) const {
|
||||||
|
return label->getTextLineOffset(line);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<UINode> TextBox::getAt(glm::vec2 pos, std::shared_ptr<UINode> self) {
|
std::shared_ptr<UINode> TextBox::getAt(glm::vec2 pos, std::shared_ptr<UINode> self) {
|
||||||
return UINode::getAt(pos, self);
|
return UINode::getAt(pos, self);
|
||||||
}
|
}
|
||||||
@@ -619,6 +684,15 @@ glm::vec4 TextBox::getFocusedColor() const {
|
|||||||
return focusedColor;
|
return focusedColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TextBox::setTextColor(glm::vec4 color) {
|
||||||
|
this->textColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec4 TextBox::getTextColor() const {
|
||||||
|
return textColor;
|
||||||
|
}
|
||||||
|
|
||||||
void TextBox::setErrorColor(glm::vec4 color) {
|
void TextBox::setErrorColor(glm::vec4 color) {
|
||||||
this->invalidColor = color;
|
this->invalidColor = color;
|
||||||
}
|
}
|
||||||
@@ -673,9 +747,11 @@ void TextBox::setCaret(size_t position) {
|
|||||||
uint line = label->getLineByTextIndex(caret);
|
uint line = label->getLineByTextIndex(caret);
|
||||||
int offset = label->getLineYOffset(line) + getContentOffset().y;
|
int offset = label->getLineYOffset(line) + getContentOffset().y;
|
||||||
uint lineHeight = font->getLineHeight()*label->getLineInterval();
|
uint lineHeight = font->getLineHeight()*label->getLineInterval();
|
||||||
scrollStep = lineHeight;
|
if (scrollStep == 0) {
|
||||||
|
scrollStep = lineHeight;
|
||||||
|
}
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
scrolled(1);
|
scrolled(-glm::floor(offset/static_cast<double>(scrollStep)+0.5f));
|
||||||
} else if (offset >= getSize().y) {
|
} else if (offset >= getSize().y) {
|
||||||
offset -= getSize().y;
|
offset -= getSize().y;
|
||||||
scrolled(-glm::ceil(offset/static_cast<double>(scrollStep)+0.5f));
|
scrolled(-glm::ceil(offset/static_cast<double>(scrollStep)+0.5f));
|
||||||
@@ -696,3 +772,20 @@ void TextBox::setCaret(ptrdiff_t position) {
|
|||||||
setCaret(static_cast<size_t>(position));
|
setCaret(static_cast<size_t>(position));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextBox::setPadding(glm::vec4 padding) {
|
||||||
|
this->padding = padding;
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec4 TextBox::getPadding() const {
|
||||||
|
return padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBox::setShowLineNumbers(bool flag) {
|
||||||
|
showLineNumbers = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextBox::isShowLineNumbers() const {
|
||||||
|
return showLineNumbers;
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,11 +8,14 @@ class Font;
|
|||||||
namespace gui {
|
namespace gui {
|
||||||
class Label;
|
class Label;
|
||||||
|
|
||||||
class TextBox : public Panel {
|
class TextBox : public Container {
|
||||||
protected:
|
protected:
|
||||||
glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f};
|
glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
glm::vec4 invalidColor {0.1f, 0.05f, 0.03f, 1.0f};
|
glm::vec4 invalidColor {0.1f, 0.05f, 0.03f, 1.0f};
|
||||||
|
glm::vec4 textColor {1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
glm::vec4 padding {2};
|
||||||
std::shared_ptr<Label> label;
|
std::shared_ptr<Label> label;
|
||||||
|
std::shared_ptr<Label> lineNumbersLabel;
|
||||||
/// @brief Current user input
|
/// @brief Current user input
|
||||||
std::wstring input;
|
std::wstring input;
|
||||||
/// @brief Text will be used if nothing entered
|
/// @brief Text will be used if nothing entered
|
||||||
@@ -52,6 +55,7 @@ namespace gui {
|
|||||||
bool multiline = false;
|
bool multiline = false;
|
||||||
bool editable = true;
|
bool editable = true;
|
||||||
bool autoresize = false;
|
bool autoresize = false;
|
||||||
|
bool showLineNumbers = false;
|
||||||
|
|
||||||
void stepLeft(bool shiftPressed, bool breakSelection);
|
void stepLeft(bool shiftPressed, bool breakSelection);
|
||||||
void stepRight(bool shiftPressed, bool breakSelection);
|
void stepRight(bool shiftPressed, bool breakSelection);
|
||||||
@@ -106,6 +110,9 @@ namespace gui {
|
|||||||
virtual void setFocusedColor(glm::vec4 color);
|
virtual void setFocusedColor(glm::vec4 color);
|
||||||
virtual glm::vec4 getFocusedColor() const;
|
virtual glm::vec4 getFocusedColor() const;
|
||||||
|
|
||||||
|
virtual void setTextColor(glm::vec4 color);
|
||||||
|
virtual glm::vec4 getTextColor() const;
|
||||||
|
|
||||||
/// @brief Set color of textbox marked by validator as invalid
|
/// @brief Set color of textbox marked by validator as invalid
|
||||||
virtual void setErrorColor(glm::vec4 color);
|
virtual void setErrorColor(glm::vec4 color);
|
||||||
|
|
||||||
@@ -152,6 +159,16 @@ namespace gui {
|
|||||||
/// @param end index of the last selected character + 1
|
/// @param end index of the last selected character + 1
|
||||||
virtual void select(int start, int end);
|
virtual void select(int start, int end);
|
||||||
|
|
||||||
|
/// @brief Get number of line at specific position in text
|
||||||
|
/// @param position target position
|
||||||
|
/// @return line number
|
||||||
|
virtual uint getLineAt(size_t position) const;
|
||||||
|
|
||||||
|
/// @brief Get specific line text position
|
||||||
|
/// @param line target line
|
||||||
|
/// @return line position in text
|
||||||
|
virtual size_t getLinePos(uint line) const;
|
||||||
|
|
||||||
/// @brief Check text with validator set with setTextValidator
|
/// @brief Check text with validator set with setTextValidator
|
||||||
/// @return true if text is valid
|
/// @return true if text is valid
|
||||||
virtual bool validate();
|
virtual bool validate();
|
||||||
@@ -177,12 +194,18 @@ namespace gui {
|
|||||||
/// @brief Check if text editing feature is enabled
|
/// @brief Check if text editing feature is enabled
|
||||||
virtual bool isEditable() const;
|
virtual bool isEditable() const;
|
||||||
|
|
||||||
|
virtual void setPadding(glm::vec4 padding);
|
||||||
|
glm::vec4 getPadding() const;
|
||||||
|
|
||||||
/// @brief Set runnable called on textbox focus
|
/// @brief Set runnable called on textbox focus
|
||||||
virtual void setOnEditStart(runnable oneditstart);
|
virtual void setOnEditStart(runnable oneditstart);
|
||||||
|
|
||||||
virtual void setAutoResize(bool flag);
|
virtual void setAutoResize(bool flag);
|
||||||
virtual bool isAutoResize() const;
|
virtual bool isAutoResize() const;
|
||||||
|
|
||||||
|
virtual void setShowLineNumbers(bool flag);
|
||||||
|
virtual bool isShowLineNumbers() const;
|
||||||
|
|
||||||
virtual void onFocus(GUI*) override;
|
virtual void onFocus(GUI*) override;
|
||||||
virtual void refresh() override;
|
virtual void refresh() override;
|
||||||
virtual void doubleClick(GUI*, int x, int y) override;
|
virtual void doubleClick(GUI*, int x, int y) override;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace gui {
|
|||||||
/// @brief element color when clicked
|
/// @brief element color when clicked
|
||||||
glm::vec4 pressedColor {1.0f};
|
glm::vec4 pressedColor {1.0f};
|
||||||
/// @brief element margin (only supported for Panel sub-nodes)
|
/// @brief element margin (only supported for Panel sub-nodes)
|
||||||
glm::vec4 margin {1.0f};
|
glm::vec4 margin {0.0f};
|
||||||
/// @brief is element visible
|
/// @brief is element visible
|
||||||
bool visible = true;
|
bool visible = true;
|
||||||
/// @brief is mouse over the element
|
/// @brief is mouse over the element
|
||||||
|
|||||||
@@ -172,6 +172,9 @@ static void _readContainer(UiXmlReader& reader, const xml::xmlelement& element,
|
|||||||
if (element->has("scrollable")) {
|
if (element->has("scrollable")) {
|
||||||
container.setScrollable(element->attr("scrollable").asBool());
|
container.setScrollable(element->attr("scrollable").asBool());
|
||||||
}
|
}
|
||||||
|
if (element->has("scroll-step")) {
|
||||||
|
container.setScrollStep(element->attr("scroll-step").asInt());
|
||||||
|
}
|
||||||
for (auto& sub : element->getElements()) {
|
for (auto& sub : element->getElements()) {
|
||||||
if (sub->isText())
|
if (sub->isText())
|
||||||
continue;
|
continue;
|
||||||
@@ -342,7 +345,16 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlel
|
|||||||
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f));
|
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f));
|
||||||
textbox->setHint(hint);
|
textbox->setHint(hint);
|
||||||
|
|
||||||
_readPanel(reader, element, *textbox);
|
_readContainer(reader, element, *textbox);
|
||||||
|
if (element->has("padding")) {
|
||||||
|
glm::vec4 padding = element->attr("padding").asVec4();
|
||||||
|
textbox->setPadding(padding);
|
||||||
|
glm::vec2 size = textbox->getSize();
|
||||||
|
textbox->setSize(glm::vec2(
|
||||||
|
size.x + padding.x + padding.z,
|
||||||
|
size.y + padding.y + padding.w
|
||||||
|
));
|
||||||
|
}
|
||||||
textbox->setText(text);
|
textbox->setText(text);
|
||||||
|
|
||||||
if (element->has("multiline")) {
|
if (element->has("multiline")) {
|
||||||
@@ -357,6 +369,9 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlel
|
|||||||
if (element->has("autoresize")) {
|
if (element->has("autoresize")) {
|
||||||
textbox->setAutoResize(element->attr("autoresize").asBool());
|
textbox->setAutoResize(element->attr("autoresize").asBool());
|
||||||
}
|
}
|
||||||
|
if (element->has("line-numbers")) {
|
||||||
|
textbox->setShowLineNumbers(element->attr("line-numbers").asBool());
|
||||||
|
}
|
||||||
if (element->has("consumer")) {
|
if (element->has("consumer")) {
|
||||||
textbox->setTextConsumer(scripting::create_wstring_consumer(
|
textbox->setTextConsumer(scripting::create_wstring_consumer(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
@@ -384,6 +399,9 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlel
|
|||||||
if (element->has("error-color")) {
|
if (element->has("error-color")) {
|
||||||
textbox->setErrorColor(element->attr("error-color").asColor());
|
textbox->setErrorColor(element->attr("error-color").asColor());
|
||||||
}
|
}
|
||||||
|
if (element->has("text-color")) {
|
||||||
|
textbox->setTextColor(element->attr("text-color").asColor());
|
||||||
|
}
|
||||||
if (element->has("validator")) {
|
if (element->has("validator")) {
|
||||||
textbox->setTextValidator(scripting::create_wstring_validator(
|
textbox->setTextValidator(scripting::create_wstring_validator(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
extern const luaL_Reg audiolib[];
|
extern const luaL_Reg audiolib[];
|
||||||
|
extern const luaL_Reg base64lib[];
|
||||||
extern const luaL_Reg bjsonlib[];
|
extern const luaL_Reg bjsonlib[];
|
||||||
extern const luaL_Reg blocklib[];
|
extern const luaL_Reg blocklib[];
|
||||||
extern const luaL_Reg cameralib[];
|
extern const luaL_Reg cameralib[];
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#include "api_lua.hpp"
|
||||||
|
|
||||||
|
#include "util/stringutil.hpp"
|
||||||
|
|
||||||
|
static int l_encode(lua::State* L) {
|
||||||
|
if (lua::istable(L, 1)) {
|
||||||
|
lua::pushvalue(L, 1);
|
||||||
|
size_t size = lua::objlen(L, 1);
|
||||||
|
util::Buffer<char> buffer(size);
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
lua::rawgeti(L, i + 1);
|
||||||
|
buffer[i] = lua::tointeger(L, -1);
|
||||||
|
lua::pop(L);
|
||||||
|
}
|
||||||
|
lua::pop(L);
|
||||||
|
return lua::pushstring(L, util::base64_encode(
|
||||||
|
reinterpret_cast<const ubyte*>(buffer.data()), buffer.size()
|
||||||
|
));
|
||||||
|
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 1)) {
|
||||||
|
return lua::pushstring(
|
||||||
|
L,
|
||||||
|
util::base64_encode(
|
||||||
|
bytes->data().data(),
|
||||||
|
bytes->data().size()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw std::runtime_error("array or ByteArray expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_decode(lua::State* L) {
|
||||||
|
auto buffer = util::base64_decode(lua::require_lstring(L, 1));
|
||||||
|
if (lua::toboolean(L, 2)) {
|
||||||
|
lua::createtable(L, buffer.size(), 0);
|
||||||
|
for (size_t i = 0; i < buffer.size(); i++) {
|
||||||
|
lua::pushinteger(L, buffer[i] & 0xFF);
|
||||||
|
lua::rawseti(L, i+1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lua::newuserdata<lua::LuaBytearray>(L, buffer.size());
|
||||||
|
auto bytearray = lua::touserdata<lua::LuaBytearray>(L, -1);
|
||||||
|
bytearray->data().reserve(buffer.size());
|
||||||
|
std::memcpy(bytearray->data().data(), buffer.data(), buffer.size());
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const luaL_Reg base64lib[] = {
|
||||||
|
{"encode", lua::wrap<l_encode>},
|
||||||
|
{"decode", lua::wrap<l_decode>},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
@@ -134,6 +134,24 @@ static int l_move_into(lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_get_line_at(lua::State* L) {
|
||||||
|
auto node = getDocumentNode(L, 1);
|
||||||
|
auto position = lua::tointeger(L, 2);
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node.node.get())) {
|
||||||
|
return lua::pushinteger(L, box->getLineAt(position));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_get_line_pos(lua::State* L) {
|
||||||
|
auto node = getDocumentNode(L, 1);
|
||||||
|
auto line = lua::tointeger(L, 2);
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node.node.get())) {
|
||||||
|
return lua::pushinteger(L, box->getLinePos(line));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int p_get_inventory(UINode* node, lua::State* L) {
|
static int p_get_inventory(UINode* node, lua::State* L) {
|
||||||
if (auto inventory = dynamic_cast<InventoryView*>(node)) {
|
if (auto inventory = dynamic_cast<InventoryView*>(node)) {
|
||||||
auto inv = inventory->getInventory();
|
auto inv = inventory->getInventory();
|
||||||
@@ -221,6 +239,13 @@ static int p_get_track_color(UINode* node, lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int p_get_text_color(UINode* node, lua::State* L) {
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
|
return lua::pushcolor(L, box->getTextColor());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int p_is_valid(UINode* node, lua::State* L) {
|
static int p_is_valid(UINode* node, lua::State* L) {
|
||||||
if (auto box = dynamic_cast<TextBox*>(node)) {
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
return lua::pushboolean(L, box->validate());
|
return lua::pushboolean(L, box->validate());
|
||||||
@@ -267,6 +292,13 @@ static int p_get_editable(UINode* node, lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int p_get_line_numbers(UINode* node, lua::State* L) {
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
|
return lua::pushboolean(L, box->isShowLineNumbers());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int p_get_src(UINode* node, lua::State* L) {
|
static int p_get_src(UINode* node, lua::State* L) {
|
||||||
if (auto image = dynamic_cast<Image*>(node)) {
|
if (auto image = dynamic_cast<Image*>(node)) {
|
||||||
return lua::pushstring(L, image->getTexture());
|
return lua::pushstring(L, image->getTexture());
|
||||||
@@ -342,6 +374,12 @@ static int p_move_into(UINode*, lua::State* L) {
|
|||||||
static int p_get_focused(UINode* node, lua::State* L) {
|
static int p_get_focused(UINode* node, lua::State* L) {
|
||||||
return lua::pushboolean(L, node->isFocused());
|
return lua::pushboolean(L, node->isFocused());
|
||||||
}
|
}
|
||||||
|
static int p_get_line_at(UINode*, lua::State* L) {
|
||||||
|
return lua::pushcfunction(L, l_get_line_at);
|
||||||
|
}
|
||||||
|
static int p_get_line_pos(UINode*, lua::State* L) {
|
||||||
|
return lua::pushcfunction(L, l_get_line_pos);
|
||||||
|
}
|
||||||
|
|
||||||
static int l_gui_getattr(lua::State* L) {
|
static int l_gui_getattr(lua::State* L) {
|
||||||
auto docname = lua::require_string(L, 1);
|
auto docname = lua::require_string(L, 1);
|
||||||
@@ -376,6 +414,9 @@ static int l_gui_getattr(lua::State* L) {
|
|||||||
{"caret", p_get_caret},
|
{"caret", p_get_caret},
|
||||||
{"text", p_get_text},
|
{"text", p_get_text},
|
||||||
{"editable", p_get_editable},
|
{"editable", p_get_editable},
|
||||||
|
{"lineNumbers", p_get_line_numbers},
|
||||||
|
{"lineAt", p_get_line_at},
|
||||||
|
{"linePos", p_get_line_pos},
|
||||||
{"src", p_get_src},
|
{"src", p_get_src},
|
||||||
{"value", p_get_value},
|
{"value", p_get_value},
|
||||||
{"min", p_get_min},
|
{"min", p_get_min},
|
||||||
@@ -383,6 +424,7 @@ static int l_gui_getattr(lua::State* L) {
|
|||||||
{"step", p_get_step},
|
{"step", p_get_step},
|
||||||
{"trackWidth", p_get_track_width},
|
{"trackWidth", p_get_track_width},
|
||||||
{"trackColor", p_get_track_color},
|
{"trackColor", p_get_track_color},
|
||||||
|
{"textColor", p_get_text_color},
|
||||||
{"checked", p_is_checked},
|
{"checked", p_is_checked},
|
||||||
{"page", p_get_page},
|
{"page", p_get_page},
|
||||||
{"back", p_get_back},
|
{"back", p_get_back},
|
||||||
@@ -462,6 +504,11 @@ static void p_set_editable(UINode* node, lua::State* L, int idx) {
|
|||||||
box->setEditable(lua::toboolean(L, idx));
|
box->setEditable(lua::toboolean(L, idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void p_set_line_numbers(UINode* node, lua::State* L, int idx) {
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
|
box->setShowLineNumbers(lua::toboolean(L, idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
static void p_set_src(UINode* node, lua::State* L, int idx) {
|
static void p_set_src(UINode* node, lua::State* L, int idx) {
|
||||||
if (auto image = dynamic_cast<Image*>(node)) {
|
if (auto image = dynamic_cast<Image*>(node)) {
|
||||||
image->setTexture(lua::require_string(L, idx));
|
image->setTexture(lua::require_string(L, idx));
|
||||||
@@ -497,6 +544,11 @@ static void p_set_track_color(UINode* node, lua::State* L, int idx) {
|
|||||||
bar->setTrackColor(lua::tocolor(L, idx));
|
bar->setTrackColor(lua::tocolor(L, idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void p_set_text_color(UINode* node, lua::State* L, int idx) {
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
|
box->setTextColor(lua::tocolor(L, idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
static void p_set_checked(UINode* node, lua::State* L, int idx) {
|
static void p_set_checked(UINode* node, lua::State* L, int idx) {
|
||||||
if (auto box = dynamic_cast<CheckBox*>(node)) {
|
if (auto box = dynamic_cast<CheckBox*>(node)) {
|
||||||
box->setChecked(lua::toboolean(L, idx));
|
box->setChecked(lua::toboolean(L, idx));
|
||||||
@@ -556,6 +608,7 @@ static int l_gui_setattr(lua::State* L) {
|
|||||||
{"hint", p_set_hint},
|
{"hint", p_set_hint},
|
||||||
{"text", p_set_text},
|
{"text", p_set_text},
|
||||||
{"editable", p_set_editable},
|
{"editable", p_set_editable},
|
||||||
|
{"lineNumbers", p_set_line_numbers},
|
||||||
{"src", p_set_src},
|
{"src", p_set_src},
|
||||||
{"caret", p_set_caret},
|
{"caret", p_set_caret},
|
||||||
{"value", p_set_value},
|
{"value", p_set_value},
|
||||||
@@ -564,6 +617,7 @@ static int l_gui_setattr(lua::State* L) {
|
|||||||
{"step", p_set_step},
|
{"step", p_set_step},
|
||||||
{"trackWidth", p_set_track_width},
|
{"trackWidth", p_set_track_width},
|
||||||
{"trackColor", p_set_track_color},
|
{"trackColor", p_set_track_color},
|
||||||
|
{"textColor", p_set_text_color},
|
||||||
{"checked", p_set_checked},
|
{"checked", p_set_checked},
|
||||||
{"page", p_set_page},
|
{"page", p_set_page},
|
||||||
{"inventory", p_set_inventory},
|
{"inventory", p_set_inventory},
|
||||||
|
|||||||
@@ -94,6 +94,11 @@ static int l_encode(lua::State* L) {
|
|||||||
return lua::pushlstring(L, bytes, count);
|
return lua::pushlstring(L, bytes, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_escape(lua::State* L) {
|
||||||
|
auto string = lua::require_lstring(L, 1);
|
||||||
|
return lua::pushstring(L, util::escape(string));
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg utf8lib[] = {
|
const luaL_Reg utf8lib[] = {
|
||||||
{"tobytes", lua::wrap<l_tobytes>},
|
{"tobytes", lua::wrap<l_tobytes>},
|
||||||
{"tostring", lua::wrap<l_tostring>},
|
{"tostring", lua::wrap<l_tostring>},
|
||||||
@@ -103,5 +108,6 @@ const luaL_Reg utf8lib[] = {
|
|||||||
{"upper", lua::wrap<l_upper>},
|
{"upper", lua::wrap<l_upper>},
|
||||||
{"lower", lua::wrap<l_lower>},
|
{"lower", lua::wrap<l_lower>},
|
||||||
{"encode", lua::wrap<l_encode>},
|
{"encode", lua::wrap<l_encode>},
|
||||||
|
{"escape", lua::wrap<l_escape>},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ static void remove_lib_funcs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void create_libs(State* L, StateType stateType) {
|
static void create_libs(State* L, StateType stateType) {
|
||||||
|
openlib(L, "base64", base64lib);
|
||||||
openlib(L, "bjson", bjsonlib);
|
openlib(L, "bjson", bjsonlib);
|
||||||
openlib(L, "block", blocklib);
|
openlib(L, "block", blocklib);
|
||||||
openlib(L, "core", corelib);
|
openlib(L, "core", corelib);
|
||||||
@@ -143,7 +144,8 @@ State* lua::create_state(const EnginePaths& paths, StateType stateType) {
|
|||||||
init_state(L, stateType);
|
init_state(L, stateType);
|
||||||
|
|
||||||
auto resDir = paths.getResourcesFolder();
|
auto resDir = paths.getResourcesFolder();
|
||||||
auto src = files::read_string(resDir / fs::u8path("scripts/stdmin.lua"));
|
auto file = resDir / fs::u8path("scripts/stdmin.lua");
|
||||||
lua::pop(L, lua::execute(L, 0, src, "<stdmin>"));
|
auto src = files::read_string(file);
|
||||||
|
lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua"));
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,10 +145,14 @@ static int l_error_handler(lua_State* L) {
|
|||||||
if (!isstring(L, 1)) { // 'message' not a string?
|
if (!isstring(L, 1)) { // 'message' not a string?
|
||||||
return 1; // keep it intact
|
return 1; // keep it intact
|
||||||
}
|
}
|
||||||
if (get_from(L, "debug", "traceback")) {
|
if (getglobal(L, "__vc__error")) {
|
||||||
lua_pushvalue(L, 1); // pass error message
|
lua_pushvalue(L, 1); // pass error message
|
||||||
lua_pushinteger(L, 2); // skip this function and traceback
|
lua_pushinteger(L, 2); // skip this function and traceback
|
||||||
lua_call(L, 2, 1); // call debug.traceback
|
lua_call(L, 2, 1); // call debug.traceback
|
||||||
|
} if (get_from(L, "debug", "traceback")) {
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_pushinteger(L, 2);
|
||||||
|
lua_call(L, 2, 1);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -172,8 +176,13 @@ int lua::call_nothrow(State* L, int argc, int nresults) {
|
|||||||
pushcfunction(L, l_error_handler);
|
pushcfunction(L, l_error_handler);
|
||||||
insert(L, handler_pos);
|
insert(L, handler_pos);
|
||||||
if (lua_pcall(L, argc, LUA_MULTRET, handler_pos)) {
|
if (lua_pcall(L, argc, LUA_MULTRET, handler_pos)) {
|
||||||
log_error(tostring(L, -1));
|
auto errorstr = tostring(L, -1);
|
||||||
pop(L);
|
if (errorstr) {
|
||||||
|
log_error(errorstr);
|
||||||
|
pop(L);
|
||||||
|
} else {
|
||||||
|
log_error("");
|
||||||
|
}
|
||||||
remove(L, handler_pos);
|
remove(L, handler_pos);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,6 +240,11 @@ namespace lua {
|
|||||||
inline const char* tostring(lua::State* L, int idx) {
|
inline const char* tostring(lua::State* L, int idx) {
|
||||||
return lua_tostring(L, idx);
|
return lua_tostring(L, idx);
|
||||||
}
|
}
|
||||||
|
inline std::string_view tolstring(lua::State* L, int idx) {
|
||||||
|
size_t len = 0;
|
||||||
|
auto string = lua_tolstring(L, idx, &len);
|
||||||
|
return std::string_view(string, len);
|
||||||
|
}
|
||||||
inline const void* topointer(lua::State* L, int idx) {
|
inline const void* topointer(lua::State* L, int idx) {
|
||||||
return lua_topointer(L, idx);
|
return lua_topointer(L, idx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ void scripting::load_script(const fs::path& name, bool throwable) {
|
|||||||
fs::path file = paths->getResourcesFolder() / fs::path("scripts") / name;
|
fs::path file = paths->getResourcesFolder() / fs::path("scripts") / name;
|
||||||
std::string src = files::read_string(file);
|
std::string src = files::read_string(file);
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
lua::loadbuffer(L, 0, src, file.u8string());
|
lua::loadbuffer(L, 0, src, "core:scripts/"+name.u8string());
|
||||||
if (throwable) {
|
if (throwable) {
|
||||||
lua::call(L, 0, 0);
|
lua::call(L, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -53,11 +53,14 @@ void scripting::load_script(const fs::path& name, bool throwable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int scripting::load_script(
|
int scripting::load_script(
|
||||||
int env, const std::string& type, const fs::path& file
|
int env,
|
||||||
|
const std::string& type,
|
||||||
|
const fs::path& file,
|
||||||
|
const std::string& fileName
|
||||||
) {
|
) {
|
||||||
std::string src = files::read_string(file);
|
std::string src = files::read_string(file);
|
||||||
logger.info() << "script (" << type << ") " << file.u8string();
|
logger.info() << "script (" << type << ") " << file.u8string();
|
||||||
return lua::execute(lua::get_main_state(), env, src, file.u8string());
|
return lua::execute(lua::get_main_state(), env, src, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scripting::initialize(Engine* engine) {
|
void scripting::initialize(Engine* engine) {
|
||||||
@@ -657,10 +660,11 @@ void scripting::load_block_script(
|
|||||||
const scriptenv& senv,
|
const scriptenv& senv,
|
||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
|
const std::string& fileName,
|
||||||
block_funcs_set& funcsset
|
block_funcs_set& funcsset
|
||||||
) {
|
) {
|
||||||
int env = *senv;
|
int env = *senv;
|
||||||
lua::pop(lua::get_main_state(), load_script(env, "block", file));
|
lua::pop(lua::get_main_state(), load_script(env, "block", file, fileName));
|
||||||
funcsset.init = register_event(env, "init", prefix + ".init");
|
funcsset.init = register_event(env, "init", prefix + ".init");
|
||||||
funcsset.update = register_event(env, "on_update", prefix + ".update");
|
funcsset.update = register_event(env, "on_update", prefix + ".update");
|
||||||
funcsset.randupdate =
|
funcsset.randupdate =
|
||||||
@@ -677,10 +681,11 @@ void scripting::load_item_script(
|
|||||||
const scriptenv& senv,
|
const scriptenv& senv,
|
||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
|
const std::string& fileName,
|
||||||
item_funcs_set& funcsset
|
item_funcs_set& funcsset
|
||||||
) {
|
) {
|
||||||
int env = *senv;
|
int env = *senv;
|
||||||
lua::pop(lua::get_main_state(), load_script(env, "item", file));
|
lua::pop(lua::get_main_state(), load_script(env, "item", file, fileName));
|
||||||
funcsset.init = register_event(env, "init", prefix + ".init");
|
funcsset.init = register_event(env, "init", prefix + ".init");
|
||||||
funcsset.on_use = register_event(env, "on_use", prefix + ".use");
|
funcsset.on_use = register_event(env, "on_use", prefix + ".use");
|
||||||
funcsset.on_use_on_block =
|
funcsset.on_use_on_block =
|
||||||
@@ -690,12 +695,12 @@ void scripting::load_item_script(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void scripting::load_entity_component(
|
void scripting::load_entity_component(
|
||||||
const std::string& name, const fs::path& file
|
const std::string& name, const fs::path& file, const std::string& fileName
|
||||||
) {
|
) {
|
||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
std::string src = files::read_string(file);
|
std::string src = files::read_string(file);
|
||||||
logger.info() << "script (component) " << file.u8string();
|
logger.info() << "script (component) " << file.u8string();
|
||||||
lua::loadbuffer(L, 0, src, "C!" + name);
|
lua::loadbuffer(L, 0, src, fileName);
|
||||||
lua::store_in(L, lua::CHUNKS_TABLE, name);
|
lua::store_in(L, lua::CHUNKS_TABLE, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,10 +708,11 @@ void scripting::load_world_script(
|
|||||||
const scriptenv& senv,
|
const scriptenv& senv,
|
||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
|
const std::string& fileName,
|
||||||
world_funcs_set& funcsset
|
world_funcs_set& funcsset
|
||||||
) {
|
) {
|
||||||
int env = *senv;
|
int env = *senv;
|
||||||
lua::pop(lua::get_main_state(), load_script(env, "world", file));
|
lua::pop(lua::get_main_state(), load_script(env, "world", file, fileName));
|
||||||
register_event(env, "init", prefix + ".init");
|
register_event(env, "init", prefix + ".init");
|
||||||
register_event(env, "on_world_open", prefix + ":.worldopen");
|
register_event(env, "on_world_open", prefix + ":.worldopen");
|
||||||
register_event(env, "on_world_tick", prefix + ":.worldtick");
|
register_event(env, "on_world_tick", prefix + ":.worldtick");
|
||||||
@@ -724,11 +730,12 @@ void scripting::load_layout_script(
|
|||||||
const scriptenv& senv,
|
const scriptenv& senv,
|
||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
|
const std::string& fileName,
|
||||||
uidocscript& script
|
uidocscript& script
|
||||||
) {
|
) {
|
||||||
int env = *senv;
|
int env = *senv;
|
||||||
|
|
||||||
lua::pop(lua::get_main_state(), load_script(env, "layout", file));
|
lua::pop(lua::get_main_state(), load_script(env, "layout", file, fileName));
|
||||||
script.onopen = register_event(env, "on_open", prefix + ".open");
|
script.onopen = register_event(env, "on_open", prefix + ".open");
|
||||||
script.onprogress =
|
script.onprogress =
|
||||||
register_event(env, "on_progress", prefix + ".progress");
|
register_event(env, "on_progress", prefix + ".progress");
|
||||||
|
|||||||
@@ -125,11 +125,13 @@ namespace scripting {
|
|||||||
/// @param env environment
|
/// @param env environment
|
||||||
/// @param prefix pack id
|
/// @param prefix pack id
|
||||||
/// @param file item script file
|
/// @param file item script file
|
||||||
|
/// @param fileName script file path using the engine format
|
||||||
/// @param funcsset block callbacks set
|
/// @param funcsset block callbacks set
|
||||||
void load_block_script(
|
void load_block_script(
|
||||||
const scriptenv& env,
|
const scriptenv& env,
|
||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
|
const std::string& fileName,
|
||||||
block_funcs_set& funcsset
|
block_funcs_set& funcsset
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -137,15 +139,25 @@ namespace scripting {
|
|||||||
/// @param env environment
|
/// @param env environment
|
||||||
/// @param prefix pack id
|
/// @param prefix pack id
|
||||||
/// @param file item script file
|
/// @param file item script file
|
||||||
|
/// @param fileName script file path using the engine format
|
||||||
/// @param funcsset item callbacks set
|
/// @param funcsset item callbacks set
|
||||||
void load_item_script(
|
void load_item_script(
|
||||||
const scriptenv& env,
|
const scriptenv& env,
|
||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
|
const std::string& fileName,
|
||||||
item_funcs_set& funcsset
|
item_funcs_set& funcsset
|
||||||
);
|
);
|
||||||
|
|
||||||
void load_entity_component(const std::string& name, const fs::path& file);
|
/// @brief Load component script
|
||||||
|
/// @param name component full name (packid:name)
|
||||||
|
/// @param file component script file path
|
||||||
|
/// @param fileName script file path using the engine format
|
||||||
|
void load_entity_component(
|
||||||
|
const std::string& name,
|
||||||
|
const fs::path& file,
|
||||||
|
const std::string& fileName
|
||||||
|
);
|
||||||
|
|
||||||
std::unique_ptr<GeneratorScript> load_generator(
|
std::unique_ptr<GeneratorScript> load_generator(
|
||||||
const GeneratorDef& def,
|
const GeneratorDef& def,
|
||||||
@@ -157,10 +169,12 @@ namespace scripting {
|
|||||||
/// @param env environment
|
/// @param env environment
|
||||||
/// @param packid content-pack id
|
/// @param packid content-pack id
|
||||||
/// @param file script file path
|
/// @param file script file path
|
||||||
|
/// @param fileName script file path using the engine format
|
||||||
void load_world_script(
|
void load_world_script(
|
||||||
const scriptenv& env,
|
const scriptenv& env,
|
||||||
const std::string& packid,
|
const std::string& packid,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
|
const std::string& fileName,
|
||||||
world_funcs_set& funcsset
|
world_funcs_set& funcsset
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -168,11 +182,13 @@ namespace scripting {
|
|||||||
/// @param env environment
|
/// @param env environment
|
||||||
/// @param prefix pack id
|
/// @param prefix pack id
|
||||||
/// @param file item script file
|
/// @param file item script file
|
||||||
|
/// @param fileName script file path using the engine format
|
||||||
/// @param script document script info
|
/// @param script document script info
|
||||||
void load_layout_script(
|
void load_layout_script(
|
||||||
const scriptenv& env,
|
const scriptenv& env,
|
||||||
const std::string& prefix,
|
const std::string& prefix,
|
||||||
const fs::path& file,
|
const fs::path& file,
|
||||||
|
const std::string& fileName,
|
||||||
uidocscript& script
|
uidocscript& script
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
namespace scripting {
|
namespace scripting {
|
||||||
void load_script(const std::filesystem::path& name, bool throwable);
|
void load_script(const std::filesystem::path& name, bool throwable);
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]] int load_script(
|
||||||
int load_script(int env, const std::string& type, const std::filesystem::path& file);
|
int env,
|
||||||
|
const std::string& type,
|
||||||
|
const std::filesystem::path& file,
|
||||||
|
const std::string& fileName
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,13 +76,16 @@ void scripting::on_frontend_close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void scripting::load_hud_script(
|
void scripting::load_hud_script(
|
||||||
const scriptenv& senv, const std::string& packid, const fs::path& file
|
const scriptenv& senv,
|
||||||
|
const std::string& packid,
|
||||||
|
const fs::path& file,
|
||||||
|
const std::string& fileName
|
||||||
) {
|
) {
|
||||||
int env = *senv;
|
int env = *senv;
|
||||||
std::string src = files::read_string(file);
|
std::string src = files::read_string(file);
|
||||||
logger.info() << "loading script " << file.u8string();
|
logger.info() << "loading script " << file.u8string();
|
||||||
|
|
||||||
lua::execute(lua::get_main_state(), env, src, file.u8string());
|
lua::execute(lua::get_main_state(), env, src, fileName);
|
||||||
|
|
||||||
register_event(env, "init", packid + ":.init");
|
register_event(env, "init", packid + ":.init");
|
||||||
register_event(env, "on_hud_open", packid + ":.hudopen");
|
register_event(env, "on_hud_open", packid + ":.hudopen");
|
||||||
|
|||||||
@@ -22,7 +22,11 @@ namespace scripting {
|
|||||||
/// @param env environment id
|
/// @param env environment id
|
||||||
/// @param packid content-pack id
|
/// @param packid content-pack id
|
||||||
/// @param file script file path
|
/// @param file script file path
|
||||||
|
/// @param fileName script file path using the engine format
|
||||||
void load_hud_script(
|
void load_hud_script(
|
||||||
const scriptenv &env, const std::string &packid, const fs::path &file
|
const scriptenv& env,
|
||||||
|
const std::string& packid,
|
||||||
|
const fs::path& file,
|
||||||
|
const std::string& fileName
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
// TODO: finish
|
std::string util::escape(std::string_view s) {
|
||||||
std::string util::escape(const std::string& s) {
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << '"';
|
ss << '"';
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
@@ -318,7 +317,7 @@ std::string util::base64_encode(const ubyte* data, size_t size) {
|
|||||||
ending[i - fullsegments] = data[i];
|
ending[i - fullsegments] = data[i];
|
||||||
}
|
}
|
||||||
size_t trailing = size - fullsegments;
|
size_t trailing = size - fullsegments;
|
||||||
{
|
if (trailing) {
|
||||||
char output[] = "====";
|
char output[] = "====";
|
||||||
output[0] = B64ABC[(ending[0] & 0b11111100) >> 2];
|
output[0] = B64ABC[(ending[0] & 0b11111100) >> 2];
|
||||||
output[1] =
|
output[1] =
|
||||||
@@ -364,8 +363,8 @@ util::Buffer<ubyte> util::base64_decode(const char* str, size_t size) {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Buffer<ubyte> util::base64_decode(const std::string& str) {
|
util::Buffer<ubyte> util::base64_decode(std::string_view str) {
|
||||||
return base64_decode(str.c_str(), str.size());
|
return base64_decode(str.data(), str.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int util::replaceAll(
|
int util::replaceAll(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
/// @brief Function used for string serialization in text formats
|
/// @brief Function used for string serialization in text formats
|
||||||
std::string escape(const std::string& s);
|
std::string escape(std::string_view s);
|
||||||
|
|
||||||
/// @brief Function used for error messages
|
/// @brief Function used for error messages
|
||||||
std::string quote(const std::string& s);
|
std::string quote(const std::string& s);
|
||||||
@@ -63,7 +63,7 @@ namespace util {
|
|||||||
|
|
||||||
std::string base64_encode(const ubyte* data, size_t size);
|
std::string base64_encode(const ubyte* data, size_t size);
|
||||||
util::Buffer<ubyte> base64_decode(const char* str, size_t size);
|
util::Buffer<ubyte> base64_decode(const char* str, size_t size);
|
||||||
util::Buffer<ubyte> base64_decode(const std::string& str);
|
util::Buffer<ubyte> base64_decode(std::string_view str);
|
||||||
|
|
||||||
std::string tohex(uint64_t value);
|
std::string tohex(uint64_t value);
|
||||||
|
|
||||||
|
|||||||
@@ -258,14 +258,14 @@ void Window::pushScissor(glm::vec4 area) {
|
|||||||
}
|
}
|
||||||
scissorStack.push(scissorArea);
|
scissorStack.push(scissorArea);
|
||||||
|
|
||||||
area.z += area.x;
|
area.z += glm::ceil(area.x);
|
||||||
area.w += area.y;
|
area.w += glm::ceil(area.y);
|
||||||
|
|
||||||
area.x = fmax(area.x, scissorArea.x);
|
area.x = glm::max(area.x, scissorArea.x);
|
||||||
area.y = fmax(area.y, scissorArea.y);
|
area.y = glm::max(area.y, scissorArea.y);
|
||||||
|
|
||||||
area.z = fmin(area.z, scissorArea.z);
|
area.z = glm::min(area.z, scissorArea.z);
|
||||||
area.w = fmin(area.w, scissorArea.w);
|
area.w = glm::min(area.w, scissorArea.w);
|
||||||
|
|
||||||
if (area.z < 0.0f || area.w < 0.0f) {
|
if (area.z < 0.0f || area.w < 0.0f) {
|
||||||
glScissor(0, 0, 0, 0);
|
glScissor(0, 0, 0, 0);
|
||||||
@@ -273,8 +273,8 @@ void Window::pushScissor(glm::vec4 area) {
|
|||||||
glScissor(
|
glScissor(
|
||||||
area.x,
|
area.x,
|
||||||
Window::height - area.w,
|
Window::height - area.w,
|
||||||
std::max(0, int(area.z - area.x)),
|
std::max(0, static_cast<int>(glm::ceil(area.z - area.x))),
|
||||||
std::max(0, int(area.w - area.y))
|
std::max(0, static_cast<int>(glm::ceil(area.w - area.y)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
scissorArea = area;
|
scissorArea = area;
|
||||||
|
|||||||
@@ -15,3 +15,19 @@ TEST(stringutil, utf8) {
|
|||||||
std::string str2 = util::u32str2str_utf8(u32str);
|
std::string str2 = util::u32str2str_utf8(u32str);
|
||||||
EXPECT_EQ(str, str2);
|
EXPECT_EQ(str, str2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(stringutil, base64) {
|
||||||
|
srand(2019);
|
||||||
|
for (size_t size = 0; size < 30; size++) {
|
||||||
|
auto bytes = std::make_unique<ubyte[]>(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
bytes[i] = rand();
|
||||||
|
}
|
||||||
|
auto base64 = util::base64_encode(bytes.get(), size);
|
||||||
|
auto decoded = util::base64_decode(base64);
|
||||||
|
ASSERT_EQ(size, decoded.size());
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
ASSERT_EQ(bytes[i], decoded[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user