textbox onup, ondown callbacks

This commit is contained in:
MihailRis 2024-05-16 13:02:20 +03:00
parent 2bb6ad523e
commit 7be1c3f223
5 changed files with 107 additions and 49 deletions

View File

@ -12,9 +12,12 @@
using namespace gui;
TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
: Panel(glm::vec2(200,32), padding, 0),
input(L""),
placeholder(placeholder) {
: Panel(glm::vec2(200,32), padding, 0),
input(L""),
placeholder(placeholder)
{
setOnUpPressed(nullptr);
setOnDownPressed(nullptr);
label = std::make_shared<Label>(L"");
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
add(label);
@ -374,7 +377,8 @@ void TextBox::resetMaxLocalCaret() {
maxLocalCaret = caret - label->getTextLineOffset(label->getLineByTextIndex(caret));
}
void TextBox::stepLeft(bool shiftPressed, bool breakSelection, uint previousCaret) {
void TextBox::stepLeft(bool shiftPressed, bool breakSelection) {
uint previousCaret = this->caret;
uint caret = breakSelection ? selectionStart : this->caret;
if (caret > 0) {
if (caret > input.length()) {
@ -397,7 +401,8 @@ void TextBox::stepLeft(bool shiftPressed, bool breakSelection, uint previousCare
resetMaxLocalCaret();
}
void TextBox::stepRight(bool shiftPressed, bool breakSelection, uint previousCaret) {
void TextBox::stepRight(bool shiftPressed, bool breakSelection) {
uint previousCaret = this->caret;
uint caret = breakSelection ? selectionEnd : this->caret;
if (caret < input.length()) {
setCaret(caret+1);
@ -417,7 +422,8 @@ void TextBox::stepRight(bool shiftPressed, bool breakSelection, uint previousCar
resetMaxLocalCaret();
}
void TextBox::stepDown(bool shiftPressed, bool breakSelection, uint previousCaret) {
void TextBox::stepDefaultDown(bool shiftPressed, bool breakSelection) {
uint previousCaret = this->caret;
uint caret = breakSelection ? selectionEnd : this->caret;
uint caretLine = label->getLineByTextIndex(caret);
if (caretLine < label->getLinesNumber()-1) {
@ -436,7 +442,8 @@ void TextBox::stepDown(bool shiftPressed, bool breakSelection, uint previousCare
}
}
void TextBox::stepUp(bool shiftPressed, bool breakSelection, uint previousCaret) {
void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) {
uint previousCaret = this->caret;
uint caret = breakSelection ? selectionStart : this->caret;
uint caretLine = label->getLineByTextIndex(caret);
if (caretLine > 0) {
@ -458,7 +465,6 @@ void TextBox::stepUp(bool shiftPressed, bool breakSelection, uint previousCaret)
void TextBox::performEditingKeyboardEvents(keycode key) {
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT);
bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
uint previousCaret = caret;
if (key == keycode::BACKSPACE) {
if (!eraseSelected() && caret > 0 && input.length() > 0) {
if (caret > input.length()) {
@ -485,13 +491,13 @@ void TextBox::performEditingKeyboardEvents(keycode key) {
} else if (key == keycode::TAB) {
paste(L" ");
} else if (key == keycode::LEFT) {
stepLeft(shiftPressed, breakSelection, previousCaret);
stepLeft(shiftPressed, breakSelection);
} else if (key == keycode::RIGHT) {
stepRight(shiftPressed, breakSelection, previousCaret);
} else if (key == keycode::UP) {
stepUp(shiftPressed, breakSelection, previousCaret);
} else if (key == keycode::DOWN) {
stepDown(shiftPressed, breakSelection, previousCaret);
stepRight(shiftPressed, breakSelection);
} else if (key == keycode::UP && onUpPressed) {
onUpPressed();
} else if (key == keycode::DOWN && onDownPressed) {
onDownPressed();
}
}
@ -545,6 +551,30 @@ std::shared_ptr<UINode> TextBox::getAt(glm::vec2 pos, std::shared_ptr<UINode> se
return UINode::getAt(pos, self);
}
void TextBox::setOnUpPressed(runnable callback) {
if (callback == nullptr) {
onUpPressed = [this]() {
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT);
bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
stepDefaultUp(shiftPressed, breakSelection);
};
} else {
onUpPressed = callback;
}
}
void TextBox::setOnDownPressed(runnable callback) {
if (callback == nullptr) {
onDownPressed = [this]() {
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT);
bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
stepDefaultDown(shiftPressed, breakSelection);
};
} else {
onDownPressed = callback;
}
}
void TextBox::setTextSupplier(wstringsupplier supplier) {
this->supplier = supplier;
}

View File

@ -20,6 +20,8 @@ namespace gui {
wstringconsumer consumer = nullptr;
wstringchecker validator = nullptr;
runnable onEditStart = nullptr;
runnable onUpPressed;
runnable onDownPressed;
bool valid = true;
/// @brief text input pointer, value may be greather than text length
uint caret = 0;
@ -39,10 +41,10 @@ namespace gui {
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);
void stepLeft(bool shiftPressed, bool breakSelection);
void stepRight(bool shiftPressed, bool breakSelection);
void stepDefaultDown(bool shiftPressed, bool breakSelection);
void stepDefaultUp(bool shiftPressed, bool breakSelection);
size_t normalizeIndex(int index);
@ -163,6 +165,8 @@ namespace gui {
virtual void typed(unsigned int codepoint) override;
virtual void keyPressed(keycode key) override;
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
virtual void setOnUpPressed(runnable callback);
virtual void setOnDownPressed(runnable callback);
};
}

View File

@ -60,12 +60,12 @@ UINode* UINode::getParent() const {
}
UINode* UINode::listenAction(onaction action) {
actions.push_back(action);
actions.listen(action);
return this;
}
UINode* UINode::listenDoubleClick(onaction action) {
doubleClickCallbacks.push_back(action);
doubleClickCallbacks.listen(action);
return this;
}
@ -76,18 +76,14 @@ void UINode::click(GUI*, int, int) {
void UINode::doubleClick(GUI* gui, int x, int y) {
pressed = true;
if (isInside(glm::vec2(x, y))) {
for (auto callback : doubleClickCallbacks) {
callback(gui);
}
doubleClickCallbacks.notify(gui);
}
}
void UINode::mouseRelease(GUI* gui, int x, int y) {
pressed = false;
if (isInside(glm::vec2(x, y))) {
for (auto callback : actions) {
callback(gui);
}
actions.notify(gui);
}
}

View File

@ -22,6 +22,25 @@ namespace gui {
using onaction = std::function<void(GUI*)>;
using onnumberchange = std::function<void(GUI*, double)>;
class ActionsSet {
std::unique_ptr<std::vector<onaction>> callbacks;
public:
void listen(onaction callback) {
if (callbacks == nullptr) {
callbacks = std::make_unique<std::vector<onaction>>();
}
callbacks->push_back(callback);
}
void notify(GUI* gui) {
if (callbacks) {
for (auto& callback : *callbacks) {
callback(gui);
}
}
}
};
enum class Align {
left, center, right,
top=left, bottom=right,
@ -87,9 +106,9 @@ namespace gui {
/// @brief size supplier for the element (called on parent element size update)
vec2supplier sizefunc = nullptr;
/// @brief 'onclick' callbacks
std::vector<onaction> actions;
ActionsSet actions;
/// @brief 'ondoubleclick' callbacks
std::vector<onaction> doubleClickCallbacks;
ActionsSet doubleClickCallbacks;
UINode(glm::vec2 size);
public:

View File

@ -50,6 +50,26 @@ 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) {
if (element->has(name)) {
std::string text = element->attr(name).getText();
if (!text.empty()) {
return scripting::create_runnable(
reader.getEnvironment(), text, reader.getFilename()
);
}
}
return nullptr;
}
static onaction create_action(UiXmlReader& reader, xml::xmlelement element, const std::string& name) {
auto callback = create_runnable(reader, element, name);
if (callback == nullptr) {
return nullptr;
}
return [callback](GUI*) {callback();};
}
/* Read basic UINode properties */
static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& node) {
if (element->has("id")) {
@ -119,28 +139,12 @@ static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& no
));
}
if (element->has("onclick")) {
std::string text = element->attr("onclick").getText();
if (!text.empty()) {
auto callback = scripting::create_runnable(
reader.getEnvironment(), text, reader.getFilename()
);
node.listenAction([callback](GUI*) {
callback();
});
}
if (auto onclick = create_action(reader, element, "onclick")) {
node.listenAction(onclick);
}
if (element->has("ondoubleclick")) {
std::string text = element->attr("ondoubleclick").getText();
if (!text.empty()) {
auto callback = scripting::create_runnable(
reader.getEnvironment(), text, reader.getFilename()
);
node.listenDoubleClick([callback](GUI*) {
callback();
});
}
if (auto ondoubleclick = create_action(reader, element, "ondoubleclick")) {
node.listenDoubleClick(ondoubleclick);
}
}
@ -336,7 +340,6 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, xml::xmlelement
reader.getFilename()
));
}
if (element->has("supplier")) {
textbox->setTextSupplier(scripting::create_wstring_supplier(
reader.getEnvironment(),
@ -357,6 +360,12 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, xml::xmlelement
reader.getFilename()
));
}
if (auto onUpPressed = create_runnable(reader, element, "onup")) {
textbox->setOnUpPressed(onUpPressed);
}
if (auto onDownPressed = create_runnable(reader, element, "ondown")) {
textbox->setOnDownPressed(onDownPressed);
}
return textbox;
}