2 Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #ifndef DCPOMATIC_MULTIPLE_WIDGET_H
21 #define DCPOMATIC_MULTIPLE_WIDGET_H
25 #include <wx/gbsizer.h>
26 #include <boost/function.hpp>
29 /** A widget which represents some Content state and which can be used
30 * when multiple pieces of content are selected.
32 * @param S Type containing the content being represented (e.g. VideoContent)
33 * @param T Type of the widget (e.g. wxSpinCtrl)
34 * @param U Data type of state as used by the model.
35 * @param V Data type of state as used by the view.
37 template <class S, class T, typename U, typename V>
41 /** @param parent Parent window.
42 * @param wrapped Control widget that we are wrapping.
43 * @param property ContentProperty that the widget is handling.
44 * @param model_getter Function on the Content to get the value.
45 * @param model_setter Function on the Content to set the value.
51 boost::function<U (S*)> model_getter,
52 boost::function<void (S*, U)> model_setter,
53 boost::function<V (T*)> view_getter
57 , _button (new wxButton (parent, wxID_ANY, _("Multiple values")))
58 , _property (property)
59 , _model_getter (model_getter)
60 , _model_setter (model_setter)
61 , _view_getter (view_getter)
62 , _ignore_model_changes (false)
64 _button->SetToolTip (_("Click the button to set all selected content to the same value."));
66 _button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentWidget::button_clicked, this));
73 typedef std::vector<boost::shared_ptr<S> > List;
75 void set_content (List content)
77 for (typename std::list<boost::signals2::connection>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
81 _connections.clear ();
85 _wrapped->Enable (!_content.empty ());
89 for (typename List::iterator i = _content.begin(); i != _content.end(); ++i) {
90 _connections.push_back ((*i)->Changed.connect (boost::bind (&ContentWidget::model_changed, this, _2)));
94 void add (wxGridBagSizer* sizer, wxGBPosition position)
98 _sizer->Add (_wrapped, _position);
101 void update_from_model ()
103 if (_content.empty ()) {
108 typename List::iterator i = _content.begin ();
109 U const v = boost::bind (_model_getter, _content.front().get())();
110 while (i != _content.end() && boost::bind (_model_getter, i->get())() == v) {
114 if (i == _content.end ()) {
116 checked_set (_wrapped, v);
124 for (size_t i = 0; i < _content.size(); ++i) {
125 /* Only update our view on the last time round this loop */
126 _ignore_model_changes = i < (_content.size() - 1);
127 boost::bind (_model_setter, _content[i].get(), static_cast<U> (boost::bind (_view_getter, _wrapped)()))();
135 if (_wrapped->IsShown ()) {
139 _sizer->Detach (_button);
141 _sizer->Add (_wrapped, _position);
148 if (_button->IsShown ()) {
153 _sizer->Detach (_wrapped);
155 _sizer->Add (_button, _position);
159 void button_clicked ()
161 U const v = boost::bind (_model_getter, _content.front().get())();
162 for (typename List::iterator i = _content.begin (); i != _content.end(); ++i) {
163 boost::bind (_model_setter, i->get(), v) ();
167 void model_changed (int property)
169 if (property == _property && !_ignore_model_changes) {
170 update_from_model ();
175 wxGridBagSizer* _sizer;
176 wxGBPosition _position;
180 boost::function<U (S*)> _model_getter;
181 boost::function<void (S*, U)> _model_setter;
182 boost::function<V (T*)> _view_getter;
183 std::list<boost::signals2::connection> _connections;
184 bool _ignore_model_changes;
188 class ContentSpinCtrl : public ContentWidget<S, wxSpinCtrl, int, int>
191 ContentSpinCtrl (wxWindow* parent, wxSpinCtrl* wrapped, int property, boost::function<int (S*)> getter, boost::function<void (S*, int)> setter)
192 : ContentWidget<S, wxSpinCtrl, int, int> (parent, wrapped, property, getter, setter, boost::mem_fn (&wxSpinCtrl::GetValue))
194 wrapped->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ContentWidget<S, wxSpinCtrl, int, int>::view_changed, this));
199 template <class S, class U>
200 class ContentChoice : public ContentWidget<S, wxChoice, U, int>
203 ContentChoice (wxWindow* parent, wxChoice* wrapped, int property, boost::function<U (S*)> getter, boost::function<void (S*, U)> setter)
204 : ContentWidget<S, wxChoice, U, int> (parent, wrapped, property, getter, setter, boost::mem_fn (&wxChoice::GetSelection))
206 wrapped->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ContentWidget<S, wxChoice, U, int>::view_changed, this));