From 9fbf46169f3725fa0d530295288f2e3ff0e19dcc Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 4 Mar 2024 20:16:22 +0300 Subject: [PATCH] textbox: 'editable' property --- src/frontend/gui/controls.cpp | 39 ++++++++++++++++++----- src/frontend/gui/controls.h | 58 ++++++++++++++++++++++++++++++++--- src/frontend/gui/gui_xml.cpp | 4 +++ src/frontend/hud.cpp | 5 +-- 4 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/frontend/gui/controls.cpp b/src/frontend/gui/controls.cpp index 85cb7568..1d566fa8 100644 --- a/src/frontend/gui/controls.cpp +++ b/src/frontend/gui/controls.cpp @@ -388,7 +388,7 @@ void TextBox::draw(const GfxContext* pctx, Assets* assets) { lcoord.y -= 2; auto batch = pctx->getBatch2D(); batch->texture(nullptr); - if (int((Window::time() - caretLastMove) * 2) % 2 == 0) { + if (editable && int((Window::time() - caretLastMove) * 2) % 2 == 0) { uint line = label->getLineByTextIndex(caret); uint lcaret = caret - label->getTextLineOffset(line); batch->setColor(glm::vec4(1.0f)); @@ -426,7 +426,7 @@ void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) { batch->texture(nullptr); if (valid) { - if (isFocused()) { + if (isFocused() && !multiline) { batch->setColor(focusedColor); } else if (hover && !multiline) { batch->setColor(hoverColor); @@ -442,6 +442,17 @@ void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) { input = supplier(); } + if (isFocused() && multiline) { + batch->setColor(glm::vec4(1, 1, 1, 0.1f)); + glm::vec2 lcoord = label->calcCoord(); + lcoord.y -= 4; + uint line = label->getLineByTextIndex(caret); + int lineY = label->getLineYOffset(line); + int lineHeight = font->getLineHeight() * label->getLineInterval(); + batch->rect(lcoord.x, lcoord.y+lineY, label->getSize().x, 1); + batch->rect(lcoord.x, lcoord.y+lineY+lineHeight, label->getSize().x, 1); + } + label->setColor(glm::vec4(input.empty() ? 0.5f : 1.0f)); label->setText(getText()); if (multiline && font) { @@ -465,8 +476,8 @@ void TextBox::paste(const std::wstring& text) { auto left = input.substr(0, caret); auto right = input.substr(caret); input = left + text + right; - input.erase(std::remove(input.begin(), input.end(), '\r'), input.end()); } + input.erase(std::remove(input.begin(), input.end(), '\r'), input.end()); // refresh label lines configuration for correct setCaret work label->setText(input); @@ -560,6 +571,14 @@ bool TextBox::isMultiline() const { return multiline; } +void TextBox::setEditable(bool editable) { + this->editable = editable; +} + +bool TextBox::isEditable() const { + return editable; +} + void TextBox::setOnEditStart(runnable oneditstart) { onEditStart = oneditstart; } @@ -621,9 +640,7 @@ void TextBox::resetMaxLocalCaret() { maxLocalCaret = caret - label->getTextLineOffset(label->getLineByTextIndex(caret)); } - -// TODO: refactor -void TextBox::keyPressed(keycode key) { +void TextBox::performEditingKeyboardEvents(keycode key) { bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT); bool breakSelection = getSelectionLength() != 0 && !shiftPressed; uint previousCaret = caret; @@ -726,6 +743,12 @@ void TextBox::keyPressed(keycode key) { resetSelection(); } } +} + +void TextBox::keyPressed(keycode key) { + if (editable) { + performEditingKeyboardEvents(key); + } if (Events::pressed(keycode::LEFT_CONTROL)) { // Copy selected text to clipboard if (key == keycode::C || key == keycode::X) { @@ -733,12 +756,12 @@ void TextBox::keyPressed(keycode key) { if (!text.empty()) { Window::setClipboardText(text.c_str()); } - if (key == keycode::X) { + if (editable && key == keycode::X) { eraseSelected(); } } // Paste text from clipboard - if (key == keycode::V) { + if (key == keycode::V && editable) { const char* text = Window::getClipboardText(); if (text) { paste(util::str2wstr_utf8(text)); diff --git a/src/frontend/gui/controls.h b/src/frontend/gui/controls.h index c6e66a41..539e46a9 100644 --- a/src/frontend/gui/controls.h +++ b/src/frontend/gui/controls.h @@ -175,6 +175,7 @@ namespace gui { size_t selectionOrigin = 0; bool multiline = false; + bool editable = true; size_t normalizeIndex(int index); @@ -192,34 +193,83 @@ namespace gui { /// @brief Set maxLocalCaret to local (line) caret position void resetMaxLocalCaret(); + + void performEditingKeyboardEvents(keycode key); public: - TextBox(std::wstring placeholder, - glm::vec4 padding=glm::vec4(4.0f)); + TextBox( + std::wstring placeholder, + glm::vec4 padding=glm::vec4(4.0f) + ); virtual void setTextSupplier(wstringsupplier supplier); + + /// @brief Consumer called on stop editing text (textbox defocus) + /// @param consumer std::wstring consumer function virtual void setTextConsumer(wstringconsumer consumer); + + /// @brief Text validator called while text editing and returns true if + /// text is valid + /// @param validator std::wstring consumer returning boolean virtual void setTextValidator(wstringchecker validator); + virtual void setFocusedColor(glm::vec4 color); virtual glm::vec4 getFocusedColor() const; + + /// @brief Set color of textbox marked by validator as invalid virtual void setErrorColor(glm::vec4 color); + + /// @brief Get color of textbox marked by validator as invalid virtual glm::vec4 getErrorColor() const; + /// @brief Get TextBox content text or placeholder if empty virtual std::wstring getText() const; + /// @brief Set TextBox content text virtual void setText(std::wstring value); + + /// @brief Get text placeholder virtual std::wstring getPlaceholder() const; - virtual void setPlaceholder(const std::wstring&); + + /// @brief Set text placeholder + /// @param text will be used instead of empty + virtual void setPlaceholder(const std::wstring& text); + + /// @brief Get selected text virtual std::wstring getSelection() const; + + /// @brief Get current caret position in text + /// @return integer in range [0, text.length()] virtual uint getCaret() const; + + /// @brief Set caret position in the text + /// @param position integer in range [0, text.length()] virtual void setCaret(uint position); + + /// @brief Select part of the text + /// @param start index of the first selected character + /// @param end index of the last selected character + 1 virtual void select(int start, int end); + + /// @brief Check text with validator set with setTextValidator + /// @return true if text is valid virtual bool validate(); + virtual void setValid(bool valid); virtual bool isValid() const; - // multiline mode is in development + /// @brief Enable/disable multiline mode virtual void setMultiline(bool multiline); + + /// @brief Check if multiline mode is enabled virtual bool isMultiline() const; + + /// @brief Enable/disable text editing feature + virtual void setEditable(bool editable); + + /// @brief Check if text editing feature is enabled + virtual bool isEditable() const; + + /// @brief Set runnable called on textbox focus virtual void setOnEditStart(runnable oneditstart); virtual void focus(GUI*) override; diff --git a/src/frontend/gui/gui_xml.cpp b/src/frontend/gui/gui_xml.cpp index 401090f0..18d2b125 100644 --- a/src/frontend/gui/gui_xml.cpp +++ b/src/frontend/gui/gui_xml.cpp @@ -221,6 +221,10 @@ static std::shared_ptr readTextBox(UiXmlReader& reader, xml::xmlelement if (element->has("multiline")) { textbox->setMultiline(element->attr("multiline").asBool()); } + + if (element->has("editable")) { + textbox->setEditable(element->attr("editable").asBool()); + } if (element->has("consumer")) { auto consumer = scripting::create_wstring_consumer( diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 8ea22a2b..1e14501a 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -353,8 +353,9 @@ void Hud::update(bool visible) { setPause(true); } } - if (visible && !gui->isFocusCaught() && Events::jactive(BIND_HUD_INVENTORY)) { - if (!pause) { + + if (visible && !gui->isFocusCaught() && !pause) { + if (Events::jactive(BIND_HUD_INVENTORY)) { if (inventoryOpen) { closeInventory(); } else {