add 'hint' property to TextBox

This commit is contained in:
MihailRis 2024-11-12 23:20:43 +03:00
parent 01c568e032
commit d72f758dc5
6 changed files with 64 additions and 11 deletions

View File

@ -74,6 +74,7 @@ Properties:
| ----------- | ------ | ---- | ----- | ------------------------------------------------------------------------------------ | | ----------- | ------ | ---- | ----- | ------------------------------------------------------------------------------------ |
| text | string | yes | yes | entered text or placeholder | | text | string | yes | yes | entered text or placeholder |
| placeholder | string | yes | yes | placeholder (used if nothing has been entered) | | placeholder | string | yes | yes | placeholder (used if nothing has been 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 |
| multiline | bool | yes | yes | multiline support | | multiline | bool | yes | yes | multiline support |

View File

@ -74,6 +74,7 @@ document["worlds-panel"]:clear()
| ----------- | ------ | ------ | ------ | ---------------------------------------------------------------------- | | ----------- | ------ | ------ | ------ | ---------------------------------------------------------------------- |
| text | string | да | да | введенный текст или заполнитель | | text | string | да | да | введенный текст или заполнитель |
| placeholder | string | да | да | заполнитель (используется если ничего не было введено) | | placeholder | string | да | да | заполнитель (используется если ничего не было введено) |
| hint | string | да | да | текст, отображаемый, когда ничего не введено |
| caret | int | да | да | позиция каретки. `textbox.caret = -1` установит позицию в конец текста | | caret | int | да | да | позиция каретки. `textbox.caret = -1` установит позицию в конец текста |
| editable | bool | да | да | изменяемость текста | | editable | bool | да | да | изменяемость текста |
| multiline | bool | да | да | поддержка многострочности | | multiline | bool | да | да | поддержка многострочности |

View File

@ -127,7 +127,7 @@ void TextBox::drawBackground(const DrawContext* pctx, Assets*) {
void TextBox::refreshLabel() { void TextBox::refreshLabel() {
label->setColor(glm::vec4(input.empty() ? 0.5f : 1.0f)); label->setColor(glm::vec4(input.empty() ? 0.5f : 1.0f));
label->setText(getText()); label->setText(input.empty() && !hint.empty() ? hint : getText());
if (autoresize && font) { if (autoresize && font) {
auto size = getSize(); auto size = getSize();
@ -505,7 +505,7 @@ void TextBox::performEditingKeyboardEvents(keycode key) {
} else { } else {
defocus(); defocus();
if (validate() && consumer) { if (validate() && consumer) {
consumer(label->getText()); consumer(getText());
} }
} }
} else if (key == keycode::TAB) { } else if (key == keycode::TAB) {
@ -627,7 +627,7 @@ glm::vec4 TextBox::getErrorColor() const {
return invalidColor; return invalidColor;
} }
std::wstring TextBox::getText() const { const std::wstring& TextBox::getText() const {
if (input.empty()) if (input.empty())
return placeholder; return placeholder;
return input; return input;
@ -638,7 +638,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());
} }
std::wstring TextBox::getPlaceholder() const { const std::wstring& TextBox::getPlaceholder() const {
return placeholder; return placeholder;
} }
@ -646,6 +646,15 @@ void TextBox::setPlaceholder(const std::wstring& placeholder) {
this->placeholder = placeholder; this->placeholder = placeholder;
} }
const std::wstring& TextBox::getHint() const {
return hint;
}
void TextBox::setHint(const std::wstring& text) {
this->hint = text;
}
std::wstring TextBox::getSelection() const { std::wstring TextBox::getSelection() const {
return input.substr(selectionStart, selectionEnd-selectionStart); return input.substr(selectionStart, selectionEnd-selectionStart);
} }

View File

@ -13,23 +13,35 @@ namespace gui {
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};
std::shared_ptr<Label> label; std::shared_ptr<Label> label;
/// @brief Current user input
std::wstring input; std::wstring input;
/// @brief Text will be used if nothing entered
std::wstring placeholder; std::wstring placeholder;
/// @brief Text will be shown when nothing entered
std::wstring hint;
/// @brief Text supplier called every frame when not focused
wstringsupplier supplier = nullptr; wstringsupplier supplier = nullptr;
/// @brief Text supplier called on Enter pressed
wstringconsumer consumer = nullptr; wstringconsumer consumer = nullptr;
/// @brief Text supplier called while input
wstringconsumer subconsumer = nullptr; wstringconsumer subconsumer = nullptr;
/// @brief Text validator returning boolean value
wstringchecker validator = nullptr; wstringchecker validator = nullptr;
/// @brief Function called on focus
runnable onEditStart = nullptr; runnable onEditStart = nullptr;
/// @brief Function called on up arrow pressed
runnable onUpPressed; runnable onUpPressed;
/// @brief Function called on down arrow pressed
runnable onDownPressed; runnable onDownPressed;
/// @brief Is current input valid
bool valid = true; bool valid = true;
/// @brief text input pointer, value may be greather than text length /// @brief Text input pointer, value may be greather than text length
size_t caret = 0; size_t caret = 0;
/// @brief actual local (line) position of the caret on vertical move /// @brief Actual local (line) position of the caret on vertical move
size_t maxLocalCaret = 0; size_t maxLocalCaret = 0;
size_t textOffset = 0; size_t textOffset = 0;
int textInitX; int textInitX;
/// @brief last time of the caret was moved (used for blink animation) /// @brief Last time of the caret was moved (used for blink animation)
double caretLastMove = 0.0; double caretLastMove = 0.0;
Font* font = nullptr; Font* font = nullptr;
@ -101,17 +113,24 @@ namespace gui {
virtual glm::vec4 getErrorColor() const; virtual glm::vec4 getErrorColor() const;
/// @brief Get TextBox content text or placeholder if empty /// @brief Get TextBox content text or placeholder if empty
virtual std::wstring getText() const; virtual const std::wstring& getText() const;
/// @brief Set TextBox content text /// @brief Set TextBox content text
virtual void setText(const std::wstring &value); virtual void setText(const std::wstring &value);
/// @brief Get text placeholder /// @brief Get text placeholder
virtual std::wstring getPlaceholder() const; virtual const std::wstring& getPlaceholder() const;
/// @brief Set text placeholder /// @brief Set text placeholder
/// @param text will be used instead of empty /// @param text will be used instead of empty
virtual void setPlaceholder(const std::wstring& text); virtual void setPlaceholder(const std::wstring& text);
/// @brief Get textbox hint
virtual const std::wstring& getHint() const;
/// @brief Set textbox hint
/// @param text will be shown instead of empty
virtual void setHint(const std::wstring& text);
/// @brief Get selected text /// @brief Get selected text
virtual std::wstring getSelection() const; virtual std::wstring getSelection() const;

View File

@ -67,7 +67,11 @@ static runnable create_runnable(
return nullptr; return nullptr;
} }
static onaction create_action(UiXmlReader& reader, const xml::xmlelement& element, const std::string& name) { static onaction create_action(
const UiXmlReader& reader,
const xml::xmlelement& element,
const std::string& name
) {
auto callback = create_runnable(reader, element, name); auto callback = create_runnable(reader, element, name);
if (callback == nullptr) { if (callback == nullptr) {
return nullptr; return nullptr;
@ -76,7 +80,9 @@ static onaction create_action(UiXmlReader& reader, const xml::xmlelement& elemen
} }
/* Read basic UINode properties */ /* Read basic UINode properties */
static void _readUINode(UiXmlReader& reader, const xml::xmlelement& element, UINode& node) { static void _readUINode(
const UiXmlReader& reader, const xml::xmlelement& element, UINode& node
) {
if (element->has("id")) { if (element->has("id")) {
node.setId(element->attr("id").getText()); node.setId(element->attr("id").getText());
} }
@ -331,8 +337,11 @@ static std::shared_ptr<UINode> readCheckBox(UiXmlReader& reader, const xml::xmle
static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlelement& element) { static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlelement& element) {
auto placeholder = util::str2wstr_utf8(element->attr("placeholder", "").getText()); auto placeholder = util::str2wstr_utf8(element->attr("placeholder", "").getText());
auto hint = util::str2wstr_utf8(element->attr("hint", "").getText());
auto text = readAndProcessInnerText(element, reader.getContext()); auto text = readAndProcessInnerText(element, reader.getContext());
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f)); auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f));
textbox->setHint(hint);
_readPanel(reader, element, *textbox); _readPanel(reader, element, *textbox);
textbox->setText(text); textbox->setText(text);

View File

@ -242,6 +242,13 @@ static int p_get_placeholder(UINode* node, lua::State* L) {
return 0; return 0;
} }
static int p_get_hint(UINode* node, lua::State* L) {
if (auto box = dynamic_cast<TextBox*>(node)) {
return lua::pushwstring(L, box->getHint());
}
return 0;
}
static int p_get_text(UINode* node, lua::State* L) { static int p_get_text(UINode* node, lua::State* L) {
if (auto button = dynamic_cast<Button*>(node)) { if (auto button = dynamic_cast<Button*>(node)) {
return lua::pushwstring(L, button->getText()); return lua::pushwstring(L, button->getText());
@ -364,6 +371,7 @@ static int l_gui_getattr(lua::State* L) {
{"clear", p_get_clear}, {"clear", p_get_clear},
{"setInterval", p_set_interval}, {"setInterval", p_set_interval},
{"placeholder", p_get_placeholder}, {"placeholder", p_get_placeholder},
{"hint", p_get_hint},
{"valid", p_is_valid}, {"valid", p_is_valid},
{"caret", p_get_caret}, {"caret", p_get_caret},
{"text", p_get_text}, {"text", p_get_text},
@ -430,6 +438,11 @@ static void p_set_placeholder(UINode* node, lua::State* L, int idx) {
box->setPlaceholder(lua::require_wstring(L, idx)); box->setPlaceholder(lua::require_wstring(L, idx));
} }
} }
static void p_set_hint(UINode* node, lua::State* L, int idx) {
if (auto box = dynamic_cast<TextBox*>(node)) {
box->setHint(lua::require_wstring(L, idx));
}
}
static void p_set_text(UINode* node, lua::State* L, int idx) { static void p_set_text(UINode* node, lua::State* L, int idx) {
if (auto label = dynamic_cast<Label*>(node)) { if (auto label = dynamic_cast<Label*>(node)) {
label->setText(lua::require_wstring(L, idx)); label->setText(lua::require_wstring(L, idx));
@ -540,6 +553,7 @@ static int l_gui_setattr(lua::State* L) {
{"visible", p_set_visible}, {"visible", p_set_visible},
{"enabled", p_set_enabled}, {"enabled", p_set_enabled},
{"placeholder", p_set_placeholder}, {"placeholder", p_set_placeholder},
{"hint", p_set_hint},
{"text", p_set_text}, {"text", p_set_text},
{"editable", p_set_editable}, {"editable", p_set_editable},
{"src", p_set_src}, {"src", p_set_src},