diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-11-11 15:41:31 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-11-11 15:41:31 +0000 |
| commit | 1e1e5b454c72d818c9fe142296d489c7983a5849 (patch) | |
| tree | 005fcb5d09e5f4cfe204308db63f0b85a4cd2165 /src/wx/content_widget.h | |
| parent | cb83eb7b209054da2f81b456a0fbda6ea9d03844 (diff) | |
Pull more stuff into ContentWidget.
Diffstat (limited to 'src/wx/content_widget.h')
| -rw-r--r-- | src/wx/content_widget.h | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/wx/content_widget.h b/src/wx/content_widget.h new file mode 100644 index 000000000..32fabda97 --- /dev/null +++ b/src/wx/content_widget.h @@ -0,0 +1,175 @@ +/* + 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 |
