#pragma once #include #include #include #include "RichText/TextStyleModifier.hpp" #include "RichText/TextBox.hpp" #include "TimePoint.hpp" #include #include #include #include #include #include "UndoManager.hpp" #include #include #include using namespace Eigen; class MainProgram; struct InputManager { InputManager(MainProgram& initMain); void update(); void frame_reset(const Vector2i& windowSize); // Just renamed SDL3 cursor types, but if we need to change to a different backend we can // translate this enum to different commands in main.cpp enum class SystemCursorType : unsigned { DEFAULT = 0, TEXT, WAIT, CROSSHAIR, PROGRESS, NWSE_RESIZE, NESW_RESIZE, EW_RESIZE, NS_RESIZE, MOVE, NOT_ALLOWED, POINTER, NW_RESIZE, N_RESIZE, NE_RESIZE, E_RESIZE, SE_RESIZE, S_RESIZE, SW_RESIZE, W_RESIZE } cursorIcon; bool hideCursor = false; bool toggleFullscreen = false; struct KeyData { bool pressed = false; bool held = false; bool repeat = false; std::chrono::steady_clock::time_point lastPressTime; }; struct Mouse { void set_pos(const Vector2f& newPos); Vector2f scrollAmount = {0, 0}; Vector2f pos = {0, 0}; Vector2f previousPos = {0, 0}; Vector2f move = {0, 0}; bool leftDown = false; bool rightDown = false; bool middleDown = false; uint8_t leftClicks = 0; uint8_t rightClicks = 0; uint8_t middleClicks = 0; Vector2f lastPos = {0, 0}; } mouse; struct Touch { int leftClicksSaved = 0; int fingerTapsSaved = 0; std::chrono::steady_clock::time_point lastLeftClickTime; std::chrono::steady_clock::time_point lastFingerTapTime; std::vector fingers; enum TypeOfTouchEvent { NO_TOUCH_EVENT, ONE_FINGER_EVENT, TWO_FINGER_EVENT, EVENT_DONE } touchEventType = EVENT_DONE; } touch; struct Pen { bool inProximity = false; bool isDown = false; bool isEraser = false; float pressure = 0.0f; int leftClicksSaved = 0; Vector2f previousPos; std::chrono::steady_clock::time_point lastPenLeftClickTime; std::array buttons; } pen; bool isTouchDevice = true; void set_rich_text_box_input_front(const std::shared_ptr& nTextBox, const std::shared_ptr& nCursor, bool isRichTextBox, const std::optional& nModMap = std::nullopt); void set_rich_text_box_input_back(const std::shared_ptr& nTextBox, const std::shared_ptr& nCursor, bool isRichTextBox, const std::optional& nModMap = std::nullopt); void remove_rich_text_box_input(const std::shared_ptr& nTextBox); struct Text { bool is_accepting_input(); void add_text_to_textbox(const std::string& inputText); void add_textbox_undo(const RichText::TextBox::Cursor& prevCursor, const RichText::TextData& prevRichText); void do_textbox_operation_with_undo(const std::function& func); private: struct TextBoxInfo { bool isRichTextBox; std::shared_ptr textBox; std::shared_ptr cursor; std::optional modMap; UndoManager textboxUndo; }; void set_accepting_input(SDL_Window* window, bool newAcceptingInputVal); bool isNextPasteRich = false; bool acceptingInput = false; std::deque textBoxes; friend struct InputManager; } text; #ifdef __APPLE__ SDL_Keymod CTRL_MOD = SDL_KMOD_GUI; #else SDL_Keymod CTRL_MOD = SDL_KMOD_CTRL; #endif int stopKeyInput = 0; std::optional lastPressedKeybind; enum KeyCodeEnum : unsigned { // Assignable KEY_CAMERA_ROTATE_CLOCKWISE = 0, KEY_CAMERA_ROTATE_COUNTERCLOCKWISE, KEY_DRAW_DELETE, KEY_UNDO, KEY_REDO, KEY_NOGUI, KEY_FULLSCREEN, KEY_SAVE, KEY_SAVE_AS, KEY_COPY, KEY_CUT, KEY_PASTE, KEY_PASTE_IMAGE, KEY_DRAW_TOOL_BRUSH, KEY_DRAW_TOOL_ERASER, KEY_DRAW_TOOL_ZOOM, KEY_DRAW_TOOL_PAN, KEY_DRAW_TOOL_LASSOSELECT, KEY_DRAW_TOOL_TEXTBOX, KEY_DRAW_TOOL_RECTANGLE, KEY_DRAW_TOOL_ELLIPSE, KEY_DRAW_TOOL_RECTSELECT, KEY_DRAW_TOOL_EYEDROPPER, KEY_DRAW_TOOL_SCREENSHOT, KEY_DRAW_TOOL_LINE, KEY_SHOW_METRICS, KEY_OPEN_CHAT, KEY_SHOW_PLAYER_LIST, KEY_HOLD_TO_PAN, KEY_HOLD_TO_ZOOM, KEY_DESELECT_AND_EDIT_TOOL, KEY_ASSIGNABLE_COUNT, // Not a real key // Unassignable KEY_TEXT_DOWN, KEY_TEXT_UP, KEY_TEXT_LEFT, KEY_TEXT_RIGHT, KEY_TEXT_BACKSPACE, KEY_TEXT_DELETE, KEY_TEXT_HOME, KEY_TEXT_END, KEY_TEXT_SHIFT, KEY_TEXT_COPY, KEY_TEXT_CUT, KEY_TEXT_PASTE, KEY_TEXT_ENTER, KEY_TEXT_TAB, KEY_TEXT_CTRL, KEY_TEXT_META, 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, KEY_GENERIC_LCTRL, KEY_GENERIC_LMETA, KEY_COUNT }; typedef unsigned KeyCode; bool ctrl_or_meta_held(); void stop_key_input(); uint32_t make_generic_key_mod(SDL_Keymod m); void set_key_up(const SDL_KeyboardEvent& e, KeyCode kCode); void set_key_down(const SDL_KeyboardEvent& e, KeyCode kCode); std::vector get_multiple_finger_positions(); std::vector get_multiple_finger_motions(); void touch_finger_do_mouse_down(); void touch_finger_do_mouse_up(const SDL_TouchFingerEvent& f); void touch_finger_do_mouse_motion(const SDL_TouchFingerEvent& f); void backend_drop_file_event(const SDL_DropEvent& e); void backend_drop_text_event(const SDL_DropEvent& e); 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); void backend_pen_button_down_update(const SDL_PenButtonEvent& e); void backend_pen_button_up_update(const SDL_PenButtonEvent& e); void backend_pen_touch_down_update(const SDL_PenTouchEvent& e); void backend_pen_touch_up_update(const SDL_PenTouchEvent& e); void backend_pen_motion_update(const SDL_PenMotionEvent& e); void backend_pen_axis_update(const SDL_PenAxisEvent& e); void backend_touch_finger_down_update(const SDL_TouchFingerEvent& e); void backend_touch_finger_up_update(const SDL_TouchFingerEvent& e); void backend_touch_finger_motion_update(const SDL_TouchFingerEvent& e); void set_clipboard_str(std::string_view s); void set_clipboard_plain_and_richtext_pair(const std::pair& plainAndRichtextPair); std::string get_clipboard_str_SDL(); void get_clipboard_image_data_SDL(const std::function& callback); void call_text_paste(bool isRichTextPaste); void process_text_paste(const std::string& plainClipboardStr); std::optional lastCopiedRichText; std::string key_assignment_to_str(const Vector2ui32& k); Vector2ui32 key_assignment_from_str(const std::string& s); const KeyData& key(KeyCode kCode); struct KeyCallbackArgs { KeyCode key; bool down; bool repeat; }; std::unordered_map keyAssignments; std::unordered_map defaultKeyAssignments; std::array keys; enum class MouseButton : uint8_t { LEFT = 1, MIDDLE, RIGHT } button; enum class MouseDeviceType { MOUSE, PEN, TOUCH }; struct MouseButtonCallbackArgs { MouseDeviceType deviceType; MouseButton button; bool down; uint8_t clicks; Vector2f pos; }; struct MouseMotionCallbackArgs { MouseDeviceType deviceType; Vector2f pos; Vector2f move; }; struct MouseWheelCallbackArgs { Vector2f mousePos; Vector2f amount; Vector2i tickAmount; }; struct PenButtonCallbackArgs { uint8_t button; bool down; Vector2f pos; }; struct PenTouchCallbackArgs { bool down; bool eraser; Vector2f pos; }; struct PenMotionCallbackArgs { Vector2f pos; Vector2f move; }; struct PenAxisCallbackArgs { Vector2f pos; SDL_PenAxis axis; float value; }; struct DropCallbackArgs { Vector2f pos; const char* source; const char* data; }; struct MultiFingerTouchCallbackArgs { bool down; std::vector pos; }; struct MultiFingerMotionCallbackArgs { std::vector pos; std::vector move; }; struct FingerTouchCallbackArgs { SDL_FingerID fingerID; bool down; Vector2f pos; size_t fingerDownCount; int fingerTapCount; }; struct FingerMotionCallbackArgs { SDL_FingerID fingerID; Vector2f pos; Vector2f move; size_t fingerDownCount; }; MainProgram& main; }; NLOHMANN_JSON_SERIALIZE_ENUM(InputManager::KeyCodeEnum, { {InputManager::KEY_CAMERA_ROTATE_CLOCKWISE, "Rotate Canvas CW"}, {InputManager::KEY_CAMERA_ROTATE_COUNTERCLOCKWISE, "Rotate Canvas CCW"}, {InputManager::KEY_DRAW_DELETE, "Delete Selection"}, {InputManager::KEY_UNDO, "Undo"}, {InputManager::KEY_REDO, "Redo"}, {InputManager::KEY_NOGUI, "Toggle GUI"}, {InputManager::KEY_FULLSCREEN, "Toggle Fullscreen"}, {InputManager::KEY_SAVE, "Save"}, {InputManager::KEY_SAVE_AS, "Save As"}, {InputManager::KEY_COPY, "Copy"}, {InputManager::KEY_CUT, "Cut"}, {InputManager::KEY_PASTE, "Paste"}, {InputManager::KEY_PASTE_IMAGE, "Paste Image"}, {InputManager::KEY_DRAW_TOOL_BRUSH, "Brush Tool"}, {InputManager::KEY_DRAW_TOOL_ERASER, "Eraser Tool"}, {InputManager::KEY_DRAW_TOOL_ZOOM, "Zoom Tool"}, {InputManager::KEY_DRAW_TOOL_LASSOSELECT, "Lasso Select Tool"}, {InputManager::KEY_DRAW_TOOL_PAN, "Pan Tool"}, {InputManager::KEY_DRAW_TOOL_TEXTBOX, "Textbox Tool"}, {InputManager::KEY_DRAW_TOOL_RECTANGLE, "Rectangle Tool"}, {InputManager::KEY_DRAW_TOOL_ELLIPSE, "Ellipse Tool"}, {InputManager::KEY_DRAW_TOOL_RECTSELECT, "Rect Select Tool"}, {InputManager::KEY_DRAW_TOOL_EYEDROPPER, "Color Select Tool"}, {InputManager::KEY_DRAW_TOOL_SCREENSHOT, "Take Screenshot"}, {InputManager::KEY_DRAW_TOOL_LINE, "Line Tool"}, {InputManager::KEY_SHOW_METRICS, "Show Metrics"}, {InputManager::KEY_OPEN_CHAT, "Open Chat"}, {InputManager::KEY_SHOW_PLAYER_LIST, "Show Player List"}, {InputManager::KEY_HOLD_TO_PAN, "Hold to Pan"}, {InputManager::KEY_HOLD_TO_ZOOM, "Hold to Zoom"}, {InputManager::KEY_DESELECT_AND_EDIT_TOOL, "Deselect selection / Edit Tool"} })