├── .gitignore ├── .vscode ├── c_cpp_properties.json └── settings.json ├── ButtonMappingTypes.cpp ├── ButtonMappingTypes.h ├── CMakeLists.txt ├── ControlPanelDialog.cpp ├── ControlPanelDialog.h ├── InkCanvas.cpp ├── InkCanvas.h ├── KeyCaptureDialog.cpp ├── KeyCaptureDialog.h ├── LICENSE ├── Main.cpp ├── MainWindow.cpp ├── MainWindow.h ├── README.md ├── RecentNotebooksDialog.cpp ├── RecentNotebooksDialog.h ├── RecentNotebooksManager.cpp ├── RecentNotebooksManager.h ├── SDLControllerManager.cpp ├── SDLControllerManager.h ├── ToolType.h ├── app_icon.rc ├── compile.ps1 ├── copy_dlls.bat ├── packaging.iss ├── resources.qrc ├── resources ├── fonts │ ├── Jersey20-Regular.ttf │ └── PixelFont.ttf ├── icons │ ├── addtab.png │ ├── addtab_reversed.png │ ├── background.png │ ├── background_reversed.png │ ├── benchmark.png │ ├── benchmark_reversed.png │ ├── black.png │ ├── blue.png │ ├── bookpage.png │ ├── bookpage_reversed.png │ ├── color.png │ ├── color_reversed.png │ ├── cross.png │ ├── cross_reversed.png │ ├── dial.png │ ├── dial_reversed.png │ ├── down_arrow.png │ ├── down_arrow_reversed.png │ ├── eraser.png │ ├── eraser_reversed.png │ ├── export.png │ ├── export_reversed.png │ ├── fastforward.png │ ├── fastforward_reversed.png │ ├── folder.png │ ├── folder_reversed.png │ ├── fullscreen.png │ ├── fullscreen_reversed.png │ ├── green.png │ ├── import.png │ ├── import_reversed.png │ ├── mainicon.png │ ├── marker.png │ ├── marker_reversed.png │ ├── pdf.png │ ├── pdf_reversed.png │ ├── pdfdelete.png │ ├── pdfdelete_reversed.png │ ├── pen.png │ ├── pen_reversed.png │ ├── preset.png │ ├── preset_reversed.png │ ├── recent.png │ ├── recent_reversed.png │ ├── red.png │ ├── rope.png │ ├── rope_reversed.png │ ├── save.png │ ├── save_reversed.png │ ├── saveannotated.png │ ├── saveannotated_reversed.png │ ├── savepreset.png │ ├── savepreset_reversed.png │ ├── scroll.png │ ├── scroll_reversed.png │ ├── settings.png │ ├── settings_reversed.png │ ├── straightLine.png │ ├── straightLine_reversed.png │ ├── tabs.png │ ├── tabs_reversed.png │ ├── thickness.png │ ├── thickness_reversed.png │ ├── trash.png │ ├── trash_reversed.png │ ├── up_arrow.png │ ├── up_arrow_reversed.png │ ├── white.png │ ├── writing_write_pen_icon_149355.png │ ├── writing_write_pen_icon_149355_reversed.png │ ├── yellow.png │ ├── zoom.png │ └── zoom_reversed.png ├── icons_backup │ ├── addtab.png │ ├── background.png │ ├── benchmark.png │ ├── black.png │ ├── blue.png │ ├── bookpage.png │ ├── color.png │ ├── cross.png │ ├── dial.png │ ├── down_arrow.png │ ├── eraser.png │ ├── fastforward.png │ ├── folder.png │ ├── fullscreen.png │ ├── green.png │ ├── mainicon.png │ ├── marker.png │ ├── pdf.png │ ├── pdfdelete.png │ ├── pen.png │ ├── preset.png │ ├── red.png │ ├── save.png │ ├── saveannotated.png │ ├── savepreset.png │ ├── thickness.png │ ├── trash.png │ ├── up_arrow.png │ ├── white.png │ ├── writing_write_pen_icon_149355.png │ ├── yellow.png │ └── zoom.png ├── icontest │ ├── export.png │ ├── export_reversed.png │ ├── import.png │ ├── import_reversed.png │ ├── rope.png │ └── rope_reversed.png ├── newicons │ ├── 3643772-archive-archives-document-folder-open_113445.png │ ├── Chiseltipmarker_marker_3253.png │ ├── Circle_34541.png │ ├── Circle_icon-icons.com_52186.png │ ├── arrow_down_arrow_icon_253880.png │ ├── cross-symbol_icon-icons.com_74149.png │ ├── document_write_writing_draw_drawing_pen_icon_262129.png │ ├── dustbin_120823.png │ ├── eraser_icon_173850.png │ ├── magnifier-1_icon-icons.com_56924.png │ ├── markerpen_marcado_3797.png │ ├── mountain-range-on-black-background_icon-icons.com_72655.png │ ├── pdf-file-outlined-interface-symbol_icon-icons.com_57528.png │ ├── pen_3247.png │ ├── perfect-circle_icon-icons.com_53928.png │ ├── save_3621.png │ ├── savedisk_121993.png │ ├── tab_add_filled_icon_201837.png │ ├── time_alarm_stopwatch_watch_hour_timer_clock_icon_252109.png │ ├── trafficlight-green_40427.png │ ├── trafficlight-red_40428.png │ ├── up_arrow_arrow_icon_253897.png │ └── writing_write_pen_icon_149355.png ├── oldicons │ ├── addtab.ico │ ├── background.ico │ ├── benchmark.ico │ ├── black.ico │ ├── blue.ico │ ├── cross.ico │ ├── down_arrow.ico │ ├── eraser.ico │ ├── folder.ico │ ├── fullscreen.ico │ ├── green.ico │ ├── marker.ico │ ├── my_ebooks_folder_14975.ico │ ├── pdf.ico │ ├── pdfdelete.ico │ ├── pen.ico │ ├── red.ico │ ├── save.ico │ ├── saveannotated.ico │ ├── thickness.ico │ ├── trash.ico │ ├── up_arrow.ico │ ├── white.ico │ ├── yellow.ico │ └── zoom.ico ├── reversed_icons │ ├── bookpage_reversed.png │ ├── color_reversed.png │ ├── eraser_reversed.png │ ├── marker_reversed.png │ ├── pen_reversed.png │ ├── preset_reversed.png │ ├── thickness_reversed.png │ └── zoom_reversed.png ├── sounds │ └── dial_click.wav └── translations │ ├── app_es.qm │ ├── app_es.ts │ ├── app_fr.qm │ ├── app_fr.ts │ ├── app_zh.qm │ └── app_zh.ts └── translate.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "C:/Qt/6.8.2/mingw_64/include", 8 | "C:/Qt/6.8.2/mingw_64/include/QtWidgets", 9 | "C:/Qt/6.8.2/mingw_64/include/QtGui", 10 | "C:/Qt/6.8.2/mingw_64/include/QtCore", 11 | "C:/msys64/mingw64/include/poppler", 12 | "C:/msys64/mingw64/include/poppler/qt6", 13 | "C:/msys64/mingw64/include/poppler/cpp" 14 | ], 15 | "defines": [ 16 | "UNICODE", 17 | "_UNICODE" 18 | ], 19 | "compilerPath": "C:/Qt/Tools/mingw1310_64/bin/g++.exe", 20 | "cStandard": "c17", 21 | "cppStandard": "c++17" 22 | } 23 | ], 24 | "version": 4 25 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "qopenglfunctions_3_3_core": "cpp", 4 | "qvboxlayout": "cpp", 5 | "deque": "cpp", 6 | "list": "cpp", 7 | "array": "cpp", 8 | "atomic": "cpp", 9 | "bit": "cpp", 10 | "*.tcc": "cpp", 11 | "cctype": "cpp", 12 | "charconv": "cpp", 13 | "chrono": "cpp", 14 | "clocale": "cpp", 15 | "cmath": "cpp", 16 | "compare": "cpp", 17 | "concepts": "cpp", 18 | "condition_variable": "cpp", 19 | "cstdarg": "cpp", 20 | "cstddef": "cpp", 21 | "cstdint": "cpp", 22 | "cstdio": "cpp", 23 | "cstdlib": "cpp", 24 | "cstring": "cpp", 25 | "ctime": "cpp", 26 | "cwchar": "cpp", 27 | "cwctype": "cpp", 28 | "map": "cpp", 29 | "string": "cpp", 30 | "unordered_map": "cpp", 31 | "vector": "cpp", 32 | "exception": "cpp", 33 | "algorithm": "cpp", 34 | "functional": "cpp", 35 | "iterator": "cpp", 36 | "memory": "cpp", 37 | "memory_resource": "cpp", 38 | "numeric": "cpp", 39 | "optional": "cpp", 40 | "random": "cpp", 41 | "ratio": "cpp", 42 | "string_view": "cpp", 43 | "system_error": "cpp", 44 | "tuple": "cpp", 45 | "type_traits": "cpp", 46 | "utility": "cpp", 47 | "format": "cpp", 48 | "future": "cpp", 49 | "initializer_list": "cpp", 50 | "iomanip": "cpp", 51 | "iosfwd": "cpp", 52 | "istream": "cpp", 53 | "limits": "cpp", 54 | "mutex": "cpp", 55 | "new": "cpp", 56 | "numbers": "cpp", 57 | "ostream": "cpp", 58 | "semaphore": "cpp", 59 | "span": "cpp", 60 | "sstream": "cpp", 61 | "stdexcept": "cpp", 62 | "stdfloat": "cpp", 63 | "stop_token": "cpp", 64 | "streambuf": "cpp", 65 | "thread": "cpp", 66 | "cinttypes": "cpp", 67 | "typeinfo": "cpp", 68 | "variant": "cpp", 69 | "qhboxlayout": "cpp", 70 | "qlabel": "cpp", 71 | "qapplication": "cpp", 72 | "codecvt": "cpp", 73 | "qgestureevent": "cpp", 74 | "qstackedwidget": "cpp", 75 | "qguiapplication": "cpp", 76 | "qlineedit": "cpp", 77 | "qfocusevent": "cpp" 78 | }, 79 | "C_Cpp.errorSquiggles": "disabled" 80 | } -------------------------------------------------------------------------------- /ButtonMappingTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "ButtonMappingTypes.h" 2 | 3 | QString ButtonMappingHelper::dialModeToInternalKey(InternalDialMode mode) { 4 | switch (mode) { 5 | case InternalDialMode::None: return "none"; 6 | case InternalDialMode::PageSwitching: return "page_switching"; 7 | case InternalDialMode::ZoomControl: return "zoom_control"; 8 | case InternalDialMode::ThicknessControl: return "thickness_control"; 9 | case InternalDialMode::ColorAdjustment: return "color_adjustment"; 10 | case InternalDialMode::ToolSwitching: return "tool_switching"; 11 | case InternalDialMode::PresetSelection: return "preset_selection"; 12 | case InternalDialMode::PanAndPageScroll: return "pan_and_page_scroll"; 13 | } 14 | return "none"; 15 | } 16 | 17 | QString ButtonMappingHelper::actionToInternalKey(InternalControllerAction action) { 18 | switch (action) { 19 | case InternalControllerAction::None: return "none"; 20 | case InternalControllerAction::ToggleFullscreen: return "toggle_fullscreen"; 21 | case InternalControllerAction::ToggleDial: return "toggle_dial"; 22 | case InternalControllerAction::Zoom50: return "zoom_50"; 23 | case InternalControllerAction::ZoomOut: return "zoom_out"; 24 | case InternalControllerAction::Zoom200: return "zoom_200"; 25 | case InternalControllerAction::AddPreset: return "add_preset"; 26 | case InternalControllerAction::DeletePage: return "delete_page"; 27 | case InternalControllerAction::FastForward: return "fast_forward"; 28 | case InternalControllerAction::OpenControlPanel: return "open_control_panel"; 29 | case InternalControllerAction::RedColor: return "red_color"; 30 | case InternalControllerAction::BlueColor: return "blue_color"; 31 | case InternalControllerAction::YellowColor: return "yellow_color"; 32 | case InternalControllerAction::GreenColor: return "green_color"; 33 | case InternalControllerAction::BlackColor: return "black_color"; 34 | case InternalControllerAction::WhiteColor: return "white_color"; 35 | case InternalControllerAction::CustomColor: return "custom_color"; 36 | case InternalControllerAction::ToggleSidebar: return "toggle_sidebar"; 37 | case InternalControllerAction::Save: return "save"; 38 | case InternalControllerAction::StraightLineTool: return "straight_line_tool"; 39 | case InternalControllerAction::RopeTool: return "rope_tool"; 40 | case InternalControllerAction::SetPenTool: return "set_pen_tool"; 41 | case InternalControllerAction::SetMarkerTool: return "set_marker_tool"; 42 | case InternalControllerAction::SetEraserTool: return "set_eraser_tool"; 43 | } 44 | return "none"; 45 | } 46 | 47 | InternalDialMode ButtonMappingHelper::internalKeyToDialMode(const QString &key) { 48 | if (key == "none") return InternalDialMode::None; 49 | if (key == "page_switching") return InternalDialMode::PageSwitching; 50 | if (key == "zoom_control") return InternalDialMode::ZoomControl; 51 | if (key == "thickness_control") return InternalDialMode::ThicknessControl; 52 | if (key == "color_adjustment") return InternalDialMode::ColorAdjustment; 53 | if (key == "tool_switching") return InternalDialMode::ToolSwitching; 54 | if (key == "preset_selection") return InternalDialMode::PresetSelection; 55 | if (key == "pan_and_page_scroll") return InternalDialMode::PanAndPageScroll; 56 | return InternalDialMode::None; 57 | } 58 | 59 | InternalControllerAction ButtonMappingHelper::internalKeyToAction(const QString &key) { 60 | if (key == "none") return InternalControllerAction::None; 61 | if (key == "toggle_fullscreen") return InternalControllerAction::ToggleFullscreen; 62 | if (key == "toggle_dial") return InternalControllerAction::ToggleDial; 63 | if (key == "zoom_50") return InternalControllerAction::Zoom50; 64 | if (key == "zoom_out") return InternalControllerAction::ZoomOut; 65 | if (key == "zoom_200") return InternalControllerAction::Zoom200; 66 | if (key == "add_preset") return InternalControllerAction::AddPreset; 67 | if (key == "delete_page") return InternalControllerAction::DeletePage; 68 | if (key == "fast_forward") return InternalControllerAction::FastForward; 69 | if (key == "open_control_panel") return InternalControllerAction::OpenControlPanel; 70 | if (key == "red_color") return InternalControllerAction::RedColor; 71 | if (key == "blue_color") return InternalControllerAction::BlueColor; 72 | if (key == "yellow_color") return InternalControllerAction::YellowColor; 73 | if (key == "green_color") return InternalControllerAction::GreenColor; 74 | if (key == "black_color") return InternalControllerAction::BlackColor; 75 | if (key == "white_color") return InternalControllerAction::WhiteColor; 76 | if (key == "custom_color") return InternalControllerAction::CustomColor; 77 | if (key == "toggle_sidebar") return InternalControllerAction::ToggleSidebar; 78 | if (key == "save") return InternalControllerAction::Save; 79 | if (key == "straight_line_tool") return InternalControllerAction::StraightLineTool; 80 | if (key == "rope_tool") return InternalControllerAction::RopeTool; 81 | if (key == "set_pen_tool") return InternalControllerAction::SetPenTool; 82 | if (key == "set_marker_tool") return InternalControllerAction::SetMarkerTool; 83 | if (key == "set_eraser_tool") return InternalControllerAction::SetEraserTool; 84 | return InternalControllerAction::None; 85 | } 86 | 87 | QStringList ButtonMappingHelper::getTranslatedDialModes() { 88 | return { 89 | tr("None"), 90 | tr("Page Switching"), 91 | tr("Zoom Control"), 92 | tr("Thickness Control"), 93 | tr("Color Adjustment"), 94 | tr("Tool Switching"), 95 | tr("Preset Selection"), 96 | tr("Pan and Page Scroll") 97 | }; 98 | } 99 | 100 | QStringList ButtonMappingHelper::getTranslatedActions() { 101 | return { 102 | tr("None"), 103 | tr("Toggle Fullscreen"), 104 | tr("Toggle Dial"), 105 | tr("Zoom 50%"), 106 | tr("Zoom Out"), 107 | tr("Zoom 200%"), 108 | tr("Add Preset"), 109 | tr("Delete Page"), 110 | tr("Fast Forward"), 111 | tr("Open Control Panel"), 112 | tr("Red"), 113 | tr("Blue"), 114 | tr("Yellow"), 115 | tr("Green"), 116 | tr("Black"), 117 | tr("White"), 118 | tr("Custom Color"), 119 | tr("Toggle Sidebar"), 120 | tr("Save"), 121 | tr("Straight Line Tool"), 122 | tr("Rope Tool"), 123 | tr("Set Pen Tool"), 124 | tr("Set Marker Tool"), 125 | tr("Set Eraser Tool") 126 | }; 127 | } 128 | 129 | QStringList ButtonMappingHelper::getTranslatedButtons() { 130 | return { 131 | tr("Left Shoulder"), 132 | tr("Right Shoulder"), 133 | tr("Paddle 2"), 134 | tr("Paddle 4"), 135 | tr("Y Button"), 136 | tr("A Button"), 137 | tr("B Button"), 138 | tr("X Button"), 139 | tr("Left Stick"), 140 | tr("Start Button"), 141 | tr("Guide Button") 142 | }; 143 | } 144 | 145 | QStringList ButtonMappingHelper::getInternalDialModeKeys() { 146 | return { 147 | "none", 148 | "page_switching", 149 | "zoom_control", 150 | "thickness_control", 151 | "color_adjustment", 152 | "tool_switching", 153 | "preset_selection", 154 | "pan_and_page_scroll" 155 | }; 156 | } 157 | 158 | QStringList ButtonMappingHelper::getInternalActionKeys() { 159 | return { 160 | "none", 161 | "toggle_fullscreen", 162 | "toggle_dial", 163 | "zoom_50", 164 | "zoom_out", 165 | "zoom_200", 166 | "add_preset", 167 | "delete_page", 168 | "fast_forward", 169 | "open_control_panel", 170 | "red_color", 171 | "blue_color", 172 | "yellow_color", 173 | "green_color", 174 | "black_color", 175 | "white_color", 176 | "custom_color", 177 | "toggle_sidebar", 178 | "save", 179 | "straight_line_tool", 180 | "rope_tool", 181 | "set_pen_tool", 182 | "set_marker_tool", 183 | "set_eraser_tool" 184 | }; 185 | } 186 | 187 | QStringList ButtonMappingHelper::getInternalButtonKeys() { 188 | return { 189 | "LEFTSHOULDER", 190 | "RIGHTSHOULDER", 191 | "PADDLE2", 192 | "PADDLE4", 193 | "Y", 194 | "A", 195 | "B", 196 | "X", 197 | "LEFTSTICK", 198 | "START", 199 | "GUIDE" 200 | }; 201 | } 202 | 203 | QString ButtonMappingHelper::displayToInternalKey(const QString &displayString, bool isDialMode) { 204 | if (isDialMode) { 205 | QStringList translated = getTranslatedDialModes(); 206 | QStringList internal = getInternalDialModeKeys(); 207 | int index = translated.indexOf(displayString); 208 | return (index >= 0) ? internal[index] : "none"; 209 | } else { 210 | QStringList translated = getTranslatedActions(); 211 | QStringList internal = getInternalActionKeys(); 212 | int index = translated.indexOf(displayString); 213 | return (index >= 0) ? internal[index] : "none"; 214 | } 215 | } 216 | 217 | QString ButtonMappingHelper::internalKeyToDisplay(const QString &internalKey, bool isDialMode) { 218 | if (isDialMode) { 219 | QStringList translated = getTranslatedDialModes(); 220 | QStringList internal = getInternalDialModeKeys(); 221 | int index = internal.indexOf(internalKey); 222 | return (index >= 0) ? translated[index] : tr("None"); 223 | } else { 224 | QStringList translated = getTranslatedActions(); 225 | QStringList internal = getInternalActionKeys(); 226 | int index = internal.indexOf(internalKey); 227 | return (index >= 0) ? translated[index] : tr("None"); 228 | } 229 | } -------------------------------------------------------------------------------- /ButtonMappingTypes.h: -------------------------------------------------------------------------------- 1 | #ifndef BUTTONMAPPINGTYPES_H 2 | #define BUTTONMAPPINGTYPES_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // Internal enum for dial modes (language-independent) 9 | enum class InternalDialMode { 10 | None, 11 | PageSwitching, 12 | ZoomControl, 13 | ThicknessControl, 14 | ColorAdjustment, 15 | ToolSwitching, 16 | PresetSelection, 17 | PanAndPageScroll 18 | }; 19 | 20 | // Internal enum for controller actions (language-independent) 21 | enum class InternalControllerAction { 22 | None, 23 | ToggleFullscreen, 24 | ToggleDial, 25 | Zoom50, 26 | ZoomOut, 27 | Zoom200, 28 | AddPreset, 29 | DeletePage, 30 | FastForward, 31 | OpenControlPanel, 32 | RedColor, 33 | BlueColor, 34 | YellowColor, 35 | GreenColor, 36 | BlackColor, 37 | WhiteColor, 38 | CustomColor, 39 | ToggleSidebar, // New: Hide/show sidebar 40 | Save, // New: Save current page 41 | StraightLineTool, // New: Toggle straight line tool 42 | RopeTool, // New: Toggle rope tool 43 | SetPenTool, // New: Set tool to pen 44 | SetMarkerTool, // New: Set tool to marker 45 | SetEraserTool // New: Set tool to eraser 46 | }; 47 | 48 | class ButtonMappingHelper { 49 | Q_DECLARE_TR_FUNCTIONS(ButtonMappingHelper) 50 | 51 | public: 52 | // Get internal key from display string 53 | static QString dialModeToInternalKey(InternalDialMode mode); 54 | static QString actionToInternalKey(InternalControllerAction action); 55 | 56 | // Get enum from internal key 57 | static InternalDialMode internalKeyToDialMode(const QString &key); 58 | static InternalControllerAction internalKeyToAction(const QString &key); 59 | 60 | // Get translated display strings 61 | static QStringList getTranslatedDialModes(); 62 | static QStringList getTranslatedActions(); 63 | static QStringList getTranslatedButtons(); 64 | 65 | // Get internal keys (for storage) 66 | static QStringList getInternalDialModeKeys(); 67 | static QStringList getInternalActionKeys(); 68 | static QStringList getInternalButtonKeys(); 69 | 70 | // Convert between display string and internal key 71 | static QString displayToInternalKey(const QString &displayString, bool isDialMode); 72 | static QString internalKeyToDisplay(const QString &internalKey, bool isDialMode); 73 | }; 74 | 75 | #endif // BUTTONMAPPINGTYPES_H -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | cmake_policy(SET CMP0074 NEW) 3 | 4 | project(NoteApp) 5 | set(CMAKE_CXX_STANDARD 17) 6 | 7 | # ✅ Add correct CMake module search paths 8 | set(CMAKE_PREFIX_PATH 9 | "C:/Qt/6.8.2/mingw_64/lib/cmake" 10 | "C:/libs/SDL2/lib/cmake" 11 | ) 12 | set(CMAKE_MODULE_PATH "C:/Qt/6.8.2/mingw_64/lib/cmake/Poppler") 13 | set(SDL2_ROOT "C:/libs/SDL2") 14 | 15 | set(TS_FILES 16 | ${CMAKE_SOURCE_DIR}/resources/translations/app_zh.ts 17 | ${CMAKE_SOURCE_DIR}/resources/translations/app_es.ts 18 | ${CMAKE_SOURCE_DIR}/resources/translations/app_fr.ts 19 | ) 20 | 21 | # ✅ Prevent SDL2 from redefining main() 22 | add_compile_definitions(SDL_MAIN_HANDLED) 23 | 24 | # ✅ Find all dependencies 25 | find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets VirtualKeyboard Multimedia Concurrent) 26 | find_package(Poppler REQUIRED) 27 | find_package(SDL2 REQUIRED CONFIG) 28 | unset(SDL2main CACHE) # Ensure SDL2main isn't picked up 29 | 30 | # ✅ Resources 31 | set(RESOURCES resources.qrc) 32 | QT6_ADD_RESOURCES(QRCC_FILES ${RESOURCES}) 33 | 34 | # ✅ Include + Link paths 35 | include_directories( 36 | "C:/msys64/mingw64/include/poppler" 37 | "C:/msys64/mingw64/include/poppler/cpp" 38 | "C:/msys64/mingw64/include/poppler/qt6" 39 | "${SDL2_ROOT}/include" 40 | ) 41 | link_directories("C:/msys64/mingw64/lib") 42 | 43 | # ✅ Qt Meta-Object Compiler support 44 | set(CMAKE_AUTOMOC ON) 45 | set(CMAKE_AUTORCC ON) 46 | 47 | # ✅ Windows-specific resource file for executable icon 48 | if(WIN32) 49 | enable_language(RC) 50 | set(WIN_RESOURCES app_icon.rc) 51 | endif() 52 | 53 | # ✅ Build target 54 | add_executable(NoteApp 55 | Main.cpp MainWindow.cpp InkCanvas.cpp ControlPanelDialog.cpp SDLControllerManager.cpp ButtonMappingTypes.cpp ${QRCC_FILES} 56 | RecentNotebooksManager.cpp 57 | RecentNotebooksDialog.cpp 58 | KeyCaptureDialog.cpp 59 | ${WIN_RESOURCES} # Windows resource file for executable icon (only on Windows) 60 | ) 61 | 62 | # ✅ Compile .ts → .qm using Qt's lrelease 63 | find_program(LRELEASE_EXECUTABLE lrelease PATHS "C:/Qt/6.8.2/mingw_64/bin") 64 | 65 | foreach(_ts ${TS_FILES}) 66 | get_filename_component(_qm ${_ts} NAME_WE) 67 | set(_qm_file ${CMAKE_CURRENT_BINARY_DIR}/${_qm}.qm) 68 | add_custom_command( 69 | OUTPUT ${_qm_file} 70 | COMMAND ${LRELEASE_EXECUTABLE} ${_ts} -qm ${_qm_file} 71 | DEPENDS ${_ts} 72 | COMMENT "Generating ${_qm_file}" 73 | VERBATIM 74 | ) 75 | list(APPEND QM_FILES ${_qm_file}) 76 | endforeach() 77 | 78 | # ✅ Add a target to build translations 79 | # add_custom_target(translations ALL DEPENDS ${QM_FILES}) 80 | 81 | # 82 | add_compile_definitions(QT_NO_DEPRECATED_WARNINGS) 83 | 84 | 85 | # ✅ Link libraries 86 | target_link_libraries(NoteApp 87 | Qt6::Core Qt6::Gui Qt6::Widgets Qt6::VirtualKeyboard Qt6::Multimedia Qt6::Concurrent 88 | SDL2::SDL2 89 | ${POPPLER_LIBRARIES} 90 | ) 91 | -------------------------------------------------------------------------------- /ControlPanelDialog.cpp: -------------------------------------------------------------------------------- 1 | #include "ControlPanelDialog.h" 2 | #include "ButtonMappingTypes.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | ControlPanelDialog::ControlPanelDialog(MainWindow *mainWindow, InkCanvas *targetCanvas, QWidget *parent) 15 | : QDialog(parent), canvas(targetCanvas), selectedColor(canvas->getBackgroundColor()), mainWindowRef(mainWindow) { 16 | 17 | setWindowTitle(tr("Canvas Control Panel")); 18 | resize(400, 200); 19 | 20 | tabWidget = new QTabWidget(this); 21 | 22 | // === Tabs === 23 | createBackgroundTab(); 24 | tabWidget->addTab(backgroundTab, tr("Background")); 25 | if (mainWindowRef) { 26 | createPerformanceTab(); 27 | tabWidget->addTab(performanceTab, tr("Performance")); 28 | createToolbarTab(); 29 | } 30 | createButtonMappingTab(); 31 | createKeyboardMappingTab(); 32 | // === Buttons === 33 | applyButton = new QPushButton(tr("Apply")); 34 | okButton = new QPushButton(tr("OK")); 35 | cancelButton = new QPushButton(tr("Cancel")); 36 | 37 | connect(applyButton, &QPushButton::clicked, this, &ControlPanelDialog::applyChanges); 38 | connect(okButton, &QPushButton::clicked, this, [=]() { 39 | applyChanges(); 40 | accept(); 41 | }); 42 | connect(cancelButton, &QPushButton::clicked, this, &ControlPanelDialog::reject); 43 | 44 | // === Layout === 45 | QHBoxLayout *buttonLayout = new QHBoxLayout(); 46 | buttonLayout->addStretch(); 47 | buttonLayout->addWidget(applyButton); 48 | buttonLayout->addWidget(okButton); 49 | buttonLayout->addWidget(cancelButton); 50 | 51 | QVBoxLayout *mainLayout = new QVBoxLayout(this); 52 | mainLayout->addWidget(tabWidget); 53 | mainLayout->addLayout(buttonLayout); 54 | 55 | loadFromCanvas(); 56 | } 57 | 58 | 59 | void ControlPanelDialog::createBackgroundTab() { 60 | backgroundTab = new QWidget(this); 61 | 62 | QLabel *styleLabel = new QLabel(tr("Background Style:")); 63 | styleCombo = new QComboBox(); 64 | styleCombo->addItem(tr("None"), static_cast(BackgroundStyle::None)); 65 | styleCombo->addItem(tr("Grid"), static_cast(BackgroundStyle::Grid)); 66 | styleCombo->addItem(tr("Lines"), static_cast(BackgroundStyle::Lines)); 67 | 68 | QLabel *colorLabel = new QLabel(tr("Background Color:")); 69 | colorButton = new QPushButton(); 70 | connect(colorButton, &QPushButton::clicked, this, &ControlPanelDialog::chooseColor); 71 | 72 | QLabel *densityLabel = new QLabel(tr("Density:")); 73 | densitySpin = new QSpinBox(); 74 | densitySpin->setRange(10, 200); 75 | densitySpin->setSuffix(" px"); 76 | densitySpin->setSingleStep(5); 77 | 78 | QGridLayout *layout = new QGridLayout(backgroundTab); 79 | layout->addWidget(styleLabel, 0, 0); 80 | layout->addWidget(styleCombo, 0, 1); 81 | layout->addWidget(colorLabel, 1, 0); 82 | layout->addWidget(colorButton, 1, 1); 83 | layout->addWidget(densityLabel, 2, 0); 84 | layout->addWidget(densitySpin, 2, 1); 85 | // layout->setColumnStretch(1, 1); // Stretch the second column 86 | layout->setRowStretch(3, 1); // Stretch the last row 87 | } 88 | 89 | void ControlPanelDialog::chooseColor() { 90 | QColor chosen = QColorDialog::getColor(selectedColor, this, tr("Select Background Color")); 91 | if (chosen.isValid()) { 92 | selectedColor = chosen; 93 | colorButton->setStyleSheet(QString("background-color: %1").arg(selectedColor.name())); 94 | } 95 | } 96 | 97 | void ControlPanelDialog::applyChanges() { 98 | if (!canvas) return; 99 | 100 | BackgroundStyle style = static_cast( 101 | styleCombo->currentData().toInt() 102 | ); 103 | 104 | canvas->setBackgroundStyle(style); 105 | canvas->setBackgroundColor(selectedColor); 106 | canvas->setBackgroundDensity(densitySpin->value()); 107 | canvas->update(); 108 | canvas->saveBackgroundMetadata(); 109 | 110 | // ✅ Save these settings as defaults for new tabs 111 | if (mainWindowRef) { 112 | mainWindowRef->saveDefaultBackgroundSettings(style, selectedColor, densitySpin->value()); 113 | } 114 | 115 | // ✅ Apply button mappings back to MainWindow with internal keys 116 | if (mainWindowRef) { 117 | for (const QString &buttonKey : holdMappingCombos.keys()) { 118 | QString displayString = holdMappingCombos[buttonKey]->currentText(); 119 | QString internalKey = ButtonMappingHelper::displayToInternalKey(displayString, true); // true = isDialMode 120 | mainWindowRef->setHoldMapping(buttonKey, internalKey); 121 | } 122 | for (const QString &buttonKey : pressMappingCombos.keys()) { 123 | QString displayString = pressMappingCombos[buttonKey]->currentText(); 124 | QString internalKey = ButtonMappingHelper::displayToInternalKey(displayString, false); // false = isAction 125 | mainWindowRef->setPressMapping(buttonKey, internalKey); 126 | } 127 | 128 | // ✅ Save to persistent settings 129 | mainWindowRef->saveButtonMappings(); 130 | } 131 | } 132 | 133 | void ControlPanelDialog::loadFromCanvas() { 134 | styleCombo->setCurrentIndex(static_cast(canvas->getBackgroundStyle())); 135 | densitySpin->setValue(canvas->getBackgroundDensity()); 136 | selectedColor = canvas->getBackgroundColor(); 137 | 138 | colorButton->setStyleSheet(QString("background-color: %1").arg(selectedColor.name())); 139 | 140 | if (mainWindowRef) { 141 | for (const QString &buttonKey : holdMappingCombos.keys()) { 142 | QString internalKey = mainWindowRef->getHoldMapping(buttonKey); 143 | QString displayString = ButtonMappingHelper::internalKeyToDisplay(internalKey, true); // true = isDialMode 144 | int index = holdMappingCombos[buttonKey]->findText(displayString); 145 | if (index >= 0) holdMappingCombos[buttonKey]->setCurrentIndex(index); 146 | } 147 | 148 | for (const QString &buttonKey : pressMappingCombos.keys()) { 149 | QString internalKey = mainWindowRef->getPressMapping(buttonKey); 150 | QString displayString = ButtonMappingHelper::internalKeyToDisplay(internalKey, false); // false = isAction 151 | int index = pressMappingCombos[buttonKey]->findText(displayString); 152 | if (index >= 0) pressMappingCombos[buttonKey]->setCurrentIndex(index); 153 | } 154 | } 155 | } 156 | 157 | 158 | void ControlPanelDialog::createPerformanceTab() { 159 | performanceTab = new QWidget(); 160 | QVBoxLayout *layout = new QVBoxLayout(performanceTab); 161 | 162 | QCheckBox *previewToggle = new QCheckBox(tr("Enable Low-Resolution PDF Previews")); 163 | previewToggle->setChecked(mainWindowRef->isLowResPreviewEnabled()); 164 | 165 | connect(previewToggle, &QCheckBox::toggled, mainWindowRef, &MainWindow::setLowResPreviewEnabled); 166 | 167 | QLabel *note = new QLabel(tr("Disabling this may improve dial smoothness on low-end devices.")); 168 | note->setWordWrap(true); 169 | note->setStyleSheet("color: gray; font-size: 10px;"); 170 | 171 | QLabel *dpiLabel = new QLabel(tr("PDF Rendering DPI:")); 172 | QComboBox *dpiSelector = new QComboBox(); 173 | dpiSelector->addItems({"96", "192", "288", "384", "480"}); 174 | dpiSelector->setCurrentText(QString::number(mainWindowRef->getPdfDPI())); 175 | 176 | connect(dpiSelector, &QComboBox::currentTextChanged, this, [=](const QString &value) { 177 | mainWindowRef->setPdfDPI(value.toInt()); 178 | }); 179 | 180 | QLabel *notePDF = new QLabel(tr("Adjust how the PDF is rendered. Higher DPI means better quality but slower performance. DO NOT CHANGE THIS OPTION WHEN MULTIPLE TABS ARE OPEN. THIS MAY LEAD TO UNDEFINED BEHAVIOR!")); 181 | notePDF->setWordWrap(true); 182 | notePDF->setStyleSheet("color: gray; font-size: 10px;"); 183 | 184 | 185 | layout->addWidget(previewToggle); 186 | layout->addWidget(note); 187 | layout->addWidget(dpiLabel); 188 | layout->addWidget(dpiSelector); 189 | layout->addWidget(notePDF); 190 | 191 | layout->addStretch(); 192 | 193 | // return performanceTab; 194 | } 195 | 196 | void ControlPanelDialog::createToolbarTab(){ 197 | toolbarTab = new QWidget(this); 198 | QVBoxLayout *toolbarLayout = new QVBoxLayout(toolbarTab); 199 | 200 | // ✅ Checkbox to show/hide benchmark controls 201 | QCheckBox *benchmarkVisibilityCheckbox = new QCheckBox(tr("Show Benchmark Controls"), toolbarTab); 202 | benchmarkVisibilityCheckbox->setChecked(mainWindowRef->areBenchmarkControlsVisible()); 203 | toolbarLayout->addWidget(benchmarkVisibilityCheckbox); 204 | QLabel *benchmarkNote = new QLabel(tr("This will show/hide the benchmark controls on the toolbar. Press the clock button to start/stop the benchmark.")); 205 | benchmarkNote->setWordWrap(true); 206 | benchmarkNote->setStyleSheet("color: gray; font-size: 10px;"); 207 | toolbarLayout->addWidget(benchmarkNote); 208 | 209 | // ✅ Checkbox to show/hide color buttons 210 | QCheckBox *colorButtonsVisibilityCheckbox = new QCheckBox(tr("Show Color Buttons"), toolbarTab); 211 | colorButtonsVisibilityCheckbox->setChecked(mainWindowRef->areColorButtonsVisible()); 212 | toolbarLayout->addWidget(colorButtonsVisibilityCheckbox); 213 | QLabel *colorButtonsNote = new QLabel(tr("This will show/hide the color buttons on the toolbar")); 214 | colorButtonsNote->setWordWrap(true); 215 | colorButtonsNote->setStyleSheet("color: gray; font-size: 10px;"); 216 | toolbarLayout->addWidget(colorButtonsNote); 217 | 218 | QCheckBox *scrollOnTopCheckBox = new QCheckBox(tr("Scroll on Top after Page Switching"), toolbarTab); 219 | scrollOnTopCheckBox->setChecked(mainWindowRef->isScrollOnTopEnabled()); 220 | toolbarLayout->addWidget(scrollOnTopCheckBox); 221 | QLabel *scrollNote = new QLabel(tr("Enabling this will make the page scroll to the top after switching to a new page.")); 222 | scrollNote->setWordWrap(true); 223 | scrollNote->setStyleSheet("color: gray; font-size: 10px;"); 224 | toolbarLayout->addWidget(scrollNote); 225 | 226 | // ✅ Checkbox to enable/disable touch gestures 227 | QCheckBox *touchGesturesCheckbox = new QCheckBox(tr("Enable Touch Gestures"), toolbarTab); 228 | touchGesturesCheckbox->setChecked(mainWindowRef->areTouchGesturesEnabled()); 229 | toolbarLayout->addWidget(touchGesturesCheckbox); 230 | QLabel *touchGesturesNote = new QLabel(tr("Enable pinch to zoom and touch panning on the canvas. When disabled, only pen input is accepted.")); 231 | touchGesturesNote->setWordWrap(true); 232 | touchGesturesNote->setStyleSheet("color: gray; font-size: 10px;"); 233 | toolbarLayout->addWidget(touchGesturesNote); 234 | 235 | toolbarLayout->addStretch(); 236 | toolbarTab->setLayout(toolbarLayout); 237 | tabWidget->addTab(toolbarTab, tr("Features")); 238 | 239 | 240 | // Connect the checkbox 241 | connect(benchmarkVisibilityCheckbox, &QCheckBox::toggled, mainWindowRef, &MainWindow::setBenchmarkControlsVisible); 242 | connect(colorButtonsVisibilityCheckbox, &QCheckBox::toggled, mainWindowRef, &MainWindow::setColorButtonsVisible); 243 | connect(scrollOnTopCheckBox, &QCheckBox::toggled, mainWindowRef, &MainWindow::setScrollOnTopEnabled); 244 | connect(touchGesturesCheckbox, &QCheckBox::toggled, mainWindowRef, &MainWindow::setTouchGesturesEnabled); 245 | } 246 | 247 | 248 | void ControlPanelDialog::createButtonMappingTab() { 249 | QWidget *buttonTab = new QWidget(this); 250 | QVBoxLayout *layout = new QVBoxLayout(buttonTab); 251 | 252 | QStringList buttonKeys = ButtonMappingHelper::getInternalButtonKeys(); 253 | QStringList buttonDisplayNames = ButtonMappingHelper::getTranslatedButtons(); 254 | QStringList dialModes = ButtonMappingHelper::getTranslatedDialModes(); 255 | QStringList actions = ButtonMappingHelper::getTranslatedActions(); 256 | 257 | for (int i = 0; i < buttonKeys.size(); ++i) { 258 | const QString &buttonKey = buttonKeys[i]; 259 | const QString &buttonDisplayName = buttonDisplayNames[i]; 260 | 261 | QHBoxLayout *h = new QHBoxLayout(); 262 | h->addWidget(new QLabel(buttonDisplayName)); // Use translated button name 263 | 264 | QComboBox *holdCombo = new QComboBox(); 265 | holdCombo->addItems(dialModes); // Add translated dial mode names 266 | holdMappingCombos[buttonKey] = holdCombo; 267 | h->addWidget(new QLabel(tr("Hold:"))); 268 | h->addWidget(holdCombo); 269 | 270 | QComboBox *pressCombo = new QComboBox(); 271 | pressCombo->addItems(actions); // Add translated action names 272 | pressMappingCombos[buttonKey] = pressCombo; 273 | h->addWidget(new QLabel(tr("Press:"))); 274 | h->addWidget(pressCombo); 275 | 276 | layout->addLayout(h); 277 | } 278 | 279 | layout->addStretch(); 280 | buttonTab->setLayout(layout); 281 | tabWidget->addTab(buttonTab, tr("Button Mapping")); 282 | } 283 | 284 | void ControlPanelDialog::createKeyboardMappingTab() { 285 | keyboardTab = new QWidget(this); 286 | QVBoxLayout *layout = new QVBoxLayout(keyboardTab); 287 | 288 | // Instructions 289 | QLabel *instructionLabel = new QLabel(tr("Configure custom keyboard shortcuts for application actions:"), keyboardTab); 290 | instructionLabel->setWordWrap(true); 291 | layout->addWidget(instructionLabel); 292 | 293 | // Table to show current mappings 294 | keyboardTable = new QTableWidget(0, 2, keyboardTab); 295 | keyboardTable->setHorizontalHeaderLabels({tr("Key Sequence"), tr("Action")}); 296 | keyboardTable->horizontalHeader()->setStretchLastSection(true); 297 | keyboardTable->setSelectionBehavior(QAbstractItemView::SelectRows); 298 | keyboardTable->setEditTriggers(QAbstractItemView::NoEditTriggers); 299 | layout->addWidget(keyboardTable); 300 | 301 | // Buttons 302 | QHBoxLayout *buttonLayout = new QHBoxLayout(); 303 | addKeyboardMappingButton = new QPushButton(tr("Add Mapping"), keyboardTab); 304 | removeKeyboardMappingButton = new QPushButton(tr("Remove Mapping"), keyboardTab); 305 | 306 | buttonLayout->addWidget(addKeyboardMappingButton); 307 | buttonLayout->addWidget(removeKeyboardMappingButton); 308 | buttonLayout->addStretch(); 309 | 310 | layout->addLayout(buttonLayout); 311 | 312 | // Connections 313 | connect(addKeyboardMappingButton, &QPushButton::clicked, this, &ControlPanelDialog::addKeyboardMapping); 314 | connect(removeKeyboardMappingButton, &QPushButton::clicked, this, &ControlPanelDialog::removeKeyboardMapping); 315 | 316 | // Load current mappings 317 | if (mainWindowRef) { 318 | QMap mappings = mainWindowRef->getKeyboardMappings(); 319 | keyboardTable->setRowCount(mappings.size()); 320 | int row = 0; 321 | for (auto it = mappings.begin(); it != mappings.end(); ++it) { 322 | keyboardTable->setItem(row, 0, new QTableWidgetItem(it.key())); 323 | QString displayAction = ButtonMappingHelper::internalKeyToDisplay(it.value(), false); 324 | keyboardTable->setItem(row, 1, new QTableWidgetItem(displayAction)); 325 | row++; 326 | } 327 | } 328 | 329 | tabWidget->addTab(keyboardTab, tr("Keyboard Shortcuts")); 330 | } 331 | 332 | void ControlPanelDialog::addKeyboardMapping() { 333 | // Step 1: Capture key sequence 334 | KeyCaptureDialog captureDialog(this); 335 | if (captureDialog.exec() != QDialog::Accepted) { 336 | return; 337 | } 338 | 339 | QString keySequence = captureDialog.getCapturedKeySequence(); 340 | if (keySequence.isEmpty()) { 341 | return; 342 | } 343 | 344 | // Check if key sequence already exists 345 | if (mainWindowRef && mainWindowRef->getKeyboardMappings().contains(keySequence)) { 346 | QMessageBox::warning(this, tr("Key Already Mapped"), 347 | tr("The key sequence '%1' is already mapped. Please choose a different key combination.").arg(keySequence)); 348 | return; 349 | } 350 | 351 | // Step 2: Choose action 352 | QStringList actions = ButtonMappingHelper::getTranslatedActions(); 353 | bool ok; 354 | QString selectedAction = QInputDialog::getItem(this, tr("Select Action"), 355 | tr("Choose the action to perform when '%1' is pressed:").arg(keySequence), 356 | actions, 0, false, &ok); 357 | 358 | if (!ok || selectedAction.isEmpty()) { 359 | return; 360 | } 361 | 362 | // Convert display name to internal key 363 | QString internalKey = ButtonMappingHelper::displayToInternalKey(selectedAction, false); 364 | 365 | // Add the mapping 366 | if (mainWindowRef) { 367 | mainWindowRef->addKeyboardMapping(keySequence, internalKey); 368 | 369 | // Update table 370 | int row = keyboardTable->rowCount(); 371 | keyboardTable->insertRow(row); 372 | keyboardTable->setItem(row, 0, new QTableWidgetItem(keySequence)); 373 | keyboardTable->setItem(row, 1, new QTableWidgetItem(selectedAction)); 374 | } 375 | } 376 | 377 | void ControlPanelDialog::removeKeyboardMapping() { 378 | int currentRow = keyboardTable->currentRow(); 379 | if (currentRow < 0) { 380 | QMessageBox::information(this, tr("No Selection"), tr("Please select a mapping to remove.")); 381 | return; 382 | } 383 | 384 | QTableWidgetItem *keyItem = keyboardTable->item(currentRow, 0); 385 | if (!keyItem) return; 386 | 387 | QString keySequence = keyItem->text(); 388 | 389 | // Confirm removal 390 | int ret = QMessageBox::question(this, tr("Remove Mapping"), 391 | tr("Are you sure you want to remove the keyboard shortcut '%1'?").arg(keySequence), 392 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); 393 | 394 | if (ret == QMessageBox::Yes) { 395 | // Remove from MainWindow 396 | if (mainWindowRef) { 397 | mainWindowRef->removeKeyboardMapping(keySequence); 398 | } 399 | 400 | // Remove from table 401 | keyboardTable->removeRow(currentRow); 402 | } 403 | } 404 | -------------------------------------------------------------------------------- /ControlPanelDialog.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTROLPANELDIALOG_H 2 | #define CONTROLPANELDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "InkCanvas.h" // Needed for BackgroundStyle enum 15 | #include "MainWindow.h" 16 | #include "KeyCaptureDialog.h" 17 | 18 | class ControlPanelDialog : public QDialog { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit ControlPanelDialog(MainWindow *mainWindow, InkCanvas *targetCanvas, QWidget *parent = nullptr); 23 | 24 | private slots: 25 | void applyChanges(); 26 | void chooseColor(); 27 | void addKeyboardMapping(); // New: add keyboard shortcut 28 | void removeKeyboardMapping(); // New: remove keyboard shortcut 29 | 30 | private: 31 | InkCanvas *canvas; 32 | 33 | QTabWidget *tabWidget; 34 | QWidget *backgroundTab; 35 | 36 | QComboBox *styleCombo; 37 | QPushButton *colorButton; 38 | QSpinBox *densitySpin; 39 | 40 | QPushButton *applyButton; 41 | QPushButton *okButton; 42 | QPushButton *cancelButton; 43 | 44 | QColor selectedColor; 45 | 46 | void createBackgroundTab(); 47 | void loadFromCanvas(); 48 | 49 | MainWindow *mainWindowRef; 50 | InkCanvas *canvasRef; 51 | QWidget *performanceTab; 52 | QWidget *toolbarTab; 53 | void createToolbarTab(); 54 | void createPerformanceTab(); 55 | 56 | QWidget *controllerMappingTab; 57 | 58 | // Mapping comboboxes for hold and press 59 | QMap holdMappingCombos; 60 | QMap pressMappingCombos; 61 | 62 | void createButtonMappingTab(); 63 | void createKeyboardMappingTab(); // New: keyboard mapping tab 64 | 65 | // Keyboard mapping widgets 66 | QWidget *keyboardTab; 67 | QTableWidget *keyboardTable; 68 | QPushButton *addKeyboardMappingButton; 69 | QPushButton *removeKeyboardMappingButton; 70 | }; 71 | 72 | #endif // CONTROLPANELDIALOG_H 73 | -------------------------------------------------------------------------------- /InkCanvas.h: -------------------------------------------------------------------------------- 1 | #ifndef INKCANVAS_H 2 | #define INKCANVAS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "ToolType.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | enum class BackgroundStyle { 18 | None, 19 | Grid, 20 | Lines 21 | }; 22 | 23 | class InkCanvas : public QWidget { 24 | Q_OBJECT 25 | 26 | signals: 27 | void zoomChanged(int newZoom); 28 | void panChanged(int panX, int panY); 29 | void touchGestureEnded(); // Signal emitted when touch gestures end 30 | 31 | public: 32 | explicit InkCanvas(QWidget *parent = nullptr); 33 | virtual ~InkCanvas(); 34 | 35 | void startBenchmark(); 36 | void stopBenchmark(); 37 | int getProcessedRate(); 38 | void setPenColor(const QColor &color); // Added function to set pen color 39 | void setPenThickness(qreal thickness); // Added function to set pen thickness 40 | void setTool(ToolType tool); 41 | void setSaveFolder(const QString &folderPath); // Function to set save folder 42 | void saveToFile(int pageNumber); // Function to save canvas to file 43 | void saveCurrentPage(); // ✅ New function (see below) 44 | void loadPage(int pageNumber); 45 | void deletePage(int pageNumber); 46 | void setBackground(const QString &filePath, int pageNumber); 47 | void saveAnnotated(int pageNumber); 48 | 49 | void setZoom(int zoomLevel); 50 | int getZoom() const; 51 | QSize getCanvasSize() const; 52 | void updatePanOffsets(int xOffset, int yOffset); 53 | 54 | int getPanOffsetX() const; // Getter for panOffsetX 55 | int getPanOffsetY() const; // Getter for panOffsetY 56 | 57 | void setPanX(int xOffset); // Setter for panOffsetX 58 | void setPanY(int yOffset); // Setter for panOffsetY 59 | 60 | void loadPdf(const QString &pdfPath); 61 | void loadPdfPage(int pageNumber); 62 | 63 | bool isPdfLoadedFunc() const; 64 | int getTotalPdfPages() const; 65 | 66 | void clearPdf(); 67 | void clearPdfNoDelete(); 68 | 69 | QString getSaveFolder() const; 70 | 71 | void setLastActivePage(int page) { lastActivePage = page; } 72 | int getLastActivePage() const { return lastActivePage; } 73 | // ✅ Zoom & Pan Management 74 | void setLastZoomLevel(int zoom) { lastZoomLevel = zoom; } 75 | int getLastZoomLevel() const { return lastZoomLevel; } 76 | 77 | void setLastPanX(int pan) { lastPanX = pan; } 78 | int getLastPanX() const { return lastPanX; } 79 | 80 | void setLastPanY(int pan) { lastPanY = pan; } 81 | int getLastPanY() const { return lastPanY; } 82 | QColor getPenColor(); // Added getter for pen color 83 | qreal getPenThickness(); // Added getter for pen thickness 84 | ToolType getCurrentTool(); // Added getter for tool type 85 | 86 | // Straight line mode toggle 87 | void setStraightLineMode(bool enabled) { straightLineMode = enabled; } 88 | bool isStraightLineMode() const { return straightLineMode; } 89 | 90 | // Rope tool mode toggle 91 | void setRopeToolMode(bool enabled) { ropeToolMode = enabled; } 92 | bool isRopeToolMode() const { return ropeToolMode; } 93 | 94 | void loadPdfPreviewAsync(int pageNumber); // ✅ Load a quick preview of the PDF page 95 | // for notebook background below 96 | void setBackgroundStyle(BackgroundStyle style); 97 | void setBackgroundColor(const QColor &color); 98 | void setBackgroundDensity(int density); 99 | 100 | BackgroundStyle getBackgroundStyle() const { return backgroundStyle; } 101 | QColor getBackgroundColor() const { return backgroundColor; } 102 | int getBackgroundDensity() const { return backgroundDensity; } 103 | 104 | void saveBackgroundMetadata(); // ✅ Save background metadata 105 | 106 | int getBufferWidth() const { return buffer.width(); } 107 | 108 | void exportNotebook(const QString &destinationFile); 109 | void importNotebook(const QString &packageFile); 110 | 111 | void importNotebookTo(const QString &packageFile, const QString &destFolder); 112 | 113 | bool isEdited() const { return edited; } // ✅ Check if the canvas has been edited 114 | 115 | void setPDFRenderDPI(int dpi) { pdfRenderDPI = dpi; } // ✅ Set PDF render DPI 116 | 117 | void clearPdfCache() { pdfCache.clear(); } 118 | 119 | // Touch gesture support 120 | void setTouchGesturesEnabled(bool enabled) { touchGesturesEnabled = enabled; } 121 | bool areTouchGesturesEnabled() const { return touchGesturesEnabled; } 122 | 123 | protected: 124 | void paintEvent(QPaintEvent *event) override; 125 | void tabletEvent(QTabletEvent *event) override; 126 | void mousePressEvent(QMouseEvent *event) override; 127 | void mouseMoveEvent(QMouseEvent *event) override; 128 | void mouseReleaseEvent(QMouseEvent *event) override; 129 | void resizeEvent(QResizeEvent *event) override; // Handle resizing 130 | 131 | // Touch event handling 132 | bool event(QEvent *event) override; 133 | 134 | private: 135 | QPointF mapLogicalWidgetToPhysicalBuffer(const QPointF& logicalWidgetPoint); 136 | QRect mapRectBufferToWidgetLogical(const QRectF& physicalBufferRect); 137 | 138 | QPixmap buffer; // Off-screen buffer 139 | QImage background; 140 | QPointF lastPoint; 141 | QPointF straightLineStartPoint; // Stores the start point for straight line mode 142 | bool drawing; 143 | QColor penColor; // Added pen color property 144 | qreal penThickness; // Added pen thickness property 145 | ToolType currentTool; 146 | ToolType previousTool; // To restore tool after erasing 147 | QString saveFolder; // Folder to save images 148 | QPixmap backgroundImage; 149 | bool straightLineMode = false; // Flag for straight line mode 150 | bool ropeToolMode = false; // Flag for rope tool mode 151 | QPixmap selectionBuffer; // Buffer for the selected area in rope tool mode (physical pixels, masked) 152 | QRect selectionRect; // Bounding rectangle of the current selection in LOGICAL WIDGET coordinates 153 | QRectF exactSelectionRectF; // Floating-point version for smoother movement 154 | QPolygonF lassoPathPoints; // Points of the lasso selection in LOGICAL WIDGET coordinates 155 | bool selectingWithRope = false; // True if currently drawing the lasso 156 | bool movingSelection = false; // True if currently moving the selection 157 | QPointF lastMovePoint; // Last point during selection movement (logical widget coordinates) 158 | 159 | int zoomFactor; // Zoom percentage (100 = normal) 160 | int panOffsetX; // Horizontal pan offset 161 | int panOffsetY; // Vertical pan offset 162 | 163 | // Internal floating-point zoom for smoother gestures 164 | qreal internalZoomFactor = 100.0; 165 | 166 | void initializeBuffer(); // Helper to initialize the buffer 167 | void drawStroke(const QPointF &start, const QPointF &end, qreal pressure); 168 | void eraseStroke(const QPointF &start, const QPointF &end, qreal pressure); 169 | QRectF calculatePreviewRect(const QPointF &start, const QPointF &oldEnd, const QPointF &newEnd); 170 | 171 | 172 | QCache pdfCache; // Caches 5 pages of the PDF 173 | std::unique_ptr pdfDocument; 174 | int currentPdfPage; 175 | bool isPdfLoaded = false; 176 | int totalPdfPages = 0; 177 | 178 | int lastActivePage = 0; // ✅ Stores last active page per tab 179 | int lastZoomLevel = 100; // ✅ Default zoom level 180 | int lastPanX = 0; // ✅ Default pan X 181 | int lastPanY = 0; // ✅ Default pan Y 182 | 183 | // QImage *pdfImage = nullptr; // ✅ Image for the current PDF page 184 | 185 | bool edited = false; // ✅ Track if the canvas has been edited 186 | 187 | bool benchmarking; 188 | std::deque processedTimestamps; 189 | QElapsedTimer benchmarkTimer; 190 | 191 | QString notebookId; 192 | 193 | void loadNotebookId(); 194 | void saveNotebookId(); 195 | 196 | int pdfRenderDPI = 288; // Default to 288 DPI 197 | 198 | // Touch gesture support 199 | bool touchGesturesEnabled = false; 200 | QPointF lastTouchPos; 201 | qreal lastPinchScale = 1.0; 202 | bool isPanning = false; 203 | int activeTouchPoints = 0; 204 | 205 | // Background style members 206 | BackgroundStyle backgroundStyle = BackgroundStyle::None; 207 | QColor backgroundColor = Qt::transparent; 208 | int backgroundDensity = 40; // pixels between lines 209 | }; 210 | 211 | #endif // INKCANVAS_H -------------------------------------------------------------------------------- /KeyCaptureDialog.cpp: -------------------------------------------------------------------------------- 1 | #include "KeyCaptureDialog.h" 2 | #include 3 | 4 | KeyCaptureDialog::KeyCaptureDialog(QWidget *parent) : QDialog(parent) { 5 | setWindowTitle(tr("Capture Key Sequence")); 6 | setFixedSize(350, 150); 7 | setModal(true); 8 | 9 | // Create UI elements 10 | instructionLabel = new QLabel(tr("Press the key combination you want to use:"), this); 11 | instructionLabel->setWordWrap(true); 12 | 13 | capturedLabel = new QLabel(tr("(No key captured yet)"), this); 14 | capturedLabel->setStyleSheet("QLabel { background-color: #f0f0f0; padding: 8px; border: 1px solid #ccc; }"); 15 | capturedLabel->setAlignment(Qt::AlignCenter); 16 | 17 | // Buttons 18 | clearButton = new QPushButton(tr("Clear"), this); 19 | okButton = new QPushButton(tr("OK"), this); 20 | cancelButton = new QPushButton(tr("Cancel"), this); 21 | 22 | okButton->setDefault(true); 23 | okButton->setEnabled(false); // Disabled until a key is captured 24 | 25 | // Layout 26 | QVBoxLayout *mainLayout = new QVBoxLayout(this); 27 | mainLayout->addWidget(instructionLabel); 28 | mainLayout->addWidget(capturedLabel); 29 | 30 | QHBoxLayout *buttonLayout = new QHBoxLayout(); 31 | buttonLayout->addWidget(clearButton); 32 | buttonLayout->addStretch(); 33 | buttonLayout->addWidget(okButton); 34 | buttonLayout->addWidget(cancelButton); 35 | 36 | mainLayout->addLayout(buttonLayout); 37 | 38 | // Connections 39 | connect(clearButton, &QPushButton::clicked, this, &KeyCaptureDialog::clearSequence); 40 | connect(okButton, &QPushButton::clicked, this, &QDialog::accept); 41 | connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject); 42 | 43 | // Set focus to capture keys immediately 44 | setFocus(); 45 | } 46 | 47 | void KeyCaptureDialog::keyPressEvent(QKeyEvent *event) { 48 | // Build key sequence string 49 | QStringList modifiers; 50 | 51 | if (event->modifiers() & Qt::ControlModifier) modifiers << "Ctrl"; 52 | if (event->modifiers() & Qt::ShiftModifier) modifiers << "Shift"; 53 | if (event->modifiers() & Qt::AltModifier) modifiers << "Alt"; 54 | if (event->modifiers() & Qt::MetaModifier) modifiers << "Meta"; 55 | 56 | // Don't capture modifier keys alone 57 | if (event->key() == Qt::Key_Control || event->key() == Qt::Key_Shift || 58 | event->key() == Qt::Key_Alt || event->key() == Qt::Key_Meta) { 59 | return; 60 | } 61 | 62 | // Don't capture Escape (let it close the dialog) 63 | if (event->key() == Qt::Key_Escape) { 64 | QDialog::keyPressEvent(event); 65 | return; 66 | } 67 | 68 | QString keyString = QKeySequence(event->key()).toString(); 69 | 70 | if (!modifiers.isEmpty()) { 71 | capturedSequence = modifiers.join("+") + "+" + keyString; 72 | } else { 73 | capturedSequence = keyString; 74 | } 75 | 76 | updateDisplay(); 77 | event->accept(); 78 | } 79 | 80 | void KeyCaptureDialog::clearSequence() { 81 | capturedSequence.clear(); 82 | updateDisplay(); 83 | setFocus(); // Return focus to dialog for key capture 84 | } 85 | 86 | void KeyCaptureDialog::updateDisplay() { 87 | if (capturedSequence.isEmpty()) { 88 | capturedLabel->setText(tr("(No key captured yet)")); 89 | okButton->setEnabled(false); 90 | } else { 91 | capturedLabel->setText(capturedSequence); 92 | okButton->setEnabled(true); 93 | } 94 | } -------------------------------------------------------------------------------- /KeyCaptureDialog.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYCAPTUREDIALOG_H 2 | #define KEYCAPTUREDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class KeyCaptureDialog : public QDialog { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit KeyCaptureDialog(QWidget *parent = nullptr); 16 | QString getCapturedKeySequence() const { return capturedSequence; } 17 | 18 | protected: 19 | void keyPressEvent(QKeyEvent *event) override; 20 | 21 | private slots: 22 | void clearSequence(); 23 | 24 | private: 25 | QLabel *instructionLabel; 26 | QLabel *capturedLabel; 27 | QPushButton *clearButton; 28 | QPushButton *okButton; 29 | QPushButton *cancelButton; 30 | QString capturedSequence; 31 | 32 | void updateDisplay(); 33 | }; 34 | 35 | #endif // KEYCAPTUREDIALOG_H -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 alpha-liu-01 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Main.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "MainWindow.h" 13 | 14 | int main(int argc, char *argv[]) { 15 | #ifdef _WIN32 16 | FreeConsole(); // Hide console safely on Windows 17 | 18 | /* 19 | AllocConsole(); 20 | freopen("CONOUT$", "w", stdout); 21 | freopen("CONOUT$", "w", stderr); 22 | */ 23 | 24 | // to show console for debugging 25 | 26 | 27 | #endif 28 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "1"); 29 | SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); 30 | SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK); 31 | 32 | /* 33 | qDebug() << "SDL2 version:" << SDL_GetRevision(); 34 | qDebug() << "Num Joysticks:" << SDL_NumJoysticks(); 35 | 36 | for (int i = 0; i < SDL_NumJoysticks(); ++i) { 37 | if (SDL_IsGameController(i)) { 38 | qDebug() << "Controller" << i << "is" << SDL_GameControllerNameForIndex(i); 39 | } else { 40 | qDebug() << "Joystick" << i << "is not a recognized controller"; 41 | } 42 | } 43 | */ // For sdl2 debugging 44 | 45 | 46 | 47 | qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); // ✅ Enable Virtual Keyboard 48 | QApplication app(argc, argv); 49 | 50 | 51 | QTranslator translator; 52 | QString locale = QLocale::system().name(); // e.g., "zh_CN", "es_ES" 53 | QString langCode = locale.section('_', 0, 0); // e.g., "zh" 54 | 55 | // printf("Locale: %s\n", locale.toStdString().c_str()); 56 | // printf("Language Code: %s\n", langCode.toStdString().c_str()); 57 | 58 | // QString locale = "es-ES"; // e.g., "zh_CN", "es_ES" 59 | // QString langCode = "es"; // e.g., "zh" 60 | QString translationsPath = QCoreApplication::applicationDirPath(); 61 | 62 | if (translator.load(translationsPath + "/app_" + langCode + ".qm")) { 63 | app.installTranslator(&translator); 64 | } 65 | 66 | QString notebookFile; 67 | if (argc >= 2) { 68 | notebookFile = QString::fromLocal8Bit(argv[1]); 69 | // qDebug() << "Notebook file received:" << notebookFile; 70 | } 71 | 72 | MainWindow w; 73 | if (!notebookFile.isEmpty()) { 74 | w.importNotebookFromFile(notebookFile); 75 | } 76 | w.show(); 77 | return app.exec(); 78 | } 79 | -------------------------------------------------------------------------------- /MainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "InkCanvas.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "SDLControllerManager.h" 22 | #include "ButtonMappingTypes.h" 23 | #include "RecentNotebooksManager.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | // #include "HandwritingLineEdit.h" 31 | 32 | enum DialMode { 33 | None, 34 | PageSwitching, 35 | ZoomControl, 36 | ThicknessControl, 37 | ColorAdjustment, 38 | ToolSwitching, 39 | PresetSelection, 40 | PanAndPageScroll 41 | }; 42 | 43 | enum class ControllerAction { 44 | None, 45 | ToggleFullscreen, 46 | ToggleDial, 47 | Zoom50, 48 | ZoomOut, 49 | Zoom200, 50 | AddPreset, 51 | DeletePage, 52 | FastForward, 53 | OpenControlPanel, 54 | RedColor, 55 | BlueColor, 56 | YellowColor, 57 | GreenColor, 58 | BlackColor, 59 | WhiteColor, 60 | CustomColor, 61 | ToggleSidebar, 62 | Save, 63 | StraightLineTool, 64 | RopeTool, 65 | SetPenTool, 66 | SetMarkerTool, 67 | SetEraserTool 68 | }; 69 | 70 | static QString actionToString(ControllerAction action) { 71 | switch (action) { 72 | case ControllerAction::ToggleFullscreen: return "Toggle Fullscreen"; 73 | case ControllerAction::ToggleDial: return "Toggle Dial"; 74 | case ControllerAction::Zoom50: return "Zoom 50%"; 75 | case ControllerAction::ZoomOut: return "Zoom Out"; 76 | case ControllerAction::Zoom200: return "Zoom 200%"; 77 | case ControllerAction::AddPreset: return "Add Preset"; 78 | case ControllerAction::DeletePage: return "Delete Page"; 79 | case ControllerAction::FastForward: return "Fast Forward"; 80 | case ControllerAction::OpenControlPanel: return "Open Control Panel"; 81 | case ControllerAction::RedColor: return "Red"; 82 | case ControllerAction::BlueColor: return "Blue"; 83 | case ControllerAction::YellowColor: return "Yellow"; 84 | case ControllerAction::GreenColor: return "Green"; 85 | case ControllerAction::BlackColor: return "Black"; 86 | case ControllerAction::WhiteColor: return "White"; 87 | case ControllerAction::CustomColor: return "Custom Color"; 88 | case ControllerAction::ToggleSidebar: return "Toggle Sidebar"; 89 | case ControllerAction::Save: return "Save"; 90 | case ControllerAction::StraightLineTool: return "Straight Line Tool"; 91 | case ControllerAction::RopeTool: return "Rope Tool"; 92 | case ControllerAction::SetPenTool: return "Set Pen Tool"; 93 | case ControllerAction::SetMarkerTool: return "Set Marker Tool"; 94 | case ControllerAction::SetEraserTool: return "Set Eraser Tool"; 95 | default: return "None"; 96 | } 97 | } 98 | 99 | static ControllerAction stringToAction(const QString &str) { 100 | // Convert internal key to ControllerAction enum 101 | InternalControllerAction internalAction = ButtonMappingHelper::internalKeyToAction(str); 102 | 103 | switch (internalAction) { 104 | case InternalControllerAction::None: return ControllerAction::None; 105 | case InternalControllerAction::ToggleFullscreen: return ControllerAction::ToggleFullscreen; 106 | case InternalControllerAction::ToggleDial: return ControllerAction::ToggleDial; 107 | case InternalControllerAction::Zoom50: return ControllerAction::Zoom50; 108 | case InternalControllerAction::ZoomOut: return ControllerAction::ZoomOut; 109 | case InternalControllerAction::Zoom200: return ControllerAction::Zoom200; 110 | case InternalControllerAction::AddPreset: return ControllerAction::AddPreset; 111 | case InternalControllerAction::DeletePage: return ControllerAction::DeletePage; 112 | case InternalControllerAction::FastForward: return ControllerAction::FastForward; 113 | case InternalControllerAction::OpenControlPanel: return ControllerAction::OpenControlPanel; 114 | case InternalControllerAction::RedColor: return ControllerAction::RedColor; 115 | case InternalControllerAction::BlueColor: return ControllerAction::BlueColor; 116 | case InternalControllerAction::YellowColor: return ControllerAction::YellowColor; 117 | case InternalControllerAction::GreenColor: return ControllerAction::GreenColor; 118 | case InternalControllerAction::BlackColor: return ControllerAction::BlackColor; 119 | case InternalControllerAction::WhiteColor: return ControllerAction::WhiteColor; 120 | case InternalControllerAction::CustomColor: return ControllerAction::CustomColor; 121 | case InternalControllerAction::ToggleSidebar: return ControllerAction::ToggleSidebar; 122 | case InternalControllerAction::Save: return ControllerAction::Save; 123 | case InternalControllerAction::StraightLineTool: return ControllerAction::StraightLineTool; 124 | case InternalControllerAction::RopeTool: return ControllerAction::RopeTool; 125 | case InternalControllerAction::SetPenTool: return ControllerAction::SetPenTool; 126 | case InternalControllerAction::SetMarkerTool: return ControllerAction::SetMarkerTool; 127 | case InternalControllerAction::SetEraserTool: return ControllerAction::SetEraserTool; 128 | } 129 | return ControllerAction::None; 130 | } 131 | 132 | class MainWindow : public QMainWindow { 133 | Q_OBJECT 134 | 135 | public: 136 | explicit MainWindow(QWidget *parent = nullptr); 137 | virtual ~MainWindow(); 138 | int getCurrentPageForCanvas(InkCanvas *canvas); 139 | 140 | bool lowResPreviewEnabled = true; 141 | 142 | void setLowResPreviewEnabled(bool enabled); 143 | bool isLowResPreviewEnabled() const; 144 | 145 | bool areBenchmarkControlsVisible() const; 146 | void setBenchmarkControlsVisible(bool visible); 147 | 148 | bool colorButtonsVisible = true; 149 | bool areColorButtonsVisible() const; 150 | void setColorButtonsVisible(bool visible); 151 | 152 | bool scrollOnTopEnabled = false; 153 | bool isScrollOnTopEnabled() const; 154 | void setScrollOnTopEnabled(bool enabled); 155 | 156 | bool touchGesturesEnabled = false; 157 | bool areTouchGesturesEnabled() const; 158 | void setTouchGesturesEnabled(bool enabled); 159 | 160 | SDLControllerManager *controllerManager = nullptr; 161 | QThread *controllerThread = nullptr; 162 | 163 | QString getHoldMapping(const QString &buttonName); 164 | QString getPressMapping(const QString &buttonName); 165 | 166 | void saveButtonMappings(); 167 | void loadButtonMappings(); 168 | 169 | void setHoldMapping(const QString &buttonName, const QString &dialMode); 170 | void setPressMapping(const QString &buttonName, const QString &action); 171 | DialMode dialModeFromString(const QString &mode); 172 | 173 | void importNotebookFromFile(const QString &packageFile); 174 | 175 | int getPdfDPI() const { return pdfRenderDPI; } 176 | void setPdfDPI(int dpi); 177 | 178 | // void loadUserSettings(); // New 179 | void savePdfDPI(int dpi); // New 180 | 181 | // Background settings persistence 182 | void saveDefaultBackgroundSettings(BackgroundStyle style, QColor color, int density); 183 | void loadDefaultBackgroundSettings(BackgroundStyle &style, QColor &color, int &density); 184 | 185 | void migrateOldButtonMappings(); 186 | QString migrateOldDialModeString(const QString &oldString); 187 | QString migrateOldActionString(const QString &oldString); 188 | 189 | InkCanvas* currentCanvas(); // Made public for RecentNotebooksDialog 190 | void saveCurrentPage(); // Made public for RecentNotebooksDialog 191 | void switchPage(int pageNumber); // Made public for RecentNotebooksDialog 192 | void updateTabLabel(); // Made public for RecentNotebooksDialog 193 | QSpinBox *pageInput; // Made public for RecentNotebooksDialog 194 | 195 | // New: Keyboard mapping methods (made public for ControlPanelDialog) 196 | void addKeyboardMapping(const QString &keySequence, const QString &action); 197 | void removeKeyboardMapping(const QString &keySequence); 198 | QMap getKeyboardMappings() const; 199 | 200 | private slots: 201 | void toggleBenchmark(); 202 | void updateBenchmarkDisplay(); 203 | void applyCustomColor(); // Added function for custom color input 204 | void updateThickness(int value); // New function for thickness control 205 | void changeTool(int index); 206 | void selectFolder(); // Select save folder 207 | void saveCanvas(); // Save canvas to file 208 | void saveAnnotated(); 209 | void deleteCurrentPage(); 210 | 211 | void loadPdf(); 212 | void clearPdf(); 213 | 214 | void updateZoom(); 215 | void onZoomSliderChanged(int value); // Handle manual zoom slider changes 216 | void applyZoom(); 217 | void updatePanRange(); 218 | void updatePanX(int value); 219 | void updatePanY(int value); 220 | 221 | void selectBackground(); // Added back 222 | 223 | void forceUIRefresh(); 224 | 225 | void switchTab(int index); 226 | void addNewTab(); 227 | void removeTabAt(int index); 228 | void toggleZoomSlider(); 229 | void toggleThicknessSlider(); // Added function to toggle thickness slider 230 | void toggleFullscreen(); 231 | void showJumpToPageDialog(); 232 | 233 | void toggleDial(); // ✅ Show/Hide dial 234 | void handleDialInput(int angle); // ✅ Handle touch input 235 | void onDialReleased(); 236 | // void processPageSwitch(); 237 | void initializeDialSound(); 238 | 239 | void changeDialMode(DialMode mode); 240 | void handleDialZoom(int angle); 241 | void handleDialThickness(int angle); // Added function to handle thickness control 242 | void onZoomReleased(); 243 | void onThicknessReleased(); // Added function to handle thickness control 244 | void handleDialColor(int angle); // Added function to handle color adjustment 245 | void onColorReleased(); // Added function to handle color adjustment 246 | // void updateCustomColor(); 247 | void updateSelectedChannel(int index); 248 | void updateDialDisplay(); 249 | // void handleModeSelection(int angle); 250 | 251 | void handleToolSelection(int angle); 252 | void onToolReleased(); 253 | void cycleColorChannel(); 254 | 255 | void handlePresetSelection(int angle); 256 | void onPresetReleased(); 257 | void addColorPreset(); 258 | qreal getDevicePixelRatio(); 259 | 260 | bool isDarkMode(); 261 | QIcon loadThemedIcon(const QString& baseName); 262 | 263 | void handleDialPanScroll(int angle); // Add missing function declaration 264 | void onPanScrollReleased(); // Add missing function declaration 265 | 266 | // Touch gesture handlers 267 | void handleTouchZoomChange(int newZoom); 268 | void handleTouchPanChange(int panX, int panY); 269 | void handleTouchGestureEnd(); // Add handler for touch gesture completion 270 | 271 | // Color button state management 272 | void updateColorButtonStates(); 273 | void selectColorButton(QPushButton* selectedButton); 274 | void updateStraightLineButtonState(); 275 | void updateRopeToolButtonState(); // New slot for rope tool button 276 | void updateDialButtonState(); // New method for dial toggle button 277 | void updateFastForwardButtonState(); // New method for fast forward toggle button 278 | 279 | QColor getContrastingTextColor(const QColor &backgroundColor); 280 | void updateCustomColorButtonStyle(const QColor &color); 281 | 282 | void openRecentNotebooksDialog(); // Added slot 283 | 284 | void showPendingTooltip(); // Show tooltip with throttling 285 | 286 | private: 287 | InkCanvas *canvas; 288 | QPushButton *benchmarkButton; 289 | QLabel *benchmarkLabel; 290 | QTimer *benchmarkTimer; 291 | bool benchmarking; 292 | 293 | QPushButton *exportNotebookButton; 294 | QPushButton *importNotebookButton; 295 | 296 | QPushButton *redButton; 297 | QPushButton *blueButton; 298 | QPushButton *yellowButton; 299 | QPushButton *greenButton; 300 | QPushButton *blackButton; 301 | QPushButton *whiteButton; 302 | QLineEdit *customColorInput; 303 | QPushButton *customColorButton; 304 | QPushButton *thicknessButton; // Added thickness button 305 | QSlider *thicknessSlider; // Added thickness slider 306 | QFrame *thicknessFrame; // Added thickness frame 307 | QComboBox *toolSelector; 308 | QPushButton *deletePageButton; 309 | QPushButton *selectFolderButton; // Button to select folder 310 | QPushButton *saveButton; // Button to save file 311 | QPushButton *saveAnnotatedButton; 312 | QPushButton *fullscreenButton; 313 | QPushButton *openControlPanelButton; 314 | QPushButton *openRecentNotebooksButton; // Added button 315 | 316 | QPushButton *loadPdfButton; 317 | QPushButton *clearPdfButton; 318 | QPushButton *toggleTabBarButton; 319 | 320 | QMap pageMap; 321 | 322 | 323 | QPushButton *backgroundButton; // New button to set background 324 | QPushButton *straightLineToggleButton; // Button to toggle straight line mode 325 | QPushButton *ropeToolButton; // Button to toggle rope tool mode 326 | 327 | QSlider *zoomSlider; 328 | QPushButton *zoomButton; 329 | QFrame *zoomFrame; 330 | QPushButton *dezoomButton; 331 | QPushButton *zoom50Button; 332 | QPushButton *zoom200Button; 333 | QWidget *zoomContainer; 334 | QLineEdit *zoomInput; 335 | QScrollBar *panXSlider; 336 | QScrollBar *panYSlider; 337 | 338 | 339 | QListWidget *tabList; // Sidebar for tabs 340 | QStackedWidget *canvasStack; // Holds multiple InkCanvas instances 341 | QPushButton *addTabButton; // Button to add tabs 342 | QPushButton *jumpToPageButton; // Button to jump to a specific page 343 | 344 | QWidget *dialContainer = nullptr; // ✅ Floating dial container 345 | QDial *pageDial = nullptr; // ✅ The dial itself 346 | QDial *modeDial = nullptr; // ✅ Mode dial 347 | QPushButton *dialToggleButton; // ✅ Toggle button 348 | bool fastForwardMode = false; // ✅ Toggle fast forward 349 | QPushButton *fastForwardButton; // ✅ Fast forward button 350 | int lastAngle = 0; 351 | int startAngle = 0; 352 | bool tracking = false; 353 | int accumulatedRotation = 0; 354 | QSoundEffect *dialClickSound = nullptr; 355 | 356 | int grossTotalClicks = 0; 357 | 358 | /* 359 | enum DialMode { 360 | PageSwitching, 361 | ZoomControl, 362 | PenThickness, 363 | ColorAdjustment 364 | }; 365 | 366 | DialMode currentDialMode = PageSwitching; ✅ Default mode 367 | 368 | QComboBox *dialModeSelector; ✅ Mode selector 369 | QComboBox *channelSelector; ✅ Channel selector 370 | int selectedChannel = 0; ✅ Default channel 371 | */ 372 | 373 | DialMode currentDialMode = PanAndPageScroll; // ✅ Default mode 374 | DialMode temporaryDialMode = None; 375 | 376 | QComboBox *dialModeSelector; // ✅ Mode selector 377 | QComboBox *channelSelector; // ✅ Channel selector 378 | int selectedChannel = 0; // ✅ Default channel 379 | QPushButton *colorPreview; // ✅ Color preview 380 | 381 | QLabel *dialDisplay = nullptr; // ✅ Display for dial mode 382 | 383 | QFrame *dialColorPreview; 384 | QLabel *dialIconView; 385 | QFont pixelFont; // ✅ Font for pixel effect 386 | // QLabel *modeIndicator; ✅ Indicator for mode selection 387 | // QLabel *dialNeedle; 388 | 389 | QPushButton *btnPageSwitch; 390 | QPushButton *btnZoom; 391 | QPushButton *btnThickness; 392 | QPushButton *btnColor; 393 | QPushButton *btnTool; 394 | QPushButton *btnPresets; 395 | QPushButton *btnPannScroll; 396 | int tempClicks = 0; 397 | 398 | QPushButton *dialHiddenButton; // ✅ Invisible tap button over OLED display 399 | 400 | QQueue colorPresets; // ✅ FIFO queue for color presets 401 | QPushButton *addPresetButton; // ✅ Button to add current color to queue 402 | int currentPresetIndex = 0; // ✅ Track selected preset 403 | 404 | qreal initialDpr = 1.0; // Will be set in constructor 405 | 406 | QWidget *sidebarContainer; // Container for sidebar 407 | QWidget *controlBar; // Control toolbar 408 | 409 | void setTemporaryDialMode(DialMode mode); 410 | void clearTemporaryDialMode(); 411 | 412 | bool controlBarVisible = true; // Track controlBar visibility state 413 | void toggleControlBar(); // Function to toggle controlBar visibility 414 | bool sidebarWasVisibleBeforeFullscreen = true; // Track sidebar state before fullscreen 415 | 416 | int accumulatedRotationAfterLimit = 0; 417 | 418 | int pendingPageFlip = 0; // -1 for previous, +1 for next, 0 for no flip. This is used for mode PanAndPageScroll 419 | 420 | // Add in MainWindow class: 421 | QMap buttonHoldMapping; 422 | QMap buttonPressMapping; 423 | QMap buttonPressActionMapping; 424 | 425 | // New: Keyboard mapping support 426 | QMap keyboardMappings; // keySequence -> action internal key 427 | QMap keyboardActionMapping; // keySequence -> action enum 428 | 429 | // Tooltip handling for pen input 430 | QTimer *tooltipTimer; 431 | QWidget *lastHoveredWidget; 432 | QPoint pendingTooltipPos; 433 | 434 | void handleButtonHeld(const QString &buttonName); 435 | void handleButtonReleased(const QString &buttonName); 436 | 437 | void handleControllerButton(const QString &buttonName); 438 | 439 | // New: Keyboard mapping methods 440 | void handleKeyboardShortcut(const QString &keySequence); 441 | void saveKeyboardMappings(); 442 | void loadKeyboardMappings(); 443 | 444 | void ensureTabHasUniqueSaveFolder(InkCanvas* canvas); 445 | 446 | RecentNotebooksManager *recentNotebooksManager; // Added manager instance 447 | 448 | int pdfRenderDPI = 288; // Default to 288 DPI 449 | 450 | void setupUi(); 451 | 452 | void loadUserSettings(); 453 | 454 | bool scrollbarsVisible = false; 455 | QTimer *scrollbarHideTimer = nullptr; 456 | 457 | // Event filter for scrollbar hover detection and dial container drag 458 | bool eventFilter(QObject *obj, QEvent *event) override; 459 | 460 | // Update scrollbar positions based on container size 461 | void updateScrollbarPositions(); 462 | 463 | // Handle edge proximity detection for scrollbar visibility 464 | void handleEdgeProximity(InkCanvas* canvas, const QPoint& pos); 465 | 466 | // Responsive toolbar management 467 | bool isToolbarTwoRows = false; 468 | QVBoxLayout *controlLayoutVertical = nullptr; 469 | QHBoxLayout *controlLayoutSingle = nullptr; 470 | QHBoxLayout *controlLayoutFirstRow = nullptr; 471 | QHBoxLayout *controlLayoutSecondRow = nullptr; 472 | void updateToolbarLayout(); 473 | void createSingleRowLayout(); 474 | void createTwoRowLayout(); 475 | 476 | // Add timer for delayed layout updates 477 | QTimer *layoutUpdateTimer = nullptr; 478 | 479 | // Separator line for 2-row layout 480 | QFrame *separatorLine = nullptr; 481 | 482 | protected: 483 | void resizeEvent(QResizeEvent *event) override; 484 | void keyPressEvent(QKeyEvent *event) override; // New: Handle keyboard shortcuts 485 | void tabletEvent(QTabletEvent *event) override; // Handle pen hover for tooltips 486 | }; 487 | 488 | #endif // MAINWINDOW_H 489 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📝 SpeedyNote 2 | 3 | _A lightweight, fast, and stylus-optimized note-taking app built for classic tablet PCs, low-resolution screens, and vintage hardware._ 4 | 5 | ![cover](https://i.imgur.com/qENmB5x.png) 6 | 7 | --- 8 | 9 | ## ✨ Features 10 | 11 | - 🖊️ **Pressure-sensitive inking** with stylus support 12 | - 📄 **Multi-page notebooks** with tabbed or scrollable page view 13 | - 📌 **PDF background integration** with annotation overlay 14 | - 🌀 **Dial UI + Joy-Con support** for intuitive one-handed control 15 | - 🎨 **Per-page background styles**: grid, lined, or blank (customizable) 16 | - 💾 **Portable `.snpkg` notebooks** for export/import & sharing 17 | - 🔎 **Zoom, pan, thickness, and color preset switching** via dial 18 | - 💡 **Designed for low-spec devices** (133Hz Sample Rate @ Intel Atom N450) 19 | - 🌏 **Supports multiple languages across the globe** (Covers half the global population) 20 | 21 | --- 22 | 23 | ## 📸 Screenshots 24 | 25 | | Drawing | Dial UI / Joycon Controls | Overlay Grid Options | 26 | |----------------|------------------------|-----------------------| 27 | | ![draw](https://i.imgur.com/iARL6Vo.gif) | ![pdf](https://i.imgur.com/NnrqOQQ.gif) | ![grid](https://i.imgur.com/YaEdx1p.gif) | 28 | 29 | 30 | --- 31 | 32 | ## 🚀 Getting Started 33 | 34 | ### ✅ Requirements 35 | 36 | - Windows 7/8/10/11/Ubuntu amd64/Kali amd64/PostmarketOS arm64 37 | - Qt 5 or Qt 6 runtime (bundled in Windows releases) 38 | - Stylus input (Wacom recommended) 39 | 40 | ### 🛠️ Usage 41 | 42 | 1. Launch `NoteApp.exe` 43 | 2. Click **Folder Icon** to select a working folder or **Import `.snpkg` Package** 44 | 3. Start writing/drawing using your stylus 45 | 4. Use the **MagicDial** or **Joy-Con** to change tools, zoom, scroll, or switch pages 46 | 5. Notebooks can be exported as `.snpkg` 47 | 48 | --- 49 | 50 | ## 📦 Notebook Format 51 | 52 | - Can be saved as: 53 | - 📁 A **folder** with `.png` pages + metadata 54 | - 🗜️ A **`.snpkg` archive** for portability (non-compressed `.tar`) 55 | - Each notebook may contain: 56 | - Annotated page images (`annotated_XXXX.png`) 57 | - Optional background images from PDF (`XXXX.png`) 58 | - Metadata: background style, density, color, and PDF path 59 | 60 | --- 61 | 62 | ## 🎮 Controller Support 63 | 64 | SpeedyNote supports controller input, ideal for tablet users: 65 | 66 | - ✅ **Left Joy-Con supported** 67 | - 🎛️ Analog stick → Dial control 68 | - 🔘 Buttons can be mapped to: 69 | - Control the dial with multiple features 70 | - Toggle fullscreen 71 | - Change color / thickness 72 | - Open control panel 73 | - Create/delete pages 74 | 75 | > Long press + turn = hold-and-turn mappings 76 | 77 | --- 78 | 79 | ## 📁 Building From Source 80 | 81 | 82 | 1. Install **Qt 6** and **CMake** 83 | 2. Clone this repository 84 | 3. Run: 85 | 86 | ```bash 87 | rm -r build 88 | mkdir build 89 | # ✅ Update translation source files (ensure the .ts files exist already) 90 | & "C:\Qt\6.8.2\mingw_64\bin\lupdate.exe" . -ts ./resources/translations/app_fr.ts ./resources/translations/app_zh.ts ./resources/translations/app_es.ts 91 | & "C:\Qt\6.8.2\mingw_64\bin\linguist.exe" resources/translations/app_zh.ts 92 | & "C:\Qt\6.8.2\mingw_64\bin\linguist.exe" resources/translations/app_fr.ts 93 | & "C:\Qt\6.8.2\mingw_64\bin\linguist.exe" resources/translations/app_es.ts 94 | ``` 95 | 4. (Optional) Modify translations in the GUI interface 96 | 5. Run: 97 | ```bash 98 | rm -r build 99 | mkdir build 100 | & "C:\Qt\6.8.2\mingw_64\bin\lrelease.exe" ./resources/translations/app_zh.ts ./resources/translations/app_fr.ts ./resources/translations/app_es.ts 101 | 102 | Copy-Item -Path "C:\Games\yourfolder\resources\translations\*.qm" -Destination "C:\Games\yourfolder\build" -Force 103 | 104 | cd .\build 105 | cmake -G "MinGW Makefiles" .. 106 | cmake --build . 107 | & "C:\Qt\6.8.2\mingw_64\bin\windeployqt.exe" "NoteApp.exe" 108 | Copy-Item -Path "C:\yourfolder\dllpack\*.dll" -Destination "C:\yourfolder\build" -Force 109 | Copy-Item -Path "C:\yourfolder\bsdtar.exe" -Destination "C:\yourfolder\build" -Force 110 | ./NoteApp.exe 111 | cd ../ 112 | ``` -------------------------------------------------------------------------------- /RecentNotebooksDialog.cpp: -------------------------------------------------------------------------------- 1 | #include "RecentNotebooksDialog.h" 2 | #include "MainWindow.h" // For selectFolder functionality 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | RecentNotebooksDialog::RecentNotebooksDialog(MainWindow *mainWindow, RecentNotebooksManager *manager, QWidget *parent) 10 | : QDialog(parent), notebookManager(manager), mainWindowRef(mainWindow) { 11 | setupUi(); 12 | populateGrid(); 13 | setWindowTitle(tr("Recent Notebooks")); 14 | setMinimumSize(800, 600); 15 | } 16 | 17 | void RecentNotebooksDialog::setupUi() { 18 | QVBoxLayout *mainLayout = new QVBoxLayout(this); 19 | QScrollArea *scrollArea = new QScrollArea(this); 20 | scrollArea->setWidgetResizable(true); 21 | QWidget *gridContainer = new QWidget(); 22 | gridLayout = new QGridLayout(gridContainer); 23 | gridLayout->setSpacing(15); 24 | 25 | scrollArea->setWidget(gridContainer); 26 | mainLayout->addWidget(scrollArea); 27 | setLayout(mainLayout); 28 | } 29 | 30 | void RecentNotebooksDialog::populateGrid() { 31 | QStringList recentPaths = notebookManager->getRecentNotebooks(); 32 | int row = 0; 33 | int col = 0; 34 | const int numCols = 4; 35 | 36 | for (const QString &path : recentPaths) { 37 | if (path.isEmpty()) continue; 38 | 39 | QPushButton *button = new QPushButton(this); 40 | button->setFixedSize(180, 180); // Larger buttons 41 | button->setProperty("notebookPath", path); // Store path for slot 42 | connect(button, &QPushButton::clicked, this, &RecentNotebooksDialog::onNotebookClicked); 43 | 44 | QVBoxLayout *buttonLayout = new QVBoxLayout(button); 45 | buttonLayout->setContentsMargins(5,5,5,5); 46 | 47 | QLabel *coverLabel = new QLabel(this); 48 | coverLabel->setFixedSize(170, 127); // 4:3 aspect ratio for cover 49 | coverLabel->setAlignment(Qt::AlignCenter); 50 | QString coverPath = notebookManager->getCoverImagePathForNotebook(path); 51 | if (!coverPath.isEmpty()) { 52 | QPixmap coverPixmap(coverPath); 53 | coverLabel->setPixmap(coverPixmap.scaled(coverLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); 54 | } else { 55 | coverLabel->setText(tr("No Preview")); 56 | } 57 | coverLabel->setStyleSheet("border: 1px solid gray;"); 58 | 59 | QLabel *nameLabel = new QLabel(notebookManager->getNotebookDisplayName(path), this); 60 | nameLabel->setAlignment(Qt::AlignCenter); 61 | nameLabel->setWordWrap(true); 62 | nameLabel->setFixedHeight(40); // Fixed height for name label 63 | 64 | buttonLayout->addWidget(coverLabel); 65 | buttonLayout->addWidget(nameLabel); 66 | button->setLayout(buttonLayout); 67 | 68 | gridLayout->addWidget(button, row, col); 69 | 70 | col++; 71 | if (col >= numCols) { 72 | col = 0; 73 | row++; 74 | } 75 | } 76 | } 77 | 78 | void RecentNotebooksDialog::onNotebookClicked() { 79 | QPushButton *button = qobject_cast(sender()); 80 | if (button) { 81 | QString notebookPath = button->property("notebookPath").toString(); 82 | if (!notebookPath.isEmpty() && mainWindowRef) { 83 | // This logic is similar to MainWindow::selectFolder but directly sets the folder. 84 | InkCanvas *canvas = mainWindowRef->currentCanvas(); // Get current canvas from MainWindow 85 | if (canvas) { 86 | if (canvas->isEdited()){ 87 | mainWindowRef->saveCurrentPage(); // Use MainWindow's save method 88 | } 89 | canvas->setSaveFolder(notebookPath); 90 | mainWindowRef->switchPage(1); // Use MainWindow's switchPage method 91 | mainWindowRef->pageInput->setValue(1); // Update pageInput in MainWindow 92 | mainWindowRef->updateTabLabel(); // Update tab label in MainWindow 93 | 94 | // Update recent notebooks list and refresh cover page 95 | if (notebookManager) { 96 | // Generate and save fresh cover preview 97 | notebookManager->generateAndSaveCoverPreview(notebookPath, canvas); 98 | // Add/update in recent list (this moves it to the top) 99 | notebookManager->addRecentNotebook(notebookPath, canvas); 100 | } 101 | } 102 | accept(); // Close the dialog 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /RecentNotebooksDialog.h: -------------------------------------------------------------------------------- 1 | #ifndef RECENTNOTEBOOKSDIALOG_H 2 | #define RECENTNOTEBOOKSDIALOG_H 3 | 4 | #include 5 | #include 6 | #include "RecentNotebooksManager.h" 7 | 8 | class QPushButton; 9 | class QLabel; 10 | class MainWindow; // Forward declaration 11 | 12 | class RecentNotebooksDialog : public QDialog { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit RecentNotebooksDialog(MainWindow *mainWindow, RecentNotebooksManager *manager, QWidget *parent = nullptr); 17 | 18 | private slots: 19 | void onNotebookClicked(); 20 | 21 | private: 22 | void setupUi(); 23 | void populateGrid(); 24 | 25 | RecentNotebooksManager *notebookManager; 26 | QGridLayout *gridLayout; 27 | MainWindow *mainWindowRef; // To call selectFolder-like functionality 28 | }; 29 | 30 | #endif // RECENTNOTEBOOKSDIALOG_H -------------------------------------------------------------------------------- /RecentNotebooksManager.cpp: -------------------------------------------------------------------------------- 1 | #include "RecentNotebooksManager.h" 2 | #include "InkCanvas.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | RecentNotebooksManager::RecentNotebooksManager(QObject *parent) 12 | : QObject(parent), settings("SpeedyNote", "App") { 13 | QDir().mkpath(getCoverImageDir()); // Ensure cover image directory exists 14 | loadRecentNotebooks(); 15 | } 16 | 17 | void RecentNotebooksManager::addRecentNotebook(const QString& folderPath, InkCanvas* canvasForPreview) { 18 | if (folderPath.isEmpty()) return; 19 | 20 | // Remove if already exists to move it to the front 21 | recentNotebookPaths.removeAll(folderPath); 22 | recentNotebookPaths.prepend(folderPath); 23 | 24 | // Trim the list if it exceeds the maximum size 25 | while (recentNotebookPaths.size() > MAX_RECENT_NOTEBOOKS) { 26 | recentNotebookPaths.removeLast(); 27 | } 28 | 29 | generateAndSaveCoverPreview(folderPath, canvasForPreview); 30 | saveRecentNotebooks(); 31 | } 32 | 33 | QStringList RecentNotebooksManager::getRecentNotebooks() const { 34 | return recentNotebookPaths; 35 | } 36 | 37 | void RecentNotebooksManager::loadRecentNotebooks() { 38 | recentNotebookPaths = settings.value("recentNotebooks").toStringList(); 39 | } 40 | 41 | void RecentNotebooksManager::saveRecentNotebooks() { 42 | settings.setValue("recentNotebooks", recentNotebookPaths); 43 | } 44 | 45 | QString RecentNotebooksManager::sanitizeFolderName(const QString& folderPath) const { 46 | return QFileInfo(folderPath).baseName().replace(QRegularExpression("[^a-zA-Z0-9_]"), "_"); 47 | } 48 | 49 | QString RecentNotebooksManager::getCoverImageDir() const { 50 | return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/RecentCovers/"; 51 | } 52 | 53 | void RecentNotebooksManager::generateAndSaveCoverPreview(const QString& folderPath, InkCanvas* optionalCanvas) { 54 | QString coverDir = getCoverImageDir(); 55 | QString coverFileName = sanitizeFolderName(folderPath) + "_cover.png"; 56 | QString coverFilePath = coverDir + coverFileName; 57 | 58 | QImage coverImage(400, 300, QImage::Format_ARGB32_Premultiplied); 59 | coverImage.fill(Qt::white); // Default background 60 | QPainter painter(&coverImage); 61 | painter.setRenderHint(QPainter::SmoothPixmapTransform); 62 | 63 | if (optionalCanvas && optionalCanvas->width() > 0 && optionalCanvas->height() > 0) { 64 | int logicalCanvasWidth = optionalCanvas->width(); 65 | int logicalCanvasHeight = optionalCanvas->height(); 66 | 67 | double targetAspectRatio = 4.0 / 3.0; 68 | double canvasAspectRatio = (double)logicalCanvasWidth / logicalCanvasHeight; 69 | 70 | int grabWidth, grabHeight; 71 | int xOffset = 0, yOffset = 0; 72 | 73 | if (canvasAspectRatio > targetAspectRatio) { // Canvas is wider than target 4:3 74 | grabHeight = logicalCanvasHeight; 75 | grabWidth = qRound(logicalCanvasHeight * targetAspectRatio); 76 | xOffset = (logicalCanvasWidth - grabWidth) / 2; 77 | } else { // Canvas is taller than or equal to target 4:3 78 | grabWidth = logicalCanvasWidth; 79 | grabHeight = qRound(logicalCanvasWidth / targetAspectRatio); 80 | yOffset = (logicalCanvasHeight - grabHeight) / 2; 81 | } 82 | 83 | if (grabWidth > 0 && grabHeight > 0) { 84 | QRect grabRect(xOffset, yOffset, grabWidth, grabHeight); 85 | QPixmap capturedView = optionalCanvas->grab(grabRect); 86 | painter.drawPixmap(coverImage.rect(), capturedView, capturedView.rect()); 87 | } else { 88 | // Fallback if calculated grab dimensions are invalid, draw placeholder or fill 89 | // This case should ideally not be hit if canvas width/height > 0 90 | painter.fillRect(coverImage.rect(), Qt::lightGray); 91 | painter.setPen(Qt::black); 92 | painter.drawText(coverImage.rect(), Qt::AlignCenter, tr("Preview Error")); 93 | } 94 | } else { 95 | // Fallback: check for a saved "annotated_..._00000.png" or the first page 96 | // This part remains the same as it deals with pre-rendered images. 97 | QString notebookIdStr; 98 | InkCanvas tempCanvas(nullptr); // Temporary canvas to access potential notebookId property logic if it were there 99 | // However, notebookId is specific to an instance with a saveFolder. 100 | // For a generic fallback, we might need a different way or assume a common naming if notebookId is unknown. 101 | // For now, let's assume a simple naming or improve this fallback if needed. 102 | 103 | // Attempt to get notebookId if folderPath is a valid notebook with an ID file 104 | QFile idFile(folderPath + "/.notebook_id.txt"); 105 | if (idFile.open(QIODevice::ReadOnly | QIODevice::Text)) { 106 | QTextStream in(&idFile); 107 | notebookIdStr = in.readLine().trimmed(); 108 | idFile.close(); 109 | } 110 | 111 | QString firstPagePath, firstAnnotatedPagePath; 112 | if (!notebookIdStr.isEmpty()) { 113 | firstPagePath = folderPath + QString("/%1_00000.png").arg(notebookIdStr); 114 | firstAnnotatedPagePath = folderPath + QString("/annotated_%1_00000.png").arg(notebookIdStr); 115 | } else { 116 | // Fallback if no ID, try a generic name (less ideal) 117 | // This situation should be rare if notebooks are managed properly 118 | // For robustness, one might iterate files or use a known default page name 119 | // For this example, we'll stick to a pattern that might not always work without an ID 120 | // Consider that `InkCanvas(nullptr).property("notebookId")` was problematic as `notebookId` is instance specific. 121 | } 122 | 123 | QImage pageImage; 124 | if (!firstAnnotatedPagePath.isEmpty() && QFile::exists(firstAnnotatedPagePath)) { 125 | pageImage.load(firstAnnotatedPagePath); 126 | } else if (!firstPagePath.isEmpty() && QFile::exists(firstPagePath)) { 127 | pageImage.load(firstPagePath); 128 | } 129 | 130 | if (!pageImage.isNull()) { 131 | painter.drawImage(coverImage.rect(), pageImage, pageImage.rect()); 132 | } else { 133 | // If no image found, draw a placeholder 134 | painter.fillRect(coverImage.rect(), Qt::darkGray); 135 | painter.setPen(Qt::white); 136 | painter.drawText(coverImage.rect(), Qt::AlignCenter, tr("No Page 0 Preview")); 137 | } 138 | } 139 | coverImage.save(coverFilePath, "PNG"); 140 | } 141 | 142 | QString RecentNotebooksManager::getCoverImagePathForNotebook(const QString& folderPath) const { 143 | QString coverDir = getCoverImageDir(); 144 | QString coverFileName = sanitizeFolderName(folderPath) + "_cover.png"; 145 | QString coverFilePath = coverDir + coverFileName; 146 | if (QFile::exists(coverFilePath)) { 147 | return coverFilePath; 148 | } 149 | return ""; // Return empty if no cover exists 150 | } 151 | 152 | QString RecentNotebooksManager::getNotebookDisplayName(const QString& folderPath) const { 153 | // Check for PDF metadata first 154 | QString metadataFile = folderPath + "/.pdf_path.txt"; 155 | if (QFile::exists(metadataFile)) { 156 | QFile file(metadataFile); 157 | if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { 158 | QTextStream in(&file); 159 | QString pdfPath = in.readLine().trimmed(); 160 | file.close(); 161 | if (!pdfPath.isEmpty()) { 162 | return QFileInfo(pdfPath).fileName(); 163 | } 164 | } 165 | } 166 | // Fallback to folder name 167 | return QFileInfo(folderPath).fileName(); 168 | } -------------------------------------------------------------------------------- /RecentNotebooksManager.h: -------------------------------------------------------------------------------- 1 | #ifndef RECENTNOTEBOOKSMANAGER_H 2 | #define RECENTNOTEBOOKSMANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class InkCanvas; // Forward declaration 9 | 10 | class RecentNotebooksManager : public QObject { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit RecentNotebooksManager(QObject *parent = nullptr); 15 | 16 | void addRecentNotebook(const QString& folderPath, InkCanvas* canvasForPreview = nullptr); 17 | QStringList getRecentNotebooks() const; 18 | QString getCoverImagePathForNotebook(const QString& folderPath) const; 19 | QString getNotebookDisplayName(const QString& folderPath) const; 20 | void generateAndSaveCoverPreview(const QString& folderPath, InkCanvas* optionalCanvas = nullptr); 21 | 22 | private: 23 | void loadRecentNotebooks(); 24 | void saveRecentNotebooks(); 25 | QString getCoverImageDir() const; 26 | QString sanitizeFolderName(const QString& folderPath) const; 27 | 28 | QStringList recentNotebookPaths; 29 | const int MAX_RECENT_NOTEBOOKS = 16; 30 | QSettings settings; 31 | }; 32 | 33 | #endif // RECENTNOTEBOOKSMANAGER_H -------------------------------------------------------------------------------- /SDLControllerManager.cpp: -------------------------------------------------------------------------------- 1 | #include "SDLControllerManager.h" 2 | #include 3 | #include 4 | 5 | SDLControllerManager::SDLControllerManager(QObject *parent) 6 | : QObject(parent), pollTimer(new QTimer(this)) { 7 | 8 | connect(pollTimer, &QTimer::timeout, this, [=]() { 9 | SDL_PumpEvents(); // ✅ Update SDL input state 10 | 11 | // 🔁 Poll for axis movement (left stick) 12 | if (controller) { 13 | int x = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); 14 | int y = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); 15 | 16 | const int DEADZONE = 16000; 17 | if (qAbs(x) >= DEADZONE || qAbs(y) >= DEADZONE) { 18 | float fx = x / 32768.0f; 19 | float fy = y / 32768.0f; 20 | 21 | float angle = qAtan2(-fy, fx) * 180.0 / M_PI; 22 | if (angle < 0) angle += 360; 23 | 24 | int angleInt = static_cast(angle); 25 | 26 | // ✅ Invert angle for dial so clockwise = clockwise 27 | angleInt = (360 - angleInt) % 360; 28 | 29 | 30 | if (qAbs(angleInt - lastAngle) > 3) { 31 | lastAngle = angleInt; 32 | emit leftStickAngleChanged(angleInt); 33 | } 34 | leftStickActive = true; // ✅ Mark stick as active 35 | } 36 | else { 37 | // Stick is in deadzone (center) 38 | if (leftStickActive) { 39 | // ✅ Was active → now released → emit release signal once 40 | emit leftStickReleased(); 41 | leftStickActive = false; 42 | } 43 | } 44 | } 45 | 46 | SDL_PumpEvents(); 47 | 48 | // Check hold timer 49 | for (auto it = buttonPressTime.begin(); it != buttonPressTime.end(); ++it) { 50 | QString btn = it.key(); 51 | quint32 pressTime = it.value(); 52 | quint32 now = SDL_GetTicks(); 53 | 54 | if (!buttonHeldEmitted.value(btn, false) && (now - pressTime) >= HOLD_THRESHOLD) { 55 | emit buttonHeld(btn); 56 | buttonHeldEmitted[btn] = true; 57 | } 58 | } 59 | 60 | // 🔁 Poll for button events 61 | SDL_Event e; 62 | 63 | /* 64 | for (int i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; ++i) { 65 | SDL_GameControllerButton button = static_cast(i); 66 | const char* name = SDL_GameControllerGetStringForButton(button); 67 | if (SDL_GameControllerGetButton(controller, button)) { 68 | qDebug() << "Button" << name << "is pressed"; 69 | } 70 | } 71 | This is for testing button mappings. 72 | */ 73 | 74 | 75 | 76 | while (SDL_PollEvent(&e)) { 77 | if (e.type == SDL_CONTROLLERBUTTONDOWN) { 78 | QString btnName = getButtonName(e.cbutton.button); 79 | buttonPressTime[btnName] = SDL_GetTicks(); 80 | buttonHeldEmitted[btnName] = false; 81 | } 82 | 83 | if (e.type == SDL_CONTROLLERBUTTONUP) { 84 | QString btnName = getButtonName(e.cbutton.button); 85 | 86 | quint32 pressTime = buttonPressTime.value(btnName, 0); 87 | quint32 now = SDL_GetTicks(); 88 | quint32 duration = now - pressTime; 89 | 90 | if (duration < HOLD_THRESHOLD) { 91 | emit buttonSinglePress(btnName); 92 | } else { 93 | emit buttonReleased(btnName); 94 | } 95 | 96 | buttonPressTime.remove(btnName); 97 | buttonHeldEmitted.remove(btnName); 98 | } 99 | } 100 | }); 101 | } 102 | 103 | QString SDLControllerManager::getButtonName(Uint8 sdlButton) { 104 | switch (sdlButton) { 105 | case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: return "LEFTSHOULDER"; 106 | case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: return "RIGHTSHOULDER"; 107 | case SDL_CONTROLLER_BUTTON_PADDLE2: return "PADDLE2"; 108 | case SDL_CONTROLLER_BUTTON_PADDLE4: return "PADDLE4"; 109 | case SDL_CONTROLLER_BUTTON_Y: return "Y"; 110 | case SDL_CONTROLLER_BUTTON_A: return "A"; 111 | case SDL_CONTROLLER_BUTTON_B: return "B"; 112 | case SDL_CONTROLLER_BUTTON_X: return "X"; 113 | case SDL_CONTROLLER_BUTTON_LEFTSTICK: return "LEFTSTICK"; 114 | case SDL_CONTROLLER_BUTTON_START: return "START"; 115 | case SDL_CONTROLLER_BUTTON_GUIDE: return "GUIDE"; 116 | } 117 | return "UNKNOWN"; 118 | } 119 | 120 | 121 | SDLControllerManager::~SDLControllerManager() { 122 | if (controller) SDL_GameControllerClose(controller); 123 | if (sdlInitialized) SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); 124 | } 125 | 126 | void SDLControllerManager::start() { 127 | if (!sdlInitialized) { 128 | if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) { 129 | qWarning() << "Failed to initialize SDL controller subsystem"; 130 | return; 131 | } 132 | sdlInitialized = true; 133 | } 134 | 135 | SDL_GameControllerEventState(SDL_ENABLE); // ✅ Enable controller events 136 | 137 | for (int i = 0; i < SDL_NumJoysticks(); ++i) { 138 | if (SDL_IsGameController(i)) { 139 | controller = SDL_GameControllerOpen(i); 140 | if (controller) { 141 | qDebug() << "Controller added!"; 142 | break; 143 | } 144 | } 145 | } 146 | 147 | pollTimer->start(16); // 60 FPS polling 148 | } 149 | 150 | void SDLControllerManager::stop() { 151 | pollTimer->stop(); 152 | } 153 | -------------------------------------------------------------------------------- /SDLControllerManager.h: -------------------------------------------------------------------------------- 1 | #ifndef SDLCONTROLLERMANAGER_H 2 | #define SDLCONTROLLERMANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class SDLControllerManager : public QObject { 12 | Q_OBJECT 13 | public: 14 | explicit SDLControllerManager(QObject *parent = nullptr); 15 | ~SDLControllerManager(); 16 | SDL_GameController* getController() const { return controller; } 17 | 18 | signals: 19 | void buttonHeld(QString buttonName); 20 | void buttonReleased(QString buttonName); 21 | void buttonSinglePress(QString buttonName); 22 | void leftStickAngleChanged(int angle); 23 | void leftStickReleased(); 24 | 25 | public slots: 26 | void start(); 27 | void stop(); 28 | 29 | private: 30 | QTimer *pollTimer; 31 | SDL_GameController *controller = nullptr; 32 | bool sdlInitialized = false; 33 | bool leftStickActive = false; // Whether stick is out of deadzone 34 | 35 | 36 | int lastAngle = -1; 37 | QString getButtonName(Uint8 sdlButton); 38 | 39 | QMap buttonPressTime; 40 | QMap buttonHeldEmitted; // NEW -> whether buttonHeld has been fired 41 | 42 | const quint32 HOLD_THRESHOLD = 300; // ms 43 | const quint32 POLL_INTERVAL = 16; // ms 44 | }; 45 | 46 | #endif // SDLCONTROLLERMANAGER_H 47 | -------------------------------------------------------------------------------- /ToolType.h: -------------------------------------------------------------------------------- 1 | #ifndef TOOLTYPE_H 2 | #define TOOLTYPE_H 3 | 4 | // ✅ Now it can be used anywhere 5 | enum class ToolType { 6 | Pen, 7 | Marker, 8 | Eraser 9 | }; 10 | 11 | #endif // TOOLTYPE_H -------------------------------------------------------------------------------- /app_icon.rc: -------------------------------------------------------------------------------- 1 | // Windows resource file for application icon 2 | #include 3 | 4 | // Application icon (ID 1 is the main application icon) 5 | 1 ICON "resources/icons/mainicon.ico" 6 | 7 | // Version information 8 | 1 VERSIONINFO 9 | FILEVERSION 0,4,10,0 10 | PRODUCTVERSION 0,4,10,0 11 | FILEFLAGSMASK 0x3fL 12 | FILEFLAGS 0x0L 13 | FILEOS 0x40004L 14 | FILETYPE 0x1L 15 | FILESUBTYPE 0x0L 16 | BEGIN 17 | BLOCK "StringFileInfo" 18 | BEGIN 19 | BLOCK "040904b0" 20 | BEGIN 21 | VALUE "CompanyName", "SpeedyNote" 22 | VALUE "FileDescription", "SpeedyNote - Fast Digital Note Taking Application" 23 | VALUE "FileVersion", "0.4.10.0" 24 | VALUE "InternalName", "NoteApp" 25 | VALUE "LegalCopyright", "Copyright (C) 2024" 26 | VALUE "OriginalFilename", "NoteApp.exe" 27 | VALUE "ProductName", "SpeedyNote" 28 | VALUE "ProductVersion", "0.4.10.0" 29 | END 30 | END 31 | BLOCK "VarFileInfo" 32 | BEGIN 33 | VALUE "Translation", 0x409, 1200 34 | END 35 | END -------------------------------------------------------------------------------- /compile.ps1: -------------------------------------------------------------------------------- 1 | rm -r build 2 | mkdir build 3 | 4 | 5 | # ✅ Compile .ts → .qm files 6 | & "C:\Qt\6.8.2\mingw_64\bin\lrelease.exe" ./resources/translations/app_zh.ts ./resources/translations/app_fr.ts ./resources/translations/app_es.ts 7 | 8 | 9 | Copy-Item -Path "C:\Games\notecpp_2rowlowres_legacy\resources\translations\*.qm" -Destination "C:\Games\notecpp_2rowlowres_legacy\build" -Force 10 | 11 | cd .\build 12 | cmake -G "MinGW Makefiles" .. 13 | cmake --build . -- -j8 14 | 15 | 16 | # ✅ Optionally, copy compiled .qm files into build or embed them via qrc 17 | 18 | # ✅ Deploy Qt runtime 19 | & "C:\Qt\6.8.2\mingw_64\bin\windeployqt.exe" "NoteApp.exe" 20 | 21 | Copy-Item -Path "C:\Games\notecpp_2rowlowres\dllpack\*.dll" -Destination "C:\Games\notecpp_2rowlowres_legacy\build" -Force 22 | Copy-Item -Path "C:\Games\notecpp_2rowlowres_legacy\dllpack\bsdtar.exe" -Destination "C:\Games\notecpp_2rowlowres_legacy\build" -Force 23 | ./NoteApp.exe 24 | cd ../ -------------------------------------------------------------------------------- /copy_dlls.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | 4 | set "EXE_PATH=C:\Games\notecpp\build\NoteApp.exe" 5 | set "DEST_DIR=C:\Games\notecpp\build\" 6 | set "MINGW_BIN=C:\msys64\mingw64\bin" 7 | 8 | echo Finding missing DLLs using `ldd`... 9 | for /f "tokens=3" %%i in ('C:\msys64\usr\bin\ldd "%EXE_PATH%" ^| findstr "=>"') do ( 10 | set "DLL_NAME=%%~nxi" 11 | 12 | rem Skip Windows system DLLs 13 | echo !DLL_NAME! | findstr /i "ntdll.dll kernel32.dll msvcrt.dll user32.dll gdi32.dll combase.dll ole32.dll shell32.dll" >nul && ( 14 | echo Skipping system DLL: !DLL_NAME! 15 | goto :continue 16 | ) 17 | 18 | rem Try to copy from MINGW bin folder 19 | if exist "%MINGW_BIN%\!DLL_NAME!" ( 20 | echo Copying: %MINGW_BIN%\!DLL_NAME! 21 | copy /Y "%MINGW_BIN%\!DLL_NAME!" "%DEST_DIR%" 22 | ) else ( 23 | echo Missing DLL: !DLL_NAME! 24 | ) 25 | 26 | :continue 27 | ) 28 | echo Done! 29 | pause 30 | -------------------------------------------------------------------------------- /packaging.iss: -------------------------------------------------------------------------------- 1 | ; SpeedyNote Inno Setup Script 2 | [Setup] 3 | AppName=SpeedyNote 4 | AppVersion=0.4.10 5 | DefaultDirName={autopf}\SpeedyNote 6 | DefaultGroupName=SpeedyNote 7 | OutputBaseFilename=SpeedyNoteInstaller 8 | Compression=lzma 9 | SolidCompression=yes 10 | OutputDir=Output 11 | DisableProgramGroupPage=yes 12 | WizardStyle=modern 13 | 14 | [Languages] 15 | Name: "en"; MessagesFile: "compiler:Default.isl" 16 | Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl" 17 | Name: "zh"; MessagesFile: "compiler:Languages\ChineseSimplified.isl" 18 | Name: "fr"; MessagesFile: "compiler:Languages\French.isl" 19 | 20 | [Files] 21 | Source: "C:\Games\notecpp_2rowlowres_legacy\build\*"; DestDir: "{app}"; Flags: recursesubdirs ignoreversion 22 | 23 | [Icons] 24 | Name: "{group}\SpeedyNote"; Filename: "{app}\NoteApp.exe"; WorkingDir: "{app}" 25 | Name: "{commondesktop}\SpeedyNote"; Filename: "{app}\NoteApp.exe"; WorkingDir: "{app}"; IconFilename: "{app}\NoteApp.exe"; Tasks: desktopicon 26 | Name: "{group}\Uninstall SpeedyNote"; Filename: "{uninstallexe}" 27 | 28 | [Tasks] 29 | Name: "desktopicon"; Description: "Create a desktop shortcut"; GroupDescription: "Additional icons:" 30 | 31 | [Run] 32 | Filename: "{app}\NoteApp.exe"; Description: "{cm:LaunchProgram,SpeedyNote}"; Flags: nowait postinstall skipifsilent 33 | -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | resources/icons/yellow.png 5 | resources/icons/blue.png 6 | resources/icons/red.png 7 | resources/icons/background.png 8 | resources/icons/background_reversed.png 9 | resources/icons/benchmark.png 10 | resources/icons/benchmark_reversed.png 11 | resources/icons/black.png 12 | resources/icons/white.png 13 | resources/icons/green.png 14 | resources/icons/pen.png 15 | resources/icons/pen_reversed.png 16 | resources/icons/marker.png 17 | resources/icons/marker_reversed.png 18 | resources/icons/eraser.png 19 | resources/icons/eraser_reversed.png 20 | resources/icons/save_reversed.png 21 | resources/icons/save.png 22 | resources/icons/saveannotated.png 23 | resources/icons/saveannotated_reversed.png 24 | resources/icons/pdf.png 25 | resources/icons/pdf_reversed.png 26 | resources/icons/pdfdelete.png 27 | resources/icons/pdfdelete_reversed.png 28 | resources/icons/folder.png 29 | resources/icons/folder_reversed.png 30 | resources/icons/straightLine.png 31 | resources/icons/straightLine_reversed.png 32 | resources/icons/trash.png 33 | resources/icons/trash_reversed.png 34 | resources/icons/addtab.png 35 | resources/icons/addtab_reversed.png 36 | resources/icons/cross.png 37 | resources/icons/cross_reversed.png 38 | resources/icons/up_arrow.png 39 | resources/icons/up_arrow_reversed.png 40 | resources/icons/down_arrow.png 41 | resources/icons/down_arrow_reversed.png 42 | resources/icons/zoom.png 43 | resources/icons/zoom_reversed.png 44 | resources/icons/thickness.png 45 | resources/icons/thickness_reversed.png 46 | resources/icons/fullscreen.png 47 | resources/icons/fullscreen_reversed.png 48 | resources/icons/bookpage.png 49 | resources/icons/bookpage_reversed.png 50 | resources/icons/dial.png 51 | resources/icons/dial_reversed.png 52 | resources/icons/fastforward.png 53 | resources/icons/fastforward_reversed.png 54 | resources/icons/color.png 55 | resources/icons/color_reversed.png 56 | resources/icons/preset.png 57 | resources/icons/preset_reversed.png 58 | resources/icons/savepreset.png 59 | resources/icons/savepreset_reversed.png 60 | resources/icons/tabs.png 61 | resources/icons/tabs_reversed.png 62 | resources/icons/mainicon.png 63 | resources/icons/settings.png 64 | resources/icons/settings_reversed.png 65 | resources/icons/scroll.png 66 | resources/icons/scroll_reversed.png 67 | resources/icons/import.png 68 | resources/icons/import_reversed.png 69 | resources/icons/export.png 70 | resources/icons/export_reversed.png 71 | resources/icons/rope.png 72 | resources/icons/rope_reversed.png 73 | resources/icons/recent.png 74 | resources/icons/recent_reversed.png 75 | resources/reversed_icons/color_reversed.png 76 | resources/reversed_icons/bookpage_reversed.png 77 | resources/reversed_icons/zoom_reversed.png 78 | resources/reversed_icons/thickness_reversed.png 79 | resources/reversed_icons/eraser_reversed.png 80 | resources/reversed_icons/marker_reversed.png 81 | resources/reversed_icons/pen_reversed.png 82 | resources/reversed_icons/preset_reversed.png 83 | resources/sounds/dial_click.wav 84 | resources/fonts/PixelFont.ttf 85 | resources/fonts/Jersey20-Regular.ttf 86 | resources/translations/app_zh.qm 87 | resources/translations/app_es.qm 88 | resources/translations/app_fr.qm 89 | 90 | 91 | -------------------------------------------------------------------------------- /resources/fonts/Jersey20-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/fonts/Jersey20-Regular.ttf -------------------------------------------------------------------------------- /resources/fonts/PixelFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/fonts/PixelFont.ttf -------------------------------------------------------------------------------- /resources/icons/addtab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/addtab.png -------------------------------------------------------------------------------- /resources/icons/addtab_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/addtab_reversed.png -------------------------------------------------------------------------------- /resources/icons/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/background.png -------------------------------------------------------------------------------- /resources/icons/background_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/background_reversed.png -------------------------------------------------------------------------------- /resources/icons/benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/benchmark.png -------------------------------------------------------------------------------- /resources/icons/benchmark_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/benchmark_reversed.png -------------------------------------------------------------------------------- /resources/icons/black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/black.png -------------------------------------------------------------------------------- /resources/icons/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/blue.png -------------------------------------------------------------------------------- /resources/icons/bookpage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/bookpage.png -------------------------------------------------------------------------------- /resources/icons/bookpage_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/bookpage_reversed.png -------------------------------------------------------------------------------- /resources/icons/color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/color.png -------------------------------------------------------------------------------- /resources/icons/color_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/color_reversed.png -------------------------------------------------------------------------------- /resources/icons/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/cross.png -------------------------------------------------------------------------------- /resources/icons/cross_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/cross_reversed.png -------------------------------------------------------------------------------- /resources/icons/dial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/dial.png -------------------------------------------------------------------------------- /resources/icons/dial_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/dial_reversed.png -------------------------------------------------------------------------------- /resources/icons/down_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/down_arrow.png -------------------------------------------------------------------------------- /resources/icons/down_arrow_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/down_arrow_reversed.png -------------------------------------------------------------------------------- /resources/icons/eraser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/eraser.png -------------------------------------------------------------------------------- /resources/icons/eraser_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/eraser_reversed.png -------------------------------------------------------------------------------- /resources/icons/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/export.png -------------------------------------------------------------------------------- /resources/icons/export_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/export_reversed.png -------------------------------------------------------------------------------- /resources/icons/fastforward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/fastforward.png -------------------------------------------------------------------------------- /resources/icons/fastforward_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/fastforward_reversed.png -------------------------------------------------------------------------------- /resources/icons/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/folder.png -------------------------------------------------------------------------------- /resources/icons/folder_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/folder_reversed.png -------------------------------------------------------------------------------- /resources/icons/fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/fullscreen.png -------------------------------------------------------------------------------- /resources/icons/fullscreen_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/fullscreen_reversed.png -------------------------------------------------------------------------------- /resources/icons/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/green.png -------------------------------------------------------------------------------- /resources/icons/import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/import.png -------------------------------------------------------------------------------- /resources/icons/import_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/import_reversed.png -------------------------------------------------------------------------------- /resources/icons/mainicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/mainicon.png -------------------------------------------------------------------------------- /resources/icons/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/marker.png -------------------------------------------------------------------------------- /resources/icons/marker_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/marker_reversed.png -------------------------------------------------------------------------------- /resources/icons/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/pdf.png -------------------------------------------------------------------------------- /resources/icons/pdf_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/pdf_reversed.png -------------------------------------------------------------------------------- /resources/icons/pdfdelete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/pdfdelete.png -------------------------------------------------------------------------------- /resources/icons/pdfdelete_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/pdfdelete_reversed.png -------------------------------------------------------------------------------- /resources/icons/pen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/pen.png -------------------------------------------------------------------------------- /resources/icons/pen_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/pen_reversed.png -------------------------------------------------------------------------------- /resources/icons/preset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/preset.png -------------------------------------------------------------------------------- /resources/icons/preset_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/preset_reversed.png -------------------------------------------------------------------------------- /resources/icons/recent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/recent.png -------------------------------------------------------------------------------- /resources/icons/recent_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/recent_reversed.png -------------------------------------------------------------------------------- /resources/icons/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/red.png -------------------------------------------------------------------------------- /resources/icons/rope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/rope.png -------------------------------------------------------------------------------- /resources/icons/rope_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/rope_reversed.png -------------------------------------------------------------------------------- /resources/icons/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/save.png -------------------------------------------------------------------------------- /resources/icons/save_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/save_reversed.png -------------------------------------------------------------------------------- /resources/icons/saveannotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/saveannotated.png -------------------------------------------------------------------------------- /resources/icons/saveannotated_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/saveannotated_reversed.png -------------------------------------------------------------------------------- /resources/icons/savepreset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/savepreset.png -------------------------------------------------------------------------------- /resources/icons/savepreset_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/savepreset_reversed.png -------------------------------------------------------------------------------- /resources/icons/scroll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/scroll.png -------------------------------------------------------------------------------- /resources/icons/scroll_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/scroll_reversed.png -------------------------------------------------------------------------------- /resources/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/settings.png -------------------------------------------------------------------------------- /resources/icons/settings_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/settings_reversed.png -------------------------------------------------------------------------------- /resources/icons/straightLine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/straightLine.png -------------------------------------------------------------------------------- /resources/icons/straightLine_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/straightLine_reversed.png -------------------------------------------------------------------------------- /resources/icons/tabs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/tabs.png -------------------------------------------------------------------------------- /resources/icons/tabs_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/tabs_reversed.png -------------------------------------------------------------------------------- /resources/icons/thickness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/thickness.png -------------------------------------------------------------------------------- /resources/icons/thickness_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/thickness_reversed.png -------------------------------------------------------------------------------- /resources/icons/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/trash.png -------------------------------------------------------------------------------- /resources/icons/trash_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/trash_reversed.png -------------------------------------------------------------------------------- /resources/icons/up_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/up_arrow.png -------------------------------------------------------------------------------- /resources/icons/up_arrow_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/up_arrow_reversed.png -------------------------------------------------------------------------------- /resources/icons/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/white.png -------------------------------------------------------------------------------- /resources/icons/writing_write_pen_icon_149355.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/writing_write_pen_icon_149355.png -------------------------------------------------------------------------------- /resources/icons/writing_write_pen_icon_149355_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/writing_write_pen_icon_149355_reversed.png -------------------------------------------------------------------------------- /resources/icons/yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/yellow.png -------------------------------------------------------------------------------- /resources/icons/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/zoom.png -------------------------------------------------------------------------------- /resources/icons/zoom_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons/zoom_reversed.png -------------------------------------------------------------------------------- /resources/icons_backup/addtab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/addtab.png -------------------------------------------------------------------------------- /resources/icons_backup/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/background.png -------------------------------------------------------------------------------- /resources/icons_backup/benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/benchmark.png -------------------------------------------------------------------------------- /resources/icons_backup/black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/black.png -------------------------------------------------------------------------------- /resources/icons_backup/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/blue.png -------------------------------------------------------------------------------- /resources/icons_backup/bookpage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/bookpage.png -------------------------------------------------------------------------------- /resources/icons_backup/color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/color.png -------------------------------------------------------------------------------- /resources/icons_backup/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/cross.png -------------------------------------------------------------------------------- /resources/icons_backup/dial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/dial.png -------------------------------------------------------------------------------- /resources/icons_backup/down_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/down_arrow.png -------------------------------------------------------------------------------- /resources/icons_backup/eraser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/eraser.png -------------------------------------------------------------------------------- /resources/icons_backup/fastforward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/fastforward.png -------------------------------------------------------------------------------- /resources/icons_backup/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/folder.png -------------------------------------------------------------------------------- /resources/icons_backup/fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/fullscreen.png -------------------------------------------------------------------------------- /resources/icons_backup/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/green.png -------------------------------------------------------------------------------- /resources/icons_backup/mainicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/mainicon.png -------------------------------------------------------------------------------- /resources/icons_backup/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/marker.png -------------------------------------------------------------------------------- /resources/icons_backup/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/pdf.png -------------------------------------------------------------------------------- /resources/icons_backup/pdfdelete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/pdfdelete.png -------------------------------------------------------------------------------- /resources/icons_backup/pen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/pen.png -------------------------------------------------------------------------------- /resources/icons_backup/preset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/preset.png -------------------------------------------------------------------------------- /resources/icons_backup/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/red.png -------------------------------------------------------------------------------- /resources/icons_backup/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/save.png -------------------------------------------------------------------------------- /resources/icons_backup/saveannotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/saveannotated.png -------------------------------------------------------------------------------- /resources/icons_backup/savepreset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/savepreset.png -------------------------------------------------------------------------------- /resources/icons_backup/thickness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/thickness.png -------------------------------------------------------------------------------- /resources/icons_backup/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/trash.png -------------------------------------------------------------------------------- /resources/icons_backup/up_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/up_arrow.png -------------------------------------------------------------------------------- /resources/icons_backup/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/white.png -------------------------------------------------------------------------------- /resources/icons_backup/writing_write_pen_icon_149355.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/writing_write_pen_icon_149355.png -------------------------------------------------------------------------------- /resources/icons_backup/yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/yellow.png -------------------------------------------------------------------------------- /resources/icons_backup/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icons_backup/zoom.png -------------------------------------------------------------------------------- /resources/icontest/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icontest/export.png -------------------------------------------------------------------------------- /resources/icontest/export_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icontest/export_reversed.png -------------------------------------------------------------------------------- /resources/icontest/import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icontest/import.png -------------------------------------------------------------------------------- /resources/icontest/import_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icontest/import_reversed.png -------------------------------------------------------------------------------- /resources/icontest/rope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icontest/rope.png -------------------------------------------------------------------------------- /resources/icontest/rope_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/icontest/rope_reversed.png -------------------------------------------------------------------------------- /resources/newicons/3643772-archive-archives-document-folder-open_113445.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/3643772-archive-archives-document-folder-open_113445.png -------------------------------------------------------------------------------- /resources/newicons/Chiseltipmarker_marker_3253.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/Chiseltipmarker_marker_3253.png -------------------------------------------------------------------------------- /resources/newicons/Circle_34541.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/Circle_34541.png -------------------------------------------------------------------------------- /resources/newicons/Circle_icon-icons.com_52186.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/Circle_icon-icons.com_52186.png -------------------------------------------------------------------------------- /resources/newicons/arrow_down_arrow_icon_253880.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/arrow_down_arrow_icon_253880.png -------------------------------------------------------------------------------- /resources/newicons/cross-symbol_icon-icons.com_74149.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/cross-symbol_icon-icons.com_74149.png -------------------------------------------------------------------------------- /resources/newicons/document_write_writing_draw_drawing_pen_icon_262129.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/document_write_writing_draw_drawing_pen_icon_262129.png -------------------------------------------------------------------------------- /resources/newicons/dustbin_120823.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/dustbin_120823.png -------------------------------------------------------------------------------- /resources/newicons/eraser_icon_173850.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/eraser_icon_173850.png -------------------------------------------------------------------------------- /resources/newicons/magnifier-1_icon-icons.com_56924.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/magnifier-1_icon-icons.com_56924.png -------------------------------------------------------------------------------- /resources/newicons/markerpen_marcado_3797.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/markerpen_marcado_3797.png -------------------------------------------------------------------------------- /resources/newicons/mountain-range-on-black-background_icon-icons.com_72655.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/mountain-range-on-black-background_icon-icons.com_72655.png -------------------------------------------------------------------------------- /resources/newicons/pdf-file-outlined-interface-symbol_icon-icons.com_57528.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/pdf-file-outlined-interface-symbol_icon-icons.com_57528.png -------------------------------------------------------------------------------- /resources/newicons/pen_3247.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/pen_3247.png -------------------------------------------------------------------------------- /resources/newicons/perfect-circle_icon-icons.com_53928.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/perfect-circle_icon-icons.com_53928.png -------------------------------------------------------------------------------- /resources/newicons/save_3621.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/save_3621.png -------------------------------------------------------------------------------- /resources/newicons/savedisk_121993.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/savedisk_121993.png -------------------------------------------------------------------------------- /resources/newicons/tab_add_filled_icon_201837.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/tab_add_filled_icon_201837.png -------------------------------------------------------------------------------- /resources/newicons/time_alarm_stopwatch_watch_hour_timer_clock_icon_252109.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/time_alarm_stopwatch_watch_hour_timer_clock_icon_252109.png -------------------------------------------------------------------------------- /resources/newicons/trafficlight-green_40427.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/trafficlight-green_40427.png -------------------------------------------------------------------------------- /resources/newicons/trafficlight-red_40428.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/trafficlight-red_40428.png -------------------------------------------------------------------------------- /resources/newicons/up_arrow_arrow_icon_253897.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/up_arrow_arrow_icon_253897.png -------------------------------------------------------------------------------- /resources/newicons/writing_write_pen_icon_149355.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/newicons/writing_write_pen_icon_149355.png -------------------------------------------------------------------------------- /resources/oldicons/addtab.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/addtab.ico -------------------------------------------------------------------------------- /resources/oldicons/background.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/background.ico -------------------------------------------------------------------------------- /resources/oldicons/benchmark.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/benchmark.ico -------------------------------------------------------------------------------- /resources/oldicons/black.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/black.ico -------------------------------------------------------------------------------- /resources/oldicons/blue.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/blue.ico -------------------------------------------------------------------------------- /resources/oldicons/cross.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/cross.ico -------------------------------------------------------------------------------- /resources/oldicons/down_arrow.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/down_arrow.ico -------------------------------------------------------------------------------- /resources/oldicons/eraser.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/eraser.ico -------------------------------------------------------------------------------- /resources/oldicons/folder.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/folder.ico -------------------------------------------------------------------------------- /resources/oldicons/fullscreen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/fullscreen.ico -------------------------------------------------------------------------------- /resources/oldicons/green.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/green.ico -------------------------------------------------------------------------------- /resources/oldicons/marker.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/marker.ico -------------------------------------------------------------------------------- /resources/oldicons/my_ebooks_folder_14975.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/my_ebooks_folder_14975.ico -------------------------------------------------------------------------------- /resources/oldicons/pdf.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/pdf.ico -------------------------------------------------------------------------------- /resources/oldicons/pdfdelete.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/pdfdelete.ico -------------------------------------------------------------------------------- /resources/oldicons/pen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/pen.ico -------------------------------------------------------------------------------- /resources/oldicons/red.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/red.ico -------------------------------------------------------------------------------- /resources/oldicons/save.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/save.ico -------------------------------------------------------------------------------- /resources/oldicons/saveannotated.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/saveannotated.ico -------------------------------------------------------------------------------- /resources/oldicons/thickness.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/thickness.ico -------------------------------------------------------------------------------- /resources/oldicons/trash.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/trash.ico -------------------------------------------------------------------------------- /resources/oldicons/up_arrow.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/up_arrow.ico -------------------------------------------------------------------------------- /resources/oldicons/white.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/white.ico -------------------------------------------------------------------------------- /resources/oldicons/yellow.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/yellow.ico -------------------------------------------------------------------------------- /resources/oldicons/zoom.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/oldicons/zoom.ico -------------------------------------------------------------------------------- /resources/reversed_icons/bookpage_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/reversed_icons/bookpage_reversed.png -------------------------------------------------------------------------------- /resources/reversed_icons/color_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/reversed_icons/color_reversed.png -------------------------------------------------------------------------------- /resources/reversed_icons/eraser_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/reversed_icons/eraser_reversed.png -------------------------------------------------------------------------------- /resources/reversed_icons/marker_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/reversed_icons/marker_reversed.png -------------------------------------------------------------------------------- /resources/reversed_icons/pen_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/reversed_icons/pen_reversed.png -------------------------------------------------------------------------------- /resources/reversed_icons/preset_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/reversed_icons/preset_reversed.png -------------------------------------------------------------------------------- /resources/reversed_icons/thickness_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/reversed_icons/thickness_reversed.png -------------------------------------------------------------------------------- /resources/reversed_icons/zoom_reversed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/reversed_icons/zoom_reversed.png -------------------------------------------------------------------------------- /resources/sounds/dial_click.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/sounds/dial_click.wav -------------------------------------------------------------------------------- /resources/translations/app_es.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/translations/app_es.qm -------------------------------------------------------------------------------- /resources/translations/app_es.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ButtonMappingHelper 6 | 7 | 8 | 9 | 10 | 11 | None 12 | Ninguno 13 | 14 | 15 | 16 | Page Switching 17 | 18 | 19 | 20 | 21 | Zoom Control 22 | 23 | 24 | 25 | 26 | Thickness Control 27 | 28 | 29 | 30 | 31 | Color Adjustment 32 | 33 | 34 | 35 | 36 | Tool Switching 37 | 38 | 39 | 40 | 41 | Preset Selection 42 | 43 | 44 | 45 | 46 | Pan and Page Scroll 47 | 48 | 49 | 50 | 51 | Toggle Fullscreen 52 | Cambiar a pantalla completa 53 | 54 | 55 | 56 | Toggle Dial 57 | 58 | 59 | 60 | 61 | Zoom 50% 62 | 63 | 64 | 65 | 66 | Zoom Out 67 | 68 | 69 | 70 | 71 | Zoom 200% 72 | 73 | 74 | 75 | 76 | Add Preset 77 | 78 | 79 | 80 | 81 | Delete Page 82 | 83 | 84 | 85 | 86 | Fast Forward 87 | 88 | 89 | 90 | 91 | Open Control Panel 92 | Abrir el Panel de Control 93 | 94 | 95 | 96 | Red 97 | 98 | 99 | 100 | 101 | Blue 102 | 103 | 104 | 105 | 106 | Yellow 107 | 108 | 109 | 110 | 111 | Green 112 | 113 | 114 | 115 | 116 | Black 117 | 118 | 119 | 120 | 121 | White 122 | 123 | 124 | 125 | 126 | Custom Color 127 | 128 | 129 | 130 | 131 | Toggle Sidebar 132 | 133 | 134 | 135 | 136 | Save 137 | 138 | 139 | 140 | 141 | Straight Line Tool 142 | 143 | 144 | 145 | 146 | Rope Tool 147 | 148 | 149 | 150 | 151 | Set Pen Tool 152 | 153 | 154 | 155 | 156 | Set Marker Tool 157 | 158 | 159 | 160 | 161 | Set Eraser Tool 162 | 163 | 164 | 165 | 166 | Left Shoulder 167 | 168 | 169 | 170 | 171 | Right Shoulder 172 | 173 | 174 | 175 | 176 | Paddle 2 177 | 178 | 179 | 180 | 181 | Paddle 4 182 | 183 | 184 | 185 | 186 | Y Button 187 | 188 | 189 | 190 | 191 | A Button 192 | 193 | 194 | 195 | 196 | B Button 197 | 198 | 199 | 200 | 201 | X Button 202 | 203 | 204 | 205 | 206 | Left Stick 207 | 208 | 209 | 210 | 211 | Start Button 212 | 213 | 214 | 215 | 216 | Guide Button 217 | 218 | 219 | 220 | 221 | ControlPanelDialog 222 | 223 | 224 | Canvas Control Panel 225 | Panel de control 226 | 227 | 228 | 229 | Background 230 | Fondo 231 | 232 | 233 | 234 | Performance 235 | Actuación 236 | 237 | 238 | 239 | Apply 240 | Aplicar 241 | 242 | 243 | 244 | OK 245 | DE ACUERDO 246 | 247 | 248 | 249 | Cancel 250 | Cancelar 251 | 252 | 253 | 254 | Background Style: 255 | Estilo de fondo: 256 | 257 | 258 | 259 | None 260 | Ninguno 261 | 262 | 263 | 264 | Grid 265 | Red 266 | 267 | 268 | 269 | Lines 270 | Pauta 271 | 272 | 273 | 274 | Background Color: 275 | Color de fondo: 276 | 277 | 278 | 279 | Density: 280 | Densidad: 281 | 282 | 283 | 284 | Select Background Color 285 | Seleccionar color de fondo 286 | 287 | 288 | 289 | Enable Low-Resolution PDF Previews 290 | Habilitar vistas previas de PDF de baja resolución 291 | 292 | 293 | 294 | Disabling this may improve dial smoothness on low-end devices. 295 | Deshabilitar esta opción puede mejorar la suavidad del marcado en dispositivos de gama baja. 296 | 297 | 298 | 299 | PDF Rendering DPI: 300 | 301 | 302 | 303 | 304 | Adjust how the PDF is rendered. Higher DPI means better quality but slower performance. DO NOT CHANGE THIS OPTION WHEN MULTIPLE TABS ARE OPEN. THIS MAY LEAD TO UNDEFINED BEHAVIOR! 305 | 306 | 307 | 308 | 309 | Show Benchmark Controls 310 | Mostrar controles de referencia 311 | 312 | 313 | 314 | This will show/hide the benchmark controls on the toolbar. Press the clock button to start/stop the benchmark. 315 | Esto mostrará u ocultará los controles de la prueba de rendimiento en la barra de herramientas. Pulse el botón del reloj para iniciar o detener la prueba de rendimiento. 316 | 317 | 318 | 319 | Show Color Buttons 320 | Mostrar botones de color 321 | 322 | 323 | 324 | This will show/hide the color buttons on the toolbar 325 | Esto mostrará/ocultará algunos de los botones de color en la barra de herramientas 326 | 327 | 328 | 329 | Scroll on Top after Page Switching 330 | Desplazarse hacia arriba después de cambiar de página 331 | 332 | 333 | 334 | Enabling this will make the page scroll to the top after switching to a new page. 335 | Habilitar esta opción hará que la página se desplace hacia la parte superior después de cambiar a una nueva página. 336 | 337 | 338 | 339 | Enable Touch Gestures 340 | 341 | 342 | 343 | 344 | Enable pinch to zoom and touch panning on the canvas. When disabled, only pen input is accepted. 345 | 346 | 347 | 348 | 349 | Features 350 | Características 351 | 352 | 353 | 354 | Hold: 355 | Sostener: 356 | 357 | 358 | 359 | Press: 360 | Prensa: 361 | 362 | 363 | 364 | Button Mapping 365 | Asignación de botones 366 | 367 | 368 | 369 | Configure custom keyboard shortcuts for application actions: 370 | 371 | 372 | 373 | 374 | Key Sequence 375 | 376 | 377 | 378 | 379 | Action 380 | 381 | 382 | 383 | 384 | Add Mapping 385 | 386 | 387 | 388 | 389 | 390 | Remove Mapping 391 | 392 | 393 | 394 | 395 | Keyboard Shortcuts 396 | 397 | 398 | 399 | 400 | Key Already Mapped 401 | 402 | 403 | 404 | 405 | The key sequence '%1' is already mapped. Please choose a different key combination. 406 | 407 | 408 | 409 | 410 | Select Action 411 | 412 | 413 | 414 | 415 | Choose the action to perform when '%1' is pressed: 416 | 417 | 418 | 419 | 420 | No Selection 421 | 422 | 423 | 424 | 425 | Please select a mapping to remove. 426 | 427 | 428 | 429 | 430 | Are you sure you want to remove the keyboard shortcut '%1'? 431 | 432 | 433 | 434 | 435 | InkCanvas 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | Export Error 444 | 445 | 446 | 447 | 448 | No export file specified. 449 | 450 | 451 | 452 | 453 | No notebook loaded (saveFolder is empty) 454 | 455 | 456 | 457 | 458 | No files found to export. 459 | 460 | 461 | 462 | 463 | Failed to create temporary file list. 464 | 465 | 466 | 467 | 468 | Tar process failed to finish. 469 | 470 | 471 | 472 | 473 | Tar process failed. 474 | 475 | 476 | 477 | 478 | Export 479 | 480 | 481 | 482 | 483 | Notebook exported successfully. 484 | 485 | 486 | 487 | 488 | Select Destination Folder for Imported Notebook 489 | 490 | 491 | 492 | 493 | Import Canceled 494 | 495 | 496 | 497 | 498 | No destination folder selected. 499 | 500 | 501 | 502 | 503 | Destination Not Empty 504 | 505 | 506 | 507 | 508 | The selected folder is not empty. Files may be overwritten. Continue? 509 | 510 | 511 | 512 | 513 | Import Complete 514 | 515 | 516 | 517 | 518 | 519 | Notebook imported successfully. 520 | 521 | 522 | 523 | 524 | Import 525 | 526 | 527 | 528 | 529 | KeyCaptureDialog 530 | 531 | 532 | Capture Key Sequence 533 | 534 | 535 | 536 | 537 | Press the key combination you want to use: 538 | 539 | 540 | 541 | 542 | 543 | (No key captured yet) 544 | 545 | 546 | 547 | 548 | Clear 549 | 550 | 551 | 552 | 553 | OK 554 | DE ACUERDO 555 | 556 | 557 | 558 | Cancel 559 | Cancelar 560 | 561 | 562 | 563 | MainWindow 564 | 565 | SpeedyNote Beta 0.4.2 566 | SpeedyNote Beta 0.4.2 567 | 568 | 569 | 570 | SpeedyNote Beta 0.4.10 571 | 572 | 573 | 574 | 575 | Load PDF 576 | Cargar PDF 577 | 578 | 579 | 580 | Clear PDF 581 | Borrar PDF 582 | 583 | 584 | 585 | Export Notebook Into .SNPKG File 586 | Exportar cuaderno a un archivo .SNPKG 587 | 588 | 589 | 590 | Import Notebook From .SNPKG File 591 | Importar un cuaderno desde un archivo .SNPKG 592 | 593 | 594 | 595 | Export Notebook 596 | 597 | 598 | 599 | 600 | Import Notebook 601 | 602 | 603 | 604 | 605 | Toggle Benchmark 606 | Alternar punto de referencia 607 | 608 | 609 | 610 | Show/Hide Tabs 611 | Mostrar/ocultar pestañas 612 | 613 | 614 | 615 | 616 | 617 | Select Save Folder 618 | Seleccionar carpeta para guardar 619 | 620 | 621 | 622 | Save Current Page 623 | Guardar página actual 624 | 625 | 626 | 627 | Save Page with Background 628 | Guardar página con fondo 629 | 630 | 631 | 632 | Toggle Fullscreen 633 | Cambiar a pantalla completa 634 | 635 | 636 | 637 | Set Background Pic 638 | Establecer imagen de fondo 639 | 640 | 641 | 642 | Toggle Straight Line Mode 643 | 644 | 645 | 646 | 647 | Toggle Rope Tool Mode 648 | 649 | 650 | 651 | 652 | Delete Current Page 653 | Eliminar página actual 654 | 655 | 656 | 657 | Set Zoom to 50% 658 | Establecer el zoom al 50% 659 | 660 | 661 | 662 | Set Zoom to 100% 663 | Establecer el zoom al 100% 664 | 665 | 666 | 667 | Set Zoom to 200% 668 | Establecer el zoom al 200% 669 | 670 | 671 | 672 | Toggle Magic Dial 673 | Activar/desactivar MagicDial 674 | 675 | 676 | 677 | Toggle Fast Forward 8x 678 | Alternar avance rápido 8x 679 | 680 | 681 | 682 | Set Dial Mode to Page Switching 683 | Establecer el modo de marcado en cambio de página 684 | 685 | 686 | 687 | Set Dial Mode to Zoom Ctrl 688 | Establecer el modo de dial en control de zoom 689 | 690 | 691 | 692 | Set Dial Mode to Pen Tip Thickness Ctrl 693 | Establezca el modo de dial en Control de grosor de la punta del lápiz 694 | 695 | 696 | 697 | Set Dial Mode to Color Adjustment 698 | Establecer el modo de marcado en Ajuste de color 699 | 700 | 701 | 702 | Set Dial Mode to Tool Switching 703 | Establecer el modo de marcado en Cambio de herramienta 704 | 705 | 706 | 707 | Set Dial Mode to Color Preset Selection 708 | Establecer el modo de marcado en Selección de preajuste de color 709 | 710 | 711 | 712 | Slide and turn pages with the dial 713 | Deslice y pase las páginas con el dial 714 | 715 | 716 | 717 | Add Current Color to Presets 718 | Agregar color actual a ajustes preestablecidos 719 | 720 | 721 | 722 | Open Control Panel 723 | Abrir el Panel de Control 724 | 725 | 726 | 727 | Open Recent Notebooks 728 | 729 | 730 | 731 | 732 | PR:N/A 733 | PR:N/A 734 | 735 | 736 | 737 | PR:%1 Hz 738 | PR:%1 Hz 739 | 740 | 741 | 742 | Select Background Image 743 | 744 | 745 | 746 | 747 | Cannot Load PDF 748 | 749 | 750 | 751 | 752 | Please select a permanent save folder before loading a PDF. 753 | 754 | Click the folder icon to choose a location for your notebook. 755 | 756 | 757 | 758 | 759 | Select PDF 760 | 761 | 762 | 763 | 764 | Notice 765 | Aviso 766 | 767 | 768 | 769 | At least one tab must remain open. 770 | Al menos una pestaña debe permanecer abierta. 771 | 772 | 773 | 774 | Unsaved Notebook 775 | 776 | 777 | 778 | 779 | This notebook is still using a temporary session folder. 780 | Please select a permanent folder to avoid data loss. 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | Page 789 | %1 790 | 791 | 792 | Página 793 | %1 794 | 795 | 796 | 797 | 798 | 799 | Thickness 800 | %1 801 | 802 | 803 | Espesor 804 | %1 805 | 806 | 807 | 808 | 809 | 810 | Zoom 811 | %1% 812 | 813 | 814 | Zoom 815 | %1% 816 | 817 | 818 | 819 | 820 | 821 | Adjust Red 822 | #%1 823 | 824 | 825 | Ajustar rojo 826 | #%1 827 | 828 | 829 | 830 | 831 | 832 | Adjust Green 833 | #%1 834 | 835 | 836 | Ajustar verde 837 | #%1 838 | 839 | 840 | 841 | 842 | 843 | Adjust Blue 844 | #%1 845 | 846 | 847 | Ajustar azul 848 | #%1 849 | 850 | 851 | 852 | 853 | 854 | 855 | Pen 856 | 857 | 858 | 859 | Bolígrafo 860 | 861 | 862 | 863 | 864 | 865 | 866 | Marker 867 | 868 | 869 | 870 | Marcador 871 | 872 | 873 | 874 | 875 | 876 | 877 | Eraser 878 | 879 | 880 | 881 | Borrador 882 | 883 | 884 | 885 | 886 | 887 | Preset %1 888 | #%2 889 | 890 | 891 | Programar %1 892 | #%2 893 | 894 | 895 | 896 | Etr 897 | 898 | 899 | 900 | 901 | Exit 902 | 903 | 904 | 905 | 906 | 907 | 908 | Page %1 909 | %2 FulScr 910 | 911 | 912 | 913 | 914 | Select Working Directory for Notebook 915 | 916 | 917 | 918 | 919 | Import Cancelled 920 | 921 | 922 | 923 | 924 | No directory selected. Notebook will not be opened. 925 | 926 | 927 | 928 | 929 | RecentNotebooksDialog 930 | 931 | 932 | Recent Notebooks 933 | 934 | 935 | 936 | 937 | No Preview 938 | 939 | 940 | 941 | 942 | RecentNotebooksManager 943 | 944 | 945 | Preview Error 946 | 947 | 948 | 949 | 950 | No Page 0 Preview 951 | 952 | 953 | 954 | 955 | -------------------------------------------------------------------------------- /resources/translations/app_fr.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/translations/app_fr.qm -------------------------------------------------------------------------------- /resources/translations/app_zh.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpha-liu-01/SpeedyNote/670fd3fa0fb4c199afb8745756a1d1b84706ed8d/resources/translations/app_zh.qm -------------------------------------------------------------------------------- /translate.ps1: -------------------------------------------------------------------------------- 1 | rm -r build 2 | mkdir build 3 | 4 | # ✅ Update translation source files (ensure the .ts files exist already) 5 | & "C:\Qt\6.8.2\mingw_64\bin\lupdate.exe" . -ts ./resources/translations/app_fr.ts ./resources/translations/app_zh.ts ./resources/translations/app_es.ts 6 | & "C:\Qt\6.8.2\mingw_64\bin\linguist.exe" resources/translations/app_zh.ts 7 | # & "C:\Qt\6.8.2\mingw_64\bin\linguist.exe" resources/translations/app_fr.ts 8 | # & "C:\Qt\6.8.2\mingw_64\bin\linguist.exe" resources/translations/app_es.ts 9 | --------------------------------------------------------------------------------