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