feat: 'edited' property reset & add 'oncontrolkey' textbox callback
This commit is contained in:
parent
fb18442322
commit
3a4b334d0b
@ -79,7 +79,7 @@ Properties:
|
|||||||
| hint | string | yes | yes | text to display when nothing is entered |
|
| hint | string | yes | yes | text to display when nothing is entered |
|
||||||
| 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 |
|
||||||
| edited | bool | yes | no | is text edited since the last set (history is not empty) |
|
| edited | bool | yes | yes\* | is text edited since the last set / edited status reset |
|
||||||
| multiline | bool | yes | yes | multiline support |
|
| multiline | bool | yes | yes | multiline support |
|
||||||
| lineNumbers | bool | yes | yes | display line numbers |
|
| 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") |
|
||||||
@ -88,6 +88,8 @@ Properties:
|
|||||||
| syntax | string | yes | yes | syntax highlighting ("lua" - Lua) |
|
| syntax | string | yes | yes | syntax highlighting ("lua" - Lua) |
|
||||||
| markup | string | yes | yes | text markup language ("md" - Markdown) |
|
| markup | string | yes | yes | text markup language ("md" - Markdown) |
|
||||||
|
|
||||||
|
\* - false only
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
| Method | Description |
|
| Method | Description |
|
||||||
|
|||||||
@ -110,6 +110,8 @@ Inner text - initially entered text
|
|||||||
- `supplier` - text supplier (called every frame)
|
- `supplier` - text supplier (called every frame)
|
||||||
- `consumer` - lua function that receives the entered text. Called only when input is complete
|
- `consumer` - lua function that receives the entered text. Called only when input is complete
|
||||||
- `sub-consumer` - lua function-receiver of the input text. Called during text input or deletion.
|
- `sub-consumer` - lua function-receiver of the input text. Called during text input or deletion.
|
||||||
|
- `oncontrolkey` - lua function called for combinations of the form (Ctrl + ?). The codepoint of the second key is given as the first argument.
|
||||||
|
The key code for comparison can be obtained via `input.keycode("key_name")`
|
||||||
- `autoresize` - automatic change of element size (default - false). Does not affect font size.
|
- `autoresize` - automatic change of element size (default - false). Does not affect font size.
|
||||||
- `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")
|
||||||
|
|||||||
@ -79,7 +79,7 @@ document["worlds-panel"]:clear()
|
|||||||
| hint | string | да | да | текст, отображаемый, когда ничего не введено |
|
| hint | string | да | да | текст, отображаемый, когда ничего не введено |
|
||||||
| caret | int | да | да | позиция каретки. `textbox.caret = -1` установит позицию в конец текста |
|
| caret | int | да | да | позиция каретки. `textbox.caret = -1` установит позицию в конец текста |
|
||||||
| editable | bool | да | да | изменяемость текста |
|
| editable | bool | да | да | изменяемость текста |
|
||||||
| edited | bool | да | нет | был ли изменён текст с последней установки (история не пуста) |
|
| edited | bool | да | да\* | был ли изменён текст с последней установки/сброса свойства |
|
||||||
| multiline | bool | да | да | поддержка многострочности |
|
| multiline | bool | да | да | поддержка многострочности |
|
||||||
| lineNumbers | bool | да | да | отображение номеров строк |
|
| lineNumbers | bool | да | да | отображение номеров строк |
|
||||||
| textWrap | bool | да | да | автоматический перенос текста (только при multiline: "true") |
|
| textWrap | bool | да | да | автоматический перенос текста (только при multiline: "true") |
|
||||||
@ -88,6 +88,8 @@ document["worlds-panel"]:clear()
|
|||||||
| syntax | string | да | да | подсветка синтаксиса ("lua" - Lua) |
|
| syntax | string | да | да | подсветка синтаксиса ("lua" - Lua) |
|
||||||
| markup | string | да | да | язык разметки текста ("md" - Markdown) |
|
| markup | string | да | да | язык разметки текста ("md" - Markdown) |
|
||||||
|
|
||||||
|
\* - только false
|
||||||
|
|
||||||
Методы:
|
Методы:
|
||||||
|
|
||||||
| Метод | Описание |
|
| Метод | Описание |
|
||||||
|
|||||||
@ -111,6 +111,8 @@
|
|||||||
- `supplier` - поставщик текста (вызывается каждый кадр)
|
- `supplier` - поставщик текста (вызывается каждый кадр)
|
||||||
- `consumer` - lua функция-приемник введенного текста. Вызывается только при завершении ввода
|
- `consumer` - lua функция-приемник введенного текста. Вызывается только при завершении ввода
|
||||||
- `sub-consumer` - lua функция-приемник вводимого текста. Вызывается во время ввода или удаления текста.
|
- `sub-consumer` - lua функция-приемник вводимого текста. Вызывается во время ввода или удаления текста.
|
||||||
|
- `oncontrolkey` - lua функция вызываемая для сочетаний вида (Ctrl + ?). На вход подаётся числовой код второй клавиши.
|
||||||
|
Код клавиши для сравнения можно получить через `input.keycode("имя_клавиши")`
|
||||||
- `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта.
|
- `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта.
|
||||||
- `multiline` - разрешает отображение многострочного текста.
|
- `multiline` - разрешает отображение многострочного текста.
|
||||||
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
||||||
|
|||||||
@ -57,6 +57,7 @@
|
|||||||
padding='5'
|
padding='5'
|
||||||
multiline='true'
|
multiline='true'
|
||||||
line-numbers='true'
|
line-numbers='true'
|
||||||
|
oncontrolkey='on_control_combination'
|
||||||
syntax='lua'
|
syntax='lua'
|
||||||
size-func="-1,40"
|
size-func="-1,40"
|
||||||
text-wrap='false'
|
text-wrap='false'
|
||||||
|
|||||||
@ -81,6 +81,12 @@ local function refresh_file_title()
|
|||||||
..(edited and ' *' or '')
|
..(edited and ' *' or '')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function on_control_combination(keycode)
|
||||||
|
if keycode == input.keycode("s") then
|
||||||
|
save_current_file()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function unlock_access()
|
function unlock_access()
|
||||||
if current_file.filename == "" then
|
if current_file.filename == "" then
|
||||||
return
|
return
|
||||||
@ -102,6 +108,7 @@ function save_current_file()
|
|||||||
current_file.modified = false
|
current_file.modified = false
|
||||||
document.saveIcon.enabled = false
|
document.saveIcon.enabled = false
|
||||||
document.title.text = gui.str('File')..' - '..current_file.filename
|
document.title.text = gui.str('File')..' - '..current_file.filename
|
||||||
|
document.editor.edited = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function open_file_in_editor(filename, line, mutable)
|
function open_file_in_editor(filename, line, mutable)
|
||||||
|
|||||||
@ -15,6 +15,7 @@ using wstringsupplier = std::function<std::wstring()>;
|
|||||||
using doublesupplier = std::function<double()>;
|
using doublesupplier = std::function<double()>;
|
||||||
using boolsupplier = std::function<bool()>;
|
using boolsupplier = std::function<bool()>;
|
||||||
using vec2supplier = std::function<glm::vec2()>;
|
using vec2supplier = std::function<glm::vec2()>;
|
||||||
|
using key_handler = std::function<bool(int)>;
|
||||||
|
|
||||||
using stringconsumer = std::function<void(const std::string&)>;
|
using stringconsumer = std::function<void(const std::string&)>;
|
||||||
using wstringconsumer = std::function<void(const std::wstring&)>;
|
using wstringconsumer = std::function<void(const std::wstring&)>;
|
||||||
|
|||||||
@ -145,6 +145,10 @@ public:
|
|||||||
: history(history), historySize(history.size()) {
|
: history(history), historySize(history.size()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Combination(const Combination&) = delete;
|
||||||
|
|
||||||
|
Combination(Combination&&) = default;
|
||||||
|
|
||||||
~Combination() {
|
~Combination() {
|
||||||
history.squash(history.size() - historySize);
|
history.squash(history.size() - historySize);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -564,7 +564,12 @@ bool TextBox::isEditable() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TextBox::isEdited() const {
|
bool TextBox::isEdited() const {
|
||||||
return history->size() != 0 || !historian->isSynced();
|
return history->size() != editedHistorySize || !historian->isSynced();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBox::setUnedited() {
|
||||||
|
historian->sync();
|
||||||
|
editedHistorySize = history->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t TextBox::getSelectionStart() const {
|
size_t TextBox::getSelectionStart() const {
|
||||||
@ -575,7 +580,6 @@ size_t TextBox::getSelectionEnd() const {
|
|||||||
return selectionEnd;
|
return selectionEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TextBox::setOnEditStart(runnable oneditstart) {
|
void TextBox::setOnEditStart(runnable oneditstart) {
|
||||||
onEditStart = oneditstart;
|
onEditStart = oneditstart;
|
||||||
}
|
}
|
||||||
@ -849,7 +853,12 @@ void TextBox::keyPressed(keycode key) {
|
|||||||
if (editable) {
|
if (editable) {
|
||||||
performEditingKeyboardEvents(key);
|
performEditingKeyboardEvents(key);
|
||||||
}
|
}
|
||||||
if (Events::pressed(keycode::LEFT_CONTROL)) {
|
if (Events::pressed(keycode::LEFT_CONTROL) && key != keycode::LEFT_CONTROL) {
|
||||||
|
if (controlCombinationsHandler) {
|
||||||
|
if (controlCombinationsHandler(static_cast<int>(key))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Copy selected text to clipboard
|
// Copy selected text to clipboard
|
||||||
if (key == keycode::C || key == keycode::X) {
|
if (key == keycode::C || key == keycode::X) {
|
||||||
std::string text = util::wstr2str_utf8(getSelection());
|
std::string text = util::wstr2str_utf8(getSelection());
|
||||||
@ -963,6 +972,10 @@ void TextBox::setTextValidator(wstringchecker validator) {
|
|||||||
this->validator = std::move(validator);
|
this->validator = std::move(validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextBox::setOnControlCombination(key_handler handler) {
|
||||||
|
this->controlCombinationsHandler = std::move(handler);
|
||||||
|
}
|
||||||
|
|
||||||
void TextBox::setFocusedColor(glm::vec4 color) {
|
void TextBox::setFocusedColor(glm::vec4 color) {
|
||||||
this->focusedColor = color;
|
this->focusedColor = color;
|
||||||
}
|
}
|
||||||
@ -999,6 +1012,7 @@ void TextBox::setText(const std::wstring& value) {
|
|||||||
input.erase(std::remove(input.begin(), input.end(), '\r'), input.end());
|
input.erase(std::remove(input.begin(), input.end(), '\r'), input.end());
|
||||||
historian->reset();
|
historian->reset();
|
||||||
history->clear();
|
history->clear();
|
||||||
|
editedHistorySize = 0;
|
||||||
refreshSyntax();
|
refreshSyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ namespace gui {
|
|||||||
LabelCache rawTextCache;
|
LabelCache rawTextCache;
|
||||||
std::shared_ptr<ActionsHistory> history;
|
std::shared_ptr<ActionsHistory> history;
|
||||||
std::unique_ptr<TextBoxHistorian> historian;
|
std::unique_ptr<TextBoxHistorian> historian;
|
||||||
|
int editedHistorySize = 0;
|
||||||
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};
|
||||||
@ -33,6 +34,7 @@ namespace gui {
|
|||||||
wstringconsumer subconsumer = nullptr;
|
wstringconsumer subconsumer = nullptr;
|
||||||
/// @brief Text validator returning boolean value
|
/// @brief Text validator returning boolean value
|
||||||
wstringchecker validator = nullptr;
|
wstringchecker validator = nullptr;
|
||||||
|
key_handler controlCombinationsHandler = nullptr;
|
||||||
/// @brief Function called on focus
|
/// @brief Function called on focus
|
||||||
runnable onEditStart = nullptr;
|
runnable onEditStart = nullptr;
|
||||||
/// @brief Function called on up arrow pressed
|
/// @brief Function called on up arrow pressed
|
||||||
@ -117,6 +119,8 @@ namespace gui {
|
|||||||
/// @param validator std::wstring consumer returning boolean
|
/// @param validator std::wstring consumer returning boolean
|
||||||
virtual void setTextValidator(wstringchecker validator);
|
virtual void setTextValidator(wstringchecker validator);
|
||||||
|
|
||||||
|
virtual void setOnControlCombination(key_handler handler);
|
||||||
|
|
||||||
virtual void setFocusedColor(glm::vec4 color);
|
virtual void setFocusedColor(glm::vec4 color);
|
||||||
virtual glm::vec4 getFocusedColor() const;
|
virtual glm::vec4 getFocusedColor() const;
|
||||||
|
|
||||||
@ -205,6 +209,7 @@ namespace gui {
|
|||||||
virtual bool isEditable() const;
|
virtual bool isEditable() const;
|
||||||
|
|
||||||
virtual bool isEdited() const;
|
virtual bool isEdited() const;
|
||||||
|
virtual void setUnedited();
|
||||||
|
|
||||||
virtual void setPadding(glm::vec4 padding);
|
virtual void setPadding(glm::vec4 padding);
|
||||||
glm::vec4 getPadding() const;
|
glm::vec4 getPadding() const;
|
||||||
|
|||||||
@ -493,6 +493,13 @@ static std::shared_ptr<UINode> read_text_box(
|
|||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if (element.has("oncontrolkey")) {
|
||||||
|
textbox->setOnControlCombination(scripting::create_key_handler(
|
||||||
|
reader.getEnvironment(),
|
||||||
|
element.attr("oncontrolkey").getText(),
|
||||||
|
reader.getFilename()
|
||||||
|
));
|
||||||
|
}
|
||||||
if (auto onUpPressed = create_runnable(reader, element, "onup")) {
|
if (auto onUpPressed = create_runnable(reader, element, "onup")) {
|
||||||
textbox->setOnUpPressed(onUpPressed);
|
textbox->setOnUpPressed(onUpPressed);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -553,6 +553,13 @@ 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_edited(UINode* node, lua::State* L, int idx) {
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
|
if (!lua::toboolean(L, idx)) {
|
||||||
|
box->setUnedited();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
static void p_set_line_numbers(UINode* node, lua::State* L, int idx) {
|
static void p_set_line_numbers(UINode* node, lua::State* L, int idx) {
|
||||||
if (auto box = dynamic_cast<TextBox*>(node)) {
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
box->setShowLineNumbers(lua::toboolean(L, idx));
|
box->setShowLineNumbers(lua::toboolean(L, idx));
|
||||||
@ -675,6 +682,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},
|
||||||
|
{"edited", p_set_edited},
|
||||||
{"lineNumbers", p_set_line_numbers},
|
{"lineNumbers", p_set_line_numbers},
|
||||||
{"syntax", p_set_syntax},
|
{"syntax", p_set_syntax},
|
||||||
{"markup", p_set_markup},
|
{"markup", p_set_markup},
|
||||||
|
|||||||
@ -36,6 +36,28 @@ static lua::State* process_callback(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
key_handler scripting::create_key_handler(
|
||||||
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
|
) {
|
||||||
|
return [=](int code) {
|
||||||
|
if (auto L = process_callback(env, src, file)) {
|
||||||
|
int top = lua::gettop(L);
|
||||||
|
if (lua::isfunction(L, -1)) {
|
||||||
|
lua::pushinteger(L, code);
|
||||||
|
lua::call_nothrow(L, 1);
|
||||||
|
}
|
||||||
|
int returned = lua::gettop(L) - top + 1;
|
||||||
|
if (returned) {
|
||||||
|
bool x = lua::toboolean(L, -1);
|
||||||
|
lua::pop(L, returned);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
wstringconsumer scripting::create_wstring_consumer(
|
wstringconsumer scripting::create_wstring_consumer(
|
||||||
const scriptenv& env, const std::string& src, const std::string& file
|
const scriptenv& env, const std::string& src, const std::string& file
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -17,6 +17,12 @@ namespace scripting {
|
|||||||
const std::string& file = "[string]"
|
const std::string& file = "[string]"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
key_handler create_key_handler(
|
||||||
|
const scriptenv& env,
|
||||||
|
const std::string& src,
|
||||||
|
const std::string& file = "[string]"
|
||||||
|
);
|
||||||
|
|
||||||
wstringconsumer create_wstring_consumer(
|
wstringconsumer create_wstring_consumer(
|
||||||
const scriptenv& env,
|
const scriptenv& env,
|
||||||
const std::string& src,
|
const std::string& src,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user