Show overlapping subs in multiple tracks on the timeline (#941).
authorCarl Hetherington <cth@carlh.net>
Mon, 8 May 2017 09:54:49 +0000 (10:54 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 8 May 2017 09:54:49 +0000 (10:54 +0100)
ChangeLog
src/wx/timeline.cc
src/wx/timeline_labels_view.cc
src/wx/timeline_labels_view.h

index 3b504500fc9ff770a13d991b51cbabdb9e49c930..f349abaa9f724b23ee05683ffb090c11d43c0dcb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2017-05-08  Carl Hetherington  <cth@carlh.net>
 
+       * Show multiple tracks in the timeline if there are overlapping subtitles (#941).
+
        * Various fixes to films with areas of no video content.
 
 2017-05-05  Carl Hetherington  <cth@carlh.net>
index 5cdd73b25d46712195306aea37f58a955fe778e7..04db5c628d4e6f148dbb6ab706ed21b857d35400 100644 (file)
@@ -184,19 +184,75 @@ Timeline::film_content_changed (int property, bool frequent)
        }
 }
 
+template <class T>
+int
+place (TimelineViewList& views, int& tracks)
+{
+       int const base = tracks;
+
+       BOOST_FOREACH (shared_ptr<TimelineView> i, views) {
+               if (!dynamic_pointer_cast<T>(i)) {
+                       continue;
+               }
+
+               shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (i);
+
+               int t = base;
+
+               shared_ptr<Content> content = cv->content();
+               DCPTimePeriod const content_period (content->position(), content->end());
+
+               while (true) {
+                       TimelineViewList::iterator j = views.begin();
+                       while (j != views.end()) {
+                               shared_ptr<T> test = dynamic_pointer_cast<T> (*j);
+                               if (!test) {
+                                       ++j;
+                                       continue;
+                               }
+
+                               shared_ptr<Content> test_content = test->content();
+                               if (
+                                       test->track() && test->track().get() == t &&
+                                       content_period.overlap(DCPTimePeriod(test_content->position(), test_content->end()))) {
+                                       /* we have an overlap on track `t' */
+                                       ++t;
+                                       break;
+                               }
+
+                               ++j;
+                       }
+
+                       if (j == views.end ()) {
+                               /* no overlap on `t' */
+                               break;
+                       }
+               }
+
+               cv->set_track (t);
+               tracks = max (tracks, t + 1);
+       }
+
+       return tracks - base;
+}
+
 void
 Timeline::assign_tracks ()
 {
        /* Tracks are:
           Video (mono or left-eye)
           Video (right-eye)
-          Subtitle
+          Subtitle 1
+          Subtitle 2
+          Subtitle N
           Atmos
           Audio 1
           Audio 2
           Audio N
        */
 
+       _tracks = 0;
+
        for (TimelineViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
                shared_ptr<TimelineContentView> c = dynamic_pointer_cast<TimelineContentView> (*i);
                if (c) {
@@ -204,93 +260,56 @@ Timeline::assign_tracks ()
                }
        }
 
-       /* See if we have any subtitle / atmos / right-eye views */
+       /* Video */
+
        bool have_3d = false;
-       bool have_subtitle = false;
-       bool have_atmos = false;
        BOOST_FOREACH (shared_ptr<TimelineView> i, _views) {
-               shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (i);
+               shared_ptr<TimelineVideoContentView> cv = dynamic_pointer_cast<TimelineVideoContentView> (i);
                if (!cv) {
                        continue;
                }
 
-               if (dynamic_pointer_cast<TimelineVideoContentView> (i)) {
-                       if (cv->content()->video->frame_type() == VIDEO_FRAME_TYPE_3D_RIGHT) {
-                               have_3d = true;
-                       }
-               } else if (dynamic_pointer_cast<TimelineSubtitleContentView> (i)) {
-                       have_subtitle = true;
-               } else if (dynamic_pointer_cast<TimelineAtmosContentView> (i)) {
-                       have_atmos = true;
+               /* Video on tracks 0 and maybe 1 (left and right eye) */
+               if (cv->content()->video->frame_type() == VIDEO_FRAME_TYPE_3D_RIGHT) {
+                       cv->set_track (1);
+                       _tracks = max (_tracks, 2);
+                       have_3d = true;
+               } else {
+                       cv->set_track (0);
                }
        }
 
-       _labels_view->set_3d (have_3d);
-       _labels_view->set_subtitle (have_subtitle);
-       _labels_view->set_atmos (have_atmos);
+       _tracks = max (_tracks, 1);
 
-       /* Hence decide where to start subtitle, atmos and audio tracks */
-       int const subtitle = have_3d ? 2 : 1;
-       int const atmos = have_subtitle ? subtitle + 1 : subtitle;
-       int const audio = have_atmos ? atmos + 1: atmos;
+       /* Subtitle */
 
-       for (TimelineViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
-               shared_ptr<TimelineContentView> cv = dynamic_pointer_cast<TimelineContentView> (*i);
+       int const subtitle_tracks = place<TimelineSubtitleContentView> (_views, _tracks);
+
+       /* Atmos */
+
+       bool have_atmos = false;
+       BOOST_FOREACH (shared_ptr<TimelineView> i, _views) {
+               shared_ptr<TimelineVideoContentView> cv = dynamic_pointer_cast<TimelineVideoContentView> (i);
                if (!cv) {
                        continue;
                }
-
-               if (dynamic_pointer_cast<TimelineVideoContentView> (*i)) {
-                       /* Video on tracks 0 and maybe 1 (left and right eye) */
-                       cv->set_track (cv->content()->video->frame_type() == VIDEO_FRAME_TYPE_3D_RIGHT ? 1 : 0);
-                       _tracks = max (_tracks, have_3d ? 2 : 1);
-                       continue;
-               } else if (dynamic_pointer_cast<TimelineSubtitleContentView> (*i)) {
-                       cv->set_track (subtitle);
-                       _tracks = max (_tracks, subtitle + 1);
-                       continue;
-               } else if (dynamic_pointer_cast<TimelineAtmosContentView> (*i)) {
-                       cv->set_track (atmos);
-                       _tracks = max (_tracks, atmos + 1);
-                       continue;
+               if (dynamic_pointer_cast<TimelineAtmosContentView> (i)) {
+                       cv->set_track (_tracks - 1);
+                       have_atmos = true;
                }
+       }
 
-               int t = audio;
-
-               shared_ptr<Content> content = cv->content();
-               DCPTimePeriod content_period (content->position(), content->end());
-
-               while (true) {
-                       TimelineViewList::iterator j = _views.begin();
-                       while (j != _views.end()) {
-                               shared_ptr<TimelineAudioContentView> test = dynamic_pointer_cast<TimelineAudioContentView> (*j);
-                               if (!test) {
-                                       ++j;
-                                       continue;
-                               }
-
-                               shared_ptr<Content> test_content = test->content();
+       if (have_atmos) {
+               ++_tracks;
+       }
 
-                               if (test && test->track() && test->track().get() == t) {
-                                       if (content_period.overlap (DCPTimePeriod(test_content->position(), test_content->end()))) {
-                                               /* we have an overlap on track `t' */
-                                               ++t;
-                                               break;
-                                       }
-                               }
+       /* Audio */
 
-                               ++j;
-                       }
+       place<TimelineAudioContentView> (_views, _tracks);
 
-                       if (j == _views.end ()) {
-                               /* no overlap on `t' */
-                               break;
-                       }
-               }
-
-               cv->set_track (t);
-               _tracks = max (_tracks, t + 1);
-       }
+       _labels_view->set_3d (have_3d);
+       _labels_view->set_subtitle_tracks (subtitle_tracks);
+       _labels_view->set_atmos (have_atmos);
 
        _time_axis_view->set_y (tracks() * track_height() + 64);
        _reels_view->set_y (8);
index 1a712f42d71538e302f0a67fc06738003cbf5627..ee1b1948996e3120571873f397cc9b6bdae0e0bc 100644 (file)
@@ -31,7 +31,7 @@ using std::max;
 TimelineLabelsView::TimelineLabelsView (Timeline& tl)
        : TimelineView (tl)
        , _threed (true)
-       , _subtitle (true)
+       , _subtitle_tracks (0)
        , _atmos (true)
 {
        wxString labels[] = {
@@ -69,8 +69,8 @@ TimelineLabelsView::do_paint (wxGraphicsContext* gc, list<dcpomatic::Rect<int> >
        gc->DrawText (_("Video"), 0, _timeline.tracks_position().y + (ty + fy) / 2 - 8);
        fy = ty;
 
-       if (_subtitle) {
-               ty = fy + h;
+       if (_subtitle_tracks) {
+               ty = fy + _subtitle_tracks * h;
                gc->DrawText (_("Subtitles"), 0, _timeline.tracks_position().y + (ty + fy) / 2 - 8);
                fy = ty;
        }
@@ -92,9 +92,9 @@ TimelineLabelsView::set_3d (bool s)
 }
 
 void
-TimelineLabelsView::set_subtitle (bool s)
+TimelineLabelsView::set_subtitle_tracks (int n)
 {
-       _subtitle = s;
+       _subtitle_tracks = n;
 }
 
 void
index 3b71533440f383f3fb71b782ea4648ff2da74e38..87b3cc90284a734f923a660f785a8878a67f7867 100644 (file)
@@ -30,7 +30,7 @@ public:
        dcpomatic::Rect<int> bbox () const;
 
        void set_3d (bool s);
-       void set_subtitle (bool s);
+       void set_subtitle_tracks (int n);
        void set_atmos (bool s);
 
 private:
@@ -38,6 +38,6 @@ private:
 
        int _width;
        bool _threed;
-       bool _subtitle;
+       int _subtitle_tracks;
        bool _atmos;
 };