diff --git a/res/layouts/console.xml.lua b/res/layouts/console.xml.lua index bfdd5f3f..7ed29c1f 100644 --- a/res/layouts/console.xml.lua +++ b/res/layouts/console.xml.lua @@ -13,6 +13,7 @@ function on_history_up() return end document.prompt.text = history[history_pointer] + document.prompt.caret = -1 history_pointer = history_pointer - 1 end @@ -22,6 +23,7 @@ function on_history_down() end history_pointer = history_pointer + 1 document.prompt.text = history[history_pointer + 1] + document.prompt.caret = -1 end function add_to_history(text) diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index 5f4aba2c..2240acee 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -369,7 +369,7 @@ void TextBox::click(GUI*, int x, int y) { } void TextBox::mouseMove(GUI*, int x, int y) { - int index = calcIndexAt(x, y); + ssize_t index = calcIndexAt(x, y); setCaret(index); extendSelection(index); resetMaxLocalCaret(); @@ -381,7 +381,7 @@ void TextBox::resetMaxLocalCaret() { void TextBox::stepLeft(bool shiftPressed, bool breakSelection) { uint previousCaret = this->caret; - uint caret = breakSelection ? selectionStart : this->caret; + size_t caret = breakSelection ? selectionStart : this->caret; if (caret > 0) { if (caret > input.length()) { setCaret(input.length()-1); @@ -405,7 +405,7 @@ void TextBox::stepLeft(bool shiftPressed, bool breakSelection) { void TextBox::stepRight(bool shiftPressed, bool breakSelection) { uint previousCaret = this->caret; - uint caret = breakSelection ? selectionEnd : this->caret; + size_t caret = breakSelection ? selectionEnd : this->caret; if (caret < input.length()) { setCaret(caret+1); caretLastMove = Window::time(); @@ -452,7 +452,7 @@ void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) { uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine-1)-1); setCaret(label->getTextLineOffset(caretLine-1) + offset); } else { - setCaret(0); + setCaret(0UL); } if (shiftPressed) { if (selectionStart == selectionEnd) { @@ -628,11 +628,11 @@ std::wstring TextBox::getSelection() const { return input.substr(selectionStart, selectionEnd-selectionStart); } -uint TextBox::getCaret() const { +size_t TextBox::getCaret() const { return caret; } -void TextBox::setCaret(uint position) { +void TextBox::setCaret(size_t position) { this->caret = std::min(static_cast(position), input.length()); caretLastMove = Window::time(); @@ -652,6 +652,14 @@ void TextBox::setCaret(uint position) { if (realoffset-width > 0) { setTextOffset(textOffset + realoffset-width); } else if (realoffset < 0) { - setTextOffset(std::max(textOffset + realoffset, 0U)); + setTextOffset(std::max(textOffset + realoffset, 0LU)); + } +} + +void TextBox::setCaret(ssize_t position) { + if (position < 0) { + setCaret(static_cast(input.length() + position + 1)); + } else { + setCaret(static_cast(position)); } } diff --git a/src/graphics/ui/elements/TextBox.hpp b/src/graphics/ui/elements/TextBox.hpp index c041702f..183a5ec7 100644 --- a/src/graphics/ui/elements/TextBox.hpp +++ b/src/graphics/ui/elements/TextBox.hpp @@ -24,10 +24,10 @@ namespace gui { runnable onDownPressed; bool valid = true; /// @brief text input pointer, value may be greather than text length - uint caret = 0; + size_t caret = 0; /// @brief actual local (line) position of the caret on vertical move - uint maxLocalCaret = 0; - uint textOffset = 0; + size_t maxLocalCaret = 0; + size_t textOffset = 0; int textInitX; /// @brief last time of the caret was moved (used for blink animation) double caretLastMove = 0.0; @@ -112,11 +112,15 @@ namespace gui { /// @brief Get current caret position in text /// @return integer in range [0, text.length()] - virtual uint getCaret() const; + virtual size_t getCaret() const; /// @brief Set caret position in the text /// @param position integer in range [0, text.length()] - virtual void setCaret(uint position); + virtual void setCaret(size_t position); + + /// @brief Set caret position in the text + /// @param position integer in range [-text.length(), text.length()] + virtual void setCaret(ssize_t position); /// @brief Select part of the text /// @param start index of the first selected character diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp index 3484cc45..50ba1bb2 100644 --- a/src/graphics/ui/gui_xml.cpp +++ b/src/graphics/ui/gui_xml.cpp @@ -50,7 +50,11 @@ static Gravity gravity_from_string(const std::string& str) { return Gravity::none; } -static runnable create_runnable(UiXmlReader& reader, xml::xmlelement element, const std::string& name) { +static runnable create_runnable( + const UiXmlReader& reader, + xml::xmlelement element, + const std::string& name +) { if (element->has(name)) { std::string text = element->attr(name).getText(); if (!text.empty()) { diff --git a/src/logic/scripting/lua/libgui.cpp b/src/logic/scripting/lua/libgui.cpp index 4ee959dc..d2e72d8a 100644 --- a/src/logic/scripting/lua/libgui.cpp +++ b/src/logic/scripting/lua/libgui.cpp @@ -201,6 +201,13 @@ static int p_is_valid(UINode* node) { return 0; } +static int p_get_caret(UINode* node) { + if (auto box = dynamic_cast(node)) { + return state->pushinteger(static_cast(box->getCaret())); + } + return 0; +} + static int p_get_placeholder(UINode* node) { if (auto box = dynamic_cast(node)) { return state->pushstring(util::wstr2str_utf8(box->getPlaceholder())); @@ -292,6 +299,7 @@ static int l_gui_getattr(lua_State* L) { {"clear", p_get_clear}, {"placeholder", p_get_placeholder}, {"valid", p_is_valid}, + {"caret", p_get_caret}, {"text", p_get_text}, {"editable", p_get_editable}, {"value", p_get_value}, @@ -353,6 +361,11 @@ static void p_set_text(UINode* node, int idx) { box->setText(util::str2wstr_utf8(state->tostring(idx))); } } +static void p_set_caret(UINode* node, int idx) { + if (auto box = dynamic_cast(node)) { + box->setCaret(static_cast(state->tointeger(idx))); + } +} static void p_set_editable(UINode* node, int idx) { if (auto box = dynamic_cast(node)) { box->setEditable(state->toboolean(idx)); @@ -438,6 +451,7 @@ static int l_gui_setattr(lua_State* L) { {"placeholder", p_set_placeholder}, {"text", p_set_text}, {"editable", p_set_editable}, + {"caret", p_set_caret}, {"value", p_set_value}, {"min", p_set_min}, {"max", p_set_max},