From 16de0a666c3a5d698e1c3c7b32447b82a9209657 Mon Sep 17 00:00:00 2001 From: ecorm <9456478-ecorm@users.noreply.gitlab.com> Date: Mon, 22 Jan 2024 21:02:50 -0400 Subject: [PATCH] Horizontal/vertical zoom for Simulator plots ADDED: Horizontal/vertical zoom for simulator plots, via mouse wheel, toolbar buttons, menu commands, and hotkeys. ADDED: Simulator preferences panel, populated with mouse wheel and trackpad settings that control pan and zoom of simulator plots. ADDED: Zoom In/Out Horizontally/Vertically commands that can be bound to hotkeys. CHANGED: Simulator plot scroll wheel gestures are no longer hard-coded and can now be configured via the new Simulator preferences panel. Fixes https://gitlab.com/kicad/code/kicad/-/issues/16597 Other unreported bugs that were fixed: - Fixed wierd, jumpy simulator plot view limiting behavior. - Fixed Zoom In Center and Zoom Out Center commands not preserving the simulator plot center point. - Fixed simulator plot nudging when exported as PNGs. - Fixed rectangular selection zoom being able to exceed simulator plot view limits. Notes: - Provided new SIM_PREFERENCES struct to be used for future simulator preferences set via the simulator preferences dialog. - Bundled pre-existing EESCHEMA_SETTINGS::SIMULATOR settings into EESCHEMA_SETTINGS::SIMULATOR::VIEW. - Replaced mpWindow::EnableMouseWheelPan with more general SetMouseWheelActions. - Refactored and tidied up wxMathPlot's mpWindow code involved with fitting, zooming, and panning. - Consolidated long lists of duplicated member variable initializers to a new mpWindow private delegated constructor. - Provided provisional Zoom In/Out Horizontally/Vertically toolbar icons that need improvement by a graphics designer. - Provided gitignore entries for the Qt Creator IDE --- .gitignore | 4 + AUTHORS.txt | 1 + common/bitmap_info.cpp | 40 + common/eda_base_frame.cpp | 1 + common/tool/actions.cpp | 30 +- common/widgets/mathplot.cpp | 714 ++++---- eeschema/CMakeLists.txt | 2 + .../dialogs/panel_simulator_preferences.cpp | 168 ++ .../dialogs/panel_simulator_preferences.fbp | 1431 +++++++++++++++++ .../dialogs/panel_simulator_preferences.h | 49 + .../panel_simulator_preferences_base.cpp | 166 ++ .../panel_simulator_preferences_base.h | 72 + eeschema/eeschema.cpp | 6 +- eeschema/eeschema_settings.cpp | 49 +- eeschema/eeschema_settings.h | 22 +- eeschema/sim/sim_plot_tab.h | 24 +- eeschema/sim/sim_preferences.h | 101 ++ eeschema/sim/sim_tab.cpp | 6 +- eeschema/sim/sim_tab.h | 5 +- eeschema/sim/simulator_frame.cpp | 12 +- eeschema/sim/simulator_frame.h | 4 +- eeschema/sim/simulator_frame_ui.cpp | 51 +- eeschema/sim/simulator_frame_ui.h | 9 +- eeschema/sim/toolbars_simulator_frame.cpp | 8 + eeschema/tools/simulator_control.cpp | 30 +- eeschema/tools/simulator_control.h | 3 +- include/bitmaps/bitmaps_list.h | 6 +- include/frame_type.h | 3 +- include/tool/actions.h | 6 +- include/widgets/mathplot.h | 96 +- .../png/zoom_in_horizontally_16.png | Bin 0 -> 272 bytes .../png/zoom_in_horizontally_24.png | Bin 0 -> 379 bytes .../png/zoom_in_horizontally_32.png | Bin 0 -> 516 bytes .../png/zoom_in_horizontally_48.png | Bin 0 -> 778 bytes .../png/zoom_in_horizontally_64.png | Bin 0 -> 1016 bytes .../png/zoom_in_horizontally_dark_16.png | Bin 0 -> 381 bytes .../png/zoom_in_horizontally_dark_24.png | Bin 0 -> 498 bytes .../png/zoom_in_horizontally_dark_32.png | Bin 0 -> 694 bytes .../png/zoom_in_horizontally_dark_48.png | Bin 0 -> 1025 bytes .../png/zoom_in_horizontally_dark_64.png | Bin 0 -> 1356 bytes .../bitmaps_png/png/zoom_in_vertically_16.png | Bin 0 -> 282 bytes .../bitmaps_png/png/zoom_in_vertically_24.png | Bin 0 -> 378 bytes .../bitmaps_png/png/zoom_in_vertically_32.png | Bin 0 -> 523 bytes .../bitmaps_png/png/zoom_in_vertically_48.png | Bin 0 -> 747 bytes .../bitmaps_png/png/zoom_in_vertically_64.png | Bin 0 -> 992 bytes .../png/zoom_in_vertically_dark_16.png | Bin 0 -> 392 bytes .../png/zoom_in_vertically_dark_24.png | Bin 0 -> 502 bytes .../png/zoom_in_vertically_dark_32.png | Bin 0 -> 697 bytes .../png/zoom_in_vertically_dark_48.png | Bin 0 -> 982 bytes .../png/zoom_in_vertically_dark_64.png | Bin 0 -> 1303 bytes .../png/zoom_out_horizontally_16.png | Bin 0 -> 264 bytes .../png/zoom_out_horizontally_24.png | Bin 0 -> 367 bytes .../png/zoom_out_horizontally_32.png | Bin 0 -> 505 bytes .../png/zoom_out_horizontally_48.png | Bin 0 -> 730 bytes .../png/zoom_out_horizontally_64.png | Bin 0 -> 965 bytes .../png/zoom_out_horizontally_dark_16.png | Bin 0 -> 369 bytes .../png/zoom_out_horizontally_dark_24.png | Bin 0 -> 486 bytes .../png/zoom_out_horizontally_dark_32.png | Bin 0 -> 677 bytes .../png/zoom_out_horizontally_dark_48.png | Bin 0 -> 969 bytes .../png/zoom_out_horizontally_dark_64.png | Bin 0 -> 1281 bytes .../png/zoom_out_vertically_16.png | Bin 0 -> 270 bytes .../png/zoom_out_vertically_24.png | Bin 0 -> 380 bytes .../png/zoom_out_vertically_32.png | Bin 0 -> 501 bytes .../png/zoom_out_vertically_48.png | Bin 0 -> 695 bytes .../png/zoom_out_vertically_64.png | Bin 0 -> 915 bytes .../png/zoom_out_vertically_dark_16.png | Bin 0 -> 382 bytes .../png/zoom_out_vertically_dark_24.png | Bin 0 -> 502 bytes .../png/zoom_out_vertically_dark_32.png | Bin 0 -> 686 bytes .../png/zoom_out_vertically_dark_48.png | Bin 0 -> 920 bytes .../png/zoom_out_vertically_dark_64.png | Bin 0 -> 1208 bytes .../sources/dark/zoom_in_horizontally.svg | 122 ++ .../sources/dark/zoom_in_vertically.svg | 122 ++ .../sources/dark/zoom_out_horizontally.svg | 114 ++ .../sources/dark/zoom_out_vertically.svg | 114 ++ .../sources/light/zoom_in_horizontally.svg | 122 ++ .../sources/light/zoom_in_vertically.svg | 122 ++ .../sources/light/zoom_out_horizontally.svg | 114 ++ .../sources/light/zoom_out_vertically.svg | 114 ++ 78 files changed, 3704 insertions(+), 359 deletions(-) create mode 100644 eeschema/dialogs/panel_simulator_preferences.cpp create mode 100644 eeschema/dialogs/panel_simulator_preferences.fbp create mode 100644 eeschema/dialogs/panel_simulator_preferences.h create mode 100644 eeschema/dialogs/panel_simulator_preferences_base.cpp create mode 100644 eeschema/dialogs/panel_simulator_preferences_base.h create mode 100644 eeschema/sim/sim_preferences.h create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_16.png create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_24.png create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_32.png create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_48.png create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_64.png create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_dark_16.png create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_dark_24.png create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_dark_32.png create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_dark_48.png create mode 100644 resources/bitmaps_png/png/zoom_in_horizontally_dark_64.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_16.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_24.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_32.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_48.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_64.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_dark_16.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_dark_24.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_dark_32.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_dark_48.png create mode 100644 resources/bitmaps_png/png/zoom_in_vertically_dark_64.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_16.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_24.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_32.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_48.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_64.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_dark_16.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_dark_24.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_dark_32.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_dark_48.png create mode 100644 resources/bitmaps_png/png/zoom_out_horizontally_dark_64.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_16.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_24.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_32.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_48.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_64.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_dark_16.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_dark_24.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_dark_32.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_dark_48.png create mode 100644 resources/bitmaps_png/png/zoom_out_vertically_dark_64.png create mode 100644 resources/bitmaps_png/sources/dark/zoom_in_horizontally.svg create mode 100644 resources/bitmaps_png/sources/dark/zoom_in_vertically.svg create mode 100644 resources/bitmaps_png/sources/dark/zoom_out_horizontally.svg create mode 100644 resources/bitmaps_png/sources/dark/zoom_out_vertically.svg create mode 100644 resources/bitmaps_png/sources/light/zoom_in_horizontally.svg create mode 100644 resources/bitmaps_png/sources/light/zoom_in_vertically.svg create mode 100644 resources/bitmaps_png/sources/light/zoom_out_horizontally.svg create mode 100644 resources/bitmaps_png/sources/light/zoom_out_vertically.svg diff --git a/.gitignore b/.gitignore index 7273096724..73f4cd0ee6 100644 --- a/.gitignore +++ b/.gitignore @@ -113,6 +113,10 @@ compile_commands.json .kdev4/ *.kdev4 +# Qt Creator +CMakeLists.txt.user +*.autosave + # Translations *.mo i18n_status.svg diff --git a/AUTHORS.txt b/AUTHORS.txt index 3ac31a167b..2b3cc40d88 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -51,6 +51,7 @@ Thomas Pointhuber Roberto Fernandez Bautista Mikołaj Wielgus Mike Williams +Emile Cormier See git repo on GitLab for contributors at https://gitlab.com/kicad/code/kicad/-/graphs/master diff --git a/common/bitmap_info.cpp b/common/bitmap_info.cpp index e372fc2d1c..1bda9c334b 100644 --- a/common/bitmap_info.cpp +++ b/common/bitmap_info.cpp @@ -755,6 +755,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_24.png" ), 24, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_24.png" ), 24, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_24.png" ), 24, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_24.png" ), 24, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::about].emplace_back( BITMAPS::about, wxT( "about_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::add_aligned_dimension].emplace_back( BITMAPS::add_aligned_dimension, wxT( "add_aligned_dimension_dark_24.png" ), 24, wxT( "dark" ) ); @@ -1157,6 +1161,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_dark_24.png" ), 24, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_dark_24.png" ), 24, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_dark_24.png" ), 24, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_dark_24.png" ), 24, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_dark_24.png" ), 24, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::about].emplace_back( BITMAPS::about, wxT( "about_16.png" ), 16, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::add_aligned_dimension].emplace_back( BITMAPS::add_aligned_dimension, wxT( "add_aligned_dimension_16.png" ), 16, wxT( "light" ) ); @@ -1559,6 +1567,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_16.png" ), 16, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_16.png" ), 16, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_16.png" ), 16, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_16.png" ), 16, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_16.png" ), 16, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_16.png" ), 16, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_16.png" ), 16, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_16.png" ), 16, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::about].emplace_back( BITMAPS::about, wxT( "about_dark_16.png" ), 16, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::add_aligned_dimension].emplace_back( BITMAPS::add_aligned_dimension, wxT( "add_aligned_dimension_dark_16.png" ), 16, wxT( "dark" ) ); @@ -1961,6 +1973,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_dark_16.png" ), 16, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_dark_16.png" ), 16, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_dark_16.png" ), 16, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_dark_16.png" ), 16, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_dark_16.png" ), 16, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_dark_16.png" ), 16, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_dark_16.png" ), 16, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_dark_16.png" ), 16, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::about].emplace_back( BITMAPS::about, wxT( "about_32.png" ), 32, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::add_aligned_dimension].emplace_back( BITMAPS::add_aligned_dimension, wxT( "add_aligned_dimension_32.png" ), 32, wxT( "light" ) ); @@ -2363,6 +2379,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_32.png" ), 32, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_32.png" ), 32, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_32.png" ), 32, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_32.png" ), 32, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_32.png" ), 32, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_32.png" ), 32, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_32.png" ), 32, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_32.png" ), 32, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::about].emplace_back( BITMAPS::about, wxT( "about_dark_32.png" ), 32, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::add_aligned_dimension].emplace_back( BITMAPS::add_aligned_dimension, wxT( "add_aligned_dimension_dark_32.png" ), 32, wxT( "dark" ) ); @@ -2765,6 +2785,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_dark_32.png" ), 32, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_dark_32.png" ), 32, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_dark_32.png" ), 32, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_dark_32.png" ), 32, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_dark_32.png" ), 32, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_dark_32.png" ), 32, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_dark_32.png" ), 32, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_dark_32.png" ), 32, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::about].emplace_back( BITMAPS::about, wxT( "about_48.png" ), 48, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::add_aligned_dimension].emplace_back( BITMAPS::add_aligned_dimension, wxT( "add_aligned_dimension_48.png" ), 48, wxT( "light" ) ); @@ -3167,6 +3191,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_48.png" ), 48, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_48.png" ), 48, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_48.png" ), 48, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_48.png" ), 48, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_48.png" ), 48, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_48.png" ), 48, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_48.png" ), 48, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_48.png" ), 48, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::about].emplace_back( BITMAPS::about, wxT( "about_dark_48.png" ), 48, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::add_aligned_dimension].emplace_back( BITMAPS::add_aligned_dimension, wxT( "add_aligned_dimension_dark_48.png" ), 48, wxT( "dark" ) ); @@ -3569,6 +3597,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_dark_48.png" ), 48, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_dark_48.png" ), 48, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_dark_48.png" ), 48, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_dark_48.png" ), 48, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_dark_48.png" ), 48, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_dark_48.png" ), 48, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_dark_48.png" ), 48, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_dark_48.png" ), 48, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::about].emplace_back( BITMAPS::about, wxT( "about_64.png" ), 64, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::add_aligned_dimension].emplace_back( BITMAPS::add_aligned_dimension, wxT( "add_aligned_dimension_64.png" ), 64, wxT( "light" ) ); @@ -3971,6 +4003,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_64.png" ), 64, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_64.png" ), 64, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_64.png" ), 64, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_64.png" ), 64, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_64.png" ), 64, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_64.png" ), 64, wxT( "light" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_64.png" ), 64, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_64.png" ), 64, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::about].emplace_back( BITMAPS::about, wxT( "about_dark_64.png" ), 64, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::add_aligned_dimension].emplace_back( BITMAPS::add_aligned_dimension, wxT( "add_aligned_dimension_dark_64.png" ), 64, wxT( "dark" ) ); @@ -4373,6 +4409,10 @@ void BuildBitmapInfo( std::unordered_map>& aBi aBitmapInfoCache[BITMAPS::zoom_center_on_screen].emplace_back( BITMAPS::zoom_center_on_screen, wxT( "zoom_center_on_screen_dark_64.png" ), 64, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_in].emplace_back( BITMAPS::zoom_in, wxT( "zoom_in_dark_64.png" ), 64, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_out].emplace_back( BITMAPS::zoom_out, wxT( "zoom_out_dark_64.png" ), 64, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_horizontally].emplace_back( BITMAPS::zoom_in_horizontally, wxT( "zoom_in_horizontally_dark_64.png" ), 64, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_horizontally].emplace_back( BITMAPS::zoom_out_horizontally, wxT( "zoom_out_horizontally_dark_64.png" ), 64, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_in_vertically].emplace_back( BITMAPS::zoom_in_vertically, wxT( "zoom_in_vertically_dark_64.png" ), 64, wxT( "dark" ) ); + aBitmapInfoCache[BITMAPS::zoom_out_vertically].emplace_back( BITMAPS::zoom_out_vertically, wxT( "zoom_out_vertically_dark_64.png" ), 64, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::zoom_selection].emplace_back( BITMAPS::zoom_selection, wxT( "zoom_selection_dark_64.png" ), 64, wxT( "dark" ) ); aBitmapInfoCache[BITMAPS::icon_bitmap2component_32].emplace_back( BITMAPS::icon_bitmap2component_32, wxT( "icon_bitmap2component_32_32.png" ), 32, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::icon_eeschema_32].emplace_back( BITMAPS::icon_eeschema_32, wxT( "icon_eeschema_32_32.png" ), 32, wxT( "light" ) ); diff --git a/common/eda_base_frame.cpp b/common/eda_base_frame.cpp index 441e197719..b014763608 100644 --- a/common/eda_base_frame.cpp +++ b/common/eda_base_frame.cpp @@ -1137,6 +1137,7 @@ void EDA_BASE_FRAME::ShowPreferences( wxString aStartPage, wxString aStartParent book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_ANNO_OPTIONS ), _( "Annotation Options" ) ); book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_COLORS ), _( "Colors" ) ); book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_FIELD_NAME_TEMPLATES ), _( "Field Name Templates" ) ); + book->AddLazySubPage( LAZY_CTOR( PANEL_SCH_SIMULATOR ), _( "Simulator" ) ); } catch( ... ) { diff --git a/common/tool/actions.cpp b/common/tool/actions.cpp index b9417347ca..bbb32aca68 100644 --- a/common/tool/actions.cpp +++ b/common/tool/actions.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2019-2023 CERN - * Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -568,6 +568,34 @@ TOOL_ACTION ACTIONS::zoomOutCenter( TOOL_ACTION_ARGS() .FriendlyName( _( "Zoom Out" ) ) .Icon( BITMAPS::zoom_out ) ); +TOOL_ACTION ACTIONS::zoomInHorizontally( TOOL_ACTION_ARGS() + .Name( "common.Control.zoomInHorizontally" ) + .Scope( AS_GLOBAL ) + .FriendlyName( _( "Zoom In Horizontally" ) ) + .Tooltip( _( "Zoom In Horizontally" ) ) + .Icon( BITMAPS::zoom_in_horizontally ) ); + +TOOL_ACTION ACTIONS::zoomOutHorizontally( TOOL_ACTION_ARGS() + .Name( "common.Control.zoomOutHorizontally" ) + .Scope( AS_GLOBAL ) + .FriendlyName( _( "Zoom Out Horizontally" ) ) + .Tooltip( _( "Zoom Out Horizontally" ) ) + .Icon( BITMAPS::zoom_out_horizontally ) ); + +TOOL_ACTION ACTIONS::zoomInVertically( TOOL_ACTION_ARGS() + .Name( "common.Control.zoomInVertically" ) + .Scope( AS_GLOBAL ) + .FriendlyName( _( "Zoom In Vertically" ) ) + .Tooltip( _( "Zoom In Vertically" ) ) + .Icon( BITMAPS::zoom_in_vertically ) ); + +TOOL_ACTION ACTIONS::zoomOutVertically( TOOL_ACTION_ARGS() + .Name( "common.Control.zoomOutVertically" ) + .Scope( AS_GLOBAL ) + .FriendlyName( _( "Zoom Out Vertically" ) ) + .Tooltip( _( "Zoom Out Vertically" ) ) + .Icon( BITMAPS::zoom_out_vertically ) ); + TOOL_ACTION ACTIONS::zoomCenter( TOOL_ACTION_ARGS() .Name( "common.Control.zoomCenter" ) .Scope( AS_GLOBAL ) diff --git a/common/widgets/mathplot.cpp b/common/widgets/mathplot.cpp index cc27b9e49a..b8fd77ce59 100644 --- a/common/widgets/mathplot.cpp +++ b/common/widgets/mathplot.cpp @@ -5,9 +5,9 @@ // Maintainer: Davide Rondini // Contributors: Jose Luis Blanco, Val Greene, Maciej Suminski, Tomasz Wlostowski // Created: 21/07/2003 -// Last edit: 2023 +// Last edit: 2024 // Copyright: (c) David Schalig, Davide Rondini -// Copyright (c) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors. +// Copyright (c) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors. // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -1367,82 +1367,14 @@ EVT_MENU( mpID_ZOOM_REDO, mpWindow::onZoomRedo ) END_EVENT_TABLE() mpWindow::mpWindow() : - wxWindow(), - m_minX( 0.0 ), - m_maxX( 0.0 ), - m_minY( 0.0 ), - m_maxY( 0.0 ), - m_scaleX( 1.0 ), - m_scaleY( 1.0 ), - m_posX( 0.0 ), - m_posY( 0.0 ), - m_scrX( 64 ), - m_scrY( 64 ), - m_clickedX( 0 ), - m_clickedY( 0 ), - m_yLocked( false ), - m_desiredXmin( 0.0 ), - m_desiredXmax( 1.0 ), - m_desiredYmin( 0.0 ), - m_desiredYmax( 1.0 ), - m_marginTop( 0 ), - m_marginRight( 0 ), - m_marginBottom( 0 ), - m_marginLeft( 0 ), - m_last_lx( 0 ), - m_last_ly( 0 ), - m_buff_bmp( nullptr ), - m_enableDoubleBuffer( false ), - m_enableMouseNavigation( true ), - m_enableMouseWheelPan( false ), - m_enableLimitedView( false ), - m_movingInfoLayer( nullptr ), - m_zooming( false ) + mpWindow( DelegatingContructorTag() ) { - if( wxGraphicsContext *ctx = m_buff_dc.GetGraphicsContext() ) - { - if( !ctx->SetInterpolationQuality( wxINTERPOLATION_BEST ) - || !ctx->SetInterpolationQuality( wxINTERPOLATION_GOOD ) ) - { - ctx->SetInterpolationQuality( wxINTERPOLATION_FAST ); - } - - ctx->SetAntialiasMode( wxANTIALIAS_DEFAULT ); - } + initializeGraphicsContext(); } mpWindow::mpWindow( wxWindow* parent, wxWindowID id ) : - wxWindow( parent, id, wxDefaultPosition, wxDefaultSize, 0, wxT( "mathplot" ) ), - m_minX( 0.0 ), - m_maxX( 0.0 ), - m_minY( 0.0 ), - m_maxY( 0.0 ), - m_scaleX( 1.0 ), - m_scaleY( 1.0 ), - m_posX( 0.0 ), - m_posY( 0.0 ), - m_scrX( 64 ), - m_scrY( 64 ), - m_clickedX( 0 ), - m_clickedY( 0 ), - m_yLocked( false ), - m_desiredXmin( 0.0 ), - m_desiredXmax( 1.0 ), - m_desiredYmin( 0.0 ), - m_desiredYmax( 1.0 ), - m_marginTop( 0 ), - m_marginRight( 0 ), - m_marginBottom( 0 ), - m_marginLeft( 0 ), - m_last_lx( 0 ), - m_last_ly( 0 ), - m_buff_bmp( nullptr ), - m_enableDoubleBuffer( false ), - m_enableMouseNavigation( true ), - m_enableMouseWheelPan( false ), - m_enableLimitedView( false ), - m_movingInfoLayer( nullptr ), - m_zooming( false ) + mpWindow( DelegatingContructorTag(), + parent, id, wxDefaultPosition, wxDefaultSize, 0, wxT( "mathplot" ) ) { m_popmenu.Append( mpID_ZOOM_UNDO, _( "Undo Last Zoom" ), _( "Return zoom to level prior to last zoom action" ) ); m_popmenu.Append( mpID_ZOOM_REDO, _( "Redo Last Zoom" ), _( "Return zoom to level prior to last zoom undo" ) ); @@ -1462,17 +1394,7 @@ mpWindow::mpWindow( wxWindow* parent, wxWindowID id ) : // J.L.Blanco: Eliminates the "flick" with the double buffer. SetBackgroundStyle( wxBG_STYLE_CUSTOM ); - if( wxGraphicsContext* ctx = m_buff_dc.GetGraphicsContext() ) - { - if( !ctx->SetInterpolationQuality( wxINTERPOLATION_BEST ) - || !ctx->SetInterpolationQuality( wxINTERPOLATION_GOOD ) ) - { - ctx->SetInterpolationQuality( wxINTERPOLATION_FAST ); - } - - ctx->SetAntialiasMode( wxANTIALIAS_DEFAULT ); - } - + initializeGraphicsContext(); UpdateAll(); } @@ -1524,56 +1446,37 @@ void mpWindow::onMouseWheel( wxMouseEvent& event ) return; } - int change = event.GetWheelRotation(); - const int axis = event.GetWheelAxis(); - double changeUnitsX = change / m_scaleX; - double changeUnitsY = change / m_scaleY; + const wxMouseWheelAxis axis = event.GetWheelAxis(); + const int modifiers = event.GetModifiers(); + MouseWheelAction action = MouseWheelAction::NONE; - if( ( !m_enableMouseWheelPan && ( event.ControlDown() || event.ShiftDown() ) ) - || ( m_enableMouseWheelPan && !event.ControlDown() ) ) + if( axis == wxMOUSE_WHEEL_HORIZONTAL ) { - // Scrolling - if( m_enableMouseWheelPan ) - { - if( axis == wxMOUSE_WHEEL_HORIZONTAL || event.ShiftDown() ) - { - SetXView( m_posX + changeUnitsX, m_desiredXmax + changeUnitsX, - m_desiredXmin + changeUnitsX ); - } - else if( !m_yLocked ) - { - SetYView( m_posY + changeUnitsY, m_desiredYmax + changeUnitsY, - m_desiredYmin + changeUnitsY ); - } - } - else - { - if( event.ControlDown() ) - { - SetXView( m_posX + changeUnitsX, m_desiredXmax + changeUnitsX, - m_desiredXmin + changeUnitsX ); - } - else if( !m_yLocked ) - { - SetYView( m_posY + changeUnitsY, m_desiredYmax + changeUnitsY, - m_desiredYmin + changeUnitsY ); - } - } - - UpdateAll(); + action = m_mouseWheelActions.horizontal; + } + else if( modifiers == wxMOD_NONE ) + { + action = m_mouseWheelActions.verticalUnmodified; + } + else if( modifiers == wxMOD_CONTROL ) + { + action = m_mouseWheelActions.verticalWithCtrl; + } + else if( modifiers == wxMOD_SHIFT ) + { + action = m_mouseWheelActions.verticalWithShift; + } + else if( modifiers == wxMOD_ALT ) + { + action = m_mouseWheelActions.verticalWithAlt; } else { - // zoom in/out - wxPoint clickPt( event.GetX(), event.GetY() ); - - if( event.GetWheelRotation() > 0 ) - ZoomIn( clickPt ); - else - ZoomOut( clickPt ); - + event.Skip(); return; } + + PerformMouseWheelAction( event, action ); } @@ -1716,107 +1619,151 @@ void mpWindow::Fit() // JL void mpWindow::Fit( double xMin, double xMax, double yMin, double yMax, - const wxCoord* printSizeX, const wxCoord* printSizeY ) + const wxCoord* printSizeX, const wxCoord* printSizeY, + wxOrientation directions ) { + const bool isPrinting = printSizeX != nullptr && printSizeY != nullptr; + // Save desired borders: - m_desiredXmin = xMin; m_desiredXmax = xMax; - m_desiredYmin = yMin; m_desiredYmax = yMax; + double newDesiredXmin = xMin; + double newDesiredXmax = xMax; + double newDesiredYmin = yMin; + double newDesiredYmax = yMax; - // Give a small margin to plot area - double xExtra = fabs( xMax - xMin ) * 0.00; - double yExtra = fabs( yMax - yMin ) * 0.03; + // Provide a gap between the extrema of the curve and the top/bottom edges of the + // plot area. Not to be confused with the left/right/top/bottom margins outside the plot area. + const double xGap = fabs( xMax - xMin ) * m_leftRightPlotGapFactor; + const double yGap = fabs( yMax - yMin ) * m_topBottomPlotGapFactor; + xMin -= xGap; + xMax += xGap; + yMin -= yGap; + yMax += yGap; - xMin -= xExtra; - xMax += xExtra; - yMin -= yExtra; - yMax += yExtra; + int newScrX = m_scrX; + int newScrY = m_scrY; - if( printSizeX != nullptr && printSizeY != nullptr ) + if( isPrinting ) { // Printer: - m_scrX = *printSizeX; - m_scrY = *printSizeY; + newScrX = *printSizeX; + newScrY = *printSizeY; } else { // Normal case (screen): - GetClientSize( &m_scrX, &m_scrY ); + GetClientSize( &newScrX, &newScrY ); } - double Ax = xMax - xMin; - double Ay = yMax - yMin; + // Compute the width/height in pixels for the plot area. + const int plotScreenWidth = newScrX - m_marginLeft - m_marginRight; + const int plotScreenHeight = newScrY - m_marginTop - m_marginBottom; - m_scaleX = (Ax != 0) ? (m_scrX - m_marginLeft - m_marginRight) / Ax : 1; - m_scaleY = (Ay != 0) ? (m_scrY - m_marginTop - m_marginBottom) / Ay : 1; + // Adjust scale so that desired X/Y span plus extra gap fits in the plot area + double desiredSpanX = xMax - xMin; + double desiredSpanY = yMax - yMin; + double newScaleX = (desiredSpanX != 0) ? double(plotScreenWidth) / desiredSpanX : 1; + double newScaleY = (desiredSpanY != 0) ? double(plotScreenHeight) / desiredSpanY : 1; - // Adjusts corner coordinates: This should be simply: - // m_posX = m_minX; - // m_posY = m_maxY; - // But account for centering if we have lock aspect: - m_posX = (xMin + xMax) / 2 - ( (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft ) / - m_scaleX; - m_posY = (yMin + yMax) / 2 + ( (m_scrY - m_marginTop - m_marginBottom) / 2 + m_marginTop ) / - m_scaleY; + // Adjust corner coordinates: + // Upstream's aspect lock code has been removed, so no need to account for centering. + double newPosX = xMin - (m_marginLeft / newScaleX); + double newPosY = yMax + (m_marginTop / newScaleY); - // It is VERY IMPORTANT to DO NOT call Refresh if we are drawing to the printer!! + // Commit above changes to member variables only if enabled for their respective dimension. + if( ((directions & wxHORIZONTAL) != 0) || isPrinting ) + { + // Don't commit the passed desired bounds when printing + if (!isPrinting) + { + m_desiredXmin = newDesiredXmin; + m_desiredXmax = newDesiredXmax; + } + + m_scrX = newScrX; + m_scaleX = newScaleX; + m_posX = newPosX; + } + + if( ((directions & wxVERTICAL) != 0) || isPrinting ) + { + // Don't commit the passed desired bounds when printing + if (!isPrinting) + { + m_desiredYmin = newDesiredYmin; + m_desiredYmax = newDesiredYmax; + } + + m_scrY = newScrY; + m_scaleY = newScaleY; + m_posY = newPosY; + } + + // It is VERY IMPORTANT to NOT call Refresh if we are drawing to the printer!! // Otherwise, the DC dimensions will be those of the window instead of the printer device - if( printSizeX == nullptr || printSizeY == nullptr ) + // The caller wanting to print should perform another Fit() afterwards to restore this + // object's state. + if( !isPrinting ) UpdateAll(); } -void mpWindow::AdjustLimitedView() +void mpWindow::AdjustLimitedView( wxOrientation directions ) { if( !m_enableLimitedView ) return; - // m_min and m_max are plot limits for curves - // xMin, xMax, yMin, yMax are the full limits (plot limit + margin) - const double xMin = m_minX - m_marginLeft / m_scaleX; - const double xMax = m_maxX + m_marginRight / m_scaleX; - const double yMin = m_minY - m_marginBottom / m_scaleY; - const double yMax = m_maxY + m_marginTop / m_scaleY; + // The m_desired* members are expressed in plot coordinates. + // They should be clamped against their respective m_minX, m_maxX, m_minY, m_maxY limits. - if( m_desiredXmin < xMin ) + if( (directions & wxHORIZONTAL) != 0 ) { - double diff = xMin - m_desiredXmin; - m_posX += diff; - m_desiredXmax += diff; - m_desiredXmin = xMin; + if( m_desiredXmin < m_minX ) + { + double diff = m_minX - m_desiredXmin; + m_posX += diff; + m_desiredXmax += diff; + m_desiredXmin = m_minX; + } + + if( m_desiredXmax > m_maxX ) + { + double diff = m_desiredXmax - m_maxX; + m_posX -= diff; + m_desiredXmin -= diff; + m_desiredXmax = m_maxX; + } } - if( m_desiredXmax > xMax ) + if( (directions & wxVERTICAL) != 0 ) { - double diff = m_desiredXmax - xMax; - m_posX -= diff; - m_desiredXmin -= diff; - m_desiredXmax = xMax; - } + if( m_desiredYmin < m_minY ) + { + double diff = m_minY - m_desiredYmin; + m_posY += diff; + m_desiredYmax += diff; + m_desiredYmin = m_minY; + } - if( m_desiredYmin < yMin ) - { - double diff = yMin - m_desiredYmin; - m_posY += diff; - m_desiredYmax += diff; - m_desiredYmin = yMin; - } - - if( m_desiredYmax > yMax ) - { - double diff = m_desiredYmax - yMax; - m_posY -= diff; - m_desiredYmin -= diff; - m_desiredYmax = yMax; + if( m_desiredYmax > m_maxY ) + { + double diff = m_desiredYmax - m_maxY; + m_posY -= diff; + m_desiredYmin -= diff; + m_desiredYmax = m_maxY; + } } } bool mpWindow::SetXView( double pos, double desiredMax, double desiredMin ) { + // TODO (ecorm): Investigate X scale flickering when panning at minimum zoom level + // Possible cause: When AdjustLimitedView subtracts the out-of-bound delta, it does not + // revert back to the exact same original coordinates due to floating point rounding errors. m_posX = pos; m_desiredXmax = desiredMax; m_desiredXmin = desiredMin; - AdjustLimitedView(); + AdjustLimitedView( wxHORIZONTAL ); return true; } @@ -1827,7 +1774,7 @@ bool mpWindow::SetYView( double pos, double desiredMax, double desiredMin ) m_posY = pos; m_desiredYmax = desiredMax; m_desiredYmin = desiredMin; - AdjustLimitedView(); + AdjustLimitedView( wxVERTICAL ); return true; } @@ -1835,116 +1782,28 @@ bool mpWindow::SetYView( double pos, double desiredMax, double desiredMin ) void mpWindow::ZoomIn( const wxPoint& centerPoint ) { - ZoomIn( centerPoint, zoomIncrementalFactor ); + ZoomIn( centerPoint, zoomIncrementalFactor, wxBOTH ); } -void mpWindow::ZoomIn( const wxPoint& centerPoint, double zoomFactor ) +void mpWindow::ZoomIn( const wxPoint& centerPoint, double zoomFactor, wxOrientation directions ) { - pushZoomUndo( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); - - wxPoint c( centerPoint ); - - if( c == wxDefaultPosition ) - { - GetClientSize( &m_scrX, &m_scrY ); - c.x = (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft; // c.x = m_scrX/2; - c.y = (m_scrY - m_marginTop - m_marginBottom) / 2 - m_marginTop; // c.y = m_scrY/2; - } - else - { - c.x = std::max( c.x, m_marginLeft ); - c.x = std::min( c.x, m_scrX - m_marginRight ); - c.y = std::max( c.y, m_marginTop ); - c.y = std::min( c.y, m_scrY - m_marginBottom ); - } - - // Preserve the position of the clicked point: - double prior_layer_x = p2x( c.x ); - double prior_layer_y = p2y( c.y ); - - // Zoom in: - const double MAX_SCALE = 1e6; - double newScaleX = m_scaleX * zoomFactor; - double newScaleY = m_scaleY * zoomFactor; - - // Baaaaad things happen when you zoom in too much.. - if( newScaleX <= MAX_SCALE && newScaleY <= MAX_SCALE ) - { - m_scaleX = newScaleX; - - if( !m_yLocked ) - m_scaleY = newScaleY; - } - else - { - return; - } - - // Adjust the new m_posx/y: - m_posX = prior_layer_x - c.x / m_scaleX; - - if( !m_yLocked ) - m_posY = prior_layer_y + c.y / m_scaleY; - - m_desiredXmin = m_posX; - m_desiredXmax = m_posX + (m_scrX - m_marginLeft - m_marginRight) / m_scaleX; - m_desiredYmax = m_posY; - m_desiredYmin = m_posY - (m_scrY - m_marginTop - m_marginBottom) / m_scaleY; - AdjustLimitedView(); - UpdateAll(); + DoZoom( centerPoint, zoomFactor, directions ); } void mpWindow::ZoomOut( const wxPoint& centerPoint ) { - ZoomOut( centerPoint, zoomIncrementalFactor ); + ZoomOut( centerPoint, zoomIncrementalFactor, wxBOTH ); } -void mpWindow::ZoomOut( const wxPoint& centerPoint, double zoomFactor ) +void mpWindow::ZoomOut( const wxPoint& centerPoint, double zoomFactor, + wxOrientation directions ) { - pushZoomUndo( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); - - wxPoint c( centerPoint ); - - if( c == wxDefaultPosition ) - { - GetClientSize( &m_scrX, &m_scrY ); - c.x = (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft; - c.y = (m_scrY - m_marginTop - m_marginBottom) / 2 - m_marginTop; - } - - // Preserve the position of the clicked point: - double prior_layer_x = p2x( c.x ); - double prior_layer_y = p2y( c.y ); - - // Zoom out: - m_scaleX = m_scaleX / zoomFactor; - - if( !m_yLocked ) - m_scaleY = m_scaleY / zoomFactor; - - // Adjust the new m_posx/y: - m_posX = prior_layer_x - c.x / m_scaleX; - - if( !m_yLocked ) - m_posY = prior_layer_y + c.y / m_scaleY; - - m_desiredXmin = m_posX; - m_desiredXmax = m_posX + (m_scrX - m_marginLeft - m_marginRight) / m_scaleX; - m_desiredYmax = m_posY; - m_desiredYmin = m_posY - (m_scrY - m_marginTop - m_marginBottom) / m_scaleY; - - AdjustLimitedView(); - - if( !CheckXLimits( m_desiredXmax, m_desiredXmin ) - || !CheckYLimits( m_desiredYmax, m_desiredYmin ) ) - { - Fit(); - } - - UpdateAll(); + if (zoomFactor == 0) + zoomFactor = 1.0; + DoZoom( centerPoint, 1.0 / zoomFactor, directions ); } @@ -1952,6 +1811,20 @@ void mpWindow::ZoomRect( wxPoint p0, wxPoint p1 ) { pushZoomUndo( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); + // Constrain given rectangle to plot area + const int pMinX = m_marginLeft; + const int pMaxX = m_scrX - m_marginRight; + const int pMinY = m_marginTop; + const int pMaxY = m_scrY - m_marginBottom; + p0.x = std::max( p0.x, pMinX ); + p0.x = std::min( p0.x, pMaxX ); + p0.y = std::max( p0.y, pMinY ); + p0.y = std::min( p0.y, pMaxY ); + p1.x = std::max( p1.x, pMinX ); + p1.x = std::min( p1.x, pMaxX ); + p1.y = std::max( p1.y, pMinY ); + p1.y = std::min( p1.y, pMaxY ); + // Compute the 2 corners in graph coordinates: double p0x = p2x( p0.x ); double p0y = p2y( p0.y ); @@ -1971,7 +1844,16 @@ void mpWindow::ZoomRect( wxPoint p0, wxPoint p1 ) } Fit( zoom_x_min, zoom_x_max, zoom_y_min, zoom_y_max ); + + // Even with the input rectangle contrained to the plot area, it's still possible for the + // resulting view to exceed limits when a portion of the gap is grabbed. AdjustLimitedView(); + + // These additional checks are needed because AdjustLimitedView only adjusts the position + // and not the scale. + wxOrientation directionsNeedingRefitting = ViewNeedsRefitting( wxBOTH ); + if( directionsNeedingRefitting != 0 ) + Fit( m_minX, m_maxX, m_minY, m_maxY, nullptr, nullptr, directionsNeedingRefitting ); } @@ -2043,6 +1925,18 @@ void mpWindow::OnCenter( wxCommandEvent& WXUNUSED( event ) ) } +mpWindow::MouseWheelActionSet mpWindow::defaultMouseWheelActions() +{ + MouseWheelActionSet actions; + actions.verticalUnmodified = MouseWheelAction::ZOOM; + actions.verticalWithCtrl = MouseWheelAction::PAN_LEFT_RIGHT; + actions.verticalWithShift = MouseWheelAction::PAN_UP_DOWN; + actions.verticalWithAlt = MouseWheelAction::NONE; + actions.horizontal = MouseWheelAction::NONE; + return actions; +} + + void mpWindow::onZoomIn( wxCommandEvent& WXUNUSED( event ) ) { ZoomIn( wxPoint( m_mouseMClick.x, m_mouseMClick.y ) ); @@ -2188,6 +2082,199 @@ void mpWindow::OnPaint( wxPaintEvent& WXUNUSED( event ) ) paintDC.Blit( 0, 0, m_scrX, m_scrY, targetDC, 0, 0 ); } +void mpWindow::DoZoom( const wxPoint& centerPoint, double zoomFactor, + wxOrientation directions ) +{ + if( m_yLocked ) + { + if( directions == wxVERTICAL ) + return; + directions = wxHORIZONTAL; + } + + const bool horizontally = (directions & wxHORIZONTAL) != 0; + const bool vertically = (directions & wxVERTICAL) != 0; + + pushZoomUndo( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); + + // Preserve the position of the clicked point: + wxPoint c( centerPoint ); + if( c == wxDefaultPosition ) + { + GetClientSize( &m_scrX, &m_scrY ); + c.x = (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft; + c.y = (m_scrY - m_marginTop - m_marginBottom) / 2 + m_marginTop; + } + else + { + c.x = std::max( c.x, m_marginLeft ); + c.x = std::min( c.x, m_scrX - m_marginRight ); + c.y = std::max( c.y, m_marginTop ); + c.y = std::min( c.y, m_scrY - m_marginBottom ); + } + + // Zoom in/out: + const double MAX_SCALE = 1e6; + const double newScaleX = horizontally ? (m_scaleX * zoomFactor) : m_scaleX; + const double newScaleY = vertically ? (m_scaleY * zoomFactor) : m_scaleY; + + // Baaaaad things happen when you zoom in too much.. + if( newScaleX > MAX_SCALE || newScaleY > MAX_SCALE ) + return; + + if ( horizontally ) + { + // Transform the clicked X point to layer coordinates: + const double prior_layer_x = p2x( c.x ); + + // Adjust the new X scale and plot X origin: + m_scaleX = newScaleX; + m_posX = prior_layer_x - c.x / newScaleX; + + // Recompute the desired X view extents: + RecomputeDesiredX( m_desiredXmin, m_desiredXmax ); + } + + if ( vertically ) + { + // Transform the clicked Y point to layer coordinates: + const double prior_layer_y = p2y( c.y ); + + // Adjust the new Y scale and plot Y origin: + m_scaleY = newScaleY; + m_posY = prior_layer_y + c.y / newScaleY; + + // Recompute the desired Y view extents: + RecomputeDesiredY( m_desiredYmin, m_desiredYmax ); + } + + AdjustLimitedView( directions ); + + if (zoomFactor < 1.0) + { + // These additional checks are needed because AdjustLimitedView only adjusts the position + // and not the scale. + wxOrientation directionsNeedingRefitting = ViewNeedsRefitting( directions ); + + // If the view is still out-of-limits after AdjustLimitedView is called, perform a Fit + // along the offending dimension(s). + if( directionsNeedingRefitting != 0 ) + Fit( m_minX, m_maxX, m_minY, m_maxY, nullptr, nullptr, directionsNeedingRefitting ); + } + + UpdateAll(); +} + + +void mpWindow::RecomputeDesiredX( double& min, double& max ) +{ + const int plotScreenWidth = m_scrX - m_marginLeft - m_marginRight; + const double plotSpanX = plotScreenWidth / m_scaleX; + const double desiredSpanX = plotSpanX / ( 2*m_leftRightPlotGapFactor + 1 ); + const double xGap = desiredSpanX * m_leftRightPlotGapFactor; + min = m_posX + ( m_marginLeft / m_scaleX ) + xGap; + max = m_desiredXmin + desiredSpanX; +} + + +void mpWindow::RecomputeDesiredY( double& min, double& max ) +{ + const int plotScreenHeight = m_scrY - m_marginTop - m_marginBottom; + const double plotSpanY = plotScreenHeight / m_scaleY; + const double desiredSpanY = plotSpanY / ( 2*m_topBottomPlotGapFactor + 1 ); + const double yGap = desiredSpanY * m_topBottomPlotGapFactor; + max = m_posY - ( m_marginTop / m_scaleY) - yGap; + min = m_desiredYmax - desiredSpanY; +} + + +wxOrientation mpWindow::ViewNeedsRefitting( wxOrientation directions ) const +{ + if( !m_enableLimitedView ) + return static_cast( 0 ); + + // Allow a gap between the extrema of the curve and the edges of the plot area. Not to be + // confused with the left/right/top/bottom margins outside the plot area. + const double xGap = fabs( m_maxX - m_minX ) * m_leftRightPlotGapFactor; + const double yGap = fabs( m_maxY - m_minY ) * m_topBottomPlotGapFactor; + + wxOrientation result = {}; + + if ( (directions & wxHORIZONTAL) != 0 ) + { + if ( ( m_desiredXmax > m_maxX + xGap ) || ( m_desiredXmin < m_minX - xGap ) ) + result = static_cast( result | wxHORIZONTAL ); + } + + if ( (directions & wxVERTICAL) != 0 ) + { + if ( ( m_desiredYmax > m_maxY + yGap ) || ( m_desiredYmin < m_minY - yGap ) ) + result = static_cast( result | wxVERTICAL ); + } + + return result; +} + + +void mpWindow::PerformMouseWheelAction( wxMouseEvent& event, MouseWheelAction action ) +{ + const int change = event.GetWheelRotation(); + const double changeUnitsX = change / m_scaleX; + const double changeUnitsY = change / m_scaleY; + const wxPoint clickPt( event.GetX(), event.GetY() ); + + switch (action) + { + case MouseWheelAction::NONE: + break; + + case MouseWheelAction::PAN_LEFT_RIGHT: + SetXView( m_posX + changeUnitsX, m_desiredXmax + changeUnitsX, + m_desiredXmin + changeUnitsX ); + UpdateAll(); + break; + + case MouseWheelAction::PAN_RIGHT_LEFT: + SetXView( m_posX - changeUnitsX, m_desiredXmax - changeUnitsX, + m_desiredXmin - changeUnitsX ); + UpdateAll(); + break; + + case MouseWheelAction::PAN_UP_DOWN: + if( !m_yLocked ) + { + SetYView( m_posY + changeUnitsY, m_desiredYmax + changeUnitsY, + m_desiredYmin + changeUnitsY ); + UpdateAll(); + } + break; + + case MouseWheelAction::ZOOM: + if( event.GetWheelRotation() > 0 ) + ZoomIn( clickPt ); + else + ZoomOut( clickPt ); + break; + + case MouseWheelAction::ZOOM_HORIZONTALLY: + if( event.GetWheelRotation() > 0 ) + ZoomIn( clickPt, zoomIncrementalFactor, wxHORIZONTAL ); + else + ZoomOut( clickPt, zoomIncrementalFactor, wxHORIZONTAL ); + break; + + case MouseWheelAction::ZOOM_VERTICALLY: + if( event.GetWheelRotation() > 0 ) + ZoomIn( clickPt, zoomIncrementalFactor, wxVERTICAL ); + else + ZoomOut( clickPt, zoomIncrementalFactor, wxVERTICAL ); + break; + + default: + break; + } +} + bool mpWindow::UpdateBBox() { @@ -2392,6 +2479,59 @@ void mpWindow::SetColourTheme( const wxColour& bgColour, const wxColour& drawCol } +template +mpWindow::mpWindow( DelegatingContructorTag, Ts&&... windowArgs ) : + wxWindow( std::forward( windowArgs )... ), + m_minX( 0.0 ), + m_maxX( 0.0 ), + m_minY( 0.0 ), + m_maxY( 0.0 ), + m_scaleX( 1.0 ), + m_scaleY( 1.0 ), + m_posX( 0.0 ), + m_posY( 0.0 ), + m_scrX( 64 ), + m_scrY( 64 ), + m_clickedX( 0 ), + m_clickedY( 0 ), + m_yLocked( false ), + m_desiredXmin( 0.0 ), + m_desiredXmax( 1.0 ), + m_desiredYmin( 0.0 ), + m_desiredYmax( 1.0 ), + m_topBottomPlotGapFactor( 0.03 ), + m_leftRightPlotGapFactor( 0.0 ), + m_marginTop( 0 ), + m_marginRight( 0 ), + m_marginBottom( 0 ), + m_marginLeft( 0 ), + m_last_lx( 0 ), + m_last_ly( 0 ), + m_buff_bmp( nullptr ), + m_enableDoubleBuffer( false ), + m_enableMouseNavigation( true ), + m_enableLimitedView( false ), + m_mouseWheelActions( defaultMouseWheelActions() ), + m_movingInfoLayer( nullptr ), + m_zooming( false ) +{} + + +void mpWindow::initializeGraphicsContext() +{ + if( wxGraphicsContext* ctx = m_buff_dc.GetGraphicsContext() ) + { + if( !ctx->SetInterpolationQuality( wxINTERPOLATION_BEST ) + || !ctx->SetInterpolationQuality( wxINTERPOLATION_GOOD ) ) + { + ctx->SetInterpolationQuality( wxINTERPOLATION_FAST ); + } + + ctx->SetAntialiasMode( wxANTIALIAS_DEFAULT ); + } +} + + // ----------------------------------------------------------------------------- // mpFXYVector implementation - by Jose Luis Blanco (AGO-2007) // ----------------------------------------------------------------------------- diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 014ce6ca40..801970d72c 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -186,6 +186,8 @@ set( EESCHEMA_DLGS dialogs/panel_setup_formatting_base.cpp dialogs/panel_setup_pinmap.cpp dialogs/panel_setup_pinmap_base.cpp + dialogs/panel_simulator_preferences.cpp + dialogs/panel_simulator_preferences_base.cpp dialogs/panel_sym_color_settings.cpp dialogs/panel_sym_color_settings_base.cpp dialogs/panel_sym_display_options.cpp diff --git a/eeschema/dialogs/panel_simulator_preferences.cpp b/eeschema/dialogs/panel_simulator_preferences.cpp new file mode 100644 index 0000000000..fe5f3e9097 --- /dev/null +++ b/eeschema/dialogs/panel_simulator_preferences.cpp @@ -0,0 +1,168 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include +#include +#include +#include "panel_simulator_preferences.h" +#include "../eeschema_settings.h" + + +PANEL_SIMULATOR_PREFERENCES::PANEL_SIMULATOR_PREFERENCES( wxWindow* aParent ) : + PANEL_SIMULATOR_PREFERENCES_BASE( aParent ) +{ +#ifdef __WXOSX_MAC__ + m_lblVScrollCtrl->SetLabel( _( "Cmd" ) ); + m_lblVScrollAlt->SetLabel( _( "Option" ) ); +#endif + + // Populate the wxChoice items programmatically here instead of via the form builder + // to ease maintenance. + + static const wxString verticalChoiceItems[] = + { + _("No action"), + _("Pan left/right"), + _("Pan right/left"), + _("Pan up/down"), + _("Zoom"), + _("Zoom horizontally"), + _("Zoom vertically") + }; + + static constexpr auto ACTION_COUNT = static_cast( SIM_MOUSE_WHEEL_ACTION::COUNT ); + + static_assert( std::extent::value == ACTION_COUNT, + "verticalChoiceItems size does not match VERTICAL_SCROLL_ACTION::COUNT" ); + + m_choiceVScrollUnmodified->Set( ACTION_COUNT, verticalChoiceItems ); + m_choiceVScrollCtrl ->Set( ACTION_COUNT, verticalChoiceItems ); + m_choiceVScrollShift ->Set( ACTION_COUNT, verticalChoiceItems ); + m_choiceVScrollAlt ->Set( ACTION_COUNT, verticalChoiceItems ); + + static const wxString horizontalChoiceItems[] = + { + _("No action"), + _("Pan left/right"), + _("Zoom horizontally") + }; + + m_choiceHScroll->Set( std::extent::value, + horizontalChoiceItems ); +} + + +PANEL_SIMULATOR_PREFERENCES::~PANEL_SIMULATOR_PREFERENCES() = default; + + +void PANEL_SIMULATOR_PREFERENCES::ResetPanel() +{ + applyMouseScrollActionsToPanel( SIM_MOUSE_WHEEL_ACTION_SET::GetMouseDefaults() ); +} + + +bool PANEL_SIMULATOR_PREFERENCES::TransferDataFromWindow() +{ + static constexpr auto toAction = + []( const wxChoice* aChoice ) + { + return static_cast( aChoice->GetSelection() ); + }; + + SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager(); + EESCHEMA_SETTINGS* settings = mgr.GetAppSettings(); + SIM_MOUSE_WHEEL_ACTION_SET& actions = settings->m_Simulator.preferences.mouse_wheel_actions; + + actions.vertical_unmodified = toAction( m_choiceVScrollUnmodified ); + actions.vertical_with_ctrl = toAction( m_choiceVScrollCtrl ); + actions.vertical_with_shift = toAction( m_choiceVScrollShift ); + actions.vertical_with_alt = toAction( m_choiceVScrollAlt ); + + actions.horizontal = horizontalScrollSelectionToAction( m_choiceHScroll->GetSelection() ); + + return true; +} + + +bool PANEL_SIMULATOR_PREFERENCES::TransferDataToWindow() +{ + SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager(); + const EESCHEMA_SETTINGS* settings = mgr.GetAppSettings(); + applyMouseScrollActionsToPanel( settings->m_Simulator.preferences.mouse_wheel_actions ); + return true; +} + + +void PANEL_SIMULATOR_PREFERENCES::onMouseDefaults( wxCommandEvent& ) +{ + applyMouseScrollActionsToPanel( SIM_MOUSE_WHEEL_ACTION_SET::GetMouseDefaults() ); +} + + +void PANEL_SIMULATOR_PREFERENCES::onTrackpadDefaults( wxCommandEvent& ) +{ + applyMouseScrollActionsToPanel( SIM_MOUSE_WHEEL_ACTION_SET::GetTrackpadDefaults() ); +} + + +SIM_MOUSE_WHEEL_ACTION +PANEL_SIMULATOR_PREFERENCES::horizontalScrollSelectionToAction( int aSelection ) +{ + switch( aSelection ) + { + case 0: return SIM_MOUSE_WHEEL_ACTION::NONE; + case 1: return SIM_MOUSE_WHEEL_ACTION::PAN_LEFT_RIGHT; + case 2: return SIM_MOUSE_WHEEL_ACTION::ZOOM_HORIZONTALLY; + default: break; + } + + return SIM_MOUSE_WHEEL_ACTION::NONE; +} + +int PANEL_SIMULATOR_PREFERENCES::actionToHorizontalScrollSelection( SIM_MOUSE_WHEEL_ACTION a ) +{ + switch( a ) + { + case SIM_MOUSE_WHEEL_ACTION::NONE: return 0; + case SIM_MOUSE_WHEEL_ACTION::PAN_LEFT_RIGHT: return 1; + case SIM_MOUSE_WHEEL_ACTION::ZOOM_HORIZONTALLY: return 2; + default: break; + } + + return 0; +} + + +void PANEL_SIMULATOR_PREFERENCES::applyMouseScrollActionsToPanel( + const SIM_MOUSE_WHEEL_ACTION_SET& anActionSet ) +{ + static constexpr auto setSelection = + []( wxChoice* aChoice, auto action ) + { + aChoice->SetSelection( static_cast( action ) ); + }; + + setSelection( m_choiceVScrollUnmodified, anActionSet.vertical_unmodified ); + setSelection( m_choiceVScrollCtrl, anActionSet.vertical_with_ctrl ); + setSelection( m_choiceVScrollShift, anActionSet.vertical_with_shift ); + setSelection( m_choiceVScrollAlt, anActionSet.vertical_with_alt ); + + m_choiceHScroll->SetSelection( actionToHorizontalScrollSelection( anActionSet.horizontal ) ); +} diff --git a/eeschema/dialogs/panel_simulator_preferences.fbp b/eeschema/dialogs/panel_simulator_preferences.fbp new file mode 100644 index 0000000000..9dfe23403a --- /dev/null +++ b/eeschema/dialogs/panel_simulator_preferences.fbp @@ -0,0 +1,1431 @@ + + + + + ; + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + panel_simulator_preferences_base + 1000 + none + + + 1 + PANEL_SIMULATOR_PREFERENCES_BASE + + . + + 1 + 1 + 1 + 1 + UI + 0 + 1 + 0 + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 1 + impl_virtual + + + 0 + wxID_ANY + + + PANEL_SIMULATOR_PREFERENCES_BASE + + -1,-1 + RESETTABLE_PANEL; widgets/resettable_panel.h; Not forward_declare + + 0 + + + wxTAB_TRAVERSAL + + + bMainSizer + wxVERTICAL + none + + 5 + + 1 + + + bScrollSizer + wxVERTICAL + none + + 13 + wxEXPAND|wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Scroll Gestures + 0 + + 0 + + + 0 + + 1 + m_lblScrollHeading + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND|wxBOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_scrollLine + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 10 + wxEXPAND|wxTOP|wxRIGHT + 1 + + + bScrollMargins + wxHORIZONTAL + none + + 5 + wxEXPAND|wxLEFT + 0 + + + bScrollSizerLeft + wxVERTICAL + none + + 5 + wxLEFT|wxRIGHT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Vertical touchpad or scroll wheel movement: + 0 + + 0 + + + 0 + + 1 + m_lblVScrollMovement + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 0 + + 10 + protected + 0 + + + + 24 + wxRIGHT|wxLEFT + 0 + + 2 + wxBOTH + 0 + + 0 + + fgVScroll + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALIGN_BOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Modifier + 0 + + 0 + + + 0 + + 1 + m_lblVScrollModifier + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Action + 0 + + 0 + + + 0 + -1,-1 + 1 + m_lblVScrollAction + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + None: + 0 + + 0 + + + 0 + + 1 + m_lblVScrollUnmodified + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceVScrollUnmodified + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Ctrl: + 0 + + 0 + + + 0 + + 1 + m_lblVScrollCtrl + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceVScrollCtrl + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Shift: + 0 + + 0 + + + 0 + + 1 + m_lblVScrollShift + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceVScrollShift + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Alt: + 0 + + 0 + + + 0 + + 1 + m_lblVScrollAlt + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceVScrollAlt + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 0 + + 10 + protected + 0 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Horizontal touchpad movement: + 0 + + 0 + + + 0 + + 1 + m_lblHScrollMovement + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 0 + + 10 + protected + 0 + + + + 24 + wxRIGHT|wxLEFT + 0 + + 2 + wxBOTH + 0 + + 0 + + fgHScroll + wxFLEX_GROWMODE_SPECIFIED + none + 0 + 0 + + 5 + wxALIGN_BOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Modifier + 0 + + 0 + + + 0 + + 1 + m_lblHScrollModifier + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Action + 0 + + 0 + + + 0 + -1,-1 + 1 + m_lblHScrollAction + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Any: + 0 + + 0 + + + 0 + + 1 + m_lblHScrollAny + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_choiceHScroll + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + 5 + wxTOP|wxLEFT|wxEXPAND + 0 + + + bScrollSizerRight + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Reset to Mouse Defaults + + 0 + + 0 + + + 0 + + 1 + m_btnMouseDefaults + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onMouseDefaults + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Reset to Trackpad Defaults + + 0 + + 0 + + + 0 + + 1 + m_btnTrackpadDefaults + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onTrackpadDefaults + + + + + + + + + + + + diff --git a/eeschema/dialogs/panel_simulator_preferences.h b/eeschema/dialogs/panel_simulator_preferences.h new file mode 100644 index 0000000000..5704f536ab --- /dev/null +++ b/eeschema/dialogs/panel_simulator_preferences.h @@ -0,0 +1,49 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef KICAD_PANEL_SIMULATOR_PREFERENCES_H +#define KICAD_PANEL_SIMULATOR_PREFERENCES_H + +#include "panel_simulator_preferences_base.h" +#include + + +class PANEL_SIMULATOR_PREFERENCES : public PANEL_SIMULATOR_PREFERENCES_BASE +{ +public: + PANEL_SIMULATOR_PREFERENCES( wxWindow* aParent ); + ~PANEL_SIMULATOR_PREFERENCES(); + void ResetPanel() override; + +protected: + bool TransferDataFromWindow() override; + bool TransferDataToWindow() override; + void onMouseDefaults( wxCommandEvent& ) override; + void onTrackpadDefaults( wxCommandEvent& ) override; + +private: + static SIM_MOUSE_WHEEL_ACTION horizontalScrollSelectionToAction( int aSelection ); + + static int actionToHorizontalScrollSelection( SIM_MOUSE_WHEEL_ACTION anAction ); + + void applyMouseScrollActionsToPanel( const SIM_MOUSE_WHEEL_ACTION_SET& anActionSet ); +}; + + +#endif diff --git a/eeschema/dialogs/panel_simulator_preferences_base.cpp b/eeschema/dialogs/panel_simulator_preferences_base.cpp new file mode 100644 index 0000000000..f1c0dcbd6b --- /dev/null +++ b/eeschema/dialogs/panel_simulator_preferences_base.cpp @@ -0,0 +1,166 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b) +// http://www.wxformbuilder.org/ +// +// PLEASE DO *NOT* EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "panel_simulator_preferences_base.h" + +/////////////////////////////////////////////////////////////////////////// + +PANEL_SIMULATOR_PREFERENCES_BASE::PANEL_SIMULATOR_PREFERENCES_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : RESETTABLE_PANEL( parent, id, pos, size, style, name ) +{ + wxBoxSizer* bMainSizer; + bMainSizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bScrollSizer; + bScrollSizer = new wxBoxSizer( wxVERTICAL ); + + m_lblScrollHeading = new wxStaticText( this, wxID_ANY, _("Scroll Gestures"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblScrollHeading->Wrap( -1 ); + bScrollSizer->Add( m_lblScrollHeading, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 13 ); + + m_scrollLine = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); + bScrollSizer->Add( m_scrollLine, 0, wxEXPAND|wxBOTTOM, 5 ); + + wxBoxSizer* bScrollMargins; + bScrollMargins = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bScrollSizerLeft; + bScrollSizerLeft = new wxBoxSizer( wxVERTICAL ); + + m_lblVScrollMovement = new wxStaticText( this, wxID_ANY, _("Vertical touchpad or scroll wheel movement:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblVScrollMovement->Wrap( -1 ); + bScrollSizerLeft->Add( m_lblVScrollMovement, 0, wxLEFT|wxRIGHT, 5 ); + + + bScrollSizerLeft->Add( 0, 10, 0, wxEXPAND, 5 ); + + wxFlexGridSizer* fgVScroll; + fgVScroll = new wxFlexGridSizer( 0, 2, 0, 0 ); + fgVScroll->AddGrowableCol( 0 ); + fgVScroll->SetFlexibleDirection( wxBOTH ); + fgVScroll->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_lblVScrollModifier = new wxStaticText( this, wxID_ANY, _("Modifier"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblVScrollModifier->Wrap( -1 ); + fgVScroll->Add( m_lblVScrollModifier, 0, wxALIGN_BOTTOM, 5 ); + + m_lblVScrollAction = new wxStaticText( this, wxID_ANY, _("Action"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblVScrollAction->Wrap( -1 ); + fgVScroll->Add( m_lblVScrollAction, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 5 ); + + m_lblVScrollUnmodified = new wxStaticText( this, wxID_ANY, _("None:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblVScrollUnmodified->Wrap( -1 ); + fgVScroll->Add( m_lblVScrollUnmodified, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + wxArrayString m_choiceVScrollUnmodifiedChoices; + m_choiceVScrollUnmodified = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceVScrollUnmodifiedChoices, 0 ); + m_choiceVScrollUnmodified->SetSelection( 0 ); + fgVScroll->Add( m_choiceVScrollUnmodified, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_lblVScrollCtrl = new wxStaticText( this, wxID_ANY, _("Ctrl:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblVScrollCtrl->Wrap( -1 ); + fgVScroll->Add( m_lblVScrollCtrl, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + wxArrayString m_choiceVScrollCtrlChoices; + m_choiceVScrollCtrl = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceVScrollCtrlChoices, 0 ); + m_choiceVScrollCtrl->SetSelection( 0 ); + fgVScroll->Add( m_choiceVScrollCtrl, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_lblVScrollShift = new wxStaticText( this, wxID_ANY, _("Shift:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblVScrollShift->Wrap( -1 ); + fgVScroll->Add( m_lblVScrollShift, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + wxArrayString m_choiceVScrollShiftChoices; + m_choiceVScrollShift = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceVScrollShiftChoices, 0 ); + m_choiceVScrollShift->SetSelection( 0 ); + fgVScroll->Add( m_choiceVScrollShift, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_lblVScrollAlt = new wxStaticText( this, wxID_ANY, _("Alt:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblVScrollAlt->Wrap( -1 ); + fgVScroll->Add( m_lblVScrollAlt, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + wxArrayString m_choiceVScrollAltChoices; + m_choiceVScrollAlt = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceVScrollAltChoices, 0 ); + m_choiceVScrollAlt->SetSelection( 0 ); + fgVScroll->Add( m_choiceVScrollAlt, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bScrollSizerLeft->Add( fgVScroll, 0, wxRIGHT|wxLEFT, 24 ); + + + bScrollSizerLeft->Add( 0, 10, 0, wxEXPAND, 5 ); + + m_lblHScrollMovement = new wxStaticText( this, wxID_ANY, _("Horizontal touchpad movement:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblHScrollMovement->Wrap( -1 ); + bScrollSizerLeft->Add( m_lblHScrollMovement, 0, wxALL, 5 ); + + + bScrollSizerLeft->Add( 0, 10, 0, wxEXPAND, 5 ); + + wxFlexGridSizer* fgHScroll; + fgHScroll = new wxFlexGridSizer( 0, 2, 0, 0 ); + fgHScroll->AddGrowableCol( 0 ); + fgHScroll->SetFlexibleDirection( wxBOTH ); + fgHScroll->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_lblHScrollModifier = new wxStaticText( this, wxID_ANY, _("Modifier"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblHScrollModifier->Wrap( -1 ); + fgHScroll->Add( m_lblHScrollModifier, 0, wxALIGN_BOTTOM, 5 ); + + m_lblHScrollAction = new wxStaticText( this, wxID_ANY, _("Action"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblHScrollAction->Wrap( -1 ); + fgHScroll->Add( m_lblHScrollAction, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_BOTTOM, 5 ); + + m_lblHScrollAny = new wxStaticText( this, wxID_ANY, _("Any:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_lblHScrollAny->Wrap( -1 ); + fgHScroll->Add( m_lblHScrollAny, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + wxArrayString m_choiceHScrollChoices; + m_choiceHScroll = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceHScrollChoices, 0 ); + m_choiceHScroll->SetSelection( 0 ); + fgHScroll->Add( m_choiceHScroll, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bScrollSizerLeft->Add( fgHScroll, 0, wxRIGHT|wxLEFT, 24 ); + + + bScrollMargins->Add( bScrollSizerLeft, 0, wxEXPAND|wxLEFT, 5 ); + + wxBoxSizer* bScrollSizerRight; + bScrollSizerRight = new wxBoxSizer( wxVERTICAL ); + + m_btnMouseDefaults = new wxButton( this, wxID_ANY, _("Reset to Mouse Defaults"), wxDefaultPosition, wxDefaultSize, 0 ); + bScrollSizerRight->Add( m_btnMouseDefaults, 0, wxALL|wxEXPAND, 5 ); + + m_btnTrackpadDefaults = new wxButton( this, wxID_ANY, _("Reset to Trackpad Defaults"), wxDefaultPosition, wxDefaultSize, 0 ); + bScrollSizerRight->Add( m_btnTrackpadDefaults, 0, wxALL|wxEXPAND, 5 ); + + + bScrollMargins->Add( bScrollSizerRight, 0, wxTOP|wxLEFT|wxEXPAND, 5 ); + + + bScrollSizer->Add( bScrollMargins, 1, wxEXPAND|wxTOP|wxRIGHT, 10 ); + + + bMainSizer->Add( bScrollSizer, 1, 0, 5 ); + + + this->SetSizer( bMainSizer ); + this->Layout(); + bMainSizer->Fit( this ); + + // Connect Events + m_btnMouseDefaults->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SIMULATOR_PREFERENCES_BASE::onMouseDefaults ), NULL, this ); + m_btnTrackpadDefaults->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SIMULATOR_PREFERENCES_BASE::onTrackpadDefaults ), NULL, this ); +} + +PANEL_SIMULATOR_PREFERENCES_BASE::~PANEL_SIMULATOR_PREFERENCES_BASE() +{ + // Disconnect Events + m_btnMouseDefaults->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SIMULATOR_PREFERENCES_BASE::onMouseDefaults ), NULL, this ); + m_btnTrackpadDefaults->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SIMULATOR_PREFERENCES_BASE::onTrackpadDefaults ), NULL, this ); + +} diff --git a/eeschema/dialogs/panel_simulator_preferences_base.h b/eeschema/dialogs/panel_simulator_preferences_base.h new file mode 100644 index 0000000000..945c07ba1c --- /dev/null +++ b/eeschema/dialogs/panel_simulator_preferences_base.h @@ -0,0 +1,72 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b) +// http://www.wxformbuilder.org/ +// +// PLEASE DO *NOT* EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include +#include "widgets/resettable_panel.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +/// Class PANEL_SIMULATOR_PREFERENCES_BASE +/////////////////////////////////////////////////////////////////////////////// +class PANEL_SIMULATOR_PREFERENCES_BASE : public RESETTABLE_PANEL +{ + private: + + protected: + wxStaticText* m_lblScrollHeading; + wxStaticLine* m_scrollLine; + wxStaticText* m_lblVScrollMovement; + wxStaticText* m_lblVScrollModifier; + wxStaticText* m_lblVScrollAction; + wxStaticText* m_lblVScrollUnmodified; + wxChoice* m_choiceVScrollUnmodified; + wxStaticText* m_lblVScrollCtrl; + wxChoice* m_choiceVScrollCtrl; + wxStaticText* m_lblVScrollShift; + wxChoice* m_choiceVScrollShift; + wxStaticText* m_lblVScrollAlt; + wxChoice* m_choiceVScrollAlt; + wxStaticText* m_lblHScrollMovement; + wxStaticText* m_lblHScrollModifier; + wxStaticText* m_lblHScrollAction; + wxStaticText* m_lblHScrollAny; + wxChoice* m_choiceHScroll; + wxButton* m_btnMouseDefaults; + wxButton* m_btnTrackpadDefaults; + + // Virtual event handlers, override them in your derived class + virtual void onMouseDefaults( wxCommandEvent& event ) { event.Skip(); } + virtual void onTrackpadDefaults( wxCommandEvent& event ) { event.Skip(); } + + + public: + + PANEL_SIMULATOR_PREFERENCES_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString ); + + ~PANEL_SIMULATOR_PREFERENCES_BASE(); + +}; + diff --git a/eeschema/eeschema.cpp b/eeschema/eeschema.cpp index 006bda132b..3a9c131e69 100644 --- a/eeschema/eeschema.cpp +++ b/eeschema/eeschema.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com * Copyright (C) 2008 Wayne Stambaugh - * Copyright (C) 2004-2023 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2004-2024 KiCad Developers, see change_log.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -294,6 +295,9 @@ static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER case PANEL_SCH_FIELD_NAME_TEMPLATES: return new PANEL_TEMPLATE_FIELDNAMES( aParent, nullptr ); + case PANEL_SCH_SIMULATOR: + return new PANEL_SIMULATOR_PREFERENCES( aParent ); + default: return nullptr; } diff --git a/eeschema/eeschema_settings.cpp b/eeschema/eeschema_settings.cpp index 941aa39ea8..0a74b561b7 100644 --- a/eeschema/eeschema_settings.cpp +++ b/eeschema/eeschema_settings.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * -* Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors. +* Copyright (C) 2020-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -531,22 +531,57 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() : &m_Simulator.window.perspective, "" ) ); m_params.emplace_back( new PARAM( "simulator.plot_panel_width", - &m_Simulator.plot_panel_width, 0 ) ); + &m_Simulator.view.plot_panel_width, 0 ) ); m_params.emplace_back( new PARAM( "simulator.plot_panel_height", - &m_Simulator.plot_panel_height, 0 ) ); + &m_Simulator.view.plot_panel_height, 0 ) ); m_params.emplace_back( new PARAM( "simulator.signal_panel_height", - &m_Simulator.signal_panel_height, 0 ) ); + &m_Simulator.view.signal_panel_height, 0 ) ); m_params.emplace_back( new PARAM( "simulator.cursors_panel_height", - &m_Simulator.cursors_panel_height, 0 ) ); + &m_Simulator.view.cursors_panel_height, 0 ) ); m_params.emplace_back( new PARAM( "simulator.measurements_panel_height", - &m_Simulator.measurements_panel_height, 0 ) ); + &m_Simulator.view.measurements_panel_height, 0 ) ); m_params.emplace_back( new PARAM( "simulator.white_background", - &m_Simulator.white_background, false ) ); + &m_Simulator.view.white_background, false ) ); + + m_params.emplace_back( new PARAM_ENUM( + "simulator.mouse_wheel_actions.vertical_unmodified", + &m_Simulator.preferences.mouse_wheel_actions.vertical_unmodified, + SIM_MOUSE_WHEEL_ACTION::ZOOM, + SIM_MOUSE_WHEEL_ACTION::NONE, + SIM_MOUSE_WHEEL_ACTION::ZOOM_VERTICALLY ) ); + + m_params.emplace_back( new PARAM_ENUM( + "simulator.mouse_wheel_actions.vertical_with_ctrl", + &m_Simulator.preferences.mouse_wheel_actions.vertical_with_ctrl, + SIM_MOUSE_WHEEL_ACTION::PAN_LEFT_RIGHT, + SIM_MOUSE_WHEEL_ACTION::NONE, + SIM_MOUSE_WHEEL_ACTION::ZOOM_VERTICALLY ) ); + + m_params.emplace_back( new PARAM_ENUM( + "simulator.mouse_wheel_actions.vertical_with_shift", + &m_Simulator.preferences.mouse_wheel_actions.vertical_with_shift, + SIM_MOUSE_WHEEL_ACTION::PAN_UP_DOWN, + SIM_MOUSE_WHEEL_ACTION::NONE, + SIM_MOUSE_WHEEL_ACTION::ZOOM_VERTICALLY) ); + + m_params.emplace_back( new PARAM_ENUM( + "simulator.mouse_wheel_actions.vertical_with_alt", + &m_Simulator.preferences.mouse_wheel_actions.vertical_with_alt, + SIM_MOUSE_WHEEL_ACTION::NONE, + SIM_MOUSE_WHEEL_ACTION::NONE, + SIM_MOUSE_WHEEL_ACTION::ZOOM_VERTICALLY) ); + + m_params.emplace_back( new PARAM_ENUM( + "simulator.mouse_wheel_actions.horizontal", + &m_Simulator.preferences.mouse_wheel_actions.horizontal, + SIM_MOUSE_WHEEL_ACTION::NONE, + SIM_MOUSE_WHEEL_ACTION::NONE, + SIM_MOUSE_WHEEL_ACTION::ZOOM_VERTICALLY) ); m_params.emplace_back( new PARAM( "symbol_chooser.sash_pos_h", &m_SymChooserPanel.sash_pos_h, -1 ) ); diff --git a/eeschema/eeschema_settings.h b/eeschema/eeschema_settings.h index 425e9b6d6d..374d144dcd 100644 --- a/eeschema/eeschema_settings.h +++ b/eeschema/eeschema_settings.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * -* Copyright (C) 2020-2023 KiCad Developers, see AUTHORS.txt for contributors. +* Copyright (C) 2020-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,7 +27,7 @@ #include #include - +#include using KIGFX::COLOR4D; @@ -278,13 +278,19 @@ public: struct SIMULATOR { - int plot_panel_width; - int plot_panel_height; - int signal_panel_height; - int cursors_panel_height; - int measurements_panel_height; - bool white_background; + struct VIEW + { + int plot_panel_width; + int plot_panel_height; + int signal_panel_height; + int cursors_panel_height; + int measurements_panel_height; + bool white_background; + }; + + VIEW view; WINDOW_SETTINGS window; + SIM_PREFERENCES preferences; }; struct FIND_REPLACE_EXTRA diff --git a/eeschema/sim/sim_plot_tab.h b/eeschema/sim/sim_plot_tab.h index aa6c5b475e..40d76c45bf 100644 --- a/eeschema/sim/sim_plot_tab.h +++ b/eeschema/sim/sim_plot_tab.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016-2023 CERN - * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors. * * @author Tomasz Wlostowski * @author Maciej Suminski @@ -195,6 +195,12 @@ public: virtual ~SIM_PLOT_TAB(); + void ApplyPreferences( const SIM_PREFERENCES& aPrefs ) override + { + m_plotWin->SetMouseWheelActions( + convertMouseWheelActions( aPrefs.mouse_wheel_actions ) ); + } + wxString GetLabelX() const { return m_axis_x ? m_axis_x->GetName() : wxString( wxS( "" ) ); @@ -359,6 +365,22 @@ public: wxPoint m_LastLegendPosition; private: + static mpWindow::MouseWheelActionSet + convertMouseWheelActions(const SIM_MOUSE_WHEEL_ACTION_SET& s) + { + static_assert( static_cast(mpWindow::MouseWheelAction::COUNT) == + static_cast(SIM_MOUSE_WHEEL_ACTION::COUNT), + "mpWindow::MouseWheelAction enum must match SIM_MOUSE_WHEEL_ACTION" ); + + using A = mpWindow::MouseWheelAction; + mpWindow::MouseWheelActionSet m; + m.verticalUnmodified = static_cast( s.vertical_unmodified ); + m.verticalWithCtrl = static_cast( s.vertical_with_ctrl ); + m.verticalWithShift = static_cast( s.vertical_with_shift ); + m.verticalWithAlt = static_cast( s.vertical_with_alt ); + return m; + } + wxString getTraceId( const wxString& aVectorName, int aType ) const { return wxString::Format( wxS( "%s%d" ), aVectorName, aType & SPT_Y_AXIS_MASK ); diff --git a/eeschema/sim/sim_preferences.h b/eeschema/sim/sim_preferences.h new file mode 100644 index 0000000000..b415aa5054 --- /dev/null +++ b/eeschema/sim/sim_preferences.h @@ -0,0 +1,101 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * https://www.gnu.org/licenses/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __SIM_PREFERENCES__ +#define __SIM_PREFERENCES__ + + +/** + * @file sim_preferences.h + * + * Contains preferences pertaining to the simulator. + */ + +/** + * Enumerates the possible mouse wheel actions that can be performed on simulator plots. + */ +enum class SIM_MOUSE_WHEEL_ACTION +{ + // Directly using mpWindow::MouseWheelAction would leak wxMathPlot via the eeschema_settings.h + // header, so we duplicate it here in this miminal header. + + NONE, + PAN_LEFT_RIGHT, + PAN_RIGHT_LEFT, + PAN_UP_DOWN, + ZOOM, + ZOOM_HORIZONTALLY, + ZOOM_VERTICALLY, + COUNT // Internal use only +}; + +/** + * Contains the set of modified mouse wheel actions that can be performed on a simulator plot. + */ +struct SIM_MOUSE_WHEEL_ACTION_SET +{ + // Directly using mpWindow::MouseWheelActionSet would leak wxMathPlot via the + // eeschema_settings.h header, so we duplicate it here in this miminal header. + + SIM_MOUSE_WHEEL_ACTION vertical_unmodified; + SIM_MOUSE_WHEEL_ACTION vertical_with_ctrl; + SIM_MOUSE_WHEEL_ACTION vertical_with_shift; + SIM_MOUSE_WHEEL_ACTION vertical_with_alt; + SIM_MOUSE_WHEEL_ACTION horizontal; + + static SIM_MOUSE_WHEEL_ACTION_SET GetMouseDefaults() + { + // Returns defaults equivalent to the global Mouse and Touchpad default settings + + SIM_MOUSE_WHEEL_ACTION_SET actions; + actions.vertical_unmodified = SIM_MOUSE_WHEEL_ACTION::ZOOM; + actions.vertical_with_ctrl = SIM_MOUSE_WHEEL_ACTION::PAN_LEFT_RIGHT; + actions.vertical_with_shift = SIM_MOUSE_WHEEL_ACTION::PAN_UP_DOWN; + actions.vertical_with_alt = SIM_MOUSE_WHEEL_ACTION::NONE; + actions.horizontal = SIM_MOUSE_WHEEL_ACTION::NONE; + return actions; + } + + static SIM_MOUSE_WHEEL_ACTION_SET GetTrackpadDefaults() + { + // Returns defaults equivalent to the global Mouse and Touchpad default settings + + SIM_MOUSE_WHEEL_ACTION_SET actions; + actions.vertical_unmodified = SIM_MOUSE_WHEEL_ACTION::PAN_UP_DOWN; + actions.vertical_with_ctrl = SIM_MOUSE_WHEEL_ACTION::ZOOM; + actions.vertical_with_shift = SIM_MOUSE_WHEEL_ACTION::PAN_LEFT_RIGHT; + actions.vertical_with_alt = SIM_MOUSE_WHEEL_ACTION::NONE; + actions.horizontal = SIM_MOUSE_WHEEL_ACTION::PAN_LEFT_RIGHT; + return actions; + } +}; + +/** + * Contains preferences pertaining to the simulator. + */ +struct SIM_PREFERENCES +{ + SIM_MOUSE_WHEEL_ACTION_SET mouse_wheel_actions; +}; + +#endif // __SIM_PREFERENCES__ diff --git a/eeschema/sim/sim_tab.cpp b/eeschema/sim/sim_tab.cpp index 3ba2931860..4904cb8d25 100644 --- a/eeschema/sim/sim_tab.cpp +++ b/eeschema/sim/sim_tab.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016-2023 CERN - * Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors. * @author Sylwester Kocjan * * This program is free software; you can redistribute it and/or @@ -67,6 +67,10 @@ bool SIM_TAB::IsPlottable( SIM_TYPE aSimType ) } } +void SIM_TAB::ApplyPreferences( const SIM_PREFERENCES& /*aPrefs*/ ) +{ +} + SIM_TYPE SIM_TAB::GetSimType() const { diff --git a/eeschema/sim/sim_tab.h b/eeschema/sim/sim_tab.h index af70d528c9..ebdeaa20af 100644 --- a/eeschema/sim/sim_tab.h +++ b/eeschema/sim/sim_tab.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016-2023 CERN - * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors. * @author Sylwester Kocjan * * This program is free software; you can redistribute it and/or @@ -26,6 +26,7 @@ #ifndef __SIM_PLOT_PANEL_BASE_H #define __SIM_PLOT_PANEL_BASE_H +#include #include #include #include @@ -44,6 +45,8 @@ public: virtual void OnLanguageChanged() = 0; + virtual void ApplyPreferences( const SIM_PREFERENCES& aPrefs ); + SIM_TYPE GetSimType() const; const wxString& GetSimCommand() const { return m_simCommand; } diff --git a/eeschema/sim/simulator_frame.cpp b/eeschema/sim/simulator_frame.cpp index 14bbfa7191..8871517303 100644 --- a/eeschema/sim/simulator_frame.cpp +++ b/eeschema/sim/simulator_frame.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016-2023 CERN - * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors. * @author Tomasz Wlostowski * @author Maciej Suminski * @@ -272,6 +272,16 @@ void SIMULATOR_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg ) } +void SIMULATOR_FRAME::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) +{ + KIWAY_PLAYER::CommonSettingsChanged( aEnvVarsChanged, aTextVarsChanged ); + + auto* cfg = dynamic_cast( m_toolManager->GetSettings() ); + wxASSERT( cfg != nullptr ); + m_ui->ApplyPreferences( cfg->m_Simulator.preferences ); +} + + WINDOW_SETTINGS* SIMULATOR_FRAME::GetWindowSettings( APP_SETTINGS_BASE* aCfg ) { EESCHEMA_SETTINGS* cfg = dynamic_cast( aCfg ); diff --git a/eeschema/sim/simulator_frame.h b/eeschema/sim/simulator_frame.h index 4da48bbcf5..39dc92c6d0 100644 --- a/eeschema/sim/simulator_frame.h +++ b/eeschema/sim/simulator_frame.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016-2023 CERN - * Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017-2024 KiCad Developers, see AUTHORS.txt for contributors. * * @author Tomasz Wlostowski * @author Maciej Suminski @@ -162,6 +162,8 @@ public: void SaveSettings( APP_SETTINGS_BASE* aCfg ) override; + void CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged ) override; + WINDOW_SETTINGS* GetWindowSettings( APP_SETTINGS_BASE* aCfg ) override; SCH_EDIT_FRAME* GetSchematicFrame() const { return m_schematicFrame; } diff --git a/eeschema/sim/simulator_frame_ui.cpp b/eeschema/sim/simulator_frame_ui.cpp index 3b29c47652..ea268eb309 100644 --- a/eeschema/sim/simulator_frame_ui.cpp +++ b/eeschema/sim/simulator_frame_ui.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016-2023 CERN - * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors. * @author Tomasz Wlostowski * @author Maciej Suminski * @@ -605,24 +605,45 @@ void SIMULATOR_FRAME_UI::ShowChangedLanguage() void SIMULATOR_FRAME_UI::LoadSettings( EESCHEMA_SETTINGS* aCfg ) { + const EESCHEMA_SETTINGS::SIMULATOR& settings = aCfg->m_Simulator; + // Read subwindows sizes (should be > 0 ) - m_splitterLeftRightSashPosition = aCfg->m_Simulator.plot_panel_width; - m_splitterPlotAndConsoleSashPosition = aCfg->m_Simulator.plot_panel_height; - m_splitterSignalsSashPosition = aCfg->m_Simulator.signal_panel_height; - m_splitterCursorsSashPosition = aCfg->m_Simulator.cursors_panel_height; - m_splitterTuneValuesSashPosition = aCfg->m_Simulator.measurements_panel_height; - m_darkMode = !aCfg->m_Simulator.white_background; + m_splitterLeftRightSashPosition = settings.view.plot_panel_width; + m_splitterPlotAndConsoleSashPosition = settings.view.plot_panel_height; + m_splitterSignalsSashPosition = settings.view.signal_panel_height; + m_splitterCursorsSashPosition = settings.view.cursors_panel_height; + m_splitterTuneValuesSashPosition = settings.view.measurements_panel_height; + m_darkMode = !settings.view.white_background; + + m_preferences = settings.preferences; } void SIMULATOR_FRAME_UI::SaveSettings( EESCHEMA_SETTINGS* aCfg ) { - aCfg->m_Simulator.plot_panel_width = m_splitterLeftRight->GetSashPosition(); - aCfg->m_Simulator.plot_panel_height = m_splitterPlotAndConsole->GetSashPosition(); - aCfg->m_Simulator.signal_panel_height = m_splitterSignals->GetSashPosition(); - aCfg->m_Simulator.cursors_panel_height = m_splitterCursors->GetSashPosition(); - aCfg->m_Simulator.measurements_panel_height = m_splitterMeasurements->GetSashPosition(); - aCfg->m_Simulator.white_background = !m_darkMode; + EESCHEMA_SETTINGS::SIMULATOR& settings = aCfg->m_Simulator; + + settings.view.plot_panel_width = m_splitterLeftRight->GetSashPosition(); + settings.view.plot_panel_height = m_splitterPlotAndConsole->GetSashPosition(); + settings.view.signal_panel_height = m_splitterSignals->GetSashPosition(); + settings.view.cursors_panel_height = m_splitterCursors->GetSashPosition(); + settings.view.measurements_panel_height = m_splitterMeasurements->GetSashPosition(); + settings.view.white_background = !m_darkMode; +} + + +void SIMULATOR_FRAME_UI::ApplyPreferences( const SIM_PREFERENCES& aPrefs ) +{ + m_preferences = aPrefs; + + const std::size_t pageCount = m_plotNotebook->GetPageCount(); + for( std::size_t i = 0; iGetPage( i ); + auto simTab = dynamic_cast( page ); + wxASSERT( simTab != nullptr ); + simTab->ApplyPreferences( aPrefs ); + } } @@ -943,9 +964,7 @@ SIM_TAB* SIMULATOR_FRAME_UI::NewSimTab( const wxString& aSimCommand ) { SIM_PLOT_TAB* panel = new SIM_PLOT_TAB( aSimCommand, m_plotNotebook ); simTab = panel; - - COMMON_SETTINGS::INPUT cfg = Pgm().GetCommonSettings()->m_Input; - panel->GetPlotWin()->EnableMouseWheelPan( cfg.scroll_modifier_zoom != 0 ); + panel->ApplyPreferences( m_preferences ); } else { diff --git a/eeschema/sim/simulator_frame_ui.h b/eeschema/sim/simulator_frame_ui.h index 157a195274..f8537f315a 100644 --- a/eeschema/sim/simulator_frame_ui.h +++ b/eeschema/sim/simulator_frame_ui.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016-2023 CERN - * Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017-2024 KiCad Developers, see AUTHORS.txt for contributors. * * @author Tomasz Wlostowski * @author Maciej Suminski @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -185,6 +186,11 @@ public: void SaveSettings( EESCHEMA_SETTINGS* aCfg ); + /** + * Called when settings are changed via the common Preferences dialog. + */ + void ApplyPreferences( const SIM_PREFERENCES& aPrefs ); + // adjust the sash dimension of splitter windows after reading // the config settings // must be called after the config settings are read, and once the @@ -342,6 +348,7 @@ private: bool m_darkMode; unsigned int m_plotNumber; wxTimer m_refreshTimer; + SIM_PREFERENCES m_preferences; }; #endif // SIMULATOR_FRAME_UI_H diff --git a/eeschema/sim/toolbars_simulator_frame.cpp b/eeschema/sim/toolbars_simulator_frame.cpp index 4d0edaf869..d8c2ad5dcd 100644 --- a/eeschema/sim/toolbars_simulator_frame.cpp +++ b/eeschema/sim/toolbars_simulator_frame.cpp @@ -58,6 +58,10 @@ void SIMULATOR_FRAME::ReCreateHToolbar() m_toolBar->AddScaledSeparator( this ); m_toolBar->Add( ACTIONS::zoomInCenter ); m_toolBar->Add( ACTIONS::zoomOutCenter ); + m_toolBar->Add( ACTIONS::zoomInHorizontally ); + m_toolBar->Add( ACTIONS::zoomOutHorizontally ); + m_toolBar->Add( ACTIONS::zoomInVertically ); + m_toolBar->Add( ACTIONS::zoomOutVertically ); m_toolBar->Add( ACTIONS::zoomFitScreen ); m_toolBar->AddScaledSeparator( this ); @@ -117,6 +121,10 @@ void SIMULATOR_FRAME::doReCreateMenuBar() viewMenu->AppendSeparator(); viewMenu->Add( ACTIONS::zoomInCenter ); viewMenu->Add( ACTIONS::zoomOutCenter ); + viewMenu->Add( ACTIONS::zoomInHorizontally ); + viewMenu->Add( ACTIONS::zoomOutHorizontally ); + viewMenu->Add( ACTIONS::zoomInVertically ); + viewMenu->Add( ACTIONS::zoomOutVertically ); viewMenu->Add( ACTIONS::zoomFitScreen ); viewMenu->AppendSeparator(); diff --git a/eeschema/tools/simulator_control.cpp b/eeschema/tools/simulator_control.cpp index f171f4d5a6..2caf3a1087 100644 --- a/eeschema/tools/simulator_control.cpp +++ b/eeschema/tools/simulator_control.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2023-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -248,18 +248,36 @@ int SIMULATOR_CONTROL::Zoom( const TOOL_EVENT& aEvent ) { if( SIM_PLOT_TAB* plotTab = dynamic_cast( getCurrentSimTab() ) ) { + mpWindow* plot = plotTab->GetPlotWin(); + if( aEvent.IsAction( &ACTIONS::zoomInCenter ) ) { - plotTab->GetPlotWin()->ZoomIn(); + plot->ZoomIn(); } else if( aEvent.IsAction( &ACTIONS::zoomOutCenter ) ) { - plotTab->GetPlotWin()->ZoomOut(); + plot->ZoomOut(); + } + else if( aEvent.IsAction( &ACTIONS::zoomInHorizontally ) ) + { + plot->ZoomIn( wxDefaultPosition, mpWindow::zoomIncrementalFactor, wxHORIZONTAL ); + } + else if( aEvent.IsAction( &ACTIONS::zoomOutHorizontally ) ) + { + plot->ZoomOut( wxDefaultPosition, mpWindow::zoomIncrementalFactor, wxHORIZONTAL ); + } + else if( aEvent.IsAction( &ACTIONS::zoomInVertically ) ) + { + plot->ZoomIn( wxDefaultPosition, mpWindow::zoomIncrementalFactor, wxVERTICAL ); + } + else if( aEvent.IsAction( &ACTIONS::zoomOutVertically ) ) + { + plot->ZoomOut( wxDefaultPosition, mpWindow::zoomIncrementalFactor, wxVERTICAL ); } else if( aEvent.IsAction( &ACTIONS::zoomFitScreen ) ) { wxCommandEvent dummy; - plotTab->GetPlotWin()->OnFit( dummy ); + plot->OnFit( dummy ); } } @@ -519,6 +537,10 @@ void SIMULATOR_CONTROL::setTransitions() Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomInCenter.MakeEvent() ); Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomOutCenter.MakeEvent() ); + Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomInHorizontally.MakeEvent() ); + Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomOutHorizontally.MakeEvent() ); + Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomInVertically.MakeEvent() ); + Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomOutVertically.MakeEvent() ); Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomFitScreen.MakeEvent() ); Go( &SIMULATOR_CONTROL::UndoZoom, ACTIONS::zoomUndo.MakeEvent() ); Go( &SIMULATOR_CONTROL::RedoZoom, ACTIONS::zoomRedo.MakeEvent() ); diff --git a/eeschema/tools/simulator_control.h b/eeschema/tools/simulator_control.h index 596b68bcfa..b02a877896 100644 --- a/eeschema/tools/simulator_control.h +++ b/eeschema/tools/simulator_control.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2023-2024 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,6 +28,7 @@ #include class SIMULATOR_FRAME; +class SCH_EDIT_FRAME; class SPICE_CIRCUIT_MODEL; class SPICE_SIMULATOR; class SIM_TAB; diff --git a/include/bitmaps/bitmaps_list.h b/include/bitmaps/bitmaps_list.h index 642433e460..dba30cc731 100644 --- a/include/bitmaps/bitmaps_list.h +++ b/include/bitmaps/bitmaps_list.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2007-2017 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.TXT for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.TXT for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -653,6 +653,10 @@ enum class BITMAPS : unsigned int zoom_fit_to_objects, zoom_in, zoom_out, + zoom_in_horizontally, + zoom_out_horizontally, + zoom_in_vertically, + zoom_out_vertically, zoom_page, zoom_selection, }; diff --git a/include/frame_type.h b/include/frame_type.h index 803bd89e0f..c5b7bca780 100644 --- a/include/frame_type.h +++ b/include/frame_type.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014 CERN - * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors. * @author Maciej Suminski * * This program is free software; you can redistribute it and/or @@ -80,6 +80,7 @@ enum FRAME_T PANEL_SCH_ANNO_OPTIONS, PANEL_SCH_COLORS, PANEL_SCH_FIELD_NAME_TEMPLATES, + PANEL_SCH_SIMULATOR, PANEL_FP_DISPLAY_OPTIONS, PANEL_FP_GRIDS, diff --git a/include/tool/actions.h b/include/tool/actions.h index 365ab175b5..d131e916df 100644 --- a/include/tool/actions.h +++ b/include/tool/actions.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2013-2016 CERN - * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors. * @author Maciej Suminski * * This program is free software; you can redistribute it and/or @@ -116,6 +116,10 @@ public: static TOOL_ACTION zoomOut; static TOOL_ACTION zoomInCenter; static TOOL_ACTION zoomOutCenter; + static TOOL_ACTION zoomInHorizontally; + static TOOL_ACTION zoomOutHorizontally; + static TOOL_ACTION zoomInVertically; + static TOOL_ACTION zoomOutVertically; static TOOL_ACTION zoomCenter; static TOOL_ACTION zoomFitScreen; static TOOL_ACTION zoomFitObjects; // Zooms to bbox of items on screen (except page border) diff --git a/include/widgets/mathplot.h b/include/widgets/mathplot.h index 2b31bfea6d..990cc4e647 100644 --- a/include/widgets/mathplot.h +++ b/include/widgets/mathplot.h @@ -7,7 +7,7 @@ // Created: 21/07/2003 // Last edit: 05/08/2016 // Copyright: (c) David Schalig, Davide Rondini -// Copyright (c) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors. +// Copyright (c) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors. // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -905,6 +905,38 @@ typedef std::deque wxLayerList; class WXDLLIMPEXP_MATHPLOT mpWindow : public wxWindow { public: + /** + * Enumerates the possible mouse wheel actions that can be performed on the plot. + */ + enum class MouseWheelAction + { + NONE, + PAN_LEFT_RIGHT, + PAN_RIGHT_LEFT, + PAN_UP_DOWN, + ZOOM, + ZOOM_HORIZONTALLY, + ZOOM_VERTICALLY, + COUNT // Internal use only + }; + + /** + * Contains the set of modified mouse wheel actions that can be performed on the plot. + */ + struct MouseWheelActionSet + { + /* If this bundled wxMathPlot implementation is to remain single-header and not dependent + * on any part of KiCad, then the SIM_MOUSE_WHEEL_ACTION_SET struct must be duplicated + * here. SIM_PLOT_TAB::convertMouseWheelActions is used to convert from + * SIM_MOUSE_WHEEL_ACTION_SET to mpWindow::MouseWheelActionSet. */ + + MouseWheelAction verticalUnmodified; + MouseWheelAction verticalWithCtrl; + MouseWheelAction verticalWithShift; + MouseWheelAction verticalWithAlt; + MouseWheelAction horizontal; + }; + mpWindow(); mpWindow( wxWindow* parent, wxWindowID id ); ~mpWindow(); @@ -1068,9 +1100,8 @@ public: */ void EnableMousePanZoom( bool enabled ) { m_enableMouseNavigation = enabled; } - /** Enable/disable trackpad friendly panning (2-axis scroll wheel) - */ - void EnableMouseWheelPan( bool enabled ) { m_enableMouseWheelPan = enabled; } + /** Set the pan/zoom actions corresponding to mousewheel/trackpad events. */ + void SetMouseWheelActions( const MouseWheelActionSet& s ) {m_mouseWheelActions = s;} /** Set view to fit global bounding box of all plot layers and refresh display. * Scale and position will be set to show all attached mpLayers. @@ -1085,21 +1116,24 @@ public: * as the "desired borders", since this use will be invoked only when printing. */ void Fit( double xMin, double xMax, double yMin, double yMax, - const wxCoord* printSizeX = nullptr, const wxCoord* printSizeY = nullptr ); + const wxCoord* printSizeX = nullptr, const wxCoord* printSizeY = nullptr, + wxOrientation directions = wxBOTH ); /** Zoom into current view and refresh display * @param centerPoint The point (pixel coordinates) that will stay in the same * position on the screen after the zoom (by default, the center of the mpWindow). */ void ZoomIn( const wxPoint& centerPoint = wxDefaultPosition ); - void ZoomIn( const wxPoint& centerPoint, double zoomFactor ); + void ZoomIn( const wxPoint& centerPoint, double zoomFactor, + wxOrientation directions = wxBOTH ); /** Zoom out current view and refresh display * @param centerPoint The point (pixel coordinates) that will stay in the same * position on the screen after the zoom (by default, the center of the mpWindow). */ void ZoomOut( const wxPoint& centerPoint = wxDefaultPosition ); - void ZoomOut( const wxPoint& centerPoint, double zoomFactor ); + void ZoomOut( const wxPoint& centerPoint, double zoomFactor, + wxOrientation directions = wxBOTH ); /** Zoom view fitting given coordinates to the window (p0 and p1 do not need to be in any specific order) */ @@ -1219,7 +1253,7 @@ public: * @return reference to axis colour used in theme */ const wxColour& GetAxesColour() { return m_axColour; }; - /** Limit zooming & panning to the area used by the plots */ + /** Enable limiting of zooming & panning to the area used by the plots */ void LimitView( bool aEnable ) { m_enableLimitedView = aEnable; @@ -1233,12 +1267,15 @@ public: int UndoZoomStackSize() const { return m_undoZoomStack.size(); } int RedoZoomStackSize() const { return m_redoZoomStack.size(); } - void AdjustLimitedView(); + /** Limits the zoomed or panned view to the area used by the plots. */ + void AdjustLimitedView( wxOrientation directions = wxBOTH ); void OnFit( wxCommandEvent& event ); void OnCenter( wxCommandEvent& event ); protected: + static MouseWheelActionSet defaultMouseWheelActions(); + void pushZoomUndo( const std::array& aZoom ); void OnPaint( wxPaintEvent& event ); // !< Paint handler, will plot all attached layers @@ -1258,19 +1295,12 @@ protected: void onMouseLeftDown( wxMouseEvent& event ); // !< Mouse left click (for rect zoom) void onMouseLeftRelease( wxMouseEvent& event ); // !< Mouse left click (for rect zoom) - bool CheckXLimits( double& desiredMax, double& desiredMin ) const - { - return !( m_enableLimitedView - && (desiredMax > m_maxX - m_marginRight / m_scaleX - || desiredMin < m_minX - m_marginLeft / m_scaleX) ); - } + void DoZoom( const wxPoint& centerPoint, double zoomFactor, wxOrientation directions ); + void RecomputeDesiredX( double& min, double& max ); + void RecomputeDesiredY( double& min, double& max ); + wxOrientation ViewNeedsRefitting( wxOrientation directions ) const; - bool CheckYLimits( double& desiredMax, double& desiredMin ) const - { - return !( m_enableLimitedView - && (desiredMax > m_maxY + m_marginTop / m_scaleY - || desiredMin < m_minY - m_marginBottom / m_scaleY) ); - } + void PerformMouseWheelAction( wxMouseEvent& event, MouseWheelAction action ); /** Recalculate global layer bounding box, and save it in m_minX,... * \return true if there is any valid BBox information. @@ -1309,11 +1339,19 @@ protected: bool m_yLocked; - /** These are updated in Fit() only, and may be different from the real borders - * (layer coordinates) only if lock aspect ratio is true. + /** These are updated in Fit, ZoomIn, ZoomOut, ZoomRect, SetXView, SetYView and may be different + * from the real borders (layer coordinates) only if lock aspect ratio is true. + * + * @note They use the plot area as their coordinate system, and not the layer coordinate + * system used by m_posX/Y. */ double m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax; + // These are gaps between the curve extrema and the edges of the plot area, expressed as + // a factor of global layer bounding box width/height. + double m_topBottomPlotGapFactor; + double m_leftRightPlotGapFactor; + int m_marginTop, m_marginRight, m_marginBottom, m_marginLeft; int m_last_lx, m_last_ly; // !< For double buffering @@ -1321,11 +1359,11 @@ protected: wxBitmap* m_buff_bmp; // !< For double buffering bool m_enableDoubleBuffer; // !< For double buffering bool m_enableMouseNavigation; // !< For pan/zoom with the mouse. - bool m_enableMouseWheelPan; // !< Trackpad pan/zoom bool m_enableLimitedView; + MouseWheelActionSet m_mouseWheelActions; wxPoint m_mouseMClick; // !< For the middle button "drag" feature wxPoint m_mouseLClick; // !< Starting coords for rectangular zoom selection - mpInfoLayer* m_movingInfoLayer; // !< For moving info layers over the window area + mpInfoLayer* m_movingInfoLayer; // !< For moving info layers over the window area bool m_zooming; wxRect m_zoomRect; std::stack> m_undoZoomStack; @@ -1333,6 +1371,14 @@ protected: DECLARE_DYNAMIC_CLASS( mpWindow ) DECLARE_EVENT_TABLE() + +private: + struct DelegatingContructorTag {}; + + template + mpWindow( DelegatingContructorTag, Ts&&... windowArgs ); + + void initializeGraphicsContext(); }; // ----------------------------------------------------------------------------- diff --git a/resources/bitmaps_png/png/zoom_in_horizontally_16.png b/resources/bitmaps_png/png/zoom_in_horizontally_16.png new file mode 100644 index 0000000000000000000000000000000000000000..b9712f40cc3e92898f4558c999f3e8913dfba2bd GIT binary patch literal 272 zcmV+r0q_2aP)Z~ z&ww8?P)C6$J2okZC=f;Sg+xGvLOFw7g57<&AiUtnP=2t2(2CGZkU)@i$cE4~Alw>c z2UeaLQVvuQ${F$^d(OAv1tdp`m^upt1a0M_c{CGpwg))blh1fcuw zgj<1dWT;cf#^A`1pwLYrcY`(HjzsY$e`sK6AW*k@$oXJxxHqu{RJdmF9C$#{ID00000fhdEP)X$P-F`BgWW|CQk#M} zEwt>@NZQJ*=AHAv{G1oU{{o`}`1CO0m!gwIxibvlu1CKCmaO`tl;auOeDMn}^j@v% zt6cyQHhTc~`M{h{dz4u=?6?Q;9uWb8%}o>%c4*gZ^2k$rV|-4Je*^N&0FWLJ z=IoTWe6-VGNnqP!A)v3NOJ5ANG|OgROW~od=yi_?KJOX9<5suLfuX}|wG%eD;8CHF zV2vNPKCsq-!kdg0005YNklM6s|i3oG%?_cqNRVP&DLEd9vO63K7*F~h=-h*FCDj4~F4 z#?nq%*!VTidC!|?-n^?uHWs>@bMHOpbI-ZwhoULJTgpG+F9Af>Pt3lwtt0gO1VG&} z08xRULn#-{7{Vl4s4(^pK~&iRt9F1$!3e^*g`XC1#ZsUlH3qN}1)w6lM+54Uag00i zMD}VmUDCBL-3AC#i3PwsG=#__+~)NdLL$R3%~W$tkAh;;^v+ElgxF%<1bFlC%3FQ; z^&@XS`%`NwFJae|N)Z;N20mbFzj^Zw0Kcb21NiH1ELYcXY{~oRumLn0Wq_KEXFGr< zFsEmlW?A(f4+zkL{uTzXXb0d$&5-~wgBb=C;0UL9#1l@%36(RrPpnG-k`P+IGGYs1 z8-tP%oS#T#{9P5M(J~G`C0$F@Nk37N#$|C{pKQQNsM5$m5(UMfk|0f^vygmgxD{uO z#Zg6l!3Kf0#BU18S;}gr*ktGqdeMa~4sp+Ld_01PDP?&xsnzJm21ABLji$6Ea$8vl zM>ECK&WxCfARO%+-#`&Anr1}1bfCmJiCol)rvI`2*8m^5G4o(R&@V9n0000a9NCt3TN+Y;M6 z%@a^L<^t@j<*gTB!?qtqQNHsn|Lc`K;05r$ea1Mz9zxv!6R;Ohln0WGFH)l>vB0)* z4@J4Yv(^<*4weB@!*h3lODH35`dFFWSm4Mr3|rRWC?0ke}&UDp&xl&40|b z(ZYZP%KhT>`|45Dt{wwkLpf3CX-SI~03Nyn+(gGlU*@7{WKHo)v=x;u51_{c)EG6g zqwJ3&@CHpR^aD~sKJ!CrTmiM))fhE&x&x^oSu#%S%Lmhw+b29hWwARzr!Qavj53lR z+BmjhXa z%F_vw?7dAnh{`QLfQu++Cfuf_2hF~42JD%`Fr(3pS}Z7i3>ObpY&qZf9$i`h(jEuR zr&Jt9?d$jwr@wnvE+=Z##24`n<=XGUks40&6-61Mn{Ga!C_gwaTgjk&W^)A>j{lXJ zSin&pk@ZIpKL_R&wdL&#;Zsl&mWWNg3gD=}-3AQcCzdThxRbBF&R| zs>oKppkySZCej>kn1ZKcp13@PZ_{Y2y&_H3=X({X0{;Z~4WDlY$yE%c-2eap07*qo IM6N<$g0)X!_5c6? literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_horizontally_64.png b/resources/bitmaps_png/png/zoom_in_horizontally_64.png new file mode 100644 index 0000000000000000000000000000000000000000..a97206b51895d1b936f3c422133bc27a91cd432c GIT binary patch literal 1016 zcmV0u>Y)p!Wfylkb9S7anVp$)7Iv|R;XKWM{+aWgIsf%|WY5$N zj|<=exBxDI3*Z9$hX6P;S&LbH*+PxfCkp`T1ORX&=}8s<>47a=0O(IDzyl5du7f$Fx(C1@&F(#t+EAR3XT9+4DZ$DhT$@X$ZjYjHP8V=s&oXaH~=!-v;n}Sk)7EC zfFH&c4SWt|o)i<>8hEJwhhrRozqs5I0J_!lv;pvMgsERIILl-^O+Wk~+s!4DIWC6ZRNm(ZAVZrDVDDV`!T}hjlGiaOZV5o;_o)0w z^k^&rzTrF#0Gq7>OBA4TAzSEzFhDK)LWv`Q3{5IPC=EV11NgVG=W5OLb^uEPs$up= zo?y@Z8CphBL_37x=!nMI;Yyf0992Wo3vgf6 z&t&>11OfO*fTiqNiab?i(3sJy41A$x1@=U)k~}S`Df$h9N5D72z%sq#@QsiVqtkMX zkne`AsY)2eC&FHEg9YtuVK)>AMAu_8xg9|H9QbMs#@s-}55>5i$$De5pCUbHlAdDH z+PFfoAsG!tQU?|qc00g!TVdL39}XI;AgKt(6vNb~Y?2>IZ#2!>B_n=1rk1VDkC=Y5Iry=3Q_zODi#I=8&N?Nu~7^NT3HB!g|_-TtSq#$vk(nfUm;i>h`V=iu=8;t z5d0VG%xS{mDg9VXq46Jau!Lq@#Qa~$_#W#s3Ffgyx zl$<2VFlXGLj27ZJt_kTb&-1!s6ssKNMr`3!4!#USyJTry;!s59J~9 z?J!r30LYiMP$x-;0+(j7cLtPzH{c==w297fPmwLqJ8bs5V$w4+K#jGXa;NPd0ro{ea{~tmxk@0F+K2q)G2_3rebkD3f;hyyo-y&Kd!LJetZB;KMdjsgJRKLIxgx2a+ZupAt&gl`4=?qD$kN ziL??SlMx<{x+SXDWNska$`J;xKgLnVMfyE-JPemh-U6kQx o;P^x7k6nXca&CO zON-P%5XZ;ys^~#bQ4kbVP!|PJ(1Qo};Fs~_LGTm!z$b_zzD3;~J*BM{iut&!$0odmqEXWyV=#x9MmIWUmLFd@ztAIYJT(xm10BlPkca;MO zx?crA)3k(Lc>(YIg@i2RBtRxG{%CX_wbTc-v;bpR0nYI!Muf#hHA=?JENiif|nkekA~@$jMm)ZCbChLk{iDMRXStKhJ>rYO9V?Kl_TW zm9>2$6`I?M*B8>{;GwjlxApk%1_E`a7enX2HJG=qL-yq6qJip=j-HZjj!`^Q1 z)zc~H9$EodZo#3V(^0ksaQGDZvsPPRQ-qNpZZpRRjVkMirvUe=UzgfazT9VBgf_=8 zaYk+35Bf4QhHBrL&VAos1UruM`8DPXtdF5hBMO3GneKl0_`P)G=Hm8Du67V1V(6N4 zYD6}z*fbtAnFN%dA*z#@AH)2KPJ86>3)~GR-KeX}d5FqZJeSKTX}f$H$McZ^5p*7x z(VpIVQ(sU;5JNAc5njhlfL+T&484v=`a{x+7h-#^o1*jRu=NkgNX0<#QGo2Pe@bhB c8lX)60q2J;gg_#9K>z>%07*qoM6N<$g3CxhvH$=8 literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_horizontally_dark_48.png b/resources/bitmaps_png/png/zoom_in_horizontally_dark_48.png new file mode 100644 index 0000000000000000000000000000000000000000..1d50790eb4ed82f6d27ace08470b0718b3c5c550 GIT binary patch literal 1025 zcmV+c1pfPpP)lqh`4|tQ4i|HT@e(#xPY2qE?)GYAPRz@M-Sq5@gg1t6+sk4JO&ia z!C*4I=)|t7?wQdfNE9VeNlY^SZ@Ome^zw4d-_g=lKnsho{Gm%?O z1P}p401-e05CKF0;}L+j@_7licZ zC3OB}+yLmJ$285^WdlIqJOI+F09a(It+S(C=MV4=j&J-y8$?SALp-Ii=H})p>Hs{= zHGZxv0L!wbL4i-I0Jg>s2!q=s=V|?DzkPiPeE)FDTKguWv}6EAY}G=86qr2qgKcCt9Yqx57HSKWDbqV8?=!0e=PsTT*XQGx8KO*cOZr(axpJ)WQH)W|_4! zI{ed#bR=E#0ARtxzF_mV;XGF`c!L~!6{I};d#=Z7>k0tglLojDFjhzxf;f~1fPuFv z0I<+wncf-;o#Z)rL#z*U4|f;HjapOykPO~sW5-p-Wc!K=1OT8fC9S(SEC9Iz#{19) zD1np>kl8hRZw>%y@TDTaBzZvf=KFl{g~@u}OoBd*`cv&4OH=?z=Sl!-sgDBCx9EqG z3+w!=H>mNuy<&inF62-@1#2!Y+U)sEV;iVhnzbVrbTQtL?f1JJ#=p^S`cGLU7YY-^ zbO_0eus>`JAOWnEbM%UWI7}L)V_gC~2@8O7;-<_(S1L}U#SSt$RQwCXz6mzvy=gX{M!#W#F)j?!=%RBaM7Q|Tns6C&UjAG(vHn3$P$UJP3E)(KuaRh|MZ%@d# v(aa^s5O*kcqSxsNAOeU0B7g|szX$jW%#D3n|1bqB00000NkvXXu0mjf!&TNQ literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_horizontally_dark_64.png b/resources/bitmaps_png/png/zoom_in_horizontally_dark_64.png new file mode 100644 index 0000000000000000000000000000000000000000..f8aa064ab6591a4d6ad11f16f0ece3ae94590339 GIT binary patch literal 1356 zcmV-S1+)5zP)g<3 zq2(+?7Jvm{0aySQfCXRySO6A)1z-VK02V-s_`bjAQrlS3cP_M;^yJ#51_1B8#t49h z6Pzbq@!paHfOnR4d0}M$(vhP}6##kkStS6aOTQ5UC`2B0m_GXUkNi=`ueift~C4!y1% zaW^@1O~VmaD^J{o^ZKH4$cv5r17q%}2mm7AEd`)aZyeXHvGM?*!5cAmm$sSjc(Zsm zoHb84;!KSFT(<^n;E`$o=s)3$6AJ^t%Wv$~L^%M692a5U-{Jf@X!fbGv9aAtSr4p2 z1IQ5WtN?(W;f6v0;Q5clgq^(tU=NQuvk`eV^cktQL7 zqVBtlY;L`6@qXQQKU^6V7s3ZV@#*ffE?klDN z;Qdxd|OK`fV%P7*DCQqDx5t9NHh~9{{Al zF)#jdSpbkvyBwiEeXwR>PnZQ@;0P#RTopZUxZ;NH@Hll)E5Gn)Bob)&d+i7W`ZHL} zn;cRTinGwdXr0j`V8RIoZg4_cs4?OMJ-R6?#8z^GhQiNNZW6S)Ctlk73M?sF{*hR&#--7i?U>l`e)%l*6I7-nr1x z$!SVvme!NoR#L|z=ar|f?0Y$Eq#@$Twc7k&I7F7+eBcMCs!lI}t4oztHXCb*m}-f! zv(a8)uGI&Gb>+?D_{<%o#a7trONtSE{NNPcEGJ3i z(=nVp;rSbyw{M%hE2m;0Hcfv$y-#18q9)to*zDPf4k<5LaY?|6t_v;Vi?R?Zx5W)# zjI7{@5O#ZW?gzv-(AYit?QSm+DqoEB>uQXP8g_~Zr4M7>=UG~R`*IaDb$E_%C=9{K z)!3k2j+TL7h+k~&*Urs3%~-f04x9tzyh!UEC35&dCLDhwDq98c{j@d O0000F2-=3IWmH9o@#rkFDFefN2cafTaQHFwPWNe{p^v4&vZyRtJ^&p#Rw8R`SW{Me zKER4&%Ye#JsRwx&r8Fklz+Mg^c)(R=^f42(X^&D&<05k!K$MM`tI%Qdi8UO$Q07*qoM6N<$f}8Jc;s5{u literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_vertically_24.png b/resources/bitmaps_png/png/zoom_in_vertically_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f6b57256e8da7702e6bf47d7abf5fd3c0579b223 GIT binary patch literal 378 zcmV-=0fqjFP) z%#51j1@@(E2d=TBMh(uSsYZ>H#l024TVcMGl5_FU!v!;q2wr9mZVcpNPF7qz;7MF( zLk&iZ+a%p`eL~U-dR9qNW`}V#TxDJj6Vj2RfVN5#U92&xrj$Y(pK=g9xC;9i;Tc1m zl=tz@!w{>%_;;z;n?yov4=VU@(iVVK-w(BM#z`|_F%Vk5AG`nq{kA9u7K{Gj2!uH^ YUlUj=kAND<0{{R307*qoM6N<$f&r15kN^Mx literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_vertically_32.png b/resources/bitmaps_png/png/zoom_in_vertically_32.png new file mode 100644 index 0000000000000000000000000000000000000000..336db9af1f401ff4d9847d5504880a05383be1e7 GIT binary patch literal 523 zcmV+m0`&cfP)kdg0005fNkl2_T+M%Q~MI-B=?oZr3gIp=v^n`$$QuHvp@^EXT$Q7K08iZ>Aum6idW zE)hTssvhrHr#fkXs6_~IBiRVrQJQ`Q`0ViGT#IN@dPKkL_t_{C>vfzO>qGeEv@nY${$i0> zh=t*lh z(o0*87`4f^ag8q9b2M1BXw-U;Ey8qc%a8>4@^MEOovwtTzG6{_`ZJ|RSt+C~o`yXP zV+h-9ZU@{E6*H*_6EP`nHq}jrOj5II>(69a{eZ9_Tt>{NA}nd2ve>It3`haI&O}S2 zDg!ZyZYhA`Ni@|jY0KMsB+1sJ7Hpk`oBqM_Cr4ZA;Yt;0+xqXv`v)m;^8j60`Cb43 N002ovPDHLkV1g-C=JWsn literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_vertically_48.png b/resources/bitmaps_png/png/zoom_in_vertically_48.png new file mode 100644 index 0000000000000000000000000000000000000000..685f44cf1d56626c86b2173d217df7122721d65c GIT binary patch literal 747 zcmVNuhC^wN1 z(W0Fd5=coA5?JOBno*LBDe5?<#mqRPlQYhHGee6woA=(moR53Xx##CuYGqf_+AMYQ zLSC6B%aw6}L>vJL1g zmL4WHQ@$oM_@yjuKy!)oFr89)RDR%>U1vxzMM^VINqLVWkrdbE% z=qCRMB)!q%Be=jse_3nUk{#r#i)V)bysR4XJG3it@{I^sj6CnL@eb03Zd7p|r=H=cx?D z611n5RpvHJb6WryAIi(vdq*jXnnQ8G2Pju;19*(aTVKjhwDoZ8i>DTq0sDXn)VDhs zz@NuF%gO3<@>(1u5Vd_mJ$M_wYP?5fk1c@ZBE(z-Fq{DR8Fsb|*#@Y^S3(`7YN^$- zQ{3W~6DVqY;ud$*bj%X$F0>m(y{Mc?<^ws1$_M*SzJSV;WB_iXT(b>mE@76C=lB{R zpD)bDE|#~7MV37KoTQ42s2OkH8+~uu5%!5%YPDA|g>v0dF0x$op=Q(^*|_4Zl4+D+ z+ewGnREp#o$_n?z9nG9_fEz5JvWgOrI)?>E^0~@Fq=Oq|kZ&l;GB>4x0Lnb|j!UMm zoXfl;h@ylT=DMj=OD&G2LZnr|y9-UFRCgAy3*{7u4D=1j5gBPsq=DZk0dZ%oFNz@U z+6I`Bglsyweut;l+>`1o0@944gaIURl$vogfMk7y%K8wPlQA|YgLqDUCBzx5k$(E6 d@t>M-{s8=e20Fp3=Y9YH002ovPDHLkV1frjUW)(# literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_vertically_64.png b/resources/bitmaps_png/png/zoom_in_vertically_64.png new file mode 100644 index 0000000000000000000000000000000000000000..9d7b02c1e359a8e5556ca515a6033f2958863b19 GIT binary patch literal 992 zcmV<610Vc}P)iba!E=-K}Yrrsz3ZE z@Q*MI#2`WtilF{65Hg7V2qKW8(zMiTc5c_az1?H>Zuag7d4KINyYtyMGw*%pO@c2W zwieOLm<$cjfXOidz@^v-pTI}$3wSD*M-@Oy2M>&}!8Q91UR)g&04akG{w-i|&3=Mc zUS}(SD-*mhW;nQJ6Qt9*$rb=-Hn|IbLJqFk6m(&(Pyi{PbiyRp;F?WC4;Bgmz#{0O zpYw%dI6(GC1c1p{4_!evWIEtraBr*+9Vf!rIM8nT&&^SZ19JeF2WV{0oG2%wm}kQ| zfEWWv>GDpt_KI9_4K1QZq?* zXC_<+?HB<7Sgbnuswuz|wSOAxe_k9w8T+8*e{!diYpUjdt!4%GL~fBR^%$4K`Zo## zaAvcCT6q^CAx4`v0sv2v5{7Yrdlx)lL3^dhIB;J{GSU_vfQn`Cl|LBs>VQJ#)UKfH zr?g(twO(YcwStoo^s&FK)ctEW_6MpUDIZ3ag=vpHdL&}4f6 O0000Xjrnws-tUN3Lq zpSaE$CJJvZ7GF(w?)lDlzVqFh_rCTWI**+}vT&@>@1O2{IdIMmv&9oK@Jtr{J6_P@ zDYtm6CxH|XkfA*`a3r0ZC4mq=6ld~J@AOnqf*dVqfdUhp4<6yO2WW7O6W-{?-JxF* zKmv=D(5=cYVDVm*EC&&2H!Y6ixSt)*>L^hZ)y2e{G)+e;3CPmA;7~|rr0W@5J_iGH zg&&T#DhYA}o1DObjv*dg$`-EJ@XFhEvh7L&m8o+5weKr7@kC2L@^v9-@cITiir)jfTCnFc#Rn2Xl`Lgp`As^gs5m`E}IS`knog2(oqV3Y(6C<7eP_h m_!uPY`b>67}0000_d6jE14iKv*Mm_y zhYEMgmbB8Hho%edGXX!gn%aWGTe868??Ays`A&&k*b$ZB)Ce>FlZ(ibVeU%~F49RN zxvFRw2!FKFO^exLH=h{=>rQFP8goj5gfUK0+qO9-0xu{YucX9^bD?p^d{0R(G=0yh zOL5qsz%SF@GwrR$(kj?hwE-m;E&WCkOTQ^w_!8v(!AJz$n(K#+PJQWDB%A{uY2eu5 sQb#~T$Z_B_GBQP^k@;6cKbGH?Hz%&p2dJn_HUIzs07*qoM6N<$f&lT?UH||9 literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_vertically_dark_32.png b/resources/bitmaps_png/png/zoom_in_vertically_dark_32.png new file mode 100644 index 0000000000000000000000000000000000000000..735a479896dfe362c872f1558b6c3d82991ca21f GIT binary patch literal 697 zcmV;q0!ICbP)F_X0=@@HkUmHdMOE# z)vS4xHGPGBV{NZFO{?1j7>Ti}FS05XR0yKD`4;NH5$l>msMXd#@u zgt1gY4@re~4*)d)BK}k94FmvneGwazGj7>$f@&noxxuTtBBUt*kb7PMP@UEZ)lxwF zyNQY>@Wqe2fEu?|jzgZ_07$|K1NN@dlpISzw4MqJ`inqFmyzi=W&EKYuW%vV$a}*_ z*r)cG$0SlY;4`e~w#Nw2b+K$5@Oo_iBI^r^KI8c%?-8$1mOC=QnoeWwj?W`FD#=y$ z2oRBnSU>Bx9ZQ`X-r4PlCjstR=UPj*){0(m#vb%qhHYn57e45S%ob$(uIafkW&y$< zIK$5|pXU`o9LGz9{ovq@D5GL}CM9h-K~iF^=ADW&;sMFD`BN^ z&>N&WQY7J}G9U(1!x`=JD9ZD021L_&G^2g_?=@*qWkFQcW@`X;wG4>rdi{7hKUdHx zB6Z9g0Fhn&B$>#yUJ!f&Kn{5WAi}esC@pH!Rmk#a7Fph`M3!eQ_HSHF{+X*;naink f$)U?~AJ_9=30W;h1jjPd00000NkvXXu0mjfD@r&i literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_vertically_dark_48.png b/resources/bitmaps_png/png/zoom_in_vertically_dark_48.png new file mode 100644 index 0000000000000000000000000000000000000000..6e427610425e2d7858a94ab2bf8a4eb2c488de35 GIT binary patch literal 982 zcmV;{11bE8P)NklCH!j5A#*MfXvpCqQr znW?bzZEbCH0w{7VIZyF`2=BDQWXuNnc~%{MZIZ7U?SnjXN~Q~d_LBd{oh75wbQiEB2D zhMquOoy0Q)W(bscGMg$p31@zcxX$6U{~#lf1ahQSnyXX_QE>vuZ;n!W;EFm!kiV|6 zUJyK2O9YUC^4pFu`3|dpCJ{?CW_055_zH}jK*INOLQmn348xcgI03HkyAsqdd_L_# z{~&a~%JiY7+&ZBw@RrJsN$@|p#&>vrE^4jCGkxRFvP*#wNT<@U=d?L!>{LD-%smId z_IxQb)7VbTkJ8RfH-W1N0jzkFT>Urs=3(DU9GT{p0t6q*1!(r20G#zHy}Xd!Q+}T< zUc}aXI&v4tjM{xCkS%7!%2ElWOHq{%LWWDNl}oRI#}BB1T$?Xa4=CcJ^Dx7hLgRK< ze3hRBB6#T-IiQO`kB5ThyVI%D-HHGR(2Ff1LC!ki7oFy^Ol4&##@-BQ9_3Bhs%^5# zVg3j0rfHhI{FqmeZ)b&(bUFM37FB1 zAd@-jg|=ooZ7`?p#h#&+=d!P4s$#^7S^ERcMkyrXRDL0M0tF0vK+(pXWs0cSgt?p0 z`6G2l<=+A7WCvT&z}~T{R~_Keoi-5bAi?*f;~W?Ukz1B-9U$;>Y|vDVeSw#hRJg#l zuK-Y|JgGCF>Co#Td+${~t#j~t=Oi6iNG?QZJ=gw!9Y+ZiJIsvltZFs+9TL0 z@`>LW$CiO0Tz#QQBouzncLLP7EtZW^19(ajROD#lKKV{42~;%-dAQ*4a^=(?*ab)E zub4uA$yYbmtaWqIT~GgNkQ-8Ub_izjnuI>j+|U$||GwjViBlV|0000007*qoM6N<$ Ef|%jcE&u=k literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_in_vertically_dark_64.png b/resources/bitmaps_png/png/zoom_in_vertically_dark_64.png new file mode 100644 index 0000000000000000000000000000000000000000..9640242649deab87079e5745744471e78dc5d119 GIT binary patch literal 1303 zcmV+y1?c*TP);COfU z&7>qMds0(8D1S>PcPp-@Gz|ce6O)RH{}rNmP)-vFC+AE{EdVs@yiw{Z?vlSkAg)L`7-6&Zjnwlqy1 zkO63Q0O+jl#l5;BisV^-MpG9)=u4ozny}iA+0E15>R)<&cH{TMpR0B|!S{P`3kvP(VkCY`|!TjLq zyd|Dews;wAcvo3q2RlSKW@Rb?;0iv63Y^oF`Hhst@7h8;NS2t3WA~Sr!1AqB0l-Y| zVXvFxH8XH!w{>=Qj*4VGXcZbjg0LzT0La7Rga?ZgzeJ{9b3c)Z1zvy9{afdfNRQ)R zeFk3)nXe_bhKy}PIBRgFH!7vBtFV>)sPU800Q#-IJBPfz1-}+L3fBw^ip!-wD0Fn2 z!lAmYHg~Mx;!$G(l$X8o@lYpe!y8)ZyC<~!bfkAGj=SKEmERc)zzuPpQhgPpL<9hy zV-?>Q$Da+`GL7pBGdX$4q#1k|HvrrwtNrncIgc0zAa9FBn)wGqRvYACvEJ|i-C5dV zZ{WLUy1KfqE!$pP%_)tSuNenGG4aB1E94%AMr?^8gwKL0b(PV@005W*2fXV1j00o6Q5j#gqO7^GrNj9v=H|!bHc*%cS+16FbS>qOUyanwQ5tf(ZG+#5H9q)&z01Kr>=Xwu)HQ+tW- z`;fAfBmsxpD0#x~Ki0gxXZB3?2SDtL^I~Q4C&M;8fGc+>YATHI1X|IOqD34?3PQaO zMn+OZD0X`*oDYa!Fw=XLb3Qt-EfRrH|2x81)R0rec)kIZeTT&T%;i$LR9V3{#10`< z2boDgNZn~}+z?WEq&=7$ydM2TXD~!Mjx(lZ?g#uY1Y5poBmg%(j(ACmE>=Z_fCbiz zMgpKKZ#CoryQ;mhim=vG`faQaND@FQ@_?oU5b?4!tD!60or=rS!WIuU?7Dmo7MpZ5 zc3&MHOk6hZ!9@0CW;lyDDsPYN(bQ46D|x!}J8-5&m$#o2(%Mv&24` zRGh14i(fZ^H*<{wC;PMsrFDB8CO>bn;q^`Ch!p)~|0H}u&5G=dq6Kvx86Fuc3;)R_fV1HH!J M>FVdQ&MBb@0N|5e(EtDd literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_horizontally_24.png b/resources/bitmaps_png/png/zoom_out_horizontally_24.png new file mode 100644 index 0000000000000000000000000000000000000000..eb37664a3136145abe6e085515d31e7db191186e GIT binary patch literal 367 zcmV-#0g(QQP)F5ppGz2c{^2 zBlJRW7}TIMKviv_HVh#RKn4&7yMs0C4)H;DcaTNMNvJ_!RUr*<4IziX=6vyF57Y^6 z59t8GP~!%skoTZ43^{~Tg9A&DMes}r3~~gDd<kdg0005NNklp<4300CtAK;e+js0REGX+lW*@rIlXxfkpL;|Ey> zUkkn&DUMJP(hSrAF(6Vr*d=&Akozv04=z17{12WV>=G%? z5E2U141whk>2S4>zah>Tfo2f$FVq0au7K+aMK<82FBjPU;*eX|!ad|@NGFI+;0Sq! z-GKigx!~}fAF>P-%fU-SRzYC!if}cc0h2;jgXQy(bYL?eWO2x1paJS3Cqm9ZVCbn} z6QITkpK?$_h;00000NkvXXu0mjfv2xL& literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_horizontally_48.png b/resources/bitmaps_png/png/zoom_out_horizontally_48.png new file mode 100644 index 0000000000000000000000000000000000000000..7db4e660e62b6f3d2edd0483418a818b8554e5d7 GIT binary patch literal 730 zcmV<00ww*4P) zPe_ze5WwGRq+)+8gusZ%gdpr>U9`d^C<$VB-|y+JwIE&WP!I({P~fG5^zYIoItJw> z5+b@A(IK%Y#6xbTrG}U!Yl^z=bnsi<-S69PcWWhx0CxrA@d0HMR73OxD_g7Dge0#%|!1uJz6 zFA;>t%_R=kIgg|Re6~NFdk8b8&F1DflZftCo|Iq~^C>+*^w|`3AHq-nA;-MzVI1LN ziZo<}a1Ee`2s37h2Re%qQ_BcKAYC&34JbXs;f2HF1fS8?@R&P!K&3$Zg>M2YfN zn7ZT>4;|A);~gNo5G5p8cO&MMYg;~mn2)(7IiXDHK+H4OGQEp%GgFy{)BR|tH#1Gl ze>9!@*1gQL;NP9@N7F-@Tg3%Lj|O%*xert^j?k5{Rk$@f<)H`B!}_58_GSVh+Hx$H zX6MkZO__Otu*5@C7f-+0$1Ua%vy2cihqG}SdjyNHlM`jj7zr9pfo0?F0k~0T{^U(j}wZ#cxTU&g! z-ip6ivzqvY5HWReiMPU6o7dIRLfl`+-PGTpADEiL`d$DO0RIH=8wDi^x*7J@8~^|S M07*qoM6N<$g2V?)!~g&Q literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_horizontally_64.png b/resources/bitmaps_png/png/zoom_out_horizontally_64.png new file mode 100644 index 0000000000000000000000000000000000000000..77039322511a9b0cc5a56d41dfb6a3b345701949 GIT binary patch literal 965 zcmV;$13LVPP)aDz=|~bK_b!;O2enVJLmA84@Av$(?XJ|#=%UQjd^X7c_oHJ+6Oh64R ztOR@jAHWCj0ek=-;6DPu#mO>iwqzQHuG_roc{3a`BZR6NB0vvL6b(D^BBEnejEeYFfQhBYqcOLRYp z0pJ-w=iwWjo5VU{itU46RBJ4p$DMu71;8kcp(aLZDTSP`>tu6hJ+oZVb_c%Xc(Bk& z*9kbyq>=$Zw9OiQwUY|^zAb0tJ#77Q0_uT+uWT)-BF0k>#Ql(}+j8ol*Hmn`y zy5R+&LYEC-kd6(=Ry*jS+P~|TS^(~GtOx)m!&^+nXAP@%SEK>z*&4;OBjL?386SX3 zI!)hXht(PywmHN>jJdB{1rDm09rFT_BIEZ8d^!TF~1~B(O8HIS%hX zXtT~l6EUlx*l6)!Gc)hKnb}R`y^nr_=x+#EYsY>{EIGvoC3I3R7~BrVQRAjd-1bln zC+c~p;q+a=;0@m6T$zLfR$25yiV7IKB28z4tT~hJLW;-(ys6Lk!oqNZ*acb*Zrwrgin{4!Uh*yVuD93cEC&Q zIs?d^ECfsZ>KakuWNu(zAkNgIc_!W2)Gh_r_}zz;n|!ex^}|E@-#^m}o0a=tJSeSH P00000NkvXXu0mjf1)-mE literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_horizontally_dark_24.png b/resources/bitmaps_png/png/zoom_out_horizontally_dark_24.png new file mode 100644 index 0000000000000000000000000000000000000000..da7369b1f98fe7480f011379afea896167c8d9cb GIT binary patch literal 486 zcmV@P)Q1A=<15b(|B8YfU!HWu_;BxUp1R;9yD)8b$j$?)m#PqS(7CKY03k?NPGuv^9-Rp$ zfgB8lCt(-3FiXBWqu|hv2L&sPRVDxrrcgqLo%EYa2BW9vQGoJ1Z_oxp#6G(7Kys}9 z@DoOam0@g$vfgD!Y^ZSVTT3{j^Tldfql*(1bCXOciN)9{0($mEg5cHn{a)?r5mc~G z&p(Jw3q8g)qnPKo1NrW+3HWj;Q)P~m7AQRv#S}@xo`wl5i7rv#bTx_SCF9ft_q8Re zQDiP4`ETP4la{~A_wyMlye^szlwp=99noW{g6@OiJ(F@-L*B`C8?3!T=&V_G( c(OQq-6ASstXc>uahX4Qo07*qoM6N<$g4$)%>Hq)$ literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_horizontally_dark_32.png b/resources/bitmaps_png/png/zoom_out_horizontally_dark_32.png new file mode 100644 index 0000000000000000000000000000000000000000..ea2a6a0cf494e04b343e1bf5d2990e2b7cea5b97 GIT binary patch literal 677 zcmV;W0$TlvP) zOOFgu6vtcJh;{U1Y`At)c@~*^Mr1 z*{9Q@RRTcYqIc2qvc=S-#jMO_%=-z80DKQ1ck$j%`+REH_jXCy`cLilQq22089>55 zA1PYg>2wxi{56b8(XRZs@y&Js4Fe(s)QZBdSA29#BLg6l#Uc50EgjVKC5oa&6ZTHi z70e~s!$~8g$pgsa{FwL@-=ZN}qAA)!wWlZCH`&tx$1Pfq{vYJgPKPAhEZZT^0UwGE z=5<875CHbM+w9KIoRA^(jW}nzrWX)A-fvqw59_p8-V;49FpX6 z-2z19Ddu1J<1NT1VH`wT(sLg0wyDG;9j(LM?=~>I-ICDp7@|Hrz*tM_L78|E1Pc&; z&j$Pw?Kw`z(6tbSVYp1H9|YbS&ul6#&!oghjHEUXh(0nE*Df8MEPYjv)6GQ z{%#aOlwQX({zKA8<|3judr5a}${&(hu@r(&WQ$t$Q(6I30D1cb=m#YVr69^q00000 LNkvXXu0mjfFZesZ literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_horizontally_dark_48.png b/resources/bitmaps_png/png/zoom_out_horizontally_dark_48.png new file mode 100644 index 0000000000000000000000000000000000000000..ab734c968f2aebdbedeb391e4661b01d3570f2b7 GIT binary patch literal 969 zcmV;)12+7LP)6(%LqDe=>=iC7aA{5}L{$hBmYR|Ih#Z@0pftHrq0pS4#vS z0uTX+07L*H01<#@0l;FcBdH}9G^?__htErz)*62RI@>4=cA;4T2#sAN9V-LS#eiv= zvztx%Oe`}?==_TU0G{O->=4)aJs5&R)*q}uNU zbW;L=)oLO%A?bhM|4s$^ofOM? z9&w)xP?6_Bb_!^%FaYR)qm_g^I@>2{zjK3cPz?zu<}3%#=R7YvRVDVj+&Yy702i@b z(rN6In;3Ct;(ME4!csiv!ogsNgC-?2*e39fk>}E8dZ7?X@GM+XB?=Y+qe<{B;MO{aSE?JlqI(_ECA^R3ZvIP0N>OO zAZH(JbrUo_W0rjM+EO^vi-LR+8 ze!4HQq(m0ZY$SkI5+^@$@wufKLcHBm~W9Zqe<%_I#$Xb(NMk zlZ>kNlZ;hR;fLq$77AJmFMUUOJct=N~4DS{wOQ}j1$*o6}nVo8O=9_ zAdM^@kI#|rABUH=236kDt(9`n8y4@xvY?HOns3dc1Qb6hX;a``s;WG|x7$X3lt36= zu6dNGVVG;BIbT*P8`fH{VtLT@=OcpMx4H@QC$7w2waOYFWhYJk5P1VMm_#!4& zyjJ4kuCH)QM9 zwz^$t!d@xq;)2*d4H><%Qx_`+H93m+r1oKj%PU({K?Jx`*5^`B9wcR%$yU*Y+*dJ0 z5bBru33ygf1yTK3CB`~v9GHk_6L^Yp;%6bTWg#f_Dvc`8v1y+cOF(G+=A?WZ&0TT~ raf@;%dYz5{L;xZH5r7E5e-GdacDtX>0oP1YC+PfS#=RALKjj&sl|nYg4!;k z3pd&1yzlVE@1VEUK<{EPg%dw!|j*jIbC7$Ot zKZwF?_F{Lsdv#d=z#h28GLZp*$JgFY7!T0#Jo+~93V0OVjHyJOQg#LL{E zw>+C8++g1bgC1oDdn0SmU2saZ%wnGlgIS)occ9IY1fGA7G*&zSu-F@MCI@f_p#PAx zfSb74AdR91-2!bd$=U#B@nNh3Fxl1Q06?fsw?`sx@Ry+9J*WRDob1OfEiDg3wB1?> zAVPR2(gCE{4v#j)2LR6Laug2_efpig|DmeKRbgt<7hsIL&R9cPGrK;#`LX8E0MO3R z23_%USQxg##az}}1C}0#HsCh3qQ;fD>*E^vnkRHE7~4 zqjOCG9{LVNc?5*dAETHfwEHbM($MqK0Kh3^ZL&GQ>6|IH=dY=XF^?QviA5wCz-$&VmLyWB)6JSTY5GpTp%EF#w=bW9@8RiHTQ9puSQK z0Q}UkfT%LxFb!Ef@cMPHTF-y5pGa=_u=;uAHXpGi$6Via#~aBgkWLy5yp45=$tpDo+`SK6nRq0J*F7|q`)38{zX&( zAiqy=gm%v|Ny9#xP5{0pAZ)tRZId3zN6ATE03#1hI57hwRbboLUfwYmwrXvi7NrYS#9HS|^ zN!8}l>GY#8=It=)aQPCU5UDV?`8MeS)u>SYKPhM-QD zXIH^k18y-T%(c4IWk|m8xrG+x*I~z74;CsqCVMV+@wBtI8v6g^nw7A`>t(qPD=&yx zyiV%>H-^ZlncG^<3+D z=zbMN6PLwdvsC1P5y7eU2D}f@>-dx}M$Xziqx3lBbmcz9Bk<1_pN ziT+goBXFuM-VjL$S*+v(iP`XRgf9e(A6N2;%xn=a1oZgx?kh30eTX6_N~yU1OilyP r05kv%Km*VKGyn}i1JD3806+O3(|Gf6D82SY00000NkvXXu0mjfYWq(3 literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_vertically_16.png b/resources/bitmaps_png/png/zoom_out_vertically_16.png new file mode 100644 index 0000000000000000000000000000000000000000..464f9769eb7c38f5175c76c5bfb56f24d2c0c246 GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6u6nvShG?8m{&BvcK`~NswNqH@ zGlg!)l>yr>Jh>pN=Ty%;77-63EFQOPyI0z`SG!B4R>l=gy1esFM)1l=ebU1Z0>C=t$AEKyE!;R z@;|k+wXwNzwykQP!+-6Vbil(|2a7$pvoca_ncc4i%S>bqna14pZh}sVA;S{MXGMt@ SuNwkA$l&Sf=d#Wzp$Pzj(_#4l literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_vertically_24.png b/resources/bitmaps_png/png/zoom_out_vertically_24.png new file mode 100644 index 0000000000000000000000000000000000000000..cac80014e36aca281852259c0b1d099f53b9c4a2 GIT binary patch literal 380 zcmV-?0fYXDP)i^U z%NXn%auTLE^g>8nC^JqcAz-LS$f1x!p&r=euxh{usi7gnGh|oD$B@sV2SWpi&=Arb zaw)_!ls}X?#5v@2a4!K3K<{1&<$>`MI6^N3hvC<-JH!W>A7l}760e4kFP`jyI>GHB z9UvHL42;b8$kB#Hg9A&DMes}r3~~gDd<q6O1Cg9X;e|jeTzM1TLICbbTS!U@=?JpM alm!6k`yy1+C9%H%0000kdg0005JNklBy|0gHfDN{_+=#GrTvMPp;5L=Y@Q zJWwzeii&nNf*@iS%sM1$cFFGg7Ll)6cHjJVX5Ji%rkIOrK?Q~CtGO-j&eZdG>E61@iSrr zRgROGgSZezm|S*eYymR*Pk?B~5N5HAsAzKxpi0aki+gN}4czck(khLnFZ~rb#bcrR z)NXMtZq3Wt6o3Uh7;l|DN>fS_5cJ>!eMLcektMGbfKzv8>emrQr2t|H>-@(?v4&(` zVk78bz%;hxJV+qHfL5H~JTE#EoeZ9&9XY@-(xxHoV@5874o+8BQEFR|p?=wG+@?!^ zg|Rn9nvRtcNkFIu_jD0x*A?{@w{>-0gz6}kF#R!{bQoAvQ zU53P|S5so8+*T$C2aU^!m12aW-lsCL%7~Faj5J1!A^iVC^-p8nezB-c@~ds$U>uiT rZ9moL(*x8V$5S~}uV3#}Yjy4u5~}GHKKg4q00000NkvXXu0mjfO@Y;J literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_vertically_48.png b/resources/bitmaps_png/png/zoom_out_vertically_48.png new file mode 100644 index 0000000000000000000000000000000000000000..a05151e4d227b13c43b7cefce97ed8e444fef475 GIT binary patch literal 695 zcmV;o0!aOdP)Nux`Z=mtbpYP2B7jZTZ?tSOG_ndRjk5Ln>6u8Zfq8nst zYXfYZg#Q&LU4Ys29ky;$fYwUsVaBC2oBX6#_H5cjofXoP;pDEH&?~z<`#?(RvR|?( zw`0;H<-VQVyA9#9OZli=Y}{V7C^8}2!n>4m8Kz50iW;Vl!I~LlP?`gHXo0`v|A74N zEtL))^OaQ+c7g%vC?rG+2G}+`=7i`nOU~E0y-*Z@3EA5y${Xp7R;y7HtFrC9Kv5o@ z-r*a-U6gq_=epG?exSDBgnR+yEXwc5v5ad6nMS$d10bc0qeQcuvFH}BV<8Xr;F=Luj! zB$;;rBQC(N^;#ywo&jq3M)LelHEP;+r}q#NPMMB565VB9qo^O1GdTnK2r8evJNXhS zPjl|LgL1<&ptX`Yl93bH);kWd#B$_-pHy)fwG+|(nbxA!Or!Mq%0(u`0BXnVQTOR( z1|`vc(q}f6a(Rxj$^!|fGN&BoCX1-7p~R)ZXTgyYuCwU$phFDt9YtB;mNXGZS)kE( z$&6KTl@BCPlq4hc*%~!!IGzu&sRG_zW^1Ijvmz}}^B{`QH{?bXr8SWz{-DGq99UoE zAny5XejDVaytXZw3Vo#B-j~{~*}exlfCM^11v&%$Og~om|xU dAaHM8^OC literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_vertically_64.png b/resources/bitmaps_png/png/zoom_out_vertically_64.png new file mode 100644 index 0000000000000000000000000000000000000000..eb2bf2abcd4ee6396d0cd2900cb1386df3bb414e GIT binary patch literal 915 zcmV;E18n?>P)B5E>DIR1~<#AZU8vB61UgX=6U-w3zEO$=va~Gxy#plCzqbZ#cjEoqOIkwk22M z_zPU$u?1ZSU|RHuZItUK*`1^7_(F#^N#jm0*onl zzTp7k78s245@rg5>6yU*A`dfQyrg9kXM4b4I%p^WI>BHZk@A#HmgKB-b;JS z12BFpUJ*+JRIdkv#Z_s51~3@qh5@(^fWh<5WlO;!P!u`dl%^V?2n@za!vM$~`9$Q? ztcq`j!?l#h=melL^@1;J0z6dDXMw?V&NzSyFqo9kCvT>>5^Xvlu8X|T33omiOg_T^ z+*`q5v`YsqA@8)3y&*=yG$`!_cfgpXwMNE)+h7Eh0-3Xwt1%`YjAiS9Jzy|;r3`QZ z3`T>&$q4;mu&7!zYZhV>48L4+t^>fGj{q3sVpq(YD#CX#g5szN1&L?`gYk_jG*9fn zM5siS%LDpLvUar>?xqb3e{Kw0kpYGby-+F|{Hb zQ4#tn!<4ezwHrfPp;&wnPNyAD^dQ91O0=blDhw>_4d?}(pcNrw=s}2oJds5e)Qk>v zP%~93>;8Nnw0AoOl-VsR^jQqQ##Us#-{1@i&M(T^O1=s)p002ovPDHLkV1lhQlUD!$ literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_vertically_dark_16.png b/resources/bitmaps_png/png/zoom_out_vertically_dark_16.png new file mode 100644 index 0000000000000000000000000000000000000000..ad15715f5cbd62da10241af9f94cc2987a2b6cff GIT binary patch literal 382 zcmV-^0fGLBP)Y5Dgdw1rdLMg_Vkhg{7b%ir6R$7O5-*3-Qm`TUn+M4G4DESsh6B0}gIxc0=&~ zf?%`GEV)1==Ou#0gS*+;H?uSEH9`oDaX^DNWUw8f=(Z|vS4^FxD+75mKG^_}I%c(r*zxC%);ej*ms7Q;2sR+Qp z4jFoK3a%qGzVIM-CnAt)ayd=Y*)oI^C(ByS?daAcP*$^%4vyh%yjV&fS=OK2S z1{|k_$~9t&OJ2j7Kq^z0*0_uJ+~%8q7LwO~gGuiHPs$@^iUt~(DH>}EGeteHg-bh& cwX5>J0VHetC%ed3$N&HU07*qoM6N<$g3tS;5dZ)H literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_vertically_dark_24.png b/resources/bitmaps_png/png/zoom_out_vertically_dark_24.png new file mode 100644 index 0000000000000000000000000000000000000000..96410f211a3257689792c13ae337c0b0fe35a975 GIT binary patch literal 502 zcmVK=dCxdvXDBLBxxK9y~ZGxLm|v@UDnnybAt;pP+|95phFIcjscNx+8NH zWYCL(#Hwf@F&WJyBh2AJ=uXwE)bc6?&+`g@0VNI^ftz8V!l5*_iHDBkbU%uR-T+$Z zEiKWD0(QdhuuW*(6 zQ4)*|(^}yfgP+sdr6$OV#vpJ7%uvpc2^GQ%;nbBdUl#)ErfqU4m;`UJhl`39PSM#7 z)nh*w0T+{oO4+vE6}vO0!|x=iihzyGYWS}9`*u& zfB}CXB|cXhvQz|Y>_@8fVHmE0$?tb6l)|>G1m{MWiK-$)u5tc8? zoqT5$tmSG`60-wtNsurS=#F0#ftN<<4+>&A_n@(;eYGSHnttNer8=xr;g{&_jm}o; zA{CsfpXs6$E&fJQ7rpuZ!gtql`ZE)tjbl7`+*!OMcvnR9ikx%d8)o7B@5+oVeOmA_ s=kz0xXX!_aXzB5=4*6Q7U^I>GClAodO)5T>O8@`>07*qoM6N<$f@|jCAOHXW literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_vertically_dark_32.png b/resources/bitmaps_png/png/zoom_out_vertically_dark_32.png new file mode 100644 index 0000000000000000000000000000000000000000..a061bceefd2ac610efbce101b196e82a6710ebd6 GIT binary patch literal 686 zcmV;f0#W^mP)AkWO^`&dml^va>t0dxwzXursrF&iUq?@4RwR6y?&0|J^?!ZF#${ zIPz3leYvzRz|eK+P*hLIrkh3qD4|X(m+mT?26u%V8jk}YonW%|tbP|d+VVhP1t($j zJ`8Ne8{Q+^2*+rp=$$ndf}f?*u_};_28OrTaI>#&ivvQ4PUX-YX$QY*46idd^+R=K zPQqQO%vBB}=KU;u-Kw6J0hp4531H1$?FQKf5ce_Eg%>+%r!Hjnk-p*at@^c+los|yh7JDSWJCft7l zGP0+tfFDbn-W&7)y=KwZmb?h%3;4?ATEYKINXsi4utOtw_R(Yr?lHL%&kQcj;`|e1 z07BvS>O2?nYSW3y@z3MzZzY0TM$=Hb@&gnXxgIp?lyJYLgq+9yA)^31&pXc54+g$r zNa?9xp2_C+9Dn2As_LX zgFlq++gRStV&Yr=IpeDtuV1mdp-xA`tJ$8`jBzaX%dxm-za3-Vi(Aimbx*7BA9Tkg U9O9)sh5!Hn07*qoM6N<$f;etIQvd(} literal 0 HcmV?d00001 diff --git a/resources/bitmaps_png/png/zoom_out_vertically_dark_48.png b/resources/bitmaps_png/png/zoom_out_vertically_dark_48.png new file mode 100644 index 0000000000000000000000000000000000000000..600f3d567f7dc1e40f6b715ef8cf87a3351fbffd GIT binary patch literal 920 zcmV;J184k+P)O@gQy&FXBe+71e;7U=`51NPm;-dZ~pJ!|Npf)j?fVjmcN`w!-ONn6eXXJ%}}Xjw?r*&dk5b0Yelh(wn7 zOxyy{0uYcWFPJJjjBt7%nUy2*{05DIa)?e{^k1{WXVU>7w(qCpR1rEyK)))U4FKTD zH~~QH=hr=n>J_AaJeSFJl-6Xk*`;`P2+8j0vv=A zCt1LCk^mwDV5#hYWd0l1_-5bx($*^M`B2=;&PD>jE#zR&t~qGzNWJ@+#An~J8`Y#$i1AFgE0bB?j0G#!q+amg~`x;sxGkOy`fWOU*SQe-ZSNSk#w9zUx z$crgK4OM`8T(gl;#5->?!!w1R+r8Q4VFGB!ODD(yD**KS=*GTyyD+y;hyVb+*dh=} zMhhqXqQ_iZZQ@XzT$Gy}&iG2&G);4E$N)sAob&7rkOVhKt*GHgA%&fm03J1d2EQSr z(B;qp(2Pi`e*%uVz25zXYOIlk-iYWEDGhMn4=C?fd$h7GD2VABY#}ibvrK1eX&5|ZAP5K|7L$b_AYwBffu_hOev}+r z27+YGg~~uE{8pp@C^UkRXP}ofvG&`%yG@QJZj)Zxx{c00006nb40O{G$m1&C2pfFopz;cWT~=1s*VR4%Lf9&JOBK=- zS9lf3c33;tQ%;a+Y%wVCq!-GUqg8o63IsKMc9h@{*49nMUxTBx9`5FN6UQB{;cOJqXNlJ)RCZgd{<@vq=ptiPlBqQur z67rKw+TfXo2%4t>0CKaGEA*p9Ih`x)x=`qTNSf9M6}nESbRSdMC803Y^4qUY*9M&} zgc8}+G+KgO*KXNSqrV@Fbe8);3$JYKKqZ%w7 z0C?kLjJFTx_NoJg)&udTiN4Hr00dRK++_aNkd?~~W^{2D0HDAYFMhcPCGn>Tj!+8^H(A&z_W_{MwZ;a6 zgl0RmWYyeoyO$@0CM+``isc~B5IskN{Pc@y9*^cM{e8BC= zP-#3G(9OM{F5&sGRgZt1A#5H`2RsdZgL0X+ZBI95UxYrIhqQTbt0 zJpYU#(soqQ^qC@F3&8AB$jkv8FNt9&Oz8Y#9Z(ZvyLt}ieXxRLvLf@K#536-I9n8L zr@-cFa5I?n18{1)LYh7Ul|_=oG&T{*6MTQenlh1qHG6v#hO W9QAz3C-(IK0000 + + + + + + + + + image/svg+xml + + zoom_in + + + + + + + + + + + + + + + zoom_in + + + + + + + diff --git a/resources/bitmaps_png/sources/dark/zoom_in_vertically.svg b/resources/bitmaps_png/sources/dark/zoom_in_vertically.svg new file mode 100644 index 0000000000..de6e48affd --- /dev/null +++ b/resources/bitmaps_png/sources/dark/zoom_in_vertically.svg @@ -0,0 +1,122 @@ + + + + + + + + + + image/svg+xml + + zoom_in + + + + + + + + + + + + + + + zoom_in + + + + + + + diff --git a/resources/bitmaps_png/sources/dark/zoom_out_horizontally.svg b/resources/bitmaps_png/sources/dark/zoom_out_horizontally.svg new file mode 100644 index 0000000000..a8a667e6a9 --- /dev/null +++ b/resources/bitmaps_png/sources/dark/zoom_out_horizontally.svg @@ -0,0 +1,114 @@ + + + + + + + + + + image/svg+xml + + zoom_in + + + + + + + + + + + + + + + zoom_in + + + + + + diff --git a/resources/bitmaps_png/sources/dark/zoom_out_vertically.svg b/resources/bitmaps_png/sources/dark/zoom_out_vertically.svg new file mode 100644 index 0000000000..b2e901c37f --- /dev/null +++ b/resources/bitmaps_png/sources/dark/zoom_out_vertically.svg @@ -0,0 +1,114 @@ + + + + + + + + + + image/svg+xml + + zoom_in + + + + + + + + + + + + + + + zoom_in + + + + + + diff --git a/resources/bitmaps_png/sources/light/zoom_in_horizontally.svg b/resources/bitmaps_png/sources/light/zoom_in_horizontally.svg new file mode 100644 index 0000000000..48476a11ef --- /dev/null +++ b/resources/bitmaps_png/sources/light/zoom_in_horizontally.svg @@ -0,0 +1,122 @@ + + + + + + + + + + image/svg+xml + + zoom_in + + + + + + + + + + + + + + + zoom_in + + + + + + + diff --git a/resources/bitmaps_png/sources/light/zoom_in_vertically.svg b/resources/bitmaps_png/sources/light/zoom_in_vertically.svg new file mode 100644 index 0000000000..73d63ad31f --- /dev/null +++ b/resources/bitmaps_png/sources/light/zoom_in_vertically.svg @@ -0,0 +1,122 @@ + + + + + + + + + + image/svg+xml + + zoom_in + + + + + + + + + + + + + + + zoom_in + + + + + + + diff --git a/resources/bitmaps_png/sources/light/zoom_out_horizontally.svg b/resources/bitmaps_png/sources/light/zoom_out_horizontally.svg new file mode 100644 index 0000000000..30a0a5a52f --- /dev/null +++ b/resources/bitmaps_png/sources/light/zoom_out_horizontally.svg @@ -0,0 +1,114 @@ + + + + + + + + + + image/svg+xml + + zoom_in + + + + + + + + + + + + + + + zoom_in + + + + + + diff --git a/resources/bitmaps_png/sources/light/zoom_out_vertically.svg b/resources/bitmaps_png/sources/light/zoom_out_vertically.svg new file mode 100644 index 0000000000..8021dd0d0f --- /dev/null +++ b/resources/bitmaps_png/sources/light/zoom_out_vertically.svg @@ -0,0 +1,114 @@ + + + + + + + + + + image/svg+xml + + zoom_in + + + + + + + + + + + + + + + zoom_in + + + + + +