OSC: GUI tweaking
[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
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         int prt = atoi (str.c_str());
515         if (prt == 3819 || prt < 1024) {
516                 // indicate non-valid text
517                 port_entry.set_progress_fraction (1.0);
518         } else {
519                 port_entry.set_progress_fraction (0.0);
520                 cp.set_remote_port (string_compose ("%1", prt));
521                 save_user ();
522         }
523 }
524
525 bool
526 OSC_GUI::port_focus_out (GdkEventFocus* )
527 {
528         std::string str = port_entry.get_text ();
529         int prt = atoi (str.c_str());
530         if (prt == 3819 || prt < 1024) {
531                 port_entry.set_text(cp.get_remote_port().c_str());
532                 port_entry.set_progress_fraction (0.0);
533         }
534         return false;
535 }
536
537 void
538 OSC_GUI::bank_changed ()
539 {
540         uint32_t bsize = atoi(bank_entry.get_text ());
541         bank_entry.set_text (string_compose ("%1", bsize));
542         cp.set_banksize (bsize);
543         save_user ();
544
545 }
546
547 void
548 OSC_GUI::send_page_changed ()
549 {
550         uint32_t ssize = atoi (send_page_entry.get_text ());
551         send_page_entry.set_text (string_compose ("%1", ssize));
552         cp.set_send_size (ssize);
553         save_user ();
554
555 }
556
557 void
558 OSC_GUI::plugin_page_changed ()
559 {
560         uint32_t psize = atoi (plugin_page_entry.get_text ());
561         plugin_page_entry.set_text (string_compose ("%1", psize));
562         cp.set_plugin_size (psize);
563         save_user ();
564
565 }
566
567 void
568 OSC_GUI::gainmode_changed ()
569 {
570         std::string str = gainmode_combo.get_active_text ();
571         if (str == _("/strip/gain (dB)")) {
572                 cp.set_gainmode (0);
573         }
574         else if (str == _("/strip/fader (Position)")) {
575                 cp.set_gainmode (1);
576         }
577         else {
578                 std::cerr << "Invalid OSC Gain Mode\n";
579                 assert (0);
580         }
581         save_user ();
582 }
583
584 void
585 OSC_GUI::clear_device ()
586 {
587         cp.clear_devices();
588 }
589
590 void
591 OSC_GUI::preset_changed ()
592 {
593         preset_busy = true;
594         std::string str = preset_combo.get_active_text ();
595         if (str == "Last Loaded Session") {
596                 restore_sesn_values ();
597         }
598         else if (str == "Ardour Factory Setting") {
599                 factory_reset ();
600         }
601         else if (str == "User") {
602                 load_preset ("User");
603         }
604         else {
605                 load_preset (str);
606         }
607         cp.clear_devices ();
608         preset_busy = false;
609 }
610
611 void
612 OSC_GUI::factory_reset ()
613 {
614         cp.set_banksize (0);
615         bank_entry.set_text ("0");
616         cp.set_send_size (0);
617         send_page_entry.set_text ("0");
618         cp.set_plugin_size (0);
619         plugin_page_entry.set_text ("0");
620         cp.set_defaultstrip (159);
621         cp.set_defaultfeedback (0);
622         reshow_values ();
623         cp.set_gainmode (0);
624         gainmode_combo.set_active (0);
625         cp.set_portmode (0);
626         portmode_combo.set_active (0);
627         cp.set_remote_port ("8000");
628         port_entry.set_text ("8000");
629         cp.clear_devices ();
630         cp.gui_changed ();
631 }
632
633 void
634 OSC_GUI::reshow_values ()
635 {
636         def_strip = cp.get_defaultstrip();
637         audio_tracks.set_active(def_strip & 1);
638         midi_tracks.set_active(def_strip & 2);
639         audio_buses.set_active(def_strip & 4);
640         midi_buses.set_active(def_strip & 8);
641         control_masters.set_active(def_strip & 16);
642         master_type.set_active(def_strip & 32);
643         monitor_type.set_active(def_strip & 64);
644         audio_auxes.set_active(def_strip & 128);
645         selected_tracks.set_active(def_strip & 256);
646         hidden_tracks.set_active(def_strip & 512);
647         def_feedback = cp.get_defaultfeedback();
648         strip_buttons_button.set_active(def_feedback & 1);
649         strip_control_button.set_active(def_feedback & 2);
650         ssid_as_path.set_active(def_feedback & 4);
651         heart_beat.set_active(def_feedback & 8);
652         master_fb.set_active(def_feedback & 16);
653         bar_and_beat.set_active(def_feedback & 32);
654         smpte.set_active(def_feedback & 64);
655         meter_float.set_active(def_feedback & 128);
656         meter_led.set_active(def_feedback & 256);
657         signal_present.set_active(def_feedback & 512);
658         hp_samples.set_active(def_feedback & 1024);
659         hp_min_sec.set_active (def_feedback & 2048);
660         //hp_gui.set_active (false); // we don't have this yet (Mixbus wants)
661         select_fb.set_active(def_feedback & 8192);
662         use_osc10.set_active(def_feedback & 16384);
663
664         calculate_strip_types ();
665         calculate_feedback ();
666 }
667
668 void
669 OSC_GUI::calculate_feedback ()
670 {
671         fbvalue = 0;
672         if (strip_buttons_button.get_active()) {
673                 fbvalue += 1;
674         }
675         if (strip_control_button.get_active()) {
676                 fbvalue += 2;
677         }
678         if (ssid_as_path.get_active()) {
679                 fbvalue += 4;
680         }
681         if (heart_beat.get_active()) {
682                 fbvalue += 8;
683         }
684         if (master_fb.get_active()) {
685                 fbvalue += 16;
686         }
687         if (bar_and_beat.get_active()) {
688                 fbvalue += 32;
689         }
690         if (smpte.get_active()) {
691                 fbvalue += 64;
692         }
693         if (meter_float.get_active()) {
694                 fbvalue += 128;
695         }
696         if (meter_led.get_active()) {
697                 fbvalue += 256;
698         }
699         if (signal_present.get_active()) {
700                 fbvalue += 512;
701         }
702         if (hp_samples.get_active()) {
703                 fbvalue += 1024;
704         }
705         if (hp_min_sec.get_active()) {
706                 fbvalue += 2048;
707         }
708         if (hp_gui.get_active()) {
709                 fbvalue += 4096;
710         }
711         if (select_fb.get_active()) {
712                 fbvalue += 8192;
713         }
714         if (use_osc10.get_active()) {
715                 fbvalue += 16384;
716         }
717
718         current_feedback.set_text(string_compose("%1", fbvalue));
719 }
720
721 void
722 OSC_GUI::calculate_strip_types ()
723 {
724         stvalue = 0;
725         if (audio_tracks.get_active()) {
726                 stvalue += 1;
727         }
728         if (midi_tracks.get_active()) {
729                 stvalue += 2;
730         }
731         if (audio_buses.get_active()) {
732                 stvalue += 4;
733         }
734         if (midi_buses.get_active()) {
735                 stvalue += 8;
736         }
737         if (control_masters.get_active()) {
738                 stvalue += 16;
739         }
740         if (master_type.get_active()) {
741                 stvalue += 32;
742         }
743         if (monitor_type.get_active()) {
744                 stvalue += 64;
745         }
746         if (audio_auxes.get_active()) {
747                 stvalue += 128;
748         }
749         if (selected_tracks.get_active()) {
750                 stvalue += 256;
751         }
752         if (hidden_tracks.get_active()) {
753                 stvalue += 512;
754         }
755
756         current_strip_types.set_text(string_compose("%1", stvalue));
757 }
758
759 void
760 OSC_GUI::set_bitsets ()
761 {
762         if (preset_busy) {
763                 return;
764         }
765         calculate_strip_types ();
766         calculate_feedback ();
767         cp.set_defaultstrip (stvalue);
768         cp.set_defaultfeedback (fbvalue);
769         save_user ();
770 }
771
772 void
773 OSC_GUI::scan_preset_files ()
774 {
775         std::vector<std::string> presets;
776         Searchpath spath (preset_search_path());
777
778         find_files_matching_filter (presets, spath, preset_filter, 0, false, true);
779         //device_profiles.clear ();preset_list.clear // first two entries already there
780
781         if (presets.empty()) {
782                 error << "No OSC preset files found using " << spath.to_string() << endmsg;
783                 return;
784         }
785
786         for (std::vector<std::string>::iterator i = presets.begin(); i != presets.end(); ++i) {
787                 std::string fullpath = *i;
788                 //DeviceProfile dp; // has to be initial every loop or info from last added.
789
790                 XMLTree tree;
791
792                 if (!tree.read (fullpath.c_str())) {
793                         continue;
794                 }
795
796                 XMLNode* root = tree.root ();
797                 if (!root) {
798                         continue;
799                 }
800                 const XMLProperty* prop;
801                 const XMLNode* child;
802
803                 if (root->name() != "OSCPreset") {
804                         continue;
805                 }
806
807                 if ((child = root->child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
808                         continue;
809                 } else {
810                         if (prop->value() == "User") {
811                                 // We already added user but no file name
812                                 preset_files[prop->value()] = fullpath;
813                         } else if (preset_files.find(prop->value()) == preset_files.end()) {
814                                 preset_options.push_back (prop->value());
815                                 preset_files[prop->value()] = fullpath;
816                         }
817                 }
818
819         }
820 }
821
822 void
823 OSC_GUI::save_user ()
824 {
825         if (preset_busy) {
826                 return;
827         }
828         std::string fullpath = user_preset_directory();
829
830         if (g_mkdir_with_parents (fullpath.c_str(), 0755) < 0) {
831                 error << string_compose(_("Session: cannot create user OSC profile folder \"%1\" (%2)"), fullpath, strerror (errno)) << endmsg;
832                 return;
833         }
834
835         fullpath = Glib::build_filename (fullpath, string_compose ("%1%2", legalize_for_path ("user"), preset_suffix));
836
837         XMLNode* node = new XMLNode ("OSCPreset");
838         XMLNode* child = new XMLNode ("Name");
839
840         child->set_property ("value", "User");
841         node->add_child_nocopy (*child);
842
843         child = new XMLNode ("PortMode");
844         child->set_property ("value", cp.get_portmode());
845         node->add_child_nocopy (*child);
846
847         child = new XMLNode ("Remote-Port");
848         child->set_property ("value", cp.get_remote_port());
849         node->add_child_nocopy (*child);
850
851         child = new XMLNode ("Bank-Size");
852         child->set_property ("value", cp.get_banksize());
853         node->add_child_nocopy (*child);
854
855         child = new XMLNode ("Send-Size");
856         child->set_property ("value", cp.get_send_size());
857         node->add_child_nocopy (*child);
858
859         child = new XMLNode ("Plugin-Size");
860         child->set_property ("value", cp.get_plugin_size());
861         node->add_child_nocopy (*child);
862
863         child = new XMLNode ("Strip-Types");
864         child->set_property ("value", cp.get_defaultstrip());
865         node->add_child_nocopy (*child);
866
867         child = new XMLNode ("Feedback");
868         child->set_property ("value", cp.get_defaultfeedback());
869         node->add_child_nocopy (*child);
870
871         child = new XMLNode ("Gain-Mode");
872         child->set_property ("value", cp.get_gainmode());
873         node->add_child_nocopy (*child);
874
875         XMLTree tree;
876         tree.set_root (node);
877
878         if (!tree.write (fullpath)) {
879                 error << string_compose ("OSC profile not saved to %1", fullpath) << endmsg;
880         }
881         preset_combo.set_active (2);
882         cp.gui_changed();
883         clear_device ();
884
885 }
886
887 void
888 OSC_GUI::load_preset (std::string preset)
889 {
890         if (preset == "User" && preset_files["User"] == "") {
891                 restore_sesn_values ();
892         } else if (preset_files.find(preset) != preset_files.end()) {
893                 XMLTree tree;
894
895                 if (!tree.read (preset_files[preset])) {
896                         std::cerr << "preset file not found " << preset_files[preset] << "\n";
897                         return;
898                 }
899
900                 XMLNode* root = tree.root ();
901                 if (!root) {
902                         std::cerr << "invalid preset file " << preset_files[preset] << "\n";
903                         return;
904                 }
905                 const XMLProperty* prop;
906                 const XMLNode* child;
907
908                 if (root->name() != "OSCPreset") {
909                         std::cerr << "invalid preset file " << preset_files[preset] << "\n";
910                         return;
911                 }
912
913                 if ((child = root->child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
914                         std::cerr << "preset file missing Name " << preset_files[preset] << "\n";
915                         return;
916                 }
917                 if ((child = root->child ("PortMode")) == 0 || (prop = child->property ("value")) == 0) {
918                         cp.set_portmode (sesn_portmode);
919                         portmode_combo.set_active (sesn_portmode);
920                 } else {
921                         cp.set_portmode (atoi (prop->value().c_str()));
922                         portmode_combo.set_active (atoi (prop->value().c_str()));
923                 }
924                 if ((child = root->child ("Remote-Port")) == 0 || (prop = child->property ("value")) == 0) {
925                         cp.set_remote_port (sesn_port);
926                         port_entry.set_text (sesn_port);
927                 } else {
928                         cp.set_remote_port (prop->value());
929                         port_entry.set_text (prop->value());
930                 }
931                 if ((child = root->child ("Bank-Size")) == 0 || (prop = child->property ("value")) == 0) {
932                         cp.set_banksize (sesn_bank);
933                         bank_entry.set_text (string_compose("%1", sesn_bank));
934                 } else {
935                         cp.set_banksize (atoi (prop->value().c_str()));
936                         bank_entry.set_text (prop->value().c_str());
937                 }
938                 if ((child = root->child ("Send-Size")) == 0 || (prop = child->property ("value")) == 0) {
939                         cp.set_send_size (sesn_send);
940                         send_page_entry.set_text (string_compose("%1", sesn_send));
941                 } else {
942                         cp.set_send_size (atoi (prop->value().c_str()));
943                         send_page_entry.set_text (prop->value().c_str());
944                 }
945                 if ((child = root->child ("Plugin-Size")) == 0 || (prop = child->property ("value")) == 0) {
946                         cp.set_plugin_size (sesn_plugin);
947                         plugin_page_entry.set_text (string_compose("%1", sesn_plugin));
948                 } else {
949                         cp.set_plugin_size (atoi (prop->value().c_str()));
950                         plugin_page_entry.set_text (prop->value().c_str());
951                 }
952                 if ((child = root->child ("Strip-Types")) == 0 || (prop = child->property ("value")) == 0) {
953                         cp.set_defaultstrip (sesn_strips);
954                 } else {
955                         cp.set_defaultstrip (atoi (prop->value().c_str()));
956                 }
957                 if ((child = root->child ("Feedback")) == 0 || (prop = child->property ("value")) == 0) {
958                         cp.set_defaultfeedback (sesn_feedback);
959                 } else {
960                         cp.set_defaultfeedback (atoi (prop->value().c_str()));
961                 }
962                 reshow_values (); // show strip types and feed back in GUI
963
964                 if ((child = root->child ("Gain-Mode")) == 0 || (prop = child->property ("value")) == 0) {
965                         cp.set_gainmode (sesn_gainmode);
966                         gainmode_combo.set_active (sesn_gainmode);
967                 } else {
968                         cp.set_gainmode (atoi (prop->value().c_str()));
969                         gainmode_combo.set_active (atoi (prop->value().c_str()));
970                 }
971                 cp.gui_changed();
972
973         }
974 }
975
976 void
977 OSC_GUI::get_session ()
978 {
979         sesn_portmode = cp.get_portmode ();
980         sesn_port = cp.get_remote_port ();
981         sesn_bank = cp.get_banksize ();
982         sesn_send = cp.get_send_size ();
983         sesn_plugin = cp.get_plugin_size ();
984         sesn_strips = cp.get_defaultstrip ();
985         sesn_feedback = cp.get_defaultfeedback ();
986         sesn_gainmode = cp.get_gainmode ();
987 }
988
989 void
990 OSC_GUI::restore_sesn_values ()
991 {
992         cp.set_portmode (sesn_portmode);
993         portmode_combo.set_active (sesn_portmode);
994         cp.set_remote_port (sesn_port);
995         port_entry.set_text (sesn_port);
996         cp.set_banksize (sesn_bank);
997         bank_entry.set_text (string_compose ("%1", sesn_bank));
998         cp.set_send_size (sesn_send);
999         send_page_entry.set_text (string_compose ("%1", sesn_send));
1000         cp.set_plugin_size (sesn_plugin);
1001         plugin_page_entry.set_text (string_compose ("%1", sesn_plugin));
1002         cp.set_defaultstrip (sesn_strips);
1003         cp.set_defaultfeedback (sesn_feedback);
1004         reshow_values ();
1005         cp.set_gainmode (sesn_gainmode);
1006         gainmode_combo.set_active (sesn_gainmode);
1007 }