OSC: account for user sending the wrong number of paramters gracefully
[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
158         set_popdown_strings (debug_combo, debug_options);
159         debug_combo.set_active ((int)cp.get_debug_mode());
160         ++n;
161
162         // Preset loader combo
163         label = manage (new Gtk::Label(_("Preset:")));
164         label->set_alignment(1, .5);
165         table->attach (*label, 0, 1, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
166         table->attach (preset_combo, 1, 2, n, n+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
167
168         preset_files.clear();
169         // no files for these two
170         preset_options.push_back (_("Last Loaded Session"));
171         preset_options.push_back (_("Ardour Factory Setting"));
172         // user is special it appears in menu even if no file is present
173         preset_options.push_back ("User");
174         preset_files["User"] = "";
175         // scan for OSC .preset files
176         scan_preset_files ();
177
178         set_popdown_strings (preset_combo, preset_options);
179         preset_combo.set_active (0);
180         preset_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::preset_changed));
181         ++n;
182
183         table->show_all ();
184         append_page (*table, _("OSC Setup"));
185
186         debug_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::debug_changed));
187         portmode_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::portmode_changed));
188         gainmode_combo.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::gainmode_changed));
189         port_entry.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::port_changed));
190         port_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &OSC_GUI::port_focus_out));
191         bank_entry.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::bank_changed));
192         send_page_entry.signal_changed().connect (sigc::mem_fun (*this, &OSC_GUI::send_page_changed));
193         plugin_page_entry.signal_changed().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         label = manage (new Gtk::Label(_("Use Groups:")));
276         label->set_alignment(1, .5);
277         sttable->attach (*label, 0, 1, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
278         sttable->attach (usegroups, 1, 2, stn, stn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
279         ++stn;
280
281
282         sttable->show_all ();
283         append_page (*sttable, _("Default Strip Types"));
284
285
286         // Feedback Calculate Page
287         int fn = 0; // table row
288         Table* fbtable = manage (new Table);
289         fbtable->set_row_spacings (4);
290         fbtable->set_col_spacings (6);
291         fbtable->set_border_width (12);
292
293         label = manage (new Gtk::Label(_("Select Desired Types of Feedback")));
294         fbtable->attach (*label, 0, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
295         ++fn;
296
297         label = manage (new Gtk::Label(_("Feedback Value:")));
298         label->set_alignment(1, .5);
299         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
300         calculate_feedback ();
301         current_feedback.set_width_chars(10);
302         fbtable->attach (current_feedback, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 15);
303         ++fn;
304
305         label = manage (new Gtk::Label(_("Strip Buttons:")));
306         label->set_alignment(1, .5);
307         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
308         fbtable->attach (strip_buttons_button, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
309         ++fn;
310
311         label = manage (new Gtk::Label(_("Strip Controls:")));
312         label->set_alignment(1, .5);
313         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
314         fbtable->attach (strip_control_button, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
315         ++fn;
316
317         label = manage (new Gtk::Label(_("Use SSID as Path Extension:")));
318         label->set_alignment(1, .5);
319         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
320         fbtable->attach (ssid_as_path, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
321         ++fn;
322
323         label = manage (new Gtk::Label(_("Use Heart Beat:")));
324         label->set_alignment(1, .5);
325         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
326         fbtable->attach (heart_beat, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
327         ++fn;
328
329         label = manage (new Gtk::Label(_("Master Section:")));
330         label->set_alignment(1, .5);
331         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
332         fbtable->attach (master_fb, 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 Bar and Beat:")));
336         label->set_alignment(1, .5);
337         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
338         fbtable->attach (bar_and_beat, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
339         ++fn;
340
341         label = manage (new Gtk::Label(_("Play Head Position as SMPTE Time:")));
342         label->set_alignment(1, .5);
343         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
344         fbtable->attach (smpte, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
345         ++fn;
346
347         label = manage (new Gtk::Label(_("Metering as a Float:")));
348         label->set_alignment(1, .5);
349         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
350         fbtable->attach (meter_float, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
351         ++fn;
352
353         label = manage (new Gtk::Label(_("Metering as a LED Strip:")));
354         label->set_alignment(1, .5);
355         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
356         fbtable->attach (meter_led, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
357         ++fn;
358
359         label = manage (new Gtk::Label(_("Signal Present:")));
360         label->set_alignment(1, .5);
361         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
362         fbtable->attach (signal_present, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
363         ++fn;
364
365         label = manage (new Gtk::Label(_("Play Head Position as Samples:")));
366         label->set_alignment(1, .5);
367         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
368         fbtable->attach (hp_samples, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
369         ++fn;
370
371         label = manage (new Gtk::Label(_("Playhead Position as Minutes Seconds:")));
372         label->set_alignment(1, .5);
373         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
374         fbtable->attach (hp_min_sec, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
375         ++fn;
376
377         label = manage (new Gtk::Label(_("Playhead Position as per GUI Clock:")));
378         label->set_alignment(1, .5);
379         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
380         fbtable->attach (hp_gui, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
381         hp_gui.set_sensitive (false); // we don't have this yet (Mixbus wants)
382         ++fn;
383
384         label = manage (new Gtk::Label(_("Extra Select Only Feedback:")));
385         label->set_alignment(1, .5);
386         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
387         fbtable->attach (select_fb, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
388         ++fn;
389
390         label = manage (new Gtk::Label(_("Use /reply instead of #reply:")));
391         label->set_alignment(1, .5);
392         fbtable->attach (*label, 0, 1, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
393         fbtable->attach (use_osc10, 1, 2, fn, fn+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
394         ++fn;
395
396         fbtable->show_all ();
397         append_page (*fbtable, _("Default Feedback"));
398         // set strips and feedback from loaded default values
399         reshow_values ();
400         // connect signals
401         audio_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
402         midi_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
403         audio_buses.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
404         audio_auxes.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
405         midi_buses.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
406         control_masters.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
407         master_type.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
408         monitor_type.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
409         selected_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
410         hidden_tracks.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
411         usegroups.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
412         strip_buttons_button.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
413         strip_control_button.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
414         ssid_as_path.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
415         heart_beat.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
416         master_fb.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
417         bar_and_beat.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
418         smpte.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
419         meter_float.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
420         meter_led.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
421         signal_present.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
422         hp_samples.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
423         hp_min_sec.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
424         hp_gui.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
425         select_fb.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
426         use_osc10.signal_clicked().connect (sigc::mem_fun (*this, &OSC_GUI::set_bitsets));
427         preset_busy = false;
428
429 }
430
431 OSC_GUI::~OSC_GUI ()
432 {
433 }
434
435 // static directory and file handling stuff
436 static Searchpath
437 preset_search_path ()
438 {
439         bool preset_path_defined = false;
440         std::string spath_env (Glib::getenv (preset_env_variable_name, preset_path_defined));
441
442         if (preset_path_defined) {
443                 return spath_env;
444         }
445
446         Searchpath spath (ardour_data_search_path());
447         spath.add_subdirectory_to_paths(preset_dir_name);
448
449         return spath;
450 }
451
452 static std::string
453 user_preset_directory ()
454 {
455         return Glib::build_filename (user_config_directory(), preset_dir_name);
456 }
457
458 static bool
459 preset_filter (const std::string &str, void* /*arg*/)
460 {
461         return (str.length() > strlen(preset_suffix) &&
462                 str.find (preset_suffix) == (str.length() - strlen (preset_suffix)));
463 }
464
465 static std::string
466 legalize_for_path (const std::string& str)
467 {
468         std::string::size_type pos;
469         std::string illegal_chars = "/\\"; /* DOS, POSIX. Yes, we're going to ignore HFS */
470         std::string legal;
471
472         legal = str;
473         pos = 0;
474
475         while ((pos = legal.find_first_of (illegal_chars, pos)) != std::string::npos) {
476                 legal.replace (pos, 1, "_");
477                 pos += 1;
478         }
479
480         return std::string (legal);
481 }
482
483 // end of static functions
484
485 void
486 OSC_GUI::debug_changed ()
487 {
488         std::string str = debug_combo.get_active_text ();
489         if (str == _("Off")) {
490                 cp.set_debug_mode (OSC::Off);
491         }
492         else if (str == _("Log invalid messages")) {
493                 cp.set_debug_mode (OSC::Unhandled);
494         }
495         else if (str == _("Log all messages")) {
496                 cp.set_debug_mode (OSC::All);
497         }
498         else {
499                 std::cerr << "Invalid OSC Debug Mode\n";
500                 assert (0);
501         }
502 }
503
504 void
505 OSC_GUI::portmode_changed ()
506 {
507         int pm = portmode_combo.get_active_row_number ();
508         cp.set_portmode (pm);
509         if (pm) {
510                 port_entry.set_sensitive (true);
511         } else {
512                 port_entry.set_sensitive (false);
513         }
514         save_user ();
515 }
516
517 void
518 OSC_GUI::port_changed ()
519 {
520         std::string str = port_entry.get_text ();
521         int prt = atoi (str.c_str());
522         if (prt == 3819 || prt < 1024) {
523                 // indicate non-valid text
524                 port_entry.set_progress_fraction (1.0);
525         } else {
526                 port_entry.set_progress_fraction (0.0);
527                 cp.set_remote_port (string_compose ("%1", prt));
528                 save_user ();
529         }
530 }
531
532 bool
533 OSC_GUI::port_focus_out (GdkEventFocus* )
534 {
535         std::string str = port_entry.get_text ();
536         int prt = atoi (str.c_str());
537         if (prt == 3819 || prt < 1024) {
538                 port_entry.set_text(cp.get_remote_port().c_str());
539                 port_entry.set_progress_fraction (0.0);
540         }
541         return false;
542 }
543
544 void
545 OSC_GUI::bank_changed ()
546 {
547         uint32_t bsize = atoi(bank_entry.get_text ());
548         bank_entry.set_text (string_compose ("%1", bsize));
549         cp.set_banksize (bsize);
550         save_user ();
551
552 }
553
554 void
555 OSC_GUI::send_page_changed ()
556 {
557         uint32_t ssize = atoi (send_page_entry.get_text ());
558         send_page_entry.set_text (string_compose ("%1", ssize));
559         cp.set_send_size (ssize);
560         save_user ();
561
562 }
563
564 void
565 OSC_GUI::plugin_page_changed ()
566 {
567         uint32_t psize = atoi (plugin_page_entry.get_text ());
568         plugin_page_entry.set_text (string_compose ("%1", psize));
569         cp.set_plugin_size (psize);
570         save_user ();
571
572 }
573
574 void
575 OSC_GUI::gainmode_changed ()
576 {
577         std::string str = gainmode_combo.get_active_text ();
578         if (str == _("/strip/gain (dB)")) {
579                 cp.set_gainmode (0);
580         }
581         else if (str == _("/strip/fader (Position)")) {
582                 cp.set_gainmode (1);
583         }
584         else {
585                 std::cerr << "Invalid OSC Gain Mode\n";
586                 assert (0);
587         }
588         save_user ();
589 }
590
591 void
592 OSC_GUI::clear_device ()
593 {
594         cp.clear_devices();
595 }
596
597 void
598 OSC_GUI::preset_changed ()
599 {
600         preset_busy = true;
601         std::string str = preset_combo.get_active_text ();
602         if (str == "Last Loaded Session") {
603                 restore_sesn_values ();
604         }
605         else if (str == "Ardour Factory Setting") {
606                 factory_reset ();
607         }
608         else if (str == "User") {
609                 load_preset ("User");
610         }
611         else {
612                 load_preset (str);
613         }
614         cp.clear_devices ();
615         preset_busy = false;
616 }
617
618 void
619 OSC_GUI::factory_reset ()
620 {
621         cp.set_banksize (0);
622         bank_entry.set_text ("0");
623         cp.set_send_size (0);
624         send_page_entry.set_text ("0");
625         cp.set_plugin_size (0);
626         plugin_page_entry.set_text ("0");
627         cp.set_defaultstrip (159);
628         cp.set_defaultfeedback (0);
629         reshow_values ();
630         cp.set_gainmode (0);
631         gainmode_combo.set_active (0);
632         cp.set_portmode (1);
633         portmode_combo.set_active (1);
634         cp.set_remote_port ("8000");
635         port_entry.set_text ("8000");
636         cp.clear_devices ();
637         cp.gui_changed ();
638 }
639
640 void
641 OSC_GUI::reshow_values ()
642 {
643         def_strip = cp.get_defaultstrip();
644         audio_tracks.set_active(def_strip & 1);
645         midi_tracks.set_active(def_strip & 2);
646         audio_buses.set_active(def_strip & 4);
647         midi_buses.set_active(def_strip & 8);
648         control_masters.set_active(def_strip & 16);
649         master_type.set_active(def_strip & 32);
650         monitor_type.set_active(def_strip & 64);
651         audio_auxes.set_active(def_strip & 128);
652         selected_tracks.set_active(def_strip & 256);
653         hidden_tracks.set_active(def_strip & 512);
654         usegroups.set_active(def_strip & 1024);
655         def_feedback = cp.get_defaultfeedback();
656         strip_buttons_button.set_active(def_feedback & 1);
657         strip_control_button.set_active(def_feedback & 2);
658         ssid_as_path.set_active(def_feedback & 4);
659         heart_beat.set_active(def_feedback & 8);
660         master_fb.set_active(def_feedback & 16);
661         bar_and_beat.set_active(def_feedback & 32);
662         smpte.set_active(def_feedback & 64);
663         meter_float.set_active(def_feedback & 128);
664         meter_led.set_active(def_feedback & 256);
665         signal_present.set_active(def_feedback & 512);
666         hp_samples.set_active(def_feedback & 1024);
667         hp_min_sec.set_active (def_feedback & 2048);
668         //hp_gui.set_active (false); // we don't have this yet (Mixbus wants)
669         select_fb.set_active(def_feedback & 8192);
670         use_osc10.set_active(def_feedback & 16384);
671
672         calculate_strip_types ();
673         calculate_feedback ();
674 }
675
676 void
677 OSC_GUI::calculate_feedback ()
678 {
679         fbvalue = 0;
680         if (strip_buttons_button.get_active()) {
681                 fbvalue += 1;
682         }
683         if (strip_control_button.get_active()) {
684                 fbvalue += 2;
685         }
686         if (ssid_as_path.get_active()) {
687                 fbvalue += 4;
688         }
689         if (heart_beat.get_active()) {
690                 fbvalue += 8;
691         }
692         if (master_fb.get_active()) {
693                 fbvalue += 16;
694         }
695         if (bar_and_beat.get_active()) {
696                 fbvalue += 32;
697         }
698         if (smpte.get_active()) {
699                 fbvalue += 64;
700         }
701         if (meter_float.get_active()) {
702                 fbvalue += 128;
703         }
704         if (meter_led.get_active()) {
705                 fbvalue += 256;
706         }
707         if (signal_present.get_active()) {
708                 fbvalue += 512;
709         }
710         if (hp_samples.get_active()) {
711                 fbvalue += 1024;
712         }
713         if (hp_min_sec.get_active()) {
714                 fbvalue += 2048;
715         }
716         if (hp_gui.get_active()) {
717                 fbvalue += 4096;
718         }
719         if (select_fb.get_active()) {
720                 fbvalue += 8192;
721         }
722         if (use_osc10.get_active()) {
723                 fbvalue += 16384;
724         }
725
726         current_feedback.set_text(string_compose("%1", fbvalue));
727 }
728
729 void
730 OSC_GUI::calculate_strip_types ()
731 {
732         stvalue = 0;
733         if (audio_tracks.get_active()) {
734                 stvalue += 1;
735         }
736         if (midi_tracks.get_active()) {
737                 stvalue += 2;
738         }
739         if (audio_buses.get_active()) {
740                 stvalue += 4;
741         }
742         if (midi_buses.get_active()) {
743                 stvalue += 8;
744         }
745         if (control_masters.get_active()) {
746                 stvalue += 16;
747         }
748         if (master_type.get_active()) {
749                 stvalue += 32;
750         }
751         if (monitor_type.get_active()) {
752                 stvalue += 64;
753         }
754         if (audio_auxes.get_active()) {
755                 stvalue += 128;
756         }
757         if (selected_tracks.get_active()) {
758                 stvalue += 256;
759         }
760         if (hidden_tracks.get_active()) {
761                 stvalue += 512;
762         }
763         if (usegroups.get_active()) {
764                 stvalue += 1024;
765         }
766
767         current_strip_types.set_text(string_compose("%1", stvalue));
768 }
769
770 void
771 OSC_GUI::set_bitsets ()
772 {
773         if (preset_busy) {
774                 return;
775         }
776         calculate_strip_types ();
777         calculate_feedback ();
778         cp.set_defaultstrip (stvalue);
779         cp.set_defaultfeedback (fbvalue);
780         save_user ();
781 }
782
783 void
784 OSC_GUI::scan_preset_files ()
785 {
786         std::vector<std::string> presets;
787         Searchpath spath (preset_search_path());
788
789         find_files_matching_filter (presets, spath, preset_filter, 0, false, true);
790         //device_profiles.clear ();preset_list.clear // first two entries already there
791
792         if (presets.empty()) {
793                 error << "No OSC preset files found using " << spath.to_string() << endmsg;
794                 return;
795         }
796
797         for (std::vector<std::string>::iterator i = presets.begin(); i != presets.end(); ++i) {
798                 std::string fullpath = *i;
799                 //DeviceProfile dp; // has to be initial every loop or info from last added.
800
801                 XMLTree tree;
802
803                 if (!tree.read (fullpath.c_str())) {
804                         continue;
805                 }
806
807                 XMLNode* root = tree.root ();
808                 if (!root) {
809                         continue;
810                 }
811                 const XMLProperty* prop;
812                 const XMLNode* child;
813
814                 if (root->name() != "OSCPreset") {
815                         continue;
816                 }
817
818                 if ((child = root->child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
819                         continue;
820                 } else {
821                         if (prop->value() == "User") {
822                                 // We already added user but no file name
823                                 preset_files[prop->value()] = fullpath;
824                         } else if (preset_files.find(prop->value()) == preset_files.end()) {
825                                 preset_options.push_back (prop->value());
826                                 preset_files[prop->value()] = fullpath;
827                         }
828                 }
829
830         }
831 }
832
833 void
834 OSC_GUI::save_user ()
835 {
836         if (preset_busy) {
837                 return;
838         }
839         std::string fullpath = user_preset_directory();
840
841         if (g_mkdir_with_parents (fullpath.c_str(), 0755) < 0) {
842                 error << string_compose(_("Session: cannot create user OSC profile folder \"%1\" (%2)"), fullpath, strerror (errno)) << endmsg;
843                 return;
844         }
845
846         fullpath = Glib::build_filename (fullpath, string_compose ("%1%2", legalize_for_path ("user"), preset_suffix));
847
848         XMLNode* node = new XMLNode ("OSCPreset");
849         XMLNode* child = new XMLNode ("Name");
850
851         child->set_property ("value", "User");
852         node->add_child_nocopy (*child);
853
854         child = new XMLNode ("PortMode");
855         child->set_property ("value", cp.get_portmode());
856         node->add_child_nocopy (*child);
857
858         child = new XMLNode ("Remote-Port");
859         child->set_property ("value", cp.get_remote_port());
860         node->add_child_nocopy (*child);
861
862         child = new XMLNode ("Bank-Size");
863         child->set_property ("value", cp.get_banksize());
864         node->add_child_nocopy (*child);
865
866         child = new XMLNode ("Send-Size");
867         child->set_property ("value", cp.get_send_size());
868         node->add_child_nocopy (*child);
869
870         child = new XMLNode ("Plugin-Size");
871         child->set_property ("value", cp.get_plugin_size());
872         node->add_child_nocopy (*child);
873
874         child = new XMLNode ("Strip-Types");
875         child->set_property ("value", cp.get_defaultstrip());
876         node->add_child_nocopy (*child);
877
878         child = new XMLNode ("Feedback");
879         child->set_property ("value", cp.get_defaultfeedback());
880         node->add_child_nocopy (*child);
881
882         child = new XMLNode ("Gain-Mode");
883         child->set_property ("value", cp.get_gainmode());
884         node->add_child_nocopy (*child);
885
886         XMLTree tree;
887         tree.set_root (node);
888
889         if (!tree.write (fullpath)) {
890                 error << string_compose ("OSC profile not saved to %1", fullpath) << endmsg;
891         }
892         preset_combo.set_active (2);
893         cp.gui_changed();
894         clear_device ();
895
896 }
897
898 void
899 OSC_GUI::load_preset (std::string preset)
900 {
901         if (preset == "User" && preset_files["User"] == "") {
902                 restore_sesn_values ();
903         } else if (preset_files.find(preset) != preset_files.end()) {
904                 XMLTree tree;
905
906                 if (!tree.read (preset_files[preset])) {
907                         std::cerr << "preset file not found " << preset_files[preset] << "\n";
908                         return;
909                 }
910
911                 XMLNode* root = tree.root ();
912                 if (!root) {
913                         std::cerr << "invalid preset file " << preset_files[preset] << "\n";
914                         return;
915                 }
916                 const XMLProperty* prop;
917                 const XMLNode* child;
918
919                 if (root->name() != "OSCPreset") {
920                         std::cerr << "invalid preset file " << preset_files[preset] << "\n";
921                         return;
922                 }
923
924                 if ((child = root->child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
925                         std::cerr << "preset file missing Name " << preset_files[preset] << "\n";
926                         return;
927                 }
928                 if ((child = root->child ("PortMode")) == 0 || (prop = child->property ("value")) == 0) {
929                         cp.set_portmode (sesn_portmode);
930                         portmode_combo.set_active (sesn_portmode);
931                 } else {
932                         cp.set_portmode (atoi (prop->value().c_str()));
933                         portmode_combo.set_active (atoi (prop->value().c_str()));
934                 }
935                 if ((child = root->child ("Remote-Port")) == 0 || (prop = child->property ("value")) == 0) {
936                         cp.set_remote_port (sesn_port);
937                         port_entry.set_text (sesn_port);
938                 } else {
939                         cp.set_remote_port (prop->value());
940                         port_entry.set_text (prop->value());
941                 }
942                 if ((child = root->child ("Bank-Size")) == 0 || (prop = child->property ("value")) == 0) {
943                         cp.set_banksize (sesn_bank);
944                         bank_entry.set_text (string_compose("%1", sesn_bank));
945                 } else {
946                         cp.set_banksize (atoi (prop->value().c_str()));
947                         bank_entry.set_text (prop->value().c_str());
948                 }
949                 if ((child = root->child ("Send-Size")) == 0 || (prop = child->property ("value")) == 0) {
950                         cp.set_send_size (sesn_send);
951                         send_page_entry.set_text (string_compose("%1", sesn_send));
952                 } else {
953                         cp.set_send_size (atoi (prop->value().c_str()));
954                         send_page_entry.set_text (prop->value().c_str());
955                 }
956                 if ((child = root->child ("Plugin-Size")) == 0 || (prop = child->property ("value")) == 0) {
957                         cp.set_plugin_size (sesn_plugin);
958                         plugin_page_entry.set_text (string_compose("%1", sesn_plugin));
959                 } else {
960                         cp.set_plugin_size (atoi (prop->value().c_str()));
961                         plugin_page_entry.set_text (prop->value().c_str());
962                 }
963                 if ((child = root->child ("Strip-Types")) == 0 || (prop = child->property ("value")) == 0) {
964                         cp.set_defaultstrip (sesn_strips);
965                 } else {
966                         cp.set_defaultstrip (atoi (prop->value().c_str()));
967                 }
968                 if ((child = root->child ("Feedback")) == 0 || (prop = child->property ("value")) == 0) {
969                         cp.set_defaultfeedback (sesn_feedback);
970                 } else {
971                         cp.set_defaultfeedback (atoi (prop->value().c_str()));
972                 }
973                 reshow_values (); // show strip types and feed back in GUI
974
975                 if ((child = root->child ("Gain-Mode")) == 0 || (prop = child->property ("value")) == 0) {
976                         cp.set_gainmode (sesn_gainmode);
977                         gainmode_combo.set_active (sesn_gainmode);
978                 } else {
979                         cp.set_gainmode (atoi (prop->value().c_str()));
980                         gainmode_combo.set_active (atoi (prop->value().c_str()));
981                 }
982                 cp.gui_changed();
983
984         }
985 }
986
987 void
988 OSC_GUI::get_session ()
989 {
990         sesn_portmode = cp.get_portmode ();
991         sesn_port = cp.get_remote_port ();
992         sesn_bank = cp.get_banksize ();
993         sesn_send = cp.get_send_size ();
994         sesn_plugin = cp.get_plugin_size ();
995         sesn_strips = cp.get_defaultstrip ();
996         sesn_feedback = cp.get_defaultfeedback ();
997         sesn_gainmode = cp.get_gainmode ();
998 }
999
1000 void
1001 OSC_GUI::restore_sesn_values ()
1002 {
1003         cp.set_portmode (sesn_portmode);
1004         portmode_combo.set_active (sesn_portmode);
1005         cp.set_remote_port (sesn_port);
1006         port_entry.set_text (sesn_port);
1007         cp.set_banksize (sesn_bank);
1008         bank_entry.set_text (string_compose ("%1", sesn_bank));
1009         cp.set_send_size (sesn_send);
1010         send_page_entry.set_text (string_compose ("%1", sesn_send));
1011         cp.set_plugin_size (sesn_plugin);
1012         plugin_page_entry.set_text (string_compose ("%1", sesn_plugin));
1013         cp.set_defaultstrip (sesn_strips);
1014         cp.set_defaultfeedback (sesn_feedback);
1015         reshow_values ();
1016         cp.set_gainmode (sesn_gainmode);
1017         gainmode_combo.set_active (sesn_gainmode);
1018 }