2 * Copyright (C) 2017-2018 Robin Gareus <robin@gareus.org>
3 * Copyright (C) 2018-2019 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2019 Johannes Mueller <github@johannes-mueller.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <gtkmm/alignment.h>
22 #include <gtkmm/label.h>
23 #include <gtkmm/liststore.h>
24 #include <gtkmm/separator.h>
26 #include "pbd/unwind.h"
27 #include "pbd/strsplit.h"
28 #include "pbd/file_utils.h"
30 #include "gtkmm2ext/actions.h"
31 #include "gtkmm2ext/action_model.h"
32 #include "gtkmm2ext/bindings.h"
33 #include "gtkmm2ext/gtk_ui.h"
34 #include "gtkmm2ext/gui_thread.h"
35 #include "gtkmm2ext/utils.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/filesystem_paths.h"
40 #include "faderport8.h"
46 using namespace ARDOUR;
49 using namespace Gtkmm2ext;
50 using namespace ArdourSurface::FP_NAMESPACE;
53 FaderPort8::get_gui () const
56 const_cast<FaderPort8*>(this)->build_gui ();
58 static_cast<Gtk::VBox*>(gui)->show_all();
63 FaderPort8::tear_down_gui ()
66 Gtk::Widget *w = static_cast<Gtk::VBox*>(gui)->get_parent();
72 delete static_cast<FP8GUI*> (gui);
77 FaderPort8::build_gui ()
79 gui = (void*) new FP8GUI (*this);
82 /* ****************************************************************************/
84 FP8GUI::FP8GUI (FaderPort8& p)
87 , ignore_active_change (false)
88 , two_line_text_cb (_("Two Line Trackname"))
89 , auto_pluginui_cb (_("Auto Show/Hide Plugin GUIs"))
90 , action_model (ActionManager::ActionModel::instance ())
92 set_border_width (12);
94 table.set_row_spacings (4);
95 table.set_col_spacings (6);
96 table.set_border_width (12);
97 table.set_homogeneous (false);
99 std::string data_file_path;
101 string name = "faderport16-small.png";
102 #elif defined FADERPORT2
103 string name = "faderport2018-small.png";
105 string name = "faderport8-small.png";
107 Searchpath spath(ARDOUR::ardour_data_search_path());
108 spath.add_subdirectory_to_paths ("icons");
109 find_file (spath, name, data_file_path);
110 if (!data_file_path.empty()) {
111 image.set (data_file_path);
112 hpacker.pack_start (image, false, false);
118 input_combo.pack_start (midi_port_columns.short_name);
119 output_combo.pack_start (midi_port_columns.short_name);
121 build_prefs_combos ();
122 update_prefs_combos ();
124 input_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FP8GUI::active_port_changed), &input_combo, true));
125 output_combo.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FP8GUI::active_port_changed), &output_combo, false));
127 clock_combo.signal_changed().connect (sigc::mem_fun (*this, &FP8GUI::clock_mode_changed));
128 scribble_combo.signal_changed().connect (sigc::mem_fun (*this, &FP8GUI::scribble_mode_changed));
129 two_line_text_cb.signal_toggled().connect(sigc::mem_fun (*this, &FP8GUI::twolinetext_toggled));
130 auto_pluginui_cb.signal_toggled().connect(sigc::mem_fun (*this, &FP8GUI::auto_pluginui_toggled));
132 l = manage (new Gtk::Label);
133 l->set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Incoming MIDI on:")));
134 l->set_alignment (1.0, 0.5);
135 table.attach (*l, 1, 4, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
136 table.attach (input_combo, 4, 8, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
139 l = manage (new Gtk::Label);
140 l->set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Outgoing MIDI on:")));
141 l->set_alignment (1.0, 0.5);
142 table.attach (*l, 1, 4, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
143 table.attach (output_combo, 4, 8, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
146 Gtk::HSeparator *hsep = manage(new Gtk::HSeparator);
147 table.attach (*hsep, 0, 8, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 6);
150 hpacker.pack_start (table, true, true);
151 pack_start (hpacker, false, false);
157 Gtk::Alignment* align;
159 for (FP8Controls::UserButtonMap::const_iterator i = fp.control().user_buttons ().begin ();
160 i != fp.control().user_buttons ().end (); ++i) {
161 Gtk::ComboBox* user_combo = manage (new Gtk::ComboBox);
162 build_action_combo (*user_combo, i->first);
163 l = manage (new Gtk::Label);
164 l->set_markup (string_compose ("<span weight=\"bold\">%1:</span>", i->second));
165 l->set_alignment (1.0, 0.5);
166 table.attach (*l, 3 * action_col, 3 * action_col + 1, row + action_row, row + action_row + 1, AttachOptions(FILL|EXPAND), AttachOptions (0));
167 align = manage (new Alignment);
168 align->set (0.0, 0.5);
169 align->add (*user_combo);
170 table.attach (*align, 3 * action_col + 1, 3 * action_col + 2, row + action_row, row + action_row + 1, AttachOptions(FILL|EXPAND), AttachOptions (0));
173 if (++action_row == 2)
175 if (++action_row == 4)
183 for (int c = 0; c < 2; ++c) {
184 Gtk::VSeparator *vsep = manage(new Gtk::VSeparator);
185 table.attach (*vsep, 3 * c + 2, 3 * c + 3, row, row + 4, AttachOptions(0), AttachOptions(FILL), 6, 0);
191 hsep = manage(new Gtk::HSeparator);
192 table.attach (*hsep, 0, 8, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 6);
195 l = manage (new Gtk::Label);
196 l->set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Clock:")));
197 l->set_alignment (1.0, 0.5);
198 table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
199 table.attach (clock_combo, 1, 4, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
201 table.attach (two_line_text_cb, 4, 8, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
204 l = manage (new Gtk::Label);
205 l->set_markup (string_compose ("<span weight=\"bold\">%1</span>", _("Display:")));
206 l->set_alignment (1.0, 0.5);
207 table.attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
208 table.attach (scribble_combo, 1, 4, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
210 table.attach (auto_pluginui_cb, 4, 8, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
214 /* update the port connection combos */
215 update_port_combos ();
217 /* catch future changes to connection state */
218 fp.ConnectionChange.connect (connection_change_connection, invalidator (*this), boost::bind (&FP8GUI::connection_handler, this), gui_context());
226 FP8GUI::connection_handler ()
228 PBD::Unwinder<bool> ici (ignore_active_change, true);
229 update_port_combos ();
233 FP8GUI::update_port_combos ()
235 vector<string> midi_inputs;
236 vector<string> midi_outputs;
238 ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsTerminal), midi_inputs);
239 ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsTerminal), midi_outputs);
241 Glib::RefPtr<Gtk::ListStore> input = build_midi_port_list (midi_inputs, true);
242 Glib::RefPtr<Gtk::ListStore> output = build_midi_port_list (midi_outputs, false);
243 bool input_found = false;
244 bool output_found = false;
247 input_combo.set_model (input);
248 output_combo.set_model (output);
250 Gtk::TreeModel::Children children = input->children();
251 Gtk::TreeModel::Children::iterator i;
252 i = children.begin();
253 ++i; /* skip "Disconnected" */
255 for (n = 1; i != children.end(); ++i, ++n) {
256 string port_name = (*i)[midi_port_columns.full_name];
257 if (fp.input_port()->connected_to (port_name)) {
258 input_combo.set_active (n);
265 input_combo.set_active (0); /* disconnected */
268 children = output->children();
269 i = children.begin();
270 ++i; /* skip "Disconnected" */
272 for (n = 1; i != children.end(); ++i, ++n) {
273 string port_name = (*i)[midi_port_columns.full_name];
274 if (fp.output_port()->connected_to (port_name)) {
275 output_combo.set_active (n);
282 output_combo.set_active (0); /* disconnected */
287 Glib::RefPtr<Gtk::ListStore>
288 FP8GUI::build_midi_port_list (vector<string> const & ports, bool for_input)
290 Glib::RefPtr<Gtk::ListStore> store = ListStore::create (midi_port_columns);
293 row = *store->append ();
294 row[midi_port_columns.full_name] = string();
295 row[midi_port_columns.short_name] = _("Disconnected");
297 for (vector<string>::const_iterator p = ports.begin(); p != ports.end(); ++p) {
298 row = *store->append ();
299 row[midi_port_columns.full_name] = *p;
300 std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*p);
302 pn = (*p).substr ((*p).find (':') + 1);
304 row[midi_port_columns.short_name] = pn;
311 FP8GUI::active_port_changed (Gtk::ComboBox* combo, bool for_input)
313 if (ignore_active_change) {
317 TreeModel::iterator active = combo->get_active ();
318 string new_port = (*active)[midi_port_columns.full_name];
320 if (new_port.empty()) {
322 fp.input_port()->disconnect_all ();
324 fp.output_port()->disconnect_all ();
331 if (!fp.input_port()->connected_to (new_port)) {
332 fp.input_port()->disconnect_all ();
333 fp.input_port()->connect (new_port);
336 if (!fp.output_port()->connected_to (new_port)) {
337 fp.output_port()->disconnect_all ();
338 fp.output_port()->connect (new_port);
344 FP8GUI::build_action_combo (Gtk::ComboBox& cb, FP8Controls::ButtonId id)
346 /* set the active "row" to the right value for the current button binding */
347 const string current_action = fp.get_button_action (id, false); /* lookup release action */
348 action_model.build_action_combo(cb, current_action);
349 cb.signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &FP8GUI::action_changed), &cb, id));
353 FP8GUI::action_changed (Gtk::ComboBox* cb, FP8Controls::ButtonId id)
355 TreeModel::const_iterator row = cb->get_active ();
356 string action_path = (*row)[action_model.path()];
357 fp.set_button_action (id, false, action_path);
362 FP8GUI::build_prefs_combos ()
364 vector<string> clock_strings;
365 vector<string> scribble_strings;
367 //clock_strings.push_back (_("Off"));
368 clock_strings.push_back (_("Timecode"));
369 clock_strings.push_back (_("BBT"));
370 clock_strings.push_back (_("Timecode + BBT"));
372 scribble_strings.push_back (_("Off"));
373 scribble_strings.push_back (_("Meter"));
374 scribble_strings.push_back (_("Pan"));
375 scribble_strings.push_back (_("Meter + Pan"));
377 set_popdown_strings (clock_combo, clock_strings);
378 set_popdown_strings (scribble_combo, scribble_strings);
382 FP8GUI::update_prefs_combos ()
384 switch (fp.clock_mode()) {
386 clock_combo.set_active_text (_("Off"));
389 clock_combo.set_active_text (_("Timecode"));
392 clock_combo.set_active_text (_("BBT"));
395 clock_combo.set_active_text (_("Timecode + BBT"));
399 switch (fp.scribble_mode()) {
401 scribble_combo.set_active_text (_("Off"));
404 scribble_combo.set_active_text (_("Meter"));
407 scribble_combo.set_active_text (_("Pan"));
410 scribble_combo.set_active_text (_("Meter + Pan"));
413 two_line_text_cb.set_active (fp.twolinetext ());
414 auto_pluginui_cb.set_active (fp.auto_pluginui ());
418 FP8GUI::clock_mode_changed ()
420 string str = clock_combo.get_active_text();
421 if (str == _("BBT")) {
422 fp.set_clock_mode (2);
423 } else if (str == _("Timecode + BBT")) {
424 fp.set_clock_mode (3);
426 fp.set_clock_mode (1);
431 FP8GUI::scribble_mode_changed ()
433 string str = scribble_combo.get_active_text();
434 if (str == _("Off")) {
435 fp.set_scribble_mode (0);
436 } else if (str == _("Meter")) {
437 fp.set_scribble_mode (1);
438 } else if (str == _("Pan")) {
439 fp.set_scribble_mode (2);
441 fp.set_scribble_mode (3);
446 FP8GUI::twolinetext_toggled ()
448 fp.set_two_line_text (two_line_text_cb.get_active ());
453 FP8GUI::auto_pluginui_toggled ()
455 fp.set_auto_pluginui (auto_pluginui_cb.get_active ());