1086e44bfbe507bb18f0d82c400c719febdb6cd2
[ardour.git] / libs / surfaces / mackie / gui.cc
1 /*
2         Copyright (C) 2010 Paul Davis
3
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.
8
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.
13
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.
17 */
18
19 #include <gtkmm/comboboxtext.h>
20 #include <gtkmm/box.h>
21 #include <gtkmm/spinbutton.h>
22 #include <gtkmm/table.h>
23 #include <gtkmm/treeview.h>
24 #include <gtkmm/liststore.h>
25 #include <gtkmm/treestore.h>
26 #include <gtkmm/notebook.h>
27 #include <gtkmm/cellrenderercombo.h>
28
29 #include "pbd/strsplit.h"
30
31 #include "gtkmm2ext/utils.h"
32 #include "gtkmm2ext/actions.h"
33
34 #include "mackie_control_protocol.h"
35 #include "device_info.h"
36 #include "gui.h"
37
38 #include "i18n.h"
39
40 using namespace std;
41 using namespace Mackie;
42 using namespace Gtk;
43
44 void*
45 MackieControlProtocol::get_gui () const
46 {
47         if (!_gui) {
48                 const_cast<MackieControlProtocol*>(this)->build_gui ();
49         }
50
51         return _gui;
52 }
53
54 void
55 MackieControlProtocol::tear_down_gui ()
56 {
57         delete (MackieControlProtocolGUI*) _gui;
58 }
59
60 void
61 MackieControlProtocol::build_gui ()
62 {
63         _gui = (void *) new MackieControlProtocolGUI (*this);
64 }
65
66 MackieControlProtocolGUI::MackieControlProtocolGUI (MackieControlProtocol& p)
67         : _cp (p)
68 {
69         set_border_width (12);
70
71         Gtk::Table* table = Gtk::manage (new Gtk::Table (2, 2));
72         table->set_spacings (4);
73         
74         table->attach (*manage (new Gtk::Label (_("Surface type:"))), 0, 1, 0, 1, AttachOptions(FILL|EXPAND), AttachOptions(0));
75         table->attach (_surface_combo, 1, 2, 0, 1, AttachOptions(FILL|EXPAND), AttachOptions(0));
76
77         vector<string> surfaces;
78         
79         for (std::map<std::string,DeviceInfo>::iterator i = DeviceInfo::device_info.begin(); i != DeviceInfo::device_info.end(); ++i) {
80                 std::cerr << "Dveice known: " << i->first << endl;
81                 surfaces.push_back (i->first);
82         }
83         Gtkmm2ext::set_popdown_strings (_surface_combo, surfaces);
84         _surface_combo.set_active_text (p.device_info().name());
85         _surface_combo.signal_changed().connect (sigc::mem_fun (*this, &MackieControlProtocolGUI::surface_combo_changed));
86
87         append_page (*table, _("Device Selection"));
88         table->show_all();
89
90         /* function key editor */
91
92         append_page (function_key_scroller, _("Function Keys"));
93         function_key_scroller.add (function_key_editor);
94         
95         rebuild_function_key_editor ();
96         function_key_scroller.show_all();
97 }
98
99 CellRendererCombo*
100 MackieControlProtocolGUI::make_action_renderer (Glib::RefPtr<TreeStore> model, Gtk::TreeModelColumnBase column)
101 {
102         CellRendererCombo* renderer = manage (new CellRendererCombo);
103         renderer->property_model() = model;
104         renderer->property_editable() = true;
105         renderer->property_text_column() = 0;
106         renderer->property_has_entry() = false;
107         renderer->signal_edited().connect (sigc::bind (sigc::mem_fun(*this, &MackieControlProtocolGUI::action_changed), column));
108
109         return renderer;
110 }
111
112 void
113 MackieControlProtocolGUI::rebuild_function_key_editor ()
114 {
115         /* build a model of all available actions (needs to be tree structured
116          * more) 
117          */
118
119         available_action_model = TreeStore::create (available_action_columns);
120
121         vector<string> paths;
122         vector<string> labels;
123         vector<string> tooltips;
124         vector<string> keys;
125         vector<AccelKey> bindings;
126         typedef std::map<string,TreeIter> NodeMap;
127         NodeMap nodes;
128         NodeMap::iterator r;
129
130         ActionManager::get_all_actions (labels, paths, tooltips, keys, bindings);
131
132         vector<string>::iterator k;
133         vector<string>::iterator p;
134         vector<string>::iterator t;
135         vector<string>::iterator l;
136
137         available_action_model->clear ();
138
139         for (l = labels.begin(), k = keys.begin(), p = paths.begin(), t = tooltips.begin(); l != labels.end(); ++k, ++p, ++t, ++l) {
140
141                 TreeModel::Row row;
142                 vector<string> parts;
143
144                 parts.clear ();
145
146                 split (*p, parts, '/');
147
148                 if (parts.empty()) {
149                         continue;
150                 }
151
152                 //kinda kludgy way to avoid displaying menu items as mappable
153                 if ( parts[1] == _("Main_menu") )
154                         continue;
155                 if ( parts[1] == _("JACK") )
156                         continue;
157                 if ( parts[1] == _("redirectmenu") )
158                         continue;
159                 if ( parts[1] == _("Editor_menus") )
160                         continue;
161                 if ( parts[1] == _("RegionList") )
162                         continue;
163                 if ( parts[1] == _("ProcessorMenu") )
164                         continue;
165
166                 if ((r = nodes.find (parts[1])) == nodes.end()) {
167
168                         /* top level is missing */
169
170                         TreeIter rowp;
171                         TreeModel::Row parent;
172                         rowp = available_action_model->append();
173                         nodes[parts[1]] = rowp;
174                         parent = *(rowp);
175                         parent[available_action_columns.name] = parts[1];
176
177                         row = *(available_action_model->append (parent.children()));
178
179                 } else {
180
181                         row = *(available_action_model->append ((*r->second)->children()));
182
183                 }
184
185                 /* add this action */
186
187                 if (l->empty ()) {
188                         row[available_action_columns.name] = *t;
189                 } else {
190                         row[available_action_columns.name] = *l;
191                 }
192
193                 row[available_action_columns.path] = (*p);
194         }
195
196         function_key_editor.append_column (_("Key"), function_key_columns.name);
197
198
199         TreeViewColumn* col;
200         CellRendererCombo* renderer;
201
202         renderer = make_action_renderer (available_action_model, function_key_columns.plain);
203         col = manage (new TreeViewColumn (_("Plain"), *renderer));
204         col->add_attribute (renderer->property_text(), function_key_columns.plain);
205         function_key_editor.append_column (*col);
206         
207         renderer = make_action_renderer (available_action_model, function_key_columns.shift);
208         col = manage (new TreeViewColumn (_("Shift"), *renderer));
209         col->add_attribute (renderer->property_text(), function_key_columns.shift);
210         function_key_editor.append_column (*col);
211
212         renderer = make_action_renderer (available_action_model, function_key_columns.control);
213         col = manage (new TreeViewColumn (_("Control"), *renderer));
214         col->add_attribute (renderer->property_text(), function_key_columns.control);
215         function_key_editor.append_column (*col);
216
217         renderer = make_action_renderer (available_action_model, function_key_columns.option);
218         col = manage (new TreeViewColumn (_("Option"), *renderer));
219         col->add_attribute (renderer->property_text(), function_key_columns.option);
220         function_key_editor.append_column (*col);
221
222         renderer = make_action_renderer (available_action_model, function_key_columns.cmdalt);
223         col = manage (new TreeViewColumn (_("Cmd/Alt"), *renderer));
224         col->add_attribute (renderer->property_text(), function_key_columns.cmdalt);
225         function_key_editor.append_column (*col);
226
227         renderer = make_action_renderer (available_action_model, function_key_columns.shiftcontrol);
228         col = manage (new TreeViewColumn (_("Shift+Control"), *renderer));
229         col->add_attribute (renderer->property_text(), function_key_columns.shiftcontrol);
230         function_key_editor.append_column (*col);
231
232         /* now fill with data */
233
234         function_key_model = ListStore::create (function_key_columns);
235
236         TreeModel::Row row;
237         
238         for (uint32_t n = 0; n < 16; ++n) {
239
240                 row = *(function_key_model->append());
241                 row[function_key_columns.name] = string_compose ("F%1", n+1);
242                 row[function_key_columns.number] = n;
243                 row[function_key_columns.plain] = ""; // _cp.f_action (n, 0);
244                 row[function_key_columns.control] = "c";
245                 row[function_key_columns.option] = "o";
246                 row[function_key_columns.shift] = "s";
247                 row[function_key_columns.cmdalt] = "ca";
248                 row[function_key_columns.shiftcontrol] = "sc";
249         }
250
251         function_key_editor.set_model (function_key_model);
252 }
253
254 void 
255 MackieControlProtocolGUI::action_changed (const Glib::ustring &sPath, const Glib::ustring &text, TreeModelColumnBase col)
256 {
257         Gtk::TreePath path(sPath);
258         Gtk::TreeModel::iterator row = function_key_model->get_iter(path);
259
260         cerr << sPath << '-' << col.index() <<  " changed to " << text << endl;
261         
262         if (row) {
263                 (*row).set_value (col.index(), text);
264         }
265 }
266
267 void
268 MackieControlProtocolGUI::surface_combo_changed ()
269 {
270         _cp.set_device (_surface_combo.get_active_text());
271 }
272
273