3d115cbd7b9adf5de9ab73df47e901d99547bca8
[ardour.git] / libs / surfaces / us2400 / gui.cc
1 /*
2         Copyright (C) 2010 Paul Davis
3         Copyright (C) 2017 Ben Loftis
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 #include <gtkmm/comboboxtext.h>
21 #include <gtkmm/box.h>
22 #include <gtkmm/spinbutton.h>
23 #include <gtkmm/table.h>
24 #include <gtkmm/treeview.h>
25 #include <gtkmm/liststore.h>
26 #include <gtkmm/treestore.h>
27 #include <gtkmm/notebook.h>
28 #include <gtkmm/cellrenderercombo.h>
29 #include <gtkmm/scale.h>
30 #include <gtkmm/alignment.h>
31
32 #include "pbd/error.h"
33 #include "pbd/unwind.h"
34 #include "pbd/strsplit.h"
35 #include "pbd/stacktrace.h"
36
37 #include "gtkmm2ext/actions.h"
38 #include "gtkmm2ext/bindings.h"
39 #include "gtkmm2ext/gui_thread.h"
40 #include "gtkmm2ext/utils.h"
41
42 #include "ardour/audioengine.h"
43 #include "ardour/port.h"
44 #include "ardour/rc_configuration.h"
45
46 #include "us2400_control_protocol.h"
47 #include "device_info.h"
48 #include "gui.h"
49 #include "surface.h"
50 #include "surface_port.h"
51
52 #include "pbd/i18n.h"
53
54 using namespace std;
55 using namespace Gtk;
56 using namespace ArdourSurface;
57 using namespace US2400;
58
59 void*
60 US2400Protocol::get_gui () const
61 {
62         if (!_gui) {
63                 const_cast<US2400Protocol*>(this)->build_gui ();
64         }
65         static_cast<Gtk::Notebook*>(_gui)->show_all();
66         return _gui;
67 }
68
69 void
70 US2400Protocol::tear_down_gui ()
71 {
72         if (_gui) {
73                 Gtk::Widget *w = static_cast<Gtk::Widget*>(_gui)->get_parent();
74                 if (w) {
75                         w->hide();
76                         delete w;
77                 }
78         }
79         delete (US2400ProtocolGUI*) _gui;
80         _gui = 0;
81 }
82
83 void
84 US2400Protocol::build_gui ()
85 {
86         _gui = (void *) new US2400ProtocolGUI (*this);
87 }
88
89 US2400ProtocolGUI::US2400ProtocolGUI (US2400Protocol& p)
90         : _cp (p)
91         , table (2, 9)
92         , _device_dependent_widget (0)
93         , _ignore_profile_changed (false)
94         , ignore_active_change (false)
95 {
96         Gtk::Label* l;
97         int row = 0;
98
99         set_border_width (12);
100
101         table.set_row_spacings (4);
102         table.set_col_spacings (6);
103         table.set_border_width (12);
104         table.set_homogeneous (false);
105
106         _cp.DeviceChanged.connect (device_change_connection, invalidator (*this), boost::bind (&US2400ProtocolGUI::device_changed, this), gui_context());
107         _cp.ConnectionChange.connect (connection_change_connection, invalidator (*this), boost::bind (&US2400ProtocolGUI::connection_handler, this), gui_context());
108
109         /* device-dependent part */
110
111         device_dependent_row = row;
112
113         if (_device_dependent_widget) {
114                 table.remove (*_device_dependent_widget);
115                 _device_dependent_widget = 0;
116         }
117
118         _device_dependent_widget = device_dependent_widget ();
119         table.attach (*_device_dependent_widget, 0, 12, row, row+1, AttachOptions(0), AttachOptions(0), 0, 0);
120         row++;
121
122         /* back to the boilerplate */
123
124         vector<string> profiles;
125
126         for (std::map<std::string,DeviceProfile>::iterator i = DeviceProfile::device_profiles.begin(); i != DeviceProfile::device_profiles.end(); ++i) {
127                 cerr << "add discovered profile " << i->first << endl;
128                 profiles.push_back (i->first);
129         }
130         Gtkmm2ext::set_popdown_strings (_profile_combo, profiles);
131         cerr << "set active profile from " << p.device_profile().name() << endl;
132         _profile_combo.set_active_text (p.device_profile().name());
133         _profile_combo.signal_changed().connect (sigc::mem_fun (*this, &US2400ProtocolGUI::profile_combo_changed));
134
135         append_page (table, _("Device Setup"));
136         table.show_all();
137
138         /* function key editor */
139
140         VBox* fkey_packer = manage (new VBox);
141         HBox* profile_packer = manage (new HBox);
142         HBox* observation_packer = manage (new HBox);
143
144         l = manage (new Gtk::Label (_("Profile/Settings:")));
145         profile_packer->pack_start (*l, false, false);
146         profile_packer->pack_start (_profile_combo, true, true);
147         profile_packer->set_spacing (12);
148         profile_packer->set_border_width (12);
149
150         fkey_packer->pack_start (*profile_packer, false, false);
151         fkey_packer->pack_start (function_key_scroller, true, true);
152         fkey_packer->pack_start (*observation_packer, false, false);
153         fkey_packer->set_spacing (12);
154         function_key_scroller.property_shadow_type() = Gtk::SHADOW_NONE;
155         function_key_scroller.add (function_key_editor);
156         append_page (*fkey_packer, _("Function Keys"));
157
158         build_available_action_menu ();
159         build_function_key_editor ();
160         refresh_function_key_editor ();
161         fkey_packer->show_all();
162 }
163
164 void
165 US2400ProtocolGUI::connection_handler ()
166 {
167         /* ignore all changes to combobox active strings here, because we're
168            updating them to match a new ("external") reality - we were called
169            because port connections have changed.
170         */
171
172         PBD::Unwinder<bool> ici (ignore_active_change, true);
173
174         vector<Gtk::ComboBox*>::iterator ic;
175         vector<Gtk::ComboBox*>::iterator oc;
176
177         vector<string> midi_inputs;
178         vector<string> midi_outputs;
179
180         ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsTerminal), midi_inputs);
181         ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsTerminal), midi_outputs);
182
183         for (ic = input_combos.begin(), oc = output_combos.begin(); ic != input_combos.end() && oc != output_combos.end(); ++ic, ++oc) {
184
185                 boost::shared_ptr<Surface> surface = _cp.get_surface_by_raw_pointer ((*ic)->get_data ("surface"));
186
187                 if (surface) {
188                         update_port_combos (midi_inputs, midi_outputs, *ic, *oc, surface);
189                 }
190         }
191 }
192
193 void
194 US2400ProtocolGUI::update_port_combos (vector<string> const& midi_inputs, vector<string> const& midi_outputs,
195                                               Gtk::ComboBox* input_combo,
196                                               Gtk::ComboBox* output_combo,
197                                               boost::shared_ptr<Surface> surface)
198 {
199         Glib::RefPtr<Gtk::ListStore> input = build_midi_port_list (midi_inputs, true);
200         Glib::RefPtr<Gtk::ListStore> output = build_midi_port_list (midi_outputs, false);
201         bool input_found = false;
202         bool output_found = false;
203         int n;
204
205         input_combo->set_model (input);
206         output_combo->set_model (output);
207
208         Gtk::TreeModel::Children children = input->children();
209         Gtk::TreeModel::Children::iterator i;
210         i = children.begin();
211         ++i; /* skip "Disconnected" */
212
213
214         for (n = 1;  i != children.end(); ++i, ++n) {
215                 string port_name = (*i)[midi_port_columns.full_name];
216                 if (surface->port().input().connected_to (port_name)) {
217                         input_combo->set_active (n);
218                         input_found = true;
219                         break;
220                 }
221         }
222
223         if (!input_found) {
224                 input_combo->set_active (0); /* disconnected */
225         }
226
227         children = output->children();
228         i = children.begin();
229         ++i; /* skip "Disconnected" */
230
231         for (n = 1;  i != children.end(); ++i, ++n) {
232                 string port_name = (*i)[midi_port_columns.full_name];
233                 if (surface->port().output().connected_to (port_name)) {
234                         output_combo->set_active (n);
235                         output_found = true;
236                         break;
237                 }
238         }
239
240         if (!output_found) {
241                 output_combo->set_active (0); /* disconnected */
242         }
243 }
244
245 Gtk::Widget*
246 US2400ProtocolGUI::device_dependent_widget ()
247 {
248         Gtk::Table* dd_table;
249         Gtk::Label* l;
250         int row = 0;
251
252         uint32_t n_surfaces = 1 + _cp.device_info().extenders();
253
254         dd_table = Gtk::manage (new Gtk::Table (2, n_surfaces));
255         dd_table->set_row_spacings (4);
256         dd_table->set_col_spacings (6);
257         dd_table->set_border_width (12);
258
259         vector<string> midi_inputs;
260         vector<string> midi_outputs;
261
262         ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsPhysical), midi_inputs);
263         ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsPhysical), midi_outputs);
264
265         input_combos.clear ();
266         output_combos.clear ();
267
268         int portcount = n_surfaces;
269
270         for (int32_t n = 0; n < portcount; ++n) {
271
272                 boost::shared_ptr<Surface> surface = _cp.nth_surface (n);
273
274                 if (!surface) {
275                         PBD::fatal << string_compose (_("programming error: %1\n"), string_compose ("n=%1 surface not found!", n)) << endmsg;
276                         /*NOTREACHED*/
277                 }
278
279                 Gtk::ComboBox* input_combo = manage (new Gtk::ComboBox);
280                 Gtk::ComboBox* output_combo = manage (new Gtk::ComboBox);
281
282                 update_port_combos (midi_inputs, midi_outputs, input_combo, output_combo, surface);
283
284                 input_combo->pack_start (midi_port_columns.short_name);
285                 input_combo->set_data ("surface", surface.get());
286                 input_combos.push_back (input_combo);
287                 output_combo->pack_start (midi_port_columns.short_name);
288                 output_combo->set_data ("surface", surface.get());
289                 output_combos.push_back (output_combo);
290
291                 boost::weak_ptr<Surface> ws (surface);
292                 input_combo->signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &US2400ProtocolGUI::active_port_changed), input_combo, ws, true));
293                 output_combo->signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &US2400ProtocolGUI::active_port_changed), output_combo, ws, false));
294
295                 string send_string;
296                 string receive_string;
297                 
298                 //port 1,2,3 are faders & pan knobs. like mackie MCU
299                 //port 4 is the joystick
300                 //port 5 sends "chan" knobs (24 of them )
301                 //port 6 --- ???  ( could be send to knobs... ? )
302
303                 send_string = string_compose(_("US-2400 send port #%1 (faders %2 to %3):"), n + 1, n*8+1, n*8+8);
304                 receive_string = string_compose(_("US-2400 receive port #%1 (faders %2 to %3):"), n + 1, n*8+1, n*8+8);
305                 if (n==3) {
306                         send_string = string_compose(_("US-2400 send port #%1 (joystick):"), n + 1);
307                         receive_string = string_compose(_("US-2400 receive port #%1 (joystick):"), n + 1);
308                 }
309                 
310                 l = manage (new Gtk::Label (send_string));
311                 l->set_alignment (1.0, 0.5);
312                 dd_table->attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
313                 dd_table->attach (*input_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
314                 row++;
315
316                 l = manage (new Gtk::Label (receive_string));
317                 l->set_alignment (1.0, 0.5);
318                 dd_table->attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
319                 dd_table->attach (*output_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
320                 row++;
321         }
322
323         row++;
324         
325         l = manage (new Gtk::Label ("US-2400 Port #5 is reserved for use as a generic USB device. (click the CHAN button to activate)"));
326         l->set_alignment (1.0, 0.5);
327         dd_table->attach (*l, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
328         row++;
329         row++;
330
331         l = manage (new Gtk::Label ("US-2400 Port #6 is unused."));
332         l->set_alignment (1.0, 0.5);
333         dd_table->attach (*l, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
334         row++;
335         row++;
336
337         l = manage (new Gtk::Label ("NOTE:  you must select mode 4 on the US-2400 unit."));
338         l->set_alignment (1.0, 0.5);
339         dd_table->attach (*l, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
340         row++;
341
342
343         return dd_table;
344 }
345
346 CellRendererCombo*
347 US2400ProtocolGUI::make_action_renderer (Glib::RefPtr<TreeStore> model, Gtk::TreeModelColumnBase column)
348 {
349         CellRendererCombo* renderer = manage (new CellRendererCombo);
350         renderer->property_model() = model;
351         renderer->property_editable() = true;
352         renderer->property_text_column() = 0;
353         renderer->property_has_entry() = false;
354         renderer->signal_edited().connect (sigc::bind (sigc::mem_fun(*this, &US2400ProtocolGUI::action_changed), column));
355
356         return renderer;
357 }
358
359 void
360 US2400ProtocolGUI::build_available_action_menu ()
361 {
362         /* build a model of all available actions (needs to be tree structured
363          * more)
364          */
365
366         available_action_model = TreeStore::create (available_action_columns);
367
368         vector<string> paths;
369         vector<string> labels;
370         vector<string> tooltips;
371         vector<string> keys;
372         vector<Glib::RefPtr<Gtk::Action> > actions;
373
374         typedef std::map<string,TreeIter> NodeMap;
375         NodeMap nodes;
376         NodeMap::iterator r;
377
378         Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
379
380         vector<string>::iterator k;
381         vector<string>::iterator p;
382         vector<string>::iterator t;
383         vector<string>::iterator l;
384
385         available_action_model->clear ();
386
387         /* Because there are button bindings built in that are not
388            in the key binding map, there needs to be a way to undo
389            a profile edit.
390         */
391         TreeIter rowp;
392         TreeModel::Row parent;
393         rowp = available_action_model->append();
394         parent = *(rowp);
395         parent[available_action_columns.name] = _("Remove Binding");
396
397         /* Key aliasing */
398
399         rowp = available_action_model->append();
400         parent = *(rowp);
401         parent[available_action_columns.name] = _("Shift");
402         rowp = available_action_model->append();
403         parent = *(rowp);
404         parent[available_action_columns.name] = _("Control");
405         rowp = available_action_model->append();
406         parent = *(rowp);
407         parent[available_action_columns.name] = _("Option");
408         rowp = available_action_model->append();
409         parent = *(rowp);
410         parent[available_action_columns.name] = _("CmdAlt");
411
412         for (l = labels.begin(), k = keys.begin(), p = paths.begin(), t = tooltips.begin(); l != labels.end(); ++k, ++p, ++t, ++l) {
413
414                 TreeModel::Row row;
415                 vector<string> parts;
416
417                 parts.clear ();
418
419                 split (*p, parts, '/');
420
421                 if (parts.empty()) {
422                         continue;
423                 }
424
425                 //kinda kludgy way to avoid displaying menu items as mappable
426                 if ( parts[1] == _("Main_menu") )
427                         continue;
428                 if ( parts[1] == _("JACK") )
429                         continue;
430                 if ( parts[1] == _("redirectmenu") )
431                         continue;
432                 if ( parts[1] == _("Editor_menus") )
433                         continue;
434                 if ( parts[1] == _("RegionList") )
435                         continue;
436                 if ( parts[1] == _("ProcessorMenu") )
437                         continue;
438
439                 if ((r = nodes.find (parts[1])) == nodes.end()) {
440
441                         /* top level is missing */
442
443                         TreeIter rowp;
444                         TreeModel::Row parent;
445                         rowp = available_action_model->append();
446                         nodes[parts[1]] = rowp;
447                         parent = *(rowp);
448                         parent[available_action_columns.name] = parts[1];
449
450                         row = *(available_action_model->append (parent.children()));
451
452                 } else {
453
454                         row = *(available_action_model->append ((*r->second)->children()));
455
456                 }
457
458                 /* add this action */
459
460                 if (l->empty ()) {
461                         row[available_action_columns.name] = *t;
462                         action_map[*t] = *p;
463                 } else {
464                         row[available_action_columns.name] = *l;
465                         action_map[*l] = *p;
466                 }
467
468                 row[available_action_columns.path] = (*p);
469         }
470 }
471
472 void
473 US2400ProtocolGUI::build_function_key_editor ()
474 {
475         function_key_editor.append_column (_("Key"), function_key_columns.name);
476
477         TreeViewColumn* col;
478         CellRendererCombo* renderer;
479
480         renderer = make_action_renderer (available_action_model, function_key_columns.plain);
481         col = manage (new TreeViewColumn (_("Plain"), *renderer));
482         col->add_attribute (renderer->property_text(), function_key_columns.plain);
483         function_key_editor.append_column (*col);
484
485         renderer = make_action_renderer (available_action_model, function_key_columns.shift);
486         col = manage (new TreeViewColumn (_("Shift"), *renderer));
487         col->add_attribute (renderer->property_text(), function_key_columns.shift);
488         function_key_editor.append_column (*col);
489
490 /*
491  *      renderer = make_action_renderer (available_action_model, function_key_columns.control);
492         col = manage (new TreeViewColumn (_("Control"), *renderer));
493         col->add_attribute (renderer->property_text(), function_key_columns.control);
494         function_key_editor.append_column (*col);
495
496         renderer = make_action_renderer (available_action_model, function_key_columns.option);
497         col = manage (new TreeViewColumn (_("Option"), *renderer));
498         col->add_attribute (renderer->property_text(), function_key_columns.option);
499         function_key_editor.append_column (*col);
500
501         renderer = make_action_renderer (available_action_model, function_key_columns.cmdalt);
502         col = manage (new TreeViewColumn (_("Cmd/Alt"), *renderer));
503         col->add_attribute (renderer->property_text(), function_key_columns.cmdalt);
504         function_key_editor.append_column (*col);
505
506         renderer = make_action_renderer (available_action_model, function_key_columns.shiftcontrol);
507         col = manage (new TreeViewColumn (_("Shift+Control"), *renderer));
508         col->add_attribute (renderer->property_text(), function_key_columns.shiftcontrol);
509         function_key_editor.append_column (*col);
510 */
511
512         function_key_model = ListStore::create (function_key_columns);
513         function_key_editor.set_model (function_key_model);
514 }
515
516 void
517 US2400ProtocolGUI::refresh_function_key_editor ()
518 {
519         function_key_editor.set_model (Glib::RefPtr<TreeModel>());
520         function_key_model->clear ();
521
522         /* now fill with data */
523
524         TreeModel::Row row;
525         DeviceProfile dp (_cp.device_profile());
526         DeviceInfo di;
527
528         for (int n = 0; n < US2400::Button::FinalGlobalButton; ++n) {
529
530                 US2400::Button::ID bid = (US2400::Button::ID) n;
531
532                 row = *(function_key_model->append());
533                 if (di.global_buttons().find (bid) == di.global_buttons().end()) {
534                         row[function_key_columns.name] = US2400::Button::id_to_name (bid);
535                 } else {
536                         row[function_key_columns.name] = di.get_global_button_name (bid) + "*";
537                 }
538                 row[function_key_columns.id] = bid;
539
540                 Glib::RefPtr<Gtk::Action> act;
541                 string action;
542                 const string defstring = "\u2022";
543
544                 /* We only allow plain bindings for Fn keys. All others are
545                  * reserved for hard-coded actions.
546                  */
547
548                 if (bid >= US2400::Button::F1 && bid <= US2400::Button::F6) {
549
550                         action = dp.get_button_action (bid, 0);
551                         if (action.empty()) {
552                                 row[function_key_columns.plain] = defstring;
553                         } else {
554                                 if (action.find ('/') == string::npos) {
555                                         /* Probably a key alias */
556                                         row[function_key_columns.plain] = action;
557                                 } else {
558
559                                         act = ActionManager::get_action (action.c_str());
560                                         if (act) {
561                                                 row[function_key_columns.plain] = act->get_label();
562                                         } else {
563                                                 row[function_key_columns.plain] = defstring;
564                                         }
565                                 }
566                         }
567                 }
568
569                 //~ /* We only allow plain bindings for Fn keys. All others are
570                  //~ * reserved for hard-coded actions.
571                  //~ */
572 //~ 
573                 //~ if (bid >= US2400::Button::F1 && bid <= US2400::Button::F8) {
574 //~ 
575                         //~ action = dp.get_button_action (bid, US2400Protocol::MODIFIER_SHIFT);
576                         //~ if (action.empty()) {
577                                 //~ row[function_key_columns.shift] = defstring;
578                         //~ } else {
579                                 //~ if (action.find ('/') == string::npos) {
580                                         //~ /* Probably a key alias */
581                                         //~ row[function_key_columns.shift] = action;
582                                 //~ } else {
583                                         //~ act = ActionManager::get_action (action.c_str());
584                                         //~ if (act) {
585                                                 //~ row[function_key_columns.shift] = act->get_label();
586                                         //~ } else {
587                                                 //~ row[function_key_columns.shift] = defstring;
588                                         //~ }
589                                 //~ }
590                         //~ }
591                 //~ }
592
593                 //~ action = dp.get_button_action (bid, US2400Protocol::MODIFIER_CONTROL);
594                 //~ if (action.empty()) {
595                         //~ row[function_key_columns.control] = defstring;
596                 //~ } else {
597                         //~ if (action.find ('/') == string::npos) {
598                                 //~ /* Probably a key alias */
599                                 //~ row[function_key_columns.control] = action;
600                         //~ } else {
601                                 //~ act = ActionManager::get_action (action.c_str());
602                                 //~ if (act) {
603                                         //~ row[function_key_columns.control] = act->get_label();
604                                 //~ } else {
605                                         //~ row[function_key_columns.control] = defstring;
606                                 //~ }
607                         //~ }
608                 //~ }
609 //~ 
610                 //~ action = dp.get_button_action (bid, US2400Protocol::MODIFIER_OPTION);
611                 //~ if (action.empty()) {
612                         //~ row[function_key_columns.option] = defstring;
613                 //~ } else {
614                         //~ if (action.find ('/') == string::npos) {
615                                 //~ /* Probably a key alias */
616                                 //~ row[function_key_columns.option] = action;
617                         //~ } else {
618                                 //~ act = ActionManager::get_action (action.c_str());
619                                 //~ if (act) {
620                                         //~ row[function_key_columns.option] = act->get_label();
621                                 //~ } else {
622                                         //~ row[function_key_columns.option] = defstring;
623                                 //~ }
624                         //~ }
625                 //~ }
626 //~ 
627                 //~ action = dp.get_button_action (bid, US2400Protocol::MODIFIER_CMDALT);
628                 //~ if (action.empty()) {
629                         //~ row[function_key_columns.cmdalt] = defstring;
630                 //~ } else {
631                         //~ if (action.find ('/') == string::npos) {
632                                 //~ /* Probably a key alias */
633                                 //~ row[function_key_columns.cmdalt] = action;
634                         //~ } else {
635                                 //~ act = ActionManager::get_action (action.c_str());
636                                 //~ if (act) {
637                                         //~ row[function_key_columns.cmdalt] = act->get_label();
638                                 //~ } else {
639                                         //~ row[function_key_columns.cmdalt] = defstring;
640                                 //~ }
641                         //~ }
642                 //~ }
643 //~ 
644                 //~ action = dp.get_button_action (bid, (US2400Protocol::MODIFIER_SHIFT|US2400Protocol::MODIFIER_CONTROL));
645                 //~ if (action.empty()) {
646                         //~ row[function_key_columns.shiftcontrol] = defstring;
647                 //~ } else {
648                         //~ act = ActionManager::get_action (action.c_str());
649                         //~ if (act) {
650                                 //~ row[function_key_columns.shiftcontrol] = act->get_label();
651                         //~ } else {
652                                 //~ row[function_key_columns.shiftcontrol] = defstring;
653                         //~ }
654                 //~ }
655         }
656
657         function_key_editor.set_model (function_key_model);
658 }
659
660 void
661 US2400ProtocolGUI::action_changed (const Glib::ustring &sPath, const Glib::ustring &text, TreeModelColumnBase col)
662 {
663         // Remove Binding is not in the action map but still valid
664         bool remove (false);
665         if ( text == "Remove Binding") {
666                 remove = true;
667         }
668         Gtk::TreePath path(sPath);
669         Gtk::TreeModel::iterator row = function_key_model->get_iter(path);
670
671         if (row) {
672
673                 std::map<std::string,std::string>::iterator i = action_map.find (text);
674
675                 if (i == action_map.end()) {
676                         if (!remove) {
677                                 return;
678                         }
679                 }
680                 Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (i->second.c_str());
681
682                 if (act || remove) {
683                         /* update visible text, using string supplied by
684                            available action model so that it matches and is found
685                            within the model.
686                         */
687                         if (remove) {
688                                 Glib::ustring dot = "\u2022";
689                                 (*row).set_value (col.index(), dot);
690                         } else {
691                                 (*row).set_value (col.index(), text);
692                         }
693
694                         /* update the current DeviceProfile, using the full
695                          * path
696                          */
697
698                         int modifier;
699
700                         switch (col.index()) {
701                         case 3:
702                                 modifier = US2400Protocol::MODIFIER_SHIFT;
703                                 break;
704                         case 4:
705                                 modifier = US2400Protocol::MODIFIER_CONTROL;
706                                 break;
707                         case 5:
708                                 modifier = US2400Protocol::MODIFIER_OPTION;
709                                 break;
710                         case 6:
711                                 modifier = US2400Protocol::MODIFIER_CMDALT;
712                                 break;
713                         case 7:
714                                 modifier = (US2400Protocol::MODIFIER_SHIFT|US2400Protocol::MODIFIER_CONTROL);
715                                 break;
716                         default:
717                                 modifier = 0;
718                         }
719
720                         if (remove) {
721                                 _cp.device_profile().set_button_action ((*row)[function_key_columns.id], modifier, "");
722                         } else {
723                                 _cp.device_profile().set_button_action ((*row)[function_key_columns.id], modifier, i->second);
724                         }
725
726                         _ignore_profile_changed = true;
727                         _profile_combo.set_active_text ( _cp.device_profile().name() );
728                         _ignore_profile_changed = false;
729
730                 } else {
731                         std::cerr << "no such action\n";
732                 }
733         }
734 }
735
736 void
737 US2400ProtocolGUI::device_changed ()
738 {
739         if (_device_dependent_widget) {
740                 table.remove (*_device_dependent_widget);
741                 _device_dependent_widget = 0;
742         }
743
744         _device_dependent_widget = device_dependent_widget ();
745         _device_dependent_widget->show_all ();
746
747         table.attach (*_device_dependent_widget, 0, 12, device_dependent_row, device_dependent_row+1, AttachOptions(0), AttachOptions(0), 0, 0);
748 }
749
750 void
751 US2400ProtocolGUI::profile_combo_changed ()
752 {
753         if (!_ignore_profile_changed) {
754                 string profile = _profile_combo.get_active_text();
755
756                 _cp.set_profile (profile);
757
758                 refresh_function_key_editor ();
759         }
760 }
761
762 Glib::RefPtr<Gtk::ListStore>
763 US2400ProtocolGUI::build_midi_port_list (vector<string> const & ports, bool for_input)
764 {
765         Glib::RefPtr<Gtk::ListStore> store = ListStore::create (midi_port_columns);
766         TreeModel::Row row;
767
768         row = *store->append ();
769         row[midi_port_columns.full_name] = string();
770         row[midi_port_columns.short_name] = _("Disconnected");
771
772         for (vector<string>::const_iterator p = ports.begin(); p != ports.end(); ++p) {
773                 row = *store->append ();
774                 row[midi_port_columns.full_name] = *p;
775                 std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*p);
776                 if (pn.empty ()) {
777                         pn = (*p).substr ((*p).find (':') + 1);
778                 }
779                 row[midi_port_columns.short_name] = pn;
780         }
781
782         return store;
783 }
784
785 void
786 US2400ProtocolGUI::active_port_changed (Gtk::ComboBox* combo, boost::weak_ptr<Surface> ws, bool for_input)
787 {
788         if (ignore_active_change) {
789                 return;
790         }
791
792         boost::shared_ptr<Surface> surface = ws.lock();
793
794         if (!surface) {
795                 return;
796         }
797
798         TreeModel::iterator active = combo->get_active ();
799         string new_port = (*active)[midi_port_columns.full_name];
800
801         if (new_port.empty()) {
802                 if (for_input) {
803                         surface->port().input().disconnect_all ();
804                 } else {
805                         surface->port().output().disconnect_all ();
806                 }
807
808                 return;
809         }
810
811         if (for_input) {
812                 if (!surface->port().input().connected_to (new_port)) {
813                         surface->port().input().disconnect_all ();
814                         surface->port().input().connect (new_port);
815                 }
816         } else {
817                 if (!surface->port().output().connected_to (new_port)) {
818                         surface->port().output().disconnect_all ();
819                         surface->port().output().connect (new_port);
820                 }
821         }
822 }