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