fix incorrect accumulation of export video options each time the dialog is used
[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         delete _session;
341         _session = 0;
342
343         session_loaded = false;
344
345         update_title ();
346
347         return 0;
348 }
349
350 void
351 ARDOUR_UI::toggle_editor_and_mixer ()
352 {
353         if (editor->tabbed() && mixer->tabbed()) {
354                 /* both in the same window */
355                 if (_tabs.get_current_page() == _tabs.page_num (editor->contents())) {
356                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
357                 } else if (_tabs.get_current_page() == _tabs.page_num (mixer->contents())) {
358                         _tabs.set_current_page (_tabs.page_num (editor->contents()));
359                 } else {
360                         /* go to mixer */
361                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
362                 }
363                 return;
364         }
365
366
367         if (editor->tabbed() && !mixer->tabbed()) {
368                 /* editor is tabbed, mixer is not */
369
370                 Gtk::Window* mwin = mixer->current_toplevel ();
371
372                 if (!mwin) {
373                         /* mixer's own window doesn't exist */
374                         mixer->make_visible ();
375                 } else if (!mwin->is_mapped ()) {
376                         /* mixer's own window exists but isn't mapped */
377                         mixer->make_visible ();
378                 } else {
379                         /* mixer window is mapped, editor is visible as tab */
380                         Gtk::Widget* f = mwin->get_focus();
381                         if (f && f->has_focus()) {
382                                 /* mixer has focus, switch to editor */
383                                 editor->make_visible ();
384                         } else {
385                                 mixer->make_visible ();
386                         }
387                 }
388                 return;
389         }
390
391         if (!editor->tabbed() && mixer->tabbed()) {
392                 /* mixer is tabbed, editor is not */
393
394                 Gtk::Window* ewin = editor->current_toplevel ();
395
396                 if (!ewin) {
397                         /* mixer's own window doesn't exist */
398                         editor->make_visible ();
399                 } else if (!ewin->is_mapped ()) {
400                         /* editor's own window exists but isn't mapped */
401                         editor->make_visible ();
402                 } else {
403                         /* editor window is mapped, mixer is visible as tab */
404                         Gtk::Widget* f = ewin->get_focus();
405                         if (f && f->has_focus()) {
406                                 /* editor has focus, switch to mixer */
407                                 mixer->make_visible ();
408                         } else {
409                                 editor->make_visible ();
410                         }
411                 }
412                 return;
413         }
414 }
415
416 void
417 ARDOUR_UI::step_up_through_tabs ()
418 {
419         std::vector<Tabbable*> candidates;
420
421         /* this list must match the order of visibility buttons */
422
423         if (!editor->window_visible()) {
424                 candidates.push_back (editor);
425         }
426
427         if (!mixer->window_visible()) {
428                 candidates.push_back (mixer);
429         }
430
431         if (!rc_option_editor->window_visible()) {
432                 candidates.push_back (rc_option_editor);
433         }
434
435         if (candidates.size() < 2) {
436                 /* nothing to be done with zero or one visible in tabs */
437                 return;
438         }
439
440         std::vector<Tabbable*>::iterator prev = candidates.end();
441         std::vector<Tabbable*>::iterator i;
442         Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
443
444         for (i = candidates.begin(); i != candidates.end(); ++i) {
445                 if (w == &(*i)->contents()) {
446                         if (prev != candidates.end()) {
447                                 _tabs.set_current_page (_tabs.page_num ((*prev)->contents()));
448                         } else {
449                                 _tabs.set_current_page (_tabs.page_num (candidates.back()->contents()));
450                         }
451                         return;
452                 }
453                 prev = i;
454         }
455 }
456
457 void
458 ARDOUR_UI::step_down_through_tabs ()
459 {
460         std::vector<Tabbable*> candidates;
461
462         /* this list must match the order of visibility buttons */
463
464         if (!editor->window_visible()) {
465                 candidates.push_back (editor);
466         }
467
468         if (!mixer->window_visible()) {
469                 candidates.push_back (mixer);
470         }
471
472         if (!rc_option_editor->window_visible()) {
473                 candidates.push_back (rc_option_editor);
474         }
475
476         if (candidates.size() < 2) {
477                 /* nothing to be done with zero or one visible in tabs */
478                 return;
479         }
480
481         std::vector<Tabbable*>::reverse_iterator next = candidates.rend();
482         std::vector<Tabbable*>::reverse_iterator i;
483         Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
484
485         for (i = candidates.rbegin(); i != candidates.rend(); ++i) {
486                 if (w == &(*i)->contents()) {
487                         if (next != candidates.rend()) {
488                                 _tabs.set_current_page (_tabs.page_num ((*next)->contents()));
489                         } else {
490                                 _tabs.set_current_page (_tabs.page_num (candidates.front()->contents()));
491                         }
492                         break;
493                 }
494                 next = i;
495         }
496 }
497
498 void
499 ARDOUR_UI::key_change_tabbable_visibility (Tabbable* t)
500 {
501         if (!t) {
502                 return;
503         }
504
505         if (t->tabbed()) {
506                 _tabs.set_current_page (_tabs.page_num (t->contents()));
507         } else if (!t->fully_visible()) {
508                 t->make_visible ();
509         } else {
510                 _main_window.present ();
511         }
512 }
513
514 void
515 ARDOUR_UI::button_change_tabbable_visibility (Tabbable* t)
516 {
517         /* For many/most users, clicking a button in the main window will make it
518            the main/front/key window, which will change any stacking relationship they
519            were trying to modify by clicking on the button in the first
520            place. This button-aware method knows that click on
521            a button designed to show/hide a Tabbable that has its own window
522            will have made that window be obscured (as the main window comes to
523            the front). We therefore *hide* the Tabbable's window if it is even
524            partially visible, believing that this is likely because the
525            Tabbable window used to be front, the user clicked to change that,
526            and before we even get here, the main window has become front.
527         */
528
529         if (!t) {
530                 return;
531         }
532
533         if (t->tabbed()) {
534                 _tabs.set_current_page (_tabs.page_num (t->contents()));
535         } else if (t->visible()) {
536                 t->hide();
537         } else {
538                 t->make_visible ();
539         }
540 }
541
542 void
543 ARDOUR_UI::show_tabbable (Tabbable* t)
544 {
545         if (!t) {
546                 return;
547         }
548
549         t->make_visible ();
550 }
551
552 void
553 ARDOUR_UI::hide_tabbable (Tabbable* t)
554 {
555         if (!t) {
556                 return;
557         }
558         t->make_invisible ();
559 }
560
561 void
562 ARDOUR_UI::attach_tabbable (Tabbable* t)
563 {
564         if (!t) {
565                 return;
566         }
567
568         t->attach ();
569 }
570
571 void
572 ARDOUR_UI::detach_tabbable (Tabbable* t)
573 {
574         if (!t) {
575                 return;
576         }
577         t->detach ();
578 }
579
580 void
581 ARDOUR_UI::tabs_page_added (Widget*,guint)
582 {
583         if (_tabs.get_n_pages() > 1) {
584
585                 std::vector<TargetEntry> drag_target_entries;
586                 drag_target_entries.push_back (TargetEntry ("tabbable"));
587
588                 editor_visibility_button.drag_source_set (drag_target_entries);
589                 mixer_visibility_button.drag_source_set (drag_target_entries);
590                 prefs_visibility_button.drag_source_set (drag_target_entries);
591
592                 editor_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (editor->name(),
593                                                                                               Pango::FontDescription ("Sans 24"),
594                                                                                               0, 0,
595                                                                                               Gdk::Color ("red")));
596                 mixer_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (mixer->name(),
597                                                                                              Pango::FontDescription ("Sans 24"),
598                                                                                              0, 0,
599                                                                                              Gdk::Color ("red")));
600                 prefs_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (rc_option_editor->name(),
601                                                                                              Pango::FontDescription ("Sans 24"),
602                                                                                              0, 0,
603                                                                                              Gdk::Color ("red")));
604         }
605 }
606
607 void
608 ARDOUR_UI::tabs_page_removed (Widget*, guint)
609 {
610         if (_tabs.get_n_pages() < 2) {
611                 editor_visibility_button.drag_source_unset ();
612                 mixer_visibility_button.drag_source_unset ();
613                 prefs_visibility_button.drag_source_unset ();
614         }
615 }
616
617 void
618 ARDOUR_UI::tabs_switch (GtkNotebookPage*, guint page)
619 {
620         if (editor && (page == (guint) _tabs.page_num (editor->contents()))) {
621                 editor_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
622
623                 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
624                         mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
625                 }
626
627                 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
628                         prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
629                 }
630         } else if (mixer && (page == (guint) _tabs.page_num (mixer->contents()))) {
631
632                 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
633                         editor_visibility_button.set_active_state (Gtkmm2ext::Off);
634                 }
635
636                 mixer_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
637
638                 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
639                         prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
640                 }
641
642         } else if (page == (guint) _tabs.page_num (rc_option_editor->contents())) {
643
644                 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
645                         editor_visibility_button.set_active_state (Gtkmm2ext::Off);
646                 }
647
648                 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
649                         mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
650                 }
651
652                 prefs_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
653         }
654
655 }
656
657 void
658 ARDOUR_UI::tabbable_state_change (Tabbable& t)
659 {
660         std::vector<std::string> insensitive_action_names;
661         std::vector<std::string> sensitive_action_names;
662         std::vector<std::string> active_action_names;
663         std::vector<std::string> inactive_action_names;
664         Glib::RefPtr<Action> action;
665         std::string downcased_name = downcase (t.name());
666         enum ViewState {
667                 Tabbed,
668                 Windowed,
669                 Hidden
670         };
671         ViewState vs;
672
673         if (t.tabbed()) {
674
675                 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
676                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
677                 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
678                 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
679
680                 vs = Tabbed;
681
682         } else if (t.tabbed_by_default ()) {
683
684                 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
685                 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
686                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
687                 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
688
689                 vs = Hidden;
690
691         } else if (t.window_visible()) {
692
693                 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
694                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
695                 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
696                 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
697
698                 active_action_names.push_back (string_compose ("show-%1", downcased_name));
699                 inactive_action_names.push_back (string_compose ("hide-%1", downcased_name));
700
701                 vs = Windowed;
702
703         } else {
704
705                 /* not currently visible. allow user to retab it or just make
706                  * it visible.
707                  */
708
709                 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
710                 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
711                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
712                 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
713
714                 active_action_names.push_back (string_compose ("hide-%1", downcased_name));
715                 inactive_action_names.push_back (string_compose ("show-%1", downcased_name));
716
717                 vs = Hidden;
718         }
719
720         for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
721                 action = ActionManager::get_action (X_("Common"), (*s).c_str());
722                 if (action) {
723                         action->set_sensitive (false);
724                 }
725         }
726
727         for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
728                 action = ActionManager::get_action (X_("Common"), (*s).c_str());
729                 if (action) {
730                         action->set_sensitive (true);
731                 }
732         }
733
734         ArdourButton* vis_button = 0;
735         std::vector<ArdourButton*> other_vis_buttons;
736
737         if (&t == editor) {
738                 vis_button = &editor_visibility_button;
739                 other_vis_buttons.push_back (&mixer_visibility_button);
740                 other_vis_buttons.push_back (&prefs_visibility_button);
741         } else if (&t == mixer) {
742                 vis_button = &mixer_visibility_button;
743                 other_vis_buttons.push_back (&editor_visibility_button);
744                 other_vis_buttons.push_back (&prefs_visibility_button);
745         } else if (&t == rc_option_editor) {
746                 vis_button = &prefs_visibility_button;
747                 other_vis_buttons.push_back (&editor_visibility_button);
748                 other_vis_buttons.push_back (&mixer_visibility_button);
749         }
750
751         if (!vis_button) {
752                 return;
753         }
754
755         switch (vs) {
756         case Tabbed:
757                 vis_button->set_active_state (Gtkmm2ext::ImplicitActive);
758                 break;
759         case Windowed:
760                 vis_button->set_active_state (Gtkmm2ext::ExplicitActive);
761                 break;
762         case Hidden:
763                 vis_button->set_active_state (Gtkmm2ext::Off);
764                 break;
765         }
766
767         for (std::vector<ArdourButton*>::iterator b = other_vis_buttons.begin(); b != other_vis_buttons.end(); ++b) {
768                 (*b)->set_active_state (Gtkmm2ext::Off);
769         }
770 }
771
772 void
773 ARDOUR_UI::toggle_meterbridge ()
774 {
775         assert (editor && mixer && meterbridge);
776
777         bool show = false;
778         bool obscuring = false;
779
780         if (meterbridge->not_visible ()) {
781                 show = true;
782         } else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
783                    (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
784                 obscuring = true;
785         }
786
787         if (obscuring && ((editor->own_window() && editor->own_window()->property_has_toplevel_focus()) ||
788                           (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
789                 show = true;
790         }
791
792         if (show) {
793                 meterbridge->show_window ();
794                 meterbridge->present ();
795                 meterbridge->raise ();
796         } else {
797                 meterbridge->hide_window (NULL);
798         }
799 }
800
801 void
802 ARDOUR_UI::toggle_luawindow ()
803 {
804         assert (editor && luawindow);
805
806         bool show = false;
807
808         if (luawindow->not_visible ()) {
809                 show = true;
810         }
811         // TODO check overlap
812
813         if (show) {
814                 luawindow->show_window ();
815                 luawindow->present ();
816                 luawindow->raise ();
817         } else {
818                 luawindow->hide_window (NULL);
819         }
820 }
821
822
823 void
824 ARDOUR_UI::new_midi_tracer_window ()
825 {
826         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
827         if (!act) {
828                 return;
829         }
830
831         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
832         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
833                 ++i;
834         }
835
836         if (i == _midi_tracer_windows.end()) {
837                 /* all our MIDITracer windows are visible; make a new one */
838                 MidiTracer* t = new MidiTracer ();
839                 t->show_all ();
840                 _midi_tracer_windows.push_back (t);
841         } else {
842                 /* re-use the hidden one */
843                 (*i)->show_all ();
844         }
845 }
846
847 KeyEditor*
848 ARDOUR_UI::create_key_editor ()
849 {
850         KeyEditor* kedit = new KeyEditor;
851
852         for (std::list<Bindings*>::iterator b = Bindings::bindings.begin(); b != Bindings::bindings.end(); ++b) {
853                 kedit->add_tab ((*b)->name(), **b);
854         }
855
856         return kedit;
857 }
858
859 BundleManager*
860 ARDOUR_UI::create_bundle_manager ()
861 {
862         return new BundleManager (_session);
863 }
864
865 AddVideoDialog*
866 ARDOUR_UI::create_add_video_dialog ()
867 {
868         return new AddVideoDialog (_session);
869 }
870
871 SessionOptionEditor*
872 ARDOUR_UI::create_session_option_editor ()
873 {
874         return new SessionOptionEditor (_session);
875 }
876
877 BigClockWindow*
878 ARDOUR_UI::create_big_clock_window ()
879 {
880         return new BigClockWindow (*big_clock);
881 }
882
883 BigTransportWindow*
884 ARDOUR_UI::create_big_transport_window ()
885 {
886         BigTransportWindow* btw = new BigTransportWindow ();
887         btw->set_session (_session);
888         return btw;
889 }
890
891 void
892 ARDOUR_UI::handle_locations_change (Location *)
893 {
894         if (_session) {
895                 if (_session->locations()->num_range_markers()) {
896                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
897                 } else {
898                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
899                 }
900         }
901 }
902
903 bool
904 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
905 {
906         if (object == editor) {
907
908                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
909                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
910                         if (big_clock_window) {
911                                 big_clock_window->set_transient_for (*editor->own_window());
912                         }
913                         if (big_transport_window) {
914                                 big_transport_window->set_transient_for (*editor->own_window());
915                         }
916                 }
917
918         } else if (object == mixer) {
919
920                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
921                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
922                         if (big_clock_window) {
923                                 big_clock_window->set_transient_for (*mixer->own_window());
924                         }
925                         if (big_transport_window) {
926                                 big_transport_window->set_transient_for (*mixer->own_window());
927                         }
928                 }
929         }
930
931         return false;
932 }
933
934 bool
935 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
936 {
937         if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
938                 ArdourMeter::ResetAllPeakDisplays ();
939         } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
940                 if (_session->master_out()) {
941                         ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
942                 }
943         } else if (_session->master_out()) {
944                 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
945         }
946         return false;
947 }
948
949 void
950 ARDOUR_UI::toggle_mixer_space()
951 {
952         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
953
954         if (act) {
955                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
956                 if (tact->get_active()) {
957                         mixer->maximise_mixer_space ();
958                 } else {
959                         mixer->restore_mixer_space ();
960                 }
961         }
962 }
963
964 void
965 ARDOUR_UI::toggle_mixer_list()
966 {
967         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMixerList");
968
969         if (act) {
970                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
971                         mixer->show_mixer_list (tact->get_active());
972         }
973 }
974
975 void
976 ARDOUR_UI::toggle_monitor_section_visibility ()
977 {
978         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
979
980         if (act) {
981                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
982                         mixer->show_monitor_section (tact->get_active());
983         }
984 }
985
986 void
987 ARDOUR_UI::toggle_vca_pane ()
988 {
989         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleVCAPane");
990
991         if (act) {
992                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
993                 mixer->showhide_vcas (tact->get_active());
994         }
995 }
996
997 #ifdef MIXBUS
998 void
999 ARDOUR_UI::toggle_mixbus_pane ()
1000 {
1001         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMixbusPane");
1002
1003         if (act) {
1004                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1005                 mixer->showhide_mixbusses (tact->get_active());
1006         }
1007 }
1008 #endif