1 /*
2 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
3 * Copyright (C) 2005-2015 Tim Mayberry <mojofunk@gmail.com>
4 * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2006-2007 Doug McLain <doug@nostar.net>
6 * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
7 * Copyright (C) 2006 Karsten Wiese <fzuuzf@googlemail.com>
8 * Copyright (C) 2006 Nick Mainsbridge <mainsbridge@gmail.com>
9 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
10 * Copyright (C) 2008 Hans Baier <hansfbaier@googlemail.com>
11 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
12 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 */
28
29 #ifdef WAF_BUILD
30 #include "gtk2ardour-config.h"
31 #endif
32
33 #include <fcntl.h>
34 #include <signal.h>
35 #include <unistd.h>
36 #include <cerrno>
37 #include <iostream>
38 #include <cmath>
39
40 #include <sigc++/bind.h>
41 #include <gtkmm/settings.h>
42
43 #include "canvas/canvas.h"
44
45 #include "pbd/error.h"
46 #include "pbd/basename.h"
47 #include "pbd/fastlog.h"
48
49 #include "gtkmm2ext/utils.h"
50 #include "gtkmm2ext/window_title.h"
51
52 #include "ardour/audioengine.h"
53 #include "ardour/profile.h"
54 #include "ardour/session.h"
55 #include "ardour/types.h"
56
57 #include "ardour_ui.h"
58 #include "keyboard.h"
59 #include "public_editor.h"
60 #include "audio_clock.h"
61 #include "actions.h"
62 #include "main_clock.h"
63 #include "mixer_ui.h"
64 #include "recorder_ui.h"
65 #include "utils.h"
66 #include "time_info_box.h"
67 #include "midi_tracer.h"
68 #include "global_port_matrix.h"
69 #include "location_ui.h"
70 #include "rc_option_editor.h"
71
72 #include "pbd/i18n.h"
73
74 using namespace std;
75 using namespace ARDOUR;
76 using namespace PBD;
77 using namespace Gtkmm2ext;
78 using namespace ArdourWidgets;
79 using namespace Gtk;
80 using namespace Glib;
81 using namespace ARDOUR_UI_UTILS;
82
83 void
setup_tooltips()84 ARDOUR_UI::setup_tooltips ()
85 {
86 ArdourCanvas::Canvas::set_tooltip_timeout (Gtk::Settings::get_default()->property_gtk_tooltip_timeout ());
87
88 set_tip (auto_return_button, _("Return to last playback start when stopped"));
89 set_tip (follow_edits_button, _("Playhead follows Range tool clicks, and Range selections"));
90 parameter_changed("click-gain");
91 set_tip (solo_alert_button, _("When active, something is soloed.\nClick to de-solo everything"));
92 set_tip (auditioning_alert_button, _("When active, auditioning is taking place.\nClick to stop the audition"));
93 set_tip (feedback_alert_button, _("When lit, there is a ports connection issue, leading to feedback loop or ambiguous alignment.\nThis is caused by connecting an output back to some input (feedback), or by multiple connections from a source to the same output via different paths (ambiguous latency, record alignment)."));
94 set_tip (primary_clock, _("<b>Primary Clock</b> right-click to set display mode. Click to edit, click+drag a digit or mouse-over+scroll wheel to modify.\nText edits: right-to-left overwrite <tt>Esc</tt>: cancel; <tt>Enter</tt>: confirm; postfix the edit with '+' or '-' to enter delta times.\n"));
95 set_tip (secondary_clock, _("<b>Secondary Clock</b> right-click to set display mode. Click to edit, click+drag a digit or mouse-over+scroll wheel to modify.\nText edits: right-to-left overwrite <tt>Esc</tt>: cancel; <tt>Enter</tt>: confirm; postfix the edit with '+' or '-' to enter delta times.\n"));
96 set_tip (editor_meter_peak_display, _("Reset All Peak Meters"));
97 set_tip (error_alert_button, _("Show Error Log and acknowledge warnings"));
98
99 set_tip (latency_disable_button, _("Disable all Plugin Delay Compensation. This results in the shortest delay from live input to output, but any paths with delay-causing plugins will sound later than those without."));
100
101 synchronize_sync_source_and_video_pullup ();
102
103 editor->setup_tooltips ();
104 }
105
106 bool
status_bar_button_press(GdkEventButton * ev)107 ARDOUR_UI::status_bar_button_press (GdkEventButton* ev)
108 {
109 bool handled = false;
110
111 switch (ev->button) {
112 case 1:
113 status_bar_label.set_text ("");
114 handled = true;
115 break;
116 default:
117 break;
118 }
119
120 return handled;
121 }
122
123 void
display_message(const char * prefix,gint prefix_len,RefPtr<TextBuffer::Tag> ptag,RefPtr<TextBuffer::Tag> mtag,const char * msg)124 ARDOUR_UI::display_message (const char* prefix, gint prefix_len, RefPtr<TextBuffer::Tag> ptag, RefPtr<TextBuffer::Tag> mtag, const char* msg)
125 {
126 UI::display_message (prefix, prefix_len, ptag, mtag, msg);
127
128 ArdourLogLevel ll = LogLevelNone;
129
130 if (strcmp (prefix, _("[ERROR]: ")) == 0) {
131 ll = LogLevelError;
132 } else if (strcmp (prefix, _("[WARNING]: ")) == 0) {
133 ll = LogLevelWarning;
134 } else if (strcmp (prefix, _("[INFO]: ")) == 0) {
135 ll = LogLevelInfo;
136 }
137
138 _log_not_acknowledged = std::max(_log_not_acknowledged, ll);
139 }
140
141 XMLNode*
tearoff_settings(const char * name) const142 ARDOUR_UI::tearoff_settings (const char* name) const
143 {
144 XMLNode* ui_node = Config->extra_xml(X_("UI"));
145
146 if (ui_node) {
147 XMLNode* tearoff_node = ui_node->child (X_("Tearoffs"));
148 if (tearoff_node) {
149 XMLNode* mnode = tearoff_node->child (name);
150 return mnode;
151 }
152 }
153
154 return 0;
155 }
156
157 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
158
159 static
drag_failed(const Glib::RefPtr<Gdk::DragContext> & context,DragResult result,Tabbable * tab)160 bool drag_failed (const Glib::RefPtr<Gdk::DragContext>& context, DragResult result, Tabbable* tab)
161 {
162 if (result == Gtk::DRAG_RESULT_NO_TARGET) {
163 tab->detach ();
164 return true;
165 }
166 return false;
167 }
168
169 void
repack_transport_hbox()170 ARDOUR_UI::repack_transport_hbox ()
171 {
172 if (time_info_box) {
173 if (time_info_box->get_parent()) {
174 transport_hbox.remove (*time_info_box);
175 }
176 if (UIConfiguration::instance().get_show_toolbar_selclock ()) {
177 transport_hbox.pack_start (*time_info_box, false, false);
178 time_info_box->show();
179 }
180 }
181
182 if (mini_timeline.get_parent()) {
183 transport_hbox.remove (mini_timeline);
184 }
185 if (UIConfiguration::instance().get_show_mini_timeline ()) {
186 transport_hbox.pack_start (mini_timeline, true, true);
187 mini_timeline.show();
188 }
189
190 if (editor_meter) {
191 if (editor_meter_table.get_parent()) {
192 transport_hbox.remove (editor_meter_table);
193 }
194 if (meterbox_spacer.get_parent()) {
195 transport_hbox.remove (meterbox_spacer);
196 transport_hbox.remove (meterbox_spacer2);
197 }
198
199 if (UIConfiguration::instance().get_show_editor_meter()) {
200 transport_hbox.pack_end (meterbox_spacer, false, false, 3);
201 transport_hbox.pack_end (editor_meter_table, false, false);
202 transport_hbox.pack_end (meterbox_spacer2, false, false, 3);
203 editor_meter_table.show();
204 meterbox_spacer.show();
205 meterbox_spacer2.show();
206 }
207 }
208
209 bool show_rec = UIConfiguration::instance().get_show_toolbar_recpunch ();
210 if (show_rec) {
211 punch_label.show ();
212 layered_label.show ();
213 punch_in_button.show ();
214 punch_out_button.show ();
215 layered_button.show ();
216 recpunch_spacer.show ();
217 } else {
218 punch_label.hide ();
219 layered_label.hide ();
220 punch_in_button.hide ();
221 punch_out_button.hide ();
222 layered_button.hide ();
223 recpunch_spacer.hide ();
224 }
225
226 bool show_pdc = UIConfiguration::instance().get_show_toolbar_latency ();
227 if (show_pdc) {
228 latency_disable_button.show ();
229 route_latency_value.show ();
230 io_latency_label.show ();
231 io_latency_value.show ();
232 latency_spacer.show ();
233 } else {
234 latency_disable_button.hide ();
235 route_latency_value.hide ();
236 io_latency_label.hide ();
237 io_latency_value.hide ();
238 latency_spacer.hide ();
239 }
240
241 bool show_mnfo = UIConfiguration::instance().get_show_toolbar_monitor_info ();
242 if (show_mnfo) {
243 monitor_dim_button.show ();
244 monitor_mono_button.show ();
245 monitor_mute_button.show ();
246 monitor_spacer.show ();
247 } else {
248 monitor_dim_button.hide ();
249 monitor_mono_button.hide ();
250 monitor_mute_button.hide ();
251 monitor_spacer.hide ();
252 }
253 }
254
255 void
update_clock_visibility()256 ARDOUR_UI::update_clock_visibility ()
257 {
258 if (ARDOUR::Profile->get_small_screen()) {
259 return;
260 }
261 if (UIConfiguration::instance().get_show_secondary_clock ()) {
262 secondary_clock->show();
263 secondary_clock->left_btn()->show();
264 secondary_clock->right_btn()->show();
265 if (secondary_clock_spacer) {
266 secondary_clock_spacer->show();
267 }
268 } else {
269 secondary_clock->hide();
270 secondary_clock->left_btn()->hide();
271 secondary_clock->right_btn()->hide();
272 if (secondary_clock_spacer) {
273 secondary_clock_spacer->hide();
274 }
275 }
276 }
277
278 void
setup_transport()279 ARDOUR_UI::setup_transport ()
280 {
281 RefPtr<Action> act;
282 /* setup actions */
283
284 act = ActionManager::get_action (X_("Transport"), X_("ToggleExternalSync"));
285 sync_button.set_related_action (act);
286 sync_button.signal_button_press_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::sync_button_clicked), false);
287
288 sync_button.set_sizing_text (S_("LogestSync|M-Clk"));
289
290 /* CANNOT sigc::bind these to clicked or toggled, must use pressed or released */
291 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
292 solo_alert_button.set_related_action (act);
293 auditioning_alert_button.signal_clicked.connect (sigc::mem_fun(*this,&ARDOUR_UI::audition_alert_clicked));
294 error_alert_button.signal_button_release_event().connect (sigc::mem_fun(*this,&ARDOUR_UI::error_alert_press), false);
295 act = ActionManager::get_action (X_("Editor"), X_("toggle-log-window"));
296 error_alert_button.set_related_action(act);
297 error_alert_button.set_fallthrough_to_parent(true);
298
299 layered_button.signal_clicked.connect (sigc::mem_fun(*this,&ARDOUR_UI::layered_button_clicked));
300
301 editor_visibility_button.set_related_action (ActionManager::get_action (X_("Common"), X_("change-editor-visibility")));
302 mixer_visibility_button.set_related_action (ActionManager::get_action (X_("Common"), X_("change-mixer-visibility")));
303 prefs_visibility_button.set_related_action (ActionManager::get_action (X_("Common"), X_("change-preferences-visibility")));
304 recorder_visibility_button.set_related_action (ActionManager::get_action (X_("Common"), X_("change-recorder-visibility")));
305
306 act = ActionManager::get_action ("Transport", "ToggleAutoReturn");
307 auto_return_button.set_related_action (act);
308 act = ActionManager::get_action (X_("Transport"), X_("ToggleFollowEdits"));
309 follow_edits_button.set_related_action (act);
310
311 act = ActionManager::get_action ("Transport", "TogglePunchIn");
312 punch_in_button.set_related_action (act);
313 act = ActionManager::get_action ("Transport", "TogglePunchOut");
314 punch_out_button.set_related_action (act);
315
316 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-dim-all"));
317 monitor_dim_button.set_related_action (act);
318 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-mono"));
319 monitor_mono_button.set_related_action (act);
320 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-cut-all"));
321 monitor_mute_button.set_related_action (act);
322
323 act = ActionManager::get_action ("Main", "ToggleLatencyCompensation");
324 latency_disable_button.set_related_action (act);
325
326 set_size_request_to_display_given_text (route_latency_value, "1000 spl", 0, 0);
327 set_size_request_to_display_given_text (io_latency_value, "1000 spl", 0, 0);
328
329 /* connect signals */
330 ARDOUR_UI::Clock.connect (sigc::bind (sigc::mem_fun (primary_clock, &MainClock::set), false, 0));
331 ARDOUR_UI::Clock.connect (sigc::bind (sigc::mem_fun (secondary_clock, &MainClock::set), false, 0));
332
333 primary_clock->ValueChanged.connect (sigc::mem_fun(*this, &ARDOUR_UI::primary_clock_value_changed));
334 secondary_clock->ValueChanged.connect (sigc::mem_fun(*this, &ARDOUR_UI::secondary_clock_value_changed));
335 big_clock->ValueChanged.connect (sigc::mem_fun(*this, &ARDOUR_UI::big_clock_value_changed));
336
337 editor_visibility_button.signal_drag_failed().connect (sigc::bind (sigc::ptr_fun (drag_failed), editor));
338 mixer_visibility_button.signal_drag_failed().connect (sigc::bind (sigc::ptr_fun (drag_failed), mixer));
339 prefs_visibility_button.signal_drag_failed().connect (sigc::bind (sigc::ptr_fun (drag_failed), rc_option_editor));
340 recorder_visibility_button.signal_drag_failed().connect (sigc::bind (sigc::ptr_fun (drag_failed), recorder));
341
342 /* catch context clicks so that we can show a menu on these buttons */
343
344 editor_visibility_button.signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_visibility_button_press), X_("editor")), false);
345 mixer_visibility_button.signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_visibility_button_press), X_("mixer")), false);
346 prefs_visibility_button.signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_visibility_button_press), X_("preferences")), false);
347 recorder_visibility_button.signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_visibility_button_press), X_("recorder")), false);
348
349 /* setup widget style/name */
350
351 auto_return_button.set_name ("transport option button");
352 follow_edits_button.set_name ("transport option button");
353
354 solo_alert_button.set_name ("rude solo");
355 auditioning_alert_button.set_name ("rude audition");
356 feedback_alert_button.set_name ("feedback alert");
357 error_alert_button.set_name ("error alert");
358
359 solo_alert_button.set_elements (ArdourButton::Element(ArdourButton::Body|ArdourButton::Text));
360 auditioning_alert_button.set_elements (ArdourButton::Element(ArdourButton::Body|ArdourButton::Text));
361 feedback_alert_button.set_elements (ArdourButton::Element(ArdourButton::Body|ArdourButton::Text));
362
363 solo_alert_button.set_layout_font (UIConfiguration::instance().get_SmallerFont());
364 auditioning_alert_button.set_layout_font (UIConfiguration::instance().get_SmallerFont());
365 feedback_alert_button.set_layout_font (UIConfiguration::instance().get_SmallerFont());
366
367 feedback_alert_button.set_sizing_text (_("Facdbeek")); //< longest of "Feedback" and "No Align"
368
369 editor_visibility_button.set_name (X_("page switch button"));
370 mixer_visibility_button.set_name (X_("page switch button"));
371 prefs_visibility_button.set_name (X_("page switch button"));
372 recorder_visibility_button.set_name (X_("page switch button"));
373
374 punch_in_button.set_name ("punch button");
375 punch_out_button.set_name ("punch button");
376 layered_button.set_name (("layered button"));
377
378 latency_disable_button.set_name ("latency button");
379
380 monitor_dim_button.set_name ("monitor section dim");
381 monitor_mono_button.set_name ("monitor section mono");
382 monitor_mute_button.set_name ("mute button");
383
384 monitor_dim_button.set_layout_font (UIConfiguration::instance().get_SmallerFont());
385 monitor_mono_button.set_layout_font (UIConfiguration::instance().get_SmallerFont());
386 monitor_mute_button.set_layout_font (UIConfiguration::instance().get_SmallerFont());
387
388 monitor_dim_button.set_elements (ArdourButton::Element(ArdourButton::Body|ArdourButton::Text));
389 monitor_mono_button.set_elements (ArdourButton::Element(ArdourButton::Body|ArdourButton::Text));
390 monitor_mute_button.set_elements (ArdourButton::Element(ArdourButton::Body|ArdourButton::Text));
391
392 sync_button.set_name ("transport active option button");
393
394 /* and widget text */
395 auto_return_button.set_text(_("Auto Return"));
396 follow_edits_button.set_text(_("Follow Range"));
397 punch_in_button.set_text (_("In"));
398 punch_out_button.set_text (_("Out"));
399 layered_button.set_text (_("Non-Layered"));
400
401 latency_disable_button.set_text (_("Disable PDC"));
402 io_latency_label.set_text (_("I/O Latency:"));
403
404 monitor_dim_button.set_text (_("Dim All"));
405 monitor_mono_button.set_text (_("Mono"));
406 monitor_mute_button.set_text (_("Mute All"));
407
408 punch_label.set_text (_("Punch:"));
409 layered_label.set_text (_("Rec:"));
410
411 /* and tooltips */
412
413 Gtkmm2ext::UI::instance()->set_tip (editor_visibility_button,
414 string_compose (_("Drag this tab to the desktop to show %1 in its own window\n\n"
415 "To re-attach the window, use the Window > %1 > Attach menu action"), editor->name()));
416
417 Gtkmm2ext::UI::instance()->set_tip (mixer_visibility_button,
418 string_compose (_("Drag this tab to the desktop to show %1 in its own window\n\n"
419 "To re-attach the window, use the Window > %1 > Attach menu action"), mixer->name()));
420
421 Gtkmm2ext::UI::instance()->set_tip (prefs_visibility_button,
422 string_compose (_("Drag this tab to the desktop to show %1 in its own window\n\n"
423 "To re-attach the window, use the Window > %1 > Attach menu action"), rc_option_editor->name()));
424
425 Gtkmm2ext::UI::instance()->set_tip (recorder_visibility_button,
426 string_compose (_("Drag this tab to the desktop to show %1 in its own window\n\n"
427 "To re-attach the window, use the Window > %1 > Attach menu action"), recorder->name()));
428
429 Gtkmm2ext::UI::instance()->set_tip (punch_in_button, _("Start recording at auto-punch start"));
430 Gtkmm2ext::UI::instance()->set_tip (punch_out_button, _("Stop recording at auto-punch end"));
431
432 /* monitor section */
433 Gtkmm2ext::UI::instance()->set_tip (monitor_dim_button, _("Monitor section dim output"));
434 Gtkmm2ext::UI::instance()->set_tip (monitor_mono_button, _("Monitor section mono output"));
435 Gtkmm2ext::UI::instance()->set_tip (monitor_mute_button, _("Monitor section mute output"));
436
437 /* transport control size-group */
438
439 Glib::RefPtr<SizeGroup> punch_button_size_group = SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL);
440 punch_button_size_group->add_widget (punch_in_button);
441 punch_button_size_group->add_widget (punch_out_button);
442
443 Glib::RefPtr<SizeGroup> monitor_button_size_group = SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL);
444 monitor_button_size_group->add_widget (monitor_dim_button);
445 monitor_button_size_group->add_widget (monitor_mono_button);
446 monitor_button_size_group->add_widget (monitor_mute_button);
447
448 /* and now the layout... */
449
450 /* top level packing */
451 transport_table.set_spacings (0);
452 transport_table.set_row_spacings (4);
453 transport_table.set_border_width (0);
454
455 transport_frame.set_name ("TransportFrame");
456 transport_frame.set_shadow_type (Gtk::SHADOW_NONE);
457
458 /* An event box to hold the table. We use this because we want specific
459 control over the background color, and without this event box,
460 nothing inside the transport_frame actually draws a background. We
461 would therefore end up seeing the background of the parent widget,
462 which is probably some default color. Adding the EventBox adds a
463 widget that will draw the background, using a style based on
464 the parent, "TransportFrame".
465 */
466 Gtk::EventBox* ebox = manage (new Gtk::EventBox);
467 transport_frame.add (*ebox);
468 ebox->add (transport_table);
469
470 /* alert box sub-group */
471 VBox* alert_box = manage (new VBox);
472 alert_box->set_homogeneous (true);
473 alert_box->set_spacing (1);
474 alert_box->set_border_width (0);
475 alert_box->pack_start (solo_alert_button, true, true);
476 alert_box->pack_start (auditioning_alert_button, true, true);
477 alert_box->pack_start (feedback_alert_button, true, true);
478
479 /* monitor section sub-group */
480 VBox* monitor_box = manage (new VBox);
481 monitor_box->set_homogeneous (true);
482 monitor_box->set_spacing (1);
483 monitor_box->set_border_width (0);
484 monitor_box->pack_start (monitor_mono_button, true, true);
485 monitor_box->pack_start (monitor_dim_button, true, true);
486 monitor_box->pack_start (monitor_mute_button, true, true);
487
488 /* clock button size groups */
489 Glib::RefPtr<SizeGroup> button_height_size_group = SizeGroup::create (Gtk::SIZE_GROUP_VERTICAL);
490 button_height_size_group->add_widget (follow_edits_button);
491 button_height_size_group->add_widget (*primary_clock->left_btn());
492 button_height_size_group->add_widget (*primary_clock->right_btn());
493 button_height_size_group->add_widget (*secondary_clock->left_btn());
494 button_height_size_group->add_widget (*secondary_clock->right_btn());
495
496 button_height_size_group->add_widget (transport_ctrl.size_button ());
497 button_height_size_group->add_widget (sync_button);
498 button_height_size_group->add_widget (auto_return_button);
499
500 //tab selections
501 button_height_size_group->add_widget (recorder_visibility_button);
502 button_height_size_group->add_widget (editor_visibility_button);
503 button_height_size_group->add_widget (mixer_visibility_button);
504 button_height_size_group->add_widget (prefs_visibility_button);
505
506 //punch section
507 button_height_size_group->add_widget (punch_in_button);
508 button_height_size_group->add_widget (punch_out_button);
509 button_height_size_group->add_widget (layered_button);
510
511 // PDC
512 button_height_size_group->add_widget (latency_disable_button);
513
514 for (int i = 0; i < MAX_LUA_ACTION_BUTTONS; ++i) {
515 button_height_size_group->add_widget (action_script_call_btn[i]);
516 }
517
518 Glib::RefPtr<SizeGroup> clock1_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
519 clock1_size_group->add_widget (*primary_clock->left_btn());
520 clock1_size_group->add_widget (*primary_clock->right_btn());
521
522 Glib::RefPtr<SizeGroup> clock2_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
523 clock2_size_group->add_widget (*secondary_clock->left_btn());
524 clock2_size_group->add_widget (*secondary_clock->right_btn());
525
526 /* sub-layout for Sync | Shuttle (grow) */
527 HBox* ssbox = manage (new HBox);
528 ssbox->set_spacing (PX_SCALE(2));
529 ssbox->pack_start (sync_button, false, false, 0);
530 ssbox->pack_start (shuttle_box, true, true, 0);
531 ssbox->pack_start (*shuttle_box.info_button(), false, false, 0);
532
533
534 /* and the main table layout */
535 int vpadding = 1;
536 int hpadding = 2;
537 int col = 0;
538 #define TCOL col, col + 1
539
540 transport_table.attach (transport_ctrl, TCOL, 0, 1 , SHRINK, SHRINK, 0, 0);
541 transport_table.attach (*ssbox, TCOL, 1, 2 , FILL, SHRINK, 0, 0);
542 ++col;
543
544 transport_table.attach (*(manage (new ArdourVSpacer ())), TCOL, 0, 2 , SHRINK, EXPAND|FILL, 3, 0);
545 ++col;
546
547 transport_table.attach (punch_label, TCOL, 0, 1 , FILL, SHRINK, 3, 0);
548 transport_table.attach (layered_label, TCOL, 1, 2 , FILL, SHRINK, 3, 0);
549 ++col;
550
551 transport_table.attach (punch_in_button, col, col + 1, 0, 1 , FILL, SHRINK, hpadding, vpadding);
552 transport_table.attach (punch_space, col + 1, col + 2, 0, 1 , FILL, SHRINK, 0, vpadding);
553 transport_table.attach (punch_out_button, col + 2, col + 3, 0, 1 , FILL, SHRINK, hpadding, vpadding);
554 transport_table.attach (layered_button, col, col + 3, 1, 2 , FILL, SHRINK, hpadding, vpadding);
555 col += 3;
556
557 transport_table.attach (recpunch_spacer, TCOL, 0, 2 , SHRINK, EXPAND|FILL, 3, 0);
558 ++col;
559
560 transport_table.attach (latency_disable_button, TCOL, 0, 1 , FILL, SHRINK, hpadding, vpadding);
561 transport_table.attach (io_latency_label, TCOL, 1, 2 , SHRINK, EXPAND|FILL, hpadding, 0);
562 ++col;
563 transport_table.attach (route_latency_value, TCOL, 0, 1 , SHRINK, EXPAND|FILL, hpadding, 0);
564 transport_table.attach (io_latency_value, TCOL, 1, 2 , SHRINK, EXPAND|FILL, hpadding, 0);
565 ++col;
566
567 route_latency_value.set_alignment (Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER);
568 io_latency_value.set_alignment (Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER);
569
570 transport_table.attach (latency_spacer, TCOL, 0, 2 , SHRINK, EXPAND|FILL, 3, 0);
571 ++col;
572
573 transport_table.attach (follow_edits_button, TCOL, 0, 1 , FILL, SHRINK, hpadding, vpadding);
574 transport_table.attach (auto_return_button, TCOL, 1, 2 , FILL, SHRINK, hpadding, vpadding);
575 ++col;
576
577 transport_table.attach (*(manage (new ArdourVSpacer ())), TCOL, 0, 2 , SHRINK, EXPAND|FILL, 3, 0);
578 ++col;
579
580 transport_table.attach (*primary_clock, col, col + 2, 0, 1 , FILL, SHRINK, hpadding, 0);
581 transport_table.attach (*primary_clock->left_btn(), col, col + 1, 1, 2 , FILL, SHRINK, hpadding, 0);
582 transport_table.attach (*primary_clock->right_btn(), col + 1, col + 2, 1, 2 , FILL, SHRINK, hpadding, 0);
583 col += 2;
584
585 transport_table.attach (*(manage (new ArdourVSpacer ())), TCOL, 0, 2 , SHRINK, EXPAND|FILL, 3, 0);
586 ++col;
587
588 if (!ARDOUR::Profile->get_small_screen()) {
589 transport_table.attach (*secondary_clock, col, col + 2, 0, 1 , FILL, SHRINK, hpadding, 0);
590 transport_table.attach (*secondary_clock->left_btn(), col, col + 1, 1, 2 , FILL, SHRINK, hpadding, 0);
591 transport_table.attach (*secondary_clock->right_btn(), col + 1, col + 2, 1, 2 , FILL, SHRINK, hpadding, 0);
592 secondary_clock->set_no_show_all (true);
593 secondary_clock->left_btn()->set_no_show_all (true);
594 secondary_clock->right_btn()->set_no_show_all (true);
595 col += 2;
596
597 secondary_clock_spacer = manage (new ArdourVSpacer ());
598 transport_table.attach (*secondary_clock_spacer, TCOL, 0, 2 , SHRINK, EXPAND|FILL, 3, 0);
599 ++col;
600 }
601
602 transport_table.attach (*alert_box, TCOL, 0, 2, SHRINK, EXPAND|FILL, hpadding, 0);
603 ++col;
604
605 transport_table.attach (monitor_spacer, TCOL, 0, 2 , SHRINK, EXPAND|FILL, 3, 0);
606 ++col;
607
608 transport_table.attach (*monitor_box, TCOL, 0, 2 , SHRINK, EXPAND|FILL, 3, 0);
609 ++col;
610
611 /* editor-meter, mini-timeline and selection clock are options in the transport_hbox */
612 transport_hbox.set_spacing (3);
613 transport_table.attach (transport_hbox, TCOL, 0, 2, EXPAND|FILL, EXPAND|FILL, hpadding, 0);
614 ++col;
615
616 /* lua script action buttons */
617 for (int i = 0; i < MAX_LUA_ACTION_BUTTONS; ++i) {
618 const int r = i % 2;
619 const int c = col + i / 2;
620 transport_table.attach (action_script_call_btn[i], c, c + 1, r, r + 1, FILL, SHRINK, 1, vpadding);
621 }
622 col += MAX_LUA_ACTION_BUTTONS / 2;
623
624 transport_table.attach (scripts_spacer, TCOL, 0, 2 , SHRINK, EXPAND|FILL, 3, 0);
625 ++col;
626
627 transport_table.attach (recorder_visibility_button, TCOL, 0, 1 , FILL, SHRINK, hpadding, vpadding);
628 transport_table.attach (mixer_visibility_button, col, col + 2, 1, 2 , FILL, SHRINK, hpadding, vpadding);
629 ++col;
630 transport_table.attach (editor_visibility_button, TCOL, 0, 1 , FILL, SHRINK, hpadding, vpadding);
631 ++col;
632
633 /* initialize */
634 latency_switch_changed ();
635 session_latency_updated (true);
636
637 repack_transport_hbox ();
638 update_clock_visibility ();
639 /* desensitize */
640
641 feedback_alert_button.set_sensitive (false);
642 feedback_alert_button.set_visual_state (Gtkmm2ext::NoVisualState);
643 auditioning_alert_button.set_sensitive (false);
644 auditioning_alert_button.set_visual_state (Gtkmm2ext::NoVisualState);
645
646 set_transport_sensitivity (false);
647 }
648 #undef PX_SCALE
649 #undef TCOL
650
651
652 void
latency_switch_changed()653 ARDOUR_UI::latency_switch_changed ()
654 {
655 bool pdc_off = ARDOUR::Latent::zero_latency ();
656 if (latency_disable_button.get_active() != pdc_off) {
657 latency_disable_button.set_active (pdc_off);
658 }
659 }
660
661 void
session_latency_updated(bool for_playback)662 ARDOUR_UI::session_latency_updated (bool for_playback)
663 {
664 if (!for_playback) {
665 /* latency updates happen in pairs, in the following order:
666 * - for capture
667 * - for playback
668 */
669 return;
670 }
671
672 if (!_session) {
673 route_latency_value.set_text ("--");
674 io_latency_value.set_text ("--");
675 } else {
676 samplecnt_t wrl = _session->worst_route_latency ();
677 samplecnt_t wpl = _session->worst_latency_preroll ();
678 float rate = _session->nominal_sample_rate ();
679
680 route_latency_value.set_text (samples_as_time_string (wrl, rate));
681
682 if (_session->engine().check_for_ambiguous_latency (true)) {
683 _ambiguous_latency = true;
684 io_latency_value.set_markup ("<span background=\"red\" foreground=\"white\">ambiguous</span>");
685 } else {
686 _ambiguous_latency = false;
687 io_latency_value.set_text (samples_as_time_string (wpl, rate));
688 }
689 }
690 }
691
692 void
soloing_changed(bool onoff)693 ARDOUR_UI::soloing_changed (bool onoff)
694 {
695 if (solo_alert_button.get_active() != onoff) {
696 solo_alert_button.set_active (onoff);
697 }
698 }
699
700 void
_auditioning_changed(bool onoff)701 ARDOUR_UI::_auditioning_changed (bool onoff)
702 {
703 auditioning_alert_button.set_active (onoff);
704 auditioning_alert_button.set_sensitive (onoff);
705 if (!onoff) {
706 auditioning_alert_button.set_visual_state (Gtkmm2ext::NoVisualState);
707 }
708 set_transport_sensitivity (!onoff);
709 }
710
711 void
auditioning_changed(bool onoff)712 ARDOUR_UI::auditioning_changed (bool onoff)
713 {
714 UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::_auditioning_changed, this, onoff));
715 }
716
717 void
audition_alert_clicked()718 ARDOUR_UI::audition_alert_clicked ()
719 {
720 if (_session) {
721 _session->cancel_audition();
722 }
723 }
724
725 bool
error_alert_press(GdkEventButton * ev)726 ARDOUR_UI::error_alert_press (GdkEventButton* ev)
727 {
728 bool do_toggle = true;
729 if (ev->button == 1) {
730 if (_log_not_acknowledged == LogLevelError) {
731 // just acknowledge the error, don't hide the log if it's already visible
732 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-log-window"));
733 if (tact->get_active()) {
734 do_toggle = false;
735 }
736 }
737 _log_not_acknowledged = LogLevelNone;
738 error_blink (false); // immediate acknowledge
739 }
740 // maybe fall through to to button toggle
741 return !do_toggle;
742 }
743
744 void
layered_button_clicked()745 ARDOUR_UI::layered_button_clicked ()
746 {
747 if (_session) {
748 _session->config.set_layered_record_mode (!_session->config.get_layered_record_mode ());
749 }
750 }
751
752 void
solo_blink(bool onoff)753 ARDOUR_UI::solo_blink (bool onoff)
754 {
755 if (_session == 0) {
756 return;
757 }
758
759 if (_session->soloing() || _session->listening()) {
760 if (onoff) {
761 solo_alert_button.set_active (true);
762 } else {
763 solo_alert_button.set_active (false);
764 }
765 } else {
766 solo_alert_button.set_active (false);
767 }
768 }
769
770 void
sync_blink(bool onoff)771 ARDOUR_UI::sync_blink (bool onoff)
772 {
773 if (_session == 0 || !_session->config.get_external_sync()) {
774 /* internal sync */
775 sync_button.set_active (false);
776 return;
777 }
778
779 if (!_session->transport_locked()) {
780 /* not locked, so blink on and off according to the onoff argument */
781
782 if (onoff) {
783 sync_button.set_active (true);
784 } else {
785 sync_button.set_active (false);
786 }
787 } else {
788 /* locked */
789 sync_button.set_active (true);
790 }
791 }
792
793 void
audition_blink(bool onoff)794 ARDOUR_UI::audition_blink (bool onoff)
795 {
796 if (_session == 0) {
797 return;
798 }
799
800 if (_session->is_auditioning()) {
801 if (onoff) {
802 auditioning_alert_button.set_active (true);
803 } else {
804 auditioning_alert_button.set_active (false);
805 }
806 } else {
807 auditioning_alert_button.set_active (false);
808 }
809 }
810
811 void
feedback_blink(bool onoff)812 ARDOUR_UI::feedback_blink (bool onoff)
813 {
814 if (_feedback_exists) {
815 feedback_alert_button.set_active (true);
816 feedback_alert_button.set_text (_("Feedback"));
817 if (onoff) {
818 feedback_alert_button.reset_fixed_colors ();
819 } else {
820 feedback_alert_button.set_active_color (UIConfigurationBase::instance().color ("feedback alert: alt active", NULL));
821 }
822 } else if (_ambiguous_latency && !UIConfiguration::instance().get_show_toolbar_latency ()) {
823 feedback_alert_button.set_text (_("No Align"));
824 feedback_alert_button.set_active (true);
825 if (onoff) {
826 feedback_alert_button.reset_fixed_colors ();
827 } else {
828 feedback_alert_button.set_active_color (UIConfigurationBase::instance().color ("feedback alert: alt active", NULL));
829 }
830 } else {
831 feedback_alert_button.set_text ("Feedback");
832 feedback_alert_button.reset_fixed_colors ();
833 feedback_alert_button.set_active (false);
834 }
835 }
836
837 void
error_blink(bool onoff)838 ARDOUR_UI::error_blink (bool onoff)
839 {
840 switch (_log_not_acknowledged) {
841 case LogLevelError:
842 // blink
843 if (onoff) {
844 error_alert_button.set_custom_led_color(0xff0000ff); // bright red
845 } else {
846 error_alert_button.set_custom_led_color(0x880000ff); // dark red
847 }
848 break;
849 case LogLevelWarning:
850 error_alert_button.set_custom_led_color(0xccaa00ff); // yellow
851 break;
852 case LogLevelInfo:
853 error_alert_button.set_custom_led_color(0x88cc00ff); // lime green
854 break;
855 default:
856 error_alert_button.set_custom_led_color(0x333333ff); // gray
857 break;
858 }
859 }
860 void
set_transport_sensitivity(bool yn)861 ARDOUR_UI::set_transport_sensitivity (bool yn)
862 {
863 ActionManager::set_sensitive (ActionManager::transport_sensitive_actions, yn);
864 shuttle_box.set_sensitive (yn);
865 }
866
867 void
set_punch_sensitivity()868 ARDOUR_UI::set_punch_sensitivity ()
869 {
870 bool can_punch = _session && _session->punch_is_possible() && _session->locations()->auto_punch_location ();
871 ActionManager::get_action ("Transport", "TogglePunchIn")->set_sensitive (can_punch);
872 ActionManager::get_action ("Transport", "TogglePunchOut")->set_sensitive (can_punch);
873 }
874
875 void
editor_realized()876 ARDOUR_UI::editor_realized ()
877 {
878 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
879 Config->map_parameters (pc);
880
881 UIConfiguration::instance().reset_dpi ();
882 }
883
884 void
maximise_editing_space()885 ARDOUR_UI::maximise_editing_space ()
886 {
887 if (editor) {
888 editor->maximise_editing_space ();
889 }
890 }
891
892 void
restore_editing_space()893 ARDOUR_UI::restore_editing_space ()
894 {
895 if (editor) {
896 editor->restore_editing_space ();
897 }
898 }
899
900 void
show_ui_prefs()901 ARDOUR_UI::show_ui_prefs ()
902 {
903 if (rc_option_editor) {
904 show_tabbable (rc_option_editor);
905 rc_option_editor->set_current_page (_("Appearance"));
906 }
907 }
908 void
show_mixer_prefs()909 ARDOUR_UI::show_mixer_prefs ()
910 {
911 if (rc_option_editor) {
912 show_tabbable (rc_option_editor);
913 rc_option_editor->set_current_page (_("Signal Flow"));
914 }
915 }
916
917 bool
click_button_clicked(GdkEventButton * ev)918 ARDOUR_UI::click_button_clicked (GdkEventButton* ev)
919 {
920 if (ev->button != 3) {
921 /* this handler is just for button-3 clicks */
922 return false;
923 }
924
925 show_tabbable (rc_option_editor);
926 rc_option_editor->set_current_page (_("Metronome"));
927 return true;
928 }
929
930 bool
sync_button_clicked(GdkEventButton * ev)931 ARDOUR_UI::sync_button_clicked (GdkEventButton* ev)
932 {
933 if (ev->button != 3) {
934 /* this handler is just for button-3 clicks */
935 return false;
936 }
937
938 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Window", "toggle-transport-masters");
939 tact->set_active();
940 return true;
941 }
942
943 void
toggle_follow_edits()944 ARDOUR_UI::toggle_follow_edits ()
945 {
946 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Transport"), X_("ToggleFollowEdits"));
947 UIConfiguration::instance().set_follow_edits (tact->get_active ());
948 }
949
950 void
update_title()951 ARDOUR_UI::update_title ()
952 {
953 stringstream snap_label;
954 snap_label << X_("<span weight=\"ultralight\">")
955 << _("Name")
956 << X_("</span>: ");
957
958 if (_session) {
959 bool dirty = _session->dirty();
960
961 string session_name;
962
963 if (_session->snap_name() != _session->name()) {
964 session_name = _session->snap_name();
965 } else {
966 session_name = _session->name();
967 }
968
969 if (dirty) {
970 session_name = "*" + session_name;
971 }
972
973 WindowTitle title (session_name);
974 title += Glib::get_application_name();
975 _main_window.set_title (title.get_string());
976
977 snap_label << Gtkmm2ext::markup_escape_text (session_name);
978 } else {
979 WindowTitle title (Glib::get_application_name());
980 _main_window.set_title (title.get_string());
981 snap_label << "-";
982 }
983 snapshot_name_label.set_markup (snap_label.str());
984 }
985
986