0dc7104f8c8c28b5755ec19380a7a8daa5a6dbdf
[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/profile.h"
29 #include "ardour/session.h"
30
31 #include "actions.h"
32 #include "add_route_dialog.h"
33 #include "add_video_dialog.h"
34 #include "ardour_ui.h"
35 #include "big_clock_window.h"
36 #include "bundle_manager.h"
37 #include "global_port_matrix.h"
38 #include "gui_object.h"
39 #include "gui_thread.h"
40 #include "keyeditor.h"
41 #include "location_ui.h"
42 #include "main_clock.h"
43 #include "meter_patterns.h"
44 #include "midi_tracer.h"
45 #include "mixer_ui.h"
46 #include "public_editor.h"
47 #include "rc_option_editor.h"
48 #include "route_params_ui.h"
49 #include "shuttle_control.h"
50 #include "session_option_editor.h"
51 #include "speaker_dialog.h"
52 #include "splash.h"
53 #include "sfdb_ui.h"
54 #include "theme_manager.h"
55 #include "time_info_box.h"
56
57 #include <gtkmm2ext/keyboard.h>
58
59 #include "i18n.h"
60
61 using namespace ARDOUR;
62 using namespace PBD;
63 using namespace Glib;
64 using namespace Gtk;
65 using namespace Gtkmm2ext;
66
67 void
68 ARDOUR_UI::set_session (Session *s)
69 {
70         SessionHandlePtr::set_session (s);
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         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(8, -1);
228                 editor_meter_peak_display.set_corner_radius(3);
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 (Config->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
242 int
243 ARDOUR_UI::unload_session (bool hide_stuff)
244 {
245         if (_session) {
246                 ARDOUR_UI::instance()->video_timeline->sync_session_state();
247         }
248
249         if (_session && _session->dirty()) {
250                 std::vector<std::string> actions;
251                 actions.push_back (_("Don't close"));
252                 actions.push_back (_("Just close"));
253                 actions.push_back (_("Save and close"));
254                 switch (ask_about_saving_session (actions)) {
255                 case -1:
256                         // cancel
257                         return 1;
258
259                 case 1:
260                         _session->save_state ("");
261                         break;
262                 }
263         }
264
265         if (hide_stuff) {
266                 editor->hide ();
267                 mixer->hide ();
268                 meterbridge->hide ();
269                 theme_manager->hide ();
270                 audio_port_matrix->hide();
271                 midi_port_matrix->hide();
272                 route_params->hide();
273         }
274
275         second_connection.disconnect ();
276         point_one_second_connection.disconnect ();
277         point_zero_something_second_connection.disconnect();
278         fps_connection.disconnect();
279
280         if (editor_meter) {
281                 meter_box.remove(*editor_meter);
282                 delete editor_meter;
283                 editor_meter = 0;
284                 editor_meter_peak_display.hide();
285         }
286
287         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
288
289         rec_button.set_sensitive (false);
290
291         WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
292
293         if (ARDOUR_UI::instance()->video_timeline) {
294                 ARDOUR_UI::instance()->video_timeline->close_session();
295         }
296
297         stop_blinking ();
298         stop_clocking ();
299
300         /* drop everything attached to the blink signal */
301
302         Blink.clear ();
303
304         delete _session;
305         _session = 0;
306
307         session_loaded = false;
308
309         update_buffer_load ();
310
311         return 0;
312 }
313
314 static bool
315 _hide_splash (gpointer arg)
316 {
317         ((ARDOUR_UI*)arg)->hide_splash();
318         return false;
319 }
320
321 void
322 ARDOUR_UI::goto_editor_window ()
323 {
324         if (splash && splash->is_visible()) {
325                 // in 2 seconds, hide the splash screen
326                 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
327         }
328
329         editor->show_window ();
330         editor->present ();
331         /* mixer should now be on top */
332         WM::Manager::instance().set_transient_for (editor);
333         _mixer_on_top = false;
334 }
335
336 void
337 ARDOUR_UI::goto_mixer_window ()
338 {
339         Glib::RefPtr<Gdk::Window> win;
340         Glib::RefPtr<Gdk::Screen> screen;
341         
342         if (editor) {
343                 win = editor->get_window ();
344         }
345
346         if (win) {
347                 screen = win->get_screen();
348         } else {
349                 screen = Gdk::Screen::get_default();
350         }
351         
352         if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
353                 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
354                 msg.run ();
355                 return;
356         }
357
358         mixer->show_window ();
359         mixer->present ();
360         /* mixer should now be on top */
361         WM::Manager::instance().set_transient_for (mixer);
362         _mixer_on_top = true;
363 }
364
365 void
366 ARDOUR_UI::toggle_mixer_window ()
367 {
368         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
369         if (!act) {
370                 return;
371         }
372
373         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
374
375         if (tact->get_active()) {
376                 goto_mixer_window ();
377         } else {
378                 mixer->hide ();
379         }
380 }
381
382 void
383 ARDOUR_UI::toggle_meterbridge ()
384 {
385         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
386         if (!act) {
387                 return;
388         }
389
390         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
391
392         if (tact->get_active()) {
393                 meterbridge->show_window ();
394         } else {
395                 meterbridge->hide_window (NULL);
396         }
397 }
398
399 void
400 ARDOUR_UI::toggle_editor_mixer ()
401 {
402         bool obscuring = false;
403         /* currently, if windows are on different
404            screens then we do nothing; but in the
405            future we may want to bring the window 
406            to the front or something, so I'm leaving this 
407            variable for future use
408         */
409         bool same_screen = true; 
410         
411         if (editor && mixer) {
412
413                 /* remeber: Screen != Monitor (Screen is a separately rendered
414                  * continuous geometry that make include 1 or more monitors.
415                  */
416                 
417                 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
418                         // different screens, so don't do anything
419                         same_screen = false;
420                 } else {
421                         // they are on the same screen, see if they are obscuring each other
422
423                         gint ex, ey, ew, eh;
424                         gint mx, my, mw, mh;
425
426                         editor->get_position (ex, ey);
427                         editor->get_size (ew, eh);
428
429                         mixer->get_position (mx, my);
430                         mixer->get_size (mw, mh);
431
432                         GdkRectangle e;
433                         GdkRectangle m;
434                         GdkRectangle r;
435
436                         e.x = ex;
437                         e.y = ey;
438                         e.width = ew;
439                         e.height = eh;
440
441                         m.x = mx;
442                         m.y = my;
443                         m.width = mw;
444                         m.height = mh;
445
446                         if (gdk_rectangle_intersect (&e, &m, &r)) {
447                                 obscuring = true;
448                         }
449                 }
450         }
451
452         if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
453                 if (obscuring && same_screen) {
454                         goto_editor_window();
455                 }
456         } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
457                 if (obscuring && same_screen) {
458                         goto_mixer_window();
459                 }
460         } else if (mixer && mixer->not_visible()) {
461                 if (obscuring && same_screen) {
462                         goto_mixer_window ();
463                 }
464         } else if (editor && editor->not_visible()) {
465                 if (obscuring && same_screen) {
466                         goto_editor_window ();
467                 }
468         } else if (obscuring && same_screen) {
469                 //it's unclear what to do here, so just do the opposite of what we did last time  (old behavior)
470                 if (_mixer_on_top) {
471                         goto_editor_window ();
472                 } else {
473                         goto_mixer_window ();
474                 }
475         }
476 }
477
478 void
479 ARDOUR_UI::new_midi_tracer_window ()
480 {
481         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
482         if (!act) {
483                 return;
484         }
485
486         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
487         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
488                 ++i;
489         }
490
491         if (i == _midi_tracer_windows.end()) {
492                 /* all our MIDITracer windows are visible; make a new one */
493                 MidiTracer* t = new MidiTracer ();
494                 t->show_all ();
495                 _midi_tracer_windows.push_back (t);
496         } else {
497                 /* re-use the hidden one */
498                 (*i)->show_all ();
499         }
500 }
501
502 BundleManager*
503 ARDOUR_UI::create_bundle_manager ()
504 {
505         return new BundleManager (_session);
506 }
507
508 AddVideoDialog*
509 ARDOUR_UI::create_add_video_dialog ()
510 {
511         return new AddVideoDialog (_session);
512 }
513
514 SessionOptionEditor*
515 ARDOUR_UI::create_session_option_editor ()
516 {
517         return new SessionOptionEditor (_session);
518 }
519
520 BigClockWindow*
521 ARDOUR_UI::create_big_clock_window ()
522 {
523         return new BigClockWindow (*big_clock);
524 }
525
526 void
527 ARDOUR_UI::handle_locations_change (Location *)
528 {
529         if (_session) {
530                 if (_session->locations()->num_range_markers()) {
531                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
532                 } else {
533                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
534                 }
535         }
536 }
537
538 bool
539 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
540 {
541         if (window_was_editor) {
542
543                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
544                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
545                         if (big_clock_window) {
546                                 big_clock_window->set_transient_for (*editor);
547                         }
548                 }
549
550         } else {
551
552                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
553                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
554                         if (big_clock_window) {
555                                 big_clock_window->set_transient_for (*mixer);
556                         }
557                 }
558         }
559
560         return false;
561 }
562
563 bool
564 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
565 {
566         if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
567                 ArdourMeter::ResetAllPeakDisplays ();
568         } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
569                 if (_session->master_out()) {
570                         ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
571                 }
572         } else if (_session->master_out()) {
573                 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
574         }
575         return false;
576 }
577
578 void
579 ARDOUR_UI::toggle_mixer_space()
580 {
581         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
582
583         if (act) {
584                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
585                 if (tact->get_active()) {
586                         mixer->maximise_mixer_space ();
587                 } else {
588                         mixer->restore_mixer_space ();
589                 }
590         }
591 }