Rewrote how input text box focus is decided

This commit is contained in:
Yousef Khadadeh 2026-05-07 21:48:47 +03:00
parent 1585e0aa67
commit 8b3e321ab5
41 changed files with 317 additions and 490 deletions

View file

@ -21,6 +21,7 @@ namespace GUIStuff {
input_mouse_motion_callback(InputManager::convert_finger_motion_to_mouse_motion(motion));
}
void Element::input_key_callback(const InputManager::KeyCallbackArgs& key) {}
std::optional<InputManager::TextBoxStartInfo> Element::get_text_box_start_info() { return std::nullopt; }
void Element::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {}

View file

@ -35,6 +35,7 @@ namespace GUIStuff {
virtual void input_finger_touch_callback(const InputManager::FingerTouchCallbackArgs& touch);
virtual void input_finger_motion_callback(const InputManager::FingerMotionCallbackArgs& motion);
virtual void input_key_callback(const InputManager::KeyCallbackArgs& key);
virtual std::optional<InputManager::TextBoxStartInfo> get_text_box_start_info();
protected:
static SCollision::AABB<float> get_bb_from_command(Clay_RenderCommand* command);
std::optional<SCollision::AABB<float>> boundingBox;

View file

@ -23,16 +23,6 @@ template <typename T> struct TextBoxData {
std::function<void()> onDeselect;
};
struct TextEditData {
TextEditData(unsigned initTextboxInputID, const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor):
textboxInputID(initTextboxInputID),
userInput(initTextBox, initCursor, nullptr)
{}
unsigned textboxInputID;
RichTextUserInput userInput;
};
template <typename T> class TextBox : public Element {
public:
TextBox(GUIManager& gui);
@ -47,6 +37,7 @@ template <typename T> class TextBox : public Element {
virtual void input_text_callback(const InputManager::TextCallbackArgs& text) override;
virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override;
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override;
virtual std::optional<InputManager::TextBoxStartInfo> get_text_box_start_info() override;
~TextBox();
private:
void populate_empty_textbox();
@ -64,7 +55,8 @@ template <typename T> class TextBox : public Element {
bool isEmptyText = false;
bool isHeld = false;
std::optional<TextEditData> edit;
std::unique_ptr<RichTextUserInput> edit;
std::optional<T> oldData;
std::string oldEmptyText;

View file

@ -1,5 +1,6 @@
#include "TextBox.decl.hpp"
#include "../GUIManager.hpp"
#include <SDL3/SDL_keyboard.h>
namespace GUIStuff {
@ -15,6 +16,11 @@ template <typename T> void TextBox<T>::layout(const Clay_ElementId& id, const Te
gui.invalidate_draw_element(this);
}
if(edit) {
SCollision::AABB<float> rect = {boundingBox.value().min * gui.io.guiScaleMultiplier, boundingBox.value().max * gui.io.guiScaleMultiplier};
gui.io.input->update_textbox_rectangle(edit->id, rect);
}
CLAY(id, {
.layout = {
.sizing = {.width = CLAY_SIZING_GROW(static_cast<float>(io.fontSize * 2)), .height = CLAY_SIZING_FIXED(static_cast<float>(io.fontSize * 1.25f))}
@ -32,10 +38,6 @@ template <typename T> void TextBox<T>::update() {
oldDD.cur = *cur;
gui.invalidate_draw_element(this);
}
if(edit.has_value()) {
SCollision::AABB<float> rect = {boundingBox.value().min * gui.io.guiScaleMultiplier, boundingBox.value().max * gui.io.guiScaleMultiplier};
gui.io.input->update_textbox_rectangle(edit.value().textboxInputID, rect);
}
}
template <typename T> void TextBox<T>::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {
@ -80,30 +82,29 @@ template <typename T> void TextBox<T>::clay_draw(SkCanvas* canvas, UpdateInputDa
template <typename T> void TextBox<T>::select() {
if(!is_selected()) {
SCollision::AABB<float> rect = {boundingBox.value().min * gui.io.guiScaleMultiplier, boundingBox.value().max * gui.io.guiScaleMultiplier};
unsigned id = gui.io.input->set_text_box_front(rect, userInfo.textInputProps);
if(isEmptyText)
textbox->clear_text();
edit = TextEditData(id, textbox, cur);
edit = std::make_unique<RichTextUserInput>(gui.io.input->text_box_get_new_id(), textbox, cur, nullptr);
CustomEvents::emit_event(CustomEvents::RefreshTextBoxInputEvent{});
}
}
template <typename T> void TextBox<T>::deselect() {
if(is_selected()) {
gui.io.input->remove_text_box(edit.value().textboxInputID);
edit = nullptr;
if(userInfo.onDeselect) userInfo.onDeselect();
CustomEvents::emit_event(CustomEvents::RefreshTextBoxInputEvent{});
reset_textbox_text();
edit = std::nullopt;
populate_empty_textbox();
}
}
template <typename T> bool TextBox<T>::is_selected() const {
return edit.has_value();
return edit != nullptr;
}
template <typename T> void TextBox<T>::input_paste_callback(const CustomEvents::PasteEvent& paste) {
if(is_selected() && edit.value().userInput.input_paste_callback(paste))
if(is_selected() && edit->input_paste_callback(paste))
after_text_input_callback();
}
@ -118,7 +119,7 @@ template <typename T> void TextBox<T>::input_text_key_callback(const InputManage
});
}
else {
if(edit.value().userInput.input_key_callback(*gui.io.input, key).textEdited)
if(edit->input_key_callback(*gui.io.input, key).textEdited)
after_text_input_callback();
}
}
@ -150,7 +151,7 @@ template <typename T> void TextBox<T>::after_text_input_callback() {
template <typename T> void TextBox<T>::input_text_callback(const InputManager::TextCallbackArgs& text) {
if(is_selected()) {
edit.value().userInput.add_text_to_textbox(text.str);
edit->add_text_to_textbox(text.str);
after_text_input_callback();
}
}
@ -181,6 +182,18 @@ template <typename T> void TextBox<T>::input_mouse_motion_callback(const InputMa
textbox->process_mouse_left_button(*cur, motion.pos - boundingBox.value().min, 0, isHeld, gui.io.input->key(InputManager::KEY_GENERIC_LSHIFT).held);
}
template <typename T> std::optional<InputManager::TextBoxStartInfo> TextBox<T>::get_text_box_start_info() {
if(edit) {
SCollision::AABB<float> rect = {boundingBox.value().min * gui.io.guiScaleMultiplier, boundingBox.value().max * gui.io.guiScaleMultiplier};
return InputManager::TextBoxStartInfo{
.id = edit->id,
.rect = rect,
.inputProperties = userInfo.textInputProps
};
}
return std::nullopt;
}
template <typename T> void TextBox<T>::init_textbox(UpdateInputData& io) {
if(!textbox) {
textbox = std::make_shared<RichText::TextBox>();
@ -212,7 +225,7 @@ template <typename T> bool TextBox<T>::update_data() {
template <typename T> TextBox<T>::~TextBox() {
if(is_selected())
gui.io.input->remove_text_box(edit.value().textboxInputID);
CustomEvents::emit_event(CustomEvents::RefreshTextBoxInputEvent{});
}
}