changes to support new key bindings editor design
[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 #include "control_protocol/control_protocol.h"
36
37 #include "actions.h"
38 #include "add_route_dialog.h"
39 #include "add_video_dialog.h"
40 #include "ardour_ui.h"
41 #include "big_clock_window.h"
42 #include "bundle_manager.h"
43 #include "global_port_matrix.h"
44 #include "gui_object.h"
45 #include "gui_thread.h"
46 #include "keyeditor.h"
47 #include "location_ui.h"
48 #include "main_clock.h"
49 #include "meterbridge.h"
50 #include "meter_patterns.h"
51 #include "midi_tracer.h"
52 #include "mixer_ui.h"
53 #include "public_editor.h"
54 #include "rc_option_editor.h"
55 #include "route_params_ui.h"
56 #include "shuttle_control.h"
57 #include "session_option_editor.h"
58 #include "speaker_dialog.h"
59 #include "splash.h"
60 #include "sfdb_ui.h"
61 #include "theme_manager.h"
62 #include "time_info_box.h"
63 #include "timers.h"
64
65 #include <gtkmm2ext/keyboard.h>
66
67 #include "i18n.h"
68
69 using namespace ARDOUR;
70 using namespace PBD;
71 using namespace Glib;
72 using namespace Gtk;
73 using namespace Gtkmm2ext;
74
75 void
76 ARDOUR_UI::set_session (Session *s)
77 {
78         SessionHandlePtr::set_session (s);
79
80         if (!_session) {
81                 WM::Manager::instance().set_session (s);
82                 /* Session option editor cannot exist across change-of-session */
83                 session_option_editor.drop_window ();
84                 /* Ditto for AddVideoDialog */
85                 add_video_dialog.drop_window ();
86                 return;
87         }
88
89         const XMLNode* node = _session->extra_xml (X_("UI"));
90
91         if (node) {
92                 const XMLNodeList& children = node->children();
93                 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
94                         if ((*i)->name() == GUIObjectState::xml_node_name) {
95                                 gui_object_state->load (**i);
96                                 break;
97                         }
98                 }
99         }
100
101         WM::Manager::instance().set_session (s);
102
103         AutomationWatch::instance().set_session (s);
104
105         if (shuttle_box) {
106                 shuttle_box->set_session (s);
107         }
108
109         primary_clock->set_session (s);
110         secondary_clock->set_session (s);
111         big_clock->set_session (s);
112         time_info_box->set_session (s);
113         video_timeline->set_session (s);
114
115         /* sensitize menu bar options that are now valid */
116
117         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
118         ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
119
120         if (_session->locations()->num_range_markers()) {
121                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
122         } else {
123                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
124         }
125
126         if (!_session->monitor_out()) {
127                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
128                 if (act) {
129                         act->set_sensitive (false);
130                 }
131         }
132
133         /* allow wastebasket flush again */
134
135         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
136         if (act) {
137                 act->set_sensitive (true);
138         }
139
140         /* there are never any selections on startup */
141
142         ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
143         ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
144         ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
145         ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
146         ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
147
148         rec_button.set_sensitive (true);
149
150         solo_alert_button.set_active (_session->soloing());
151
152         setup_session_options ();
153
154         blink_connection = Timers::blink_connect (sigc::mem_fun(*this, &ARDOUR_UI::blink_handler));
155
156         _session->SaveSessionRequested.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::save_session_at_its_request, this, _1), gui_context());
157         _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
158         _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
159         _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
160         _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dirty_changed, this), gui_context());
161
162         _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
163         _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
164         _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
165         _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
166         _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
167         _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
168
169         /* Clocks are on by default after we are connected to a session, so show that here.
170         */
171
172         connect_dependents_to_session (s);
173
174         /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
175            restore their modes or are explicitly set, we will cause the "new" mode to be saved
176            back to the session XML ("Extra") state.
177          */
178
179         AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
180
181         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
182
183         start_clocking ();
184
185         map_transport_state ();
186
187         second_connection = Timers::second_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second));
188         point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds));
189         point_zero_something_second_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds));
190         set_fps_timeout_connection();
191
192         update_format ();
193
194         if (meter_box.get_parent()) {
195                 transport_hbox.remove (meter_box);
196                 transport_hbox.remove (editor_meter_peak_display);
197         }
198
199         if (editor_meter) {
200                 meter_box.remove(*editor_meter);
201                 delete editor_meter;
202                 editor_meter = 0;
203                 editor_meter_peak_display.hide();
204         }
205
206         if (meter_box.get_parent()) {
207                 transport_hbox.remove (meter_box);
208                 transport_hbox.remove (editor_meter_peak_display);
209         }
210
211         if (_session &&
212             _session->master_out() &&
213             _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
214
215                 if (!ARDOUR::Profile->get_trx()) {
216                         editor_meter = new LevelMeterHBox(_session);
217                         editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
218                         editor_meter->clear_meters();
219                         editor_meter->set_type (_session->master_out()->meter_type());
220                         editor_meter->setup_meters (30, 12, 6);
221                         editor_meter->show();
222                         meter_box.pack_start(*editor_meter);
223                 }
224
225                 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
226                 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
227                 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
228
229                 editor_meter_peak_display.set_name ("meterbridge peakindicator");
230                 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
231                 editor_meter_peak_display.set_size_request (std::max(9.f, rintf(8.f * UIConfiguration::instance().get_ui_scale())), -1);
232                 editor_meter_peak_display.set_corner_radius (3.0);
233
234                 editor_meter_max_peak = -INFINITY;
235                 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
236
237                 if (UIConfiguration::instance().get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
238                         transport_hbox.pack_start (meter_box, false, false);
239                         transport_hbox.pack_start (editor_meter_peak_display, false, false);
240                         meter_box.show();
241                         editor_meter_peak_display.show();
242                 }
243         }
244
245         update_title ();
246 }
247
248 int
249 ARDOUR_UI::unload_session (bool hide_stuff)
250 {
251         if (_session) {
252                 ARDOUR_UI::instance()->video_timeline->sync_session_state();
253         }
254
255         if (_session && _session->dirty()) {
256                 std::vector<std::string> actions;
257                 actions.push_back (_("Don't close"));
258                 actions.push_back (_("Just close"));
259                 actions.push_back (_("Save and close"));
260                 switch (ask_about_saving_session (actions)) {
261                 case -1:
262                         // cancel
263                         return 1;
264
265                 case 1:
266                         _session->save_state ("");
267                         break;
268                 }
269         }
270
271         {
272                 // tear down session specific CPI (owned by rc_config_editor which can remain)
273                 ControlProtocolManager& m = ControlProtocolManager::instance ();
274                 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
275                         if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
276                                 (*i)->protocol->tear_down_gui ();
277                         }
278                 }
279         }
280
281         if (hide_stuff) {
282                 editor->hide ();
283                 mixer->hide ();
284                 meterbridge->hide ();
285                 audio_port_matrix->hide();
286                 midi_port_matrix->hide();
287                 route_params->hide();
288         }
289
290         second_connection.disconnect ();
291         point_one_second_connection.disconnect ();
292         point_zero_something_second_connection.disconnect();
293         fps_connection.disconnect();
294
295         if (editor_meter) {
296                 meter_box.remove(*editor_meter);
297                 delete editor_meter;
298                 editor_meter = 0;
299                 editor_meter_peak_display.hide();
300         }
301
302         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
303
304         rec_button.set_sensitive (false);
305
306         WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
307
308         if (ARDOUR_UI::instance()->video_timeline) {
309                 ARDOUR_UI::instance()->video_timeline->close_session();
310         }
311
312         stop_clocking ();
313
314         /* drop everything attached to the blink signal */
315
316         blink_connection.disconnect ();
317
318         delete _session;
319         _session = 0;
320
321         session_loaded = false;
322
323         update_buffer_load ();
324         update_title ();
325         
326         return 0;
327 }
328
329 void
330 ARDOUR_UI::show_tabbable (Tabbable* t)
331 {
332         if (!t) {
333                 return;
334         }
335         
336         t->make_visible ();
337 }
338
339 void
340 ARDOUR_UI::hide_tabbable (Tabbable* t)
341 {
342         if (!t) {
343                 return;
344         }
345         t->make_invisible ();
346 }
347
348 void
349 ARDOUR_UI::attach_tabbable (Tabbable* t)
350 {
351         if (!t) {
352                 return;
353         }
354
355         t->attach ();
356 }
357
358 void
359 ARDOUR_UI::detach_tabbable (Tabbable* t)
360 {
361         if (!t) {
362                 return;
363         }
364         t->detach ();
365 }
366
367 void
368 ARDOUR_UI::tabbable_state_change (Tabbable& t)
369 {
370         std::vector<std::string> insensitive_action_names;
371         std::vector<std::string> sensitive_action_names;
372         Glib::RefPtr<Action> action;    
373         std::string downcased_name = downcase (t.name());
374
375         if (t.tabbed()) {
376
377                 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
378                 insensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
379                 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
380                 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
381
382         } else if (t.tabbed_by_default ()) {
383
384                 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
385                 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
386                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
387                 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
388                 
389         } else if (t.window_visible()) {
390
391                 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
392                 insensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
393                 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
394                 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
395
396         } else {
397
398                 /* not currently visible. allow user to retab it or just make
399                  * it visible.
400                  */
401                 
402                 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
403                 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
404                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
405                 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
406         }
407
408
409         for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
410                 action = ActionManager::get_action (X_("Common"), (*s).c_str());
411                 if (action) {
412                         action->set_sensitive (false);
413                 }
414         }
415
416         for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
417                 action = ActionManager::get_action (X_("Common"), (*s).c_str());
418                 if (action) {
419                         action->set_sensitive (true);
420                 }
421         }
422 }
423
424 void
425 ARDOUR_UI::toggle_meterbridge ()
426 {
427         assert (editor && mixer && meterbridge);
428
429         bool show = false;
430         bool obscuring = false;
431
432         if (meterbridge->not_visible ()) {
433                 show = true;
434         } else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
435                    (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
436                 obscuring = true;
437         }
438
439         if (obscuring && (editor->own_window()->property_has_toplevel_focus() || (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
440                 show = true;
441         }
442
443         if (show) {
444                 meterbridge->show_window ();
445                 meterbridge->present ();
446                 meterbridge->raise ();
447         } else {
448                 meterbridge->hide_window (NULL);
449         }
450 }
451
452 void
453 ARDOUR_UI::new_midi_tracer_window ()
454 {
455         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
456         if (!act) {
457                 return;
458         }
459
460         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
461         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
462                 ++i;
463         }
464
465         if (i == _midi_tracer_windows.end()) {
466                 /* all our MIDITracer windows are visible; make a new one */
467                 MidiTracer* t = new MidiTracer ();
468                 t->show_all ();
469                 _midi_tracer_windows.push_back (t);
470         } else {
471                 /* re-use the hidden one */
472                 (*i)->show_all ();
473         }
474 }
475
476 KeyEditor*
477 ARDOUR_UI::create_key_editor ()
478 {
479         KeyEditor* kedit = new KeyEditor;
480
481         kedit->add_tab (_("Global"), global_bindings);
482         kedit->add_tab (_("Editing"), editor->bindings);
483         kedit->add_tab (_("Mixing"), mixer->bindings);
484
485         return kedit;
486 }
487
488 BundleManager*
489 ARDOUR_UI::create_bundle_manager ()
490 {
491         return new BundleManager (_session);
492 }
493
494 AddVideoDialog*
495 ARDOUR_UI::create_add_video_dialog ()
496 {
497         return new AddVideoDialog (_session);
498 }
499
500 SessionOptionEditor*
501 ARDOUR_UI::create_session_option_editor ()
502 {
503         return new SessionOptionEditor (_session);
504 }
505
506 BigClockWindow*
507 ARDOUR_UI::create_big_clock_window ()
508 {
509         return new BigClockWindow (*big_clock);
510 }
511
512 void
513 ARDOUR_UI::handle_locations_change (Location *)
514 {
515         if (_session) {
516                 if (_session->locations()->num_range_markers()) {
517                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
518                 } else {
519                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
520                 }
521         }
522 }
523
524 bool
525 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
526 {
527         if (object == editor) {
528
529                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
530                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
531                         if (big_clock_window) {
532                                 big_clock_window->set_transient_for (*editor->own_window());
533                         }
534                 }
535
536         } else if (object == mixer) {
537
538                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
539                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
540                         if (big_clock_window) {
541                                 big_clock_window->set_transient_for (*mixer->own_window());
542                         }
543                 }
544         }
545
546         return false;
547 }
548
549 bool
550 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
551 {
552         if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
553                 ArdourMeter::ResetAllPeakDisplays ();
554         } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
555                 if (_session->master_out()) {
556                         ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
557                 }
558         } else if (_session->master_out()) {
559                 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
560         }
561         return false;
562 }
563
564 void
565 ARDOUR_UI::toggle_mixer_space()
566 {
567         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
568
569         if (act) {
570                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
571                 if (tact->get_active()) {
572                         mixer->maximise_mixer_space ();
573                 } else {
574                         mixer->restore_mixer_space ();
575                 }
576         }
577 }
578
579 void
580 ARDOUR_UI::toggle_mixer_list()
581 {
582         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMixerList");
583
584         if (act) {
585                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
586                         mixer->show_mixer_list (tact->get_active());
587         }
588 }
589
590 void
591 ARDOUR_UI::toggle_monitor_section_visibility ()
592 {
593         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
594
595         if (act) {
596                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
597                         mixer->show_monitor_section (tact->get_active());
598         }
599 }