diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/types.h | 8 | ||||
| -rw-r--r-- | src/lib/video_content.h | 20 | ||||
| -rw-r--r-- | src/wx/audio_panel.cc | 207 | ||||
| -rw-r--r-- | src/wx/audio_panel.h | 10 | ||||
| -rw-r--r-- | src/wx/content_widget.h | 211 | ||||
| -rw-r--r-- | src/wx/film_editor.cc | 166 | ||||
| -rw-r--r-- | src/wx/film_editor.h | 11 | ||||
| -rw-r--r-- | src/wx/film_editor_panel.h | 5 | ||||
| -rw-r--r-- | src/wx/subtitle_panel.cc | 65 | ||||
| -rw-r--r-- | src/wx/subtitle_panel.h | 4 | ||||
| -rw-r--r-- | src/wx/timing_panel.cc | 50 | ||||
| -rw-r--r-- | src/wx/timing_panel.h | 3 | ||||
| -rw-r--r-- | src/wx/video_panel.cc | 239 | ||||
| -rw-r--r-- | src/wx/video_panel.h | 19 |
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; |
