2 * Copyright (C) 2011 Carl Hetherington <carl@carlh.net>
3 * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
4 * Copyright (C) 2016 Paul Davis <paul@linuxaudiosystems.com>
6 * This program 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 * This program 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 along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <gtkmm/menu.h>
22 #include <gtkmm/menushell.h>
23 #include <gtkmm/treeview.h>
25 #include "pbd/strsplit.h"
26 #include "pbd/xml++.h"
28 #include "context_menu_helper.h"
29 #include "visibility_group.h"
35 VisibilityGroup::VisibilityGroup (std::string const & name)
36 : _xml_property_name (name)
37 , _ignore_list_view_change (false)
42 /** Add a widget to the group.
43 * @param widget The widget.
44 * @param id Some single-word ID to be used for the state of this member in XML.
45 * @param name User-visible name for the widget.
46 * @param visible true to default to visible, otherwise false.
47 * @param override A functor to decide whether the visibility specified by the member should be
48 * overridden by some external factor; if the returned optional value is given, it will be used
49 * to override whatever visibility setting the member has.
53 VisibilityGroup::add (Gtk::Widget* widget, string const & id, string const & name, bool visible, boost::function<boost::optional<bool> ()> override)
60 m.override = override;
62 _members.push_back (m);
65 /** Pop up a menu (on right-click) to configure visibility of members */
67 VisibilityGroup::button_press_event (GdkEventButton* ev)
69 if (ev->button != 3) {
73 using namespace Gtk::Menu_Helpers;
75 Gtk::Menu* m = ARDOUR_UI_UTILS::shared_popup_menu ();
76 MenuList& items = m->items ();
78 for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
79 items.push_back (CheckMenuElem (i->name));
80 Gtk::CheckMenuItem* j = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
81 j->set_active (i->visible);
82 j->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &VisibilityGroup::toggle), i));
85 m->popup (1, ev->time);
90 /** @return true if the member should be visible, even taking into account any override functor */
92 VisibilityGroup::should_actually_be_visible (Member const & m) const
95 boost::optional<bool> o = m.override ();
104 /** Update visible consequences of any changes to our _members vector */
106 VisibilityGroup::update ()
108 for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
110 if (should_actually_be_visible (*i)) {
120 VisibilityChanged (); /* EMIT SIGNAL */
124 VisibilityGroup::toggle (vector<Member>::iterator m)
126 m->visible = !m->visible;
131 VisibilityGroup::set_state (XMLNode const & node)
133 XMLProperty const * p = node.property (_xml_property_name);
138 set_state (p->value ());
142 VisibilityGroup::set_state (string v)
144 for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
149 string::size_type const comma = v.find_first_of (',');
150 string segment = v.substr (0, comma);
152 for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
153 if (segment == i->id) {
158 if (comma == string::npos) {
162 v = v.substr (comma + 1);
170 VisibilityGroup::remove_element (std::string const& from, std::string const& element)
172 std::vector<string> s;
175 split (from, s, ',');
176 for (std::vector<string>::const_iterator i = s.begin(); i != s.end(); ++i) {
177 if ((*i) == element) {
190 VisibilityGroup::add_element (std::string const& from, std::string const& element)
192 std::vector<string> s;
195 split (from, s, ',');
197 for (std::vector<string>::const_iterator i = s.begin(); i != s.end(); ++i) {
198 if ((*i) == element) {
199 /* already present, just return the original */
216 VisibilityGroup::get_state_name () const
218 return _xml_property_name;
222 VisibilityGroup::get_state_value () const
225 for (vector<Member>::const_iterator i = _members.begin(); i != _members.end(); ++i) {
227 if (!result.empty ()) {
238 VisibilityGroup::update_list_view ()
244 _ignore_list_view_change = true;
248 for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
249 Gtk::TreeModel::iterator j = _model->append ();
250 Gtk::TreeModel::Row row = *j;
251 row[_model_columns._visible] = i->visible;
252 row[_model_columns._name] = i->name;
253 row[_model_columns._iterator] = i;
256 _ignore_list_view_change = false;
260 VisibilityGroup::list_view ()
262 _model = Gtk::ListStore::create (_model_columns);
266 Gtk::TreeView* v = Gtk::manage (new Gtk::TreeView (_model));
267 v->set_headers_visible (false);
268 v->append_column ("", _model_columns._visible);
269 v->append_column ("", _model_columns._name);
271 Gtk::CellRendererToggle* visible_cell = dynamic_cast<Gtk::CellRendererToggle*> (v->get_column_cell_renderer (0));
272 visible_cell->property_activatable() = true;
273 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &VisibilityGroup::list_view_visible_changed));
278 VisibilityGroup::list_view_visible_changed (string const & path)
280 if (_ignore_list_view_change) {
284 Gtk::TreeModel::iterator i = _model->get_iter (path);
289 vector<Member>::iterator j = (*i)[_model_columns._iterator];
290 j->visible = !j->visible;
291 (*i)[_model_columns._visible] = j->visible;