d43d1dbec6347f198232b625dbe9331951aa4cf3
[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                 manage_window (*t);
384                 t->show_all ();
385                 _midi_tracer_windows.push_back (t);
386         } else {
387                 /* re-use the hidden one */
388                 (*i)->show_all ();
389         }
390 }
391
392 BundleManager*
393 ARDOUR_UI::create_bundle_manager ()
394 {
395         return new BundleManager (_session);
396 }
397
398 AddVideoDialog*
399 ARDOUR_UI::create_add_video_dialog ()
400 {
401         return new AddVideoDialog (_session);
402 }
403
404 SessionOptionEditor*
405 ARDOUR_UI::create_session_option_editor ()
406 {
407         return new SessionOptionEditor (_session);
408 }
409
410 BigClockWindow*
411 ARDOUR_UI::create_big_clock_window ()
412 {
413         return new BigClockWindow (*big_clock);
414 }
415
416 void
417 ARDOUR_UI::handle_locations_change (Location *)
418 {
419         if (_session) {
420                 if (_session->locations()->num_range_markers()) {
421                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
422                 } else {
423                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
424                 }
425         }
426 }
427
428 bool
429 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
430 {
431         if (window_was_editor) {
432
433                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
434                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
435                         if (big_clock_window) {
436                                 big_clock_window->set_transient_for (*editor);
437                         }
438                 }
439
440         } else {
441
442                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
443                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
444                         if (big_clock_window) {
445                                 big_clock_window->set_transient_for (*mixer);
446                         }
447                 }
448         }
449
450         return false;
451 }