Started work on mouse callbacks

This commit is contained in:
Yousef Khadadeh 2026-03-01 17:28:43 +03:00
parent e1e93b8a31
commit 109fd96b67
10 changed files with 144 additions and 55 deletions

View file

@ -116,11 +116,30 @@ void DrawingProgram::register_callbacks() {
tempMoveToolSwitch = TemporaryMoveToolSwitch::NONE;
}
});
selection.register_key_callbacks();
mouseButtonCallback = world.main.input.mouseButtonCallbacks.register_callback([&](const InputManager::MouseButtonCallbackArgs& button) {
bool isHoveringOverCanvas = world.main.toolbar.check_if_position_isnt_obstructed(button.pos);
if(isHoveringOverCanvas) {
if(button.button == InputManager::MouseButtonCallbackArgs::Button::RIGHT) {
if(button.down) {
if(world.main.toolbar.rightClickPopupLocation)
world.main.toolbar.rightClickPopupLocation = std::nullopt;
else
world.main.toolbar.rightClickPopupLocation = world.main.input.mouse.pos / world.main.toolbar.final_gui_scale();
}
}
else {
if(button.down)
world.main.toolbar.rightClickPopupLocation = std::nullopt;
mouseButtonOnCanvasCallbacks.run_callbacks(button);
}
}
});
selection.register_callbacks();
}
void DrawingProgram::deregister_callbacks() {
tempMoveToolSwitch = TemporaryMoveToolSwitch::NONE;
world.main.input.mouseButtonCallbacks.deregister_callback(mouseButtonCallback);
selection.deselect_all();
}
@ -320,21 +339,12 @@ void DrawingProgram::modify_grid(const NetworkingObjects::NetObjWeakPtr<WorldGri
void DrawingProgram::update() {
tool_temporary_switch_update();
{
controls.cursorHoveringOverCanvas = true;
Vector2f mousePosGUI = world.main.input.mouse.pos / world.main.toolbar.final_gui_scale();
for(auto& aabb : world.main.toolbar.io->hoverObstructingAABBs)
controls.cursorHoveringOverCanvas &= !SCollision::collide(mousePosGUI, aabb);
for(auto& circle : world.main.toolbar.io->hoverObstructingCircles)
controls.cursorHoveringOverCanvas &= !SCollision::collide(mousePosGUI, circle);
}
controls.cursorHoveringOverCanvas = world.main.toolbar.check_if_position_isnt_obstructed(world.main.input.mouse.pos);
controls.middleClick = controls.cursorHoveringOverCanvas && (world.main.input.mouse.middleClicks || world.main.input.pen.buttons[world.main.toolbar.tabletOptions.middleClickButton].pressed);
bool middleHeld = world.main.input.mouse.middleDown || world.main.input.pen.buttons[world.main.toolbar.tabletOptions.middleClickButton].held;
if(controls.middleClick) {
if(controls.middleClick)
controls.middleClickHeld = true;
world.main.toolbar.rightClickPopupLocation = std::nullopt;
}
if(controls.middleClickHeld && !middleHeld) {
controls.middleClick = false;
controls.middleClickHeld = false;
@ -343,23 +353,14 @@ void DrawingProgram::update() {
// Left click will be ignored if middle click is held (and left click held state will be gone once middle click is pressed)
controls.leftClick = controls.cursorHoveringOverCanvas && world.main.input.mouse.leftClicks && !controls.middleClickHeld;
if(controls.leftClick) {
if(controls.leftClick)
controls.leftClickHeld = true;
world.main.toolbar.rightClickPopupLocation = std::nullopt;
}
if(controls.leftClickHeld && (!world.main.input.mouse.leftDown || controls.middleClickHeld)) {
controls.leftClick = false;
controls.leftClickHeld = false;
controls.leftClickReleased = true;
}
if(controls.cursorHoveringOverCanvas && (world.main.input.mouse.rightClicks || world.main.input.pen.buttons[world.main.toolbar.tabletOptions.rightClickButton].pressed)) {
if(world.main.toolbar.rightClickPopupLocation)
world.main.toolbar.rightClickPopupLocation = std::nullopt;
else
world.main.toolbar.rightClickPopupLocation = world.main.input.mouse.pos / world.main.toolbar.final_gui_scale();
}
controls.previousMouseWorldPos = controls.currentMouseWorldPos;
controls.currentMouseWorldPos = world.get_mouse_world_pos();

View file

@ -59,7 +59,9 @@ class DrawingProgram {
void register_callbacks();
void deregister_callbacks();
typedef CallbackManager<InputManager::MouseButtonCallbackArgs> MouseButtonOnCanvasCallbackManager;
MouseButtonOnCanvasCallbackManager mouseButtonOnCanvasCallbacks;
private:
void process_transform_message(const std::vector<std::pair<NetworkingObjects::NetObjID, CoordSpaceHelper>>& transforms);
@ -68,7 +70,6 @@ class DrawingProgram {
void check_updateable_components();
void update_downloading_dropped_files();
bool selection_action_menu(Vector2f popupPos);
void rebuild_cache();
@ -96,6 +97,8 @@ class DrawingProgram {
TemporaryMoveToolSwitch tempMoveToolSwitch = TemporaryMoveToolSwitch::NONE;
DrawingProgramToolType toolTypeAfterTempMove;
InputManager::MouseButtonCallbackManager::Callback* mouseButtonCallback;
struct GlobalControls {
std::optional<WorldScalar> lockedCameraScale;

View file

@ -442,7 +442,7 @@ void DrawingProgramSelection::update() {
}
}
void DrawingProgramSelection::register_key_callbacks() {
void DrawingProgramSelection::register_callbacks() {
auto& keyCallbacks = drawP.world.keyCallbacks;
keyCallbacks[InputManager::KEY_DRAW_DELETE] = drawP.world.main.input.keyCallbacks[InputManager::KEY_DRAW_DELETE].register_callback([&](auto& key) {
if(key.down && !key.repeat)

View file

@ -28,7 +28,7 @@ class DrawingProgramSelection {
void delete_all();
void selection_to_clipboard();
CanvasComponentContainer::ObjInfo* get_front_object_colliding_with_in_editing_layer(const SCollision::ColliderCollection<float>& cC);
void register_key_callbacks();
void register_callbacks();
private:
void translate_key(unsigned keyPressed, bool pressed);
bool mouse_collided_with_selection_aabb();

View file

@ -23,10 +23,12 @@ extern "C" {
return isAcceptingInputEmscripten;
}
}
#endif
InputManager::InputManager() {
#include "MainProgram.hpp"
InputManager::InputManager(MainProgram& initMain):
main(initMain) {
frame_reset({0, 0});
defaultKeyAssignments[{0, SDLK_W}] = KEY_CAMERA_ROTATE_COUNTERCLOCKWISE;
@ -92,7 +94,7 @@ void InputManager::text_input_silence_everything() {
}
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(sdlWindow, true);
text.set_accepting_input(main.window.sdlWindow, true);
Text::TextBoxInfo textBoxInfo;
textBoxInfo.textBox = nTextBox;
textBoxInfo.cursor = nCursor;
@ -102,7 +104,7 @@ void InputManager::set_rich_text_box_input_front(const std::shared_ptr<RichText:
}
void InputManager::set_rich_text_box_input_back(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(sdlWindow, true);
text.set_accepting_input(main.window.sdlWindow, true);
Text::TextBoxInfo textBoxInfo;
textBoxInfo.textBox = nTextBox;
textBoxInfo.cursor = nCursor;
@ -116,7 +118,7 @@ void InputManager::remove_rich_text_box_input(const std::shared_ptr<RichText::Te
return (info.textBox == nTextBox);
});
if(text.textBoxes.empty())
text.set_accepting_input(sdlWindow, false);
text.set_accepting_input(main.window.sdlWindow, false);
}
void InputManager::Text::add_text_to_textbox(const std::string& inputText) {
@ -374,6 +376,62 @@ uint32_t InputManager::make_generic_key_mod(SDL_Keymod m) {
return toRet;
}
void InputManager::backend_mouse_button_up_update(const SDL_MouseButtonEvent& e) {
Vector2f mousePos = {e.x * main.window.density, e.y * main.window.density};
if(e.button == 1)
mouse.leftDown = false;
else if(e.button == 2)
mouse.middleDown = false;
else if(e.button == 3)
mouse.rightDown = false;
mouseButtonCallbacks.run_callbacks({
.button = static_cast<MouseButtonCallbackArgs::Button>(e.button),
.down = e.down,
.clicks = e.clicks,
.pos = mousePos
});
}
void InputManager::backend_mouse_button_down_update(const SDL_MouseButtonEvent& e) {
Vector2f mousePos = {e.x * main.window.density, e.y * main.window.density};
if(e.button == 1) {
mouse.leftDown = true;
mouse.leftClicks = e.clicks;
}
else if(e.button == 2) {
mouse.middleDown = true;
mouse.middleClicks = e.clicks;
}
else if(e.button == 3) {
mouse.rightDown = true;
mouse.rightClicks = e.clicks;
}
mouseButtonCallbacks.run_callbacks({
.button = static_cast<MouseButtonCallbackArgs::Button>(e.button),
.down = e.down,
.clicks = e.clicks,
.pos = mousePos
});
}
void InputManager::backend_mouse_motion_update(const SDL_MouseMotionEvent& e) {
Vector2f mouseNewPos = {e.x * main.window.density, e.y * main.window.density};
Vector2f mouseRel = {e.xrel * main.window.density, e.yrel * main.window.density};
mouse.set_pos(mouseNewPos);
mouseMotionCallbacks.run_callbacks({
.pos = mouseNewPos,
.move = mouseRel
});
}
void InputManager::backend_mouse_wheel_update(const SDL_MouseWheelEvent& e) {
mouse.scrollAmount.x() += e.x;
mouse.scrollAmount.y() += e.y;
mouseWheelCallbacks.run_callbacks({
.amount = {e.x, e.y},
});
}
void InputManager::backend_key_down_update(const SDL_KeyboardEvent& e) {
auto kPress = e.key;
auto kMod = e.mod;

View file

@ -16,9 +16,10 @@
#include <SDL3/SDL_keycode.h>
using namespace Eigen;
class MainProgram;
struct InputManager {
InputManager();
InputManager(MainProgram& initMain);
void frame_reset(const Vector2i& windowSize);
@ -213,6 +214,10 @@ struct InputManager {
void set_key_up(const SDL_KeyboardEvent& e, KeyCode kCode);
void set_key_down(const SDL_KeyboardEvent& e, KeyCode kCode);
void backend_mouse_button_up_update(const SDL_MouseButtonEvent& e);
void backend_mouse_button_down_update(const SDL_MouseButtonEvent& e);
void backend_mouse_motion_update(const SDL_MouseMotionEvent& e);
void backend_mouse_wheel_update(const SDL_MouseWheelEvent& e);
void backend_key_up_update(const SDL_KeyboardEvent& e);
void backend_key_down_update(const SDL_KeyboardEvent& e);
@ -243,7 +248,33 @@ struct InputManager {
std::unordered_map<Vector2ui32, KeyCode> defaultKeyAssignments;
std::array<KeyData, KEY_COUNT> keys;
SDL_Window* sdlWindow;
struct MouseButtonCallbackArgs {
enum class Button : uint8_t {
LEFT = 1,
MIDDLE,
RIGHT
} button;
bool down;
uint8_t clicks;
Vector2f pos;
};
typedef CallbackManager<MouseButtonCallbackArgs> MouseButtonCallbackManager;
MouseButtonCallbackManager mouseButtonCallbacks;
struct MouseMotionCallbackArgs {
Vector2f pos;
Vector2f move;
};
typedef CallbackManager<MouseMotionCallbackArgs> MouseMotionCallbackManager;
MouseMotionCallbackManager mouseMotionCallbacks;
struct MouseWheelCallbackArgs {
Vector2f amount;
};
typedef CallbackManager<MouseWheelCallbackArgs> MouseWheelCallbackManager;
MouseWheelCallbackManager mouseWheelCallbacks;
MainProgram& main;
};
NLOHMANN_JSON_SERIALIZE_ENUM(InputManager::KeyCodeEnum, {

View file

@ -36,6 +36,7 @@
#include "DrawCollision.hpp"
MainProgram::MainProgram():
input(*this),
fonts(std::make_shared<FontData>()),
toolbar(*this)
{

View file

@ -2305,6 +2305,16 @@ float Toolbar::final_gui_scale() {
return finalCalculatedGuiScale;
}
bool Toolbar::check_if_position_isnt_obstructed(const Vector2f& pos) {
bool positionIsntObstructed = true;
Vector2f posGUI = pos / final_gui_scale();
for(auto& aabb : io->hoverObstructingAABBs)
positionIsntObstructed &= !SCollision::collide(posGUI, aabb);
for(auto& circle : io->hoverObstructingCircles)
positionIsntObstructed &= !SCollision::collide(posGUI, circle);
return positionIsntObstructed;
}
void Toolbar::calculate_final_gui_scale() {
Vector2f maxWindowSizeBeforeForcedFit = final_gui_scale_not_fit() * Vector2f{700.0f, 700.0f};
Vector2f fitRatio = {main.window.size.x() / maxWindowSizeBeforeForcedFit.x(), main.window.size.y() / maxWindowSizeBeforeForcedFit.y()};

View file

@ -90,6 +90,7 @@ class Toolbar {
bool flipZoomToolDirection = false;
float final_gui_scale();
bool check_if_position_isnt_obstructed(const Vector2f& pos);
bool app_close_requested();
private:

View file

@ -464,7 +464,6 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
mS.m->documentsPath = std::filesystem::path(documentsPathSDL);
#endif
mS.m->window.sdlWindow = mS.window;
mS.m->input.sdlWindow = mS.window;
mS.m->update_scale_and_density();
#ifdef __EMSCRIPTEN__
emscripten_set_beforeunload_callback((void*)mSPtr, emscripten_before_unload);
@ -737,34 +736,19 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
if(!mS.m->toolbar.tabletOptions.ignoreMouseMovementWhenPenInProximity || !mS.m->input.pen.inProximity)
#endif
{
mS.m->input.mouse.set_pos({event->motion.x * mS.m->window.density, event->motion.y * mS.m->window.density});
mS.m->input.backend_mouse_motion_update(event->motion);
}
break;
case SDL_EVENT_MOUSE_BUTTON_UP:
if(event->button.button == 1)
mS.m->input.mouse.leftDown = false;
else if(event->button.button == 2)
mS.m->input.mouse.middleDown = false;
else if(event->button.button == 3)
mS.m->input.mouse.rightDown = false;
mS.m->update_scale_and_density();
mS.m->input.backend_mouse_button_up_update(event->button);
break;
case SDL_EVENT_MOUSE_BUTTON_DOWN:
if(event->button.button == 1) {
mS.m->input.mouse.leftDown = true;
mS.m->input.mouse.leftClicks = event->button.clicks;
}
else if(event->button.button == 2) {
mS.m->input.mouse.middleDown = true;
mS.m->input.mouse.middleClicks = event->button.clicks;
}
else if(event->button.button == 3) {
mS.m->input.mouse.rightDown = true;
mS.m->input.mouse.rightClicks = event->button.clicks;
}
mS.m->update_scale_and_density();
mS.m->input.backend_mouse_button_down_update(event->button);
break;
case SDL_EVENT_MOUSE_WHEEL:
mS.m->input.mouse.scrollAmount.x() += event->wheel.x;
mS.m->input.mouse.scrollAmount.y() += event->wheel.y;
mS.m->input.backend_mouse_wheel_update(event->wheel);
break;
case SDL_EVENT_KEY_DOWN:
mS.m->input.backend_key_down_update(event->key);