add editor to Theme Manager for modifiers
[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                 theme_manager->hide ();
284                 audio_port_matrix->hide();
285                 midi_port_matrix->hide();
286                 route_params->hide();
287         }
288
289         second_connection.disconnect ();
290         point_one_second_connection.disconnect ();
291 #ifndef PLATFORM_WINDOWS
292         point_zero_something_second_connection.disconnect();
293 #endif
294         fps_connection.disconnect();
295
296         if (editor_meter) {
297                 meter_box.remove(*editor_meter);
298                 delete editor_meter;
299                 editor_meter = 0;
300                 editor_meter_peak_display.hide();
301         }
302
303         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
304
305         rec_button.set_sensitive (false);
306
307         WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
308
309         if (ARDOUR_UI::instance()->video_timeline) {
310                 ARDOUR_UI::instance()->video_timeline->close_session();
311         }
312
313         stop_blinking ();
314         stop_clocking ();
315
316         /* drop everything attached to the blink signal */
317
318         Blink.clear ();
319
320         delete _session;
321         _session = 0;
322
323         session_loaded = false;
324
325         update_buffer_load ();
326
327         return 0;
328 }
329
330 static bool
331 _hide_splash (gpointer arg)
332 {
333         ((ARDOUR_UI*)arg)->hide_splash();
334         return false;
335 }
336
337 void
338 ARDOUR_UI::goto_editor_window ()
339 {
340         if (splash && splash->is_visible()) {
341                 // in 2 seconds, hide the splash screen
342                 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
343         }
344
345         editor->show_window ();
346         editor->present ();
347         /* mixer should now be on top */
348         WM::Manager::instance().set_transient_for (editor);
349         _mixer_on_top = false;
350 }
351
352 void
353 ARDOUR_UI::goto_mixer_window ()
354 {
355         Glib::RefPtr<Gdk::Window> win;
356         Glib::RefPtr<Gdk::Screen> screen;
357         
358         if (editor) {
359                 win = editor->get_window ();
360         }
361
362         if (win) {
363                 screen = win->get_screen();
364         } else {
365                 screen = Gdk::Screen::get_default();
366         }
367         
368         if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
369                 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
370                 msg.run ();
371                 return;
372         }
373
374         mixer->show_window ();
375         mixer->present ();
376         /* mixer should now be on top */
377         WM::Manager::instance().set_transient_for (mixer);
378         _mixer_on_top = true;
379 }
380
381 void
382 ARDOUR_UI::toggle_mixer_window ()
383 {
384         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
385         if (!act) {
386                 return;
387         }
388
389         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
390
391         if (tact->get_active()) {
392                 goto_mixer_window ();
393         } else {
394                 mixer->hide ();
395         }
396 }
397
398 void
399 ARDOUR_UI::toggle_meterbridge ()
400 {
401         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
402         if (!act) {
403                 return;
404         }
405
406         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
407
408         if (tact->get_active()) {
409                 meterbridge->show_window ();
410         } else {
411                 meterbridge->hide_window (NULL);
412         }
413 }
414
415 void
416 ARDOUR_UI::toggle_editor_mixer ()
417 {
418         bool obscuring = false;
419         /* currently, if windows are on different
420            screens then we do nothing; but in the
421            future we may want to bring the window 
422            to the front or something, so I'm leaving this 
423            variable for future use
424         */
425         bool same_screen = true; 
426         
427         if (editor && mixer) {
428
429                 /* remeber: Screen != Monitor (Screen is a separately rendered
430                  * continuous geometry that make include 1 or more monitors.
431                  */
432                 
433                 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
434                         // different screens, so don't do anything
435                         same_screen = false;
436                 } else {
437                         // they are on the same screen, see if they are obscuring each other
438
439                         gint ex, ey, ew, eh;
440                         gint mx, my, mw, mh;
441
442                         editor->get_position (ex, ey);
443                         editor->get_size (ew, eh);
444
445                         mixer->get_position (mx, my);
446                         mixer->get_size (mw, mh);
447
448                         GdkRectangle e;
449                         GdkRectangle m;
450                         GdkRectangle r;
451
452                         e.x = ex;
453                         e.y = ey;
454                         e.width = ew;
455                         e.height = eh;
456
457                         m.x = mx;
458                         m.y = my;
459                         m.width = mw;
460                         m.height = mh;
461
462                         if (gdk_rectangle_intersect (&e, &m, &r)) {
463                                 obscuring = true;
464                         }
465                 }
466         }
467
468         if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
469                 if (obscuring && same_screen) {
470                         goto_editor_window();
471                 }
472         } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
473                 if (obscuring && same_screen) {
474                         goto_mixer_window();
475                 }
476         } else if (mixer && mixer->not_visible()) {
477                 if (obscuring && same_screen) {
478                         goto_mixer_window ();
479                 }
480         } else if (editor && editor->not_visible()) {
481                 if (obscuring && same_screen) {
482                         goto_editor_window ();
483                 }
484         } else if (obscuring && same_screen) {
485                 //it's unclear what to do here, so just do the opposite of what we did last time  (old behavior)
486                 if (_mixer_on_top) {
487                         goto_editor_window ();
488                 } else {
489                         goto_mixer_window ();
490                 }
491         }
492 }
493
494 void
495 ARDOUR_UI::new_midi_tracer_window ()
496 {
497         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
498         if (!act) {
499                 return;
500         }
501
502         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
503         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
504                 ++i;
505         }
506
507         if (i == _midi_tracer_windows.end()) {
508                 /* all our MIDITracer windows are visible; make a new one */
509                 MidiTracer* t = new MidiTracer ();
510                 t->show_all ();
511                 _midi_tracer_windows.push_back (t);
512         } else {
513                 /* re-use the hidden one */
514                 (*i)->show_all ();
515         }
516 }
517
518 BundleManager*
519 ARDOUR_UI::create_bundle_manager ()
520 {
521         return new BundleManager (_session);
522 }
523
524 AddVideoDialog*
525 ARDOUR_UI::create_add_video_dialog ()
526 {
527         return new AddVideoDialog (_session);
528 }
529
530 SessionOptionEditor*
531 ARDOUR_UI::create_session_option_editor ()
532 {
533         return new SessionOptionEditor (_session);
534 }
535
536 BigClockWindow*
537 ARDOUR_UI::create_big_clock_window ()
538 {
539         return new BigClockWindow (*big_clock);
540 }
541
542 void
543 ARDOUR_UI::handle_locations_change (Location *)
544 {
545         if (_session) {
546                 if (_session->locations()->num_range_markers()) {
547                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
548                 } else {
549                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
550                 }
551         }
552 }
553
554 bool
555 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
556 {
557         if (window_was_editor) {
558
559                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
560                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
561                         if (big_clock_window) {
562                                 big_clock_window->set_transient_for (*editor);
563                         }
564                 }
565
566         } else {
567
568                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
569                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
570                         if (big_clock_window) {
571                                 big_clock_window->set_transient_for (*mixer);
572                         }
573                 }
574         }
575
576         return false;
577 }
578
579 bool
580 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
581 {
582         if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
583                 ArdourMeter::ResetAllPeakDisplays ();
584         } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
585                 if (_session->master_out()) {
586                         ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
587                 }
588         } else if (_session->master_out()) {
589                 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
590         }
591         return false;
592 }
593
594 void
595 ARDOUR_UI::toggle_mixer_space()
596 {
597         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
598
599         if (act) {
600                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
601                 if (tact->get_active()) {
602                         mixer->maximise_mixer_space ();
603                 } else {
604                         mixer->restore_mixer_space ();
605                 }
606         }
607 }