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