1 /*
2 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
3 * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2006-2016 David Robillard <d@drobilla.net>
5 * Copyright (C) 2006 Hans Fugal <hans@fugal.net>
6 * Copyright (C) 2006 Nick Mainsbridge <mainsbridge@gmail.com>
7 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8 * Copyright (C) 2007-2015 Tim Mayberry <mojofunk@gmail.com>
9 * Copyright (C) 2007 Doug McLain <doug@nostar.net>
10 * Copyright (C) 2013-2020 Robin Gareus <robin@gareus.org>
11 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 */
27
28 /* This file contains any ARDOUR_UI methods that require knowledge of
29 the various dialog boxes, and exists so that no compilation dependency
30 exists between the main ARDOUR_UI modules and their respective classes.
31 This is to cut down on the compile times. It also helps with my sanity.
32 */
33
34 #include <vector>
35
36 #include <gtkmm/treemodelfilter.h>
37
38 #include "pbd/convert.h"
39
40 #include "ardour/audioengine.h"
41 #include "ardour/automation_watch.h"
42 #include "ardour/control_protocol_manager.h"
43 #include "ardour/profile.h"
44 #include "ardour/session.h"
45
46 #include "control_protocol/control_protocol.h"
47
48 #include "gtkmm2ext/keyboard.h"
49 #include "gtkmm2ext/utils.h"
50
51 #include "actions.h"
52 #include "add_route_dialog.h"
53 #include "add_video_dialog.h"
54 #include "ardour_ui.h"
55 #include "big_clock_window.h"
56 #include "big_transport_window.h"
57 #include "bundle_manager.h"
58 #include "dsp_stats_window.h"
59 #include "global_port_matrix.h"
60 #include "gui_object.h"
61 #include "gui_thread.h"
62 #include "keyeditor.h"
63 #include "location_ui.h"
64 #include "lua_script_manager.h"
65 #include "luawindow.h"
66 #include "main_clock.h"
67 #include "meterbridge.h"
68 #include "meter_patterns.h"
69 #include "monitor_section.h"
70 #include "midi_tracer.h"
71 #include "mini_timeline.h"
72 #include "mixer_ui.h"
73 #include "plugin_dspload_window.h"
74 #include "public_editor.h"
75 #include "processor_box.h"
76 #include "rc_option_editor.h"
77 #include "recorder_ui.h"
78 #include "route_params_ui.h"
79 #include "shuttle_control.h"
80 #include "session_option_editor.h"
81 #include "speaker_dialog.h"
82 #include "splash.h"
83 #include "sfdb_ui.h"
84 #include "time_info_box.h"
85 #include "timers.h"
86 #include "transport_masters_dialog.h"
87 #include "virtual_keyboard_window.h"
88
89 #include "pbd/i18n.h"
90
91 using namespace ARDOUR;
92 using namespace PBD;
93 using namespace Glib;
94 using namespace Gtk;
95 using namespace Gtkmm2ext;
96 using namespace ArdourWidgets;
97
98 void
set_session(Session * s)99 ARDOUR_UI::set_session (Session *s)
100 {
101 SessionHandlePtr::set_session (s);
102
103 /* adjust sensitivity of menu bar options to reflect presence/absence
104 * of session
105 */
106
107 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, _session);
108 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session ? _session->writable() : false);
109
110 if (_session && _session->locations()->num_range_markers()) {
111 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
112 } else {
113 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
114 }
115
116 transport_ctrl.set_session (s);
117
118 if (big_transport_window) {
119 big_transport_window->set_session (s);
120 }
121
122 if (virtual_keyboard_window) {
123 virtual_keyboard_window->set_session (s);
124 }
125
126 update_path_label ();
127
128 if (!_session) {
129 WM::Manager::instance().set_session (s);
130 /* Session option editor cannot exist across change-of-session */
131 session_option_editor.drop_window ();
132 /* Ditto for AddVideoDialog */
133 add_video_dialog.drop_window ();
134 /* screensaver + layered button sensitivity */
135 map_transport_state ();
136 return;
137 }
138
139 const XMLNode* node = _session->extra_xml (X_("UI"));
140
141 if (node) {
142 const XMLNodeList& children = node->children();
143 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
144 if ((*i)->name() == GUIObjectState::xml_node_name) {
145 gui_object_state->load (**i);
146 break;
147 }
148 }
149 }
150
151 WM::Manager::instance().set_session (s);
152
153 AutomationWatch::instance().set_session (s);
154
155 shuttle_box.set_session (s);
156 mini_timeline.set_session (s);
157 time_info_box->set_session (s);
158
159 primary_clock->set_session (s);
160 secondary_clock->set_session (s);
161 big_clock->set_session (s);
162 video_timeline->set_session (s);
163 lua_script_window->set_session (s);
164 plugin_dsp_load_window->set_session (s);
165 dsp_statistics_window->set_session (s);
166 transport_masters_window->set_session (s);
167 rc_option_editor->set_session (s);
168
169 roll_controllable->set_session (s);
170 stop_controllable->set_session (s);
171 goto_start_controllable->set_session (s);
172 goto_end_controllable->set_session (s);
173 auto_loop_controllable->set_session (s);
174 play_selection_controllable->set_session (s);
175 rec_controllable->set_session (s);
176
177 /* allow wastebasket flush again */
178
179 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
180 if (act) {
181 act->set_sensitive (true);
182 }
183
184 /* there are never any selections on startup */
185
186 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
187 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
188 ActionManager::set_sensitive (ActionManager::route_selection_sensitive_actions, false);
189 ActionManager::set_sensitive (ActionManager::bus_selection_sensitive_actions, false);
190 ActionManager::set_sensitive (ActionManager::vca_selection_sensitive_actions, false);
191 ActionManager::set_sensitive (ActionManager::stripable_selection_sensitive_actions, false);
192 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
193 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
194 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
195
196 solo_alert_button.set_active (_session->soloing());
197
198 setup_session_options ();
199
200 blink_connection = Timers::blink_connect (sigc::mem_fun(*this, &ARDOUR_UI::blink_handler));
201
202 _session->SaveSessionRequested.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::save_session_at_its_request, this, _1), gui_context());
203 _session->StateSaved.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_title, this), gui_context());
204 _session->StateSaved.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_path_label, this), gui_context());
205 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
206 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
207 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dirty_changed, this), gui_context());
208
209 _session->PunchLoopConstraintChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::set_punch_sensitivity, this), gui_context());
210 _session->auto_punch_location_changed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::set_punch_sensitivity, this), gui_context ());
211
212 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
213 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
214 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
215 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
216 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
217 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
218
219 _session->LatencyUpdated.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_latency_updated, this, _1), gui_context());
220 session_latency_updated (true);
221
222 /* Clocks are on by default after we are connected to a session, so show that here.
223 */
224
225 connect_dependents_to_session (s);
226
227 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
228 restore their modes or are explicitly set, we will cause the "new" mode to be saved
229 back to the session XML ("Extra") state.
230 */
231
232 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
233
234 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
235
236 start_clocking ();
237
238 map_transport_state ();
239
240 second_connection = Timers::second_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second));
241 point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds));
242 point_zero_something_second_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds));
243 set_fps_timeout_connection();
244
245 update_format ();
246
247 if (editor_meter_table.get_parent()) {
248 transport_hbox.remove (editor_meter_table);
249 }
250
251 if (editor_meter) {
252 editor_meter_table.remove(*editor_meter);
253 delete editor_meter;
254 editor_meter = 0;
255 }
256
257 if (editor_meter_table.get_parent()) {
258 transport_hbox.remove (editor_meter_table);
259 }
260 if (editor_meter_peak_display.get_parent ()) {
261 editor_meter_table.remove (editor_meter_peak_display);
262 }
263
264 if (_session &&
265 _session->master_out() &&
266 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
267
268 editor_meter = new LevelMeterHBox(_session);
269 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
270 editor_meter->clear_meters();
271 editor_meter->setup_meters (30, 10, 6);
272 editor_meter->show();
273
274 editor_meter_table.set_spacings(3);
275 editor_meter_table.attach(*editor_meter, 0,1, 0,1, FILL, EXPAND|FILL, 0, 1);
276 editor_meter_table.attach(editor_meter_peak_display, 0,1, 1,2, FILL, SHRINK, 0, 0);
277
278 editor_meter->show();
279 editor_meter_peak_display.show();
280
281 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
282 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
283 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
284
285 editor_meter_peak_display.set_name ("meterbridge peakindicator");
286 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
287 editor_meter_peak_display.set_size_request (-1, std::max (5.f, std::min (12.f, rintf (8.f * UIConfiguration::instance().get_ui_scale()))) );
288 editor_meter_peak_display.set_corner_radius (1.0);
289
290 _clear_editor_meter = true;
291 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
292
293 repack_transport_hbox ();
294 }
295
296 update_title ();
297 }
298
299 int
unload_session(bool hide_stuff)300 ARDOUR_UI::unload_session (bool hide_stuff)
301 {
302 if (_session) {
303 ARDOUR_UI::instance()->video_timeline->sync_session_state();
304
305 /* Unconditionally save session-specific GUI settings:
306 * Playhead position, zoom/scroll with stationary PH,
307 * window and pane positions, etc.
308 *
309 * While many GUI operations immediately cause an instant.xml
310 * save, changing the playhead-pos in particular does not,
311 * nor mark the session dirty.
312 */
313 save_ardour_state ();
314 }
315
316 if (_session && _session->dirty()) {
317 std::vector<std::string> actions;
318 actions.push_back (_("Don't close"));
319 if (_session->unnamed()) {
320 actions.push_back (_("Discard"));
321 } else {
322 actions.push_back (_("Just close"));
323 }
324 actions.push_back (_("Save and close"));
325
326 switch (ask_about_saving_session (actions)) {
327 case -1:
328 // cancel
329 return 1;
330 case 1:
331 // save and continue (and handle unnamed sessions)
332 if (_session->unnamed()) {
333 rename_session (true);
334 }
335 _session->save_state ("");
336 break;
337 case 0:
338 // discard/don't save
339 break;
340 }
341 }
342
343
344 {
345 // tear down session specific CPI (owned by rc_config_editor which can remain)
346 ControlProtocolManager& m = ControlProtocolManager::instance ();
347 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
348 if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
349 (*i)->protocol->tear_down_gui ();
350 }
351 }
352 }
353
354 if (hide_stuff) {
355 close_all_dialogs ();
356 editor->hide ();
357 mixer->hide ();
358 meterbridge->hide ();
359 audio_port_matrix->hide();
360 midi_port_matrix->hide();
361 route_params->hide();
362 }
363
364 second_connection.disconnect ();
365 point_one_second_connection.disconnect ();
366 point_zero_something_second_connection.disconnect();
367 fps_connection.disconnect();
368
369 if (editor_meter) {
370 editor_meter_table.remove(*editor_meter);
371 delete editor_meter;
372 editor_meter = 0;
373 editor_meter_peak_display.hide();
374 }
375
376 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
377
378 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
379
380 if (ARDOUR_UI::instance()->video_timeline) {
381 ARDOUR_UI::instance()->video_timeline->close_session();
382 }
383
384 stop_clocking ();
385
386 /* drop everything attached to the blink signal */
387
388 blink_connection.disconnect ();
389
390 ARDOUR::Session* session_to_delete = _session;
391 _session = 0;
392 delete session_to_delete;
393
394 update_title ();
395
396 return 0;
397 }
398
399 void
toggle_editor_and_mixer()400 ARDOUR_UI::toggle_editor_and_mixer ()
401 {
402 if (editor->tabbed() && mixer->tabbed()) {
403 /* both in the same window */
404 if (_tabs.get_current_page() == _tabs.page_num (editor->contents())) {
405 _tabs.set_current_page (_tabs.page_num (mixer->contents()));
406 } else if (_tabs.get_current_page() == _tabs.page_num (mixer->contents())) {
407 _tabs.set_current_page (_tabs.page_num (editor->contents()));
408 } else {
409 /* go to mixer */
410 _tabs.set_current_page (_tabs.page_num (mixer->contents()));
411 }
412 return;
413 }
414
415
416 if (editor->tabbed() && !mixer->tabbed()) {
417 /* editor is tabbed, mixer is not */
418
419 Gtk::Window* mwin = mixer->current_toplevel ();
420
421 if (!mwin) {
422 /* mixer's own window doesn't exist */
423 mixer->make_visible ();
424 } else if (!mwin->is_mapped ()) {
425 /* mixer's own window exists but isn't mapped */
426 mixer->make_visible ();
427 } else {
428 /* mixer window is mapped, editor is visible as tab */
429 Gtk::Widget* f = mwin->get_focus();
430 if (f && f->has_focus()) {
431 /* mixer has focus, switch to editor */
432 editor->make_visible ();
433 } else {
434 mixer->make_visible ();
435 }
436 }
437 return;
438 }
439
440 if (!editor->tabbed() && mixer->tabbed()) {
441 /* mixer is tabbed, editor is not */
442
443 Gtk::Window* ewin = editor->current_toplevel ();
444
445 if (!ewin) {
446 /* mixer's own window doesn't exist */
447 editor->make_visible ();
448 } else if (!ewin->is_mapped ()) {
449 /* editor's own window exists but isn't mapped */
450 editor->make_visible ();
451 } else {
452 /* editor window is mapped, mixer is visible as tab */
453 Gtk::Widget* f = ewin->get_focus();
454 if (f && f->has_focus()) {
455 /* editor has focus, switch to mixer */
456 mixer->make_visible ();
457 } else {
458 editor->make_visible ();
459 }
460 }
461 return;
462 }
463 }
464
465 void
step_up_through_tabs()466 ARDOUR_UI::step_up_through_tabs ()
467 {
468 std::vector<Tabbable*> candidates;
469
470 /* this list must match the order of visibility buttons */
471
472 if (recorder->tabbed()) {
473 candidates.push_back (recorder);
474 }
475
476 if (editor->tabbed()) {
477 candidates.push_back (editor);
478 }
479
480 if (mixer->tabbed()) {
481 candidates.push_back (mixer);
482 }
483
484 if (rc_option_editor->tabbed()) {
485 candidates.push_back (rc_option_editor);
486 }
487
488 if (candidates.size() < 2) {
489 /* nothing to be done with zero or one visible in tabs */
490 return;
491 }
492
493 std::vector<Tabbable*>::iterator prev = candidates.end();
494 std::vector<Tabbable*>::iterator i;
495 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
496
497 for (i = candidates.begin(); i != candidates.end(); ++i) {
498 if (w == &(*i)->contents()) {
499 if (prev != candidates.end()) {
500 _tabs.set_current_page (_tabs.page_num ((*prev)->contents()));
501 } else {
502 _tabs.set_current_page (_tabs.page_num (candidates.back()->contents()));
503 }
504 return;
505 }
506 prev = i;
507 }
508 }
509
510 void
step_down_through_tabs()511 ARDOUR_UI::step_down_through_tabs ()
512 {
513 std::vector<Tabbable*> candidates;
514
515 /* this list must match the order of visibility buttons */
516
517 if (recorder->tabbed()) {
518 candidates.push_back (recorder);
519 }
520
521 if (editor->tabbed()) {
522 candidates.push_back (editor);
523 }
524
525 if (mixer->tabbed()) {
526 candidates.push_back (mixer);
527 }
528
529 if (rc_option_editor->tabbed()) {
530 candidates.push_back (rc_option_editor);
531 }
532
533 if (candidates.size() < 2) {
534 /* nothing to be done with zero or one visible in tabs */
535 return;
536 }
537
538 std::vector<Tabbable*>::reverse_iterator next = candidates.rend();
539 std::vector<Tabbable*>::reverse_iterator i;
540 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
541
542 for (i = candidates.rbegin(); i != candidates.rend(); ++i) {
543 if (w == &(*i)->contents()) {
544 if (next != candidates.rend()) {
545 _tabs.set_current_page (_tabs.page_num ((*next)->contents()));
546 } else {
547 _tabs.set_current_page (_tabs.page_num (candidates.front()->contents()));
548 }
549 break;
550 }
551 next = i;
552 }
553 }
554
555 void
key_change_tabbable_visibility(Tabbable * t)556 ARDOUR_UI::key_change_tabbable_visibility (Tabbable* t)
557 {
558 if (!t) {
559 return;
560 }
561
562 if (t->tabbed()) {
563 _tabs.set_current_page (_tabs.page_num (t->contents()));
564 } else if (!t->fully_visible()) {
565 t->make_visible ();
566 } else {
567 _main_window.present ();
568 }
569 }
570
571 void
button_change_tabbable_visibility(Tabbable * t)572 ARDOUR_UI::button_change_tabbable_visibility (Tabbable* t)
573 {
574 /* For many/most users, clicking a button in the main window will make it
575 the main/front/key window, which will change any stacking relationship they
576 were trying to modify by clicking on the button in the first
577 place. This button-aware method knows that click on
578 a button designed to show/hide a Tabbable that has its own window
579 will have made that window be obscured (as the main window comes to
580 the front). We therefore *hide* the Tabbable's window if it is even
581 partially visible, believing that this is likely because the
582 Tabbable window used to be front, the user clicked to change that,
583 and before we even get here, the main window has become front.
584 */
585
586 if (!t) {
587 return;
588 }
589
590 if (t->tabbed()) {
591 _tabs.set_current_page (_tabs.page_num (t->contents()));
592 } else if (t->visible()) {
593 t->hide();
594 } else {
595 t->make_visible ();
596 }
597 }
598
599 void
show_tabbable(Tabbable * t)600 ARDOUR_UI::show_tabbable (Tabbable* t)
601 {
602 if (!t) {
603 return;
604 }
605
606 t->make_visible ();
607 }
608
609 void
hide_tabbable(Tabbable * t)610 ARDOUR_UI::hide_tabbable (Tabbable* t)
611 {
612 if (!t) {
613 return;
614 }
615 t->make_invisible ();
616 }
617
618 void
attach_tabbable(Tabbable * t)619 ARDOUR_UI::attach_tabbable (Tabbable* t)
620 {
621 if (!t) {
622 return;
623 }
624
625 t->attach ();
626 }
627
628 void
detach_tabbable(Tabbable * t)629 ARDOUR_UI::detach_tabbable (Tabbable* t)
630 {
631 if (!t) {
632 return;
633 }
634 t->detach ();
635 }
636
637 void
tabs_page_added(Widget *,guint)638 ARDOUR_UI::tabs_page_added (Widget*,guint)
639 {
640 if (_tabs.get_n_pages() > 1) {
641
642 std::vector<TargetEntry> drag_target_entries;
643 drag_target_entries.push_back (TargetEntry ("tabbable"));
644
645 editor_visibility_button.drag_source_set (drag_target_entries);
646 mixer_visibility_button.drag_source_set (drag_target_entries);
647 prefs_visibility_button.drag_source_set (drag_target_entries);
648 recorder_visibility_button.drag_source_set (drag_target_entries);
649
650 editor_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (editor->name(),
651 Pango::FontDescription ("Sans 24"),
652 0, 0,
653 Gdk::Color ("red")));
654 mixer_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (mixer->name(),
655 Pango::FontDescription ("Sans 24"),
656 0, 0,
657 Gdk::Color ("red")));
658 prefs_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (rc_option_editor->name(),
659 Pango::FontDescription ("Sans 24"),
660 0, 0,
661 Gdk::Color ("red")));
662 recorder_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (recorder->name(),
663 Pango::FontDescription ("Sans 24"),
664 0, 0,
665 Gdk::Color ("red")));
666 }
667 }
668
669 void
tabs_page_removed(Widget *,guint)670 ARDOUR_UI::tabs_page_removed (Widget*, guint)
671 {
672 if (_tabs.get_n_pages() < 2) {
673 editor_visibility_button.drag_source_unset ();
674 mixer_visibility_button.drag_source_unset ();
675 prefs_visibility_button.drag_source_unset ();
676 recorder_visibility_button.drag_source_unset ();
677 }
678 }
679
680 void
tabs_switch(GtkNotebookPage *,guint page)681 ARDOUR_UI::tabs_switch (GtkNotebookPage*, guint page)
682 {
683 if (editor && (page == (guint) _tabs.page_num (editor->contents()))) {
684
685 editor_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
686
687 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
688 mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
689 }
690
691 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
692 prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
693 }
694
695 if (recorder && (recorder->tabbed() || recorder->tabbed_by_default())) {
696 recorder_visibility_button.set_active_state (Gtkmm2ext::Off);
697 }
698
699 } else if (mixer && (page == (guint) _tabs.page_num (mixer->contents()))) {
700
701 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
702 editor_visibility_button.set_active_state (Gtkmm2ext::Off);
703 }
704
705 mixer_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
706
707 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
708 prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
709 }
710
711 if (recorder && (recorder->tabbed() || recorder->tabbed_by_default())) {
712 recorder_visibility_button.set_active_state (Gtkmm2ext::Off);
713 }
714
715 } else if (page == (guint) _tabs.page_num (rc_option_editor->contents())) {
716
717 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
718 editor_visibility_button.set_active_state (Gtkmm2ext::Off);
719 }
720
721 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
722 mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
723 }
724
725 prefs_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
726
727 if (recorder && (recorder->tabbed() || recorder->tabbed_by_default())) {
728 recorder_visibility_button.set_active_state (Gtkmm2ext::Off);
729 }
730
731 } else if (page == (guint) _tabs.page_num (recorder->contents())) {
732
733 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
734 editor_visibility_button.set_active_state (Gtkmm2ext::Off);
735 }
736
737 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
738 mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
739 }
740
741 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
742 prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
743 }
744
745 recorder_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
746
747 }
748 }
749
750 void
tabbable_state_change(Tabbable & t)751 ARDOUR_UI::tabbable_state_change (Tabbable& t)
752 {
753 std::vector<std::string> insensitive_action_names;
754 std::vector<std::string> sensitive_action_names;
755 std::vector<std::string> active_action_names;
756 std::vector<std::string> inactive_action_names;
757 Glib::RefPtr<Action> action;
758
759 enum ViewState {
760 Tabbed,
761 Windowed,
762 Hidden
763 };
764 ViewState vs;
765
766 if (t.tabbed()) {
767
768 insensitive_action_names.push_back (string_compose ("attach-%1", t.menu_name()));
769 sensitive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
770 sensitive_action_names.push_back (string_compose ("detach-%1", t.menu_name()));
771 sensitive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
772
773 vs = Tabbed;
774
775 } else if (t.tabbed_by_default ()) {
776
777 insensitive_action_names.push_back (string_compose ("attach-%1", t.menu_name()));
778 insensitive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
779 sensitive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
780 sensitive_action_names.push_back (string_compose ("detach-%1", t.menu_name()));
781
782 vs = Hidden;
783
784 } else if (t.window_visible()) {
785
786 insensitive_action_names.push_back (string_compose ("detach-%1", t.menu_name()));
787 sensitive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
788 sensitive_action_names.push_back (string_compose ("attach-%1", t.menu_name()));
789 sensitive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
790
791 active_action_names.push_back (string_compose ("show-%1", t.menu_name()));
792 inactive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
793
794 vs = Windowed;
795
796 } else {
797
798 /* not currently visible. allow user to retab it or just make
799 * it visible.
800 */
801
802 insensitive_action_names.push_back (string_compose ("detach-%1", t.menu_name()));
803 insensitive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
804 sensitive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
805 sensitive_action_names.push_back (string_compose ("attach-%1", t.menu_name()));
806
807 active_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
808 inactive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
809
810 vs = Hidden;
811 }
812
813 for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
814 action = ActionManager::get_action (X_("Common"), (*s).c_str(), false);
815 if (action) {
816 action->set_sensitive (false);
817 }
818 }
819
820 for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
821 action = ActionManager::get_action (X_("Common"), (*s).c_str(), false);
822 if (action) {
823 action->set_sensitive (true);
824 }
825 }
826
827 ArdourButton* vis_button = 0;
828
829 if (&t == editor) {
830 vis_button = &editor_visibility_button;
831 } else if (&t == mixer) {
832 vis_button = &mixer_visibility_button;
833 } else if (&t == rc_option_editor) {
834 vis_button = &prefs_visibility_button;
835 } else if (&t == recorder) {
836 vis_button = &recorder_visibility_button;
837 }
838
839 if (!vis_button) {
840 assert (0);
841 return;
842 }
843
844 /* First update button states for (other) tabbed windows.
845 * (Gtkmm2ext::Off or Gtkmm2ext::ImplicitActive)
846 */
847 tabs_switch (NULL, _tabs.get_current_page ());
848
849 switch (vs) {
850 case Tabbed:
851 /* nothing to do */
852 break;
853 case Windowed:
854 vis_button->set_active_state (Gtkmm2ext::ExplicitActive);
855 break;
856 case Hidden:
857 vis_button->set_active_state (Gtkmm2ext::Off);
858 break;
859 }
860 }
861
862 void
toggle_meterbridge()863 ARDOUR_UI::toggle_meterbridge ()
864 {
865 assert (editor && mixer && meterbridge);
866
867 bool show = false;
868 bool obscuring = false;
869
870 if (meterbridge->not_visible ()) {
871 show = true;
872 } else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
873 (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
874 obscuring = true;
875 }
876
877 if (obscuring && ((editor->own_window() && editor->own_window()->property_has_toplevel_focus()) ||
878 (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
879 show = true;
880 }
881
882 if (show) {
883 meterbridge->show_window ();
884 meterbridge->present ();
885 meterbridge->raise ();
886 } else {
887 meterbridge->hide_window (NULL);
888 }
889 }
890
891 void
toggle_luawindow()892 ARDOUR_UI::toggle_luawindow ()
893 {
894 assert (editor && luawindow);
895
896 bool show = false;
897
898 if (luawindow->not_visible ()) {
899 show = true;
900 }
901 // TODO check overlap
902
903 if (show) {
904 luawindow->show_window ();
905 luawindow->present ();
906 luawindow->raise ();
907 } else {
908 luawindow->hide_window (NULL);
909 }
910 }
911
912
913 void
new_midi_tracer_window()914 ARDOUR_UI::new_midi_tracer_window ()
915 {
916 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
917 if (!act) {
918 return;
919 }
920
921 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
922 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
923 ++i;
924 }
925
926 if (i == _midi_tracer_windows.end()) {
927 /* all our MIDITracer windows are visible; make a new one */
928 MidiTracer* t = new MidiTracer ();
929 t->show_all ();
930 _midi_tracer_windows.push_back (t);
931 } else {
932 /* re-use the hidden one */
933 (*i)->show_all ();
934 }
935 }
936
937 KeyEditor*
create_key_editor()938 ARDOUR_UI::create_key_editor ()
939 {
940 KeyEditor* kedit = new KeyEditor;
941
942 for (std::list<Bindings*>::iterator b = Bindings::bindings.begin(); b != Bindings::bindings.end(); ++b) {
943 kedit->add_tab ((*b)->name(), **b);
944 }
945
946 return kedit;
947 }
948
949 BundleManager*
create_bundle_manager()950 ARDOUR_UI::create_bundle_manager ()
951 {
952 return new BundleManager (_session);
953 }
954
955 AddVideoDialog*
create_add_video_dialog()956 ARDOUR_UI::create_add_video_dialog ()
957 {
958 return new AddVideoDialog (_session);
959 }
960
961 SessionOptionEditor*
create_session_option_editor()962 ARDOUR_UI::create_session_option_editor ()
963 {
964 return new SessionOptionEditor (_session);
965 }
966
967 BigClockWindow*
create_big_clock_window()968 ARDOUR_UI::create_big_clock_window ()
969 {
970 return new BigClockWindow (*big_clock);
971 }
972
973 BigTransportWindow*
create_big_transport_window()974 ARDOUR_UI::create_big_transport_window ()
975 {
976 BigTransportWindow* btw = new BigTransportWindow ();
977 btw->set_session (_session);
978 return btw;
979 }
980
981 VirtualKeyboardWindow*
create_virtual_keyboard_window()982 ARDOUR_UI::create_virtual_keyboard_window ()
983 {
984 VirtualKeyboardWindow* vkbd = new VirtualKeyboardWindow ();
985 vkbd->set_session (_session);
986 return vkbd;
987 }
988
989 void
handle_locations_change(Location *)990 ARDOUR_UI::handle_locations_change (Location *)
991 {
992 if (_session) {
993 if (_session->locations()->num_range_markers()) {
994 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
995 } else {
996 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
997 }
998 }
999 }
1000
1001 bool
tabbed_window_state_event_handler(GdkEventWindowState * ev,void * object)1002 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
1003 {
1004 if (object == editor) {
1005
1006 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
1007 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
1008 if (big_clock_window) {
1009 big_clock_window->set_transient_for (*editor->own_window());
1010 }
1011 if (big_transport_window) {
1012 big_transport_window->set_transient_for (*editor->own_window());
1013 }
1014 if (virtual_keyboard_window) {
1015 virtual_keyboard_window->set_transient_for (*editor->own_window());
1016 }
1017 }
1018
1019 } else if (object == mixer) {
1020
1021 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
1022 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
1023 if (big_clock_window) {
1024 big_clock_window->set_transient_for (*mixer->own_window());
1025 }
1026 if (big_transport_window) {
1027 big_transport_window->set_transient_for (*mixer->own_window());
1028 }
1029 if (virtual_keyboard_window) {
1030 virtual_keyboard_window->set_transient_for (*mixer->own_window());
1031 }
1032 }
1033 }
1034
1035 return false;
1036 }
1037
1038 bool
editor_meter_peak_button_release(GdkEventButton * ev)1039 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
1040 {
1041 if (ev->button == 1) {
1042 ArdourMeter::ResetAllPeakDisplays ();
1043 }
1044 return false;
1045 }
1046
1047 void
toggle_mixer_space()1048 ARDOUR_UI::toggle_mixer_space()
1049 {
1050 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Common", "ToggleMaximalMixer");
1051 if (tact->get_active()) {
1052 mixer->maximise_mixer_space ();
1053 } else {
1054 mixer->restore_mixer_space ();
1055 }
1056 }
1057
1058 bool
timecode_button_press(GdkEventButton * ev)1059 ARDOUR_UI::timecode_button_press (GdkEventButton* ev)
1060 {
1061 if (ev->button != 1 || ev->type != GDK_2BUTTON_PRESS) {
1062 return false;
1063 }
1064 if (_session) {
1065 session_option_editor->show ();
1066 session_option_editor->set_current_page (_("Timecode"));
1067 }
1068 return true;
1069 }
1070
1071 bool
format_button_press(GdkEventButton * ev)1072 ARDOUR_UI::format_button_press (GdkEventButton* ev)
1073 {
1074 if (ev->button != 1 || ev->type != GDK_2BUTTON_PRESS) {
1075 return false;
1076 }
1077 if (_session) {
1078 session_option_editor->show ();
1079 session_option_editor->set_current_page (_("Media"));
1080 }
1081 return true;
1082 }
1083