class VideoContent;
class AudioContent;
class SubtitleContent;
+class FFmpegContent;
class AudioBuffers;
/** The version number of the protocol used to communicate
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
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. */
}
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);
+ checked_set (_gain, acs ? acs->audio_gain() : 0);
} else if (property == AudioContentProperty::AUDIO_DELAY) {
- checked_set (_delay, ac ? ac->audio_delay() : 0);
+ checked_set (_delay, acs ? acs->audio_delay() : 0);
} else if (property == AudioContentProperty::AUDIO_MAPPING) {
- _mapping->set (ac ? ac->audio_mapping () : AudioMapping ());
+ _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 ();
}
}
void
AudioPanel::gain_changed ()
{
- shared_ptr<AudioContent> ac = _editor->selected_audio_content ();
- if (!ac) {
+ AudioContentList ac = _editor->selected_audio_content ();
+ if (ac.size() != 1) {
return;
}
- ac->set_audio_gain (_gain->GetValue ());
+ ac.front()->set_audio_gain (_gain->GetValue ());
}
void
AudioPanel::delay_changed ()
{
- shared_ptr<AudioContent> ac = _editor->selected_audio_content ();
- if (!ac) {
+ AudioContentList ac = _editor->selected_audio_content ();
+ if (ac.size() != 1) {
return;
}
- ac->set_audio_delay (_delay->GetValue ());
+ ac.front()->set_audio_delay (_delay->GetValue ());
}
void
_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) {
}
if (i != a.end ()) {
- fc->set_audio_stream (*i);
+ fcs->set_audio_stream (*i);
}
setup_stream_description ();
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);
}
}
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 ()
+{
+
+}
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
-FilmEditor::film_content_changed (weak_ptr<Content> weak_content, int property)
+FilmEditor::film_content_changed (int property)
{
ensure_ui_thread ();
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) {
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) {
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 ();
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 */
_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 ();
- _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 (selection.size() == 1 && dynamic_pointer_cast<AudioContent> (selection.front()) && _generally_sensitive);
+ _subtitle_panel->Enable (selection.size() == 1 && dynamic_pointer_cast<FFmpegContent> (selection.front()) && _generally_sensitive);
+ _timing_panel->Enable (selection.size() == 1 && _generally_sensitive);
}
ContentList
break;
}
- sel.push_back (_film->content[s]);
+ sel.push_back (_film->content()[s]);
}
return sel;
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 sc;
+}
+
void
FilmEditor::content_timeline_clicked ()
{
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
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 ();
+ }
}
VideoContentList selected_video_content ();
AudioContentList selected_audio_content ();
SubtitleContentList selected_subtitle_content ();
+ FFmpegContentList selected_ffmpeg_content ();
private:
void make_dcp_panel ();
/* 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 ();
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;
--- /dev/null
+/*
+ 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"
+
+template <class T>
+class MultipleWidget
+{
+public:
+ MultipleWidget (wxWindow* parent, T* wrapped)
+ : _wrapped (wrapped)
+ , _sizer (0)
+ , _button (new wxButton (parent, wxID_ANY, _("Multiple values")))
+ {
+ _button->SetToolTip (_("Click the button to set all selections to the same value"));
+ _button->Hide ();
+ _button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&MultipleWidget::button_clicked, this));
+ }
+
+ T* wrapped () const
+ {
+ return _wrapped;
+ }
+
+ void add (wxGridBagSizer* sizer, wxGBPosition position)
+ {
+ _sizer = sizer;
+ _position = position;
+ _sizer->Add (_wrapped, _position);
+ }
+
+ 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 ();
+ }
+
+ boost::signals2::signal<void (void)> SetAllSame;
+
+private:
+ void button_clicked ()
+ {
+ SetAllSame ();
+ }
+
+ T* _wrapped;
+ wxGridBagSizer* _sizer;
+ wxGBPosition _position;
+ wxButton* _button;
+};
+
+
+/** Set up some MultipleWidget<SpinCtrl> using a (possibly) multiple selection of objects of type T.
+ * The value is obtained from the T objects using getter.
+ */
+template <class T>
+void
+set_multiple (std::vector<boost::shared_ptr<T> > data, MultipleWidget<wxSpinCtrl>* widget, boost::function<int (T*)> getter)
+{
+ if (data.empty ()) {
+ widget->set_single ();
+ widget->wrapped()->SetValue (0);
+ return;
+ }
+
+ typename std::vector<boost::shared_ptr<T> >::iterator i = data.begin();
+ int first = boost::bind (getter, data.front().get()) ();
+ while (i != data.end() && boost::bind (getter, i->get())() == first) {
+ ++i;
+ }
+
+ if (i == data.end ()) {
+ /* All values are the same */
+ widget->set_single ();
+ checked_set (widget->wrapped(), first);
+ } else {
+ /* At least one different value */
+ widget->set_multiple ();
+ }
+}
+
+#endif
}
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
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) {
}
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);
}
+
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 ();
}
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 ());
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 ()));
}
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 ();
#include "wx_util.h"
#include "film_editor.h"
#include "content_colour_conversion_dialog.h"
+#include "multiple_widget.h"
using std::vector;
using std::string;
++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 MultipleWidget<wxSpinCtrl> (this, new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)));
+ _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 MultipleWidget<wxSpinCtrl> (this, new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)));
+ _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 MultipleWidget<wxSpinCtrl> (this, new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)));
+ _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 MultipleWidget<wxSpinCtrl> (this, new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)));
+ _bottom_crop->add (grid, wxGBPosition (r, 1));
++r;
add_label_to_grid_bag_sizer (grid, this, _("Scale to"), true, wxGBPosition (r, 0));
_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 ();
_frame_type->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));
+ _left_crop->SetAllSame.connect (boost::bind (&VideoPanel::set_left_crop_same, this));
+ _left_crop->wrapped()->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::left_crop_changed, this));
+ _right_crop->wrapped()->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::right_crop_changed, this));
+ _top_crop->wrapped()->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&VideoPanel::top_crop_changed, this));
+ _bottom_crop->wrapped()->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));
void
VideoPanel::left_crop_changed ()
{
- shared_ptr<VideoContent> c = _editor->selected_video_content ();
- if (!c) {
- return;
+ VideoContentList c = _editor->selected_video_content ();
+ for (VideoContentList::iterator i = c.begin(); i != c.end(); ++i) {
+ (*i)->set_left_crop (_left_crop->wrapped()->GetValue ());
}
-
- 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;
+ VideoContentList c = _editor->selected_video_content ();
+ for (VideoContentList::iterator i = c.begin(); i != c.end(); ++i) {
+ (*i)->set_right_crop (_right_crop->wrapped()->GetValue ());
}
-
- 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;
+ VideoContentList c = _editor->selected_video_content ();
+ for (VideoContentList::iterator i = c.begin(); i != c.end(); ++i) {
+ (*i)->set_top_crop (_top_crop->wrapped()->GetValue ());
}
-
- 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;
+ VideoContentList c = _editor->selected_video_content ();
+ for (VideoContentList::iterator i = c.begin(); i != c.end(); ++i) {
+ (*i)->set_bottom_crop (_bottom_crop->wrapped()->GetValue ());
}
-
- c->set_bottom_crop (_bottom_crop->GetValue ());
}
void
}
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);
+ checked_set (_frame_type, vcs ? vcs->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);
+ set_multiple<VideoContent> (vc, _left_crop, &VideoContent::left_crop);
+ set_multiple<VideoContent> (vc, _right_crop, &VideoContent::right_crop);
+ set_multiple<VideoContent> (vc, _top_crop, &VideoContent::top_crop);
+ set_multiple<VideoContent> (vc, _bottom_crop, &VideoContent::bottom_crop);
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;
}
} 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 {
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 ();
}
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,
++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);
++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;
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 ()));
+ VideoContentList vc = _editor->selected_video_content ();
+ if (vc.size() == 1) {
+ vc.front()->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;
+ bool const multiple = sel.size() > 1;
+
+ /* Things that are allowed with multiple selections */
+ _left_crop->wrapped()->Enable (single || multiple);
+ _right_crop->wrapped()->Enable (single || multiple);
+ _top_crop->wrapped()->Enable (single || multiple);
+ _bottom_crop->wrapped()->Enable (single || multiple);
+
+ /* Things that are only allowed with single selections */
+ _frame_type->Enable (single);
+ _ratio->Enable (single);
+ _filters_button->Enable (single);
+ _colour_conversion_button->Enable (single);
+
+ film_content_changed (VideoContentProperty::VIDEO_FRAME_TYPE);
+ 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);
+}
+
+void
+VideoPanel::set_left_crop_same ()
+{
+ VideoContentList sel = _editor->selected_video_content ();
+ for (VideoContentList::iterator i = sel.begin(); i != sel.end(); ++i) {
+ (*i)->set_left_crop (sel.front()->left_crop ());
+ }
+}
+
#include "lib/film.h"
#include "film_editor_panel.h"
+#include "multiple_widget.h"
class wxChoice;
class wxStaticText;
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 set_left_crop_same ();
void left_crop_changed ();
void right_crop_changed ();
void top_crop_changed ();
void setup_description ();
wxChoice* _frame_type;
- wxSpinCtrl* _left_crop;
- wxSpinCtrl* _right_crop;
- wxSpinCtrl* _top_crop;
- wxSpinCtrl* _bottom_crop;
+ MultipleWidget<wxSpinCtrl>* _left_crop;
+ MultipleWidget<wxSpinCtrl>* _right_crop;
+ MultipleWidget<wxSpinCtrl>* _top_crop;
+ MultipleWidget<wxSpinCtrl>* _bottom_crop;
wxChoice* _ratio;
wxStaticText* _ratio_description;
wxStaticText* _description;