Merge pull request #671 from MihailRis/debugging-client
Debugging client
This commit is contained in:
commit
6def370c2b
@ -159,6 +159,11 @@ app.get_setting_info(name: str) -> {
|
|||||||
|
|
||||||
Returns a table with information about a setting. Throws an exception if the setting does not exist.
|
Returns a table with information about a setting. Throws an exception if the setting does not exist.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
app.focus()
|
||||||
|
```
|
||||||
|
|
||||||
|
Brings the window to front and sets input focus.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
app.create_memory_device(
|
app.create_memory_device(
|
||||||
|
|||||||
@ -13,7 +13,16 @@ input.mousecode(mousename: str) --> int
|
|||||||
Returns mouse button code or -1 if unknown
|
Returns mouse button code or -1 if unknown
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
input.add_callback(bindname: str, callback: function)
|
input.add_callback(
|
||||||
|
-- Binding name
|
||||||
|
bindname: str,
|
||||||
|
-- Handler
|
||||||
|
callback: function
|
||||||
|
-- UI element that owns the handler (responsible for the handler's lifetime)
|
||||||
|
[optional] owner: Element,
|
||||||
|
-- Ignore input capture by UI elements
|
||||||
|
[optional] istoplevel: bool
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Add binding activation callback. Example:
|
Add binding activation callback. Example:
|
||||||
|
|||||||
@ -82,6 +82,16 @@ socket:recv(
|
|||||||
-- Returns nil on error (socket is closed or does not exist).
|
-- Returns nil on error (socket is closed or does not exist).
|
||||||
-- If there is no data yet, returns an empty byte array.
|
-- If there is no data yet, returns an empty byte array.
|
||||||
|
|
||||||
|
-- Asynchronous version for use in coroutines.
|
||||||
|
-- Waits for the entire specified number of bytes to be received.
|
||||||
|
-- If socket closes, function works like socket:recv
|
||||||
|
socket:recv_async(
|
||||||
|
-- Size of the byte array to read
|
||||||
|
length: int,
|
||||||
|
-- Use table instead of Bytearray
|
||||||
|
[optional] usetable: bool=false
|
||||||
|
) -> nil|table|Bytearray
|
||||||
|
|
||||||
-- Closes the connection
|
-- Closes the connection
|
||||||
socket:close()
|
socket:close()
|
||||||
|
|
||||||
@ -137,5 +147,5 @@ network.get_total_download() --> int
|
|||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Looks for a free port to use.
|
-- Looks for a free port to use.
|
||||||
network.find_free_port() --> int
|
network.find_free_port() --> int or nil
|
||||||
```
|
```
|
||||||
|
|||||||
@ -136,6 +136,7 @@ The key code for comparison can be obtained via `input.keycode("key_name")`
|
|||||||
- `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.
|
- `line-numbers` - enables line numbers display.
|
||||||
|
- `keep-line-selection` - keep showing selected line after defocus.
|
||||||
- `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.
|
- `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.
|
||||||
|
|||||||
@ -161,6 +161,11 @@ app.get_setting_info(name: str) -> {
|
|||||||
Возвращает таблицу с информацией о настройке. Бросает исключение, если настройки не существует.
|
Возвращает таблицу с информацией о настройке. Бросает исключение, если настройки не существует.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
app.focus()
|
||||||
|
```
|
||||||
|
|
||||||
|
Переводит окно на передний план и устанавливает фокус ввода.
|
||||||
|
|
||||||
app.create_memory_device(
|
app.create_memory_device(
|
||||||
-- имя точки входа
|
-- имя точки входа
|
||||||
name: str
|
name: str
|
||||||
|
|||||||
@ -13,7 +13,16 @@ input.mousecode(mousename: str) --> int
|
|||||||
Возвращает код кнопки мыши по имени, либо -1
|
Возвращает код кнопки мыши по имени, либо -1
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
input.add_callback(bindname: str, callback: function)
|
input.add_callback(
|
||||||
|
-- Имя привязки
|
||||||
|
bindname: str,
|
||||||
|
-- Обработчик
|
||||||
|
callback: function
|
||||||
|
-- UI элемент-владелец обработчика (отвечает за срок жизни)
|
||||||
|
[опционально] owner: Element,
|
||||||
|
-- Игнорировать захват ввода UI элементами
|
||||||
|
[опционально] istoplevel: bool
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Назначает функцию, которая будет вызываться при активации привязки. Пример:
|
Назначает функцию, которая будет вызываться при активации привязки. Пример:
|
||||||
|
|||||||
@ -82,6 +82,16 @@ socket:recv(
|
|||||||
-- В случае ошибки возвращает nil (сокет закрыт или несуществует).
|
-- В случае ошибки возвращает nil (сокет закрыт или несуществует).
|
||||||
-- Если данных пока нет, возвращает пустой массив байт.
|
-- Если данных пока нет, возвращает пустой массив байт.
|
||||||
|
|
||||||
|
-- Асинхронный вариант для использования в корутинах.
|
||||||
|
-- Ожидает получение всего указанного числа байт.
|
||||||
|
-- При закрытии сокета работает как socket:recv
|
||||||
|
socket:recv_async(
|
||||||
|
-- Размер читаемого массива байт
|
||||||
|
length: int,
|
||||||
|
-- Использовать таблицу вместо Bytearray
|
||||||
|
[опционально] usetable: bool=false
|
||||||
|
) -> nil|table|Bytearray
|
||||||
|
|
||||||
-- Закрывает соединение
|
-- Закрывает соединение
|
||||||
socket:close()
|
socket:close()
|
||||||
|
|
||||||
@ -202,5 +212,5 @@ network.get_total_download() --> int
|
|||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Ищет свободный для использования порт.
|
-- Ищет свободный для использования порт.
|
||||||
network.find_free_port() --> int
|
network.find_free_port() --> int или nil
|
||||||
```
|
```
|
||||||
|
|||||||
@ -137,6 +137,7 @@
|
|||||||
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
||||||
- `editable`- определяет возможность редактирования текста.
|
- `editable`- определяет возможность редактирования текста.
|
||||||
- `line-numbers` - включает отображение номеров строк.
|
- `line-numbers` - включает отображение номеров строк.
|
||||||
|
- `keep-line-selection` - продолжать отображать выбранную строку при потере фокуса.
|
||||||
- `error-color` - цвет при вводе некорректных данных (текст не проходит проверку валидатора). Тип: RGBA цвет.
|
- `error-color` - цвет при вводе некорректных данных (текст не проходит проверку валидатора). Тип: RGBA цвет.
|
||||||
- `text-color` - цвет текста. Тип: RGBA цвет.
|
- `text-color` - цвет текста. Тип: RGBA цвет.
|
||||||
- `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен.
|
- `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен.
|
||||||
|
|||||||
153
doc/specs/debugging_protocol.md
Normal file
153
doc/specs/debugging_protocol.md
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
# VC-DBG protocol v1
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- '?' in name means that the attribute is optional.
|
||||||
|
|
||||||
|
## Connecting
|
||||||
|
|
||||||
|
### Step 1
|
||||||
|
|
||||||
|
Connection initiating with binary header exchange:
|
||||||
|
|
||||||
|
```
|
||||||
|
'v' 'c' '-' 'd' 'b' 'g' NUL XX
|
||||||
|
76 63 2D 64 62 67 00 XX
|
||||||
|
```
|
||||||
|
|
||||||
|
XX - protocol version number
|
||||||
|
|
||||||
|
Client sends header to the server. Then server responds.
|
||||||
|
Server closes connection after sending header if it mismatches.
|
||||||
|
|
||||||
|
### Step 2
|
||||||
|
|
||||||
|
Client sends 'connect' command.
|
||||||
|
|
||||||
|
## Messages
|
||||||
|
|
||||||
|
Message is:
|
||||||
|
- 32 bit little-endian unsigned integer - number of encoded message bytes.
|
||||||
|
- message itself (UTF-8 encoded json).
|
||||||
|
|
||||||
|
## Client-to-server
|
||||||
|
|
||||||
|
### Establishing connection
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "connect",
|
||||||
|
"?disconnect-action": "resume|detach|terminate"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Configuring connection. Disconnect-action is action that debugged instance must perform on debugging client connection closed/refused.
|
||||||
|
|
||||||
|
- `resume` - Resume from pause mode and start listening for client.
|
||||||
|
- `detach` - Resume from pause mode and stop server.
|
||||||
|
- `terminate` - Stop the debugged application.
|
||||||
|
|
||||||
|
|
||||||
|
### Specific action signals.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "pause|resume|terminate|detach"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Breakpoints management
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "set-breakpoint|remove-breakpoint",
|
||||||
|
"source": "entry_point:path",
|
||||||
|
"line": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Local value details request
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "get-value",
|
||||||
|
"frame": 0,
|
||||||
|
"local": 1,
|
||||||
|
"path": ["path", "to", 1, "value"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `frame` - Call stack frame index (indexing from most recent call)
|
||||||
|
- `local` - Local variable index (based on `paused` event stack trace)
|
||||||
|
- `path` - Requsted value path segments. Example: `['a', 'b', 5]` is `local_variable.a.b[5]`
|
||||||
|
|
||||||
|
Responds with:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "value",
|
||||||
|
"frame": 0,
|
||||||
|
"local": 1,
|
||||||
|
"path": ["path", "to", 1, "value"],
|
||||||
|
"value": "value itself"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example: actual value is table:
|
||||||
|
```lua
|
||||||
|
{a=5, b="test", 2={}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then `value` is:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"a": {
|
||||||
|
"type": "number",
|
||||||
|
"short": "5"
|
||||||
|
},
|
||||||
|
"b": {
|
||||||
|
"type": "string",
|
||||||
|
"short": "test"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"type": "table",
|
||||||
|
"short": "{...}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Server-to-client
|
||||||
|
|
||||||
|
### Response signals
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "success|resumed"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pause event
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "paused",
|
||||||
|
"?reason": "breakpoint|exception|step",
|
||||||
|
"?message": "...",
|
||||||
|
"?stack": [
|
||||||
|
{
|
||||||
|
"?function": "function name",
|
||||||
|
"source": "source name",
|
||||||
|
"what": "what",
|
||||||
|
"line": 1,
|
||||||
|
"locals": [
|
||||||
|
"name": {
|
||||||
|
"type": "local type",
|
||||||
|
"index": 1,
|
||||||
|
"short": "short value",
|
||||||
|
"size": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
@ -8,5 +8,5 @@ multiline-string-end = "]]"
|
|||||||
keywords = [
|
keywords = [
|
||||||
"and", "break", "do", "else", "elseif", "end", "false", "for", "function",
|
"and", "break", "do", "else", "elseif", "end", "false", "for", "function",
|
||||||
"if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true",
|
"if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true",
|
||||||
"until", "while"
|
"until", "while", "self", "error"
|
||||||
]
|
]
|
||||||
|
|||||||
@ -60,7 +60,9 @@ if is_debugging then
|
|||||||
current_func = _debug_getinfo(2).func
|
current_func = _debug_getinfo(2).func
|
||||||
current_func_stack_size = calc_stack_size()
|
current_func_stack_size = calc_stack_size()
|
||||||
__pause("breakpoint")
|
__pause("breakpoint")
|
||||||
debug.pull_events()
|
while debug.pull_events() do
|
||||||
|
__pause()
|
||||||
|
end
|
||||||
end, "lr")
|
end, "lr")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -92,6 +94,7 @@ function debug.pull_events()
|
|||||||
if not events then
|
if not events then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
local keepPaused = false
|
||||||
for i, event in ipairs(events) do
|
for i, event in ipairs(events) do
|
||||||
if event[1] == DBG_EVENT_SET_BREAKPOINT then
|
if event[1] == DBG_EVENT_SET_BREAKPOINT then
|
||||||
debug.set_breakpoint(event[2], event[3])
|
debug.set_breakpoint(event[2], event[3])
|
||||||
@ -116,9 +119,10 @@ function debug.pull_events()
|
|||||||
value = value[key]
|
value = value[key]
|
||||||
end
|
end
|
||||||
__sendvalue(value, event[2], event[3], event[4])
|
__sendvalue(value, event[2], event[3], event[4])
|
||||||
__pause()
|
keepPaused = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return keepPaused
|
||||||
end
|
end
|
||||||
|
|
||||||
function debug.set_breakpoint(source, line)
|
function debug.set_breakpoint(source, line)
|
||||||
|
|||||||
@ -3,7 +3,7 @@ local Schedule = {
|
|||||||
set_interval = function(self, ms, callback, repetions)
|
set_interval = function(self, ms, callback, repetions)
|
||||||
local id = self._next_interval
|
local id = self._next_interval
|
||||||
self._intervals[id] = {
|
self._intervals[id] = {
|
||||||
last_called = 0.0,
|
last_called = self._timer,
|
||||||
delay = ms / 1000.0,
|
delay = ms / 1000.0,
|
||||||
callback = callback,
|
callback = callback,
|
||||||
repetions = repetions,
|
repetions = repetions,
|
||||||
|
|||||||
@ -39,6 +39,16 @@ end
|
|||||||
local Socket = {__index={
|
local Socket = {__index={
|
||||||
send=function(self, ...) return network.__send(self.id, ...) end,
|
send=function(self, ...) return network.__send(self.id, ...) end,
|
||||||
recv=function(self, ...) return network.__recv(self.id, ...) end,
|
recv=function(self, ...) return network.__recv(self.id, ...) end,
|
||||||
|
recv_async=function(self, length, usetable)
|
||||||
|
while self:is_alive() do
|
||||||
|
local available = self:available()
|
||||||
|
if available >= length then
|
||||||
|
return self:recv(length, usetable)
|
||||||
|
end
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
return self:recv(length, usetable)
|
||||||
|
end,
|
||||||
close=function(self) return network.__close(self.id) end,
|
close=function(self) return network.__close(self.id) end,
|
||||||
available=function(self) return network.__available(self.id) or 0 end,
|
available=function(self) return network.__available(self.id) or 0 end,
|
||||||
is_alive=function(self) return network.__is_alive(self.id) end,
|
is_alive=function(self) return network.__is_alive(self.id) end,
|
||||||
|
|||||||
@ -47,6 +47,7 @@ local function complete_app_lib(app)
|
|||||||
end
|
end
|
||||||
app.reset_content = core.reset_content
|
app.reset_content = core.reset_content
|
||||||
app.is_content_loaded = core.is_content_loaded
|
app.is_content_loaded = core.is_content_loaded
|
||||||
|
app.set_title = core.set_title
|
||||||
|
|
||||||
function app.config_packs(packs_list)
|
function app.config_packs(packs_list)
|
||||||
-- Check if packs are valid and add dependencies to the configuration
|
-- Check if packs are valid and add dependencies to the configuration
|
||||||
|
|||||||
@ -197,6 +197,7 @@ bool DebuggingServer::performCommand(
|
|||||||
connectionEstablished = true;
|
connectionEstablished = true;
|
||||||
logger.info() << "client connection established";
|
logger.info() << "client connection established";
|
||||||
connection->sendResponse("success");
|
connection->sendResponse("success");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (!connectionEstablished) {
|
if (!connectionEstablished) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -70,6 +70,7 @@ void Engine::onContentLoad() {
|
|||||||
for (auto& pack : content->getAllContentPacks()) {
|
for (auto& pack : content->getAllContentPacks()) {
|
||||||
auto configFolder = pack.folder / "config";
|
auto configFolder = pack.folder / "config";
|
||||||
auto bindsFile = configFolder / "bindings.toml";
|
auto bindsFile = configFolder / "bindings.toml";
|
||||||
|
logger.info() << "loading bindings: " << bindsFile.string();
|
||||||
if (io::is_regular_file(bindsFile)) {
|
if (io::is_regular_file(bindsFile)) {
|
||||||
input->getBindings().read(
|
input->getBindings().read(
|
||||||
toml::parse(
|
toml::parse(
|
||||||
|
|||||||
@ -72,6 +72,14 @@ EnginePaths::EnginePaths(CoreParameters& params)
|
|||||||
io::create_subdevice("config", "user", "config");
|
io::create_subdevice("config", "user", "config");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path EnginePaths::getResourcesFolder() const {
|
||||||
|
return resourcesFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path EnginePaths::getUserFilesFolder() const {
|
||||||
|
return userFilesFolder;
|
||||||
|
}
|
||||||
|
|
||||||
io::path EnginePaths::getNewScreenshotFile(const std::string& ext) const {
|
io::path EnginePaths::getNewScreenshotFile(const std::string& ext) const {
|
||||||
auto folder = SCREENSHOTS_FOLDER;
|
auto folder = SCREENSHOTS_FOLDER;
|
||||||
if (!io::is_directory(folder)) {
|
if (!io::is_directory(folder)) {
|
||||||
|
|||||||
@ -48,6 +48,9 @@ public:
|
|||||||
|
|
||||||
EnginePaths(CoreParameters& params);
|
EnginePaths(CoreParameters& params);
|
||||||
|
|
||||||
|
std::filesystem::path getResourcesFolder() const;
|
||||||
|
std::filesystem::path getUserFilesFolder() const;
|
||||||
|
|
||||||
io::path getWorldFolderByName(const std::string& name);
|
io::path getWorldFolderByName(const std::string& name);
|
||||||
io::path getWorldsFolder() const;
|
io::path getWorldsFolder() const;
|
||||||
|
|
||||||
|
|||||||
@ -33,11 +33,12 @@ WindowControl::Result WindowControl::initialize() {
|
|||||||
auto& settings = engine.getSettings();
|
auto& settings = engine.getSettings();
|
||||||
|
|
||||||
std::string title = project.title;
|
std::string title = project.title;
|
||||||
if (title.empty()) {
|
if (!title.empty()) {
|
||||||
title = "VoxelCore v" +
|
title += " - ";
|
||||||
std::to_string(ENGINE_VERSION_MAJOR) + "." +
|
|
||||||
std::to_string(ENGINE_VERSION_MINOR);
|
|
||||||
}
|
}
|
||||||
|
title += "VoxelCore v" +
|
||||||
|
std::to_string(ENGINE_VERSION_MAJOR) + "." +
|
||||||
|
std::to_string(ENGINE_VERSION_MINOR);
|
||||||
if (ENGINE_DEBUG_BUILD) {
|
if (ENGINE_DEBUG_BUILD) {
|
||||||
title += " [debug]";
|
title += " [debug]";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,10 +93,9 @@ void Container::act(float delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GUI& gui = this->gui;
|
|
||||||
intervalEvents.erase(std::remove_if(
|
intervalEvents.erase(std::remove_if(
|
||||||
intervalEvents.begin(), intervalEvents.end(),
|
intervalEvents.begin(), intervalEvents.end(),
|
||||||
[&gui](const IntervalEvent& event) {
|
[](const IntervalEvent& event) {
|
||||||
return event.repeat == 0;
|
return event.repeat == 0;
|
||||||
}
|
}
|
||||||
), intervalEvents.end());
|
), intervalEvents.end());
|
||||||
@ -177,6 +176,7 @@ void Container::add(const std::shared_ptr<UINode>& node) {
|
|||||||
parent->setMustRefresh();
|
parent->setMustRefresh();
|
||||||
parent = parent->getParent();
|
parent = parent->getParent();
|
||||||
}
|
}
|
||||||
|
gui.getWindow().setShouldRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::add(const std::shared_ptr<UINode>& node, glm::vec2 pos) {
|
void Container::add(const std::shared_ptr<UINode>& node, glm::vec2 pos) {
|
||||||
|
|||||||
@ -37,7 +37,9 @@ namespace gui {
|
|||||||
virtual void scrolled(int value) override;
|
virtual void scrolled(int value) override;
|
||||||
virtual void setScrollable(bool flag);
|
virtual void setScrollable(bool flag);
|
||||||
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() const override {
|
||||||
|
return glm::vec2(0.0f, scroll);
|
||||||
|
};
|
||||||
virtual void setSize(const glm::vec2& size) override;
|
virtual void setSize(const glm::vec2& size) override;
|
||||||
virtual int getScrollStep() const;
|
virtual int getScrollStep() const;
|
||||||
virtual void setScrollStep(int step);
|
virtual void setScrollStep(int step);
|
||||||
|
|||||||
@ -36,12 +36,11 @@ void InlineFrame::setDocument(const std::shared_ptr<UiDocument>& document) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InlineFrame::act(float delta) {
|
void InlineFrame::act(float delta) {
|
||||||
Container::act(delta);
|
if (document == nullptr && !src.empty()) {
|
||||||
if (document || src.empty()) {
|
const auto& assets = *gui.getEngine().getAssets();
|
||||||
return;
|
setDocument(assets.getShared<UiDocument>(src));
|
||||||
}
|
}
|
||||||
const auto& assets = *gui.getEngine().getAssets();
|
Container::act(delta);
|
||||||
setDocument(assets.getShared<UiDocument>(src));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InlineFrame::setSize(const glm::vec2& size) {
|
void InlineFrame::setSize(const glm::vec2& size) {
|
||||||
|
|||||||
@ -231,7 +231,7 @@ TextBox::~TextBox() = default;
|
|||||||
void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
Container::draw(pctx, assets);
|
Container::draw(pctx, assets);
|
||||||
|
|
||||||
if (!isFocused()) {
|
if (!isFocused() && !keepLineSelection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto& labelText = getText();
|
const auto& labelText = getText();
|
||||||
@ -252,7 +252,7 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
|||||||
|
|
||||||
float time = gui.getWindow().time();
|
float time = gui.getWindow().time();
|
||||||
|
|
||||||
if (editable && static_cast<int>((time - caretLastMove) * 2) % 2 == 0) {
|
if (isFocused() && editable && static_cast<int>((time - caretLastMove) * 2) % 2 == 0) {
|
||||||
uint line = label->getLineByTextIndex(caret);
|
uint line = label->getLineByTextIndex(caret);
|
||||||
uint lcaret = caret - label->getTextLineOffset(line);
|
uint lcaret = caret - label->getTextLineOffset(line);
|
||||||
int width = rawTextCache.metrics.calcWidth(input, 0, lcaret);
|
int width = rawTextCache.metrics.calcWidth(input, 0, lcaret);
|
||||||
@ -308,42 +308,44 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFocused() && multiline) {
|
if (!multiline) {
|
||||||
auto selectionCtx = subctx.sub(batch);
|
return;
|
||||||
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);
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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, const Assets& assets) {
|
void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) {
|
||||||
@ -605,6 +607,14 @@ size_t TextBox::getSelectionEnd() const {
|
|||||||
return selectionEnd;
|
return selectionEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextBox::setKeepLineSelection(bool flag) {
|
||||||
|
keepLineSelection = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextBox::isKeepLineSelection() const {
|
||||||
|
return keepLineSelection;
|
||||||
|
}
|
||||||
|
|
||||||
void TextBox::setOnEditStart(runnable oneditstart) {
|
void TextBox::setOnEditStart(runnable oneditstart) {
|
||||||
onEditStart = oneditstart;
|
onEditStart = oneditstart;
|
||||||
}
|
}
|
||||||
@ -671,6 +681,11 @@ int TextBox::calcIndexAt(int x, int y) const {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TextBox::getLineYOffset(int line) const {
|
||||||
|
if (rawTextCache.fontId == 0) return 0;
|
||||||
|
return label->getLineYOffset(line);
|
||||||
|
}
|
||||||
|
|
||||||
static inline std::wstring get_alphabet(wchar_t c) {
|
static inline std::wstring get_alphabet(wchar_t c) {
|
||||||
std::wstring alphabet {c};
|
std::wstring alphabet {c};
|
||||||
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') {
|
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') {
|
||||||
|
|||||||
@ -62,6 +62,7 @@ namespace gui {
|
|||||||
bool editable = true;
|
bool editable = true;
|
||||||
bool autoresize = false;
|
bool autoresize = false;
|
||||||
bool showLineNumbers = false;
|
bool showLineNumbers = false;
|
||||||
|
bool keepLineSelection = false;
|
||||||
std::string markup;
|
std::string markup;
|
||||||
std::string syntax;
|
std::string syntax;
|
||||||
|
|
||||||
@ -74,7 +75,6 @@ namespace gui {
|
|||||||
|
|
||||||
size_t normalizeIndex(int index);
|
size_t normalizeIndex(int index);
|
||||||
|
|
||||||
int calcIndexAt(int x, int y) const;
|
|
||||||
void setTextOffset(uint x);
|
void setTextOffset(uint x);
|
||||||
bool eraseSelected();
|
bool eraseSelected();
|
||||||
void resetSelection();
|
void resetSelection();
|
||||||
@ -186,6 +186,9 @@ namespace gui {
|
|||||||
/// @return line position in text
|
/// @return line position in text
|
||||||
virtual size_t getLinePos(uint line) const;
|
virtual size_t getLinePos(uint line) const;
|
||||||
|
|
||||||
|
int calcIndexAt(int x, int y) const;
|
||||||
|
int getLineYOffset(int 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();
|
||||||
@ -220,6 +223,9 @@ namespace gui {
|
|||||||
size_t getSelectionStart() const;
|
size_t getSelectionStart() const;
|
||||||
size_t getSelectionEnd() const;
|
size_t getSelectionEnd() const;
|
||||||
|
|
||||||
|
void setKeepLineSelection(bool flag);
|
||||||
|
bool isKeepLineSelection() 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);
|
||||||
|
|
||||||
|
|||||||
@ -68,6 +68,10 @@ void UINode::listenClick(OnAction action) {
|
|||||||
actions.listen(UIAction::CLICK, std::move(action));
|
actions.listen(UIAction::CLICK, std::move(action));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UINode::listenRightClick(OnAction action) {
|
||||||
|
actions.listen(UIAction::RIGHT_CLICK, std::move(action));
|
||||||
|
}
|
||||||
|
|
||||||
void UINode::listenDoubleClick(OnAction action) {
|
void UINode::listenDoubleClick(OnAction action) {
|
||||||
actions.listen(UIAction::DOUBLE_CLICK, std::move(action));
|
actions.listen(UIAction::DOUBLE_CLICK, std::move(action));
|
||||||
}
|
}
|
||||||
@ -84,6 +88,12 @@ void UINode::click(int, int) {
|
|||||||
pressed = true;
|
pressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UINode::clicked(Mousecode button) {
|
||||||
|
if (button == Mousecode::BUTTON_2) {
|
||||||
|
actions.notify(UIAction::RIGHT_CLICK, gui);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UINode::doubleClick(int x, int y) {
|
void UINode::doubleClick(int x, int y) {
|
||||||
pressed = true;
|
pressed = true;
|
||||||
if (isInside(glm::vec2(x, y))) {
|
if (isInside(glm::vec2(x, y))) {
|
||||||
|
|||||||
@ -75,7 +75,7 @@ namespace gui {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum class UIAction {
|
enum class UIAction {
|
||||||
CLICK, DOUBLE_CLICK, FOCUS, DEFOCUS
|
CLICK, DOUBLE_CLICK, FOCUS, DEFOCUS, RIGHT_CLICK
|
||||||
};
|
};
|
||||||
|
|
||||||
using ActionsSet = TaggedCallbacksSet<UIAction, GUI&>;
|
using ActionsSet = TaggedCallbacksSet<UIAction, GUI&>;
|
||||||
@ -214,6 +214,7 @@ namespace gui {
|
|||||||
int getZIndex() const;
|
int getZIndex() const;
|
||||||
|
|
||||||
virtual void listenClick(OnAction action);
|
virtual void listenClick(OnAction action);
|
||||||
|
virtual void listenRightClick(OnAction action);
|
||||||
virtual void listenDoubleClick(OnAction action);
|
virtual void listenDoubleClick(OnAction action);
|
||||||
virtual void listenFocus(OnAction action);
|
virtual void listenFocus(OnAction action);
|
||||||
virtual void listenDefocus(OnAction action);
|
virtual void listenDefocus(OnAction action);
|
||||||
@ -221,7 +222,7 @@ namespace gui {
|
|||||||
virtual void onFocus();
|
virtual void onFocus();
|
||||||
virtual void doubleClick(int x, int y);
|
virtual void doubleClick(int x, int y);
|
||||||
virtual void click(int x, int y);
|
virtual void click(int x, int y);
|
||||||
virtual void clicked(Mousecode button) {}
|
virtual void clicked(Mousecode button);
|
||||||
virtual void mouseMove(int x, int y) {};
|
virtual void mouseMove(int x, int y) {};
|
||||||
virtual void mouseRelease(int x, int y);
|
virtual void mouseRelease(int x, int y);
|
||||||
virtual void scrolled(int value);
|
virtual void scrolled(int value);
|
||||||
@ -266,7 +267,7 @@ namespace gui {
|
|||||||
virtual glm::vec4 calcColor() const;
|
virtual glm::vec4 calcColor() const;
|
||||||
|
|
||||||
/// @brief Get inner content offset. Used for scroll
|
/// @brief Get inner content offset. Used for scroll
|
||||||
virtual glm::vec2 getContentOffset() {return glm::vec2(0.0f);};
|
virtual glm::vec2 getContentOffset() const {return glm::vec2(0.0f);};
|
||||||
/// @brief Calculate screen position of the element
|
/// @brief Calculate screen position of the element
|
||||||
virtual glm::vec2 calcPos() const;
|
virtual glm::vec2 calcPos() const;
|
||||||
virtual void setPos(const glm::vec2& pos);
|
virtual void setPos(const glm::vec2& pos);
|
||||||
|
|||||||
@ -181,6 +181,10 @@ static void read_uinode(
|
|||||||
node.listenClick(onclick);
|
node.listenClick(onclick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auto onclick = create_action(reader, element, "onrightclick")) {
|
||||||
|
node.listenRightClick(onclick);
|
||||||
|
}
|
||||||
|
|
||||||
if (auto onfocus = create_action(reader, element, "onfocus")) {
|
if (auto onfocus = create_action(reader, element, "onfocus")) {
|
||||||
node.listenFocus(onfocus);
|
node.listenFocus(onfocus);
|
||||||
}
|
}
|
||||||
@ -569,6 +573,11 @@ static std::shared_ptr<UINode> read_text_box(
|
|||||||
if (element.has("line-numbers")) {
|
if (element.has("line-numbers")) {
|
||||||
textbox->setShowLineNumbers(element.attr("line-numbers").asBool());
|
textbox->setShowLineNumbers(element.attr("line-numbers").asBool());
|
||||||
}
|
}
|
||||||
|
if (element.has("keep-line-selection")) {
|
||||||
|
textbox->setKeepLineSelection(
|
||||||
|
element.attr("keep-line-selection").asBool()
|
||||||
|
);
|
||||||
|
}
|
||||||
if (element.has("markup")) {
|
if (element.has("markup")) {
|
||||||
textbox->setMarkup(element.attr("markup").getText());
|
textbox->setMarkup(element.attr("markup").getText());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,12 +2,40 @@
|
|||||||
|
|
||||||
#include "io/io.hpp"
|
#include "io/io.hpp"
|
||||||
#include "io/devices/MemoryDevice.hpp"
|
#include "io/devices/MemoryDevice.hpp"
|
||||||
#include "engine/Engine.hpp"
|
|
||||||
#include "content/ContentControl.hpp"
|
|
||||||
#include "logic/scripting/scripting.hpp"
|
#include "logic/scripting/scripting.hpp"
|
||||||
|
#include "content/ContentControl.hpp"
|
||||||
|
#include "engine/Engine.hpp"
|
||||||
|
#include "engine/EnginePaths.hpp"
|
||||||
|
#include "network/Network.hpp"
|
||||||
|
#include "util/platform.hpp"
|
||||||
|
#include "window/Window.hpp"
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
|
|
||||||
|
static int l_start_debug_instance(lua::State* L) {
|
||||||
|
int port = lua::tointeger(L, 1);
|
||||||
|
if (port == 0) {
|
||||||
|
port = engine->getNetwork().findFreePort();
|
||||||
|
if (port == -1) {
|
||||||
|
throw std::runtime_error("could not find free port");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto& paths = engine->getPaths();
|
||||||
|
|
||||||
|
std::vector<std::string> args {
|
||||||
|
"--res", paths.getResourcesFolder().u8string(),
|
||||||
|
"--dir", paths.getUserFilesFolder().u8string(),
|
||||||
|
"--dbg-server", "tcp:" + std::to_string(port),
|
||||||
|
};
|
||||||
|
platform::new_engine_instance(std::move(args));
|
||||||
|
return lua::pushinteger(L, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_focus(lua::State* L) {
|
||||||
|
engine->getWindow().focus();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int l_create_memory_device(lua::State* L) {
|
static int l_create_memory_device(lua::State* L) {
|
||||||
std::string name = lua::require_string(L, 1);
|
std::string name = lua::require_string(L, 1);
|
||||||
if (io::get_device(name)) {
|
if (io::get_device(name)) {
|
||||||
@ -54,10 +82,12 @@ static int l_reset_content_sources(lua::State* L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const luaL_Reg applib[] = {
|
const luaL_Reg applib[] = {
|
||||||
|
{"start_debug_instance", lua::wrap<l_start_debug_instance>},
|
||||||
|
{"focus", lua::wrap<l_focus>},
|
||||||
{"create_memory_device", lua::wrap<l_create_memory_device>},
|
{"create_memory_device", lua::wrap<l_create_memory_device>},
|
||||||
{"get_content_sources", lua::wrap<l_get_content_sources>},
|
{"get_content_sources", lua::wrap<l_get_content_sources>},
|
||||||
{"set_content_sources", lua::wrap<l_set_content_sources>},
|
{"set_content_sources", lua::wrap<l_set_content_sources>},
|
||||||
{"reset_content_sources", lua::wrap<l_reset_content_sources>},
|
{"reset_content_sources", lua::wrap<l_reset_content_sources>},
|
||||||
// see libcore.cpp an stdlib.lua
|
// for other functions see libcore.cpp and stdlib.lua
|
||||||
{nullptr, nullptr}
|
{nullptr, nullptr}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
#include "graphics/ui/gui_util.hpp"
|
#include "graphics/ui/gui_util.hpp"
|
||||||
#include "graphics/ui/GUI.hpp"
|
#include "graphics/ui/GUI.hpp"
|
||||||
#include "graphics/ui/elements/Menu.hpp"
|
#include "graphics/ui/elements/Menu.hpp"
|
||||||
|
#include "window/Window.hpp"
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
|
|
||||||
@ -299,6 +300,12 @@ static int l_capture_output(lua::State* L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_set_title(lua::State* L) {
|
||||||
|
auto title = lua::require_string(L, 1);
|
||||||
|
engine->getWindow().setTitle(title);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg corelib[] = {
|
const luaL_Reg corelib[] = {
|
||||||
{"blank", lua::wrap<l_blank>},
|
{"blank", lua::wrap<l_blank>},
|
||||||
{"get_version", lua::wrap<l_get_version>},
|
{"get_version", lua::wrap<l_get_version>},
|
||||||
@ -320,5 +327,6 @@ const luaL_Reg corelib[] = {
|
|||||||
{"open_url", lua::wrap<l_open_url>},
|
{"open_url", lua::wrap<l_open_url>},
|
||||||
{"quit", lua::wrap<l_quit>},
|
{"quit", lua::wrap<l_quit>},
|
||||||
{"capture_output", lua::wrap<l_capture_output>},
|
{"capture_output", lua::wrap<l_capture_output>},
|
||||||
|
{"set_title", lua::wrap<l_set_title>},
|
||||||
{nullptr, nullptr}
|
{nullptr, nullptr}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -173,7 +173,25 @@ static int l_get_line_at(lua::State* L) {
|
|||||||
auto node = get_document_node(L, 1);
|
auto node = get_document_node(L, 1);
|
||||||
auto position = lua::tointeger(L, 2);
|
auto position = lua::tointeger(L, 2);
|
||||||
if (auto box = dynamic_cast<TextBox*>(node.node.get())) {
|
if (auto box = dynamic_cast<TextBox*>(node.node.get())) {
|
||||||
return lua::pushinteger(L, box->getLineAt(position));
|
return lua::pushinteger(L, box->getLineAt(position) + 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_get_index_by_pos(lua::State* L) {
|
||||||
|
auto node = get_document_node(L, 1);
|
||||||
|
auto position = lua::tovec2(L, 2);
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node.node.get())) {
|
||||||
|
return lua::pushinteger(L, box->calcIndexAt(position.x, position.y));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_get_line_y(lua::State* L) {
|
||||||
|
auto node = get_document_node(L, 1);
|
||||||
|
auto line = lua::tointeger(L, 2);
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node.node.get())) {
|
||||||
|
return lua::pushinteger(L, box->getLineYOffset(line - 1));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -509,6 +527,12 @@ static int p_get_focused(UINode* node, lua::State* L) {
|
|||||||
static int p_get_line_at(UINode*, lua::State* L) {
|
static int p_get_line_at(UINode*, lua::State* L) {
|
||||||
return lua::pushcfunction(L, l_get_line_at);
|
return lua::pushcfunction(L, l_get_line_at);
|
||||||
}
|
}
|
||||||
|
static int p_get_index_by_pos(UINode*, lua::State* L) {
|
||||||
|
return lua::pushcfunction(L, l_get_index_by_pos);
|
||||||
|
}
|
||||||
|
static int p_get_line_y(UINode*, lua::State* L) {
|
||||||
|
return lua::pushcfunction(L, l_get_line_y);
|
||||||
|
}
|
||||||
static int p_get_line_pos(UINode*, lua::State* L) {
|
static int p_get_line_pos(UINode*, lua::State* L) {
|
||||||
return lua::pushcfunction(L, l_get_line_pos);
|
return lua::pushcfunction(L, l_get_line_pos);
|
||||||
}
|
}
|
||||||
@ -619,6 +643,8 @@ static int l_gui_getattr(lua::State* L) {
|
|||||||
{"edited", p_get_edited},
|
{"edited", p_get_edited},
|
||||||
{"lineNumbers", p_get_line_numbers},
|
{"lineNumbers", p_get_line_numbers},
|
||||||
{"lineAt", p_get_line_at},
|
{"lineAt", p_get_line_at},
|
||||||
|
{"indexByPos", p_get_index_by_pos},
|
||||||
|
{"lineY", p_get_line_y},
|
||||||
{"linePos", p_get_line_pos},
|
{"linePos", p_get_line_pos},
|
||||||
{"syntax", p_get_syntax},
|
{"syntax", p_get_syntax},
|
||||||
{"markup", p_get_markup},
|
{"markup", p_get_markup},
|
||||||
|
|||||||
@ -50,8 +50,11 @@ static int l_add_callback(lua::State* L) {
|
|||||||
handler = input.addKeyCallback(key, actual_callback);
|
handler = input.addKeyCallback(key, actual_callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto callback = [&gui, actual_callback]() -> bool {
|
|
||||||
if (!gui.isFocusCaught()) {
|
bool isTopLevel = lua::toboolean(L, 4);
|
||||||
|
|
||||||
|
auto callback = [&gui, actual_callback, isTopLevel]() -> bool {
|
||||||
|
if (isTopLevel || !gui.isFocusCaught()) {
|
||||||
return actual_callback();
|
return actual_callback();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -410,7 +410,11 @@ static int l_get_total_download(lua::State* L, network::Network& network) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int l_find_free_port(lua::State* L, network::Network& network) {
|
static int l_find_free_port(lua::State* L, network::Network& network) {
|
||||||
return lua::pushinteger(L, network.findFreePort());
|
int port = network.findFreePort();
|
||||||
|
if (port == -1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return lua::pushinteger(L, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_set_nodelay(lua::State* L, network::Network& network) {
|
static int l_set_nodelay(lua::State* L, network::Network& network) {
|
||||||
|
|||||||
@ -309,14 +309,15 @@ static int l_debug_sendvalue(lua::State* L) {
|
|||||||
|
|
||||||
lua::pushnil(L);
|
lua::pushnil(L);
|
||||||
while (lua::next(L, 1)) {
|
while (lua::next(L, 1)) {
|
||||||
auto key = lua::tolstring(L, -2);
|
lua::pushvalue(L, -2);
|
||||||
|
|
||||||
int type = lua::type(L, -1);
|
auto key = lua::tolstring(L, -1);
|
||||||
|
int type = lua::type(L, -2);
|
||||||
table[std::string(key)] = dv::object({
|
table[std::string(key)] = dv::object({
|
||||||
{"type", std::string(lua::type_name(L, type))},
|
{"type", std::string(lua::type_name(L, type))},
|
||||||
{"short", get_short_value(L, -1, type)},
|
{"short", get_short_value(L, -2, type)},
|
||||||
});
|
});
|
||||||
lua::pop(L);
|
lua::pop(L, 2);
|
||||||
}
|
}
|
||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
value = std::move(table);
|
value = std::move(table);
|
||||||
|
|||||||
@ -36,6 +36,9 @@ public:
|
|||||||
virtual void setMode(WindowMode mode) = 0;
|
virtual void setMode(WindowMode mode) = 0;
|
||||||
virtual WindowMode getMode() const = 0;
|
virtual WindowMode getMode() const = 0;
|
||||||
|
|
||||||
|
virtual void focus() = 0;
|
||||||
|
|
||||||
|
virtual void setTitle(const std::string& title) = 0;
|
||||||
virtual void setIcon(const ImageData* image) = 0;
|
virtual void setIcon(const ImageData* image) = 0;
|
||||||
|
|
||||||
virtual void pushScissor(glm::vec4 area) = 0;
|
virtual void pushScissor(glm::vec4 area) = 0;
|
||||||
|
|||||||
@ -188,7 +188,7 @@ public:
|
|||||||
codepoints.clear();
|
codepoints.clear();
|
||||||
pressedKeys.clear();
|
pressedKeys.clear();
|
||||||
if (waitForRefresh) {
|
if (waitForRefresh) {
|
||||||
glfwWaitEvents();
|
glfwWaitEventsTimeout(0.5);
|
||||||
} else {
|
} else {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
@ -468,6 +468,14 @@ public:
|
|||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void focus() override {
|
||||||
|
glfwFocusWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTitle(const std::string& title) override {
|
||||||
|
glfwSetWindowTitle(window, title.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void setIcon(const ImageData* image) override {
|
void setIcon(const ImageData* image) override {
|
||||||
if (image == nullptr) {
|
if (image == nullptr) {
|
||||||
glfwSetWindowIcon(window, 0, nullptr);
|
glfwSetWindowIcon(window, 0, nullptr);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user