From 8bf65eef1a01d59967fde70e03e709cbb5275ed9 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 14 May 2024 05:05:13 +0300 Subject: [PATCH] textbox autoresize --- res/layouts/console.xml | 16 ++- res/layouts/console.xml.lua | 8 +- src/graphics/ui/elements/TextBox.cpp | 186 ++++++++++++++++----------- src/graphics/ui/elements/TextBox.hpp | 14 +- src/graphics/ui/gui_xml.cpp | 5 +- src/logic/scripting/lua/libgui.cpp | 16 +++ 6 files changed, 164 insertions(+), 81 deletions(-) diff --git a/res/layouts/console.xml b/res/layouts/console.xml index f0995f4a..1f005c9e 100644 --- a/res/layouts/console.xml +++ b/res/layouts/console.xml @@ -1,5 +1,15 @@ - - - + + + + diff --git a/res/layouts/console.xml.lua b/res/layouts/console.xml.lua index 261518b3..e286562a 100644 --- a/res/layouts/console.xml.lua +++ b/res/layouts/console.xml.lua @@ -10,11 +10,15 @@ function submit(text) local status, result = pcall(function() return console.execute(text) end) if result ~= nil then - document.log.text = document.log.text..tostring(result)..'\n' + local prevtext = document.log.text + if #prevtext == 0 then + document.log:paste(tostring(result)) + else + document.log:paste('\n'..tostring(result)) + end end document.prompt.text = "" document.prompt.focused = true - print(document.log.pos) end function on_open() diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index 3d97dbca..4caab647 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -21,6 +21,7 @@ TextBox::TextBox(std::wstring placeholder, glm::vec4 padding) setHoverColor(glm::vec4(0.05f, 0.1f, 0.2f, 0.75f)); textInitX = label->getPos().x; + scrollable = true; } void TextBox::draw(const DrawContext* pctx, Assets* assets) { @@ -28,9 +29,25 @@ void TextBox::draw(const DrawContext* pctx, Assets* assets) { font = assets->getFont(label->getFontName()); - if (!isFocused()) + if (autoresize && font) { + auto size = getSize(); + int newy = glm::min(static_cast(parent->getSize().y), + static_cast( + label->getLinesNumber() * + label->getLineInterval() * + font->getLineHeight()) + ); + if (newy != static_cast(size.y)) { + size.y = newy; + setSize(size); + if (positionfunc) { + pos = positionfunc(); + } + } + } + if (!isFocused()) { return; - + } glm::vec2 pos = calcPos(); glm::vec2 size = getSize(); @@ -186,8 +203,9 @@ void TextBox::extendSelection(int index) { size_t TextBox::getLineLength(uint line) const { size_t position = label->getTextLineOffset(line); size_t lineLength = label->getTextLineOffset(line+1)-position; - if (lineLength == 0) + if (lineLength == 0) { lineLength = input.length() - position + 1; + } return lineLength; } @@ -255,6 +273,14 @@ void TextBox::setOnEditStart(runnable oneditstart) { onEditStart = oneditstart; } +void TextBox::setAutoResize(bool flag) { + this->autoresize = flag; +} + +bool TextBox::isAutoResize() const { + return autoresize; +} + void TextBox::onFocus(GUI* gui) { Panel::onFocus(gui); if (onEditStart){ @@ -312,6 +338,87 @@ void TextBox::resetMaxLocalCaret() { maxLocalCaret = caret - label->getTextLineOffset(label->getLineByTextIndex(caret)); } +void TextBox::stepLeft(bool shiftPressed, bool breakSelection, uint previousCaret) { + uint caret = breakSelection ? selectionStart : this->caret; + if (caret > 0) { + if (caret > input.length()) { + setCaret(input.length()-1); + } else { + setCaret(caret-1); + } + if (shiftPressed) { + if (selectionStart == selectionEnd) { + selectionOrigin = previousCaret; + } + extendSelection(this->caret); + } else { + resetSelection(); + } + } else { + setCaret(caret); + resetSelection(); + } + resetMaxLocalCaret(); +} + +void TextBox::stepRight(bool shiftPressed, bool breakSelection, uint previousCaret) { + uint caret = breakSelection ? selectionEnd : this->caret; + if (caret < input.length()) { + setCaret(caret+1); + caretLastMove = Window::time(); + if (shiftPressed) { + if (selectionStart == selectionEnd) { + selectionOrigin = previousCaret; + } + extendSelection(this->caret); + } else { + resetSelection(); + } + } else { + setCaret(caret); + resetSelection(); + } + resetMaxLocalCaret(); +} + +void TextBox::stepDown(bool shiftPressed, bool breakSelection, uint previousCaret) { + uint caret = breakSelection ? selectionEnd : this->caret; + uint caretLine = label->getLineByTextIndex(caret); + if (caretLine < label->getLinesNumber()-1) { + uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine+1)-1); + setCaret(label->getTextLineOffset(caretLine+1) + offset); + } else { + setCaret(input.length()); + } + if (shiftPressed) { + if (selectionStart == selectionEnd) { + selectionOrigin = previousCaret; + } + extendSelection(this->caret); + } else { + resetSelection(); + } +} + +void TextBox::stepUp(bool shiftPressed, bool breakSelection, uint previousCaret) { + uint caret = breakSelection ? selectionStart : this->caret; + uint caretLine = label->getLineByTextIndex(caret); + if (caretLine > 0) { + uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine-1)-1); + setCaret(label->getTextLineOffset(caretLine-1) + offset); + } else { + setCaret(0); + } + if (shiftPressed) { + if (selectionStart == selectionEnd) { + selectionOrigin = previousCaret; + } + extendSelection(this->caret); + } else { + resetSelection(); + } +} + void TextBox::performEditingKeyboardEvents(keycode key) { bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT); bool breakSelection = getSelectionLength() != 0 && !shiftPressed; @@ -342,78 +449,13 @@ void TextBox::performEditingKeyboardEvents(keycode key) { } else if (key == keycode::TAB) { paste(L" "); } else if (key == keycode::LEFT) { - uint caret = breakSelection ? selectionStart : this->caret; - if (caret > 0) { - if (caret > input.length()) { - setCaret(input.length()-1); - } else { - setCaret(caret-1); - } - if (shiftPressed) { - if (selectionStart == selectionEnd) { - selectionOrigin = previousCaret; - } - extendSelection(this->caret); - } else { - resetSelection(); - } - } else { - setCaret(caret); - resetSelection(); - } - resetMaxLocalCaret(); + stepLeft(shiftPressed, breakSelection, previousCaret); } else if (key == keycode::RIGHT) { - uint caret = breakSelection ? selectionEnd : this->caret; - if (caret < input.length()) { - setCaret(caret+1); - caretLastMove = Window::time(); - if (shiftPressed) { - if (selectionStart == selectionEnd) { - selectionOrigin = previousCaret; - } - extendSelection(this->caret); - } else { - resetSelection(); - } - } else { - setCaret(caret); - resetSelection(); - } - resetMaxLocalCaret(); + stepRight(shiftPressed, breakSelection, previousCaret); } else if (key == keycode::UP) { - uint caret = breakSelection ? selectionStart : this->caret; - uint caretLine = label->getLineByTextIndex(caret); - if (caretLine > 0) { - uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine-1)-1); - setCaret(label->getTextLineOffset(caretLine-1) + offset); - } else { - setCaret(0); - } - if (shiftPressed) { - if (selectionStart == selectionEnd) { - selectionOrigin = previousCaret; - } - extendSelection(this->caret); - } else { - resetSelection(); - } + stepUp(shiftPressed, breakSelection, previousCaret); } else if (key == keycode::DOWN) { - uint caret = breakSelection ? selectionEnd : this->caret; - uint caretLine = label->getLineByTextIndex(caret); - if (caretLine < label->getLinesNumber()-1) { - uint offset = std::min(size_t(maxLocalCaret), getLineLength(caretLine+1)-1); - setCaret(label->getTextLineOffset(caretLine+1) + offset); - } else { - setCaret(input.length()); - } - if (shiftPressed) { - if (selectionStart == selectionEnd) { - selectionOrigin = previousCaret; - } - extendSelection(this->caret); - } else { - resetSelection(); - } + stepDown(shiftPressed, breakSelection, previousCaret); } } diff --git a/src/graphics/ui/elements/TextBox.hpp b/src/graphics/ui/elements/TextBox.hpp index bf06c9db..84d6807a 100644 --- a/src/graphics/ui/elements/TextBox.hpp +++ b/src/graphics/ui/elements/TextBox.hpp @@ -37,11 +37,16 @@ namespace gui { bool multiline = false; bool editable = true; + bool autoresize = false; + + void stepLeft(bool shiftPressed, bool breakSelection, uint previousCaret); + void stepRight(bool shiftPressed, bool breakSelection, uint previousCaret); + void stepDown(bool shiftPressed, bool breakSelection, uint previousCaret); + void stepUp(bool shiftPressed, bool breakSelection, uint previousCaret); size_t normalizeIndex(int index); int calcIndexAt(int x, int y) const; - void paste(const std::wstring& text); void setTextOffset(uint x); void erase(size_t start, size_t length); bool eraseSelected(); @@ -61,7 +66,9 @@ namespace gui { std::wstring placeholder, glm::vec4 padding=glm::vec4(4.0f) ); - + + void paste(const std::wstring& text); + virtual void setTextSupplier(wstringsupplier supplier); /// @brief Consumer called on stop editing text (textbox defocus) @@ -139,6 +146,9 @@ namespace gui { /// @brief Set runnable called on textbox focus virtual void setOnEditStart(runnable oneditstart); + virtual void setAutoResize(bool flag); + virtual bool isAutoResize() const; + virtual void onFocus(GUI*) override; virtual void refresh() override; virtual void click(GUI*, int, int) override; diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp index 8f7acac2..9382e216 100644 --- a/src/graphics/ui/gui_xml.cpp +++ b/src/graphics/ui/gui_xml.cpp @@ -313,11 +313,12 @@ static std::shared_ptr readTextBox(UiXmlReader& reader, xml::xmlelement if (element->has("text-wrap")) { textbox->setTextWrapping(element->attr("text-wrap").asBool()); } - if (element->has("editable")) { textbox->setEditable(element->attr("editable").asBool()); } - + if (element->has("autoresize")) { + textbox->setAutoResize(element->attr("autoresize").asBool()); + } if (element->has("consumer")) { textbox->setTextConsumer(scripting::create_wstring_consumer( reader.getEnvironment(), diff --git a/src/logic/scripting/lua/libgui.cpp b/src/logic/scripting/lua/libgui.cpp index 5bcd62b4..4ee959dc 100644 --- a/src/logic/scripting/lua/libgui.cpp +++ b/src/logic/scripting/lua/libgui.cpp @@ -70,6 +70,14 @@ static int l_menu_reset(lua_State* L) { return 0; } +static int l_textbox_paste(lua_State* L) { + auto node = getDocumentNode(L); + auto box = dynamic_cast(node.node.get()); + auto text = lua_tostring(L, 2); + box->paste(util::str2wstr_utf8(text)); + return 0; +} + static int l_container_add(lua_State* L) { auto docnode = getDocumentNode(L); auto node = dynamic_cast(docnode.node.get()); @@ -121,6 +129,13 @@ static int p_get_back(UINode* node) { return 0; } +static int p_get_paste(UINode* node) { + if (dynamic_cast(node)) { + return state->pushcfunction(l_textbox_paste); + } + return 0; +} + static int p_get_page(UINode* node) { if (auto menu = dynamic_cast(node)) { return state->pushstring(menu->getCurrent().name); @@ -289,6 +304,7 @@ static int l_gui_getattr(lua_State* L) { {"page", p_get_page}, {"back", p_get_back}, {"reset", p_get_reset}, + {"paste", p_get_paste}, {"inventory", p_get_inventory}, {"focused", p_get_focused}, };