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