2e0d017d0c48e5f6ee5141ba81951a6c79d31751
[ardour.git] / gtk2_ardour / ardour_ui_dialogs.cc
1 /*
2     Copyright (C) 2000 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* This file contains any ARDOUR_UI methods that require knowledge of
21    the various dialog boxes, and exists so that no compilation dependency
22    exists between the main ARDOUR_UI modules and their respective classes.
23    This is to cut down on the compile times.  It also helps with my sanity.
24 */
25
26 #include "ardour/session.h"
27 #include "ardour/audioengine.h"
28 #include "ardour/automation_watch.h"
29
30 #include "actions.h"
31 #include "add_route_dialog.h"
32 #include "add_video_dialog.h"
33 #include "ardour_ui.h"
34 #include "big_clock_window.h"
35 #include "bundle_manager.h"
36 #include "global_port_matrix.h"
37 #include "gui_object.h"
38 #include "gui_thread.h"
39 #include "keyeditor.h"
40 #include "location_ui.h"
41 #include "main_clock.h"
42 #include "midi_tracer.h"
43 #include "mixer_ui.h"
44 #include "public_editor.h"
45 #include "rc_option_editor.h"
46 #include "route_params_ui.h"
47 #include "shuttle_control.h"
48 #include "session_option_editor.h"
49 #include "speaker_dialog.h"
50 #include "splash.h"
51 #include "sfdb_ui.h"
52 #include "theme_manager.h"
53 #include "time_info_box.h"
54
55 #include "i18n.h"
56
57 using namespace ARDOUR;
58 using namespace PBD;
59 using namespace Glib;
60 using namespace Gtk;
61 using namespace Gtkmm2ext;
62
63 void
64 ARDOUR_UI::set_session (Session *s)
65 {
66         SessionHandlePtr::set_session (s);
67
68         if (audio_port_matrix) {
69                 audio_port_matrix->set_session (s);
70         }
71
72         if (midi_port_matrix) {
73                 midi_port_matrix->set_session (s);
74         }
75
76
77         if (!_session) {
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         AutomationWatch::instance().set_session (s);
98         WindowManager::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.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
150         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
151         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
152         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
153         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
154
155         _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
156         _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
157         _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
158         _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
159
160         _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
161         _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
162         _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
163         _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
164         _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
165         _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
166
167 #ifdef HAVE_JACK_SESSION
168         engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
169 #endif
170
171         /* Clocks are on by default after we are connected to a session, so show that here.
172         */
173
174         connect_dependents_to_session (s);
175
176         /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
177            restore their modes or are explicitly set, we will cause the "new" mode to be saved
178            back to the session XML ("Extra") state.
179          */
180
181         AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
182
183         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
184
185         start_clocking ();
186         start_blinking ();
187
188         map_transport_state ();
189
190         second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
191         point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
192         point_zero_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_one_seconds), 40);
193
194         update_format ();
195 }
196
197 int
198 ARDOUR_UI::unload_session (bool hide_stuff)
199 {
200         if (_session) {
201                 ARDOUR_UI::instance()->video_timeline->sync_session_state();
202         }
203
204         if (_session && _session->dirty()) {
205                 std::vector<std::string> actions;
206                 actions.push_back (_("Don't close"));
207                 actions.push_back (_("Just close"));
208                 actions.push_back (_("Save and close"));
209                 switch (ask_about_saving_session (actions)) {
210                 case -1:
211                         // cancel
212                         return 1;
213
214                 case 1:
215                         _session->save_state ("");
216                         break;
217                 }
218         }
219
220         if (hide_stuff) {
221                 editor->hide ();
222                 mixer->hide ();
223                 theme_manager->hide ();
224         }
225
226         second_connection.disconnect ();
227         point_one_second_connection.disconnect ();
228         point_oh_five_second_connection.disconnect ();
229         point_zero_one_second_connection.disconnect();
230
231         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
232
233         rec_button.set_sensitive (false);
234
235         ARDOUR_UI::instance()->video_timeline->close_session();
236
237         stop_blinking ();
238         stop_clocking ();
239
240         /* drop everything attached to the blink signal */
241
242         Blink.clear ();
243
244         delete _session;
245         _session = 0;
246
247         session_loaded = false;
248
249         update_buffer_load ();
250
251         return 0;
252 }
253
254 static bool
255 _hide_splash (gpointer arg)
256 {
257         ((ARDOUR_UI*)arg)->hide_splash();
258         return false;
259 }
260
261 void
262 ARDOUR_UI::goto_editor_window ()
263 {
264         if (splash && splash->is_visible()) {
265                 // in 2 seconds, hide the splash screen
266                 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
267         }
268
269         editor->show_window ();
270         editor->present ();
271         flush_pending ();
272 }
273
274 void
275 ARDOUR_UI::goto_mixer_window ()
276 {
277         if (!editor) {
278                 return;
279         }
280
281         Glib::RefPtr<Gdk::Window> win = editor->get_window ();
282         Glib::RefPtr<Gdk::Screen> screen;
283         
284         if (win) {
285                 screen = win->get_screen();
286         } else {
287                 screen = Gdk::Screen::get_default();
288         }
289         
290         if (screen && screen->get_height() < 700) {
291                 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
292                 msg.run ();
293                 return;
294         }
295
296         mixer->show_window ();
297         mixer->present ();
298         flush_pending ();
299 }
300
301
302 void
303 ARDOUR_UI::toggle_mixer_window ()
304 {
305         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
306         if (!act) {
307                 return;
308         }
309
310         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
311
312         if (tact->get_active()) {
313                 goto_mixer_window ();
314         } else {
315                 mixer->hide ();
316         }
317 }
318
319 void
320 ARDOUR_UI::toggle_editor_mixer ()
321 {
322         if (editor && mixer) {
323
324                 if (editor->get_screen() != mixer->get_screen()) {
325                         // different screens, so don't do anything
326                         return;
327                 }
328
329                 /* See if they are obscuring each other */
330                 
331                 gint ex, ey, ew, eh;
332                 gint mx, my, mw, mh;
333
334                 editor->get_position (ex, ey);
335                 editor->get_size (ew, eh);
336
337                 mixer->get_position (mx, my);
338                 mixer->get_size (mw, mh);
339
340                 GdkRectangle e;
341                 GdkRectangle m;
342                 GdkRectangle r;
343
344                 e.x = ex;
345                 e.y = ey;
346                 e.width = ew;
347                 e.height = eh;
348
349                 m.x = mx;
350                 m.y = my;
351                 m.width = mw;
352                 m.height = mh;
353                 
354                 if (!gdk_rectangle_intersect (&e, &m, &r)) {
355                         /* they do not intersect so do not toggle */
356                         return;
357                 }
358         }
359                 
360         if (mixer && mixer->fully_visible()) {
361                 goto_editor_window ();
362         } else {
363                 goto_mixer_window ();
364         }
365 }
366
367 void
368 ARDOUR_UI::new_midi_tracer_window ()
369 {
370         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
371         if (!act) {
372                 return;
373         }
374
375         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
376         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
377                 ++i;
378         }
379
380         if (i == _midi_tracer_windows.end()) {
381                 /* all our MIDITracer windows are visible; make a new one */
382                 MidiTracer* t = new MidiTracer ();
383                 t->show_all ();
384                 _midi_tracer_windows.push_back (t);
385         } else {
386                 /* re-use the hidden one */
387                 (*i)->show_all ();
388         }
389 }
390
391 BundleManager*
392 ARDOUR_UI::create_bundle_manager ()
393 {
394         return new BundleManager (_session);
395 }
396
397 AddVideoDialog*
398 ARDOUR_UI::create_add_video_dialog ()
399 {
400         return new AddVideoDialog (_session);
401 }
402
403 SessionOptionEditor*
404 ARDOUR_UI::create_session_option_editor ()
405 {
406         return new SessionOptionEditor (_session);
407 }
408
409 BigClockWindow*
410 ARDOUR_UI::create_big_clock_window ()
411 {
412         return new BigClockWindow (*big_clock);
413 }
414
415 void
416 ARDOUR_UI::handle_locations_change (Location *)
417 {
418         if (_session) {
419                 if (_session->locations()->num_range_markers()) {
420                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
421                 } else {
422                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
423                 }
424         }
425 }
426
427 bool
428 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
429 {
430         if (window_was_editor) {
431
432                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
433                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
434                         if (big_clock_window) {
435                                 big_clock_window->set_transient_for (*editor);
436                         }
437                 }
438
439         } else {
440
441                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
442                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
443                         if (big_clock_window) {
444                                 big_clock_window->set_transient_for (*mixer);
445                         }
446                 }
447         }
448
449         return false;
450 }