fix up fwd/reverse stuff in semitone mode
[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
29 #include "actions.h"
30 #include "add_route_dialog.h"
31 #include "ardour_ui.h"
32 #include "bundle_manager.h"
33 #include "global_port_matrix.h"
34 #include "gui_thread.h"
35 #include "keyeditor.h"
36 #include "location_ui.h"
37 #include "midi_tracer.h"
38 #include "mixer_ui.h"
39 #include "public_editor.h"
40 #include "rc_option_editor.h"
41 #include "route_params_ui.h"
42 #include "shuttle_control.h"
43 #include "session_option_editor.h"
44 #include "speaker_dialog.h"
45 #include "sfdb_ui.h"
46 #include "theme_manager.h"
47
48 #include "i18n.h"
49
50 using namespace ARDOUR;
51 using namespace PBD;
52 using namespace Glib;
53 using namespace Gtk;
54 using namespace Gtkmm2ext;
55
56 void
57 ARDOUR_UI::set_session (Session *s)
58 {
59         SessionHandlePtr::set_session (s);
60
61         if (!_session) {
62                 return;
63         }
64
65         if (location_ui->get()) {
66                 location_ui->get()->set_session(s);
67         }
68
69         if (speaker_config_window->get()) {
70                 speaker_config_window->get()->set_speakers (s->get_speakers());
71         }
72
73         if (route_params) {
74                 route_params->set_session (s);
75         }
76
77         if (add_route_dialog) {
78                 add_route_dialog->set_session (s);
79         }
80
81         if (session_option_editor) {
82                 session_option_editor->set_session (s);
83         }
84
85         if (shuttle_box) {
86                 shuttle_box->set_session (s);
87         }
88
89         for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
90                 if (_global_port_matrix[*i]->get()) {
91                         _global_port_matrix[*i]->get()->set_session (_session);
92                 }
93         }
94
95         primary_clock.set_session (s);
96         secondary_clock.set_session (s);
97         big_clock.set_session (s);
98         preroll_clock.set_session (s);
99         postroll_clock.set_session (s);
100         
101         /* sensitize menu bar options that are now valid */
102
103         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
104         ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
105
106         if (_session->locations()->num_range_markers()) {
107                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
108         } else {
109                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
110         }
111
112         if (!_session->monitor_out()) {
113                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
114                 if (act) {
115                         act->set_sensitive (false);
116                 }
117         }
118
119         /* allow wastebasket flush again */
120
121         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
122         if (act) {
123                 act->set_sensitive (true);
124         }
125
126         /* there are never any selections on startup */
127
128         ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
129         ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
130         ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
131         ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
132         ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
133
134         rec_button.set_sensitive (true);
135
136         solo_alert_button.set_active (_session->soloing());
137
138         setup_session_options ();
139
140         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
141         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
142         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
143         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
144
145         _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
146         _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
147         _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
148         _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
149
150         _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
151         _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
152         _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
153         _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
154         _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
155
156 #ifdef HAVE_JACK_SESSION
157         engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, ui_bind (&Session::jack_session_event, _session, _1), gui_context());
158 #endif
159
160         /* Clocks are on by default after we are connected to a session, so show that here.
161         */
162
163         connect_dependents_to_session (s);
164
165         /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
166            restore their modes or are explicitly set, we will cause the "new" mode to be saved
167            back to the session XML ("Extra") state.
168          */
169
170         AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
171
172         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
173
174         start_clocking ();
175         start_blinking ();
176
177         map_transport_state ();
178
179         second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
180         point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
181         point_zero_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_one_seconds), 40);
182 }
183
184 int
185 ARDOUR_UI::unload_session (bool hide_stuff)
186 {
187         if (_session && _session->dirty()) {
188                 switch (ask_about_saving_session (_("close"))) {
189                 case -1:
190                         // cancel
191                         return 1;
192
193                 case 1:
194                         _session->save_state ("");
195                         break;
196                 }
197         }
198
199         if (hide_stuff) {
200                 editor->hide ();
201                 mixer->hide ();
202                 theme_manager->hide ();
203         }
204
205         second_connection.disconnect ();
206         point_one_second_connection.disconnect ();
207         point_oh_five_second_connection.disconnect ();
208         point_zero_one_second_connection.disconnect();
209
210         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
211
212         rec_button.set_sensitive (false);
213
214         stop_blinking ();
215         stop_clocking ();
216
217         /* drop everything attached to the blink signal */
218
219         Blink.clear ();
220
221         delete _session;
222
223         update_buffer_load ();
224
225         return 0;
226 }
227
228 void
229 ARDOUR_UI::toggle_big_clock_window ()
230 {
231         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
232         if (act) {
233                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
234
235                 if (tact->get_active()) {
236                         big_clock_window->get()->show_all ();
237                         big_clock_window->get()->present ();
238                 } else {
239                         big_clock_window->get()->hide ();
240                 }
241         }
242 }
243
244 void
245 ARDOUR_UI::toggle_speaker_config_window ()
246 {
247         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-speaker-config"));
248         if (act) {
249                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
250
251                 if (tact->get_active()) {
252                         speaker_config_window->get()->show_all ();
253                         speaker_config_window->get()->present ();
254                 } else {
255                         speaker_config_window->get()->hide ();
256                 }
257         }
258 }
259
260 void
261 ARDOUR_UI::new_midi_tracer_window ()
262 {
263         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
264         if (!act) {
265                 return;
266         }
267
268         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
269         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
270                 ++i;
271         }
272
273         if (i == _midi_tracer_windows.end()) {
274                 /* all our MIDITracer windows are visible; make a new one */
275                 MidiTracer* t = new MidiTracer ();
276                 manage_window (*t);
277                 t->show_all ();
278                 _midi_tracer_windows.push_back (t);
279         } else {
280                 /* re-use the hidden one */
281                 (*i)->show_all ();
282         }
283 }
284
285 void
286 ARDOUR_UI::toggle_rc_options_window ()
287 {
288         if (rc_option_editor == 0) {
289                 rc_option_editor = new RCOptionEditor;
290                 rc_option_editor->signal_unmap().connect(sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleRCOptionsEditor")));
291                 rc_option_editor->set_session (_session);
292         }
293
294         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleRCOptionsEditor"));
295         if (act) {
296                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
297
298                 if (tact->get_active()) {
299                         rc_option_editor->show_all ();
300                         rc_option_editor->present ();
301                 } else {
302                         rc_option_editor->hide ();
303                 }
304         }
305 }
306
307 void
308 ARDOUR_UI::toggle_session_options_window ()
309 {
310         if (session_option_editor == 0) {
311                 session_option_editor = new SessionOptionEditor (_session);
312                 session_option_editor->signal_unmap().connect(sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleSessionOptionsEditor")));
313         }
314
315         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleSessionOptionsEditor"));
316         if (act) {
317                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic (act);
318
319                 if (tact->get_active()) {
320                         session_option_editor->show_all ();
321                         session_option_editor->present ();
322                 } else {
323                         session_option_editor->hide ();
324                 }
325         }
326 }
327
328 int
329 ARDOUR_UI::create_location_ui ()
330 {
331         if (location_ui->get() == 0) {
332                 location_ui->set (new LocationUIWindow ());
333                 location_ui->get()->set_session (_session);
334                 location_ui->get()->signal_unmap().connect (sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleLocations")));
335         }
336         return 0;
337 }
338
339 void
340 ARDOUR_UI::toggle_location_window ()
341 {
342         if (create_location_ui()) {
343                 return;
344         }
345
346         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleLocations"));
347         if (act) {
348                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
349
350                 if (tact->get_active()) {
351                         location_ui->get()->show_all ();
352                         location_ui->get()->present ();
353                 } else {
354                         location_ui->get()->hide ();
355                 }
356         }
357 }
358
359 void
360 ARDOUR_UI::toggle_key_editor ()
361 {
362         if (key_editor == 0) {
363                 key_editor = new KeyEditor;
364                 key_editor->signal_unmap().connect (sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleKeyEditor")));
365         }
366
367         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleKeyEditor"));
368         if (act) {
369                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
370
371                 if (tact->get_active()) {
372                         key_editor->show_all ();
373                         key_editor->present ();
374                 } else {
375                         key_editor->hide ();
376                 }
377         }
378 }
379
380 void
381 ARDOUR_UI::toggle_theme_manager ()
382 {
383         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleThemeManager"));
384         if (act) {
385                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
386
387                 if (tact->get_active()) {
388                         theme_manager->show_all ();
389                         theme_manager->present ();
390                 } else {
391                         theme_manager->hide ();
392                 }
393         }
394 }
395
396 void
397 ARDOUR_UI::create_bundle_manager ()
398 {
399         if (bundle_manager == 0) {
400                 bundle_manager = new BundleManager (_session);
401                 bundle_manager->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleBundleManager")));
402         }
403 }
404
405 void
406 ARDOUR_UI::toggle_bundle_manager ()
407 {
408         create_bundle_manager ();
409
410         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBundleManager"));
411         if (act) {
412                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic (act);
413
414                 if (tact->get_active()) {
415                         bundle_manager->show_all ();
416                         bundle_manager->present ();
417                 } else {
418                         bundle_manager->hide ();
419                 }
420         }
421 }
422
423 int
424 ARDOUR_UI::create_route_params ()
425 {
426         if (route_params == 0) {
427                 route_params = new RouteParams_UI ();
428                 route_params->set_session (_session);
429                 route_params->signal_unmap().connect (sigc::bind(sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleInspector")));
430         }
431         return 0;
432 }
433
434 void
435 ARDOUR_UI::toggle_route_params_window ()
436 {
437         if (create_route_params ()) {
438                 return;
439         }
440
441         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleInspector"));
442         if (act) {
443                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
444
445                 if (tact->get_active()) {
446                         route_params->show_all ();
447                         route_params->present ();
448                 } else {
449                         route_params->hide ();
450                 }
451         }
452 }
453
454 void
455 ARDOUR_UI::handle_locations_change (Location *)
456 {
457         if (_session) {
458                 if (_session->locations()->num_range_markers()) {
459                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
460                 } else {
461                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
462                 }
463         }
464 }
465
466 bool
467 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
468 {
469         if (window_was_editor) {
470
471                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
472                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
473                         float_big_clock (editor);
474                 }
475
476         } else {
477
478                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
479                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
480                         float_big_clock (mixer);
481                 }
482         }
483
484         return false;
485 }