Pull more stuff into ContentWidget.
authorCarl Hetherington <cth@carlh.net>
Mon, 11 Nov 2013 15:41:31 +0000 (15:41 +0000)
committerCarl Hetherington <cth@carlh.net>
Mon, 11 Nov 2013 15:41:31 +0000 (15:41 +0000)
src/wx/content_widget.h [new file with mode: 0644]
src/wx/multiple_widget.h [deleted file]
src/wx/video_panel.cc
src/wx/video_panel.h

diff --git a/src/wx/content_widget.h b/src/wx/content_widget.h
new file mode 100644 (file)
index 0000000..32fabda
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+    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)
+ */
+template <class S, class T>
+class ContentWidget
+{
+public:
+       /** @param parent Parent window.
+        *  @param wrapped Control widget that we are wrapping.
+        *  @param property ContentProperty that the widget is handling.
+        *  @param getter Function on the Content to get the value.
+        *  @param setter Function on the Content to set the value.
+        */
+       ContentWidget (wxWindow* parent, T* wrapped, int property, boost::function<int (S*)> getter, boost::function<void (S*, int)> setter)
+               : _wrapped (wrapped)
+               , _sizer (0)
+               , _button (new wxButton (parent, wxID_ANY, _("Multiple values")))
+               , _property (property)
+               , _getter (getter)
+               , _setter (setter)
+               , _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));
+               _wrapped->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ContentWidget::view_changed, 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 ();
+               }
+               
+               _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);
+       }
+
+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 ()
+       {
+               int const v = boost::bind (_getter, _content.front().get())();
+               for (typename List::iterator i = _content.begin (); i != _content.end(); ++i) {
+                       boost::bind (_setter, i->get(), v) ();
+               }
+       }
+
+       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 (_setter, _content[i].get(), _wrapped->GetValue ()) ();
+               }
+       }
+
+       void update_from_model ()
+       {
+               if (_content.empty ()) {
+                       set_single ();
+                       return;
+               }
+
+               typename List::iterator i = _content.begin ();
+               int const v = boost::bind (_getter, _content.front().get())();
+               while (i != _content.end() && boost::bind (_getter, i->get())() == v) {
+                       ++i;
+               }
+
+               if (i == _content.end ()) {
+                       set_single ();
+                       checked_set (_wrapped, v);
+               } else {
+                       set_multiple ();
+               }
+       }
+
+       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<int (S*)> _getter;
+       boost::function<void (S*, int)> _setter;
+       std::list<boost::signals2::connection> _connections;
+       bool _ignore_model_changes;
+};
+
+#endif
diff --git a/src/wx/multiple_widget.h b/src/wx/multiple_widget.h
deleted file mode 100644 (file)
index 7c0b4a6..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
-    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 3b4dc7e46f60c7d5660ca5ca56e087ea5352b438..ca1fd1ce8702c3d78154f1cd35ccdeb4eef75e4b 100644 (file)
@@ -29,7 +29,7 @@
 #include "wx_util.h"
 #include "film_editor.h"
 #include "content_colour_conversion_dialog.h"
-#include "multiple_widget.h"
+#include "content_widget.h"
 
 using std::vector;
 using std::string;
@@ -55,22 +55,46 @@ VideoPanel::VideoPanel (FilmEditor* e)
        ++r;
        
        add_label_to_grid_bag_sizer (grid, this, _("Left crop"), true, wxGBPosition (r, 0));
-       _left_crop = new MultipleWidget<wxSpinCtrl> (this, new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)));
+       _left_crop = new ContentWidget<VideoContent, wxSpinCtrl> (
+               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 MultipleWidget<wxSpinCtrl> (this, new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)));
+       _right_crop = new ContentWidget<VideoContent, wxSpinCtrl> (
+               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 MultipleWidget<wxSpinCtrl> (this, new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)));
+       _top_crop = new ContentWidget<VideoContent, wxSpinCtrl> (
+               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 MultipleWidget<wxSpinCtrl> (this, new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)));
+       _bottom_crop = new ContentWidget<VideoContent, wxSpinCtrl> (
+               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;
 
@@ -136,57 +160,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->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));
 }
 
-
-/** Called when the left crop widget has been changed */
-void
-VideoPanel::left_crop_changed ()
-{
-       VideoContentList c = _editor->selected_video_content ();
-       for (VideoContentList::iterator i = c.begin(); i != c.end(); ++i) {
-               (*i)->set_left_crop (_left_crop->wrapped()->GetValue ());
-       }
-}
-
-/** Called when the right crop widget has been changed */
-void
-VideoPanel::right_crop_changed ()
-{
-       VideoContentList c = _editor->selected_video_content ();
-       for (VideoContentList::iterator i = c.begin(); i != c.end(); ++i) {
-               (*i)->set_right_crop (_right_crop->wrapped()->GetValue ());
-       }
-}
-
-/** Called when the top crop widget has been changed */
-void
-VideoPanel::top_crop_changed ()
-{
-       VideoContentList c = _editor->selected_video_content ();
-       for (VideoContentList::iterator i = c.begin(); i != c.end(); ++i) {
-               (*i)->set_top_crop (_top_crop->wrapped()->GetValue ());
-       }
-}
-
-/** Called when the bottom crop value has been changed */
-void
-VideoPanel::bottom_crop_changed ()
-{
-       VideoContentList c = _editor->selected_video_content ();
-       for (VideoContentList::iterator i = c.begin(); i != c.end(); ++i) {
-               (*i)->set_bottom_crop (_bottom_crop->wrapped()->GetValue ());
-       }
-}
-
 void
 VideoPanel::film_changed (Film::Property property)
 {
@@ -215,10 +193,6 @@ VideoPanel::film_content_changed (int property)
                checked_set (_frame_type, vcs ? vcs->video_frame_type () : VIDEO_FRAME_TYPE_2D);
                setup_description ();
        } else if (property == VideoContentProperty::VIDEO_CROP) {
-               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 (vcs) {
@@ -404,13 +378,11 @@ 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);
+       _left_crop->set_content (sel);
+       _right_crop->set_content (sel);
+       _top_crop->set_content (sel);
+       _bottom_crop->set_content (sel);
 
        /* Things that are only allowed with single selections */
        _frame_type->Enable (single);
@@ -425,13 +397,3 @@ VideoPanel::content_selection_changed ()
        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 5b0c958809045e9563480a20bdc16160c7c137be..b4e0eb71bed75a02174ee28720dda48ea9ce0920 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "lib/film.h"
 #include "film_editor_panel.h"
-#include "multiple_widget.h"
+#include "content_widget.h"
 
 class wxChoice;
 class wxStaticText;
@@ -36,11 +36,6 @@ public:
        void content_selection_changed ();
 
 private:
-       void set_left_crop_same ();
-       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 ();
@@ -49,10 +44,10 @@ private:
        void setup_description ();
 
        wxChoice* _frame_type;
-       MultipleWidget<wxSpinCtrl>* _left_crop;
-       MultipleWidget<wxSpinCtrl>* _right_crop;
-       MultipleWidget<wxSpinCtrl>* _top_crop;
-       MultipleWidget<wxSpinCtrl>* _bottom_crop;
+       ContentWidget<VideoContent, wxSpinCtrl>* _left_crop;
+       ContentWidget<VideoContent, wxSpinCtrl>* _right_crop;
+       ContentWidget<VideoContent, wxSpinCtrl>* _top_crop;
+       ContentWidget<VideoContent, wxSpinCtrl>* _bottom_crop;
        wxChoice* _ratio;
        wxStaticText* _ratio_description;
        wxStaticText* _description;