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_tearoff_hbox.remove (meter_box);
196 transport_tearoff_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_tearoff_hbox.remove (meter_box);
208 transport_tearoff_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_tearoff_hbox.pack_start (meter_box, false, false);
239 transport_tearoff_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));
383 } else if (t.window_visible()) {
385 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
386 insensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
387 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
388 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
392 /* not currently visible. allow user to retab it or just make
396 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
397 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
398 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
399 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
403 for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
404 action = ActionManager::get_action (X_("Common"), (*s).c_str());
406 action->set_sensitive (false);
410 for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
411 action = ActionManager::get_action (X_("Common"), (*s).c_str());
413 action->set_sensitive (true);
419 ARDOUR_UI::toggle_meterbridge ()
421 assert (editor && mixer && meterbridge);
424 bool obscuring = false;
426 if (meterbridge->not_visible ()) {
428 } else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
429 (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
433 if (obscuring && (editor->own_window()->property_has_toplevel_focus() || (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
438 meterbridge->show_window ();
439 meterbridge->present ();
440 meterbridge->raise ();
442 meterbridge->hide_window (NULL);
447 ARDOUR_UI::new_midi_tracer_window ()
449 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
454 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
455 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
459 if (i == _midi_tracer_windows.end()) {
460 /* all our MIDITracer windows are visible; make a new one */
461 MidiTracer* t = new MidiTracer ();
463 _midi_tracer_windows.push_back (t);
465 /* re-use the hidden one */
471 ARDOUR_UI::create_bundle_manager ()
473 return new BundleManager (_session);
477 ARDOUR_UI::create_add_video_dialog ()
479 return new AddVideoDialog (_session);
483 ARDOUR_UI::create_session_option_editor ()
485 return new SessionOptionEditor (_session);
489 ARDOUR_UI::create_big_clock_window ()
491 return new BigClockWindow (*big_clock);
495 ARDOUR_UI::handle_locations_change (Location *)
498 if (_session->locations()->num_range_markers()) {
499 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
501 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
507 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
509 if (object == editor) {
511 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
512 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
513 if (big_clock_window) {
514 big_clock_window->set_transient_for (*editor->own_window());
518 } else if (object == mixer) {
520 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
521 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
522 if (big_clock_window) {
523 big_clock_window->set_transient_for (*mixer->own_window());
532 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
534 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
535 ArdourMeter::ResetAllPeakDisplays ();
536 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
537 if (_session->master_out()) {
538 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
540 } else if (_session->master_out()) {
541 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
547 ARDOUR_UI::toggle_mixer_space()
549 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
552 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
553 if (tact->get_active()) {
554 mixer->maximise_mixer_space ();
556 mixer->restore_mixer_space ();
562 ARDOUR_UI::toggle_mixer_list()
564 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMixerList");
567 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
568 mixer->show_mixer_list (tact->get_active());
573 ARDOUR_UI::toggle_monitor_section_visibility ()
575 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
578 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
579 mixer->show_monitor_section (tact->get_active());