2 Copyright (C) 2000 Paul Davis
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.
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.
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.
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.
28 #include "pbd/convert.h"
30 #include "ardour/audioengine.h"
31 #include "ardour/automation_watch.h"
32 #include "ardour/control_protocol_manager.h"
33 #include "ardour/profile.h"
34 #include "ardour/session.h"
36 #include "control_protocol/control_protocol.h"
38 #include "gtkmm2ext/keyboard.h"
39 #include "gtkmm2ext/utils.h"
42 #include "add_route_dialog.h"
43 #include "add_video_dialog.h"
44 #include "ardour_ui.h"
45 #include "big_clock_window.h"
46 #include "bundle_manager.h"
47 #include "global_port_matrix.h"
48 #include "gui_object.h"
49 #include "gui_thread.h"
50 #include "keyeditor.h"
51 #include "location_ui.h"
52 #include "main_clock.h"
53 #include "meterbridge.h"
54 #include "meter_patterns.h"
55 #include "midi_tracer.h"
57 #include "public_editor.h"
58 #include "rc_option_editor.h"
59 #include "route_params_ui.h"
60 #include "shuttle_control.h"
61 #include "session_option_editor.h"
62 #include "speaker_dialog.h"
65 #include "theme_manager.h"
66 #include "time_info_box.h"
71 using namespace ARDOUR;
75 using namespace Gtkmm2ext;
78 ARDOUR_UI::set_session (Session *s)
80 SessionHandlePtr::set_session (s);
83 WM::Manager::instance().set_session (s);
84 /* Session option editor cannot exist across change-of-session */
85 session_option_editor.drop_window ();
86 /* Ditto for AddVideoDialog */
87 add_video_dialog.drop_window ();
91 const XMLNode* node = _session->extra_xml (X_("UI"));
94 const XMLNodeList& children = node->children();
95 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
96 if ((*i)->name() == GUIObjectState::xml_node_name) {
97 gui_object_state->load (**i);
103 WM::Manager::instance().set_session (s);
105 AutomationWatch::instance().set_session (s);
108 shuttle_box->set_session (s);
111 primary_clock->set_session (s);
112 secondary_clock->set_session (s);
113 big_clock->set_session (s);
114 time_info_box->set_session (s);
115 video_timeline->set_session (s);
117 /* sensitize menu bar options that are now valid */
119 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
120 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
122 if (_session->locations()->num_range_markers()) {
123 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
125 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
128 if (!_session->monitor_out()) {
129 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
131 act->set_sensitive (false);
135 /* allow wastebasket flush again */
137 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
139 act->set_sensitive (true);
142 /* there are never any selections on startup */
144 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
145 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
146 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
147 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
148 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
150 rec_button.set_sensitive (true);
152 solo_alert_button.set_active (_session->soloing());
154 setup_session_options ();
156 blink_connection = Timers::blink_connect (sigc::mem_fun(*this, &ARDOUR_UI::blink_handler));
158 _session->SaveSessionRequested.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::save_session_at_its_request, this, _1), gui_context());
159 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
160 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
161 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
162 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dirty_changed, this), gui_context());
164 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
165 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
166 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
167 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
168 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
169 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
171 /* Clocks are on by default after we are connected to a session, so show that here.
174 connect_dependents_to_session (s);
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.
181 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
183 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
187 map_transport_state ();
189 second_connection = Timers::second_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second));
190 point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds));
191 point_zero_something_second_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds));
192 set_fps_timeout_connection();
196 if (meter_box.get_parent()) {
197 transport_hbox.remove (meter_box);
198 transport_hbox.remove (editor_meter_peak_display);
202 meter_box.remove(*editor_meter);
205 editor_meter_peak_display.hide();
208 if (meter_box.get_parent()) {
209 transport_hbox.remove (meter_box);
210 transport_hbox.remove (editor_meter_peak_display);
214 _session->master_out() &&
215 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
217 if (!ARDOUR::Profile->get_trx()) {
218 editor_meter = new LevelMeterHBox(_session);
219 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
220 editor_meter->clear_meters();
221 editor_meter->set_type (_session->master_out()->meter_type());
222 editor_meter->setup_meters (30, 12, 6);
223 editor_meter->show();
224 meter_box.pack_start(*editor_meter);
227 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
228 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
229 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
231 editor_meter_peak_display.set_name ("meterbridge peakindicator");
232 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
233 editor_meter_peak_display.set_size_request (std::max(9.f, rintf(8.f * UIConfiguration::instance().get_ui_scale())), -1);
234 editor_meter_peak_display.set_corner_radius (3.0);
236 editor_meter_max_peak = -INFINITY;
237 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
239 if (UIConfiguration::instance().get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
240 transport_hbox.pack_start (meter_box, false, false);
241 transport_hbox.pack_start (editor_meter_peak_display, false, false);
243 editor_meter_peak_display.show();
251 ARDOUR_UI::unload_session (bool hide_stuff)
254 ARDOUR_UI::instance()->video_timeline->sync_session_state();
257 if (_session && _session->dirty()) {
258 std::vector<std::string> actions;
259 actions.push_back (_("Don't close"));
260 actions.push_back (_("Just close"));
261 actions.push_back (_("Save and close"));
262 switch (ask_about_saving_session (actions)) {
268 _session->save_state ("");
274 // tear down session specific CPI (owned by rc_config_editor which can remain)
275 ControlProtocolManager& m = ControlProtocolManager::instance ();
276 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
277 if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
278 (*i)->protocol->tear_down_gui ();
286 meterbridge->hide ();
287 audio_port_matrix->hide();
288 midi_port_matrix->hide();
289 route_params->hide();
292 second_connection.disconnect ();
293 point_one_second_connection.disconnect ();
294 point_zero_something_second_connection.disconnect();
295 fps_connection.disconnect();
298 meter_box.remove(*editor_meter);
301 editor_meter_peak_display.hide();
304 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
306 rec_button.set_sensitive (false);
308 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
310 if (ARDOUR_UI::instance()->video_timeline) {
311 ARDOUR_UI::instance()->video_timeline->close_session();
316 /* drop everything attached to the blink signal */
318 blink_connection.disconnect ();
323 session_loaded = false;
325 update_buffer_load ();
332 ARDOUR_UI::show_tabbable (Tabbable* t)
342 ARDOUR_UI::hide_tabbable (Tabbable* t)
347 t->make_invisible ();
351 ARDOUR_UI::attach_tabbable (Tabbable* t)
361 ARDOUR_UI::detach_tabbable (Tabbable* t)
370 ARDOUR_UI::tabs_page_added (Widget*,guint)
372 if (_tabs.get_n_pages() > 1) {
374 std::vector<TargetEntry> drag_target_entries;
375 drag_target_entries.push_back (TargetEntry ("tabbable"));
377 editor_visibility_button.drag_source_set (drag_target_entries);
378 mixer_visibility_button.drag_source_set (drag_target_entries);
379 prefs_visibility_button.drag_source_set (drag_target_entries);
381 editor_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (editor->name(),
382 Pango::FontDescription ("Sans 24"),
384 Gdk::Color ("red")));
385 mixer_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (mixer->name(),
386 Pango::FontDescription ("Sans 24"),
388 Gdk::Color ("red")));
389 prefs_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (rc_option_editor->name(),
390 Pango::FontDescription ("Sans 24"),
392 Gdk::Color ("red")));
397 ARDOUR_UI::tabs_page_removed (Widget*, guint)
399 if (_tabs.get_n_pages() < 2) {
400 editor_visibility_button.drag_source_unset ();
401 mixer_visibility_button.drag_source_unset ();
402 prefs_visibility_button.drag_source_unset ();
407 ARDOUR_UI::tabs_switch (GtkNotebookPage*, guint page)
409 if (page == (guint) _tabs.page_num (editor->contents())) {
410 editor_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
411 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
412 mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
414 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
415 prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
417 } else if (page == (guint) _tabs.page_num (mixer->contents())) {
418 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
419 editor_visibility_button.set_active_state (Gtkmm2ext::Off);
421 mixer_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
423 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
424 prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
427 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
428 editor_visibility_button.set_active_state (Gtkmm2ext::Off);
430 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
431 mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
433 prefs_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
439 ARDOUR_UI::tabbable_state_change (Tabbable& t)
441 std::vector<std::string> insensitive_action_names;
442 std::vector<std::string> sensitive_action_names;
443 std::vector<std::string> active_action_names;
444 std::vector<std::string> inactive_action_names;
445 Glib::RefPtr<Action> action;
446 std::string downcased_name = downcase (t.name());
456 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
457 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
458 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
459 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
463 } else if (t.tabbed_by_default ()) {
465 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
466 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
467 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
468 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
472 } else if (t.window_visible()) {
474 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
475 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
476 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
477 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
479 active_action_names.push_back (string_compose ("show-%1", downcased_name));
480 inactive_action_names.push_back (string_compose ("hide-%1", downcased_name));
486 /* not currently visible. allow user to retab it or just make
490 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
491 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
492 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
493 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
495 active_action_names.push_back (string_compose ("hide-%1", downcased_name));
496 inactive_action_names.push_back (string_compose ("show-%1", downcased_name));
501 for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
502 action = ActionManager::get_action (X_("Common"), (*s).c_str());
504 action->set_sensitive (false);
508 for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
509 action = ActionManager::get_action (X_("Common"), (*s).c_str());
511 action->set_sensitive (true);
515 ArdourButton* vis_button = 0;
516 std::vector<ArdourButton*> other_vis_buttons;
519 vis_button = &editor_visibility_button;
520 other_vis_buttons.push_back (&mixer_visibility_button);
521 other_vis_buttons.push_back (&prefs_visibility_button);
522 } else if (&t == mixer) {
523 vis_button = &mixer_visibility_button;
524 other_vis_buttons.push_back (&editor_visibility_button);
525 other_vis_buttons.push_back (&prefs_visibility_button);
527 vis_button = &prefs_visibility_button;
528 other_vis_buttons.push_back (&editor_visibility_button);
529 other_vis_buttons.push_back (&mixer_visibility_button);
538 vis_button->set_active_state (Gtkmm2ext::ImplicitActive);
541 vis_button->set_active_state (Gtkmm2ext::ExplicitActive);
544 vis_button->set_active_state (Gtkmm2ext::Off);
550 ARDOUR_UI::toggle_meterbridge ()
552 assert (editor && mixer && meterbridge);
555 bool obscuring = false;
557 if (meterbridge->not_visible ()) {
559 } else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
560 (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
564 if (obscuring && (editor->own_window()->property_has_toplevel_focus() || (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
569 meterbridge->show_window ();
570 meterbridge->present ();
571 meterbridge->raise ();
573 meterbridge->hide_window (NULL);
578 ARDOUR_UI::new_midi_tracer_window ()
580 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
585 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
586 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
590 if (i == _midi_tracer_windows.end()) {
591 /* all our MIDITracer windows are visible; make a new one */
592 MidiTracer* t = new MidiTracer ();
594 _midi_tracer_windows.push_back (t);
596 /* re-use the hidden one */
602 ARDOUR_UI::create_key_editor ()
604 KeyEditor* kedit = new KeyEditor;
606 if (global_bindings) {
607 kedit->add_tab (_("Global"), *global_bindings);
610 if (editor->bindings) {
611 kedit->add_tab (_("Editing"), *editor->bindings);
614 if (mixer->bindings) {
615 kedit->add_tab (_("Mixing"), *mixer->bindings);
622 ARDOUR_UI::create_bundle_manager ()
624 return new BundleManager (_session);
628 ARDOUR_UI::create_add_video_dialog ()
630 return new AddVideoDialog (_session);
634 ARDOUR_UI::create_session_option_editor ()
636 return new SessionOptionEditor (_session);
640 ARDOUR_UI::create_big_clock_window ()
642 return new BigClockWindow (*big_clock);
646 ARDOUR_UI::handle_locations_change (Location *)
649 if (_session->locations()->num_range_markers()) {
650 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
652 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
658 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
660 if (object == editor) {
662 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
663 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
664 if (big_clock_window) {
665 big_clock_window->set_transient_for (*editor->own_window());
669 } else if (object == mixer) {
671 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
672 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
673 if (big_clock_window) {
674 big_clock_window->set_transient_for (*mixer->own_window());
683 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
685 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
686 ArdourMeter::ResetAllPeakDisplays ();
687 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
688 if (_session->master_out()) {
689 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
691 } else if (_session->master_out()) {
692 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
698 ARDOUR_UI::toggle_mixer_space()
700 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
703 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
704 if (tact->get_active()) {
705 mixer->maximise_mixer_space ();
707 mixer->restore_mixer_space ();
713 ARDOUR_UI::toggle_mixer_list()
715 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMixerList");
718 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
719 mixer->show_mixer_list (tact->get_active());
724 ARDOUR_UI::toggle_monitor_section_visibility ()
726 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
729 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
730 mixer->show_monitor_section (tact->get_active());