2 Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
21 /** @file src/wx/content_widget.h
22 * @brief ContentWidget class.
25 #ifndef DCPOMATIC_CONTENT_WIDGET_H
26 #define DCPOMATIC_CONTENT_WIDGET_H
29 #include "lib/content.h"
31 #include <wx/gbsizer.h>
32 #include <wx/spinctrl.h>
33 #include <boost/function.hpp>
36 /** @class ContentWidget
37 * @brief A widget which represents some Content state and which can be used
38 * when multiple pieces of content are selected.
40 * @param S Type of ContentPart being manipulated (e.g. VideoContent)
41 * @param T Type of the widget (e.g. wxSpinCtrl)
42 * @param U Data type of state as used by the model.
43 * @param V Data type of state as used by the view.
45 template <class S, class T, typename U, typename V>
46 class ContentWidget : public boost::noncopyable
49 /** @param parent Parent window.
50 * @param wrapped Control widget that we are wrapping.
51 * @param property ContentProperty that the widget is handling.
52 * @param model_getter Function on the Content to get the value.
53 * @param model_setter Function on the Content to set the value.
59 boost::function<boost::shared_ptr<S> (Content*)> part,
60 boost::function<U (S*)> model_getter,
61 boost::function<void (S*, U)> model_setter,
62 boost::function<U (V)> view_to_model,
63 boost::function<V (U)> model_to_view
67 , _button (new wxButton (parent, wxID_ANY, _("Multiple values")))
68 , _property (property)
70 , _model_getter (model_getter)
71 , _model_setter (model_setter)
72 , _view_to_model (view_to_model)
73 , _model_to_view (model_to_view)
74 , _ignore_model_changes (false)
76 _button->SetToolTip (_("Click the button to set all selected content to the same value."));
78 _button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&ContentWidget::button_clicked, this));
81 /** @return the widget that we are wrapping */
87 typedef std::vector<boost::shared_ptr<Content> > List;
89 /** Set the content that this control is working on (i.e. the selected content) */
90 void set_content (List content)
92 for (typename std::list<boost::signals2::connection>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
96 _connections.clear ();
100 _wrapped->Enable (!_content.empty ());
102 update_from_model ();
104 for (typename List::iterator i = _content.begin(); i != _content.end(); ++i) {
105 _connections.push_back ((*i)->Changed.connect (boost::bind (&ContentWidget::model_changed, this, _2)));
109 /** Add this widget to a wxGridBagSizer */
110 void add (wxGridBagSizer* sizer, wxGBPosition position, wxGBSpan span = wxDefaultSpan)
113 _position = position;
115 _sizer->Add (_wrapped, _position, _span);
118 /** Update the view from the model */
119 void update_from_model ()
121 if (_content.empty ()) {
126 typename List::iterator i = _content.begin ();
127 U const v = boost::bind (_model_getter, _part(_content.front().get()).get())();
128 while (i != _content.end() && boost::bind (_model_getter, _part(i->get()).get())() == v) {
132 if (i == _content.end ()) {
134 checked_set (_wrapped, _model_to_view (v));
142 _ignore_model_changes = true;
143 for (size_t i = 0; i < _content.size(); ++i) {
144 boost::bind (_model_setter, _part (_content[i].get()).get(), _view_to_model (wx_get (_wrapped))) ();
146 _ignore_model_changes = false;
153 if (_wrapped->IsShown ()) {
157 _sizer->Detach (_button);
159 _sizer->Add (_wrapped, _position, _span);
166 if (_button->IsShown ()) {
171 _sizer->Detach (_wrapped);
173 _sizer->Add (_button, _position, _span);
177 void button_clicked ()
179 U const v = boost::bind (_model_getter, _part(_content.front().get()).get())();
180 for (typename List::iterator i = _content.begin (); i != _content.end(); ++i) {
181 boost::bind (_model_setter, _part(i->get()).get(), v) ();
185 void model_changed (int property)
187 if (property == _property && !_ignore_model_changes) {
188 update_from_model ();
193 wxGridBagSizer* _sizer;
194 wxGBPosition _position;
199 boost::function<boost::shared_ptr<S> (Content *)> _part;
200 boost::function<U (S*)> _model_getter;
201 boost::function<void (S*, U)> _model_setter;
202 boost::function<U (V)> _view_to_model;
203 boost::function<V (U)> _model_to_view;
204 std::list<boost::signals2::connection> _connections;
205 bool _ignore_model_changes;
208 template <typename U, typename V>
211 return static_cast<V> (x);
215 class ContentSpinCtrl : public ContentWidget<S, wxSpinCtrl, int, int>
222 boost::function<boost::shared_ptr<S> (Content *)> part,
223 boost::function<int (S*)> getter,
224 boost::function<void (S*, int)> setter
226 : ContentWidget<S, wxSpinCtrl, int, int> (
236 wrapped->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&ContentWidget<S, wxSpinCtrl, int, int>::view_changed, this));
241 class ContentSpinCtrlDouble : public ContentWidget<S, wxSpinCtrlDouble, double, double>
244 ContentSpinCtrlDouble (
246 wxSpinCtrlDouble* wrapped,
248 boost::function<boost::shared_ptr<S> (Content *)> part,
249 boost::function<double (S*)> getter,
250 boost::function<void (S*, double)> setter
252 : ContentWidget<S, wxSpinCtrlDouble, double, double> (
258 &caster<double, double>,
259 &caster<double, double>
262 wrapped->Bind (wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, boost::bind (&ContentWidget<S, wxSpinCtrlDouble, double, double>::view_changed, this));
266 template <class S, class U>
267 class ContentChoice : public ContentWidget<S, wxChoice, U, int>
274 boost::function<boost::shared_ptr<S> (Content *)> part,
275 boost::function<U (S*)> getter,
276 boost::function<void (S*, U)> setter,
277 boost::function<U (int)> view_to_model,
278 boost::function<int (U)> model_to_view
280 : ContentWidget<S, wxChoice, U, int> (
291 wrapped->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&ContentWidget<S, wxChoice, U, int>::view_changed, this));