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)
35 template <class S, class T>
39 /** @param parent Parent window.
40 * @param wrapped Control widget that we are wrapping.
41 * @param property ContentProperty that the widget is handling.
42 * @param getter Function on the Content to get the value.
43 * @param setter Function on the Content to set the value.
45 ContentWidget (wxWindow* parent, T* wrapped, int property, boost::function<int (S*)> getter, boost::function<void (S*, int)> setter)
48 , _button (new wxButton (parent, wxID_ANY, _("Multiple values")))
49 , _property (property)
52 , _ignore_model_changes (false)
54 _button->SetToolTip (_("Click the button to set all selected content to the same value."));
56 _button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentWidget::button_clicked, this));
57 _wrapped->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ContentWidget::view_changed, this));
64 typedef std::vector<boost::shared_ptr<S> > List;
66 void set_content (List content)
68 for (typename std::list<boost::signals2::connection>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
74 _wrapped->Enable (!_content.empty ());
78 for (typename List::iterator i = _content.begin(); i != _content.end(); ++i) {
79 _connections.push_back ((*i)->Changed.connect (boost::bind (&ContentWidget::model_changed, this, _2)));
83 void add (wxGridBagSizer* sizer, wxGBPosition position)
87 _sizer->Add (_wrapped, _position);
94 if (_wrapped->IsShown ()) {
98 _sizer->Detach (_button);
100 _sizer->Add (_wrapped, _position);
107 if (_button->IsShown ()) {
112 _sizer->Detach (_wrapped);
114 _sizer->Add (_button, _position);
118 void button_clicked ()
120 int const v = boost::bind (_getter, _content.front().get())();
121 for (typename List::iterator i = _content.begin (); i != _content.end(); ++i) {
122 boost::bind (_setter, i->get(), v) ();
128 for (size_t i = 0; i < _content.size(); ++i) {
129 /* Only update our view on the last time round this loop */
130 _ignore_model_changes = i < (_content.size() - 1);
131 boost::bind (_setter, _content[i].get(), _wrapped->GetValue ()) ();
135 void update_from_model ()
137 if (_content.empty ()) {
142 typename List::iterator i = _content.begin ();
143 int const v = boost::bind (_getter, _content.front().get())();
144 while (i != _content.end() && boost::bind (_getter, i->get())() == v) {
148 if (i == _content.end ()) {
150 checked_set (_wrapped, v);
156 void model_changed (int property)
158 if (property == _property && !_ignore_model_changes) {
159 update_from_model ();
164 wxGridBagSizer* _sizer;
165 wxGBPosition _position;
169 boost::function<int (S*)> _getter;
170 boost::function<void (S*, int)> _setter;
171 std::list<boost::signals2::connection> _connections;
172 bool _ignore_model_changes;