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 _scroller
.add (_display
);
72 _scroller
.set_policy (POLICY_NEVER
, POLICY_AUTOMATIC
);
74 _model
= ListStore::create (_columns
);
75 _display
.set_model (_model
);
77 // Record enable toggle
78 CellRendererPixbufMulti
* rec_col_renderer
= manage (new CellRendererPixbufMulti());
80 rec_col_renderer
->set_pixbuf (0, ::get_icon("act-disabled"));
81 rec_col_renderer
->set_pixbuf (1, ::get_icon("rec-in-progress"));
82 rec_col_renderer
->set_pixbuf (2, ::get_icon("rec-enabled"));
83 rec_col_renderer
->set_pixbuf (3, ::get_icon("step-editing"));
84 rec_col_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed
));
86 TreeViewColumn
* rec_state_column
= manage (new TreeViewColumn("R", *rec_col_renderer
));
88 rec_state_column
->add_attribute(rec_col_renderer
->property_state(), _columns
.rec_state
);
89 rec_state_column
->add_attribute(rec_col_renderer
->property_visible(), _columns
.is_track
);
90 rec_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
91 rec_state_column
->set_alignment(ALIGN_CENTER
);
92 rec_state_column
->set_expand(false);
93 rec_state_column
->set_fixed_width(15);
96 CellRendererPixbufMulti
* mute_col_renderer
= manage (new CellRendererPixbufMulti());
98 mute_col_renderer
->set_pixbuf (0, ::get_icon("act-disabled"));
99 mute_col_renderer
->set_pixbuf (1, ::get_icon("muted-by-others"));
100 mute_col_renderer
->set_pixbuf (2, ::get_icon("mute-enabled"));
101 mute_col_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled
));
103 TreeViewColumn
* mute_state_column
= manage (new TreeViewColumn("M", *mute_col_renderer
));
105 mute_state_column
->add_attribute(mute_col_renderer
->property_state(), _columns
.mute_state
);
106 mute_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
107 mute_state_column
->set_alignment(ALIGN_CENTER
);
108 mute_state_column
->set_expand(false);
109 mute_state_column
->set_fixed_width(15);
111 // Solo enable toggle
112 CellRendererPixbufMulti
* solo_col_renderer
= manage (new CellRendererPixbufMulti());
114 solo_col_renderer
->set_pixbuf (0, ::get_icon("act-disabled"));
115 solo_col_renderer
->set_pixbuf (1, ::get_icon("solo-enabled"));
116 solo_col_renderer
->set_pixbuf (3, ::get_icon("soloed-by-others"));
117 solo_col_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled
));
119 TreeViewColumn
* solo_state_column
= manage (new TreeViewColumn("S", *solo_col_renderer
));
121 solo_state_column
->add_attribute(solo_col_renderer
->property_state(), _columns
.solo_state
);
122 solo_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
123 solo_state_column
->set_alignment(ALIGN_CENTER
);
124 solo_state_column
->set_expand(false);
125 solo_state_column
->set_fixed_width(15);
127 // Solo isolate toggle
128 CellRendererPixbufMulti
* solo_iso_renderer
= manage (new CellRendererPixbufMulti());
130 solo_iso_renderer
->set_pixbuf (0, ::get_icon("act-disabled"));
131 solo_iso_renderer
->set_pixbuf (1, ::get_icon("solo-isolated"));
132 solo_iso_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled
));
134 TreeViewColumn
* solo_isolate_state_column
= manage (new TreeViewColumn("SI", *solo_iso_renderer
));
136 solo_isolate_state_column
->add_attribute(solo_iso_renderer
->property_state(), _columns
.solo_isolate_state
);
137 solo_isolate_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
138 solo_isolate_state_column
->set_alignment(ALIGN_CENTER
);
139 solo_isolate_state_column
->set_expand(false);
140 solo_isolate_state_column
->set_fixed_width(22);
143 CellRendererPixbufMulti
* solo_safe_renderer
= manage (new CellRendererPixbufMulti ());
145 solo_safe_renderer
->set_pixbuf (0, ::get_icon("act-disabled"));
146 solo_safe_renderer
->set_pixbuf (1, ::get_icon("solo-enabled"));
147 solo_safe_renderer
->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled
));
149 TreeViewColumn
* solo_safe_state_column
= manage (new TreeViewColumn(_("SS"), *solo_safe_renderer
));
150 solo_safe_state_column
->add_attribute(solo_safe_renderer
->property_state(), _columns
.solo_safe_state
);
151 solo_safe_state_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
152 solo_safe_state_column
->set_alignment(ALIGN_CENTER
);
153 solo_safe_state_column
->set_expand(false);
154 solo_safe_state_column
->set_fixed_width(22);
156 _display
.append_column (*rec_state_column
);
157 _display
.append_column (*mute_state_column
);
158 _display
.append_column (*solo_state_column
);
159 _display
.append_column (*solo_isolate_state_column
);
160 _display
.append_column (*solo_safe_state_column
);
162 int colnum
= _display
.append_column (_("Name"), _columns
.text
);
163 TreeViewColumn
* c
= _display
.get_column (colnum
-1);
164 c
->set_data ("i_am_the_tab_column", (void*) 0xfeedface);
165 _display
.append_column (_("V"), _columns
.visible
);
167 _display
.set_headers_visible (true);
168 _display
.set_name ("TrackListDisplay");
169 _display
.get_selection()->set_mode (SELECTION_SINGLE
);
170 _display
.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter
));
171 _display
.set_reorderable (true);
172 _display
.set_rules_hint (true);
173 _display
.set_size_request (100, -1);
174 _display
.add_object_drag (_columns
.route
.index(), "routes");
176 CellRendererText
* name_cell
= dynamic_cast<CellRendererText
*> (_display
.get_column_cell_renderer (5));
179 name_cell
->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started
));
181 TreeViewColumn
* name_column
= _display
.get_column (5);
183 assert (name_column
);
185 name_column
->add_attribute (name_cell
->property_editable(), _columns
.name_editable
);
186 name_column
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
187 name_column
->set_expand(true);
188 name_column
->set_min_width(50);
190 name_cell
->property_editable() = true;
191 name_cell
->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit
));
193 // Set the visible column cell renderer to radio toggle
194 CellRendererToggle
* visible_cell
= dynamic_cast<CellRendererToggle
*> (_display
.get_column_cell_renderer (6));
196 visible_cell
->property_activatable() = true;
197 visible_cell
->property_radio() = false;
198 visible_cell
->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed
));
200 TreeViewColumn
* visible_col
= dynamic_cast<TreeViewColumn
*> (_display
.get_column (6));
201 visible_col
->set_expand(false);
202 visible_col
->set_sizing(TREE_VIEW_COLUMN_FIXED
);
203 visible_col
->set_fixed_width(30);
204 visible_col
->set_alignment(ALIGN_CENTER
);
206 _model
->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted
));
207 _model
->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered
));
209 _display
.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press
), false);
210 _scroller
.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press
), false);
212 _scroller
.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in
), false);
213 _scroller
.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out
));
215 _display
.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify
), false);
216 _display
.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify
), false);
218 _display
.set_enable_search (false);
220 Route::SyncOrderKeys
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::sync_order_keys
, this, _1
), gui_context());
224 EditorRoutes::focus_in (GdkEventFocus
*)
226 Window
* win
= dynamic_cast<Window
*> (_scroller
.get_toplevel ());
229 old_focus
= win
->get_focus ();
236 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
241 EditorRoutes::focus_out (GdkEventFocus
*)
244 old_focus
->grab_focus ();
252 EditorRoutes::enter_notify (GdkEventCrossing
*)
258 /* arm counter so that ::selection_filter() will deny selecting anything for the
259 next two attempts to change selection status.
261 selection_countdown
= 2;
262 _scroller
.grab_focus ();
263 Keyboard::magic_widget_grab_focus ();
268 EditorRoutes::leave_notify (GdkEventCrossing
*)
270 selection_countdown
= 0;
273 old_focus
->grab_focus ();
277 Keyboard::magic_widget_drop_focus ();
282 EditorRoutes::set_session (Session
* s
)
284 SessionHandlePtr::set_session (s
);
289 _session
->SoloChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::solo_changed_so_update_mute
, this), gui_context());
290 _session
->RecordStateChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_rec_display
, this), gui_context());
295 EditorRoutes::on_tv_rec_enable_changed (std::string
const & path_string
)
297 // Get the model row that has been toggled.
298 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
300 TimeAxisView
* tv
= row
[_columns
.tv
];
301 RouteTimeAxisView
*rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
303 if (rtv
&& rtv
->track()) {
304 boost::shared_ptr
<RouteList
> rl (new RouteList
);
305 rl
->push_back (rtv
->route());
306 _session
->set_record_enabled (rl
, !rtv
->track()->record_enabled(), Session::rt_cleanup
);
311 EditorRoutes::on_tv_mute_enable_toggled (std::string
const & path_string
)
313 // Get the model row that has been toggled.
314 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
316 TimeAxisView
*tv
= row
[_columns
.tv
];
317 RouteTimeAxisView
*rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
320 boost::shared_ptr
<RouteList
> rl (new RouteList
);
321 rl
->push_back (rtv
->route());
322 _session
->set_mute (rl
, !rtv
->route()->muted(), Session::rt_cleanup
);
327 EditorRoutes::on_tv_solo_enable_toggled (std::string
const & path_string
)
329 // Get the model row that has been toggled.
330 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
332 TimeAxisView
*tv
= row
[_columns
.tv
];
333 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
336 boost::shared_ptr
<RouteList
> rl (new RouteList
);
337 rl
->push_back (rtv
->route());
338 if (Config
->get_solo_control_is_listen_control()) {
339 _session
->set_listen (rl
, !rtv
->route()->listening_via_monitor(), Session::rt_cleanup
);
341 _session
->set_solo (rl
, !rtv
->route()->self_soloed(), Session::rt_cleanup
);
347 EditorRoutes::on_tv_solo_isolate_toggled (std::string
const & path_string
)
349 // Get the model row that has been toggled.
350 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
352 TimeAxisView
*tv
= row
[_columns
.tv
];
353 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
356 rtv
->route()->set_solo_isolated (!rtv
->route()->solo_isolated(), this);
361 EditorRoutes::on_tv_solo_safe_toggled (std::string
const & path_string
)
363 // Get the model row that has been toggled.
364 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
366 TimeAxisView
*tv
= row
[_columns
.tv
];
367 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
370 rtv
->route()->set_solo_safe (!rtv
->route()->solo_safe(), this);
375 EditorRoutes::build_menu ()
377 using namespace Menu_Helpers
;
382 MenuList
& items
= _menu
->items();
383 _menu
->set_name ("ArdourContextMenu");
385 items
.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes
)));
386 items
.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes
)));
387 items
.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks
)));
388 items
.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks
)));
389 items
.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus
)));
390 items
.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus
)));
391 items
.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks
)));
392 items
.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks
)));
393 items
.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead
)));
397 EditorRoutes::show_menu ()
403 _menu
->popup (1, gtk_get_current_event_time());
407 EditorRoutes::redisplay ()
409 if (_no_redisplay
|| !_session
) {
413 TreeModel::Children rows
= _model
->children();
414 TreeModel::Children::iterator i
;
418 for (n
= 0, position
= 0, i
= rows
.begin(); i
!= rows
.end(); ++i
) {
419 TimeAxisView
*tv
= (*i
)[_columns
.tv
];
420 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
423 // just a "title" row
427 if (!_redisplay_does_not_reset_order_keys
) {
428 /* this reorder is caused by user action, so reassign sort order keys
431 route
->set_order_key (N_ ("editor"), n
);
434 bool visible
= (*i
)[_columns
.visible
];
436 /* show or hide the TimeAxisView */
438 tv
->set_marked_for_display (true);
439 position
+= tv
->show_at (position
, n
, &_editor
->edit_controls_vbox
);
440 tv
->clip_to_viewport ();
442 tv
->set_marked_for_display (false);
450 /* whenever we go idle, update the track view list to reflect the new order.
451 we can't do this here, because we could mess up something that is traversing
452 the track order and has caused a redisplay of the list.
454 Glib::signal_idle().connect (sigc::mem_fun (*_editor
, &Editor::sync_track_view_list_and_routes
));
456 _editor
->reset_controls_layout_height (position
);
457 _editor
->reset_controls_layout_width ();
458 _editor
->full_canvas_height
= position
+ _editor
->canvas_timebars_vsize
;
459 _editor
->vertical_adjustment
.set_upper (_editor
->full_canvas_height
);
461 if ((_editor
->vertical_adjustment
.get_value() + _editor
->_canvas_height
) > _editor
->vertical_adjustment
.get_upper()) {
463 We're increasing the size of the canvas while the bottom is visible.
464 We scroll down to keep in step with the controls layout.
466 _editor
->vertical_adjustment
.set_value (_editor
->full_canvas_height
- _editor
->_canvas_height
);
469 if (!_redisplay_does_not_reset_order_keys
&& !_redisplay_does_not_sync_order_keys
) {
470 _session
->sync_order_keys (N_ ("editor"));
475 EditorRoutes::route_deleted (Gtk::TreeModel::Path
const &)
477 if (!_session
|| _session
->deletion_in_progress()) {
481 /* this could require an order reset & sync */
482 _session
->set_remote_control_ids();
483 _ignore_reorder
= true;
485 _ignore_reorder
= false;
489 EditorRoutes::visible_changed (std::string
const & path
)
491 if (_session
&& _session
->deletion_in_progress()) {
497 if ((iter
= _model
->get_iter (path
))) {
498 TimeAxisView
* tv
= (*iter
)[_columns
.tv
];
500 bool visible
= (*iter
)[_columns
.visible
];
501 (*iter
)[_columns
.visible
] = !visible
;
505 _redisplay_does_not_reset_order_keys
= true;
506 _session
->set_remote_control_ids();
508 _redisplay_does_not_reset_order_keys
= false;
512 EditorRoutes::routes_added (list
<RouteTimeAxisView
*> routes
)
516 _redisplay_does_not_sync_order_keys
= true;
517 suspend_redisplay ();
519 for (list
<RouteTimeAxisView
*>::iterator x
= routes
.begin(); x
!= routes
.end(); ++x
) {
521 row
= *(_model
->append ());
523 row
[_columns
.text
] = (*x
)->route()->name();
524 row
[_columns
.visible
] = (*x
)->marked_for_display();
525 row
[_columns
.tv
] = *x
;
526 row
[_columns
.route
] = (*x
)->route ();
527 row
[_columns
.is_track
] = (boost::dynamic_pointer_cast
<Track
> ((*x
)->route()) != 0);
528 row
[_columns
.mute_state
] = (*x
)->route()->muted();
529 row
[_columns
.solo_state
] = RouteUI::solo_visual_state ((*x
)->route());
530 row
[_columns
.solo_isolate_state
] = (*x
)->route()->solo_isolated();
531 row
[_columns
.solo_safe_state
] = (*x
)->route()->solo_safe();
532 row
[_columns
.name_editable
] = true;
534 _ignore_reorder
= true;
536 /* added a new fresh one at the end */
537 if ((*x
)->route()->order_key (N_ ("editor")) == -1) {
538 (*x
)->route()->set_order_key (N_ ("editor"), _model
->children().size()-1);
541 _ignore_reorder
= false;
543 boost::weak_ptr
<Route
> wr ((*x
)->route());
545 (*x
)->route()->gui_changed
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::handle_gui_changes
, this, _1
, _2
), gui_context());
546 (*x
)->route()->PropertyChanged
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::route_property_changed
, this, _1
, wr
), gui_context());
548 if ((*x
)->is_track()) {
549 boost::shared_ptr
<Track
> t
= boost::dynamic_pointer_cast
<Track
> ((*x
)->route());
550 t
->RecordEnableChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_rec_display
, this), gui_context());
553 if ((*x
)->is_midi_track()) {
554 boost::shared_ptr
<MidiTrack
> t
= boost::dynamic_pointer_cast
<MidiTrack
> ((*x
)->route());
555 t
->StepEditStatusChange
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_rec_display
, this), gui_context());
558 (*x
)->route()->mute_changed
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_mute_display
, this), gui_context());
559 (*x
)->route()->solo_changed
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::update_solo_display
, this, _1
), gui_context());
560 (*x
)->route()->listen_changed
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::update_solo_display
, this, _1
), gui_context());
561 (*x
)->route()->solo_isolated_changed
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_solo_isolate_display
, this), gui_context());
562 (*x
)->route()->solo_safe_changed
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_solo_safe_display
, this), gui_context());
565 update_rec_display ();
566 update_mute_display ();
567 update_solo_display (true);
568 update_solo_isolate_display ();
569 update_solo_safe_display ();
571 _redisplay_does_not_sync_order_keys
= false;
575 EditorRoutes::handle_gui_changes (string
const & what
, void*)
577 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes
, what
, src
)
579 if (what
== "track_height") {
580 /* Optional :make tracks change height while it happens, instead
583 //update_canvas_now ();
587 if (what
== "visible_tracks") {
593 EditorRoutes::route_removed (TimeAxisView
*tv
)
595 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed
, tv
)
597 TreeModel::Children rows
= _model
->children();
598 TreeModel::Children::iterator ri
;
600 /* the core model has changed, there is no need to sync
604 _redisplay_does_not_sync_order_keys
= true;
606 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
607 if ((*ri
)[_columns
.tv
] == tv
) {
613 _redisplay_does_not_sync_order_keys
= false;
617 EditorRoutes::route_property_changed (const PropertyChange
& what_changed
, boost::weak_ptr
<Route
> r
)
619 if (!what_changed
.contains (ARDOUR::Properties::name
)) {
623 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed
, r
)
625 boost::shared_ptr
<Route
> route
= r
.lock ();
631 TreeModel::Children rows
= _model
->children();
632 TreeModel::Children::iterator i
;
634 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
635 boost::shared_ptr
<Route
> t
= (*i
)[_columns
.route
];
637 (*i
)[_columns
.text
] = route
->name();
644 EditorRoutes::update_visibility ()
646 TreeModel::Children rows
= _model
->children();
647 TreeModel::Children::iterator i
;
649 suspend_redisplay ();
651 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
652 TimeAxisView
*tv
= (*i
)[_columns
.tv
];
653 (*i
)[_columns
.visible
] = tv
->marked_for_display ();
654 cerr
<< "marked " << tv
->name() << " for display = " << tv
->marked_for_display() << endl
;
661 EditorRoutes::hide_track_in_display (TimeAxisView
& tv
)
663 TreeModel::Children rows
= _model
->children();
664 TreeModel::Children::iterator i
;
666 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
667 if ((*i
)[_columns
.tv
] == &tv
) {
668 (*i
)[_columns
.visible
] = false;
677 EditorRoutes::show_track_in_display (TimeAxisView
& tv
)
679 TreeModel::Children rows
= _model
->children();
680 TreeModel::Children::iterator i
;
682 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
683 if ((*i
)[_columns
.tv
] == &tv
) {
684 (*i
)[_columns
.visible
] = true;
693 EditorRoutes::reordered (TreeModel::Path
const &, TreeModel::iterator
const &, int* /*what*/)
698 /** If src != "editor", take editor order keys from each route and use them to rearrange the
699 * route list so that the visual arrangement of routes matches the order keys from the routes.
702 EditorRoutes::sync_order_keys (string
const & src
)
704 map
<int, int> new_order
;
705 TreeModel::Children rows
= _model
->children();
706 TreeModel::Children::iterator ri
;
708 if (src
== N_ ("editor") || !_session
|| (_session
->state_of_the_state() & (Session::Loading
|Session::Deletion
)) || rows
.empty()) {
712 bool changed
= false;
715 for (order
= 0, ri
= rows
.begin(); ri
!= rows
.end(); ++ri
, ++order
) {
716 boost::shared_ptr
<Route
> route
= (*ri
)[_columns
.route
];
718 int const old_key
= order
;
719 int const new_key
= route
->order_key (N_ ("editor"));
721 new_order
[new_key
] = old_key
;
723 if (new_key
!= old_key
) {
729 _redisplay_does_not_reset_order_keys
= true;
731 /* `compact' new_order into a vector */
733 for (map
<int, int>::const_iterator i
= new_order
.begin(); i
!= new_order
.end(); ++i
) {
734 co
.push_back (i
->second
);
737 _model
->reorder (co
);
738 _redisplay_does_not_reset_order_keys
= false;
744 EditorRoutes::hide_all_tracks (bool /*with_select*/)
746 TreeModel::Children rows
= _model
->children();
747 TreeModel::Children::iterator i
;
749 suspend_redisplay ();
751 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
753 TreeModel::Row row
= (*i
);
754 TimeAxisView
*tv
= row
[_columns
.tv
];
760 row
[_columns
.visible
] = false;
765 /* XXX this seems like a hack and half, but its not clear where to put this
769 //reset_scrolling_region ();
773 EditorRoutes::set_all_tracks_visibility (bool yn
)
775 TreeModel::Children rows
= _model
->children();
776 TreeModel::Children::iterator i
;
778 suspend_redisplay ();
780 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
782 TreeModel::Row row
= (*i
);
783 TimeAxisView
* tv
= row
[_columns
.tv
];
789 (*i
)[_columns
.visible
] = yn
;
796 EditorRoutes::set_all_audio_midi_visibility (int tracks
, bool yn
)
798 TreeModel::Children rows
= _model
->children();
799 TreeModel::Children::iterator i
;
801 suspend_redisplay ();
803 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
805 TreeModel::Row row
= (*i
);
806 TimeAxisView
* tv
= row
[_columns
.tv
];
808 AudioTimeAxisView
* atv
;
809 MidiTimeAxisView
* mtv
;
815 if ((atv
= dynamic_cast<AudioTimeAxisView
*>(tv
)) != 0) {
818 (*i
)[_columns
.visible
] = yn
;
822 if (atv
->is_audio_track()) {
823 (*i
)[_columns
.visible
] = yn
;
828 if (!atv
->is_audio_track()) {
829 (*i
)[_columns
.visible
] = yn
;
834 else if ((mtv
= dynamic_cast<MidiTimeAxisView
*>(tv
)) != 0) {
837 (*i
)[_columns
.visible
] = yn
;
841 if (mtv
->is_midi_track()) {
842 (*i
)[_columns
.visible
] = yn
;
853 EditorRoutes::hide_all_routes ()
855 set_all_tracks_visibility (false);
859 EditorRoutes::show_all_routes ()
861 set_all_tracks_visibility (true);
865 EditorRoutes::show_all_audiotracks()
867 set_all_audio_midi_visibility (1, true);
870 EditorRoutes::hide_all_audiotracks ()
872 set_all_audio_midi_visibility (1, false);
876 EditorRoutes::show_all_audiobus ()
878 set_all_audio_midi_visibility (2, true);
881 EditorRoutes::hide_all_audiobus ()
883 set_all_audio_midi_visibility (2, false);
887 EditorRoutes::show_all_miditracks()
889 set_all_audio_midi_visibility (3, true);
892 EditorRoutes::hide_all_miditracks ()
894 set_all_audio_midi_visibility (3, false);
898 EditorRoutes::key_press (GdkEventKey
* ev
)
901 boost::shared_ptr
<RouteList
> rl (new RouteList
);
904 switch (ev
->keyval
) {
906 case GDK_ISO_Left_Tab
:
908 /* If we appear to be editing something, leave that cleanly and appropriately.
911 name_editable
->editing_done ();
915 col
= _display
.get_column (5); // select&focus on name column
917 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)) {
918 treeview_select_previous (_display
, _model
, col
);
920 treeview_select_next (_display
, _model
, col
);
927 if (get_relevant_routes (rl
)) {
928 _session
->set_mute (rl
, !rl
->front()->muted(), Session::rt_cleanup
);
934 if (Config
->get_solo_control_is_listen_control()) {
935 _session
->set_listen (rl
, !rl
->front()->listening_via_monitor(), Session::rt_cleanup
);
937 _session
->set_solo (rl
, !rl
->front()->self_soloed(), Session::rt_cleanup
);
943 if (get_relevant_routes (rl
)) {
944 _session
->set_record_enabled (rl
, !rl
->front()->record_enabled(), Session::rt_cleanup
);
956 EditorRoutes::get_relevant_routes (boost::shared_ptr
<RouteList
> rl
)
959 RouteTimeAxisView
* rtv
;
960 RefPtr
<TreeSelection
> selection
= _display
.get_selection();
964 if (selection
->count_selected_rows() != 0) {
968 RefPtr
<TreeModel
> tm
= RefPtr
<TreeModel
>::cast_dynamic (_model
);
969 iter
= selection
->get_selected (tm
);
972 /* use mouse pointer */
977 _display
.get_pointer (x
, y
);
978 _display
.convert_widget_to_bin_window_coords (x
, y
, bx
, by
);
980 if (_display
.get_path_at_pos (bx
, by
, path
)) {
981 iter
= _model
->get_iter (path
);
986 tv
= (*iter
)[_columns
.tv
];
988 rtv
= dynamic_cast<RouteTimeAxisView
*>(tv
);
990 rl
->push_back (rtv
->route());
999 EditorRoutes::button_press (GdkEventButton
* ev
)
1001 if (Keyboard::is_context_menu_event (ev
)) {
1006 //Scroll editor canvas to selected track
1007 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1009 TreeModel::Path path
;
1010 TreeViewColumn
*tvc
;
1014 _display
.get_path_at_pos ((int) ev
->x
, (int) ev
->y
, path
, tvc
, cell_x
, cell_y
);
1016 // Get the model row.
1017 Gtk::TreeModel::Row row
= *_model
->get_iter (path
);
1019 TimeAxisView
*tv
= row
[_columns
.tv
];
1021 int y_pos
= tv
->y_position();
1023 //Clamp the y pos so that we do not extend beyond the canvas full height.
1024 if (_editor
->full_canvas_height
- y_pos
< _editor
->_canvas_height
){
1025 y_pos
= _editor
->full_canvas_height
- _editor
->_canvas_height
;
1028 //Only scroll to if the track is visible
1030 _editor
->reset_y_origin (y_pos
);
1038 EditorRoutes::selection_filter (Glib::RefPtr
<TreeModel
> const &, TreeModel::Path
const&, bool /*selected*/)
1040 if (selection_countdown
) {
1041 if (--selection_countdown
== 0) {
1044 /* no selection yet ... */
1051 struct EditorOrderRouteSorter
{
1052 bool operator() (boost::shared_ptr
<Route
> a
, boost::shared_ptr
<Route
> b
) {
1053 /* use of ">" forces the correct sort order */
1054 return a
->order_key (N_ ("editor")) < b
->order_key (N_ ("editor"));
1059 EditorRoutes::initial_display ()
1061 suspend_redisplay ();
1065 resume_redisplay ();
1069 boost::shared_ptr
<RouteList
> routes
= _session
->get_routes();
1070 RouteList
r (*routes
);
1071 EditorOrderRouteSorter sorter
;
1074 _editor
->handle_new_route (r
);
1076 /* don't show master bus in a new session */
1078 if (ARDOUR_UI::instance()->session_is_new ()) {
1080 TreeModel::Children rows
= _model
->children();
1081 TreeModel::Children::iterator i
;
1083 _no_redisplay
= true;
1085 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1087 TimeAxisView
*tv
= (*i
)[_columns
.tv
];
1088 RouteTimeAxisView
*rtv
;
1090 if ((rtv
= dynamic_cast<RouteTimeAxisView
*>(tv
)) != 0) {
1091 if (rtv
->route()->is_master()) {
1092 _display
.get_selection()->unselect (i
);
1097 _no_redisplay
= false;
1101 resume_redisplay ();
1105 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path
const &, Gtk::TreeModel::iterator
const &, int* /*new_order*/)
1107 _redisplay_does_not_sync_order_keys
= true;
1108 _session
->set_remote_control_ids();
1110 _redisplay_does_not_sync_order_keys
= false;
1114 EditorRoutes::display_drag_data_received (const RefPtr
<Gdk::DragContext
>& context
,
1116 const SelectionData
& data
,
1117 guint info
, guint time
)
1119 if (data
.get_target() == "GTK_TREE_MODEL_ROW") {
1120 _display
.on_drag_data_received (context
, x
, y
, data
, info
, time
);
1124 context
->drag_finish (true, false, time
);
1128 EditorRoutes::move_selected_tracks (bool up
)
1130 if (_editor
->selection
->tracks
.empty()) {
1134 typedef std::pair
<TimeAxisView
*,boost::shared_ptr
<Route
> > ViewRoute
;
1135 std::list
<ViewRoute
> view_routes
;
1136 std::vector
<int> neworder
;
1137 TreeModel::Children rows
= _model
->children();
1138 TreeModel::Children::iterator ri
;
1140 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
1141 TimeAxisView
* tv
= (*ri
)[_columns
.tv
];
1142 boost::shared_ptr
<Route
> route
= (*ri
)[_columns
.route
];
1144 view_routes
.push_back (ViewRoute (tv
, route
));
1147 list
<ViewRoute
>::iterator trailing
;
1148 list
<ViewRoute
>::iterator leading
;
1152 trailing
= view_routes
.begin();
1153 leading
= view_routes
.begin();
1157 while (leading
!= view_routes
.end()) {
1158 if (_editor
->selection
->selected (leading
->first
)) {
1159 view_routes
.insert (trailing
, ViewRoute (leading
->first
, leading
->second
));
1160 leading
= view_routes
.erase (leading
);
1169 /* if we could use reverse_iterator in list::insert, this code
1170 would be a beautiful reflection of the code above. but we can't
1171 and so it looks like a bit of a mess.
1174 trailing
= view_routes
.end();
1175 leading
= view_routes
.end();
1177 --leading
; if (leading
== view_routes
.begin()) { return; }
1183 if (_editor
->selection
->selected (leading
->first
)) {
1184 list
<ViewRoute
>::iterator tmp
;
1186 /* need to insert *after* trailing, not *before* it,
1187 which is what insert (iter, val) normally does.
1193 view_routes
.insert (tmp
, ViewRoute (leading
->first
, leading
->second
));
1195 /* can't use iter = cont.erase (iter); form here, because
1196 we need iter to move backwards.
1204 if (leading
== view_routes
.begin()) {
1205 /* the one we've just inserted somewhere else
1206 was the first in the list. erase this copy,
1207 and then break, because we're done.
1212 view_routes
.erase (leading
);
1221 if (leading
== view_routes
.begin()) {
1230 for (leading
= view_routes
.begin(); leading
!= view_routes
.end(); ++leading
) {
1231 neworder
.push_back (leading
->second
->order_key (N_ ("editor")));
1234 _model
->reorder (neworder
);
1236 _session
->sync_order_keys (N_ ("editor"));
1240 EditorRoutes::update_rec_display ()
1242 TreeModel::Children rows
= _model
->children();
1243 TreeModel::Children::iterator i
;
1245 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1246 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1248 if (boost::dynamic_pointer_cast
<Track
> (route
)) {
1249 boost::shared_ptr
<MidiTrack
> mt
= boost::dynamic_pointer_cast
<MidiTrack
> (route
);
1251 if (route
->record_enabled()) {
1252 if (_session
->record_status() == Session::Recording
) {
1253 (*i
)[_columns
.rec_state
] = 1;
1255 (*i
)[_columns
.rec_state
] = 2;
1257 } else if (mt
&& mt
->step_editing()) {
1258 (*i
)[_columns
.rec_state
] = 3;
1260 (*i
)[_columns
.rec_state
] = 0;
1263 (*i
)[_columns
.name_editable
] = !route
->record_enabled ();
1269 EditorRoutes::update_mute_display ()
1271 TreeModel::Children rows
= _model
->children();
1272 TreeModel::Children::iterator i
;
1274 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1275 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1276 (*i
)[_columns
.mute_state
] = RouteUI::mute_visual_state (_session
, route
);
1281 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1283 TreeModel::Children rows
= _model
->children();
1284 TreeModel::Children::iterator i
;
1286 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1287 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1288 (*i
)[_columns
.solo_state
] = RouteUI::solo_visual_state (route
);
1293 EditorRoutes::update_solo_isolate_display ()
1295 TreeModel::Children rows
= _model
->children();
1296 TreeModel::Children::iterator i
;
1298 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1299 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1300 (*i
)[_columns
.solo_isolate_state
] = RouteUI::solo_isolate_visual_state (route
) > 0 ? 1 : 0;
1305 EditorRoutes::update_solo_safe_display ()
1307 TreeModel::Children rows
= _model
->children();
1308 TreeModel::Children::iterator i
;
1310 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1311 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1312 (*i
)[_columns
.solo_safe_state
] = RouteUI::solo_safe_visual_state (route
) > 0 ? 1 : 0;
1317 EditorRoutes::views () const
1319 list
<TimeAxisView
*> v
;
1320 for (TreeModel::Children::iterator i
= _model
->children().begin(); i
!= _model
->children().end(); ++i
) {
1321 v
.push_back ((*i
)[_columns
.tv
]);
1328 EditorRoutes::clear ()
1330 _display
.set_model (Glib::RefPtr
<Gtk::TreeStore
> (0));
1332 _display
.set_model (_model
);
1336 EditorRoutes::name_edit_started (CellEditable
* ce
, const Glib::ustring
&)
1340 /* give it a special name */
1342 Gtk::Entry
*e
= dynamic_cast<Gtk::Entry
*> (ce
);
1345 e
->set_name (X_("RouteNameEditorEntry"));
1350 EditorRoutes::name_edit (std::string
const & path
, std::string
const & new_text
)
1354 TreeIter iter
= _model
->get_iter (path
);
1360 boost::shared_ptr
<Route
> route
= (*iter
)[_columns
.route
];
1362 if (route
&& route
->name() != new_text
) {
1363 route
->set_name (new_text
);
1368 EditorRoutes::solo_changed_so_update_mute ()
1370 update_mute_display ();
1374 EditorRoutes::show_tracks_with_regions_at_playhead ()
1376 boost::shared_ptr
<RouteList
> const r
= _session
->get_routes_with_regions_at (_session
->transport_frame ());
1378 set
<TimeAxisView
*> show
;
1379 for (RouteList::const_iterator i
= r
->begin(); i
!= r
->end(); ++i
) {
1380 TimeAxisView
* tav
= _editor
->axis_view_from_route (*i
);
1386 suspend_redisplay ();
1388 TreeModel::Children rows
= _model
->children ();
1389 for (TreeModel::Children::iterator i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1390 TimeAxisView
* tv
= (*i
)[_columns
.tv
];
1391 (*i
)[_columns
.visible
] = (show
.find (tv
) != show
.end());
1394 resume_redisplay ();