textbox onup, ondown callbacks
This commit is contained in:
parent
2bb6ad523e
commit
7be1c3f223
@ -12,9 +12,12 @@
|
|||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
|
TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
|
||||||
: Panel(glm::vec2(200,32), padding, 0),
|
: Panel(glm::vec2(200,32), padding, 0),
|
||||||
input(L""),
|
input(L""),
|
||||||
placeholder(placeholder) {
|
placeholder(placeholder)
|
||||||
|
{
|
||||||
|
setOnUpPressed(nullptr);
|
||||||
|
setOnDownPressed(nullptr);
|
||||||
label = std::make_shared<Label>(L"");
|
label = std::make_shared<Label>(L"");
|
||||||
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
label->setSize(size-glm::vec2(padding.z+padding.x, padding.w+padding.y));
|
||||||
add(label);
|
add(label);
|
||||||
@ -374,7 +377,8 @@ void TextBox::resetMaxLocalCaret() {
|
|||||||
maxLocalCaret = caret - label->getTextLineOffset(label->getLineByTextIndex(caret));
|
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;
|
uint caret = breakSelection ? selectionStart : this->caret;
|
||||||
if (caret > 0) {
|
if (caret > 0) {
|
||||||
if (caret > input.length()) {
|
if (caret > input.length()) {
|
||||||
@ -397,7 +401,8 @@ void TextBox::stepLeft(bool shiftPressed, bool breakSelection, uint previousCare
|
|||||||
resetMaxLocalCaret();
|
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;
|
uint caret = breakSelection ? selectionEnd : this->caret;
|
||||||
if (caret < input.length()) {
|
if (caret < input.length()) {
|
||||||
setCaret(caret+1);
|
setCaret(caret+1);
|
||||||
@ -417,7 +422,8 @@ void TextBox::stepRight(bool shiftPressed, bool breakSelection, uint previousCar
|
|||||||
resetMaxLocalCaret();
|
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 caret = breakSelection ? selectionEnd : this->caret;
|
||||||
uint caretLine = label->getLineByTextIndex(caret);
|
uint caretLine = label->getLineByTextIndex(caret);
|
||||||
if (caretLine < label->getLinesNumber()-1) {
|
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 caret = breakSelection ? selectionStart : this->caret;
|
||||||
uint caretLine = label->getLineByTextIndex(caret);
|
uint caretLine = label->getLineByTextIndex(caret);
|
||||||
if (caretLine > 0) {
|
if (caretLine > 0) {
|
||||||
@ -458,7 +465,6 @@ void TextBox::stepUp(bool shiftPressed, bool breakSelection, uint previousCaret)
|
|||||||
void TextBox::performEditingKeyboardEvents(keycode key) {
|
void TextBox::performEditingKeyboardEvents(keycode key) {
|
||||||
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT);
|
bool shiftPressed = Events::pressed(keycode::LEFT_SHIFT);
|
||||||
bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
|
bool breakSelection = getSelectionLength() != 0 && !shiftPressed;
|
||||||
uint previousCaret = caret;
|
|
||||||
if (key == keycode::BACKSPACE) {
|
if (key == keycode::BACKSPACE) {
|
||||||
if (!eraseSelected() && caret > 0 && input.length() > 0) {
|
if (!eraseSelected() && caret > 0 && input.length() > 0) {
|
||||||
if (caret > input.length()) {
|
if (caret > input.length()) {
|
||||||
@ -485,13 +491,13 @@ void TextBox::performEditingKeyboardEvents(keycode key) {
|
|||||||
} else if (key == keycode::TAB) {
|
} else if (key == keycode::TAB) {
|
||||||
paste(L" ");
|
paste(L" ");
|
||||||
} else if (key == keycode::LEFT) {
|
} else if (key == keycode::LEFT) {
|
||||||
stepLeft(shiftPressed, breakSelection, previousCaret);
|
stepLeft(shiftPressed, breakSelection);
|
||||||
} else if (key == keycode::RIGHT) {
|
} else if (key == keycode::RIGHT) {
|
||||||
stepRight(shiftPressed, breakSelection, previousCaret);
|
stepRight(shiftPressed, breakSelection);
|
||||||
} else if (key == keycode::UP) {
|
} else if (key == keycode::UP && onUpPressed) {
|
||||||
stepUp(shiftPressed, breakSelection, previousCaret);
|
onUpPressed();
|
||||||
} else if (key == keycode::DOWN) {
|
} else if (key == keycode::DOWN && onDownPressed) {
|
||||||
stepDown(shiftPressed, breakSelection, previousCaret);
|
onDownPressed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,6 +551,30 @@ std::shared_ptr<UINode> TextBox::getAt(glm::vec2 pos, std::shared_ptr<UINode> se
|
|||||||
return UINode::getAt(pos, self);
|
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) {
|
void TextBox::setTextSupplier(wstringsupplier supplier) {
|
||||||
this->supplier = supplier;
|
this->supplier = supplier;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,8 @@ namespace gui {
|
|||||||
wstringconsumer consumer = nullptr;
|
wstringconsumer consumer = nullptr;
|
||||||
wstringchecker validator = nullptr;
|
wstringchecker validator = nullptr;
|
||||||
runnable onEditStart = nullptr;
|
runnable onEditStart = nullptr;
|
||||||
|
runnable onUpPressed;
|
||||||
|
runnable onDownPressed;
|
||||||
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
|
||||||
uint caret = 0;
|
uint caret = 0;
|
||||||
@ -39,10 +41,10 @@ namespace gui {
|
|||||||
bool editable = true;
|
bool editable = true;
|
||||||
bool autoresize = false;
|
bool autoresize = false;
|
||||||
|
|
||||||
void stepLeft(bool shiftPressed, bool breakSelection, uint previousCaret);
|
void stepLeft(bool shiftPressed, bool breakSelection);
|
||||||
void stepRight(bool shiftPressed, bool breakSelection, uint previousCaret);
|
void stepRight(bool shiftPressed, bool breakSelection);
|
||||||
void stepDown(bool shiftPressed, bool breakSelection, uint previousCaret);
|
void stepDefaultDown(bool shiftPressed, bool breakSelection);
|
||||||
void stepUp(bool shiftPressed, bool breakSelection, uint previousCaret);
|
void stepDefaultUp(bool shiftPressed, bool breakSelection);
|
||||||
|
|
||||||
size_t normalizeIndex(int index);
|
size_t normalizeIndex(int index);
|
||||||
|
|
||||||
@ -163,6 +165,8 @@ namespace gui {
|
|||||||
virtual void typed(unsigned int codepoint) override;
|
virtual void typed(unsigned int codepoint) override;
|
||||||
virtual void keyPressed(keycode key) override;
|
virtual void keyPressed(keycode key) override;
|
||||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) 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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,12 +60,12 @@ UINode* UINode::getParent() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UINode* UINode::listenAction(onaction action) {
|
UINode* UINode::listenAction(onaction action) {
|
||||||
actions.push_back(action);
|
actions.listen(action);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINode* UINode::listenDoubleClick(onaction action) {
|
UINode* UINode::listenDoubleClick(onaction action) {
|
||||||
doubleClickCallbacks.push_back(action);
|
doubleClickCallbacks.listen(action);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,18 +76,14 @@ void UINode::click(GUI*, int, int) {
|
|||||||
void UINode::doubleClick(GUI* gui, int x, int y) {
|
void UINode::doubleClick(GUI* gui, int x, int y) {
|
||||||
pressed = true;
|
pressed = true;
|
||||||
if (isInside(glm::vec2(x, y))) {
|
if (isInside(glm::vec2(x, y))) {
|
||||||
for (auto callback : doubleClickCallbacks) {
|
doubleClickCallbacks.notify(gui);
|
||||||
callback(gui);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UINode::mouseRelease(GUI* gui, int x, int y) {
|
void UINode::mouseRelease(GUI* gui, int x, int y) {
|
||||||
pressed = false;
|
pressed = false;
|
||||||
if (isInside(glm::vec2(x, y))) {
|
if (isInside(glm::vec2(x, y))) {
|
||||||
for (auto callback : actions) {
|
actions.notify(gui);
|
||||||
callback(gui);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,25 @@ namespace gui {
|
|||||||
|
|
||||||
using onaction = std::function<void(GUI*)>;
|
using onaction = std::function<void(GUI*)>;
|
||||||
using onnumberchange = std::function<void(GUI*, double)>;
|
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 {
|
enum class Align {
|
||||||
left, center, right,
|
left, center, right,
|
||||||
@ -87,9 +106,9 @@ namespace gui {
|
|||||||
/// @brief size supplier for the element (called on parent element size update)
|
/// @brief size supplier for the element (called on parent element size update)
|
||||||
vec2supplier sizefunc = nullptr;
|
vec2supplier sizefunc = nullptr;
|
||||||
/// @brief 'onclick' callbacks
|
/// @brief 'onclick' callbacks
|
||||||
std::vector<onaction> actions;
|
ActionsSet actions;
|
||||||
/// @brief 'ondoubleclick' callbacks
|
/// @brief 'ondoubleclick' callbacks
|
||||||
std::vector<onaction> doubleClickCallbacks;
|
ActionsSet doubleClickCallbacks;
|
||||||
|
|
||||||
UINode(glm::vec2 size);
|
UINode(glm::vec2 size);
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -50,6 +50,26 @@ static Gravity gravity_from_string(const std::string& str) {
|
|||||||
return Gravity::none;
|
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 */
|
/* Read basic UINode properties */
|
||||||
static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& node) {
|
static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& node) {
|
||||||
if (element->has("id")) {
|
if (element->has("id")) {
|
||||||
@ -119,28 +139,12 @@ static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& no
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element->has("onclick")) {
|
if (auto onclick = create_action(reader, element, "onclick")) {
|
||||||
std::string text = element->attr("onclick").getText();
|
node.listenAction(onclick);
|
||||||
if (!text.empty()) {
|
|
||||||
auto callback = scripting::create_runnable(
|
|
||||||
reader.getEnvironment(), text, reader.getFilename()
|
|
||||||
);
|
|
||||||
node.listenAction([callback](GUI*) {
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element->has("ondoubleclick")) {
|
if (auto ondoubleclick = create_action(reader, element, "ondoubleclick")) {
|
||||||
std::string text = element->attr("ondoubleclick").getText();
|
node.listenDoubleClick(ondoubleclick);
|
||||||
if (!text.empty()) {
|
|
||||||
auto callback = scripting::create_runnable(
|
|
||||||
reader.getEnvironment(), text, reader.getFilename()
|
|
||||||
);
|
|
||||||
node.listenDoubleClick([callback](GUI*) {
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +340,6 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, xml::xmlelement
|
|||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element->has("supplier")) {
|
if (element->has("supplier")) {
|
||||||
textbox->setTextSupplier(scripting::create_wstring_supplier(
|
textbox->setTextSupplier(scripting::create_wstring_supplier(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
@ -357,6 +360,12 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, xml::xmlelement
|
|||||||
reader.getFilename()
|
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;
|
return textbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user