Display only required tabs, including subs / ccap.
authorCarl Hetherington <cth@carlh.net>
Sat, 21 Jul 2018 23:41:03 +0000 (00:41 +0100)
committerCarl Hetherington <cth@carlh.net>
Sat, 21 Jul 2018 23:41:03 +0000 (00:41 +0100)
16 files changed:
src/lib/caption_content.cc
src/lib/caption_content.h
src/lib/dcp_content.cc
src/lib/dcp_examiner.cc
src/lib/dcp_examiner.h
src/lib/dcp_subtitle_content.cc
src/lib/ffmpeg_content.cc
src/lib/text_caption_file_content.cc
src/lib/types.cc
src/lib/types.h
src/wx/caption_panel.cc
src/wx/caption_panel.h
src/wx/content_panel.cc
src/wx/content_panel.h
src/wx/content_sub_panel.cc
src/wx/content_sub_panel.h

index 4fa8b678f3337b61452666185780e5b432df15fc..37a3e7c70f7b8b22058e896d70d08a39e7349779 100644 (file)
@@ -57,7 +57,7 @@ int const CaptionContentProperty::FADE_OUT = 513;
 int const CaptionContentProperty::OUTLINE_WIDTH = 514;
 int const CaptionContentProperty::TYPE = 515;
 
-CaptionContent::CaptionContent (Content* parent)
+CaptionContent::CaptionContent (Content* parent, CaptionType original_type)
        : ContentPart (parent)
        , _use (false)
        , _burn (false)
@@ -68,7 +68,7 @@ CaptionContent::CaptionContent (Content* parent)
        , _line_spacing (1)
        , _outline_width (2)
        , _type (CAPTION_OPEN)
-       , _original_type (CAPTION_OPEN)
+       , _original_type (original_type)
 {
 
 }
index 767fc7234446728ab6ff4a66c9693eea711584d4..4f5780d23f6c444ec6d1feee20b7312ea9083cf4 100644 (file)
@@ -58,7 +58,7 @@ public:
 class CaptionContent : public ContentPart
 {
 public:
-       explicit CaptionContent (Content* parent);
+       CaptionContent (Content* parent, CaptionType original_type);
        CaptionContent (Content* parent, std::vector<boost::shared_ptr<Content> >);
 
        void as_xml (xmlpp::Node *) const;
index e56ad9e21f7e7ccaa086ed646a962a38548e475f..414a2225605ea599b2e11072c20b409c23680666 100644 (file)
@@ -191,8 +191,10 @@ DCPContent::examine (shared_ptr<Job> job)
        {
                boost::mutex::scoped_lock lm (_mutex);
                _name = examiner->name ();
-               for (int i = 0; i < examiner->captions(); ++i) {
-                       caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this)));
+               for (int i = 0; i < CAPTION_COUNT; ++i) {
+                       if (examiner->has_caption(static_cast<CaptionType>(i))) {
+                               caption.push_back (shared_ptr<CaptionContent>(new CaptionContent(this, static_cast<CaptionType>(i))));
+                       }
                }
                captions = caption.size ();
                _encrypted = examiner->encrypted ();
index 8ce4aee001df26f64ca57cb2cb5d2d76c3e17172..6b4f854f8d66d456b6da1c6974bb644c1b2cf846 100644 (file)
@@ -58,7 +58,6 @@ DCPExaminer::DCPExaminer (shared_ptr<const DCPContent> content)
        , _audio_length (0)
        , _has_video (false)
        , _has_audio (false)
-       , _captions (0)
        , _encrypted (false)
        , _needs_assets (false)
        , _kdm_valid (false)
@@ -66,6 +65,10 @@ DCPExaminer::DCPExaminer (shared_ptr<const DCPContent> content)
 {
        shared_ptr<dcp::CPL> cpl;
 
+       for (int i = 0; i < CAPTION_COUNT; ++i) {
+               _has_caption[i] = false;
+       }
+
        if (content->cpl ()) {
                /* Use the CPL that the content was using before */
                BOOST_FOREACH (shared_ptr<dcp::CPL> i, cpls()) {
@@ -166,7 +169,7 @@ DCPExaminer::DCPExaminer (shared_ptr<const DCPContent> content)
                                return;
                        }
 
-                       ++_captions;
+                       _has_caption[CAPTION_OPEN] = true;
                }
 
                if (i->closed_caption ()) {
@@ -176,7 +179,7 @@ DCPExaminer::DCPExaminer (shared_ptr<const DCPContent> content)
                                return;
                        }
 
-                       ++_captions;
+                       _has_caption[CAPTION_CLOSED] = true;
                }
 
                if (i->main_picture()) {
index 0d55d4643e69f80060e7305f34208b47089300ba..16385e07a66662149e27e39653938f32136cab97 100644 (file)
@@ -59,10 +59,6 @@ public:
                return _name;
        }
 
-       int captions () const {
-               return _captions;
-       }
-
        bool encrypted () const {
                return _encrypted;
        }
@@ -87,6 +83,10 @@ public:
                return _audio_frame_rate.get_value_or (48000);
        }
 
+       bool has_caption (CaptionType type) const {
+               return _has_caption[type];
+       }
+
        bool kdm_valid () const {
                return _kdm_valid;
        }
@@ -119,7 +119,7 @@ private:
        bool _has_video;
        /** true if this DCP has audio content (but false if it has unresolved references to audio content) */
        bool _has_audio;
-       int _captions;
+       bool _has_caption[CAPTION_COUNT];
        bool _encrypted;
        bool _needs_assets;
        bool _kdm_valid;
index 78e81328a22e130edf05f78c097c210e2a9c2433..779361f630c7b4a2d88a9075e8338d8ea1662cd3 100644 (file)
@@ -40,7 +40,7 @@ using dcp::raw_convert;
 DCPSubtitleContent::DCPSubtitleContent (shared_ptr<const Film> film, boost::filesystem::path path)
        : Content (film, path)
 {
-       caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this)));
+       caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this, CAPTION_OPEN)));
 }
 
 DCPSubtitleContent::DCPSubtitleContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version)
index 4300dc97071e4d4277ba09561bc9f8d74d1ade4d..3f0a692cdd646f7e08444920ebc7e03eaea114d6 100644 (file)
@@ -304,7 +304,7 @@ FFmpegContent::examine (shared_ptr<Job> job)
                _subtitle_streams = examiner->subtitle_streams ();
                if (!_subtitle_streams.empty ()) {
                        caption.clear ();
-                       caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this)));
+                       caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this, CAPTION_OPEN)));
                        _subtitle_stream = _subtitle_streams.front ();
                }
 
index c8eb2390a096e79498b5443da2ce13796f26221b..aa64ca5724e227a9ea5aeba9779a52ffe4c9dca7 100644 (file)
@@ -38,7 +38,7 @@ using dcp::raw_convert;
 TextCaptionFileContent::TextCaptionFileContent (shared_ptr<const Film> film, boost::filesystem::path path)
        : Content (film, path)
 {
-       caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this)));
+       caption.push_back (shared_ptr<CaptionContent> (new CaptionContent (this, CAPTION_OPEN)));
 }
 
 TextCaptionFileContent::TextCaptionFileContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version)
index 97373b24ee52a481f803f35e44e28863b3f46258..5474b609adfc2fdd2f43e18ad9d471465155eac4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -25,6 +25,8 @@
 #include <libxml++/libxml++.h>
 #include <libcxml/cxml.h>
 
+#include "i18n.h"
+
 using std::max;
 using std::min;
 using std::string;
@@ -116,6 +118,19 @@ caption_type_to_string (CaptionType t)
        }
 }
 
+string
+caption_type_to_name (CaptionType t)
+{
+       switch (t) {
+       case CAPTION_OPEN:
+               return _("Subtitles");
+       case CAPTION_CLOSED:
+               return _("Closed captions");
+       default:
+               DCPOMATIC_ASSERT (false);
+       }
+}
+
 string
 video_frame_type_to_string (VideoFrameType t)
 {
index b2bff78fa67f23a6e4c70e05ffe6315cacb02321..6a05f66c93c190b2d7c4e75fa2eebf411bfee385 100644 (file)
@@ -147,6 +147,7 @@ enum CaptionType
 };
 
 extern std::string caption_type_to_string (CaptionType t);
+extern std::string caption_type_to_name (CaptionType t);
 extern CaptionType string_to_caption_type (std::string s);
 
 /** @struct Crop
index 5a3ac39eda2ec3884391f3c10e63eacc76eb09fe..3957c2a457b3b9937e8ca8c945edbefd37ee7107 100644 (file)
@@ -43,11 +43,11 @@ using std::list;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 
-CaptionPanel::CaptionPanel (ContentPanel* p)
-       : ContentSubPanel (p, _("Captions"))
+CaptionPanel::CaptionPanel (ContentPanel* p, CaptionType t)
+       : ContentSubPanel (p, std_to_wx(caption_type_to_name(t)))
        , _caption_view (0)
        , _fonts_dialog (0)
-       , _original_type (CAPTION_OPEN)
+       , _original_type (t)
 {
        wxBoxSizer* reference_sizer = new wxBoxSizer (wxVERTICAL);
 
@@ -202,6 +202,11 @@ CaptionPanel::film_content_changed (int property)
                scs = sc.front ();
        }
 
+       shared_ptr<CaptionContent> caption;
+       if (scs) {
+               caption = scs->caption_of_original_type(_original_type);
+       }
+
        if (property == FFmpegContentProperty::SUBTITLE_STREAMS) {
                _stream->Clear ();
                if (fcs) {
@@ -218,11 +223,11 @@ CaptionPanel::film_content_changed (int property)
                }
                setup_sensitivity ();
        } else if (property == CaptionContentProperty::USE) {
-               checked_set (_use, scs ? scs->caption_of_original_type(_original_type)->use() : false);
+               checked_set (_use, caption ? caption->use() : false);
                setup_sensitivity ();
        } else if (property == CaptionContentProperty::TYPE) {
-               if (scs) {
-                       switch (scs->caption_of_original_type(_original_type)->type()) {
+               if (caption) {
+                       switch (caption->type()) {
                        case CAPTION_OPEN:
                                _type->SetSelection (0);
                                break;
@@ -237,19 +242,19 @@ CaptionPanel::film_content_changed (int property)
                }
                setup_sensitivity ();
        } else if (property == CaptionContentProperty::BURN) {
-               checked_set (_burn, scs ? scs->caption_of_original_type(_original_type)->burn() : false);
+               checked_set (_burn, caption ? caption->burn() : false);
        } else if (property == CaptionContentProperty::X_OFFSET) {
-               checked_set (_x_offset, scs ? lrint (scs->caption_of_original_type(_original_type)->x_offset() * 100) : 0);
+               checked_set (_x_offset, caption ? lrint (caption->x_offset() * 100) : 0);
        } else if (property == CaptionContentProperty::Y_OFFSET) {
-               checked_set (_y_offset, scs ? lrint (scs->caption_of_original_type(_original_type)->y_offset() * 100) : 0);
+               checked_set (_y_offset, caption ? lrint (caption->y_offset() * 100) : 0);
        } else if (property == CaptionContentProperty::X_SCALE) {
-               checked_set (_x_scale, scs ? lrint (scs->caption_of_original_type(_original_type)->x_scale() * 100) : 100);
+               checked_set (_x_scale, caption ? lrint (caption->x_scale() * 100) : 100);
        } else if (property == CaptionContentProperty::Y_SCALE) {
-               checked_set (_y_scale, scs ? lrint (scs->caption_of_original_type(_original_type)->y_scale() * 100) : 100);
+               checked_set (_y_scale, caption ? lrint (caption->y_scale() * 100) : 100);
        } else if (property == CaptionContentProperty::LINE_SPACING) {
-               checked_set (_line_spacing, scs ? lrint (scs->caption_of_original_type(_original_type)->line_spacing() * 100) : 100);
+               checked_set (_line_spacing, caption ? lrint (caption->line_spacing() * 100) : 100);
        } else if (property == CaptionContentProperty::LANGUAGE) {
-               checked_set (_language, scs ? scs->caption_of_original_type(_original_type)->language() : "");
+               checked_set (_language, caption ? caption->language() : "");
        } else if (property == DCPContentProperty::REFERENCE_CAPTION) {
                if (scs) {
                        shared_ptr<DCPContent> dcp = dynamic_pointer_cast<DCPContent> (scs);
index 8adb85e15ecaa010dcbfafe84eca6ab48e2fc369..20af29d7e3b29c1d77f4761fa5f7320cbde33dd8 100644 (file)
@@ -28,7 +28,7 @@ class FontsDialog;
 class CaptionPanel : public ContentSubPanel
 {
 public:
-       explicit CaptionPanel (ContentPanel *);
+       CaptionPanel (ContentPanel *, CaptionType t);
 
        void film_changed (Film::Property);
        void film_content_changed (int);
index 40501f7178a1c8cf249d16b63a59f843282990f8..ce9c66a3ed437bb9fc07b0b55019861e52f9280e 100644 (file)
@@ -52,6 +52,7 @@ using std::list;
 using std::string;
 using std::cout;
 using std::vector;
+using std::max;
 using std::exception;
 using boost::shared_ptr;
 using boost::weak_ptr;
@@ -63,6 +64,7 @@ using boost::optional;
 ContentPanel::ContentPanel (wxNotebook* n, boost::shared_ptr<Film> film, FilmViewer* viewer)
        : _timeline_dialog (0)
        , _parent (n)
+       , _last_selected_tab (0)
        , _film (film)
        , _film_viewer (viewer)
        , _generally_sensitive (true)
@@ -125,8 +127,10 @@ ContentPanel::ContentPanel (wxNotebook* n, boost::shared_ptr<Film> film, FilmVie
        _panels.push_back (_video_panel);
        _audio_panel = new AudioPanel (this);
        _panels.push_back (_audio_panel);
-       _caption_panel = new CaptionPanel (this);
-       _panels.push_back (_caption_panel);
+       for (int i = 0; i < CAPTION_COUNT; ++i) {
+               _caption_panel[i] = new CaptionPanel (this, static_cast<CaptionType>(i));
+               _panels.push_back (_caption_panel[i]);
+       }
        _timing_panel = new TimingPanel (this, _film_viewer);
        _panels.push_back (_timing_panel);
 
@@ -255,7 +259,7 @@ ContentPanel::selection_changed ()
        }
 
        optional<DCPTime> go_to;
-       BOOST_FOREACH (shared_ptr<Content> i, selected ()) {
+       BOOST_FOREACH (shared_ptr<Content> i, selected()) {
                DCPTime p;
                p = i->position();
                if (dynamic_pointer_cast<TextCaptionFileContent>(i) && i->paths_valid()) {
@@ -277,7 +281,106 @@ ContentPanel::selection_changed ()
        }
 
        if (_timeline_dialog) {
-               _timeline_dialog->set_selection (selected ());
+               _timeline_dialog->set_selection (selected());
+       }
+
+       /* Make required tabs visible */
+
+       if (_notebook->GetPageCount() > 1) {
+               /* There's more than one tab in the notebook so the current selection could be meaningful
+                  to the user; store it so that we can try to restore it later.
+               */
+               _last_selected_tab = 0;
+               if (_notebook->GetSelection() != wxNOT_FOUND) {
+                       _last_selected_tab = _notebook->GetPage(_notebook->GetSelection());
+               }
+       }
+
+       bool have_video = false;
+       bool have_audio = false;
+       bool have_caption[CAPTION_COUNT] = { false, false };
+       BOOST_FOREACH (shared_ptr<Content> i, selected()) {
+               if (i->video) {
+                       have_video = true;
+               }
+               if (i->audio) {
+                       have_audio = true;
+               }
+               BOOST_FOREACH (shared_ptr<CaptionContent> j, i->caption) {
+                       have_caption[j->original_type()] = true;
+               }
+       }
+
+       bool video_panel = false;
+       bool audio_panel = false;
+       bool caption_panel[CAPTION_COUNT] = { false, false };
+       for (size_t i = 0; i < _notebook->GetPageCount(); ++i) {
+               if (_notebook->GetPage(i) == _video_panel) {
+                       video_panel = true;
+               } else if (_notebook->GetPage(i) == _audio_panel) {
+                       audio_panel = true;
+               }
+               for (int j = 0; j < CAPTION_COUNT; ++j) {
+                       if (_notebook->GetPage(i) == _caption_panel[j]) {
+                               caption_panel[j] = true;
+                       }
+               }
+       }
+
+       int off = 0;
+
+       if (have_video != video_panel) {
+               if (video_panel) {
+                       _notebook->RemovePage (off);
+               }
+               if (have_video) {
+                       _notebook->InsertPage (off, _video_panel, _video_panel->name());
+               }
+       }
+
+       if (have_video) {
+               ++off;
+       }
+
+       if (have_audio != audio_panel) {
+               if (audio_panel) {
+                       _notebook->RemovePage (off);
+               }
+               if (have_audio) {
+                       _notebook->InsertPage (off, _audio_panel, _audio_panel->name());
+               }
+       }
+
+       if (have_audio) {
+               ++off;
+       }
+
+       for (int i = 0; i < CAPTION_COUNT; ++i) {
+               if (have_caption[i] != caption_panel[i]) {
+                       if (caption_panel[i]) {
+                               _notebook->RemovePage (off);
+                       }
+                       if (have_caption[i]) {
+                               _notebook->InsertPage (off, _caption_panel[i], _caption_panel[i]->name());
+                       }
+               }
+               if (have_caption[i]) {
+                       ++off;
+               }
+       }
+
+       /* Set up the tab selection */
+
+       bool done = false;
+       for (size_t i = 0; i < _notebook->GetPageCount(); ++i) {
+               if (_notebook->GetPage(i) == _last_selected_tab) {
+                       _notebook->SetSelection (i);
+                       done = true;
+               }
+       }
+
+       if (!done) {
+               _notebook->SetSelection (0);
        }
 
        SelectionChanged ();
@@ -447,7 +550,9 @@ ContentPanel::setup_sensitivity ()
 
        _video_panel->Enable    (_generally_sensitive && video_selection.size() > 0);
        _audio_panel->Enable    (_generally_sensitive && audio_selection.size() > 0);
-       _caption_panel->Enable  (_generally_sensitive && selection.size() == 1 && !selection.front()->caption.empty());
+       for (int i = 0; i < CAPTION_COUNT; ++i) {
+               _caption_panel[i]->Enable  (_generally_sensitive && selection.size() == 1 && !selection.front()->caption.empty());
+       }
        _timing_panel->Enable   (_generally_sensitive);
 }
 
index e7d9c95b39b110c8d79a48428f4f6f1584f86727..3f0fb17a5312b9d3a1689905e8ffcdb97f8f44a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -32,6 +32,7 @@ class wxListEvent;
 class TimelineDialog;
 class FilmEditor;
 class ContentSubPanel;
+class CaptionPanel;
 class AudioPanel;
 class Film;
 class FilmViewer;
@@ -104,13 +105,14 @@ private:
        wxButton* _timeline;
        ContentSubPanel* _video_panel;
        AudioPanel* _audio_panel;
-       ContentSubPanel* _caption_panel;
+       CaptionPanel* _caption_panel[CAPTION_COUNT];
        ContentSubPanel* _timing_panel;
        std::list<ContentSubPanel *> _panels;
        ContentMenu* _menu;
        TimelineDialog* _timeline_dialog;
        wxNotebook* _parent;
        ContentList _last_selected;
+       wxWindow* _last_selected_tab;
 
        boost::shared_ptr<Film> _film;
        FilmViewer* _film_viewer;
index 93296d5b97999c67b8e4e49bfb99feb06fb3b19c..a60a657073ae2be6d65c2b61a07d330acc1780db 100644 (file)
@@ -35,8 +35,9 @@ ContentSubPanel::ContentSubPanel (ContentPanel* p, wxString name)
        : wxScrolledWindow (p->notebook(), wxID_ANY)
        , _parent (p)
        , _sizer (new wxBoxSizer (wxVERTICAL))
+       , _name (name)
 {
-       p->notebook()->AddPage (this, name, false);
+       p->notebook()->AddPage (this, _name, false);
        SetScrollRate (-1, 8);
        SetSizer (_sizer);
 }
index 9afd50d4027dd53111de1028dbcde4deded5b8e0..8c7854af29d77dcf31a36ae86eb3ff6e88615852 100644 (file)
@@ -40,12 +40,17 @@ public:
        /** Called when the list of selected Contents changes */
        virtual void content_selection_changed () = 0;
 
+       wxString name () const {
+               return _name;
+       }
+
 protected:
 
        void setup_refer_button (wxCheckBox* button, wxStaticText* note, boost::shared_ptr<DCPContent> dcp, bool can_reference, std::string why_not) const;
 
        ContentPanel* _parent;
        wxSizer* _sizer;
+       wxString _name;
 };
 
 #endif