Add Ctrl+scrollwheel zoom to the timeline (#2781).
authorCarl Hetherington <cth@carlh.net>
Mon, 26 Feb 2024 23:57:51 +0000 (00:57 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 26 Feb 2024 23:57:51 +0000 (00:57 +0100)
src/wx/timeline.cc
src/wx/timeline.h

index 4683769d403f423316e95ad0d841cb8b131b3466..f67bf52dc4ffaf971129a0195a4a27af48843288 100644 (file)
@@ -109,6 +109,7 @@ Timeline::Timeline(wxWindow* parent, ContentPanel* cp, shared_ptr<Film> film, Fi
        _main_canvas->Bind   (wxEVT_RIGHT_DOWN, boost::bind (&Timeline::right_down,   this, _1));
        _main_canvas->Bind   (wxEVT_MOTION,     boost::bind (&Timeline::mouse_moved,  this, _1));
        _main_canvas->Bind   (wxEVT_SIZE,       boost::bind (&Timeline::resized,      this));
+       _main_canvas->Bind   (wxEVT_MOUSEWHEEL, boost::bind(&Timeline::mouse_wheel_turned, this, _1));
        _main_canvas->Bind   (wxEVT_SCROLLWIN_TOP,        boost::bind (&Timeline::scrolled,     this, _1));
        _main_canvas->Bind   (wxEVT_SCROLLWIN_BOTTOM,     boost::bind (&Timeline::scrolled,     this, _1));
        _main_canvas->Bind   (wxEVT_SCROLLWIN_LINEUP,     boost::bind (&Timeline::scrolled,     this, _1));
@@ -132,6 +133,43 @@ Timeline::Timeline(wxWindow* parent, ContentPanel* cp, shared_ptr<Film> film, Fi
 }
 
 
+void
+Timeline::mouse_wheel_turned(wxMouseEvent& event)
+{
+       if (event.ControlDown()) {
+               auto const rotation = event.GetWheelRotation();
+               /* On my mouse one click of the scroll wheel is 120, and it's -ve when
+                * scrolling the wheel towards me.
+                */
+               auto const scale = rotation > 0 ?
+                       (1.0 / (rotation / 90.0)) :
+                       (-rotation / 90.0);
+
+               int before_start_x;
+               int before_start_y;
+               _main_canvas->GetViewStart(&before_start_x, &before_start_y);
+
+               auto const before_pps = _pixels_per_second.get_value_or(1);
+               auto const before_pos = _last_mouse_wheel_x && *_last_mouse_wheel_x == event.GetX() ?
+                       *_last_mouse_wheel_time :
+                       (before_start_x * _x_scroll_rate + event.GetX()) / before_pps;
+
+               set_pixels_per_second(before_pps * scale);
+               setup_scrollbars();
+
+               auto after_left = std::max(0.0, before_pos * _pixels_per_second.get_value_or(1) - event.GetX());
+               _main_canvas->Scroll(after_left / _x_scroll_rate, before_start_y);
+               _labels_canvas->Scroll(0, before_start_y);
+               Refresh();
+
+               if (!_last_mouse_wheel_x || *_last_mouse_wheel_x != event.GetX()) {
+                       _last_mouse_wheel_x = event.GetX();
+                       _last_mouse_wheel_time = before_pos;
+               }
+       }
+}
+
+
 void
 Timeline::update_playhead ()
 {
index 2485e835fa8e4faa235d605d53371d5a09d8d5e7..621609fa7e66b94a2ae1f8cd73f2d548ce609368 100644 (file)
@@ -110,6 +110,7 @@ private:
        void set_pixels_per_track (int h);
        void zoom_all ();
        void update_playhead ();
+       void mouse_wheel_turned(wxMouseEvent& event);
 
        std::shared_ptr<TimelineView> event_to_view (wxMouseEvent &);
        TimelineContentViewList selected_views () const;
@@ -143,6 +144,8 @@ private:
        int _pixels_per_track;
        bool _first_resize;
        wxTimer _timer;
+       boost::optional<int> _last_mouse_wheel_x;
+       boost::optional<double> _last_mouse_wheel_time;
 
        static double const _minimum_pixels_per_second;
        static int const _minimum_pixels_per_track;