OSC: Add /surface/list option to setting GUI
[ardour.git] / libs / surfaces / osc / osc_gui.cc
1 /*
2     Copyright (C) 2016 Robin Gareus <robin@gareus.org
3     Copyright (C) 2009-2012 Paul Davis
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 <iostream>
22 #include <list>
23 #include <string>
24 #include <vector>
25
26 #include <errno.h>
27
28 #include "pbd/file_utils.h"
29
30 #include <gtkmm/box.h>
31 #include <gtkmm/notebook.h>
32 #include <gtkmm/table.h>
33 #include <gtkmm/label.h>
34 #include <gtkmm/button.h>
35 #include <gtkmm/spinbutton.h>
36 #include <gtkmm/comboboxtext.h>
37
38 #include "gtkmm2ext/gtk_ui.h"
39 #include "gtkmm2ext/gui_thread.h"
40 #include "gtkmm2ext/utils.h"
41
42 #include "ardour/filesystem_paths.h"
43
44 #include "osc.h"
45 #include "osc_gui.h"
46
47 #include "pbd/i18n.h"
48
49 using namespace PBD;
50 using namespace ARDOUR;
51 using namespace Gtk;
52 using namespace Gtkmm2ext;
53 using namespace ArdourSurface;
54
55 OSC_GUI::OSC_GUI (OSC& p)
56         : cp (p)
57 {
58         int n = 0; // table row
59         Table* table = manage (new Table);
60         Label* label;
61         table->set_row_spacings (16);
62         table->set_col_spacings (6);
63         table->set_border_width (12);
64         get_session ();
65         preset_busy = true;
66
67         // show our url
68         label = manage (new Gtk::Label(_("Connection:")));
69         label->set_alignment(1, .5);
70         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
71         label = manage (new Gtk::Label(cp.get_server_url()));
72         table->attach (*label, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
73         ++n;
74
75         // show and set port to auto (default) or manual (one surface only)
76         label = manage (new Gtk::Label(_("Port Mode:")));
77         label->set_alignment(1, .5);
78         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
79         table->attach (portmode_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
80         std::vector<std::string> portmode_options;
81         portmode_options.push_back (_("Auto - Reply to Originating Port"));
82         portmode_options.push_back (_("Manual - Specify Below"));
83
84         set_popdown_strings (portmode_combo, portmode_options);
85         portmode_combo.set_active ((int)cp.get_portmode());
86         ++n;
87
88         // port entry box
89         label = manage (new Gtk::Label(_("Reply Manual Port:")));
90         label->set_alignment(1, .5);
91         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
92         table->attach (port_entry, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
93         port_entry.set_range(1024, 0xffff);
94         port_entry.set_increments (1, 100);
95         port_entry.set_text(cp.get_remote_port().c_str());
96         if (!cp.get_portmode()) {
97                 port_entry.set_sensitive (false);
98         }
99         ++n;
100
101         // default banksize setting
102         label = manage (new Gtk::Label(_("Bank Size:")));
103         label->set_alignment(1, .5);
104         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
105         table->attach (bank_entry, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
106         bank_entry.set_range (0, 0xffff);
107         bank_entry.set_increments (1, 8);
108         bank_entry.set_value (cp.get_banksize());
109
110         ++n;
111
112         // default send page setting
113         label = manage (new Gtk::Label(_("Send Page Size:")));
114         label->set_alignment(1, .5);
115         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
116         table->attach (send_page_entry, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
117         send_page_entry.set_range (0, 0xffff);
118         send_page_entry.set_increments (1, 8);
119         send_page_entry.set_value (cp.get_send_size());
120
121         ++n;
122
123         // default plugin page setting
124         label = manage (new Gtk::Label(_("Plugin Page Size:")));
125         label->set_alignment(1, .5);
126         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
127         table->attach (plugin_page_entry, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
128         plugin_page_entry.set_range (0, 0xffff);
129         plugin_page_entry.set_increments (1, 8);
130         plugin_page_entry.set_value (cp.get_send_size());
131
132         ++n;
133
134         // Gain Mode
135         label = manage (new Gtk::Label(_("Gain Mode:")));
136         label->set_alignment(1, .5);
137         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
138         table->attach (gainmode_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
139         std::vector<std::string> gainmode_options;
140         gainmode_options.push_back (_("/strip/gain (dB)"));
141         gainmode_options.push_back (_("/strip/fader (Position)"));
142
143         set_popdown_strings (gainmode_combo, gainmode_options);
144         gainmode_combo.set_active ((int)cp.get_gainmode());
145         ++n;
146
147         // debug setting
148         label = manage (new Gtk::Label(_("Debug:")));
149         label->set_alignment(1, .5);
150         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
151         table->attach (debug_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
152
153         std::vector<std::string> debug_options;
154         debug_options.push_back (_("Off"));
155         debug_options.push_back (_("Log invalid messages"));
156         debug_options.push_back (_("Log all messages"));
157         debug_options.push_back (_("Print surface information to Log window"));
158
159         set_popdown_strings (debug_combo, debug_options);
160         debug_combo.set_active ((int)cp.get_debug_mode());
161         ++n;
162
163         // Preset loader combo
164         label = manage (new Gtk::Label(_("Preset:")));
165         label->set_alignment(1, .5);
166         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
167         table->attach (preset_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
168
169         preset_files.clear();
170         // no files for these two
171         preset_options.push_back (_("Last Loaded Session"));
172         preset_options.push_back (_("Ardour Factory Setting"));
173         // user is special it appears in menu even if no file is present
174         preset_options.push_back ("User");
175         preset_files["User"] = "";
176         // scan for OSC .preset files
177         scan_preset_files ();
178
179         set_popdown_strings (preset_combo, preset_options);
180         preset_combo.set_active (0);
181         preset_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::preset_changed));
182         ++n;
183
184         table->show_all ();
185         append_page (*table, _("OSC Setup"));
186
187         debug_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::debug_changed));
188         portmode_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::portmode_changed));
189         gainmode_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::gainmode_changed));
190         port_entry.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::port_changed));
191         port_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &OSC_GUI::port_focus_out));
192         bank_entry.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::bank_changed));
193         send_page_entry.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::send_page_changed));
194         plugin_page_entry.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::plugin_page_changed));
195
196         // Strip Types Calculate Page
197         int stn = 0; // table row
198         Table* sttable = manage (new Table);
199         sttable->set_row_spacings (8);
200         sttable->set_col_spacings (6);
201         sttable->set_border_width (25);
202
203         // show our url
204         label = manage (new Gtk::Label(_("Select Desired Types of Tracks")));
205         sttable->attach (*label, 0, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
206         ++stn;
207
208         label = manage (new Gtk::Label(_("Strip Types Value:")));
209         label->set_alignment(1, .5);
210         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
211         calculate_strip_types ();
212         current_strip_types.set_width_chars(10);
213         sttable->attach (current_strip_types, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
214         ++stn;
215
216         label = manage (new Gtk::Label(_("Audio Tracks:")));
217         label->set_alignment(1, .5);
218         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
219         sttable->attach (audio_tracks, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
220         ++stn;
221
222         label = manage (new Gtk::Label(_("Midi Tracks:")));
223         label->set_alignment(1, .5);
224         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
225         sttable->attach (midi_tracks, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
226         ++stn;
227
228         label = manage (new Gtk::Label(_("Audio Busses:")));
229         label->set_alignment(1, .5);
230         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
231         sttable->attach (audio_buses, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
232         ++stn;
233
234         label = manage (new Gtk::Label(_("Audio Auxes:")));
235         label->set_alignment(1, .5);
236         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
237         sttable->attach (audio_auxes, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
238         ++stn;
239
240         label = manage (new Gtk::Label(_("Midi Busses:")));
241         label->set_alignment(1, .5);
242         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
243         sttable->attach (midi_buses, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
244         ++stn;
245
246         label = manage (new Gtk::Label(_("Control Masters:")));
247         label->set_alignment(1, .5);
248         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
249         sttable->attach (control_masters, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
250         ++stn;
251
252         label = manage (new Gtk::Label(_("Master (use /master instead):")));
253         label->set_alignment(1, .5);
254         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
255         sttable->attach (master_type, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
256         ++stn;
257
258         label = manage (new Gtk::Label(_("Monitor (use /monitor instead):")));
259         label->set_alignment(1, .5);
260         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
261         sttable->attach (monitor_type, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
262         ++stn;
263
264         label = manage (new Gtk::Label(_("Selected Tracks (use for selected tracks only):")));
265         label->set_alignment(1, .5);
266         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
267         sttable->attach (selected_tracks, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
268         ++stn;
269
270         label = manage (new Gtk::Label(_("Hidden Tracks:")));
271         label->set_alignment(1, .5);
272         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
273         sttable->attach (hidden_tracks, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
274         ++stn;
275
276         label = manage (new Gtk::Label(_("Use Groups:")));
277         label->set_alignment(1, .5);
278         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
279         sttable->attach (usegroups, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
280         ++stn;
281
282
283         sttable->show_all ();
284         append_page (*sttable, _("Default Strip Types"));
285
286
287         // Feedback Calculate Page
288         int fn = 0; // table row
289         Table* fbtable = manage (new Table);
290         fbtable->set_row_spacings (4);
291         fbtable->set_col_spacings (6);
292         fbtable->set_border_width (12);
293
294         label = manage (new Gtk::Label(_("Select Desired Types of Feedback")));
295         fbtable->attach (*label, 0, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
296         ++fn;
297
298         label = manage (new Gtk::Label(_("Feedback Value:")));
299         label->set_alignment(1, .5);
300         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
301         calculate_feedback ();
302         current_feedback.set_width_chars(10);
303         fbtable->attach (current_feedback, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
304         ++fn;
305
306         label = manage (new Gtk::Label(_("Strip Buttons:")));
307         label->set_alignment(1, .5);
308         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
309         fbtable->attach (strip_buttons_button, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
310         ++fn;
311
312         label = manage (new Gtk::Label(_("Strip Controls:")));
313         label->set_alignment(1, .5);
314         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
315         fbtable->attach (strip_control_button, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
316         ++fn;
317
318         label = manage (new Gtk::Label(_("Use SSID as Path Extension:")));
319         label->set_alignment(1, .5);
320         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
321         fbtable->attach (ssid_as_path, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
322         ++fn;
323
324         label = manage (new Gtk::Label(_("Use Heart Beat:")));
325         label->set_alignment(1, .5);
326         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
327         fbtable->attach (heart_beat, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
328         ++fn;
329
330         label = manage (new Gtk::Label(_("Master Section:")));
331         label->set_alignment(1, .5);
332         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
333         fbtable->attach (master_fb, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
334         ++fn;
335
336         label = manage (new Gtk::Label(_("Play Head Position as Bar and Beat:")));
337         label->set_alignment(1, .5);
338         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
339         fbtable->attach (bar_and_beat, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
340         ++fn;
341
342         label = manage (new Gtk::Label(_("Play Head Position as SMPTE Time:")));
343         label->set_alignment(1, .5);
344         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
345         fbtable->attach (smpte, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
346         ++fn;
347
348         label = manage (new Gtk::Label(_("Metering as a Float:")));
349         label->set_alignment(1, .5);
350         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
351         fbtable->attach (meter_float, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
352         ++fn;
353
354         label = manage (new Gtk::Label(_("Metering as a LED Strip:")));
355         label->set_alignment(1, .5);
356         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
357         fbtable->attach (meter_led, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
358         ++fn;
359
360         label = manage (new Gtk::Label(_("Signal Present:")));
361         label->set_alignment(1, .5);
362         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
363         fbtable->attach (signal_present, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
364         ++fn;
365
366         label = manage (new Gtk::Label(_("Play Head Position as Samples:")));
367         label->set_alignment(1, .5);
368         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
369         fbtable->attach (hp_samples, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
370         ++fn;
371
372         label = manage (new Gtk::Label(_("Playhead Position as Minutes Seconds:")));
373         label->set_alignment(1, .5);
374         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
375         fbtable->attach (hp_min_sec, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
376         ++fn;
377
378         label = manage (new Gtk::Label(_("Playhead Position as per GUI Clock:")));
379         label->set_alignment(1, .5);
380         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
381         fbtable->attach (hp_gui, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
382         hp_gui.set_sensitive (false); // we don't have this yet (Mixbus wants)
383         ++fn;
384
385         label = manage (new Gtk::Label(_("Extra Select Only Feedback:")));
386         label->set_alignment(1, .5);
387         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
388         fbtable->attach (select_fb, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
389         ++fn;
390
391         label = manage (new Gtk::Label(_("Use /reply instead of #reply:")));
392         label->set_alignment(1, .5);
393         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
394         fbtable->attach (use_osc10, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
395         ++fn;
396
397         fbtable->show_all ();
398         append_page (*fbtable, _("Default Feedback"));
399         // set strips and feedback from loaded default values
400         reshow_values ();
401         // connect signals
402         audio_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
403         midi_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
404         audio_buses.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
405         audio_auxes.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
406         midi_buses.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
407         control_masters.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
408         master_type.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
409         monitor_type.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
410         selected_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
411         hidden_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
412         usegroups.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
413         strip_buttons_button.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
414         strip_control_button.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
415         ssid_as_path.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
416         heart_beat.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
417         master_fb.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
418         bar_and_beat.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
419         smpte.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
420         meter_float.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
421         meter_led.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
422         signal_present.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
423         hp_samples.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
424         hp_min_sec.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
425         hp_gui.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
426         select_fb.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
427         use_osc10.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
428         preset_busy = false;
429
430 }
431
432 OSC_GUI::~OSC_GUI ()
433 {
434 }
435
436 // static directory and file handling stuff
437 static Searchpath
438 preset_search_path ()
439 {
440         bool preset_path_defined = false;
441         std::string spath_env (Glib::getenv (preset_env_variable_name, preset_path_defined));
442
443         if (preset_path_defined) {
444                 return spath_env;
445         }
446
447         Searchpath spath (ardour_data_search_path());
448         spath.add_subdirectory_to_paths(preset_dir_name);
449
450         return spath;
451 }
452
453 static std::string
454 user_preset_directory ()
455 {
456         return Glib::build_filename (user_config_directory(), preset_dir_name);
457 }
458
459 static bool
460 preset_filter (const std::string &str, void* /*arg*/)
461 {
462         return (str.length() > strlen(preset_suffix) &&
463                 str.find (preset_suffix) == (str.length() - strlen (preset_suffix)));
464 }
465
466 static std::string
467 legalize_for_path (const std::string& str)
468 {
469         std::string::size_type pos;
470         std::string illegal_chars = "/\\"; /* DOS, POSIX. Yes, we're going to ignore HFS */
471         std::string legal;
472
473         legal = str;
474         pos = 0;
475
476         while ((pos = legal.find_first_of (illegal_chars, pos)) != std::string::npos) {
477                 legal.replace (pos, 1, "_");
478                 pos += 1;
479         }
480
481         return std::string (legal);
482 }
483
484 // end of static functions
485
486 void
487 OSC_GUI::debug_changed ()
488 {
489         std::string str = debug_combo.get_active_text ();
490         if (str == _("Off")) {
491                 cp.set_debug_mode (OSC::Off);
492         }
493         else if (str == _("Log invalid messages")) {
494                 cp.set_debug_mode (OSC::Unhandled);
495         }
496         else if (str == _("Log all messages")) {
497                 cp.set_debug_mode (OSC::All);
498         }
499         else if (str == _("Print surface information to Log window")) {
500                 cp.get_surfaces ();
501                 debug_combo.set_active ((int)cp.get_debug_mode());
502         }
503         else {
504                 std::cerr << "Invalid OSC Debug Mode\n";
505                 assert (0);
506         }
507 }
508
509 void
510 OSC_GUI::portmode_changed ()
511 {
512         int pm = portmode_combo.get_active_row_number ();
513         cp.set_portmode (pm);
514         if (pm) {
515                 port_entry.set_sensitive (true);
516         } else {
517                 port_entry.set_sensitive (false);
518         }
519         save_user ();
520 }
521
522 void
523 OSC_GUI::port_changed ()
524 {
525         std::string str = port_entry.get_text ();
526         int prt = atoi (str.c_str());
527         if (prt == 3819 || prt < 1024) {
528                 // indicate non-valid text
529                 port_entry.set_progress_fraction (1.0);
530         } else {
531                 port_entry.set_progress_fraction (0.0);
532                 cp.set_remote_port (string_compose ("%1", prt));
533                 save_user ();
534         }
535 }
536
537 bool
538 OSC_GUI::port_focus_out (GdkEventFocus* )
539 {
540         std::string str = port_entry.get_text ();
541         int prt = atoi (str.c_str());
542         if (prt == 3819 || prt < 1024) {
543                 port_entry.set_text(cp.get_remote_port().c_str());
544                 port_entry.set_progress_fraction (0.0);
545         }
546         return false;
547 }
548
549 void
550 OSC_GUI::bank_changed ()
551 {
552         uint32_t bsize = atoi(bank_entry.get_text ());
553         bank_entry.set_text (string_compose ("%1", bsize));
554         cp.set_banksize (bsize);
555         save_user ();
556
557 }
558
559 void
560 OSC_GUI::send_page_changed ()
561 {
562         uint32_t ssize = atoi (send_page_entry.get_text ());
563         send_page_entry.set_text (string_compose ("%1", ssize));
564         cp.set_send_size (ssize);
565         save_user ();
566
567 }
568
569 void
570 OSC_GUI::plugin_page_changed ()
571 {
572         uint32_t psize = atoi (plugin_page_entry.get_text ());
573         plugin_page_entry.set_text (string_compose ("%1", psize));
574         cp.set_plugin_size (psize);
575         save_user ();
576
577 }
578
579 void
580 OSC_GUI::gainmode_changed ()
581 {
582         std::string str = gainmode_combo.get_active_text ();
583         if (str == _("/strip/gain (dB)")) {
584                 cp.set_gainmode (0);
585         }
586         else if (str == _("/strip/fader (Position)")) {
587                 cp.set_gainmode (1);
588         }
589         else {
590                 std::cerr << "Invalid OSC Gain Mode\n";
591                 assert (0);
592         }
593         save_user ();
594 }
595
596 void
597 OSC_GUI::clear_device ()
598 {
599         cp.clear_devices();
600 }
601
602 void
603 OSC_GUI::preset_changed ()
604 {
605         preset_busy = true;
606         std::string str = preset_combo.get_active_text ();
607         if (str == "Last Loaded Session") {
608                 restore_sesn_values ();
609         }
610         else if (str == "Ardour Factory Setting") {
611                 factory_reset ();
612         }
613         else if (str == "User") {
614                 load_preset ("User");
615         }
616         else {
617                 load_preset (str);
618         }
619         cp.clear_devices ();
620         preset_busy = false;
621 }
622
623 void
624 OSC_GUI::factory_reset ()
625 {
626         cp.set_banksize (0);
627         bank_entry.set_text ("0");
628         cp.set_send_size (0);
629         send_page_entry.set_text ("0");
630         cp.set_plugin_size (0);
631         plugin_page_entry.set_text ("0");
632         cp.set_defaultstrip (159);
633         cp.set_defaultfeedback (0);
634         reshow_values ();
635         cp.set_gainmode (0);
636         gainmode_combo.set_active (0);
637         cp.set_portmode (1);
638         portmode_combo.set_active (1);
639         cp.set_remote_port ("8000");
640         port_entry.set_text ("8000");
641         cp.clear_devices ();
642         cp.gui_changed ();
643 }
644
645 void
646 OSC_GUI::reshow_values ()
647 {
648         def_strip = cp.get_defaultstrip();
649         audio_tracks.set_active(def_strip & 1);
650         midi_tracks.set_active(def_strip & 2);
651         audio_buses.set_active(def_strip & 4);
652         midi_buses.set_active(def_strip & 8);
653         control_masters.set_active(def_strip & 16);
654         master_type.set_active(def_strip & 32);
655         monitor_type.set_active(def_strip & 64);
656         audio_auxes.set_active(def_strip & 128);
657         selected_tracks.set_active(def_strip & 256);
658         hidden_tracks.set_active(def_strip & 512);
659         usegroups.set_active(def_strip & 1024);
660         def_feedback = cp.get_defaultfeedback();
661         strip_buttons_button.set_active(def_feedback & 1);
662         strip_control_button.set_active(def_feedback & 2);
663         ssid_as_path.set_active(def_feedback & 4);
664         heart_beat.set_active(def_feedback & 8);
665         master_fb.set_active(def_feedback & 16);
666         bar_and_beat.set_active(def_feedback & 32);
667         smpte.set_active(def_feedback & 64);
668         meter_float.set_active(def_feedback & 128);
669         meter_led.set_active(def_feedback & 256);
670         signal_present.set_active(def_feedback & 512);
671         hp_samples.set_active(def_feedback & 1024);
672         hp_min_sec.set_active (def_feedback & 2048);
673         //hp_gui.set_active (false); // we don't have this yet (Mixbus wants)
674         select_fb.set_active(def_feedback & 8192);
675         use_osc10.set_active(def_feedback & 16384);
676
677         calculate_strip_types ();
678         calculate_feedback ();
679 }
680
681 void
682 OSC_GUI::calculate_feedback ()
683 {
684         fbvalue = 0;
685         if (strip_buttons_button.get_active()) {
686                 fbvalue += 1;
687         }
688         if (strip_control_button.get_active()) {
689                 fbvalue += 2;
690         }
691         if (ssid_as_path.get_active()) {
692                 fbvalue += 4;
693         }
694         if (heart_beat.get_active()) {
695                 fbvalue += 8;
696         }
697         if (master_fb.get_active()) {
698                 fbvalue += 16;
699         }
700         if (bar_and_beat.get_active()) {
701                 fbvalue += 32;
702         }
703         if (smpte.get_active()) {
704                 fbvalue += 64;
705         }
706         if (meter_float.get_active()) {
707                 fbvalue += 128;
708         }
709         if (meter_led.get_active()) {
710                 fbvalue += 256;
711         }
712         if (signal_present.get_active()) {
713                 fbvalue += 512;
714         }
715         if (hp_samples.get_active()) {
716                 fbvalue += 1024;
717         }
718         if (hp_min_sec.get_active()) {
719                 fbvalue += 2048;
720         }
721         if (hp_gui.get_active()) {
722                 fbvalue += 4096;
723         }
724         if (select_fb.get_active()) {
725                 fbvalue += 8192;
726         }
727         if (use_osc10.get_active()) {
728                 fbvalue += 16384;
729         }
730
731         current_feedback.set_text(string_compose("%1", fbvalue));
732 }
733
734 void
735 OSC_GUI::calculate_strip_types ()
736 {
737         stvalue = 0;
738         if (audio_tracks.get_active()) {
739                 stvalue += 1;
740         }
741         if (midi_tracks.get_active()) {
742                 stvalue += 2;
743         }
744         if (audio_buses.get_active()) {
745                 stvalue += 4;
746         }
747         if (midi_buses.get_active()) {
748                 stvalue += 8;
749         }
750         if (control_masters.get_active()) {
751                 stvalue += 16;
752         }
753         if (master_type.get_active()) {
754                 stvalue += 32;
755         }
756         if (monitor_type.get_active()) {
757                 stvalue += 64;
758         }
759         if (audio_auxes.get_active()) {
760                 stvalue += 128;
761         }
762         if (selected_tracks.get_active()) {
763                 stvalue += 256;
764         }
765         if (hidden_tracks.get_active()) {
766                 stvalue += 512;
767         }
768         if (usegroups.get_active()) {
769                 stvalue += 1024;
770         }
771
772         current_strip_types.set_text(string_compose("%1", stvalue));
773 }
774
775 void
776 OSC_GUI::set_bitsets ()
777 {
778         if (preset_busy) {
779                 return;
780         }
781         calculate_strip_types ();
782         calculate_feedback ();
783         cp.set_defaultstrip (stvalue);
784         cp.set_defaultfeedback (fbvalue);
785         save_user ();
786 }
787
788 void
789 OSC_GUI::scan_preset_files ()
790 {
791         std::vector<std::string> presets;
792         Searchpath spath (preset_search_path());
793
794         find_files_matching_filter (presets, spath, preset_filter, 0, false, true);
795         //device_profiles.clear ();preset_list.clear // first two entries already there
796
797         if (presets.empty()) {
798                 error << "No OSC preset files found using " << spath.to_string() << endmsg;
799                 return;
800         }
801
802         for (std::vector<std::string>::iterator i = presets.begin(); i != presets.end(); ++i) {
803                 std::string fullpath = *i;
804                 //DeviceProfile dp; // has to be initial every loop or info from last added.
805
806                 XMLTree tree;
807
808                 if (!tree.read (fullpath.c_str())) {
809                         continue;
810                 }
811
812                 XMLNode* root = tree.root ();
813                 if (!root) {
814                         continue;
815                 }
816                 const XMLProperty* prop;
817                 const XMLNode* child;
818
819                 if (root->name() != "OSCPreset") {
820                         continue;
821                 }
822
823                 if ((child = root->child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
824                         continue;
825                 } else {
826                         if (prop->value() == "User") {
827                                 // We already added user but no file name
828                                 preset_files[prop->value()] = fullpath;
829                         } else if (preset_files.find(prop->value()) == preset_files.end()) {
830                                 preset_options.push_back (prop->value());
831                                 preset_files[prop->value()] = fullpath;
832                         }
833                 }
834
835         }
836 }
837
838 void
839 OSC_GUI::save_user ()
840 {
841         if (preset_busy) {
842                 return;
843         }
844         std::string fullpath = user_preset_directory();
845
846         if (g_mkdir_with_parents (fullpath.c_str(), 0755) < 0) {
847                 error << string_compose(_("Session: cannot create user OSC profile folder \"%1\" (%2)"), fullpath, strerror (errno)) << endmsg;
848                 return;
849         }
850
851         fullpath = Glib::build_filename (fullpath, string_compose ("%1%2", legalize_for_path ("user"), preset_suffix));
852
853         XMLNode* node = new XMLNode ("OSCPreset");
854         XMLNode* child = new XMLNode ("Name");
855
856         child->set_property ("value", "User");
857         node->add_child_nocopy (*child);
858
859         child = new XMLNode ("PortMode");
860         child->set_property ("value", cp.get_portmode());
861         node->add_child_nocopy (*child);
862
863         child = new XMLNode ("Remote-Port");
864         child->set_property ("value", cp.get_remote_port());
865         node->add_child_nocopy (*child);
866
867         child = new XMLNode ("Bank-Size");
868         child->set_property ("value", cp.get_banksize());
869         node->add_child_nocopy (*child);
870
871         child = new XMLNode ("Send-Size");
872         child->set_property ("value", cp.get_send_size());
873         node->add_child_nocopy (*child);
874
875         child = new XMLNode ("Plugin-Size");
876         child->set_property ("value", cp.get_plugin_size());
877         node->add_child_nocopy (*child);
878
879         child = new XMLNode ("Strip-Types");
880         child->set_property ("value", cp.get_defaultstrip());
881         node->add_child_nocopy (*child);
882
883         child = new XMLNode ("Feedback");
884         child->set_property ("value", cp.get_defaultfeedback());
885         node->add_child_nocopy (*child);
886
887         child = new XMLNode ("Gain-Mode");
888         child->set_property ("value", cp.get_gainmode());
889         node->add_child_nocopy (*child);
890
891         XMLTree tree;
892         tree.set_root (node);
893
894         if (!tree.write (fullpath)) {
895                 error << string_compose ("OSC profile not saved to %1", fullpath) << endmsg;
896         }
897         preset_combo.set_active (2);
898         cp.gui_changed();
899         clear_device ();
900
901 }
902
903 void
904 OSC_GUI::load_preset (std::string preset)
905 {
906         if (preset == "User" && preset_files["User"] == "") {
907                 restore_sesn_values ();
908         } else if (preset_files.find(preset) != preset_files.end()) {
909                 XMLTree tree;
910
911                 if (!tree.read (preset_files[preset])) {
912                         std::cerr << "preset file not found " << preset_files[preset] << "\n";
913                         return;
914                 }
915
916                 XMLNode* root = tree.root ();
917                 if (!root) {
918                         std::cerr << "invalid preset file " << preset_files[preset] << "\n";
919                         return;
920                 }
921                 const XMLProperty* prop;
922                 const XMLNode* child;
923
924                 if (root->name() != "OSCPreset") {
925                         std::cerr << "invalid preset file " << preset_files[preset] << "\n";
926                         return;
927                 }
928
929                 if ((child = root->child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
930                         std::cerr << "preset file missing Name " << preset_files[preset] << "\n";
931                         return;
932                 }
933                 if ((child = root->child ("PortMode")) == 0 || (prop = child->property ("value")) == 0) {
934                         cp.set_portmode (sesn_portmode);
935                         portmode_combo.set_active (sesn_portmode);
936                 } else {
937                         cp.set_portmode (atoi (prop->value().c_str()));
938                         portmode_combo.set_active (atoi (prop->value().c_str()));
939                 }
940                 if ((child = root->child ("Remote-Port")) == 0 || (prop = child->property ("value")) == 0) {
941                         cp.set_remote_port (sesn_port);
942                         port_entry.set_text (sesn_port);
943                 } else {
944                         cp.set_remote_port (prop->value());
945                         port_entry.set_text (prop->value());
946                 }
947                 if ((child = root->child ("Bank-Size")) == 0 || (prop = child->property ("value")) == 0) {
948                         cp.set_banksize (sesn_bank);
949                         bank_entry.set_text (string_compose("%1", sesn_bank));
950                 } else {
951                         cp.set_banksize (atoi (prop->value().c_str()));
952                         bank_entry.set_text (prop->value().c_str());
953                 }
954                 if ((child = root->child ("Send-Size")) == 0 || (prop = child->property ("value")) == 0) {
955                         cp.set_send_size (sesn_send);
956                         send_page_entry.set_text (string_compose("%1", sesn_send));
957                 } else {
958                         cp.set_send_size (atoi (prop->value().c_str()));
959                         send_page_entry.set_text (prop->value().c_str());
960                 }
961                 if ((child = root->child ("Plugin-Size")) == 0 || (prop = child->property ("value")) == 0) {
962                         cp.set_plugin_size (sesn_plugin);
963                         plugin_page_entry.set_text (string_compose("%1", sesn_plugin));
964                 } else {
965                         cp.set_plugin_size (atoi (prop->value().c_str()));
966                         plugin_page_entry.set_text (prop->value().c_str());
967                 }
968                 if ((child = root->child ("Strip-Types")) == 0 || (prop = child->property ("value")) == 0) {
969                         cp.set_defaultstrip (sesn_strips);
970                 } else {
971                         cp.set_defaultstrip (atoi (prop->value().c_str()));
972                 }
973                 if ((child = root->child ("Feedback")) == 0 || (prop = child->property ("value")) == 0) {
974                         cp.set_defaultfeedback (sesn_feedback);
975                 } else {
976                         cp.set_defaultfeedback (atoi (prop->value().c_str()));
977                 }
978                 reshow_values (); // show strip types and feed back in GUI
979
980                 if ((child = root->child ("Gain-Mode")) == 0 || (prop = child->property ("value")) == 0) {
981                         cp.set_gainmode (sesn_gainmode);
982                         gainmode_combo.set_active (sesn_gainmode);
983                 } else {
984                         cp.set_gainmode (atoi (prop->value().c_str()));
985                         gainmode_combo.set_active (atoi (prop->value().c_str()));
986                 }
987                 cp.gui_changed();
988                 clear_device ();
989
990         }
991 }
992
993 void
994 OSC_GUI::get_session ()
995 {
996         sesn_portmode = cp.get_portmode ();
997         sesn_port = cp.get_remote_port ();
998         sesn_bank = cp.get_banksize ();
999         sesn_send = cp.get_send_size ();
1000         sesn_plugin = cp.get_plugin_size ();
1001         sesn_strips = cp.get_defaultstrip ();
1002         sesn_feedback = cp.get_defaultfeedback ();
1003         sesn_gainmode = cp.get_gainmode ();
1004 }
1005
1006 void
1007 OSC_GUI::restore_sesn_values ()
1008 {
1009         cp.set_portmode (sesn_portmode);
1010         portmode_combo.set_active (sesn_portmode);
1011         cp.set_remote_port (sesn_port);
1012         port_entry.set_text (sesn_port);
1013         cp.set_banksize (sesn_bank);
1014         bank_entry.set_text (string_compose ("%1", sesn_bank));
1015         cp.set_send_size (sesn_send);
1016         send_page_entry.set_text (string_compose ("%1", sesn_send));
1017         cp.set_plugin_size (sesn_plugin);
1018         plugin_page_entry.set_text (string_compose ("%1", sesn_plugin));
1019         cp.set_defaultstrip (sesn_strips);
1020         cp.set_defaultfeedback (sesn_feedback);
1021         reshow_values ();
1022         cp.set_gainmode (sesn_gainmode);
1023         gainmode_combo.set_active (sesn_gainmode);
1024 }