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