Basic multiple selection for cropping.
authorCarl Hetherington <cth@carlh.net>
Mon, 11 Nov 2013 12:53:26 +0000 (12:53 +0000)
committerCarl Hetherington <cth@carlh.net>
Mon, 11 Nov 2013 12:53:26 +0000 (12:53 +0000)
14 files changed:
src/lib/types.h
src/lib/video_content.h
src/wx/audio_panel.cc
src/wx/audio_panel.h
src/wx/film_editor.cc
src/wx/film_editor.h
src/wx/film_editor_panel.h
src/wx/multiple_widget.h [new file with mode: 0644]
src/wx/subtitle_panel.cc
src/wx/subtitle_panel.h
src/wx/timing_panel.cc
src/wx/timing_panel.h
src/wx/video_panel.cc
src/wx/video_panel.h

index ad706270e66a79d2ace667d79604f35bc9c69de4..448b6c154bac00faae280e78a5c927f1bf1ea5a9 100644 (file)
@@ -29,6 +29,7 @@ class Content;
 class VideoContent;
 class AudioContent;
 class SubtitleContent;
+class FFmpegContent;
 class AudioBuffers;
 
 /** The version number of the protocol used to communicate
@@ -46,6 +47,7 @@ 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
index 6f80536fe4a4d6eb64c317a92b7789b107f025d4..106adf959cf4ff43f3cd039acd15dd493a633533 100644 (file)
@@ -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. */
index f96eeec2b74ff77d6ba05c94b3ba95fbf11cafbd..e2ea15f645b49af72984e848572ee1e238e3c118 100644 (file)
@@ -112,35 +112,40 @@ 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);
+               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 ();
                        }
                }
@@ -150,23 +155,23 @@ AudioPanel::film_content_changed (shared_ptr<Content> c, int property)
 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
@@ -203,39 +208,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 +240,7 @@ AudioPanel::stream_changed ()
        }
 
        if (i != a.end ()) {
-               fc->set_audio_stream (*i);
+               fcs->set_audio_stream (*i);
        }
 
        setup_stream_description ();
@@ -252,26 +249,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 +273,14 @@ 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 ()
+{
+
+}
index e1dc283e2852debd1d021baa2900567b7b7112fa..8cb94f0fa6efdf6ad8ba4f7797946962abf2b98c 100644 (file)
@@ -33,7 +33,8 @@ 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 ();
index 99b3c59a5e6450f1848b2c2e56ffc8eb64521953..fd1dd2b33ac7a5b1b727289d61ef0fd8d8ef15e5 100644 (file)
@@ -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,17 +795,18 @@ 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 ();
 
-       _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
@@ -843,7 +820,7 @@ FilmEditor::selected_content ()
                        break;
                }
 
-               sel.push_back (_film->content[s]);
+               sel.push_back (_film->content()[s]);
        }
 
        return sel;
@@ -897,6 +874,22 @@ FilmEditor::selected_subtitle_content ()
        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 ()
 {
@@ -935,11 +928,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
@@ -955,13 +944,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 ();
+       }
 }
index 9808e0d2f8f76aaa7f2729d53bfb27135d5833c7..7fd61e5fc5650e7e31e0ad585d566c5362c8e460 100644 (file)
@@ -66,6 +66,7 @@ public:
        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 ();
index 8acb3efb6d8ef651f6f516deeb695a5deba63a4a..e0514ba99d89ca6a42034e96ca77fd05a75ea803 100644 (file)
@@ -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/multiple_widget.h b/src/wx/multiple_widget.h
new file mode 100644 (file)
index 0000000..7c0b4a6
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+    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
index 8f2b08af51dd263dce782f3164c81a41566d8113..c820220d4940bb9db8abd75bed68d3bd1f3343b5 100644 (file)
@@ -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);
 }
 
+       
index 3f795189593dba1972715760686d4149c7b7db48..19df26436af6c79cd7c8712d6ba568616dbac2a0 100644 (file)
@@ -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 ();
index ba645cf3240bd7239588cdd6c81469c160b42afc..512a83cd9cec1e18863216df6695b278e767eb59 100644 (file)
@@ -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 ()));
 }
index b84ea52be644030be6b852958ce3e1899f7d3cf8..8c519bcbe77b9520b7a152e12ac7f2278a32df96 100644 (file)
@@ -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 ();
index a643832e89dd53e56aee6c73a260ade51eaa819f..3b4dc7e46f60c7d5660ca5ca56e087ea5352b438 100644 (file)
@@ -29,6 +29,7 @@
 #include "wx_util.h"
 #include "film_editor.h"
 #include "content_colour_conversion_dialog.h"
+#include "multiple_widget.h"
 
 using std::vector;
 using std::string;
@@ -54,23 +55,23 @@ VideoPanel::VideoPanel (FilmEditor* e)
        ++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));
@@ -119,10 +120,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 ();
@@ -135,10 +136,11 @@ VideoPanel::VideoPanel (FilmEditor* e)
        _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));
@@ -149,48 +151,40 @@ VideoPanel::VideoPanel (FilmEditor* e)
 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
@@ -207,26 +201,31 @@ 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);
+               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;
                        }
@@ -243,12 +242,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 +262,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 +276,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 +312,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 +335,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,15 +357,18 @@ 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);
                }
        }
 }
@@ -374,25 +376,62 @@ VideoPanel::ratio_changed ()
 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 ());
+       }
+}
+
index 2ecf3c87f449135756c21e280c439cc63abeb6ce..5b0c958809045e9563480a20bdc16160c7c137be 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "lib/film.h"
 #include "film_editor_panel.h"
+#include "multiple_widget.h"
 
 class wxChoice;
 class wxStaticText;
@@ -31,9 +32,11 @@ 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 set_left_crop_same ();
        void left_crop_changed ();
        void right_crop_changed ();
        void top_crop_changed ();
@@ -46,10 +49,10 @@ private:
        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;