summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/types.h8
-rw-r--r--src/lib/video_content.h20
-rw-r--r--src/wx/audio_panel.cc207
-rw-r--r--src/wx/audio_panel.h10
-rw-r--r--src/wx/content_widget.h211
-rw-r--r--src/wx/film_editor.cc166
-rw-r--r--src/wx/film_editor.h11
-rw-r--r--src/wx/film_editor_panel.h5
-rw-r--r--src/wx/subtitle_panel.cc65
-rw-r--r--src/wx/subtitle_panel.h4
-rw-r--r--src/wx/timing_panel.cc50
-rw-r--r--src/wx/timing_panel.h3
-rw-r--r--src/wx/video_panel.cc239
-rw-r--r--src/wx/video_panel.h19
14 files changed, 632 insertions, 386 deletions
diff --git a/src/lib/types.h b/src/lib/types.h
index d4d66387d..448b6c154 100644
--- a/src/lib/types.h
+++ b/src/lib/types.h
@@ -26,6 +26,10 @@
#include <libdcp/util.h>
class Content;
+class VideoContent;
+class AudioContent;
+class SubtitleContent;
+class FFmpegContent;
class AudioBuffers;
/** The version number of the protocol used to communicate
@@ -40,6 +44,10 @@ typedef int64_t Time;
typedef int64_t OutputAudioFrame;
typedef int OutputVideoFrame;
typedef std::vector<boost::shared_ptr<Content> > ContentList;
+typedef std::vector<boost::shared_ptr<VideoContent> > VideoContentList;
+typedef std::vector<boost::shared_ptr<AudioContent> > AudioContentList;
+typedef std::vector<boost::shared_ptr<SubtitleContent> > SubtitleContentList;
+typedef std::vector<boost::shared_ptr<FFmpegContent> > FFmpegContentList;
template<class T>
struct TimedAudioBuffers
diff --git a/src/lib/video_content.h b/src/lib/video_content.h
index 6f80536fe..106adf959 100644
--- a/src/lib/video_content.h
+++ b/src/lib/video_content.h
@@ -85,6 +85,26 @@ public:
return _crop;
}
+ int left_crop () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _crop.left;
+ }
+
+ int right_crop () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _crop.right;
+ }
+
+ int top_crop () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _crop.top;
+ }
+
+ int bottom_crop () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _crop.bottom;
+ }
+
void set_ratio (Ratio const *);
/** @return ratio to scale to, or 0 if the content's own ratio should be preserved. */
diff --git a/src/wx/audio_panel.cc b/src/wx/audio_panel.cc
index f96eeec2b..56fcf5c32 100644
--- a/src/wx/audio_panel.cc
+++ b/src/wx/audio_panel.cc
@@ -40,58 +40,61 @@ AudioPanel::AudioPanel (FilmEditor* e)
: FilmEditorPanel (e, _("Audio"))
, _audio_dialog (0)
{
- wxFlexGridSizer* grid = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+ wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
_sizer->Add (grid, 0, wxALL, 8);
+ int r = 0;
+
_show = new wxButton (this, wxID_ANY, _("Show Audio..."));
- grid->Add (_show, 1);
- grid->AddSpacer (0);
- grid->AddSpacer (0);
-
- add_label_to_sizer (grid, this, _("Audio Gain"), true);
- {
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _gain = new wxSpinCtrl (this);
- s->Add (_gain, 1);
- add_label_to_sizer (s, this, _("dB"), false);
- grid->Add (s, 1);
- }
+ grid->Add (_show, wxGBPosition (r, 0));
+ ++r;
+
+ add_label_to_grid_bag_sizer (grid, this, _("Audio Gain"), true, wxGBPosition (r, 0));
+ _gain = new ContentSpinCtrl<AudioContent> (
+ this,
+ new wxSpinCtrl (this),
+ AudioContentProperty::AUDIO_GAIN,
+ boost::mem_fn (&AudioContent::audio_gain),
+ boost::mem_fn (&AudioContent::set_audio_gain)
+ );
+ _gain->add (grid, wxGBPosition (r, 1));
+ add_label_to_grid_bag_sizer (grid, this, _("dB"), false, wxGBPosition (r, 2));
_gain_calculate_button = new wxButton (this, wxID_ANY, _("Calculate..."));
- grid->Add (_gain_calculate_button);
-
- add_label_to_sizer (grid, this, _("Audio Delay"), false);
- {
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _delay = new wxSpinCtrl (this);
- s->Add (_delay, 1);
- /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time
- add_label_to_sizer (s, this, _("ms"), false);
- grid->Add (s);
- }
-
- grid->AddSpacer (0);
+ grid->Add (_gain_calculate_button, wxGBPosition (r, 3));
+ ++r;
+
+ add_label_to_grid_bag_sizer (grid, this, _("Audio Delay"), false, wxGBPosition (r, 0));
+ _delay = new ContentSpinCtrl<AudioContent> (
+ this,
+ new wxSpinCtrl (this),
+ AudioContentProperty::AUDIO_DELAY,
+ boost::mem_fn (&AudioContent::audio_delay),
+ boost::mem_fn (&AudioContent::set_audio_delay)
+ );
+
+ _delay->add (grid, wxGBPosition (r,1 ));
+ /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time
+ add_label_to_grid_bag_sizer (grid, this, _("ms"), false, wxGBPosition (r, 2));
+ ++r;
- add_label_to_sizer (grid, this, _("Audio Stream"), true);
+ add_label_to_grid_bag_sizer (grid, this, _("Audio Stream"), true, wxGBPosition (r, 0));
_stream = new wxChoice (this, wxID_ANY);
- grid->Add (_stream, 1, wxEXPAND);
- _description = new wxStaticText (this, wxID_ANY, wxT (""));
- grid->AddSpacer (0);
+ grid->Add (_stream, wxGBPosition (r, 1));
+ ++r;
- grid->Add (_description, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 8);
- grid->AddSpacer (0);
- grid->AddSpacer (0);
+ _description = new wxStaticText (this, wxID_ANY, wxT (""));
+ grid->Add (_description, wxGBPosition (r, 0));
+ ++r;
_mapping = new AudioMappingView (this);
_sizer->Add (_mapping, 1, wxEXPAND | wxALL, 6);
- _gain->SetRange (-60, 60);
- _delay->SetRange (-1000, 1000);
+ _gain->wrapped()->SetRange (-60, 60);
+ _delay->wrapped()->SetRange (-1000, 1000);
- _delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AudioPanel::delay_changed, this));
_stream->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&AudioPanel::stream_changed, this));
_show->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&AudioPanel::show_clicked, this));
- _gain->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AudioPanel::gain_changed, this));
_gain_calculate_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&AudioPanel::gain_calculate_button_clicked, this));
_mapping->Changed.connect (boost::bind (&AudioPanel::mapping_changed, this, _1));
@@ -112,35 +115,36 @@ AudioPanel::film_changed (Film::Property property)
}
void
-AudioPanel::film_content_changed (shared_ptr<Content> c, int property)
+AudioPanel::film_content_changed (int property)
{
- shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (c);
- shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c);
-
- if (_audio_dialog && _editor->selected_audio_content()) {
- _audio_dialog->set_content (_editor->selected_audio_content ());
+ AudioContentList ac = _editor->selected_audio_content ();
+ shared_ptr<AudioContent> acs;
+ shared_ptr<FFmpegContent> fcs;
+ if (ac.size() == 1) {
+ acs = ac.front ();
+ fcs = dynamic_pointer_cast<FFmpegContent> (acs);
+ }
+
+ if (_audio_dialog && acs) {
+ _audio_dialog->set_content (acs);
}
- if (property == AudioContentProperty::AUDIO_GAIN) {
- checked_set (_gain, ac ? ac->audio_gain() : 0);
- } else if (property == AudioContentProperty::AUDIO_DELAY) {
- checked_set (_delay, ac ? ac->audio_delay() : 0);
- } else if (property == AudioContentProperty::AUDIO_MAPPING) {
- _mapping->set (ac ? ac->audio_mapping () : AudioMapping ());
+ if (property == AudioContentProperty::AUDIO_MAPPING) {
+ _mapping->set (acs ? acs->audio_mapping () : AudioMapping ());
_sizer->Layout ();
} else if (property == FFmpegContentProperty::AUDIO_STREAM) {
setup_stream_description ();
- _mapping->set (ac ? ac->audio_mapping () : AudioMapping ());
+ _mapping->set (acs ? acs->audio_mapping () : AudioMapping ());
} else if (property == FFmpegContentProperty::AUDIO_STREAMS) {
_stream->Clear ();
- if (fc) {
- vector<shared_ptr<FFmpegAudioStream> > a = fc->audio_streams ();
+ if (fcs) {
+ vector<shared_ptr<FFmpegAudioStream> > a = fcs->audio_streams ();
for (vector<shared_ptr<FFmpegAudioStream> >::iterator i = a.begin(); i != a.end(); ++i) {
_stream->Append (std_to_wx ((*i)->name), new wxStringClientData (std_to_wx (lexical_cast<string> ((*i)->id))));
}
- if (fc->audio_stream()) {
- checked_set (_stream, lexical_cast<string> (fc->audio_stream()->id));
+ if (fcs->audio_stream()) {
+ checked_set (_stream, lexical_cast<string> (fcs->audio_stream()->id));
setup_stream_description ();
}
}
@@ -148,28 +152,6 @@ AudioPanel::film_content_changed (shared_ptr<Content> c, int property)
}
void
-AudioPanel::gain_changed ()
-{
- shared_ptr<AudioContent> ac = _editor->selected_audio_content ();
- if (!ac) {
- return;
- }
-
- ac->set_audio_gain (_gain->GetValue ());
-}
-
-void
-AudioPanel::delay_changed ()
-{
- shared_ptr<AudioContent> ac = _editor->selected_audio_content ();
- if (!ac) {
- return;
- }
-
- ac->set_audio_delay (_delay->GetValue ());
-}
-
-void
AudioPanel::gain_calculate_button_clicked ()
{
GainCalculatorDialog* d = new GainCalculatorDialog (this);
@@ -180,7 +162,7 @@ AudioPanel::gain_calculate_button_clicked ()
return;
}
- _gain->SetValue (
+ _gain->wrapped()->SetValue (
Config::instance()->sound_processor()->db_for_fader_change (
d->wanted_fader (),
d->actual_fader ()
@@ -190,7 +172,7 @@ AudioPanel::gain_calculate_button_clicked ()
/* This appears to be necessary, as the change is not signalled,
I think.
*/
- gain_changed ();
+ _gain->update_from_model ();
d->Destroy ();
}
@@ -203,39 +185,31 @@ AudioPanel::show_clicked ()
_audio_dialog = 0;
}
- shared_ptr<Content> c = _editor->selected_content ();
- if (!c) {
- return;
- }
-
- shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (c);
- if (!ac) {
+ AudioContentList ac = _editor->selected_audio_content ();
+ if (ac.size() != 1) {
return;
}
_audio_dialog = new AudioDialog (this);
_audio_dialog->Show ();
- _audio_dialog->set_content (ac);
+ _audio_dialog->set_content (ac.front ());
}
void
AudioPanel::stream_changed ()
{
- shared_ptr<Content> c = _editor->selected_content ();
- if (!c) {
- return;
- }
-
- shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c);
- if (!fc) {
+ FFmpegContentList fc = _editor->selected_ffmpeg_content ();
+ if (fc.size() != 1) {
return;
}
+ shared_ptr<FFmpegContent> fcs = fc.front ();
+
if (_stream->GetSelection() == -1) {
return;
}
- vector<shared_ptr<FFmpegAudioStream> > a = fc->audio_streams ();
+ vector<shared_ptr<FFmpegAudioStream> > a = fcs->audio_streams ();
vector<shared_ptr<FFmpegAudioStream> >::iterator i = a.begin ();
string const s = string_client_data (_stream->GetClientObject (_stream->GetSelection ()));
while (i != a.end() && lexical_cast<string> ((*i)->id) != s) {
@@ -243,7 +217,7 @@ AudioPanel::stream_changed ()
}
if (i != a.end ()) {
- fc->set_audio_stream (*i);
+ fcs->set_audio_stream (*i);
}
setup_stream_description ();
@@ -252,26 +226,23 @@ AudioPanel::stream_changed ()
void
AudioPanel::setup_stream_description ()
{
- shared_ptr<Content> c = _editor->selected_content ();
- if (!c) {
- return;
- }
-
- shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c);
- if (!fc) {
+ FFmpegContentList fc = _editor->selected_ffmpeg_content ();
+ if (fc.size() != 1) {
return;
}
- if (!fc->audio_stream ()) {
+ shared_ptr<FFmpegContent> fcs = fc.front ();
+
+ if (!fcs->audio_stream ()) {
_description->SetLabel (wxT (""));
} else {
wxString s;
- if (fc->audio_channels() == 1) {
+ if (fcs->audio_channels() == 1) {
s << _("1 channel");
} else {
- s << fc->audio_channels() << wxT (" ") << _("channels");
+ s << fcs->audio_channels() << wxT (" ") << _("channels");
}
- s << wxT (", ") << fc->content_audio_frame_rate() << _("Hz");
+ s << wxT (", ") << fcs->content_audio_frame_rate() << _("Hz");
_description->SetLabel (s);
}
}
@@ -279,11 +250,25 @@ AudioPanel::setup_stream_description ()
void
AudioPanel::mapping_changed (AudioMapping m)
{
- shared_ptr<AudioContent> c = _editor->selected_audio_content ();
- if (!c) {
- return;
+ AudioContentList c = _editor->selected_audio_content ();
+ if (c.size() == 1) {
+ c.front()->set_audio_mapping (m);
}
-
- c->set_audio_mapping (m);
}
+void
+AudioPanel::content_selection_changed ()
+{
+ AudioContentList sel = _editor->selected_audio_content ();
+
+ _gain->set_content (sel);
+ _delay->set_content (sel);
+
+ _show->Enable (sel.size() == 1);
+ _stream->Enable (sel.size() == 1);
+ _mapping->Enable (sel.size() == 1);
+
+ film_content_changed (AudioContentProperty::AUDIO_MAPPING);
+ film_content_changed (FFmpegContentProperty::AUDIO_STREAM);
+ film_content_changed (FFmpegContentProperty::AUDIO_STREAMS);
+}
diff --git a/src/wx/audio_panel.h b/src/wx/audio_panel.h
index e1dc283e2..f1b932e7c 100644
--- a/src/wx/audio_panel.h
+++ b/src/wx/audio_panel.h
@@ -19,6 +19,7 @@
#include "lib/audio_mapping.h"
#include "film_editor_panel.h"
+#include "content_widget.h"
class wxSpinCtrl;
class wxButton;
@@ -33,21 +34,20 @@ public:
AudioPanel (FilmEditor *);
void film_changed (Film::Property);
- void film_content_changed (boost::shared_ptr<Content>, int);
+ void film_content_changed (int);
+ void content_selection_changed ();
private:
- void gain_changed ();
void gain_calculate_button_clicked ();
void show_clicked ();
- void delay_changed ();
void stream_changed ();
void mapping_changed (AudioMapping);
void setup_stream_description ();
- wxSpinCtrl* _gain;
+ ContentSpinCtrl<AudioContent>* _gain;
wxButton* _gain_calculate_button;
wxButton* _show;
- wxSpinCtrl* _delay;
+ ContentSpinCtrl<AudioContent>* _delay;
wxChoice* _stream;
wxStaticText* _description;
AudioMappingView* _mapping;
diff --git a/src/wx/content_widget.h b/src/wx/content_widget.h
new file mode 100644
index 000000000..07abc7cbd
--- /dev/null
+++ b/src/wx/content_widget.h
@@ -0,0 +1,211 @@
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef DCPOMATIC_MULTIPLE_WIDGET_H
+#define DCPOMATIC_MULTIPLE_WIDGET_H
+
+#include <vector>
+#include <wx/wx.h>
+#include <wx/gbsizer.h>
+#include <boost/function.hpp>
+#include "wx_util.h"
+
+/** A widget which represents some Content state and which can be used
+ * when multiple pieces of content are selected.
+ *
+ * @param S Type containing the content being represented (e.g. VideoContent)
+ * @param T Type of the widget (e.g. wxSpinCtrl)
+ * @param U Data type of state as used by the model.
+ * @param V Data type of state as used by the view.
+ */
+template <class S, class T, typename U, typename V>
+class ContentWidget
+{
+public:
+ /** @param parent Parent window.
+ * @param wrapped Control widget that we are wrapping.
+ * @param property ContentProperty that the widget is handling.
+ * @param model_getter Function on the Content to get the value.
+ * @param model_setter Function on the Content to set the value.
+ */
+ ContentWidget (
+ wxWindow* parent,
+ T* wrapped,
+ int property,
+ boost::function<U (S*)> model_getter,
+ boost::function<void (S*, U)> model_setter,
+ boost::function<V (T*)> view_getter
+ )
+ : _wrapped (wrapped)
+ , _sizer (0)
+ , _button (new wxButton (parent, wxID_ANY, _("Multiple values")))
+ , _property (property)
+ , _model_getter (model_getter)
+ , _model_setter (model_setter)
+ , _view_getter (view_getter)
+ , _ignore_model_changes (false)
+ {
+ _button->SetToolTip (_("Click the button to set all selected content to the same value."));
+ _button->Hide ();
+ _button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentWidget::button_clicked, this));
+ }
+
+ T* wrapped () const {
+ return _wrapped;
+ }
+
+ typedef std::vector<boost::shared_ptr<S> > List;
+
+ void set_content (List content)
+ {
+ for (typename std::list<boost::signals2::connection>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
+ i->disconnect ();
+ }
+
+ _connections.clear ();
+
+ _content = content;
+
+ _wrapped->Enable (!_content.empty ());
+
+ update_from_model ();
+
+ for (typename List::iterator i = _content.begin(); i != _content.end(); ++i) {
+ _connections.push_back ((*i)->Changed.connect (boost::bind (&ContentWidget::model_changed, this, _2)));
+ }
+ }
+
+ void add (wxGridBagSizer* sizer, wxGBPosition position)
+ {
+ _sizer = sizer;
+ _position = position;
+ _sizer->Add (_wrapped, _position);
+ }
+
+ void update_from_model ()
+ {
+ if (_content.empty ()) {
+ set_single ();
+ return;
+ }
+
+ typename List::iterator i = _content.begin ();
+ U const v = boost::bind (_model_getter, _content.front().get())();
+ while (i != _content.end() && boost::bind (_model_getter, i->get())() == v) {
+ ++i;
+ }
+
+ if (i == _content.end ()) {
+ set_single ();
+ checked_set (_wrapped, v);
+ } else {
+ set_multiple ();
+ }
+ }
+
+ void view_changed ()
+ {
+ for (size_t i = 0; i < _content.size(); ++i) {
+ /* Only update our view on the last time round this loop */
+ _ignore_model_changes = i < (_content.size() - 1);
+ boost::bind (_model_setter, _content[i].get(), static_cast<U> (boost::bind (_view_getter, _wrapped)()))();
+ }
+ }
+
+private:
+
+ void set_single ()
+ {
+ if (_wrapped->IsShown ()) {
+ return;
+ }
+
+ _sizer->Detach (_button);
+ _button->Hide ();
+ _sizer->Add (_wrapped, _position);
+ _wrapped->Show ();
+ _sizer->Layout ();
+ }
+
+ void set_multiple ()
+ {
+ if (_button->IsShown ()) {
+ return;
+ }
+
+ _wrapped->Hide ();
+ _sizer->Detach (_wrapped);
+ _button->Show ();
+ _sizer->Add (_button, _position);
+ _sizer->Layout ();
+ }
+
+ void button_clicked ()
+ {
+ U const v = boost::bind (_model_getter, _content.front().get())();
+ for (typename List::iterator i = _content.begin (); i != _content.end(); ++i) {
+ boost::bind (_model_setter, i->get(), v) ();
+ }
+ }
+
+ void model_changed (int property)
+ {
+ if (property == _property && !_ignore_model_changes) {
+ update_from_model ();
+ }
+ }
+
+ T* _wrapped;
+ wxGridBagSizer* _sizer;
+ wxGBPosition _position;
+ wxButton* _button;
+ List _content;
+ int _property;
+ boost::function<U (S*)> _model_getter;
+ boost::function<void (S*, U)> _model_setter;
+ boost::function<V (T*)> _view_getter;
+ std::list<boost::signals2::connection> _connections;
+ bool _ignore_model_changes;
+};
+
+template <class S>
+class ContentSpinCtrl : public ContentWidget<S, wxSpinCtrl, int, int>
+{
+public:
+ ContentSpinCtrl (wxWindow* parent, wxSpinCtrl* wrapped, int property, boost::function<int (S*)> getter, boost::function<void (S*, int)> setter)
+ : ContentWidget<S, wxSpinCtrl, int, int> (parent, wrapped, property, getter, setter, boost::mem_fn (&wxSpinCtrl::GetValue))
+ {
+ wrapped->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ContentWidget<S, wxSpinCtrl, int, int>::view_changed, this));
+ }
+
+};
+
+template <class S, class U>
+class ContentChoice : public ContentWidget<S, wxChoice, U, int>
+{
+public:
+ ContentChoice (wxWindow* parent, wxChoice* wrapped, int property, boost::function<U (S*)> getter, boost::function<void (S*, U)> setter)
+ : ContentWidget<S, wxChoice, U, int> (parent, wrapped, property, getter, setter, boost::mem_fn (&wxChoice::GetSelection))
+ {
+ wrapped->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ContentWidget<S, wxChoice, U, int>::view_changed, this));
+ }
+
+};
+
+#endif
diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc
index b789a8266..9cf840614 100644
--- a/src/wx/film_editor.cc
+++ b/src/wx/film_editor.cc
@@ -258,7 +258,7 @@ FilmEditor::make_content_panel ()
{
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _content = new wxListCtrl (_content_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL);
+ _content = new wxListCtrl (_content_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER);
s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6);
_content->InsertColumn (0, wxT(""));
@@ -470,7 +470,7 @@ FilmEditor::film_changed (Film::Property p)
}
void
-FilmEditor::film_content_changed (weak_ptr<Content> weak_content, int property)
+FilmEditor::film_content_changed (int property)
{
ensure_ui_thread ();
@@ -481,13 +481,8 @@ FilmEditor::film_content_changed (weak_ptr<Content> weak_content, int property)
return;
}
- shared_ptr<Content> content = weak_content.lock ();
- if (!content || content != selected_content ()) {
- return;
- }
-
for (list<FilmEditorPanel*>::iterator i = _panels.begin(); i != _panels.end(); ++i) {
- (*i)->film_content_changed (content, property);
+ (*i)->film_content_changed (property);
}
if (property == FFmpegContentProperty::AUDIO_STREAM) {
@@ -561,7 +556,7 @@ FilmEditor::set_film (shared_ptr<Film> f)
if (_film) {
_film->Changed.connect (bind (&FilmEditor::film_changed, this, _1));
- _film->ContentChanged.connect (bind (&FilmEditor::film_content_changed, this, _1, _2));
+ _film->ContentChanged.connect (bind (&FilmEditor::film_content_changed, this, _2));
}
if (_film) {
@@ -775,9 +770,9 @@ FilmEditor::content_add_folder_clicked ()
void
FilmEditor::content_remove_clicked ()
{
- shared_ptr<Content> c = selected_content ();
- if (c) {
- _film->remove_content (c);
+ ContentList c = selected_content ();
+ if (c.size() == 1) {
+ _film->remove_content (c.front ());
}
content_selection_changed ();
@@ -787,29 +782,10 @@ void
FilmEditor::content_selection_changed ()
{
setup_content_sensitivity ();
- shared_ptr<Content> s = selected_content ();
-
- /* All other sensitivity in content panels should be triggered by
- one of these.
- */
- film_content_changed (s, ContentProperty::POSITION);
- film_content_changed (s, ContentProperty::LENGTH);
- film_content_changed (s, ContentProperty::TRIM_START);
- film_content_changed (s, ContentProperty::TRIM_END);
- film_content_changed (s, VideoContentProperty::VIDEO_CROP);
- film_content_changed (s, VideoContentProperty::VIDEO_RATIO);
- film_content_changed (s, VideoContentProperty::VIDEO_FRAME_TYPE);
- film_content_changed (s, VideoContentProperty::COLOUR_CONVERSION);
- film_content_changed (s, AudioContentProperty::AUDIO_GAIN);
- film_content_changed (s, AudioContentProperty::AUDIO_DELAY);
- film_content_changed (s, AudioContentProperty::AUDIO_MAPPING);
- film_content_changed (s, FFmpegContentProperty::AUDIO_STREAM);
- film_content_changed (s, FFmpegContentProperty::AUDIO_STREAMS);
- film_content_changed (s, FFmpegContentProperty::SUBTITLE_STREAM);
- film_content_changed (s, FFmpegContentProperty::SUBTITLE_STREAMS);
- film_content_changed (s, FFmpegContentProperty::FILTERS);
- film_content_changed (s, SubtitleContentProperty::SUBTITLE_OFFSET);
- film_content_changed (s, SubtitleContentProperty::SUBTITLE_SCALE);
+
+ for (list<FilmEditorPanel*>::iterator i = _panels.begin(); i != _panels.end(); ++i) {
+ (*i)->content_selection_changed ();
+ }
}
/** Set up broad sensitivity based on the type of content that is selected */
@@ -819,66 +795,100 @@ FilmEditor::setup_content_sensitivity ()
_content_add_file->Enable (_generally_sensitive);
_content_add_folder->Enable (_generally_sensitive);
- shared_ptr<Content> selection = selected_content ();
+ ContentList selection = selected_content ();
+ VideoContentList video_selection = selected_video_content ();
+ AudioContentList audio_selection = selected_audio_content ();
- _content_remove->Enable (selection && _generally_sensitive);
- _content_earlier->Enable (selection && _generally_sensitive);
- _content_later->Enable (selection && _generally_sensitive);
+ _content_remove->Enable (selection.size() == 1 && _generally_sensitive);
+ _content_earlier->Enable (selection.size() == 1 && _generally_sensitive);
+ _content_later->Enable (selection.size() == 1 && _generally_sensitive);
_content_timeline->Enable (_generally_sensitive);
- _video_panel->Enable (selection && dynamic_pointer_cast<VideoContent> (selection) && _generally_sensitive);
- _audio_panel->Enable (selection && dynamic_pointer_cast<AudioContent> (selection) && _generally_sensitive);
- _subtitle_panel->Enable (selection && dynamic_pointer_cast<FFmpegContent> (selection) && _generally_sensitive);
- _timing_panel->Enable (selection && _generally_sensitive);
+ _video_panel->Enable (video_selection.size() > 0 && _generally_sensitive);
+ _audio_panel->Enable (audio_selection.size() > 0 && _generally_sensitive);
+ _subtitle_panel->Enable (selection.size() == 1 && dynamic_pointer_cast<FFmpegContent> (selection.front()) && _generally_sensitive);
+ _timing_panel->Enable (selection.size() == 1 && _generally_sensitive);
}
-shared_ptr<Content>
+ContentList
FilmEditor::selected_content ()
{
- int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
- if (s == -1) {
- return shared_ptr<Content> ();
- }
+ ContentList sel;
+ long int s = -1;
+ while (1) {
+ s = _content->GetNextItem (s, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+ if (s == -1) {
+ break;
+ }
- ContentList c = _film->content ();
- if (s < 0 || size_t (s) >= c.size ()) {
- return shared_ptr<Content> ();
+ sel.push_back (_film->content()[s]);
}
-
- return c[s];
+
+ return sel;
}
-shared_ptr<VideoContent>
+VideoContentList
FilmEditor::selected_video_content ()
{
- shared_ptr<Content> c = selected_content ();
- if (!c) {
- return shared_ptr<VideoContent> ();
+ ContentList c = selected_content ();
+ VideoContentList vc;
+
+ for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
+ shared_ptr<VideoContent> t = dynamic_pointer_cast<VideoContent> (*i);
+ if (t) {
+ vc.push_back (t);
+ }
}
- return dynamic_pointer_cast<VideoContent> (c);
+ return vc;
}
-shared_ptr<AudioContent>
+AudioContentList
FilmEditor::selected_audio_content ()
{
- shared_ptr<Content> c = selected_content ();
- if (!c) {
- return shared_ptr<AudioContent> ();
+ ContentList c = selected_content ();
+ AudioContentList ac;
+
+ for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
+ shared_ptr<AudioContent> t = dynamic_pointer_cast<AudioContent> (*i);
+ if (t) {
+ ac.push_back (t);
+ }
}
- return dynamic_pointer_cast<AudioContent> (c);
+ return ac;
}
-shared_ptr<SubtitleContent>
+SubtitleContentList
FilmEditor::selected_subtitle_content ()
{
- shared_ptr<Content> c = selected_content ();
- if (!c) {
- return shared_ptr<SubtitleContent> ();
+ ContentList c = selected_content ();
+ SubtitleContentList sc;
+
+ for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
+ shared_ptr<SubtitleContent> t = dynamic_pointer_cast<SubtitleContent> (*i);
+ if (t) {
+ sc.push_back (t);
+ }
+ }
+
+ return sc;
+}
+
+FFmpegContentList
+FilmEditor::selected_ffmpeg_content ()
+{
+ ContentList c = selected_content ();
+ FFmpegContentList sc;
+
+ for (ContentList::iterator i = c.begin(); i != c.end(); ++i) {
+ shared_ptr<FFmpegContent> t = dynamic_pointer_cast<FFmpegContent> (*i);
+ if (t) {
+ sc.push_back (t);
+ }
}
- return dynamic_pointer_cast<SubtitleContent> (c);
+ return sc;
}
void
@@ -919,11 +929,7 @@ FilmEditor::sequence_video_changed ()
void
FilmEditor::content_right_click (wxListEvent& ev)
{
- ContentList cl;
- if (selected_content ()) {
- cl.push_back (selected_content ());
- }
- _menu.popup (cl, ev.GetPoint ());
+ _menu.popup (selected_content (), ev.GetPoint ());
}
void
@@ -939,13 +945,19 @@ FilmEditor::three_d_changed ()
void
FilmEditor::content_earlier_clicked ()
{
- _film->move_content_earlier (selected_content ());
- content_selection_changed ();
+ ContentList sel = selected_content ();
+ if (sel.size() == 1) {
+ _film->move_content_earlier (sel.front ());
+ content_selection_changed ();
+ }
}
void
FilmEditor::content_later_clicked ()
{
- _film->move_content_later (selected_content ());
- content_selection_changed ();
+ ContentList sel = selected_content ();
+ if (sel.size() == 1) {
+ _film->move_content_later (sel.front ());
+ content_selection_changed ();
+ }
}
diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h
index 80c35d3d8..7fd61e5fc 100644
--- a/src/wx/film_editor.h
+++ b/src/wx/film_editor.h
@@ -62,10 +62,11 @@ public:
return _film;
}
- boost::shared_ptr<Content> selected_content ();
- boost::shared_ptr<VideoContent> selected_video_content ();
- boost::shared_ptr<AudioContent> selected_audio_content ();
- boost::shared_ptr<SubtitleContent> selected_subtitle_content ();
+ ContentList selected_content ();
+ VideoContentList selected_video_content ();
+ AudioContentList selected_audio_content ();
+ SubtitleContentList selected_subtitle_content ();
+ FFmpegContentList selected_ffmpeg_content ();
private:
void make_dcp_panel ();
@@ -99,7 +100,7 @@ private:
/* Handle changes to the model */
void film_changed (Film::Property);
- void film_content_changed (boost::weak_ptr<Content>, int);
+ void film_content_changed (int);
void set_general_sensitivity (bool);
void setup_dcp_name ();
diff --git a/src/wx/film_editor_panel.h b/src/wx/film_editor_panel.h
index 8acb3efb6..e0514ba99 100644
--- a/src/wx/film_editor_panel.h
+++ b/src/wx/film_editor_panel.h
@@ -33,7 +33,10 @@ public:
FilmEditorPanel (FilmEditor *, wxString);
virtual void film_changed (Film::Property) {}
- virtual void film_content_changed (boost::shared_ptr<Content>, int) = 0;
+ /** Called when a given property of one of the selected Contents changes */
+ virtual void film_content_changed (int) = 0;
+ /** Called when the list of selected Contents changes */
+ virtual void content_selection_changed () = 0;
protected:
FilmEditor* _editor;
diff --git a/src/wx/subtitle_panel.cc b/src/wx/subtitle_panel.cc
index 8f2b08af5..c820220d4 100644
--- a/src/wx/subtitle_panel.cc
+++ b/src/wx/subtitle_panel.cc
@@ -89,32 +89,41 @@ SubtitlePanel::film_changed (Film::Property property)
}
void
-SubtitlePanel::film_content_changed (shared_ptr<Content> c, int property)
+SubtitlePanel::film_content_changed (int property)
{
- shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (c);
- shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c);
+ FFmpegContentList fc = _editor->selected_ffmpeg_content ();
+ SubtitleContentList sc = _editor->selected_subtitle_content ();
+
+ shared_ptr<FFmpegContent> fcs;
+ if (fc.size() == 1) {
+ fcs = fc.front ();
+ }
+
+ shared_ptr<SubtitleContent> scs;
+ if (sc.size() == 1) {
+ scs = sc.front ();
+ }
if (property == FFmpegContentProperty::SUBTITLE_STREAMS) {
_stream->Clear ();
- if (fc) {
- vector<shared_ptr<FFmpegSubtitleStream> > s = fc->subtitle_streams ();
+ if (fcs) {
+ vector<shared_ptr<FFmpegSubtitleStream> > s = fcs->subtitle_streams ();
for (vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = s.begin(); i != s.end(); ++i) {
_stream->Append (std_to_wx ((*i)->name), new wxStringClientData (std_to_wx (lexical_cast<string> ((*i)->id))));
}
- if (fc->subtitle_stream()) {
- checked_set (_stream, lexical_cast<string> (fc->subtitle_stream()->id));
+ if (fcs->subtitle_stream()) {
+ checked_set (_stream, lexical_cast<string> (fcs->subtitle_stream()->id));
} else {
_stream->SetSelection (wxNOT_FOUND);
}
}
setup_sensitivity ();
} else if (property == SubtitleContentProperty::SUBTITLE_OFFSET) {
- checked_set (_offset, sc ? (sc->subtitle_offset() * 100) : 0);
+ checked_set (_offset, scs ? (scs->subtitle_offset() * 100) : 0);
} else if (property == SubtitleContentProperty::SUBTITLE_SCALE) {
- checked_set (_scale, sc ? (sc->subtitle_scale() * 100) : 100);
+ checked_set (_scale, scs ? (scs->subtitle_scale() * 100) : 100);
}
-
}
void
@@ -146,17 +155,14 @@ SubtitlePanel::setup_sensitivity ()
void
SubtitlePanel::stream_changed ()
{
- shared_ptr<Content> c = _editor->selected_content ();
- if (!c) {
- return;
- }
-
- shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c);
- if (!fc) {
+ FFmpegContentList fc = _editor->selected_ffmpeg_content ();
+ if (fc.size() != 1) {
return;
}
+
+ shared_ptr<FFmpegContent> fcs = fc.front ();
- vector<shared_ptr<FFmpegSubtitleStream> > a = fc->subtitle_streams ();
+ vector<shared_ptr<FFmpegSubtitleStream> > a = fcs->subtitle_streams ();
vector<shared_ptr<FFmpegSubtitleStream> >::iterator i = a.begin ();
string const s = string_client_data (_stream->GetClientObject (_stream->GetSelection ()));
while (i != a.end() && lexical_cast<string> ((*i)->id) != s) {
@@ -164,29 +170,32 @@ SubtitlePanel::stream_changed ()
}
if (i != a.end ()) {
- fc->set_subtitle_stream (*i);
+ fcs->set_subtitle_stream (*i);
}
}
void
SubtitlePanel::offset_changed ()
{
- shared_ptr<SubtitleContent> c = _editor->selected_subtitle_content ();
- if (!c) {
- return;
+ SubtitleContentList c = _editor->selected_subtitle_content ();
+ if (c.size() == 1) {
+ c.front()->set_subtitle_offset (_offset->GetValue() / 100.0);
}
-
- c->set_subtitle_offset (_offset->GetValue() / 100.0);
}
void
SubtitlePanel::scale_changed ()
{
- shared_ptr<SubtitleContent> c = _editor->selected_subtitle_content ();
- if (!c) {
- return;
+ SubtitleContentList c = _editor->selected_subtitle_content ();
+ if (c.size() == 1) {
+ c.front()->set_subtitle_scale (_scale->GetValue() / 100.0);
}
+}
+
+void
+SubtitlePanel::content_selection_changed ()
+{
- c->set_subtitle_scale (_scale->GetValue() / 100.0);
}
+
diff --git a/src/wx/subtitle_panel.h b/src/wx/subtitle_panel.h
index 3f7951895..19df26436 100644
--- a/src/wx/subtitle_panel.h
+++ b/src/wx/subtitle_panel.h
@@ -28,8 +28,8 @@ public:
SubtitlePanel (FilmEditor *);
void film_changed (Film::Property);
- void film_content_changed (boost::shared_ptr<Content>, int);
-
+ void film_content_changed (int);
+ void content_selection_changed ();
private:
void with_subtitles_toggled ();
diff --git a/src/wx/timing_panel.cc b/src/wx/timing_panel.cc
index ba645cf32..512a83cd9 100644
--- a/src/wx/timing_panel.cc
+++ b/src/wx/timing_panel.cc
@@ -54,8 +54,14 @@ TimingPanel::TimingPanel (FilmEditor* e)
}
void
-TimingPanel::film_content_changed (shared_ptr<Content> content, int property)
+TimingPanel::film_content_changed (int property)
{
+ ContentList cl = _editor->selected_content ();
+ shared_ptr<Content> content;
+ if (cl.size() == 1) {
+ content = cl.front ();
+ }
+
if (property == ContentProperty::POSITION) {
if (content) {
_position->set (content->position (), _editor->film()->video_frame_rate ());
@@ -88,47 +94,45 @@ TimingPanel::film_content_changed (shared_ptr<Content> content, int property)
void
TimingPanel::position_changed ()
{
- shared_ptr<Content> c = _editor->selected_content ();
- if (!c) {
- return;
+ ContentList c = _editor->selected_content ();
+ if (c.size() == 1) {
+ c.front()->set_position (_position->get (_editor->film()->video_frame_rate ()));
}
-
- c->set_position (_position->get (_editor->film()->video_frame_rate ()));
}
void
TimingPanel::length_changed ()
{
- shared_ptr<Content> c = _editor->selected_content ();
- if (!c) {
- return;
- }
-
- shared_ptr<StillImageContent> ic = dynamic_pointer_cast<StillImageContent> (c);
- if (ic) {
- ic->set_video_length (rint (_length->get (_editor->film()->video_frame_rate()) * ic->video_frame_rate() / TIME_HZ));
+ ContentList c = _editor->selected_content ();
+ if (c.size() == 1) {
+ shared_ptr<StillImageContent> ic = dynamic_pointer_cast<StillImageContent> (c.front ());
+ if (ic) {
+ ic->set_video_length (rint (_length->get (_editor->film()->video_frame_rate()) * ic->video_frame_rate() / TIME_HZ));
+ }
}
}
void
TimingPanel::trim_start_changed ()
{
- shared_ptr<Content> c = _editor->selected_content ();
- if (!c) {
- return;
+ ContentList c = _editor->selected_content ();
+ if (c.size() == 1) {
+ c.front()->set_trim_start (_trim_start->get (_editor->film()->video_frame_rate ()));
}
-
- c->set_trim_start (_trim_start->get (_editor->film()->video_frame_rate ()));
}
void
TimingPanel::trim_end_changed ()
{
- shared_ptr<Content> c = _editor->selected_content ();
- if (!c) {
- return;
+ ContentList c = _editor->selected_content ();
+ if (c.size() == 1) {
+ c.front()->set_trim_end (_trim_end->get (_editor->film()->video_frame_rate ()));
}
+}
+
+void
+TimingPanel::content_selection_changed ()
+{
- c->set_trim_end (_trim_end->get (_editor->film()->video_frame_rate ()));
}
diff --git a/src/wx/timing_panel.h b/src/wx/timing_panel.h
index b84ea52be..8c519bcbe 100644
--- a/src/wx/timing_panel.h
+++ b/src/wx/timing_panel.h
@@ -26,7 +26,8 @@ class TimingPanel : public FilmEditorPanel
public:
TimingPanel (FilmEditor *);
- void film_content_changed (boost::shared_ptr<Content>, int);
+ void film_content_changed (int);
+ void content_selection_changed ();
private:
void position_changed ();
diff --git a/src/wx/video_panel.cc b/src/wx/video_panel.cc
index a643832e8..9adc64641 100644
--- a/src/wx/video_panel.cc
+++ b/src/wx/video_panel.cc
@@ -29,6 +29,7 @@
#include "wx_util.h"
#include "film_editor.h"
#include "content_colour_conversion_dialog.h"
+#include "content_widget.h"
using std::vector;
using std::string;
@@ -49,28 +50,58 @@ VideoPanel::VideoPanel (FilmEditor* e)
int r = 0;
add_label_to_grid_bag_sizer (grid, this, _("Type"), true, wxGBPosition (r, 0));
- _frame_type = new wxChoice (this, wxID_ANY);
- grid->Add (_frame_type, wxGBPosition (r, 1));
+ _frame_type = new ContentChoice<VideoContent, VideoFrameType> (
+ this,
+ new wxChoice (this, wxID_ANY),
+ VideoContentProperty::VIDEO_FRAME_TYPE,
+ boost::mem_fn (&VideoContent::video_frame_type),
+ boost::mem_fn (&VideoContent::set_video_frame_type)
+ );
+ _frame_type->add (grid, wxGBPosition (r, 1));
++r;
add_label_to_grid_bag_sizer (grid, this, _("Left crop"), true, wxGBPosition (r, 0));
- _left_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- grid->Add (_left_crop, wxGBPosition (r, 1));
+ _left_crop = new ContentSpinCtrl<VideoContent> (
+ this,
+ new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
+ VideoContentProperty::VIDEO_CROP,
+ boost::mem_fn (&VideoContent::left_crop),
+ boost::mem_fn (&VideoContent::set_left_crop)
+ );
+ _left_crop->add (grid, wxGBPosition (r, 1));
++r;
add_label_to_grid_bag_sizer (grid, this, _("Right crop"), true, wxGBPosition (r, 0));
- _right_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- grid->Add (_right_crop, wxGBPosition (r, 1));
+ _right_crop = new ContentSpinCtrl<VideoContent> (
+ this,
+ new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
+ VideoContentProperty::VIDEO_CROP,
+ boost::mem_fn (&VideoContent::right_crop),
+ boost::mem_fn (&VideoContent::set_right_crop)
+ );
+ _right_crop->add (grid, wxGBPosition (r, 1));
++r;
add_label_to_grid_bag_sizer (grid, this, _("Top crop"), true, wxGBPosition (r, 0));
- _top_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- grid->Add (_top_crop, wxGBPosition (r, 1));
+ _top_crop = new ContentSpinCtrl<VideoContent> (
+ this,
+ new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
+ VideoContentProperty::VIDEO_CROP,
+ boost::mem_fn (&VideoContent::top_crop),
+ boost::mem_fn (&VideoContent::set_top_crop)
+ );
+ _top_crop->add (grid, wxGBPosition (r,1 ));
++r;
add_label_to_grid_bag_sizer (grid, this, _("Bottom crop"), true, wxGBPosition (r, 0));
- _bottom_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- grid->Add (_bottom_crop, wxGBPosition (r, 1));
+ _bottom_crop = new ContentSpinCtrl<VideoContent> (
+ this,
+ new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
+ VideoContentProperty::VIDEO_CROP,
+ boost::mem_fn (&VideoContent::bottom_crop),
+ boost::mem_fn (&VideoContent::set_bottom_crop)
+ );
+ _bottom_crop->add (grid, wxGBPosition (r, 1));
++r;
add_label_to_grid_bag_sizer (grid, this, _("Scale to"), true, wxGBPosition (r, 0));
@@ -119,10 +150,10 @@ VideoPanel::VideoPanel (FilmEditor* e)
_description->SetFont(font);
++r;
- _left_crop->SetRange (0, 1024);
- _top_crop->SetRange (0, 1024);
- _right_crop->SetRange (0, 1024);
- _bottom_crop->SetRange (0, 1024);
+ _left_crop->wrapped()->SetRange (0, 1024);
+ _top_crop->wrapped()->SetRange (0, 1024);
+ _right_crop->wrapped()->SetRange (0, 1024);
+ _bottom_crop->wrapped()->SetRange (0, 1024);
vector<Ratio const *> ratios = Ratio::all ();
_ratio->Clear ();
@@ -131,68 +162,14 @@ VideoPanel::VideoPanel (FilmEditor* e)
}
_ratio->Append (_("No stretch"));
- _frame_type->Append (_("2D"));
- _frame_type->Append (_("3D left/right"));
+ _frame_type->wrapped()->Append (_("2D"));
+ _frame_type->wrapped()->Append (_("3D left/right"));
- _frame_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::frame_type_changed, this));
- _left_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::left_crop_changed, this));
- _right_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::right_crop_changed, this));
- _top_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::top_crop_changed, this));
- _bottom_crop->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::bottom_crop_changed, this));
_ratio->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&VideoPanel::ratio_changed, this));
_filters_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_filters_clicked, this));
_colour_conversion_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_colour_conversion_clicked, this));
}
-
-/** Called when the left crop widget has been changed */
-void
-VideoPanel::left_crop_changed ()
-{
- shared_ptr<VideoContent> c = _editor->selected_video_content ();
- if (!c) {
- return;
- }
-
- c->set_left_crop (_left_crop->GetValue ());
-}
-
-/** Called when the right crop widget has been changed */
-void
-VideoPanel::right_crop_changed ()
-{
- shared_ptr<VideoContent> c = _editor->selected_video_content ();
- if (!c) {
- return;
- }
-
- c->set_right_crop (_right_crop->GetValue ());
-}
-
-/** Called when the top crop widget has been changed */
-void
-VideoPanel::top_crop_changed ()
-{
- shared_ptr<VideoContent> c = _editor->selected_video_content ();
- if (!c) {
- return;
- }
-
- c->set_top_crop (_top_crop->GetValue ());
-}
-
-/** Called when the bottom crop value has been changed */
-void
-VideoPanel::bottom_crop_changed ()
-{
- shared_ptr<VideoContent> c = _editor->selected_video_content ();
- if (!c) {
- return;
- }
-
- c->set_bottom_crop (_bottom_crop->GetValue ());
-}
-
void
VideoPanel::film_changed (Film::Property property)
{
@@ -207,26 +184,26 @@ VideoPanel::film_changed (Film::Property property)
}
void
-VideoPanel::film_content_changed (shared_ptr<Content> c, int property)
+VideoPanel::film_content_changed (int property)
{
- shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (c);
- shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c);
-
+ VideoContentList vc = _editor->selected_video_content ();
+ shared_ptr<VideoContent> vcs;
+ shared_ptr<FFmpegContent> fcs;
+ if (!vc.empty ()) {
+ vcs = vc.front ();
+ fcs = dynamic_pointer_cast<FFmpegContent> (vcs);
+ }
+
if (property == VideoContentProperty::VIDEO_FRAME_TYPE) {
- checked_set (_frame_type, vc ? vc->video_frame_type () : VIDEO_FRAME_TYPE_2D);
setup_description ();
} else if (property == VideoContentProperty::VIDEO_CROP) {
- checked_set (_left_crop, vc ? vc->crop().left : 0);
- checked_set (_right_crop, vc ? vc->crop().right : 0);
- checked_set (_top_crop, vc ? vc->crop().top : 0);
- checked_set (_bottom_crop, vc ? vc->crop().bottom : 0);
setup_description ();
} else if (property == VideoContentProperty::VIDEO_RATIO) {
- if (vc) {
+ if (vcs) {
int n = 0;
vector<Ratio const *> ratios = Ratio::all ();
vector<Ratio const *>::iterator i = ratios.begin ();
- while (i != ratios.end() && *i != vc->ratio()) {
+ while (i != ratios.end() && *i != vcs->ratio()) {
++i;
++n;
}
@@ -243,12 +220,12 @@ VideoPanel::film_content_changed (shared_ptr<Content> c, int property)
} else if (property == VideoContentProperty::VIDEO_FRAME_RATE) {
setup_description ();
} else if (property == VideoContentProperty::COLOUR_CONVERSION) {
- optional<size_t> preset = vc ? vc->colour_conversion().preset () : optional<size_t> ();
+ optional<size_t> preset = vcs ? vcs->colour_conversion().preset () : optional<size_t> ();
vector<PresetColourConversion> cc = Config::instance()->colour_conversions ();
_colour_conversion->SetLabel (preset ? std_to_wx (cc[preset.get()].name) : _("Custom"));
} else if (property == FFmpegContentProperty::FILTERS) {
- if (fc) {
- pair<string, string> p = Filter::ffmpeg_strings (fc->filters ());
+ if (fcs) {
+ pair<string, string> p = Filter::ffmpeg_strings (fcs->filters ());
if (p.first.empty () && p.second.empty ()) {
_filters->SetLabel (_("None"));
} else {
@@ -263,18 +240,13 @@ VideoPanel::film_content_changed (shared_ptr<Content> c, int property)
void
VideoPanel::edit_filters_clicked ()
{
- shared_ptr<Content> c = _editor->selected_content ();
- if (!c) {
+ FFmpegContentList c = _editor->selected_ffmpeg_content ();
+ if (c.size() != 1) {
return;
}
- shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (c);
- if (!fc) {
- return;
- }
-
- FilterDialog* d = new FilterDialog (this, fc->filters());
- d->ActiveChanged.connect (bind (&FFmpegContent::set_filters, fc, _1));
+ FilterDialog* d = new FilterDialog (this, c.front()->filters());
+ d->ActiveChanged.connect (bind (&FFmpegContent::set_filters, c.front(), _1));
d->ShowModal ();
d->Destroy ();
}
@@ -282,29 +254,34 @@ VideoPanel::edit_filters_clicked ()
void
VideoPanel::setup_description ()
{
- shared_ptr<VideoContent> vc = _editor->selected_video_content ();
- if (!vc) {
+ FFmpegContentList vc = _editor->selected_ffmpeg_content ();
+ if (vc.empty ()) {
_description->SetLabel ("");
return;
+ } else if (vc.size() > 1) {
+ _description->SetLabel (_("Multiple content selected"));
+ return;
}
+ shared_ptr<FFmpegContent> vcs = vc.front ();
+
wxString d;
int lines = 0;
- if (vc->video_size().width && vc->video_size().height) {
+ if (vcs->video_size().width && vcs->video_size().height) {
d << wxString::Format (
_("Content video is %dx%d (%.2f:1)\n"),
- vc->video_size_after_3d_split().width,
- vc->video_size_after_3d_split().height,
- vc->video_size_after_3d_split().ratio ()
+ vcs->video_size_after_3d_split().width,
+ vcs->video_size_after_3d_split().height,
+ vcs->video_size_after_3d_split().ratio ()
);
++lines;
}
- Crop const crop = vc->crop ();
- if ((crop.left || crop.right || crop.top || crop.bottom) && vc->video_size() != libdcp::Size (0, 0)) {
- libdcp::Size cropped = vc->video_size_after_crop ();
+ Crop const crop = vcs->crop ();
+ if ((crop.left || crop.right || crop.top || crop.bottom) && vcs->video_size() != libdcp::Size (0, 0)) {
+ libdcp::Size cropped = vcs->video_size_after_crop ();
d << wxString::Format (
_("Cropped to %dx%d (%.2f:1)\n"),
cropped.width, cropped.height,
@@ -313,9 +290,9 @@ VideoPanel::setup_description ()
++lines;
}
- Ratio const * ratio = vc->ratio ();
+ Ratio const * ratio = vcs->ratio ();
libdcp::Size container_size = fit_ratio_within (_editor->film()->container()->ratio (), _editor->film()->full_frame ());
- float const ratio_value = ratio ? ratio->ratio() : vc->video_size_after_crop().ratio ();
+ float const ratio_value = ratio ? ratio->ratio() : vcs->video_size_after_crop().ratio ();
/* We have a specified ratio to scale to */
libdcp::Size const scaled = fit_ratio_within (ratio_value, container_size);
@@ -336,9 +313,9 @@ VideoPanel::setup_description ()
++lines;
}
- d << wxString::Format (_("Content frame rate %.4f\n"), vc->video_frame_rate ());
+ d << wxString::Format (_("Content frame rate %.4f\n"), vcs->video_frame_rate ());
++lines;
- FrameRateConversion frc (vc->video_frame_rate(), _editor->film()->video_frame_rate ());
+ FrameRateConversion frc (vcs->video_frame_rate(), _editor->film()->video_frame_rate ());
d << frc.description << "\n";
++lines;
@@ -358,41 +335,59 @@ VideoPanel::ratio_changed ()
return;
}
- shared_ptr<VideoContent> vc = _editor->selected_video_content ();
+ VideoContentList vc = _editor->selected_video_content ();
+ if (vc.size() != 1) {
+ return;
+ }
int const n = _ratio->GetSelection ();
if (n >= 0) {
vector<Ratio const *> ratios = Ratio::all ();
if (n < int (ratios.size ())) {
- vc->set_ratio (ratios[n]);
+ vc.front()->set_ratio (ratios[n]);
} else {
- vc->set_ratio (0);
+ vc.front()->set_ratio (0);
}
}
}
void
-VideoPanel::frame_type_changed ()
-{
- shared_ptr<VideoContent> vc = _editor->selected_video_content ();
- if (vc) {
- vc->set_video_frame_type (static_cast<VideoFrameType> (_frame_type->GetSelection ()));
- }
-}
-
-void
VideoPanel::edit_colour_conversion_clicked ()
{
- shared_ptr<VideoContent> vc = _editor->selected_video_content ();
- if (!vc) {
+ VideoContentList vc = _editor->selected_video_content ();
+ if (vc.size() != 1) {
return;
}
- ColourConversion conversion = vc->colour_conversion ();
+ ColourConversion conversion = vc.front()->colour_conversion ();
ContentColourConversionDialog* d = new ContentColourConversionDialog (this);
d->set (conversion);
d->ShowModal ();
- vc->set_colour_conversion (d->get ());
+ vc.front()->set_colour_conversion (d->get ());
d->Destroy ();
}
+
+void
+VideoPanel::content_selection_changed ()
+{
+ VideoContentList sel = _editor->selected_video_content ();
+ bool const single = sel.size() == 1;
+
+ _left_crop->set_content (sel);
+ _right_crop->set_content (sel);
+ _top_crop->set_content (sel);
+ _bottom_crop->set_content (sel);
+ _frame_type->set_content (sel);
+
+ /* Things that are only allowed with single selections */
+ _ratio->Enable (single);
+ _filters_button->Enable (single);
+ _colour_conversion_button->Enable (single);
+
+ film_content_changed (VideoContentProperty::VIDEO_CROP);
+ film_content_changed (VideoContentProperty::VIDEO_RATIO);
+ film_content_changed (VideoContentProperty::VIDEO_FRAME_RATE);
+ film_content_changed (VideoContentProperty::COLOUR_CONVERSION);
+ film_content_changed (FFmpegContentProperty::FILTERS);
+}
diff --git a/src/wx/video_panel.h b/src/wx/video_panel.h
index 2ecf3c87f..577bbf0e7 100644
--- a/src/wx/video_panel.h
+++ b/src/wx/video_panel.h
@@ -19,6 +19,7 @@
#include "lib/film.h"
#include "film_editor_panel.h"
+#include "content_widget.h"
class wxChoice;
class wxStaticText;
@@ -31,25 +32,21 @@ public:
VideoPanel (FilmEditor *);
void film_changed (Film::Property);
- void film_content_changed (boost::shared_ptr<Content>, int);
+ void film_content_changed (int);
+ void content_selection_changed ();
private:
- void left_crop_changed ();
- void right_crop_changed ();
- void top_crop_changed ();
- void bottom_crop_changed ();
void edit_filters_clicked ();
void ratio_changed ();
- void frame_type_changed ();
void edit_colour_conversion_clicked ();
void setup_description ();
- wxChoice* _frame_type;
- wxSpinCtrl* _left_crop;
- wxSpinCtrl* _right_crop;
- wxSpinCtrl* _top_crop;
- wxSpinCtrl* _bottom_crop;
+ ContentChoice<VideoContent, VideoFrameType>* _frame_type;
+ ContentSpinCtrl<VideoContent>* _left_crop;
+ ContentSpinCtrl<VideoContent>* _right_crop;
+ ContentSpinCtrl<VideoContent>* _top_crop;
+ ContentSpinCtrl<VideoContent>* _bottom_crop;
wxChoice* _ratio;
wxStaticText* _ratio_description;
wxStaticText* _description;