2 Copyright (C) 2013-2016 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 /** @file src/wx/content_widget.h
21 * @brief ContentWidget class.
24 #ifndef DCPOMATIC_CONTENT_WIDGET_H
25 #define DCPOMATIC_CONTENT_WIDGET_H
28 #include "lib/content.h"
30 #include <wx/gbsizer.h>
31 #include <wx/spinctrl.h>
32 #include <boost/function.hpp>
35 /** @class ContentWidget
36 * @brief A widget which represents some Content state and which can be used
37 * when multiple pieces of content are selected.
39 * @param S Type of ContentPart being manipulated (e.g. VideoContent)
40 * @param T Type of the widget (e.g. wxSpinCtrl)
41 * @param U Data type of state as used by the model.
42 * @param V Data type of state as used by the view.
44 template <class S, class T, typename U, typename V>
45 class ContentWidget : public boost::noncopyable
48 /** @param parent Parent window.
49 * @param wrapped Control widget that we are wrapping.
50 * @param property ContentProperty that the widget is handling.
51 * @param model_getter Function on the Content to get the value.
52 * @param model_setter Function on the Content to set the value.
58 boost::function<boost::shared_ptr<S> (Content*)> part,
59 boost::function<U (S*)> model_getter,
60 boost::function<void (S*, U)> model_setter,
61 boost::function<U (V)> view_to_model,
62 boost::function<V (U)> model_to_view
66 , _button (new wxButton (parent, wxID_ANY, _("Multiple values")))
67 , _property (property)
69 , _model_getter (model_getter)
70 , _model_setter (model_setter)
71 , _view_to_model (view_to_model)
72 , _model_to_view (model_to_view)
73 , _ignore_model_changes (false)
75 _button->SetToolTip (_("Click the button to set all selected content to the same value."));
77 _button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentWidget::button_clicked, this));
80 /** @return the widget that we are wrapping */
86 typedef std::vector<boost::shared_ptr<Content> > List;
88 /** Set the content that this control is working on (i.e. the selected content) */
89 void set_content (List content)
91 for (typename std::list<boost::signals2::connection>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
95 _connections.clear ();
99 _wrapped->Enable (!_content.empty ());
101 update_from_model ();
103 for (typename List::iterator i = _content.begin(); i != _content.end(); ++i) {
104 _connections.push_back ((*i)->Changed.connect (boost::bind (&ContentWidget::model_changed, this, _2)));
108 /** Add this widget to a wxGridBagSizer */
109 void add (wxGridBagSizer* sizer, wxGBPosition position, wxGBSpan span = wxDefaultSpan)
112 _position = position;
114 _sizer->Add (_wrapped, _position, _span);
117 /** Update the view from the model */
118 void update_from_model ()
120 if (_content.empty ()) {
125 typename List::iterator i = _content.begin ();
126 U const v = boost::bind (_model_getter, _part(_content.front().get()).get())();
127 while (i != _content.end() && boost::bind (_model_getter, _part(i->get()).get())() == v) {
131 if (i == _content.end ()) {
133 checked_set (_wrapped, _model_to_view (v));
141 _ignore_model_changes = true;
142 for (size_t i = 0; i < _content.size(); ++i) {
143 boost::bind (_model_setter, _part (_content[i].get()).get(), _view_to_model (wx_get (_wrapped))) ();
145 _ignore_model_changes = false;
152 if (_wrapped->IsShown ()) {
156 _sizer->Detach (_button);
158 _sizer->Add (_wrapped, _position, _span);
165 if (_button->IsShown ()) {
170 _sizer->Detach (_wrapped);
172 _sizer->Add (_button, _position, _span);
176 void button_clicked ()
178 U const v = boost::bind (_model_getter, _part(_content.front().get()).get())();
179 for (typename List::iterator i = _content.begin (); i != _content.end(); ++i) {
180 boost::bind (_model_setter, _part(i->get()).get(), v) ();
184 void model_changed (int property)
186 if (property == _property && !_ignore_model_changes) {
187 update_from_model ();
192 wxGridBagSizer* _sizer;
193 wxGBPosition _position;
198 boost::function<boost::shared_ptr<S> (Content *)> _part;
199 boost::function<U (S*)> _model_getter;
200 boost::function<void (S*, U)> _model_setter;
201 boost::function<U (V)> _view_to_model;
202 boost::function<V (U)> _model_to_view;
203 std::list<boost::signals2::connection> _connections;
204 bool _ignore_model_changes;
207 template <typename U, typename V>
210 return static_cast<V> (x);
214 class ContentSpinCtrl : public ContentWidget<S, wxSpinCtrl, int, int>
221 boost::function<boost::shared_ptr<S> (Content *)> part,
222 boost::function<int (S*)> getter,
223 boost::function<void (S*, int)> setter
225 : ContentWidget<S, wxSpinCtrl, int, int> (
235 wrapped->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ContentWidget<S, wxSpinCtrl, int, int>::view_changed, this));
240 class ContentSpinCtrlDouble : public ContentWidget<S, wxSpinCtrlDouble, double, double>
243 ContentSpinCtrlDouble (
245 wxSpinCtrlDouble* wrapped,
247 boost::function<boost::shared_ptr<S> (Content *)> part,
248 boost::function<double (S*)> getter,
249 boost::function<void (S*, double)> setter
251 : ContentWidget<S, wxSpinCtrlDouble, double, double> (
257 &caster<double, double>,
258 &caster<double, double>
261 wrapped->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ContentWidget<S, wxSpinCtrlDouble, double, double>::view_changed, this));
265 template <class S, class U>
266 class ContentChoice : public ContentWidget<S, wxChoice, U, int>
273 boost::function<boost::shared_ptr<S> (Content *)> part,
274 boost::function<U (S*)> getter,
275 boost::function<void (S*, U)> setter,
276 boost::function<U (int)> view_to_model,
277 boost::function<int (U)> model_to_view
279 : ContentWidget<S, wxChoice, U, int> (
290 wrapped->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ContentWidget<S, wxChoice, U, int>::view_changed, this));