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