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"
35 #include "control_protocol/control_protocol.h"
38 #include "add_route_dialog.h"
39 #include "add_video_dialog.h"
40 #include "ardour_ui.h"
41 #include "big_clock_window.h"
42 #include "bundle_manager.h"
43 #include "global_port_matrix.h"
44 #include "gui_object.h"
45 #include "gui_thread.h"
46 #include "keyeditor.h"
47 #include "location_ui.h"
48 #include "main_clock.h"
49 #include "meterbridge.h"
50 #include "meter_patterns.h"
51 #include "midi_tracer.h"
53 #include "public_editor.h"
54 #include "rc_option_editor.h"
55 #include "route_params_ui.h"
56 #include "shuttle_control.h"
57 #include "session_option_editor.h"
58 #include "speaker_dialog.h"
61 #include "theme_manager.h"
62 #include "time_info_box.h"
65 #include <gtkmm2ext/keyboard.h>
69 using namespace ARDOUR;
73 using namespace Gtkmm2ext;
76 ARDOUR_UI::set_session (Session *s)
78 SessionHandlePtr::set_session (s);
81 WM::Manager::instance().set_session (s);
82 /* Session option editor cannot exist across change-of-session */
83 session_option_editor.drop_window ();
84 /* Ditto for AddVideoDialog */
85 add_video_dialog.drop_window ();
89 const XMLNode* node = _session->extra_xml (X_("UI"));
92 const XMLNodeList& children = node->children();
93 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
94 if ((*i)->name() == GUIObjectState::xml_node_name) {
95 gui_object_state->load (**i);
101 WM::Manager::instance().set_session (s);
103 AutomationWatch::instance().set_session (s);
106 shuttle_box->set_session (s);
109 primary_clock->set_session (s);
110 secondary_clock->set_session (s);
111 big_clock->set_session (s);
112 time_info_box->set_session (s);
113 video_timeline->set_session (s);
115 /* sensitize menu bar options that are now valid */
117 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
118 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
120 if (_session->locations()->num_range_markers()) {
121 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
123 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
126 if (!_session->monitor_out()) {
127 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
129 act->set_sensitive (false);
133 /* allow wastebasket flush again */
135 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
137 act->set_sensitive (true);
140 /* there are never any selections on startup */
142 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
143 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
144 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
145 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
146 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
148 rec_button.set_sensitive (true);
150 solo_alert_button.set_active (_session->soloing());
152 setup_session_options ();
154 blink_connection = Timers::blink_connect (sigc::mem_fun(*this, &ARDOUR_UI::blink_handler));
156 _session->SaveSessionRequested.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::save_session_at_its_request, this, _1), gui_context());
157 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
158 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
159 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
160 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dirty_changed, this), gui_context());
162 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
163 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
164 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
165 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
166 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
167 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
169 /* Clocks are on by default after we are connected to a session, so show that here.
172 connect_dependents_to_session (s);
174 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
175 restore their modes or are explicitly set, we will cause the "new" mode to be saved
176 back to the session XML ("Extra") state.
179 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
181 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
185 map_transport_state ();
187 second_connection = Timers::second_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second));
188 point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds));
189 point_zero_something_second_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds));
190 set_fps_timeout_connection();
194 if (meter_box.get_parent()) {
195 transport_hbox.remove (meter_box);
196 transport_hbox.remove (editor_meter_peak_display);
200 meter_box.remove(*editor_meter);
203 editor_meter_peak_display.hide();
206 if (meter_box.get_parent()) {
207 transport_hbox.remove (meter_box);
208 transport_hbox.remove (editor_meter_peak_display);
212 _session->master_out() &&
213 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
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);
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));
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 (std::max(9.f, rintf(8.f * UIConfiguration::instance().get_ui_scale())), -1);
232 editor_meter_peak_display.set_corner_radius (3.0);
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);
237 if (UIConfiguration::instance().get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
238 transport_hbox.pack_start (meter_box, false, false);
239 transport_hbox.pack_start (editor_meter_peak_display, false, false);
241 editor_meter_peak_display.show();
249 ARDOUR_UI::unload_session (bool hide_stuff)
252 ARDOUR_UI::instance()->video_timeline->sync_session_state();
255 if (_session && _session->dirty()) {
256 std::vector<std::string> actions;
257 actions.push_back (_("Don't close"));
258 actions.push_back (_("Just close"));
259 actions.push_back (_("Save and close"));
260 switch (ask_about_saving_session (actions)) {
266 _session->save_state ("");
272 // tear down session specific CPI (owned by rc_config_editor which can remain)
273 ControlProtocolManager& m = ControlProtocolManager::instance ();
274 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
275 if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
276 (*i)->protocol->tear_down_gui ();
284 meterbridge->hide ();
285 audio_port_matrix->hide();
286 midi_port_matrix->hide();
287 route_params->hide();
290 second_connection.disconnect ();
291 point_one_second_connection.disconnect ();
292 point_zero_something_second_connection.disconnect();
293 fps_connection.disconnect();
296 meter_box.remove(*editor_meter);
299 editor_meter_peak_display.hide();
302 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
304 rec_button.set_sensitive (false);
306 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
308 if (ARDOUR_UI::instance()->video_timeline) {
309 ARDOUR_UI::instance()->video_timeline->close_session();
314 /* drop everything attached to the blink signal */
316 blink_connection.disconnect ();
321 session_loaded = false;
323 update_buffer_load ();
330 ARDOUR_UI::show_tabbable (Tabbable* t)
340 ARDOUR_UI::hide_tabbable (Tabbable* t)
345 t->make_invisible ();
349 ARDOUR_UI::attach_tabbable (Tabbable* t)
359 ARDOUR_UI::detach_tabbable (Tabbable* t)
368 ARDOUR_UI::tabs_switch (GtkNotebookPage*, guint page)
370 if (page == (guint) _tabs.page_num (editor->contents())) {
371 editor_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
372 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
373 mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
375 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
376 prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
378 } else if (page == (guint) _tabs.page_num (mixer->contents())) {
379 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
380 editor_visibility_button.set_active_state (Gtkmm2ext::Off);
382 mixer_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
384 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
385 prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
388 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
389 editor_visibility_button.set_active_state (Gtkmm2ext::Off);
391 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
392 mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
394 prefs_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
400 ARDOUR_UI::tabbable_state_change (Tabbable& t)
402 std::vector<std::string> insensitive_action_names;
403 std::vector<std::string> sensitive_action_names;
404 std::vector<std::string> active_action_names;
405 std::vector<std::string> inactive_action_names;
406 Glib::RefPtr<Action> action;
407 std::string downcased_name = downcase (t.name());
417 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
418 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
419 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
420 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
424 } else if (t.tabbed_by_default ()) {
426 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
427 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
428 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
429 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
433 } else if (t.window_visible()) {
435 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
436 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
437 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
438 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
440 active_action_names.push_back (string_compose ("show-%1", downcased_name));
441 inactive_action_names.push_back (string_compose ("hide-%1", downcased_name));
447 /* not currently visible. allow user to retab it or just make
451 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
452 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
453 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
454 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
456 active_action_names.push_back (string_compose ("hide-%1", downcased_name));
457 inactive_action_names.push_back (string_compose ("show-%1", downcased_name));
462 for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
463 action = ActionManager::get_action (X_("Common"), (*s).c_str());
465 action->set_sensitive (false);
469 for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
470 action = ActionManager::get_action (X_("Common"), (*s).c_str());
472 action->set_sensitive (true);
476 ArdourButton* vis_button = 0;
477 std::vector<ArdourButton*> other_vis_buttons;
480 vis_button = &editor_visibility_button;
481 other_vis_buttons.push_back (&mixer_visibility_button);
482 other_vis_buttons.push_back (&prefs_visibility_button);
483 } else if (&t == mixer) {
484 vis_button = &mixer_visibility_button;
485 other_vis_buttons.push_back (&editor_visibility_button);
486 other_vis_buttons.push_back (&prefs_visibility_button);
488 vis_button = &prefs_visibility_button;
489 other_vis_buttons.push_back (&editor_visibility_button);
490 other_vis_buttons.push_back (&mixer_visibility_button);
499 vis_button->set_active_state (Gtkmm2ext::ImplicitActive);
502 vis_button->set_active_state (Gtkmm2ext::ExplicitActive);
505 vis_button->set_active_state (Gtkmm2ext::Off);
511 ARDOUR_UI::toggle_meterbridge ()
513 assert (editor && mixer && meterbridge);
516 bool obscuring = false;
518 if (meterbridge->not_visible ()) {
520 } else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
521 (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
525 if (obscuring && (editor->own_window()->property_has_toplevel_focus() || (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
530 meterbridge->show_window ();
531 meterbridge->present ();
532 meterbridge->raise ();
534 meterbridge->hide_window (NULL);
539 ARDOUR_UI::new_midi_tracer_window ()
541 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
546 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
547 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
551 if (i == _midi_tracer_windows.end()) {
552 /* all our MIDITracer windows are visible; make a new one */
553 MidiTracer* t = new MidiTracer ();
555 _midi_tracer_windows.push_back (t);
557 /* re-use the hidden one */
563 ARDOUR_UI::create_key_editor ()
565 KeyEditor* kedit = new KeyEditor;
567 if (global_bindings) {
568 kedit->add_tab (_("Global"), *global_bindings);
571 if (editor->bindings) {
572 kedit->add_tab (_("Editing"), *editor->bindings);
575 if (mixer->bindings) {
576 kedit->add_tab (_("Mixing"), *mixer->bindings);
583 ARDOUR_UI::create_bundle_manager ()
585 return new BundleManager (_session);
589 ARDOUR_UI::create_add_video_dialog ()
591 return new AddVideoDialog (_session);
595 ARDOUR_UI::create_session_option_editor ()
597 return new SessionOptionEditor (_session);
601 ARDOUR_UI::create_big_clock_window ()
603 return new BigClockWindow (*big_clock);
607 ARDOUR_UI::handle_locations_change (Location *)
610 if (_session->locations()->num_range_markers()) {
611 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
613 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
619 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
621 if (object == editor) {
623 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
624 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
625 if (big_clock_window) {
626 big_clock_window->set_transient_for (*editor->own_window());
630 } else if (object == mixer) {
632 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
633 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
634 if (big_clock_window) {
635 big_clock_window->set_transient_for (*mixer->own_window());
644 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
646 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
647 ArdourMeter::ResetAllPeakDisplays ();
648 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
649 if (_session->master_out()) {
650 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
652 } else if (_session->master_out()) {
653 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
659 ARDOUR_UI::toggle_mixer_space()
661 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
664 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
665 if (tact->get_active()) {
666 mixer->maximise_mixer_space ();
668 mixer->restore_mixer_space ();
674 ARDOUR_UI::toggle_mixer_list()
676 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMixerList");
679 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
680 mixer->show_mixer_list (tact->get_active());
685 ARDOUR_UI::toggle_monitor_section_visibility ()
687 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
690 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
691 mixer->show_monitor_section (tact->get_active());