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