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