Add missing files.
[ardour.git] / gtk2_ardour / visibility_group.cc
1 /*
2     Copyright (C) 2011 Paul Davis
3     Author: Carl Hetherington <cth@carlh.net>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include <gtkmm/menu.h>
22 #include <gtkmm/menushell.h>
23 #include <gtkmm/treeview.h>
24 #include "pbd/xml++.h"
25 #include "visibility_group.h"
26
27 #include "i18n.h"
28
29 using namespace std;
30
31 VisibilityGroup::VisibilityGroup (std::string const & name)
32         : _xml_property_name (name)
33         , _ignore_list_view_change (false)
34 {
35
36 }
37
38 /** Add a widget to the group.
39  *  @param widget The widget.
40  *  @param id Some single-word ID to be used for the state of this member in XML.
41  *  @param name User-visible name for the widget.
42  *  @param visible true to default to visible, otherwise false.
43  */
44
45 void
46 VisibilityGroup::add (Gtk::Widget* widget, string const & id, string const & name, bool visible)
47 {
48         Member m;
49         m.widget = widget;
50         m.id = id;
51         m.name = name;
52         m.visible = visible;
53         
54         _members.push_back (m);
55 }
56
57 /** Pop up a menu (on right-click) to configure visibility of members */
58 bool
59 VisibilityGroup::button_press_event (GdkEventButton* ev)
60 {
61         if (ev->button != 3) {
62                 return false;
63         }
64
65         menu()->popup (1, ev->time);
66         return true;
67 }
68
69 Gtk::Menu*
70 VisibilityGroup::menu ()
71 {
72         using namespace Gtk::Menu_Helpers;
73
74         Gtk::Menu* m = Gtk::manage (new Gtk::Menu);
75         MenuList& items = m->items ();
76
77         for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
78                 items.push_back (CheckMenuElem (i->name));
79                 Gtk::CheckMenuItem* j = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
80                 j->set_active (i->visible);
81                 j->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &VisibilityGroup::toggle), i));
82         }
83
84         return m;
85 }
86
87 /** Update visible consequences of any changes to our _members vector */
88 void
89 VisibilityGroup::update ()
90 {
91         for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
92                 if (i->widget) {
93                         if (i->visible) {
94                                 cout << "VG show " << i->name << "\n";
95                                 i->widget->show ();
96                         } else {
97                                 cout << "VG hide " << i->name << "\n";
98                                 i->widget->hide ();
99                         }
100                 }
101         }
102
103         update_list_view ();
104
105         VisibilityChanged (); /* EMIT SIGNAL */
106 }
107
108 void
109 VisibilityGroup::toggle (vector<Member>::iterator m)
110 {
111         m->visible = !m->visible;
112         update ();
113 }
114
115 void
116 VisibilityGroup::set_state (XMLNode const & node)
117 {
118         XMLProperty const * p = node.property (_xml_property_name);
119         if (!p) {
120                 return;
121         }
122
123         set_state (p->value ());
124 }
125
126 void
127 VisibilityGroup::set_state (string v)
128 {
129         for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
130                 i->visible = false;
131         }
132
133         do {
134                 string::size_type const comma = v.find_first_of (',');
135                 string segment = v.substr (0, comma);
136
137                 for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
138                         if (segment == i->id) {
139                                 i->visible = true;
140                         }
141                 }
142
143                 if (comma == string::npos) {
144                         break;
145                 }
146
147                 v = v.substr (comma + 1);
148                 
149         } while (1);
150
151         update ();
152 }
153
154 string
155 VisibilityGroup::get_state_name () const
156 {
157         return _xml_property_name;
158 }
159
160 string
161 VisibilityGroup::get_state_value () const
162 {
163         string result;
164         for (vector<Member>::const_iterator i = _members.begin(); i != _members.end(); ++i) {
165                 if (i->visible) {
166                         if (!result.empty ()) {
167                                 result += ',';
168                         }
169                         result += i->id;
170                 }
171         }
172
173         return result;
174 }
175
176 void
177 VisibilityGroup::update_list_view ()
178 {
179         if (!_model) {
180                 return;
181         }
182         
183         _ignore_list_view_change = true;
184
185         _model->clear ();
186         
187         for (vector<Member>::iterator i = _members.begin(); i != _members.end(); ++i) {
188                 Gtk::TreeModel::iterator j = _model->append ();
189                 Gtk::TreeModel::Row row = *j;
190                 row[_model_columns._visible] = i->visible;
191                 row[_model_columns._name] = i->name;
192                 row[_model_columns._iterator] = i;
193         }
194
195         _ignore_list_view_change = false;
196 }
197
198 Gtk::Widget *
199 VisibilityGroup::list_view ()
200 {
201         _model = Gtk::ListStore::create (_model_columns);
202
203         update_list_view ();
204
205         Gtk::TreeView* v = Gtk::manage (new Gtk::TreeView (_model));
206         v->set_headers_visible (false);
207         v->append_column (_(""), _model_columns._visible);
208         v->append_column (_(""), _model_columns._name);
209
210         Gtk::CellRendererToggle* visible_cell = dynamic_cast<Gtk::CellRendererToggle*> (v->get_column_cell_renderer (0));
211         visible_cell->property_activatable() = true;
212         visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &VisibilityGroup::list_view_visible_changed));
213         return v;
214 }
215
216 void
217 VisibilityGroup::list_view_visible_changed (string const & path)
218 {
219         if (_ignore_list_view_change) {
220                 return;
221         }
222         
223         Gtk::TreeModel::iterator i = _model->get_iter (path);
224         if (!i) {
225                 return;
226         }
227
228         vector<Member>::iterator j = (*i)[_model_columns._iterator];
229         j->visible = !j->visible;
230         (*i)[_model_columns._visible] = j->visible;
231
232         update ();
233 }