2 Copyright (C) 2000-2009 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.
27 #include "ardour/session.h"
31 #include "ardour_ui.h"
32 #include "audio_time_axis.h"
33 #include "midi_time_axis.h"
34 #include "mixer_strip.h"
35 #include "gui_thread.h"
38 #include "editor_group_tabs.h"
39 #include "editor_routes.h"
41 #include "pbd/unknown_type.h"
43 #include "ardour/route.h"
44 #include "ardour/midi_track.h"
46 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
47 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
48 #include "gtkmm2ext/treeutils.h"
53 using namespace ARDOUR
;
56 using namespace Gtkmm2ext
;
58 using Gtkmm2ext::Keyboard
;
60 EditorRoutes::EditorRoutes (Editor
* e
)
62 , _ignore_reorder (false)
63 , _no_redisplay (false)
64 , _redisplay_does_not_sync_order_keys (false)
65 , _redisplay_does_not_reset_order_keys (false)
68 , selection_countdown (0)
71 static const int column_width
= 22;
73 _scroller
.add (_display
);
74 _scroller
.set_policy (POLICY_NEVER
, POLICY_AUTOMATIC
);
76 _model
= ListStore::create (_columns
);
77 _display
.set_model (_model
);
79 // Record enable toggle
80 CellRendererPixbufMulti
* rec_col_renderer
= manage (new CellRendererPixbufMulti());
82 rec_col_renderer
->set_pixbuf (0, ::get_icon("act-disabled"));
83 rec_col_renderer
->set_pixbuf (1, ::get_icon("rec-in-progress"));
84 rec_col_renderer
->set_pixbuf (2, ::get_icon("rec-enabled"));
85 rec_col_renderer
->set_pixbuf (3, ::get_icon("step-editing"));
86 rec_col_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed
));
88 TreeViewColumn
* rec_state_column
= manage (new TreeViewColumn("R", *rec_col_renderer
));
90 rec_state_column
->add_attribute(rec_col_renderer
->property_state(), _columns
.rec_state
);
91 rec_state_column
->add_attribute(rec_col_renderer
->property_visible(), _columns
.is_track
);
93 rec_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
94 rec_state_column
->set_alignment(ALIGN_CENTER
);
95 rec_state_column
->set_expand(false);
96 rec_state_column
->set_fixed_width(column_width
);
100 CellRendererPixbufMulti
* input_active_col_renderer
= manage (new CellRendererPixbufMulti());
101 input_active_col_renderer
->set_pixbuf (0, ::get_icon("act-disabled"));
102 input_active_col_renderer
->set_pixbuf (1, ::get_icon("midi-input-active"));
103 input_active_col_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed
));
105 TreeViewColumn
* input_active_column
= manage (new TreeViewColumn ("I", *input_active_col_renderer
));
107 input_active_column
->add_attribute(input_active_col_renderer
->property_state(), _columns
.is_input_active
);
108 input_active_column
->add_attribute (input_active_col_renderer
->property_visible(), _columns
.is_midi
);
110 input_active_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
111 input_active_column
->set_alignment(ALIGN_CENTER
);
112 input_active_column
->set_expand(false);
113 input_active_column
->set_fixed_width(column_width
);
115 // Mute enable toggle
116 CellRendererPixbufMulti
* mute_col_renderer
= manage (new CellRendererPixbufMulti());
118 mute_col_renderer
->set_pixbuf (0, ::get_icon("mute-disabled"));
119 mute_col_renderer
->set_pixbuf (1, ::get_icon("muted-by-others"));
120 mute_col_renderer
->set_pixbuf (2, ::get_icon("mute-enabled"));
121 mute_col_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled
));
123 TreeViewColumn
* mute_state_column
= manage (new TreeViewColumn("M", *mute_col_renderer
));
125 mute_state_column
->add_attribute(mute_col_renderer
->property_state(), _columns
.mute_state
);
126 mute_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
127 mute_state_column
->set_alignment(ALIGN_CENTER
);
128 mute_state_column
->set_expand(false);
129 mute_state_column
->set_fixed_width(15);
131 // Solo enable toggle
132 CellRendererPixbufMulti
* solo_col_renderer
= manage (new CellRendererPixbufMulti());
134 solo_col_renderer
->set_pixbuf (0, ::get_icon("solo-disabled"));
135 solo_col_renderer
->set_pixbuf (1, ::get_icon("solo-enabled"));
136 solo_col_renderer
->set_pixbuf (3, ::get_icon("soloed-by-others"));
137 solo_col_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled
));
139 TreeViewColumn
* solo_state_column
= manage (new TreeViewColumn("S", *solo_col_renderer
));
141 solo_state_column
->add_attribute(solo_col_renderer
->property_state(), _columns
.solo_state
);
142 solo_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
143 solo_state_column
->set_alignment(ALIGN_CENTER
);
144 solo_state_column
->set_expand(false);
145 solo_state_column
->set_fixed_width(column_width
);
147 // Solo isolate toggle
148 CellRendererPixbufMulti
* solo_iso_renderer
= manage (new CellRendererPixbufMulti());
150 solo_iso_renderer
->set_pixbuf (0, ::get_icon("solo-isolate-disabled"));
151 solo_iso_renderer
->set_pixbuf (1, ::get_icon("solo-isolate-enabled"));
152 solo_iso_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled
));
154 TreeViewColumn
* solo_isolate_state_column
= manage (new TreeViewColumn("SI", *solo_iso_renderer
));
156 solo_isolate_state_column
->add_attribute(solo_iso_renderer
->property_state(), _columns
.solo_isolate_state
);
157 solo_isolate_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
158 solo_isolate_state_column
->set_alignment(ALIGN_CENTER
);
159 solo_isolate_state_column
->set_expand(false);
160 solo_isolate_state_column
->set_fixed_width(column_width
);
163 CellRendererPixbufMulti
* solo_safe_renderer
= manage (new CellRendererPixbufMulti ());
165 solo_safe_renderer
->set_pixbuf (0, ::get_icon("solo-safe-disabled"));
166 solo_safe_renderer
->set_pixbuf (1, ::get_icon("solo-safe-enabled"));
167 solo_safe_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled
));
169 TreeViewColumn
* solo_safe_state_column
= manage (new TreeViewColumn(_("SS"), *solo_safe_renderer
));
170 solo_safe_state_column
->add_attribute(solo_safe_renderer
->property_state(), _columns
.solo_safe_state
);
171 solo_safe_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
172 solo_safe_state_column
->set_alignment(ALIGN_CENTER
);
173 solo_safe_state_column
->set_expand(false);
174 solo_safe_state_column
->set_fixed_width(column_width
);
176 _display
.append_column (*input_active_column
);
177 _display
.append_column (*rec_state_column
);
178 _display
.append_column (*mute_state_column
);
179 _display
.append_column (*solo_state_column
);
180 _display
.append_column (*solo_isolate_state_column
);
181 _display
.append_column (*solo_safe_state_column
);
183 _name_column
= _display
.append_column (_("Name"), _columns
.text
) - 1;
184 _visible_column
= _display
.append_column (_("V"), _columns
.visible
) - 1;
186 _display
.set_headers_visible (true);
187 _display
.set_name ("TrackListDisplay");
188 _display
.get_selection()->set_mode (SELECTION_SINGLE
);
189 _display
.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter
));
190 _display
.set_reorderable (true);
191 _display
.set_rules_hint (true);
192 _display
.set_size_request (100, -1);
193 _display
.add_object_drag (_columns
.route
.index(), "routes");
195 CellRendererText
* name_cell
= dynamic_cast<CellRendererText
*> (_display
.get_column_cell_renderer (_name_column
));
198 name_cell
->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started
));
200 TreeViewColumn
* name_column
= _display
.get_column (_name_column
);
202 assert (name_column
);
204 name_column
->add_attribute (name_cell
->property_editable(), _columns
.name_editable
);
205 name_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
206 name_column
->set_expand(true);
207 name_column
->set_min_width(50);
209 name_cell
->property_editable() = true;
210 name_cell
->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit
));
212 // Set the visible column cell renderer to radio toggle
213 CellRendererToggle
* visible_cell
= dynamic_cast<CellRendererToggle
*> (_display
.get_column_cell_renderer (_visible_column
));
215 visible_cell
->property_activatable() = true;
216 visible_cell
->property_radio() = false;
217 visible_cell
->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed
));
219 TreeViewColumn
* visible_col
= dynamic_cast<TreeViewColumn
*> (_display
.get_column (_visible_column
));
220 visible_col
->set_expand(false);
221 visible_col
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
222 visible_col
->set_fixed_width(30);
223 visible_col
->set_alignment(ALIGN_CENTER
);
225 _model
->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted
));
226 _model
->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered
));
228 _display
.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press
), false);
229 _scroller
.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press
), false);
231 _scroller
.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in
), false);
232 _scroller
.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out
));
234 _display
.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify
), false);
235 _display
.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify
), false);
237 _display
.set_enable_search (false);
239 Route::SyncOrderKeys
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::sync_order_keys
, this, _1
), gui_context());
243 EditorRoutes::focus_in (GdkEventFocus
*)
245 Window
* win
= dynamic_cast<Window
*> (_scroller
.get_toplevel ());
248 old_focus
= win
->get_focus ();
255 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
260 EditorRoutes::focus_out (GdkEventFocus
*)
263 old_focus
->grab_focus ();
271 EditorRoutes::enter_notify (GdkEventCrossing
*)
277 /* arm counter so that ::selection_filter() will deny selecting anything for the
278 next two attempts to change selection status.
280 selection_countdown
= 2;
281 _scroller
.grab_focus ();
282 Keyboard::magic_widget_grab_focus ();
287 EditorRoutes::leave_notify (GdkEventCrossing
*)
289 selection_countdown
= 0;
292 old_focus
->grab_focus ();
296 Keyboard::magic_widget_drop_focus ();
301 EditorRoutes::set_session (Session
* s
)
303 SessionHandlePtr::set_session (s
);
308 _session
->SoloChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::solo_changed_so_update_mute
, this), gui_context());
309 _session
->RecordStateChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_rec_display
, this), gui_context());
314 EditorRoutes::on_input_active_changed (std::string
const & path_string
)
316 // Get the model row that has been toggled.
317 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
319 TimeAxisView
* tv
= row
[_columns
.tv
];
320 RouteTimeAxisView
*rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
323 boost::shared_ptr
<MidiTrack
> mt
;
324 mt
= rtv
->midi_track();
326 mt
->set_input_active (!mt
->input_active());
332 EditorRoutes::on_tv_rec_enable_changed (std::string
const & path_string
)
334 // Get the model row that has been toggled.
335 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
337 TimeAxisView
* tv
= row
[_columns
.tv
];
338 RouteTimeAxisView
*rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
340 if (rtv
&& rtv
->track()) {
341 boost::shared_ptr
<RouteList
> rl (new RouteList
);
342 rl
->push_back (rtv
->route());
343 _session
->set_record_enabled (rl
, !rtv
->track()->record_enabled(), Session::rt_cleanup
);
348 EditorRoutes::on_tv_mute_enable_toggled (std::string
const & path_string
)
350 // Get the model row that has been toggled.
351 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
353 TimeAxisView
*tv
= row
[_columns
.tv
];
354 RouteTimeAxisView
*rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
357 boost::shared_ptr
<RouteList
> rl (new RouteList
);
358 rl
->push_back (rtv
->route());
359 _session
->set_mute (rl
, !rtv
->route()->muted(), Session::rt_cleanup
);
364 EditorRoutes::on_tv_solo_enable_toggled (std::string
const & path_string
)
366 // Get the model row that has been toggled.
367 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
369 TimeAxisView
*tv
= row
[_columns
.tv
];
370 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
373 boost::shared_ptr
<RouteList
> rl (new RouteList
);
374 rl
->push_back (rtv
->route());
375 if (Config
->get_solo_control_is_listen_control()) {
376 _session
->set_listen (rl
, !rtv
->route()->listening_via_monitor(), Session::rt_cleanup
);
378 _session
->set_solo (rl
, !rtv
->route()->self_soloed(), Session::rt_cleanup
);
384 EditorRoutes::on_tv_solo_isolate_toggled (std::string
const & path_string
)
386 // Get the model row that has been toggled.
387 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
389 TimeAxisView
*tv
= row
[_columns
.tv
];
390 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
393 rtv
->route()->set_solo_isolated (!rtv
->route()->solo_isolated(), this);
398 EditorRoutes::on_tv_solo_safe_toggled (std::string
const & path_string
)
400 // Get the model row that has been toggled.
401 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
403 TimeAxisView
*tv
= row
[_columns
.tv
];
404 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
407 rtv
->route()->set_solo_safe (!rtv
->route()->solo_safe(), this);
412 EditorRoutes::build_menu ()
414 using namespace Menu_Helpers
;
419 MenuList
& items
= _menu
->items();
420 _menu
->set_name ("ArdourContextMenu");
422 items
.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes
)));
423 items
.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes
)));
424 items
.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks
)));
425 items
.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks
)));
426 items
.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus
)));
427 items
.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus
)));
428 items
.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks
)));
429 items
.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks
)));
430 items
.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead
)));
434 EditorRoutes::show_menu ()
440 _menu
->popup (1, gtk_get_current_event_time());
444 EditorRoutes::redisplay ()
446 if (_no_redisplay
|| !_session
) {
450 TreeModel::Children rows
= _model
->children();
451 TreeModel::Children::iterator i
;
455 for (n
= 0, position
= 0, i
= rows
.begin(); i
!= rows
.end(); ++i
) {
456 TimeAxisView
*tv
= (*i
)[_columns
.tv
];
457 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
460 // just a "title" row
464 if (!_redisplay_does_not_reset_order_keys
) {
465 /* this reorder is caused by user action, so reassign sort order keys
468 route
->set_order_key (N_ ("editor"), n
);
471 bool visible
= (*i
)[_columns
.visible
];
473 /* show or hide the TimeAxisView */
475 tv
->set_marked_for_display (true);
476 position
+= tv
->show_at (position
, n
, &_editor
->edit_controls_vbox
);
477 tv
->clip_to_viewport ();
479 tv
->set_visibility (false);
486 /* whenever we go idle, update the track view list to reflect the new order.
487 we can't do this here, because we could mess up something that is traversing
488 the track order and has caused a redisplay of the list.
490 Glib::signal_idle().connect (sigc::mem_fun (*_editor
, &Editor::sync_track_view_list_and_routes
));
492 _editor
->reset_controls_layout_height (position
);
493 _editor
->reset_controls_layout_width ();
494 _editor
->full_canvas_height
= position
+ _editor
->canvas_timebars_vsize
;
495 _editor
->vertical_adjustment
.set_upper (_editor
->full_canvas_height
);
497 if ((_editor
->vertical_adjustment
.get_value() + _editor
->_canvas_height
) > _editor
->vertical_adjustment
.get_upper()) {
499 We're increasing the size of the canvas while the bottom is visible.
500 We scroll down to keep in step with the controls layout.
502 _editor
->vertical_adjustment
.set_value (_editor
->full_canvas_height
- _editor
->_canvas_height
);
505 if (!_redisplay_does_not_reset_order_keys
&& !_redisplay_does_not_sync_order_keys
) {
506 _session
->sync_order_keys (N_ ("editor"));
511 EditorRoutes::route_deleted (Gtk::TreeModel::Path
const &)
513 if (!_session
|| _session
->deletion_in_progress()) {
517 /* this could require an order reset & sync */
518 _session
->set_remote_control_ids();
519 _ignore_reorder
= true;
521 _ignore_reorder
= false;
525 EditorRoutes::visible_changed (std::string
const & path
)
527 if (_session
&& _session
->deletion_in_progress()) {
533 if ((iter
= _model
->get_iter (path
))) {
534 TimeAxisView
* tv
= (*iter
)[_columns
.tv
];
536 bool visible
= (*iter
)[_columns
.visible
];
537 (*iter
)[_columns
.visible
] = !visible
;
541 _redisplay_does_not_reset_order_keys
= true;
542 _session
->set_remote_control_ids();
544 _redisplay_does_not_reset_order_keys
= false;
548 EditorRoutes::routes_added (list
<RouteTimeAxisView
*> routes
)
552 _redisplay_does_not_sync_order_keys
= true;
553 suspend_redisplay ();
555 for (list
<RouteTimeAxisView
*>::iterator x
= routes
.begin(); x
!= routes
.end(); ++x
) {
557 boost::shared_ptr
<MidiTrack
> midi_trk
= boost::dynamic_pointer_cast
<MidiTrack
> ((*x
)->route());
559 row
= *(_model
->append ());
561 row
[_columns
.text
] = (*x
)->route()->name();
562 row
[_columns
.visible
] = (*x
)->marked_for_display();
563 row
[_columns
.tv
] = *x
;
564 row
[_columns
.route
] = (*x
)->route ();
565 row
[_columns
.is_track
] = (boost::dynamic_pointer_cast
<Track
> ((*x
)->route()) != 0);
568 row
[_columns
.is_input_active
] = midi_trk
->input_active ();
569 row
[_columns
.is_midi
] = true;
571 row
[_columns
.is_input_active
] = false;
572 row
[_columns
.is_midi
] = false;
575 row
[_columns
.mute_state
] = (*x
)->route()->muted();
576 row
[_columns
.solo_state
] = RouteUI::solo_visual_state ((*x
)->route());
577 row
[_columns
.solo_isolate_state
] = (*x
)->route()->solo_isolated();
578 row
[_columns
.solo_safe_state
] = (*x
)->route()->solo_safe();
579 row
[_columns
.name_editable
] = true;
581 _ignore_reorder
= true;
583 /* added a new fresh one at the end */
584 if ((*x
)->route()->order_key (N_ ("editor")) == -1) {
585 (*x
)->route()->set_order_key (N_ ("editor"), _model
->children().size()-1);
588 _ignore_reorder
= false;
590 boost::weak_ptr
<Route
> wr ((*x
)->route());
592 (*x
)->route()->gui_changed
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::handle_gui_changes
, this, _1
, _2
), gui_context());
593 (*x
)->route()->PropertyChanged
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::route_property_changed
, this, _1
, wr
), gui_context());
595 if ((*x
)->is_track()) {
596 boost::shared_ptr
<Track
> t
= boost::dynamic_pointer_cast
<Track
> ((*x
)->route());
597 t
->RecordEnableChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_rec_display
, this), gui_context());
600 if ((*x
)->is_midi_track()) {
601 boost::shared_ptr
<MidiTrack
> t
= boost::dynamic_pointer_cast
<MidiTrack
> ((*x
)->route());
602 t
->StepEditStatusChange
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_rec_display
, this), gui_context());
603 t
->InputActiveChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_input_active_display
, this), gui_context());
606 (*x
)->route()->mute_changed
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_mute_display
, this), gui_context());
607 (*x
)->route()->solo_changed
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::update_solo_display
, this, _1
), gui_context());
608 (*x
)->route()->listen_changed
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::update_solo_display
, this, _1
), gui_context());
609 (*x
)->route()->solo_isolated_changed
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_solo_isolate_display
, this), gui_context());
610 (*x
)->route()->solo_safe_changed
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_solo_safe_display
, this), gui_context());
613 update_rec_display ();
614 update_mute_display ();
615 update_solo_display (true);
616 update_solo_isolate_display ();
617 update_solo_safe_display ();
618 update_input_active_display ();
620 _redisplay_does_not_sync_order_keys
= false;
624 EditorRoutes::handle_gui_changes (string
const & what
, void*)
626 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes
, what
, src
)
628 if (what
== "track_height") {
629 /* Optional :make tracks change height while it happens, instead
632 //update_canvas_now ();
636 if (what
== "visible_tracks") {
642 EditorRoutes::route_removed (TimeAxisView
*tv
)
644 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed
, tv
)
646 TreeModel::Children rows
= _model
->children();
647 TreeModel::Children::iterator ri
;
649 /* the core model has changed, there is no need to sync
653 _redisplay_does_not_sync_order_keys
= true;
655 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
656 if ((*ri
)[_columns
.tv
] == tv
) {
662 _redisplay_does_not_sync_order_keys
= false;
666 EditorRoutes::route_property_changed (const PropertyChange
& what_changed
, boost::weak_ptr
<Route
> r
)
668 if (!what_changed
.contains (ARDOUR::Properties::name
)) {
672 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed
, r
)
674 boost::shared_ptr
<Route
> route
= r
.lock ();
680 TreeModel::Children rows
= _model
->children();
681 TreeModel::Children::iterator i
;
683 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
684 boost::shared_ptr
<Route
> t
= (*i
)[_columns
.route
];
686 (*i
)[_columns
.text
] = route
->name();
693 EditorRoutes::update_visibility ()
695 TreeModel::Children rows
= _model
->children();
696 TreeModel::Children::iterator i
;
698 suspend_redisplay ();
700 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
701 TimeAxisView
*tv
= (*i
)[_columns
.tv
];
702 (*i
)[_columns
.visible
] = tv
->marked_for_display ();
703 cerr
<< "marked " << tv
->name() << " for display = " << tv
->marked_for_display() << endl
;
710 EditorRoutes::hide_track_in_display (TimeAxisView
& tv
)
712 TreeModel::Children rows
= _model
->children();
713 TreeModel::Children::iterator i
;
715 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
716 if ((*i
)[_columns
.tv
] == &tv
) {
717 (*i
)[_columns
.visible
] = false;
726 EditorRoutes::show_track_in_display (TimeAxisView
& tv
)
728 TreeModel::Children rows
= _model
->children();
729 TreeModel::Children::iterator i
;
731 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
732 if ((*i
)[_columns
.tv
] == &tv
) {
733 (*i
)[_columns
.visible
] = true;
742 EditorRoutes::reordered (TreeModel::Path
const &, TreeModel::iterator
const &, int* /*what*/)
747 /** If src != "editor", take editor order keys from each route and use them to rearrange the
748 * route list so that the visual arrangement of routes matches the order keys from the routes.
751 EditorRoutes::sync_order_keys (string
const & src
)
753 map
<int, int> new_order
;
754 TreeModel::Children rows
= _model
->children();
755 TreeModel::Children::iterator ri
;
757 if (src
== N_ ("editor") || !_session
|| (_session
->state_of_the_state() & (Session::Loading
|Session::Deletion
)) || rows
.empty()) {
761 bool changed
= false;
764 for (order
= 0, ri
= rows
.begin(); ri
!= rows
.end(); ++ri
, ++order
) {
765 boost::shared_ptr
<Route
> route
= (*ri
)[_columns
.route
];
767 int const old_key
= order
;
768 int const new_key
= route
->order_key (N_ ("editor"));
770 new_order
[new_key
] = old_key
;
772 if (new_key
!= old_key
) {
778 _redisplay_does_not_reset_order_keys
= true;
780 /* `compact' new_order into a vector */
782 for (map
<int, int>::const_iterator i
= new_order
.begin(); i
!= new_order
.end(); ++i
) {
783 co
.push_back (i
->second
);
786 _model
->reorder (co
);
787 _redisplay_does_not_reset_order_keys
= false;
793 EditorRoutes::hide_all_tracks (bool /*with_select*/)
795 TreeModel::Children rows
= _model
->children();
796 TreeModel::Children::iterator i
;
798 suspend_redisplay ();
800 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
802 TreeModel::Row row
= (*i
);
803 TimeAxisView
*tv
= row
[_columns
.tv
];
809 row
[_columns
.visible
] = false;
814 /* XXX this seems like a hack and half, but its not clear where to put this
818 //reset_scrolling_region ();
822 EditorRoutes::set_all_tracks_visibility (bool yn
)
824 TreeModel::Children rows
= _model
->children();
825 TreeModel::Children::iterator i
;
827 suspend_redisplay ();
829 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
831 TreeModel::Row row
= (*i
);
832 TimeAxisView
* tv
= row
[_columns
.tv
];
838 (*i
)[_columns
.visible
] = yn
;
845 EditorRoutes::set_all_audio_midi_visibility (int tracks
, bool yn
)
847 TreeModel::Children rows
= _model
->children();
848 TreeModel::Children::iterator i
;
850 suspend_redisplay ();
852 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
854 TreeModel::Row row
= (*i
);
855 TimeAxisView
* tv
= row
[_columns
.tv
];
857 AudioTimeAxisView
* atv
;
858 MidiTimeAxisView
* mtv
;
864 if ((atv
= dynamic_cast<AudioTimeAxisView
*>(tv
)) != 0) {
867 (*i
)[_columns
.visible
] = yn
;
871 if (atv
->is_audio_track()) {
872 (*i
)[_columns
.visible
] = yn
;
877 if (!atv
->is_audio_track()) {
878 (*i
)[_columns
.visible
] = yn
;
883 else if ((mtv
= dynamic_cast<MidiTimeAxisView
*>(tv
)) != 0) {
886 (*i
)[_columns
.visible
] = yn
;
890 if (mtv
->is_midi_track()) {
891 (*i
)[_columns
.visible
] = yn
;
902 EditorRoutes::hide_all_routes ()
904 set_all_tracks_visibility (false);
908 EditorRoutes::show_all_routes ()
910 set_all_tracks_visibility (true);
914 EditorRoutes::show_all_audiotracks()
916 set_all_audio_midi_visibility (1, true);
919 EditorRoutes::hide_all_audiotracks ()
921 set_all_audio_midi_visibility (1, false);
925 EditorRoutes::show_all_audiobus ()
927 set_all_audio_midi_visibility (2, true);
930 EditorRoutes::hide_all_audiobus ()
932 set_all_audio_midi_visibility (2, false);
936 EditorRoutes::show_all_miditracks()
938 set_all_audio_midi_visibility (3, true);
941 EditorRoutes::hide_all_miditracks ()
943 set_all_audio_midi_visibility (3, false);
947 EditorRoutes::key_press (GdkEventKey
* ev
)
950 boost::shared_ptr
<RouteList
> rl (new RouteList
);
953 switch (ev
->keyval
) {
955 case GDK_ISO_Left_Tab
:
957 /* If we appear to be editing something, leave that cleanly and appropriately.
960 name_editable
->editing_done ();
964 col
= _display
.get_column (_name_column
); // select&focus on name column
966 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)) {
967 treeview_select_previous (_display
, _model
, col
);
969 treeview_select_next (_display
, _model
, col
);
976 if (get_relevant_routes (rl
)) {
977 _session
->set_mute (rl
, !rl
->front()->muted(), Session::rt_cleanup
);
983 if (Config
->get_solo_control_is_listen_control()) {
984 _session
->set_listen (rl
, !rl
->front()->listening_via_monitor(), Session::rt_cleanup
);
986 _session
->set_solo (rl
, !rl
->front()->self_soloed(), Session::rt_cleanup
);
992 if (get_relevant_routes (rl
)) {
993 _session
->set_record_enabled (rl
, !rl
->front()->record_enabled(), Session::rt_cleanup
);
1005 EditorRoutes::get_relevant_routes (boost::shared_ptr
<RouteList
> rl
)
1008 RouteTimeAxisView
* rtv
;
1009 RefPtr
<TreeSelection
> selection
= _display
.get_selection();
1013 if (selection
->count_selected_rows() != 0) {
1017 RefPtr
<TreeModel
> tm
= RefPtr
<TreeModel
>::cast_dynamic (_model
);
1018 iter
= selection
->get_selected (tm
);
1021 /* use mouse pointer */
1026 _display
.get_pointer (x
, y
);
1027 _display
.convert_widget_to_bin_window_coords (x
, y
, bx
, by
);
1029 if (_display
.get_path_at_pos (bx
, by
, path
)) {
1030 iter
= _model
->get_iter (path
);
1035 tv
= (*iter
)[_columns
.tv
];
1037 rtv
= dynamic_cast<RouteTimeAxisView
*>(tv
);
1039 rl
->push_back (rtv
->route());
1044 return !rl
->empty();
1048 EditorRoutes::button_press (GdkEventButton
* ev
)
1050 if (Keyboard::is_context_menu_event (ev
)) {
1055 //Scroll editor canvas to selected track
1056 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1058 TreeModel::Path path
;
1059 TreeViewColumn
*tvc
;
1063 _display
.get_path_at_pos ((int) ev
->x
, (int) ev
->y
, path
, tvc
, cell_x
, cell_y
);
1065 // Get the model row.
1066 Gtk::TreeModel::Row row
= *_model
->get_iter (path
);
1068 TimeAxisView
*tv
= row
[_columns
.tv
];
1070 int y_pos
= tv
->y_position();
1072 //Clamp the y pos so that we do not extend beyond the canvas full height.
1073 if (_editor
->full_canvas_height
- y_pos
< _editor
->_canvas_height
){
1074 y_pos
= _editor
->full_canvas_height
- _editor
->_canvas_height
;
1077 //Only scroll to if the track is visible
1079 _editor
->reset_y_origin (y_pos
);
1087 EditorRoutes::selection_filter (Glib::RefPtr
<TreeModel
> const &, TreeModel::Path
const&, bool /*selected*/)
1089 if (selection_countdown
) {
1090 if (--selection_countdown
== 0) {
1093 /* no selection yet ... */
1100 struct EditorOrderRouteSorter
{
1101 bool operator() (boost::shared_ptr
<Route
> a
, boost::shared_ptr
<Route
> b
) {
1102 /* use of ">" forces the correct sort order */
1103 return a
->order_key (N_ ("editor")) < b
->order_key (N_ ("editor"));
1108 EditorRoutes::initial_display ()
1110 suspend_redisplay ();
1114 resume_redisplay ();
1118 boost::shared_ptr
<RouteList
> routes
= _session
->get_routes();
1119 RouteList
r (*routes
);
1120 EditorOrderRouteSorter sorter
;
1123 _editor
->handle_new_route (r
);
1125 /* don't show master bus in a new session */
1127 if (ARDOUR_UI::instance()->session_is_new ()) {
1129 TreeModel::Children rows
= _model
->children();
1130 TreeModel::Children::iterator i
;
1132 _no_redisplay
= true;
1134 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1136 TimeAxisView
*tv
= (*i
)[_columns
.tv
];
1137 RouteTimeAxisView
*rtv
;
1139 if ((rtv
= dynamic_cast<RouteTimeAxisView
*>(tv
)) != 0) {
1140 if (rtv
->route()->is_master()) {
1141 _display
.get_selection()->unselect (i
);
1146 _no_redisplay
= false;
1150 resume_redisplay ();
1154 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path
const &, Gtk::TreeModel::iterator
const &, int* /*new_order*/)
1156 _redisplay_does_not_sync_order_keys
= true;
1157 _session
->set_remote_control_ids();
1159 _redisplay_does_not_sync_order_keys
= false;
1163 EditorRoutes::display_drag_data_received (const RefPtr
<Gdk::DragContext
>& context
,
1165 const SelectionData
& data
,
1166 guint info
, guint time
)
1168 if (data
.get_target() == "GTK_TREE_MODEL_ROW") {
1169 _display
.on_drag_data_received (context
, x
, y
, data
, info
, time
);
1173 context
->drag_finish (true, false, time
);
1177 EditorRoutes::move_selected_tracks (bool up
)
1179 if (_editor
->selection
->tracks
.empty()) {
1183 typedef std::pair
<TimeAxisView
*,boost::shared_ptr
<Route
> > ViewRoute
;
1184 std::list
<ViewRoute
> view_routes
;
1185 std::vector
<int> neworder
;
1186 TreeModel::Children rows
= _model
->children();
1187 TreeModel::Children::iterator ri
;
1189 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
1190 TimeAxisView
* tv
= (*ri
)[_columns
.tv
];
1191 boost::shared_ptr
<Route
> route
= (*ri
)[_columns
.route
];
1193 view_routes
.push_back (ViewRoute (tv
, route
));
1196 list
<ViewRoute
>::iterator trailing
;
1197 list
<ViewRoute
>::iterator leading
;
1201 trailing
= view_routes
.begin();
1202 leading
= view_routes
.begin();
1206 while (leading
!= view_routes
.end()) {
1207 if (_editor
->selection
->selected (leading
->first
)) {
1208 view_routes
.insert (trailing
, ViewRoute (leading
->first
, leading
->second
));
1209 leading
= view_routes
.erase (leading
);
1218 /* if we could use reverse_iterator in list::insert, this code
1219 would be a beautiful reflection of the code above. but we can't
1220 and so it looks like a bit of a mess.
1223 trailing
= view_routes
.end();
1224 leading
= view_routes
.end();
1226 --leading
; if (leading
== view_routes
.begin()) { return; }
1232 if (_editor
->selection
->selected (leading
->first
)) {
1233 list
<ViewRoute
>::iterator tmp
;
1235 /* need to insert *after* trailing, not *before* it,
1236 which is what insert (iter, val) normally does.
1242 view_routes
.insert (tmp
, ViewRoute (leading
->first
, leading
->second
));
1244 /* can't use iter = cont.erase (iter); form here, because
1245 we need iter to move backwards.
1253 if (leading
== view_routes
.begin()) {
1254 /* the one we've just inserted somewhere else
1255 was the first in the list. erase this copy,
1256 and then break, because we're done.
1261 view_routes
.erase (leading
);
1270 if (leading
== view_routes
.begin()) {
1279 for (leading
= view_routes
.begin(); leading
!= view_routes
.end(); ++leading
) {
1280 neworder
.push_back (leading
->second
->order_key (N_ ("editor")));
1283 _model
->reorder (neworder
);
1285 _session
->sync_order_keys (N_ ("editor"));
1289 EditorRoutes::update_input_active_display ()
1291 TreeModel::Children rows
= _model
->children();
1292 TreeModel::Children::iterator i
;
1294 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1295 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1297 if (boost::dynamic_pointer_cast
<Track
> (route
)) {
1298 boost::shared_ptr
<MidiTrack
> mt
= boost::dynamic_pointer_cast
<MidiTrack
> (route
);
1301 (*i
)[_columns
.is_input_active
] = mt
->input_active();
1308 EditorRoutes::update_rec_display ()
1310 TreeModel::Children rows
= _model
->children();
1311 TreeModel::Children::iterator i
;
1313 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1314 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1316 if (boost::dynamic_pointer_cast
<Track
> (route
)) {
1317 boost::shared_ptr
<MidiTrack
> mt
= boost::dynamic_pointer_cast
<MidiTrack
> (route
);
1319 if (route
->record_enabled()) {
1320 if (_session
->record_status() == Session::Recording
) {
1321 (*i
)[_columns
.rec_state
] = 1;
1323 (*i
)[_columns
.rec_state
] = 2;
1325 } else if (mt
&& mt
->step_editing()) {
1326 (*i
)[_columns
.rec_state
] = 3;
1328 (*i
)[_columns
.rec_state
] = 0;
1331 (*i
)[_columns
.name_editable
] = !route
->record_enabled ();
1337 EditorRoutes::update_mute_display ()
1339 TreeModel::Children rows
= _model
->children();
1340 TreeModel::Children::iterator i
;
1342 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1343 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1344 (*i
)[_columns
.mute_state
] = RouteUI::mute_visual_state (_session
, route
);
1349 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1351 TreeModel::Children rows
= _model
->children();
1352 TreeModel::Children::iterator i
;
1354 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1355 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1356 (*i
)[_columns
.solo_state
] = RouteUI::solo_visual_state (route
);
1361 EditorRoutes::update_solo_isolate_display ()
1363 TreeModel::Children rows
= _model
->children();
1364 TreeModel::Children::iterator i
;
1366 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1367 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1368 (*i
)[_columns
.solo_isolate_state
] = RouteUI::solo_isolate_visual_state (route
) > 0 ? 1 : 0;
1373 EditorRoutes::update_solo_safe_display ()
1375 TreeModel::Children rows
= _model
->children();
1376 TreeModel::Children::iterator i
;
1378 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1379 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1380 (*i
)[_columns
.solo_safe_state
] = RouteUI::solo_safe_visual_state (route
) > 0 ? 1 : 0;
1385 EditorRoutes::views () const
1387 list
<TimeAxisView
*> v
;
1388 for (TreeModel::Children::iterator i
= _model
->children().begin(); i
!= _model
->children().end(); ++i
) {
1389 v
.push_back ((*i
)[_columns
.tv
]);
1396 EditorRoutes::clear ()
1398 _display
.set_model (Glib::RefPtr
<Gtk::TreeStore
> (0));
1400 _display
.set_model (_model
);
1404 EditorRoutes::name_edit_started (CellEditable
* ce
, const Glib::ustring
&)
1408 /* give it a special name */
1410 Gtk::Entry
*e
= dynamic_cast<Gtk::Entry
*> (ce
);
1413 e
->set_name (X_("RouteNameEditorEntry"));
1418 EditorRoutes::name_edit (std::string
const & path
, std::string
const & new_text
)
1422 TreeIter iter
= _model
->get_iter (path
);
1428 boost::shared_ptr
<Route
> route
= (*iter
)[_columns
.route
];
1430 if (route
&& route
->name() != new_text
) {
1431 route
->set_name (new_text
);
1436 EditorRoutes::solo_changed_so_update_mute ()
1438 update_mute_display ();
1442 EditorRoutes::show_tracks_with_regions_at_playhead ()
1444 boost::shared_ptr
<RouteList
> const r
= _session
->get_routes_with_regions_at (_session
->transport_frame ());
1446 set
<TimeAxisView
*> show
;
1447 for (RouteList::const_iterator i
= r
->begin(); i
!= r
->end(); ++i
) {
1448 TimeAxisView
* tav
= _editor
->axis_view_from_route (*i
);
1454 suspend_redisplay ();
1456 TreeModel::Children rows
= _model
->children ();
1457 for (TreeModel::Children::iterator i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1458 TimeAxisView
* tv
= (*i
)[_columns
.tv
];
1459 (*i
)[_columns
.visible
] = (show
.find (tv
) != show
.end());
1462 resume_redisplay ();