GUI now collects events on its own

This commit is contained in:
Yousef Khadadeh 2026-03-04 12:15:24 +03:00
parent a7030059a4
commit 911b7bc91d
10 changed files with 184 additions and 76 deletions

View file

@ -223,6 +223,7 @@ void DrawingProgram::input_key_callback(const InputManager::KeyCallbackArgs& key
break;
}
}
selection.input_key_callback_display_selection(key);
drawTool->input_key_callback(key);
}

View file

@ -356,20 +356,20 @@ void DrawingProgramSelection::update() {
void DrawingProgramSelection::input_key_callback_modify_selection(const InputManager::KeyCallbackArgs& key) {
switch(key.key) {
case InputManager::KEY_TEXT_UP: {
translate_key(InputManager::KEY_TEXT_UP, key.down);
case InputManager::KEY_GENERIC_UP: {
translate_key(InputManager::KEY_GENERIC_UP, key.down);
break;
}
case InputManager::KEY_TEXT_DOWN: {
translate_key(InputManager::KEY_TEXT_DOWN, key.down);
case InputManager::KEY_GENERIC_DOWN: {
translate_key(InputManager::KEY_GENERIC_DOWN, key.down);
break;
}
case InputManager::KEY_TEXT_LEFT: {
translate_key(InputManager::KEY_TEXT_LEFT, key.down);
case InputManager::KEY_GENERIC_LEFT: {
translate_key(InputManager::KEY_GENERIC_LEFT, key.down);
break;
}
case InputManager::KEY_TEXT_RIGHT: {
translate_key(InputManager::KEY_TEXT_RIGHT, key.down);
case InputManager::KEY_GENERIC_RIGHT: {
translate_key(InputManager::KEY_GENERIC_RIGHT, key.down);
break;
}
}
@ -515,16 +515,16 @@ void DrawingProgramSelection::translate_key(unsigned keyPressed, bool pressed) {
constexpr float KEY_TRANSLATE_MAGNITUDE = 5.0f;
Vector2f moveVec;
switch(keyPressed) {
case InputManager::KEY_TEXT_UP:
case InputManager::KEY_GENERIC_UP:
moveVec = {0.0f, -1.0f};
break;
case InputManager::KEY_TEXT_DOWN:
case InputManager::KEY_GENERIC_DOWN:
moveVec = {0.0f, 1.0f};
break;
case InputManager::KEY_TEXT_RIGHT:
case InputManager::KEY_GENERIC_RIGHT:
moveVec = {1.0f, 0.0f};
break;
case InputManager::KEY_TEXT_LEFT:
case InputManager::KEY_GENERIC_LEFT:
moveVec = {-1.0f, 0.0f};
break;
}
@ -542,7 +542,7 @@ void DrawingProgramSelection::translate_key(unsigned keyPressed, bool pressed) {
selectionTransformCoords = CoordSpaceHelperTransform(translateData.startPos);
}
else if(transformOpHappening == TransformOperation::TRANSLATE && translateData.translateWithKeys) {
bool anyKeyHeld = drawP.world.main.input.key(InputManager::KEY_TEXT_LEFT).held || drawP.world.main.input.key(InputManager::KEY_TEXT_RIGHT).held || drawP.world.main.input.key(InputManager::KEY_TEXT_DOWN).held || drawP.world.main.input.key(InputManager::KEY_TEXT_UP).held;
bool anyKeyHeld = drawP.world.main.input.key(InputManager::KEY_GENERIC_LEFT).held || drawP.world.main.input.key(InputManager::KEY_GENERIC_RIGHT).held || drawP.world.main.input.key(InputManager::KEY_GENERIC_DOWN).held || drawP.world.main.input.key(InputManager::KEY_GENERIC_UP).held;
if(!anyKeyHeld) {
commit_transform_selection();
return;

View file

@ -51,7 +51,6 @@ bool LassoSelectTool::right_click_popup_gui(Vector2f popupPos) {
}
void LassoSelectTool::input_key_callback(const InputManager::KeyCallbackArgs& key) {
drawP.selection.input_key_callback_display_selection(key);
drawP.selection.input_key_callback_modify_selection(key);
}

View file

@ -25,7 +25,6 @@ void RectSelectTool::gui_toolbox() {
}
void RectSelectTool::input_key_callback(const InputManager::KeyCallbackArgs& key) {
drawP.selection.input_key_callback_display_selection(key);
drawP.selection.input_key_callback_modify_selection(key);
}

View file

@ -86,14 +86,6 @@ InputManager::InputManager(MainProgram& initMain):
keyAssignments = defaultKeyAssignments;
}
void InputManager::text_input_silence_everything() {
for(auto& p : keys) {
p.pressed = false;
p.repeat = false;
// Not silencing p.held, as that causes double presses on some keyboards
}
}
void InputManager::set_rich_text_box_input_front(const std::shared_ptr<RichText::TextBox>& nTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& nCursor, bool isRichTextBox, const std::optional<RichText::TextStyleModifier::ModifierMap>& nModMap) {
text.set_accepting_input(main.window.sdlWindow, true);
Text::TextBoxInfo textBoxInfo;
@ -741,6 +733,7 @@ void InputManager::backend_key_down_update(const SDL_KeyboardEvent& e) {
text.do_textbox_operation_with_undo([&]() {
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::ENTER, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
});
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_ENTER, .down = e.down, .repeat = e.repeat});
break;
}
case SDLK_TAB: {
@ -752,7 +745,8 @@ void InputManager::backend_key_down_update(const SDL_KeyboardEvent& e) {
break;
}
case SDLK_ESCAPE:
set_key_down(e, KEY_GENERIC_ESCAPE);
set_key_down(e, KEY_TEXT_ESCAPE);
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_ESCAPE, .down = e.down, .repeat = e.repeat});
break;
default:
break;
@ -768,16 +762,28 @@ void InputManager::backend_key_down_update(const SDL_KeyboardEvent& e) {
}
switch(kPress) {
case SDLK_UP:
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_UP, .down = e.down, .repeat = e.repeat});
set_key_down(e, KEY_GENERIC_UP);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_UP, .down = e.down, .repeat = e.repeat});
break;
case SDLK_DOWN:
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_DOWN, .down = e.down, .repeat = e.repeat});
set_key_down(e, KEY_GENERIC_DOWN);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_DOWN, .down = e.down, .repeat = e.repeat});
break;
case SDLK_LEFT:
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_LEFT, .down = e.down, .repeat = e.repeat});
set_key_down(e, KEY_GENERIC_LEFT);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_LEFT, .down = e.down, .repeat = e.repeat});
break;
case SDLK_RIGHT:
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_RIGHT, .down = e.down, .repeat = e.repeat});
set_key_down(e, KEY_GENERIC_RIGHT);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_RIGHT, .down = e.down, .repeat = e.repeat});
break;
case SDLK_RETURN:
set_key_down(e, KEY_GENERIC_ENTER);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_ENTER, .down = e.down, .repeat = e.repeat});
break;
case SDLK_ESCAPE:
set_key_down(e, KEY_GENERIC_ESCAPE);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_ESCAPE, .down = e.down, .repeat = e.repeat});
break;
}
}
@ -873,12 +879,14 @@ void InputManager::backend_key_up_update(const SDL_KeyboardEvent& e) {
break;
case SDLK_RETURN:
set_key_up(e, KEY_TEXT_ENTER);
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_ENTER, .down = e.down, .repeat = e.repeat});
break;
case SDLK_TAB:
set_key_up(e, KEY_TEXT_TAB);
break;
case SDLK_ESCAPE:
set_key_up(e, KEY_GENERIC_ESCAPE);
set_key_up(e, KEY_TEXT_ESCAPE);
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_ESCAPE, .down = e.down, .repeat = e.repeat});
break;
default:
break;
@ -893,16 +901,28 @@ void InputManager::backend_key_up_update(const SDL_KeyboardEvent& e) {
switch(kPress) {
case SDLK_UP:
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_UP, .down = e.down, .repeat = e.repeat});
set_key_up(e, KEY_GENERIC_UP);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_UP, .down = e.down, .repeat = e.repeat});
break;
case SDLK_DOWN:
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_DOWN, .down = e.down, .repeat = e.repeat});
set_key_up(e, KEY_GENERIC_DOWN);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_DOWN, .down = e.down, .repeat = e.repeat});
break;
case SDLK_LEFT:
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_LEFT, .down = e.down, .repeat = e.repeat});
set_key_up(e, KEY_GENERIC_LEFT);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_LEFT, .down = e.down, .repeat = e.repeat});
break;
case SDLK_RIGHT:
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_RIGHT, .down = e.down, .repeat = e.repeat});
set_key_up(e, KEY_GENERIC_RIGHT);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_RIGHT, .down = e.down, .repeat = e.repeat});
break;
case SDLK_RETURN:
set_key_up(e, KEY_GENERIC_ENTER);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_ENTER, .down = e.down, .repeat = e.repeat});
break;
case SDLK_ESCAPE:
set_key_up(e, KEY_GENERIC_ESCAPE);
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_ESCAPE, .down = e.down, .repeat = e.repeat});
break;
}
}

View file

@ -131,8 +131,6 @@ struct InputManager {
int stopKeyInput = 0;
std::optional<Vector2ui32> lastPressedKeybind;
void text_input_silence_everything();
enum KeyCodeEnum : unsigned {
// Assignable
KEY_CAMERA_ROTATE_CLOCKWISE = 0,
@ -189,6 +187,12 @@ struct InputManager {
KEY_TEXT_SELECTALL,
KEY_TEXT_UNDO,
KEY_TEXT_REDO,
KEY_TEXT_ESCAPE,
KEY_GENERIC_UP,
KEY_GENERIC_DOWN,
KEY_GENERIC_LEFT,
KEY_GENERIC_RIGHT,
KEY_GENERIC_ENTER,
KEY_GENERIC_ESCAPE,
KEY_GENERIC_LSHIFT,
KEY_GENERIC_LALT,

View file

@ -92,8 +92,6 @@ void MainProgram::update() {
deltaTime.update_time_since();
deltaTime.update_time_point();
toolbar.initialize_io_before_update();
for(auto& w : worlds) {
if(w == world)
w->focus_update();
@ -103,7 +101,6 @@ void MainProgram::update() {
toolbar.update(); // GUI should be setup after the world data has been fully updated for this frame, so that the GUI reflects the current state of the world data
NetLibrary::update();
if(tabSetToOpen) {
@ -328,21 +325,25 @@ void MainProgram::input_key_callback(const InputManager::KeyCallbackArgs& key) {
drawGui = !drawGui;
}
}
toolbar.input_key_callback(key);
if(world)
world->input_key_callback(key);
}
void MainProgram::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
toolbar.input_mouse_button_callback(button);
if(world)
world->input_mouse_button_callback(button);
}
void MainProgram::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
toolbar.input_mouse_motion_callback(motion);
if(world)
world->input_mouse_motion_callback(motion);
}
void MainProgram::input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) {
toolbar.input_mouse_wheel_callback(wheel);
if(world)
world->input_mouse_wheel_callback(wheel);
}

View file

@ -393,17 +393,6 @@ void Toolbar::update() {
update_notification_check();
#endif
if(main.input.key(InputManager::KEY_SAVE).pressed && !optionsMenuOpen && !filePicker.isOpen)
save_func();
if(main.input.key(InputManager::KEY_SAVE_AS).pressed && !optionsMenuOpen && !filePicker.isOpen)
save_as_func();
if(main.input.key(InputManager::KEY_SHOW_METRICS).pressed)
showPerformance = !showPerformance;
if(main.input.key(InputManager::KEY_OPEN_CHAT).pressed && chatBoxState == CHATBOXSTATE_CLOSE)
chatBoxState = CHATBOXSTATE_JUSTOPEN;
if(main.input.key(InputManager::KEY_SHOW_PLAYER_LIST).pressed)
playerMenuOpen = !playerMenuOpen;
start_gui();
if(main.drawGui) {
@ -2259,30 +2248,126 @@ void Toolbar::file_picker_gui() {
}
void Toolbar::initialize_io_before_update() {
io->mouse.leftClick = main.input.mouse.leftClicks;
io->mouse.rightClick = main.input.mouse.rightClicks;
io->mouse.leftHeld = main.input.mouse.leftDown;
io->mouse.rightHeld = main.input.mouse.rightDown;
io->mouse.globalPos = main.input.mouse.pos / final_gui_scale();
io->mouse.scroll = main.input.mouse.scrollAmount;
void Toolbar::initialize_io() {
io->deltaTime = main.deltaTime;
io->key.left = main.input.key(InputManager::KEY_TEXT_LEFT).repeat;
io->key.right = main.input.key(InputManager::KEY_TEXT_RIGHT).repeat;
io->key.up = main.input.key(InputManager::KEY_TEXT_UP).repeat;
io->key.down = main.input.key(InputManager::KEY_TEXT_DOWN).repeat;
io->key.leftShift = main.input.key(InputManager::KEY_TEXT_SHIFT).held;
io->key.leftCtrl = main.input.key(InputManager::KEY_TEXT_CTRL).held;
io->key.enter = main.input.key(InputManager::KEY_TEXT_ENTER).repeat;
io->key.escape = main.input.key(InputManager::KEY_GENERIC_ESCAPE).repeat;
io->previousRichTextBoxToEdit = io->richTextBoxToEdit;
io->richTextBoxToEditCursor = nullptr;
io->richTextBoxToEdit = nullptr;
}
if(io->acceptingTextInput)
main.input.text_input_silence_everything();
io->acceptingTextInput = false;
void Toolbar::end_io() {
if(io->clipboard.textOut)
main.input.set_clipboard_str(*io->clipboard.textOut);
if(io->richTextBoxToEdit != io->previousRichTextBoxToEdit) {
if(io->richTextBoxToEdit)
main.input.set_rich_text_box_input_front(io->richTextBoxToEdit, io->richTextBoxToEditCursor, false);
if(io->previousRichTextBoxToEdit)
main.input.remove_rich_text_box_input(io->previousRichTextBoxToEdit);
}
io->key.left = false;
io->key.right = false;
io->key.up = false;
io->key.down = false;
io->key.enter = false;
io->key.escape = false;
io->mouse.leftClick = 0;
io->mouse.rightClick = 0;
io->mouse.scroll = {0, 0};
}
void Toolbar::input_key_callback(const InputManager::KeyCallbackArgs& key) {
if(key.down) {
switch(key.key) {
case InputManager::KEY_TEXT_LEFT: {
io->key.left = true;
break;
}
case InputManager::KEY_TEXT_RIGHT: {
io->key.right = true;
break;
}
case InputManager::KEY_TEXT_UP: {
io->key.up = true;
break;
}
case InputManager::KEY_TEXT_DOWN: {
io->key.down = true;
break;
}
case InputManager::KEY_TEXT_ENTER: {
io->key.enter = true;
break;
}
case InputManager::KEY_TEXT_ESCAPE: {
io->key.escape = true;
break;
}
case InputManager::KEY_SAVE: {
save_func();
break;
}
case InputManager::KEY_SAVE_AS: {
save_as_func();
break;
}
case InputManager::KEY_SHOW_METRICS: {
showPerformance = !showPerformance;
break;
}
case InputManager::KEY_OPEN_CHAT: {
if(chatBoxState == CHATBOXSTATE_CLOSE)
chatBoxState = CHATBOXSTATE_JUSTOPEN;
break;
}
case InputManager::KEY_SHOW_PLAYER_LIST: {
playerMenuOpen = !playerMenuOpen;
break;
}
}
}
}
void Toolbar::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
if(button.down) {
switch(button.button) {
case InputManager::MouseButton::LEFT: {
io->mouse.leftClick = std::max<int>(io->mouse.leftClick, button.clicks);
io->mouse.leftHeld = true;
break;
}
case InputManager::MouseButton::RIGHT: {
io->mouse.rightClick = std::max<int>(io->mouse.rightClick, button.clicks);
io->mouse.rightHeld = true;
break;
}
default:
break;
}
}
else {
switch(button.button) {
case InputManager::MouseButton::LEFT: {
io->mouse.leftHeld = false;
break;
}
case InputManager::MouseButton::RIGHT: {
io->mouse.rightHeld = false;
break;
}
default:
break;
}
}
}
void Toolbar::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
io->mouse.globalPos = motion.pos / final_gui_scale();
}
void Toolbar::input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) {
io->mouse.scroll = wheel.amount;
}
void Toolbar::start_gui() {
@ -2295,6 +2380,7 @@ void Toolbar::start_gui() {
gui.windowPos = Vector2f{0.0f, 0.0f};
gui.windowSize = main.window.size.cast<float>() / final_gui_scale();
}
initialize_io();
gui.io = io;
io->hoverObstructed = false;
io->hoverObstructingAABBs.clear();
@ -2328,14 +2414,7 @@ float Toolbar::final_gui_scale_not_fit() {
void Toolbar::end_gui() {
gui.end();
if(io->clipboard.textOut)
main.input.set_clipboard_str(*io->clipboard.textOut);
if(io->richTextBoxToEdit != io->previousRichTextBoxToEdit) {
if(io->richTextBoxToEdit)
main.input.set_rich_text_box_input_front(io->richTextBoxToEdit, io->richTextBoxToEditCursor, false);
if(io->previousRichTextBoxToEdit)
main.input.remove_rich_text_box_input(io->previousRichTextBoxToEdit);
}
end_io();
}
void Toolbar::draw(SkCanvas* canvas) {

View file

@ -40,7 +40,10 @@ class Toolbar {
std::string chatMessageInput;
Toolbar(MainProgram& initMain);
void initialize_io_before_update();
void input_key_callback(const InputManager::KeyCallbackArgs& key);
void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button);
void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion);
void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel);
void update();
void draw(SkCanvas* canvas);
void color_selector_left(Vector4f* color);
@ -94,6 +97,8 @@ class Toolbar {
bool app_close_requested();
private:
void end_io();
void initialize_io();
void calculate_final_gui_scale();
float final_gui_scale_not_fit();

View file

@ -210,7 +210,7 @@ void initialize_sdl(MainStruct& mS, int wWidth, int wHeight) {
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, "#canvas"); // Ensures that SDL only grabs input when browser is focused on canvas
if(!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD))
if(!SDL_Init(SDL_INIT_VIDEO))
throw std::runtime_error("[SDL_Init] " + std::string(SDL_GetError()));
Uint32 window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY;