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