Emit no audio from DCPs if none is mapped
[dcpomatic.git] / src / wx / timeline.cc
index d8e0e692e6f9fed0e283b253ec9f83641171d7c5..38e9de4ee46318ca73bfff98a29023c64bac5047 100644 (file)
 #include "lib/film.h"
 #include "lib/image_content.h"
 #include "lib/playlist.h"
-#include "lib/scope_guard.h"
 #include "lib/text_content.h"
 #include "lib/timer.h"
 #include "lib/video_content.h"
+#include <dcp/scope_guard.h>
 #include <dcp/warnings.h>
 LIBDCP_DISABLE_WARNINGS
 #include <wx/graphics.h>
@@ -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));
@@ -117,7 +118,7 @@ Timeline::Timeline(wxWindow* parent, ContentPanel* cp, shared_ptr<Film> film, Fi
        _main_canvas->Bind   (wxEVT_SCROLLWIN_PAGEDOWN,   boost::bind (&Timeline::scrolled,     this, _1));
        _main_canvas->Bind   (wxEVT_SCROLLWIN_THUMBTRACK, boost::bind (&Timeline::scrolled,     this, _1));
 
-       film_change (ChangeType::DONE, Film::Property::CONTENT);
+       film_change(ChangeType::DONE, FilmProperty::CONTENT);
 
        SetMinSize (wxSize (640, 4 * pixels_per_track() + 96));
 
@@ -132,6 +133,50 @@ Timeline::Timeline(wxWindow* parent, ContentPanel* cp, shared_ptr<Film> film, Fi
 }
 
 
+void
+Timeline::mouse_wheel_turned(wxMouseEvent& event)
+{
+       auto const rotation = event.GetWheelRotation();
+
+       if (event.ControlDown()) {
+               /* 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;
+               }
+       } else if (event.ShiftDown()) {
+               int before_start_x;
+               int before_start_y;
+               _main_canvas->GetViewStart(&before_start_x, &before_start_y);
+               auto const width = _main_canvas->GetSize().GetWidth();
+               _main_canvas->Scroll(std::max(0.0, before_start_x - rotation * 100.0 / width), before_start_y);
+       }
+}
+
+
 void
 Timeline::update_playhead ()
 {
@@ -161,7 +206,7 @@ Timeline::paint_labels ()
                return;
        }
 
-       ScopeGuard sg = [gc]() { delete gc; };
+       dcp::ScopeGuard sg = [gc]() { delete gc; };
 
        int vsx, vsy;
        _labels_canvas->GetViewStart (&vsx, &vsy);
@@ -175,6 +220,7 @@ void
 Timeline::paint_main ()
 {
        wxPaintDC dc (_main_canvas);
+       dc.Clear();
 
        auto film = _film.lock();
        if (film->content().empty()) {
@@ -188,7 +234,7 @@ Timeline::paint_main ()
                return;
        }
 
-       ScopeGuard sg = [gc]() { delete gc; };
+       dcp::ScopeGuard sg = [gc]() { delete gc; };
 
        gc->SetAntialiasMode (wxANTIALIAS_DEFAULT);
 
@@ -237,16 +283,16 @@ Timeline::paint_main ()
 
 
 void
-Timeline::film_change (ChangeType type, Film::Property p)
+Timeline::film_change(ChangeType type, FilmProperty p)
 {
        if (type != ChangeType::DONE) {
                return;
        }
 
-       if (p == Film::Property::CONTENT || p == Film::Property::REEL_TYPE || p == Film::Property::REEL_LENGTH) {
+       if (p == FilmProperty::CONTENT || p == FilmProperty::REEL_TYPE || p == FilmProperty::REEL_LENGTH) {
                ensure_ui_thread ();
                recreate_views ();
-       } else if (p == Film::Property::CONTENT_ORDER) {
+       } else if (p == FilmProperty::CONTENT_ORDER) {
                Refresh ();
        }
 }
@@ -320,6 +366,7 @@ place (shared_ptr<const Film> film, TimelineViewList& views, int& tracks)
                }
 
                auto cv = dynamic_pointer_cast<TimelineContentView> (i);
+               DCPOMATIC_ASSERT(cv);
 
                int t = base;
 
@@ -702,6 +749,7 @@ Timeline::mouse_moved_zoom (wxMouseEvent& ev)
        }
 
        _zoom_point = ev.GetPosition ();
+       setup_scrollbars();
        Refresh ();
 }
 
@@ -949,8 +997,8 @@ Timeline::zoom_all ()
 {
        auto film = _film.lock ();
        DCPOMATIC_ASSERT (film);
-       set_pixels_per_second ((_main_canvas->GetSize().GetWidth() - 32) / film->length().seconds());
-       set_pixels_per_track ((_main_canvas->GetSize().GetHeight() - tracks_y_offset() - _time_axis_view->bbox().height - 32) / _tracks);
+       set_pixels_per_second((_main_canvas->GetSize().GetWidth() - 32) / std::max(1.0, film->length().seconds()));
+       set_pixels_per_track((_main_canvas->GetSize().GetHeight() - tracks_y_offset() - _time_axis_view->bbox().height - 32) / std::max(1, _tracks));
        setup_scrollbars ();
        _main_canvas->Scroll (0, 0);
        _labels_canvas->Scroll (0, 0);
@@ -969,9 +1017,11 @@ Timeline::keypress(wxKeyEvent const& event)
                switch (event.GetRawKeyCode()) {
                case '+':
                        set_pixels_per_second(_pixels_per_second.get_value_or(1) * 2);
+                       setup_scrollbars();
                        break;
                case '-':
                        set_pixels_per_second(_pixels_per_second.get_value_or(1) / 2);
+                       setup_scrollbars();
                        break;
                }
        }