Add ratio control to multi-select.
authorCarl Hetherington <cth@carlh.net>
Thu, 14 Nov 2013 13:40:35 +0000 (13:40 +0000)
committerCarl Hetherington <cth@carlh.net>
Thu, 14 Nov 2013 13:40:35 +0000 (13:40 +0000)
src/wx/content_widget.h
src/wx/video_panel.cc
src/wx/video_panel.h
src/wx/wx_util.cc
src/wx/wx_util.h

index 07abc7cbdf8d1de81140b691d03d112be4534689..30501c1a95f513700289e31fe183874e473ade80 100644 (file)
@@ -50,7 +50,8 @@ public:
                int property,
                boost::function<U (S*)> model_getter,
                boost::function<void (S*, U)> model_setter,
-               boost::function<V (T*)> view_getter
+               boost::function<U (V)> view_to_model,
+               boost::function<V (U)> model_to_view
                )
                : _wrapped (wrapped)
                , _sizer (0)
@@ -58,7 +59,8 @@ public:
                , _property (property)
                , _model_getter (model_getter)
                , _model_setter (model_setter)
-               , _view_getter (view_getter)
+               , _view_to_model (view_to_model)
+               , _model_to_view (model_to_view)
                , _ignore_model_changes (false)
        {
                _button->SetToolTip (_("Click the button to set all selected content to the same value."));
@@ -66,12 +68,15 @@ public:
                _button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentWidget::button_clicked, this));
        }
 
-       T* wrapped () const {
+       /** @return the widget that we are wrapping */
+       T* wrapped () const
+       {
                return _wrapped;
        }
 
        typedef std::vector<boost::shared_ptr<S> > List;
 
+       /** Set the content that this control is working on (i.e. the selected content) */
        void set_content (List content)
        {
                for (typename std::list<boost::signals2::connection>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
@@ -91,6 +96,7 @@ public:
                }
        }
 
+       /** Add this widget to a wxGridBagSizer */
        void add (wxGridBagSizer* sizer, wxGBPosition position)
        {
                _sizer = sizer;
@@ -98,6 +104,7 @@ public:
                _sizer->Add (_wrapped, _position);
        }
 
+       /** Update the view from the model */
        void update_from_model ()
        {
                if (_content.empty ()) {
@@ -113,7 +120,7 @@ public:
 
                if (i == _content.end ()) {
                        set_single ();
-                       checked_set (_wrapped, v);
+                       checked_set (_wrapped, _model_to_view (v));
                } else {
                        set_multiple ();
                }
@@ -121,11 +128,11 @@ public:
 
        void view_changed ()
        {
+               _ignore_model_changes = true;
                for (size_t i = 0; i < _content.size(); ++i) {
-                       /* Only update our view on the last time round this loop */
-                       _ignore_model_changes = i < (_content.size() - 1);
-                       boost::bind (_model_setter, _content[i].get(), static_cast<U> (boost::bind (_view_getter, _wrapped)()))();
+                       boost::bind (_model_setter, _content[i].get(), _view_to_model (wx_get (_wrapped))) ();
                }
+               _ignore_model_changes = false;
        }
        
 private:
@@ -179,29 +186,64 @@ private:
        int _property;
        boost::function<U (S*)> _model_getter;
        boost::function<void (S*, U)> _model_setter;
-       boost::function<V (T*)> _view_getter;
+       boost::function<U (V)> _view_to_model;
+       boost::function<V (U)> _model_to_view;
        std::list<boost::signals2::connection> _connections;
        bool _ignore_model_changes;
 };
 
+template <typename U, typename V>
+V caster (U x)
+{
+       return static_cast<V> (x);
+}
+
 template <class S>
 class ContentSpinCtrl : public ContentWidget<S, wxSpinCtrl, int, int>
 {
 public:
-       ContentSpinCtrl (wxWindow* parent, wxSpinCtrl* wrapped, int property, boost::function<int (S*)> getter, boost::function<void (S*, int)> setter)
-               : ContentWidget<S, wxSpinCtrl, int, int> (parent, wrapped, property, getter, setter, boost::mem_fn (&wxSpinCtrl::GetValue))
+       ContentSpinCtrl (
+               wxWindow* parent,
+               wxSpinCtrl* wrapped,
+               int property,
+               boost::function<int (S*)> getter,
+               boost::function<void (S*, int)> setter
+               )
+               : ContentWidget<S, wxSpinCtrl, int, int> (
+                       parent,
+                       wrapped,
+                       property,
+                       getter, setter,
+                       &caster<int, int>,
+                       &caster<int, int>
+                       )
        {
                wrapped->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ContentWidget<S, wxSpinCtrl, int, int>::view_changed, this));
        }
-
 };
 
 template <class S, class U>
 class ContentChoice : public ContentWidget<S, wxChoice, U, int>
 {
 public:
-       ContentChoice (wxWindow* parent, wxChoice* wrapped, int property, boost::function<U (S*)> getter, boost::function<void (S*, U)> setter)
-               : ContentWidget<S, wxChoice, U, int> (parent, wrapped, property, getter, setter, boost::mem_fn (&wxChoice::GetSelection))
+       ContentChoice (
+               wxWindow* parent,
+               wxChoice* wrapped,
+               int property,
+               boost::function<U (S*)> getter,
+               boost::function<void (S*, U)> setter,
+               boost::function<U (int)> view_to_model,
+               boost::function<int (U)> model_to_view
+               )
+               : ContentWidget<S, wxChoice, U, int> (
+                       parent,
+                       wrapped,
+                       property,
+                       getter,
+                       setter,
+                       view_to_model,
+                       model_to_view
+                       )
        {
                wrapped->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ContentWidget<S, wxChoice, U, int>::view_changed, this));
        }
index 9adc64641ab387e49b9116eae0b9ee38af3b50c9..5d841b0cc45d6c5b5c3481076e85c657febc16c4 100644 (file)
@@ -41,6 +41,31 @@ using boost::dynamic_pointer_cast;
 using boost::bind;
 using boost::optional;
 
+static Ratio const *
+index_to_ratio (int n)
+{
+       assert (n >= 0);
+       
+       vector<Ratio const *> ratios = Ratio::all ();
+       if (n >= int (ratios.size ())) {
+               return 0;
+       }
+
+       return ratios[n];
+}
+
+static int
+ratio_to_index (Ratio const * r)
+{
+       vector<Ratio const *> ratios = Ratio::all ();
+       size_t i = 0;
+       while (i < ratios.size() && ratios[i] != r) {
+               ++i;
+       }
+
+       return i;
+}
+
 VideoPanel::VideoPanel (FilmEditor* e)
        : FilmEditorPanel (e, _("Video"))
 {
@@ -55,7 +80,9 @@ VideoPanel::VideoPanel (FilmEditor* e)
                new wxChoice (this, wxID_ANY),
                VideoContentProperty::VIDEO_FRAME_TYPE,
                boost::mem_fn (&VideoContent::video_frame_type),
-               boost::mem_fn (&VideoContent::set_video_frame_type)
+               boost::mem_fn (&VideoContent::set_video_frame_type),
+               &caster<int, VideoFrameType>,
+               &caster<VideoFrameType, int>
                );
        _frame_type->add (grid, wxGBPosition (r, 1));
        ++r;
@@ -105,8 +132,16 @@ VideoPanel::VideoPanel (FilmEditor* e)
        ++r;
 
        add_label_to_grid_bag_sizer (grid, this, _("Scale to"), true, wxGBPosition (r, 0));
-       _ratio = new wxChoice (this, wxID_ANY);
-       grid->Add (_ratio, wxGBPosition (r, 1));
+       _ratio = new ContentChoice<VideoContent, Ratio const *> (
+               this,
+               new wxChoice (this, wxID_ANY),
+               VideoContentProperty::VIDEO_RATIO,
+               boost::mem_fn (&VideoContent::ratio),
+               boost::mem_fn (&VideoContent::set_ratio),
+               &index_to_ratio,
+               &ratio_to_index
+               );
+       _ratio->add (grid, wxGBPosition (r, 1));
        ++r;
 
        {
@@ -156,16 +191,15 @@ VideoPanel::VideoPanel (FilmEditor* e)
        _bottom_crop->wrapped()->SetRange (0, 1024);
 
        vector<Ratio const *> ratios = Ratio::all ();
-       _ratio->Clear ();
+       _ratio->wrapped()->Clear ();
        for (vector<Ratio const *>::iterator i = ratios.begin(); i != ratios.end(); ++i) {
-               _ratio->Append (std_to_wx ((*i)->nickname ()));
+               _ratio->wrapped()->Append (std_to_wx ((*i)->nickname ()));
        }
-       _ratio->Append (_("No stretch"));
+       _ratio->wrapped()->Append (_("No stretch"));
 
        _frame_type->wrapped()->Append (_("2D"));
        _frame_type->wrapped()->Append (_("3D left/right"));
 
-       _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));
 }
@@ -199,23 +233,6 @@ VideoPanel::film_content_changed (int property)
        } else if (property == VideoContentProperty::VIDEO_CROP) {
                setup_description ();
        } else if (property == VideoContentProperty::VIDEO_RATIO) {
-               if (vcs) {
-                       int n = 0;
-                       vector<Ratio const *> ratios = Ratio::all ();
-                       vector<Ratio const *>::iterator i = ratios.begin ();
-                       while (i != ratios.end() && *i != vcs->ratio()) {
-                               ++i;
-                               ++n;
-                       }
-
-                       if (i == ratios.end()) {
-                               checked_set (_ratio, ratios.size ());
-                       } else {
-                               checked_set (_ratio, n);
-                       }
-               } else {
-                       checked_set (_ratio, -1);
-               }
                setup_description ();
        } else if (property == VideoContentProperty::VIDEO_FRAME_RATE) {
                setup_description ();
@@ -327,30 +344,6 @@ VideoPanel::setup_description ()
        _sizer->Layout ();
 }
 
-
-void
-VideoPanel::ratio_changed ()
-{
-       if (!_editor->film ()) {
-               return;
-       }
-
-       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.front()->set_ratio (ratios[n]);
-               } else {
-                       vc.front()->set_ratio (0);
-               }
-       }
-}
-
 void
 VideoPanel::edit_colour_conversion_clicked ()
 {
@@ -379,14 +372,13 @@ VideoPanel::content_selection_changed ()
        _top_crop->set_content (sel);
        _bottom_crop->set_content (sel);
        _frame_type->set_content (sel);
+       _ratio->set_content (sel);
 
        /* Things that are only allowed with single selections */
-       _ratio->Enable (single);
        _filters_button->Enable (single);
        _colour_conversion_button->Enable (single);
 
        film_content_changed (VideoContentProperty::VIDEO_CROP);
-       film_content_changed (VideoContentProperty::VIDEO_RATIO);
        film_content_changed (VideoContentProperty::VIDEO_FRAME_RATE);
        film_content_changed (VideoContentProperty::COLOUR_CONVERSION);
        film_content_changed (FFmpegContentProperty::FILTERS);
index 577bbf0e77e8a210472e5111812571757ce3e901..fb1f98b29777c83be18ed45fb1774efa6c029949 100644 (file)
@@ -37,7 +37,6 @@ public:
 
 private:
        void edit_filters_clicked ();
-       void ratio_changed ();
        void edit_colour_conversion_clicked ();
 
        void setup_description ();
@@ -47,7 +46,7 @@ private:
        ContentSpinCtrl<VideoContent>*               _right_crop;
        ContentSpinCtrl<VideoContent>*               _top_crop;
        ContentSpinCtrl<VideoContent>*               _bottom_crop;
-       wxChoice* _ratio;
+       ContentChoice<VideoContent, Ratio const *>*  _ratio;
        wxStaticText* _ratio_description;
        wxStaticText* _description;
        wxStaticText* _filters;
index 515550e5901b91327f49de0942df230bb7d10c55..27a4554ca61d5534994cbd6f794c1f289a44060c 100644 (file)
@@ -277,3 +277,15 @@ dcpomatic_setup_i18n ()
                dcpomatic_setup_gettext_i18n (wx_to_std (locale->GetCanonicalName ()));
        }
 }
+
+int
+wx_get (wxSpinCtrl* w)
+{
+       return w->GetValue ();
+}
+
+int
+wx_get (wxChoice* w)
+{
+       return w->GetSelection ();
+}
index 48683492c3599428b1b8f947d0ea77885394a652..8ac824c508d81d1edc5640de2df33f7a792cfdc2 100644 (file)
@@ -84,6 +84,9 @@ extern void checked_set (wxCheckBox* widget, bool value);
 extern void checked_set (wxRadioButton* widget, bool value);
 extern void checked_set (wxStaticText* widget, std::string value);
 
+extern int wx_get (wxChoice* widget);
+extern int wx_get (wxSpinCtrl* widget);
+
 /* GTK 2.24.17 has a buggy GtkFileChooserButton and it was put in Ubuntu 13.04.
    This also seems to apply to 2.24.20 in Ubuntu 13.10
    Use our own dir picker as this is the least bad option I can think of.