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