NOOP, remove trailing tabs/whitespace.
[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::update_autosave, 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
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         {
266                 // tear down session specific CPI (owned by rc_config_editor which can remain)
267                 ControlProtocolManager& m = ControlProtocolManager::instance ();
268                 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
269                         if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
270                                 (*i)->protocol->tear_down_gui ();
271                         }
272                 }
273         }
274
275         if (hide_stuff) {
276                 editor->hide ();
277                 mixer->hide ();
278                 meterbridge->hide ();
279                 audio_port_matrix->hide();
280                 midi_port_matrix->hide();
281                 route_params->hide();
282         }
283
284         second_connection.disconnect ();
285         point_one_second_connection.disconnect ();
286         point_zero_something_second_connection.disconnect();
287         fps_connection.disconnect();
288
289         if (editor_meter) {
290                 meter_box.remove(*editor_meter);
291                 delete editor_meter;
292                 editor_meter = 0;
293                 editor_meter_peak_display.hide();
294         }
295
296         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
297
298         rec_button.set_sensitive (false);
299
300         WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
301
302         if (ARDOUR_UI::instance()->video_timeline) {
303                 ARDOUR_UI::instance()->video_timeline->close_session();
304         }
305
306         stop_clocking ();
307
308         /* drop everything attached to the blink signal */
309
310         blink_connection.disconnect ();
311
312         delete _session;
313         _session = 0;
314
315         session_loaded = false;
316
317         update_buffer_load ();
318
319         return 0;
320 }
321
322 static bool
323 _hide_splash (gpointer arg)
324 {
325         ((ARDOUR_UI*)arg)->hide_splash();
326         return false;
327 }
328
329 void
330 ARDOUR_UI::goto_editor_window ()
331 {
332         if (splash && splash->is_visible()) {
333                 // in 2 seconds, hide the splash screen
334                 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
335         }
336
337         editor->show_window ();
338         editor->present ();
339         /* mixer should now be on top */
340         if (UIConfiguration::instance().get_transients_follow_front()) {
341                 WM::Manager::instance().set_transient_for (editor);
342         }
343         _mixer_on_top = false;
344 }
345
346 void
347 ARDOUR_UI::goto_mixer_window ()
348 {
349         Glib::RefPtr<Gdk::Window> win;
350         Glib::RefPtr<Gdk::Screen> screen;
351
352         if (editor) {
353                 win = editor->get_window ();
354         }
355
356         if (win) {
357                 screen = win->get_screen();
358         } else {
359                 screen = Gdk::Screen::get_default();
360         }
361
362         if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
363                 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
364                 msg.run ();
365                 return;
366         }
367
368         mixer->show_window ();
369         mixer->present ();
370         /* mixer should now be on top */
371         if (UIConfiguration::instance().get_transients_follow_front()) {
372                 WM::Manager::instance().set_transient_for (mixer);
373         }
374         _mixer_on_top = true;
375 }
376
377 void
378 ARDOUR_UI::toggle_mixer_window ()
379 {
380         /* thse windows are created in ARDOUR_UI::setup_windows()
381          * it should be impossible to get here with any of them being NULL
382          */
383         assert (editor && mixer && meterbridge);
384
385         bool show = false;
386         bool obscuring = false;
387
388         if (mixer->not_visible ()) {
389                 show = true;
390         }
391         else if (   (!editor->not_visible () && ARDOUR_UI_UTILS::windows_overlap (editor, mixer))
392                  || (!meterbridge->not_visible () && ARDOUR_UI_UTILS::windows_overlap (meterbridge, mixer))
393                         ) {
394                 obscuring = true;
395         }
396
397         if (obscuring && (editor->property_has_toplevel_focus() || meterbridge->property_has_toplevel_focus())) {
398                 show = true;
399         }
400
401         if (show) {
402                 goto_mixer_window ();
403         } else {
404                 mixer->hide ();
405         }
406 }
407
408 void
409 ARDOUR_UI::toggle_meterbridge ()
410 {
411         assert (editor && mixer && meterbridge);
412
413         bool show = false;
414         bool obscuring = false;
415
416         if (meterbridge->not_visible ()) {
417                 show = true;
418         }
419         else if (   (!editor->not_visible() && ARDOUR_UI_UTILS::windows_overlap (editor, meterbridge))
420                  || (!mixer->not_visible () && ARDOUR_UI_UTILS::windows_overlap (meterbridge, mixer))
421                         ) {
422                 obscuring = true;
423         }
424
425         if (obscuring && (editor->property_has_toplevel_focus() || mixer->property_has_toplevel_focus())) {
426                 show = true;
427         }
428
429         if (show) {
430                 meterbridge->show_window ();
431                 meterbridge->present ();
432                 meterbridge->raise ();
433         } else {
434                 meterbridge->hide_window (NULL);
435         }
436 }
437
438 void
439 ARDOUR_UI::toggle_editor_mixer ()
440 {
441         bool obscuring = false;
442
443         if (editor && mixer) {
444                 if (ARDOUR_UI_UTILS::windows_overlap (editor, mixer)) {
445                         obscuring = true;
446                 }
447         }
448
449         if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
450                 if (obscuring) {
451                         goto_editor_window();
452                 }
453         } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
454                 if (obscuring) {
455                         goto_mixer_window();
456                 }
457         } else if (mixer && mixer->not_visible()) {
458                 if (obscuring) {
459                         goto_mixer_window ();
460                 }
461         } else if (editor && editor->not_visible()) {
462                 if (obscuring) {
463                         goto_editor_window ();
464                 }
465         } else if (obscuring) {
466                 //it's unclear what to do here, so just do the opposite of what we did last time  (old behavior)
467                 if (_mixer_on_top) {
468                         goto_editor_window ();
469                 } else {
470                         goto_mixer_window ();
471                 }
472         }
473 }
474
475 void
476 ARDOUR_UI::new_midi_tracer_window ()
477 {
478         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
479         if (!act) {
480                 return;
481         }
482
483         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
484         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
485                 ++i;
486         }
487
488         if (i == _midi_tracer_windows.end()) {
489                 /* all our MIDITracer windows are visible; make a new one */
490                 MidiTracer* t = new MidiTracer ();
491                 t->show_all ();
492                 _midi_tracer_windows.push_back (t);
493         } else {
494                 /* re-use the hidden one */
495                 (*i)->show_all ();
496         }
497 }
498
499 BundleManager*
500 ARDOUR_UI::create_bundle_manager ()
501 {
502         return new BundleManager (_session);
503 }
504
505 AddVideoDialog*
506 ARDOUR_UI::create_add_video_dialog ()
507 {
508         return new AddVideoDialog (_session);
509 }
510
511 SessionOptionEditor*
512 ARDOUR_UI::create_session_option_editor ()
513 {
514         return new SessionOptionEditor (_session);
515 }
516
517 BigClockWindow*
518 ARDOUR_UI::create_big_clock_window ()
519 {
520         return new BigClockWindow (*big_clock);
521 }
522
523 void
524 ARDOUR_UI::handle_locations_change (Location *)
525 {
526         if (_session) {
527                 if (_session->locations()->num_range_markers()) {
528                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
529                 } else {
530                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
531                 }
532         }
533 }
534
535 bool
536 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
537 {
538         if (window_was_editor) {
539
540                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
541                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
542                         if (big_clock_window) {
543                                 big_clock_window->set_transient_for (*editor);
544                         }
545                 }
546
547         } else {
548
549                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
550                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
551                         if (big_clock_window) {
552                                 big_clock_window->set_transient_for (*mixer);
553                         }
554                 }
555         }
556
557         return false;
558 }
559
560 bool
561 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
562 {
563         if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
564                 ArdourMeter::ResetAllPeakDisplays ();
565         } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
566                 if (_session->master_out()) {
567                         ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
568                 }
569         } else if (_session->master_out()) {
570                 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
571         }
572         return false;
573 }
574
575 void
576 ARDOUR_UI::toggle_mixer_space()
577 {
578         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
579
580         if (act) {
581                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
582                 if (tact->get_active()) {
583                         mixer->maximise_mixer_space ();
584                 } else {
585                         mixer->restore_mixer_space ();
586                 }
587         }
588 }