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