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