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)
, _line_spacing (1)
, _outline_width (2)
, _type (CAPTION_OPEN)
- , _original_type (CAPTION_OPEN)
+ , _original_type (original_type)
{
}
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;
{
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 ();
, _audio_length (0)
, _has_video (false)
, _has_audio (false)
- , _captions (0)
, _encrypted (false)
, _needs_assets (false)
, _kdm_valid (false)
{
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()) {
return;
}
- ++_captions;
+ _has_caption[CAPTION_OPEN] = true;
}
if (i->closed_caption ()) {
return;
}
- ++_captions;
+ _has_caption[CAPTION_CLOSED] = true;
}
if (i->main_picture()) {
return _name;
}
- int captions () const {
- return _captions;
- }
-
bool encrypted () const {
return _encrypted;
}
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;
}
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;
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)
_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 ();
}
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)
/*
- 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.
#include <libxml++/libxml++.h>
#include <libcxml/cxml.h>
+#include "i18n.h"
+
using std::max;
using std::min;
using std::string;
}
}
+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)
{
};
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
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);
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) {
}
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;
}
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);
class CaptionPanel : public ContentSubPanel
{
public:
- explicit CaptionPanel (ContentPanel *);
+ CaptionPanel (ContentPanel *, CaptionType t);
void film_changed (Film::Property);
void film_content_changed (int);
using std::string;
using std::cout;
using std::vector;
+using std::max;
using std::exception;
using boost::shared_ptr;
using boost::weak_ptr;
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)
_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);
}
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()) {
}
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 ();
_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);
}
/*
- 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.
class TimelineDialog;
class FilmEditor;
class ContentSubPanel;
+class CaptionPanel;
class AudioPanel;
class Film;
class FilmViewer;
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;
: 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);
}
/** 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