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