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