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::tabbable_state_change (Tabbable& t)
370 std::vector<std::string> insensitive_action_names;
371 std::vector<std::string> sensitive_action_names;
372 Glib::RefPtr<Action> action;
373 std::string downcased_name = downcase (t.name());
377 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
378 insensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
379 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
380 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
382 } else if (t.tabbed_by_default ()) {
384 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
385 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
386 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
387 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
389 } else if (t.window_visible()) {
391 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
392 insensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
393 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
394 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
398 /* not currently visible. allow user to retab it or just make
402 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
403 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
404 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
405 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
409 for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
410 action = ActionManager::get_action (X_("Common"), (*s).c_str());
412 action->set_sensitive (false);
416 for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
417 action = ActionManager::get_action (X_("Common"), (*s).c_str());
419 action->set_sensitive (true);
425 ARDOUR_UI::toggle_meterbridge ()
427 assert (editor && mixer && meterbridge);
430 bool obscuring = false;
432 if (meterbridge->not_visible ()) {
434 } else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
435 (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
439 if (obscuring && (editor->own_window()->property_has_toplevel_focus() || (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
444 meterbridge->show_window ();
445 meterbridge->present ();
446 meterbridge->raise ();
448 meterbridge->hide_window (NULL);
453 ARDOUR_UI::new_midi_tracer_window ()
455 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
460 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
461 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
465 if (i == _midi_tracer_windows.end()) {
466 /* all our MIDITracer windows are visible; make a new one */
467 MidiTracer* t = new MidiTracer ();
469 _midi_tracer_windows.push_back (t);
471 /* re-use the hidden one */
477 ARDOUR_UI::create_bundle_manager ()
479 return new BundleManager (_session);
483 ARDOUR_UI::create_add_video_dialog ()
485 return new AddVideoDialog (_session);
489 ARDOUR_UI::create_session_option_editor ()
491 return new SessionOptionEditor (_session);
495 ARDOUR_UI::create_big_clock_window ()
497 return new BigClockWindow (*big_clock);
501 ARDOUR_UI::handle_locations_change (Location *)
504 if (_session->locations()->num_range_markers()) {
505 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
507 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
513 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
515 if (object == editor) {
517 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
518 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
519 if (big_clock_window) {
520 big_clock_window->set_transient_for (*editor->own_window());
524 } else if (object == mixer) {
526 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
527 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
528 if (big_clock_window) {
529 big_clock_window->set_transient_for (*mixer->own_window());
538 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
540 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
541 ArdourMeter::ResetAllPeakDisplays ();
542 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
543 if (_session->master_out()) {
544 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
546 } else if (_session->master_out()) {
547 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
553 ARDOUR_UI::toggle_mixer_space()
555 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
558 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
559 if (tact->get_active()) {
560 mixer->maximise_mixer_space ();
562 mixer->restore_mixer_space ();
568 ARDOUR_UI::toggle_mixer_list()
570 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMixerList");
573 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
574 mixer->show_mixer_list (tact->get_active());
579 ARDOUR_UI::toggle_monitor_section_visibility ()
581 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
584 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
585 mixer->show_monitor_section (tact->get_active());