--- /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"
+
+/** 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
+++ /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
#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;
++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;
_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)
{
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) {
{
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);
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"
+#include "content_widget.h"
class wxChoice;
class wxStaticText;
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 ();
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;