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