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
*)
254 /* arm counter so that ::selection_filter() will deny selecting anything for the
255 next two attempts to change selection status.
257 selection_countdown
= 2;
258 _scroller
.grab_focus ();
259 Keyboard::magic_widget_grab_focus ();
264 EditorRoutes::leave_notify (GdkEventCrossing
*)
266 selection_countdown
= 0;
269 old_focus
->grab_focus ();
273 Keyboard::magic_widget_drop_focus ();
278 EditorRoutes::set_session (Session
* s
)
280 SessionHandlePtr::set_session (s
);
285 _session
->SoloChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::solo_changed_so_update_mute
, this), gui_context());
286 _session
->RecordStateChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_rec_display
, this), gui_context());
291 EditorRoutes::on_tv_rec_enable_changed (std::string
const & path_string
)
293 // Get the model row that has been toggled.
294 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
296 TimeAxisView
*tv
= row
[_columns
.tv
];
297 AudioTimeAxisView
*atv
= dynamic_cast<AudioTimeAxisView
*> (tv
);
299 if (atv
!= 0 && atv
->is_audio_track()){
300 boost::shared_ptr
<RouteList
> rl (new RouteList
);
301 rl
->push_back (atv
->route());
302 _session
->set_record_enabled (rl
, !atv
->track()->record_enabled(), Session::rt_cleanup
);
307 EditorRoutes::on_tv_mute_enable_toggled (std::string
const & path_string
)
309 // Get the model row that has been toggled.
310 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
312 TimeAxisView
*tv
= row
[_columns
.tv
];
313 RouteTimeAxisView
*rtv
= dynamic_cast<RouteTimeAxisView
*> (tv
);
316 boost::shared_ptr
<RouteList
> rl (new RouteList
);
317 rl
->push_back (rtv
->route());
318 _session
->set_mute (rl
, !rtv
->route()->muted(), Session::rt_cleanup
);
323 EditorRoutes::on_tv_solo_enable_toggled (std::string
const & path_string
)
325 // Get the model row that has been toggled.
326 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
328 TimeAxisView
*tv
= row
[_columns
.tv
];
329 AudioTimeAxisView
*atv
= dynamic_cast<AudioTimeAxisView
*> (tv
);
332 boost::shared_ptr
<RouteList
> rl (new RouteList
);
333 rl
->push_back (atv
->route());
334 _session
->set_solo (rl
, !atv
->route()->soloed(), Session::rt_cleanup
);
339 EditorRoutes::on_tv_solo_isolate_toggled (std::string
const & path_string
)
341 // Get the model row that has been toggled.
342 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
344 TimeAxisView
*tv
= row
[_columns
.tv
];
345 AudioTimeAxisView
*atv
= dynamic_cast<AudioTimeAxisView
*> (tv
);
348 atv
->route()->set_solo_isolated (!atv
->route()->solo_isolated(), this);
353 EditorRoutes::on_tv_solo_safe_toggled (std::string
const & path_string
)
355 // Get the model row that has been toggled.
356 Gtk::TreeModel::Row row
= *_model
->get_iter (Gtk::TreeModel::Path (path_string
));
358 TimeAxisView
*tv
= row
[_columns
.tv
];
359 AudioTimeAxisView
*atv
= dynamic_cast<AudioTimeAxisView
*> (tv
);
362 atv
->route()->set_solo_safe (!atv
->route()->solo_safe(), this);
367 EditorRoutes::build_menu ()
369 using namespace Menu_Helpers
;
374 MenuList
& items
= _menu
->items();
375 _menu
->set_name ("ArdourContextMenu");
377 items
.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes
)));
378 items
.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes
)));
379 items
.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks
)));
380 items
.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks
)));
381 items
.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus
)));
382 items
.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus
)));
383 items
.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks
)));
384 items
.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks
)));
385 items
.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead
)));
389 EditorRoutes::show_menu ()
395 _menu
->popup (1, gtk_get_current_event_time());
399 EditorRoutes::redisplay ()
401 if (_no_redisplay
|| !_session
) {
405 TreeModel::Children rows
= _model
->children();
406 TreeModel::Children::iterator i
;
410 for (n
= 0, position
= 0, i
= rows
.begin(); i
!= rows
.end(); ++i
) {
411 TimeAxisView
*tv
= (*i
)[_columns
.tv
];
412 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
415 // just a "title" row
419 if (!_redisplay_does_not_reset_order_keys
) {
420 /* this reorder is caused by user action, so reassign sort order keys
423 route
->set_order_key (N_ ("editor"), n
);
426 bool visible
= (*i
)[_columns
.visible
];
428 /* show or hide the TimeAxisView */
430 tv
->set_marked_for_display (true);
431 position
+= tv
->show_at (position
, n
, &_editor
->edit_controls_vbox
);
432 tv
->clip_to_viewport ();
434 tv
->set_marked_for_display (false);
441 /* whenever we go idle, update the track view list to reflect the new order.
442 we can't do this here, because we could mess up something that is traversing
443 the track order and has caused a redisplay of the list.
445 Glib::signal_idle().connect (sigc::mem_fun (*_editor
, &Editor::sync_track_view_list_and_routes
));
447 _editor
->full_canvas_height
= position
+ _editor
->canvas_timebars_vsize
;
448 _editor
->vertical_adjustment
.set_upper (_editor
->full_canvas_height
);
450 if ((_editor
->vertical_adjustment
.get_value() + _editor
->_canvas_height
) > _editor
->vertical_adjustment
.get_upper()) {
452 We're increasing the size of the canvas while the bottom is visible.
453 We scroll down to keep in step with the controls layout.
455 _editor
->vertical_adjustment
.set_value (_editor
->full_canvas_height
- _editor
->_canvas_height
);
458 if (!_redisplay_does_not_reset_order_keys
&& !_redisplay_does_not_sync_order_keys
) {
459 _session
->sync_order_keys (N_ ("editor"));
464 EditorRoutes::route_deleted (Gtk::TreeModel::Path
const &)
466 if (!_session
|| _session
->deletion_in_progress()) {
470 /* this could require an order reset & sync */
471 _session
->set_remote_control_ids();
472 _ignore_reorder
= true;
474 _ignore_reorder
= false;
478 EditorRoutes::visible_changed (std::string
const & path
)
480 if (_session
&& _session
->deletion_in_progress()) {
486 if ((iter
= _model
->get_iter (path
))) {
487 TimeAxisView
* tv
= (*iter
)[_columns
.tv
];
489 bool visible
= (*iter
)[_columns
.visible
];
490 (*iter
)[_columns
.visible
] = !visible
;
494 _redisplay_does_not_reset_order_keys
= true;
495 _session
->set_remote_control_ids();
497 _redisplay_does_not_reset_order_keys
= false;
501 EditorRoutes::routes_added (list
<RouteTimeAxisView
*> routes
)
505 _redisplay_does_not_sync_order_keys
= true;
506 suspend_redisplay ();
508 for (list
<RouteTimeAxisView
*>::iterator x
= routes
.begin(); x
!= routes
.end(); ++x
) {
510 row
= *(_model
->append ());
512 row
[_columns
.text
] = (*x
)->route()->name();
513 row
[_columns
.visible
] = (*x
)->marked_for_display();
514 row
[_columns
.tv
] = *x
;
515 row
[_columns
.route
] = (*x
)->route ();
516 row
[_columns
.is_track
] = (boost::dynamic_pointer_cast
<Track
> ((*x
)->route()) != 0);
517 row
[_columns
.mute_state
] = (*x
)->route()->muted();
518 row
[_columns
.solo_state
] = (*x
)->route()->soloed();
519 row
[_columns
.solo_isolate_state
] = (*x
)->route()->solo_isolated();
520 row
[_columns
.solo_safe_state
] = (*x
)->route()->solo_safe();
521 row
[_columns
.name_editable
] = true;
523 _ignore_reorder
= true;
525 /* added a new fresh one at the end */
526 if ((*x
)->route()->order_key (N_ ("editor")) == -1) {
527 (*x
)->route()->set_order_key (N_ ("editor"), _model
->children().size()-1);
530 _ignore_reorder
= false;
532 boost::weak_ptr
<Route
> wr ((*x
)->route());
534 (*x
)->route()->gui_changed
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::handle_gui_changes
, this, _1
, _2
), gui_context());
535 (*x
)->route()->PropertyChanged
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::route_property_changed
, this, _1
, wr
), gui_context());
537 if ((*x
)->is_track()) {
538 boost::shared_ptr
<Track
> t
= boost::dynamic_pointer_cast
<Track
> ((*x
)->route());
539 t
->RecordEnableChanged
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_rec_display
, this), gui_context());
542 if ((*x
)->is_midi_track()) {
543 boost::shared_ptr
<MidiTrack
> t
= boost::dynamic_pointer_cast
<MidiTrack
> ((*x
)->route());
544 t
->StepEditStatusChange
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_rec_display
, this), gui_context());
547 (*x
)->route()->mute_changed
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_mute_display
, this), gui_context());
548 (*x
)->route()->solo_changed
.connect (*this, MISSING_INVALIDATOR
, ui_bind (&EditorRoutes::update_solo_display
, this, _1
), gui_context());
549 (*x
)->route()->solo_isolated_changed
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_solo_isolate_display
, this), gui_context());
550 (*x
)->route()->solo_safe_changed
.connect (*this, MISSING_INVALIDATOR
, boost::bind (&EditorRoutes::update_solo_safe_display
, this), gui_context());
553 update_rec_display ();
554 update_mute_display ();
555 update_solo_display (true);
556 update_solo_isolate_display ();
557 update_solo_safe_display ();
559 _redisplay_does_not_sync_order_keys
= false;
563 EditorRoutes::handle_gui_changes (string
const & what
, void*)
565 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes
, what
, src
)
567 if (what
== "track_height") {
568 /* Optional :make tracks change height while it happens, instead
571 //update_canvas_now ();
575 if (what
== "visible_tracks") {
581 EditorRoutes::route_removed (TimeAxisView
*tv
)
583 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed
, tv
)
585 TreeModel::Children rows
= _model
->children();
586 TreeModel::Children::iterator ri
;
588 /* the core model has changed, there is no need to sync
592 _redisplay_does_not_sync_order_keys
= true;
594 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
595 if ((*ri
)[_columns
.tv
] == tv
) {
601 _redisplay_does_not_sync_order_keys
= false;
605 EditorRoutes::route_property_changed (const PropertyChange
& what_changed
, boost::weak_ptr
<Route
> r
)
607 if (!what_changed
.contains (ARDOUR::Properties::name
)) {
611 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed
, r
)
613 boost::shared_ptr
<Route
> route
= r
.lock ();
619 TreeModel::Children rows
= _model
->children();
620 TreeModel::Children::iterator i
;
622 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
623 boost::shared_ptr
<Route
> t
= (*i
)[_columns
.route
];
625 (*i
)[_columns
.text
] = route
->name();
632 EditorRoutes::update_visibility ()
634 TreeModel::Children rows
= _model
->children();
635 TreeModel::Children::iterator i
;
637 suspend_redisplay ();
639 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
640 TimeAxisView
*tv
= (*i
)[_columns
.tv
];
641 (*i
)[_columns
.visible
] = tv
->marked_for_display ();
642 cerr
<< "marked " << tv
->name() << " for display = " << tv
->marked_for_display() << endl
;
649 EditorRoutes::hide_track_in_display (TimeAxisView
& tv
)
651 TreeModel::Children rows
= _model
->children();
652 TreeModel::Children::iterator i
;
654 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
655 if ((*i
)[_columns
.tv
] == &tv
) {
656 (*i
)[_columns
.visible
] = false;
665 EditorRoutes::show_track_in_display (TimeAxisView
& tv
)
667 TreeModel::Children rows
= _model
->children();
668 TreeModel::Children::iterator i
;
670 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
671 if ((*i
)[_columns
.tv
] == &tv
) {
672 (*i
)[_columns
.visible
] = true;
681 EditorRoutes::reordered (TreeModel::Path
const &, TreeModel::iterator
const &, int* /*what*/)
686 /** If src != "editor", take editor order keys from each route and use them to rearrange the
687 * route list so that the visual arrangement of routes matches the order keys from the routes.
690 EditorRoutes::sync_order_keys (string
const & src
)
692 vector
<int> neworder
;
693 TreeModel::Children rows
= _model
->children();
694 TreeModel::Children::iterator ri
;
696 if (src
== N_ ("editor") || !_session
|| (_session
->state_of_the_state() & (Session::Loading
|Session::Deletion
)) || rows
.empty()) {
700 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
701 neworder
.push_back (0);
704 bool changed
= false;
707 for (order
= 0, ri
= rows
.begin(); ri
!= rows
.end(); ++ri
, ++order
) {
708 boost::shared_ptr
<Route
> route
= (*ri
)[_columns
.route
];
711 int new_key
= route
->order_key (N_ ("editor"));
713 neworder
[new_key
] = old_key
;
715 if (new_key
!= old_key
) {
721 _redisplay_does_not_reset_order_keys
= true;
722 _model
->reorder (neworder
);
723 _redisplay_does_not_reset_order_keys
= false;
729 EditorRoutes::hide_all_tracks (bool /*with_select*/)
731 TreeModel::Children rows
= _model
->children();
732 TreeModel::Children::iterator i
;
734 suspend_redisplay ();
736 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
738 TreeModel::Row row
= (*i
);
739 TimeAxisView
*tv
= row
[_columns
.tv
];
745 row
[_columns
.visible
] = false;
750 /* XXX this seems like a hack and half, but its not clear where to put this
754 //reset_scrolling_region ();
758 EditorRoutes::set_all_tracks_visibility (bool yn
)
760 TreeModel::Children rows
= _model
->children();
761 TreeModel::Children::iterator i
;
763 suspend_redisplay ();
765 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
767 TreeModel::Row row
= (*i
);
768 TimeAxisView
* tv
= row
[_columns
.tv
];
774 (*i
)[_columns
.visible
] = yn
;
781 EditorRoutes::set_all_audio_midi_visibility (int tracks
, bool yn
)
783 TreeModel::Children rows
= _model
->children();
784 TreeModel::Children::iterator i
;
786 suspend_redisplay ();
788 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
790 TreeModel::Row row
= (*i
);
791 TimeAxisView
* tv
= row
[_columns
.tv
];
793 AudioTimeAxisView
* atv
;
794 MidiTimeAxisView
* mtv
;
800 if ((atv
= dynamic_cast<AudioTimeAxisView
*>(tv
)) != 0) {
803 (*i
)[_columns
.visible
] = yn
;
807 if (atv
->is_audio_track()) {
808 (*i
)[_columns
.visible
] = yn
;
813 if (!atv
->is_audio_track()) {
814 (*i
)[_columns
.visible
] = yn
;
819 else if ((mtv
= dynamic_cast<MidiTimeAxisView
*>(tv
)) != 0) {
822 (*i
)[_columns
.visible
] = yn
;
826 if (mtv
->is_midi_track()) {
827 (*i
)[_columns
.visible
] = yn
;
838 EditorRoutes::hide_all_routes ()
840 set_all_tracks_visibility (false);
844 EditorRoutes::show_all_routes ()
846 set_all_tracks_visibility (true);
850 EditorRoutes::show_all_audiotracks()
852 set_all_audio_midi_visibility (1, true);
855 EditorRoutes::hide_all_audiotracks ()
857 set_all_audio_midi_visibility (1, false);
861 EditorRoutes::show_all_audiobus ()
863 set_all_audio_midi_visibility (2, true);
866 EditorRoutes::hide_all_audiobus ()
868 set_all_audio_midi_visibility (2, false);
872 EditorRoutes::show_all_miditracks()
874 set_all_audio_midi_visibility (3, true);
877 EditorRoutes::hide_all_miditracks ()
879 set_all_audio_midi_visibility (3, false);
883 EditorRoutes::key_press (GdkEventKey
* ev
)
886 boost::shared_ptr
<RouteList
> rl (new RouteList
);
889 switch (ev
->keyval
) {
891 case GDK_ISO_Left_Tab
:
893 /* If we appear to be editing something, leave that cleanly and appropriately.
896 name_editable
->editing_done ();
900 col
= _display
.get_column (5); // select&focus on name column
902 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)) {
903 treeview_select_previous (_display
, _model
, col
);
905 treeview_select_next (_display
, _model
, col
);
912 if (get_relevant_routes (rl
)) {
913 _session
->set_mute (rl
, !rl
->front()->muted(), Session::rt_cleanup
);
919 if (get_relevant_routes (rl
)) {
920 _session
->set_solo (rl
, !rl
->front()->soloed(), Session::rt_cleanup
);
926 if (get_relevant_routes (rl
)) {
927 _session
->set_record_enabled (rl
, !rl
->front()->record_enabled(), Session::rt_cleanup
);
939 EditorRoutes::get_relevant_routes (boost::shared_ptr
<RouteList
> rl
)
942 RouteTimeAxisView
* rtv
;
943 RefPtr
<TreeSelection
> selection
= _display
.get_selection();
947 if (selection
->count_selected_rows() != 0) {
951 RefPtr
<TreeModel
> tm
= RefPtr
<TreeModel
>::cast_dynamic (_model
);
952 iter
= selection
->get_selected (tm
);
955 /* use mouse pointer */
960 _display
.get_pointer (x
, y
);
961 _display
.convert_widget_to_bin_window_coords (x
, y
, bx
, by
);
963 if (_display
.get_path_at_pos (bx
, by
, path
)) {
964 iter
= _model
->get_iter (path
);
969 tv
= (*iter
)[_columns
.tv
];
971 rtv
= dynamic_cast<RouteTimeAxisView
*>(tv
);
973 rl
->push_back (rtv
->route());
982 EditorRoutes::button_press (GdkEventButton
* ev
)
984 if (Keyboard::is_context_menu_event (ev
)) {
989 //Scroll editor canvas to selected track
990 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
992 TreeModel::Path path
;
997 _display
.get_path_at_pos ((int) ev
->x
, (int) ev
->y
, path
, tvc
, cell_x
, cell_y
);
999 // Get the model row.
1000 Gtk::TreeModel::Row row
= *_model
->get_iter (path
);
1002 TimeAxisView
*tv
= row
[_columns
.tv
];
1004 int y_pos
= tv
->y_position();
1006 //Clamp the y pos so that we do not extend beyond the canvas full height.
1007 if (_editor
->full_canvas_height
- y_pos
< _editor
->_canvas_height
){
1008 y_pos
= _editor
->full_canvas_height
- _editor
->_canvas_height
;
1011 //Only scroll to if the track is visible
1013 _editor
->reset_y_origin (y_pos
);
1021 EditorRoutes::selection_filter (Glib::RefPtr
<TreeModel
> const &, TreeModel::Path
const&, bool /*selected*/)
1023 if (selection_countdown
) {
1024 if (--selection_countdown
== 0) {
1027 /* no selection yet ... */
1034 struct EditorOrderRouteSorter
{
1035 bool operator() (boost::shared_ptr
<Route
> a
, boost::shared_ptr
<Route
> b
) {
1036 /* use of ">" forces the correct sort order */
1037 return a
->order_key (N_ ("editor")) < b
->order_key (N_ ("editor"));
1042 EditorRoutes::initial_display ()
1044 suspend_redisplay ();
1048 resume_redisplay ();
1052 boost::shared_ptr
<RouteList
> routes
= _session
->get_routes();
1053 RouteList
r (*routes
);
1054 EditorOrderRouteSorter sorter
;
1057 _editor
->handle_new_route (r
);
1059 /* don't show master bus in a new session */
1061 if (ARDOUR_UI::instance()->session_is_new ()) {
1063 TreeModel::Children rows
= _model
->children();
1064 TreeModel::Children::iterator i
;
1066 _no_redisplay
= true;
1068 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1070 TimeAxisView
*tv
= (*i
)[_columns
.tv
];
1071 RouteTimeAxisView
*rtv
;
1073 if ((rtv
= dynamic_cast<RouteTimeAxisView
*>(tv
)) != 0) {
1074 if (rtv
->route()->is_master()) {
1075 _display
.get_selection()->unselect (i
);
1080 _no_redisplay
= false;
1084 resume_redisplay ();
1088 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path
const &, Gtk::TreeModel::iterator
const &, int* /*new_order*/)
1090 _redisplay_does_not_sync_order_keys
= true;
1091 _session
->set_remote_control_ids();
1093 _redisplay_does_not_sync_order_keys
= false;
1097 EditorRoutes::display_drag_data_received (const RefPtr
<Gdk::DragContext
>& context
,
1099 const SelectionData
& data
,
1100 guint info
, guint time
)
1102 if (data
.get_target() == "GTK_TREE_MODEL_ROW") {
1103 _display
.on_drag_data_received (context
, x
, y
, data
, info
, time
);
1107 context
->drag_finish (true, false, time
);
1111 EditorRoutes::move_selected_tracks (bool up
)
1113 if (_editor
->selection
->tracks
.empty()) {
1117 typedef std::pair
<TimeAxisView
*,boost::shared_ptr
<Route
> > ViewRoute
;
1118 std::list
<ViewRoute
> view_routes
;
1119 std::vector
<int> neworder
;
1120 TreeModel::Children rows
= _model
->children();
1121 TreeModel::Children::iterator ri
;
1123 for (ri
= rows
.begin(); ri
!= rows
.end(); ++ri
) {
1124 TimeAxisView
* tv
= (*ri
)[_columns
.tv
];
1125 boost::shared_ptr
<Route
> route
= (*ri
)[_columns
.route
];
1127 view_routes
.push_back (ViewRoute (tv
, route
));
1130 list
<ViewRoute
>::iterator trailing
;
1131 list
<ViewRoute
>::iterator leading
;
1135 trailing
= view_routes
.begin();
1136 leading
= view_routes
.begin();
1140 while (leading
!= view_routes
.end()) {
1141 if (_editor
->selection
->selected (leading
->first
)) {
1142 view_routes
.insert (trailing
, ViewRoute (leading
->first
, leading
->second
));
1143 leading
= view_routes
.erase (leading
);
1152 /* if we could use reverse_iterator in list::insert, this code
1153 would be a beautiful reflection of the code above. but we can't
1154 and so it looks like a bit of a mess.
1157 trailing
= view_routes
.end();
1158 leading
= view_routes
.end();
1160 --leading
; if (leading
== view_routes
.begin()) { return; }
1166 if (_editor
->selection
->selected (leading
->first
)) {
1167 list
<ViewRoute
>::iterator tmp
;
1169 /* need to insert *after* trailing, not *before* it,
1170 which is what insert (iter, val) normally does.
1176 view_routes
.insert (tmp
, ViewRoute (leading
->first
, leading
->second
));
1178 /* can't use iter = cont.erase (iter); form here, because
1179 we need iter to move backwards.
1187 if (leading
== view_routes
.begin()) {
1188 /* the one we've just inserted somewhere else
1189 was the first in the list. erase this copy,
1190 and then break, because we're done.
1195 view_routes
.erase (leading
);
1204 if (leading
== view_routes
.begin()) {
1213 for (leading
= view_routes
.begin(); leading
!= view_routes
.end(); ++leading
) {
1214 neworder
.push_back (leading
->second
->order_key (N_ ("editor")));
1217 _model
->reorder (neworder
);
1219 _session
->sync_order_keys (N_ ("editor"));
1223 EditorRoutes::update_rec_display ()
1225 TreeModel::Children rows
= _model
->children();
1226 TreeModel::Children::iterator i
;
1228 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1229 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1231 if (boost::dynamic_pointer_cast
<Track
> (route
)) {
1232 boost::shared_ptr
<MidiTrack
> mt
= boost::dynamic_pointer_cast
<MidiTrack
> (route
);
1234 if (route
->record_enabled()) {
1235 if (_session
->record_status() == Session::Recording
) {
1236 (*i
)[_columns
.rec_state
] = 1;
1238 (*i
)[_columns
.rec_state
] = 2;
1240 } else if (mt
&& mt
->step_editing()) {
1241 (*i
)[_columns
.rec_state
] = 3;
1243 (*i
)[_columns
.rec_state
] = 0;
1246 (*i
)[_columns
.name_editable
] = !route
->record_enabled ();
1252 EditorRoutes::update_mute_display ()
1254 TreeModel::Children rows
= _model
->children();
1255 TreeModel::Children::iterator i
;
1257 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1258 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1259 (*i
)[_columns
.mute_state
] = RouteUI::mute_visual_state (_session
, route
);
1264 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1266 TreeModel::Children rows
= _model
->children();
1267 TreeModel::Children::iterator i
;
1269 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1270 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1271 (*i
)[_columns
.solo_state
] = RouteUI::solo_visual_state (route
);
1276 EditorRoutes::update_solo_isolate_display ()
1278 TreeModel::Children rows
= _model
->children();
1279 TreeModel::Children::iterator i
;
1281 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1282 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1283 (*i
)[_columns
.solo_isolate_state
] = RouteUI::solo_isolate_visual_state (route
) > 0 ? 1 : 0;
1288 EditorRoutes::update_solo_safe_display ()
1290 TreeModel::Children rows
= _model
->children();
1291 TreeModel::Children::iterator i
;
1293 for (i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1294 boost::shared_ptr
<Route
> route
= (*i
)[_columns
.route
];
1295 (*i
)[_columns
.solo_safe_state
] = RouteUI::solo_safe_visual_state (route
) > 0 ? 1 : 0;
1300 EditorRoutes::views () const
1302 list
<TimeAxisView
*> v
;
1303 for (TreeModel::Children::iterator i
= _model
->children().begin(); i
!= _model
->children().end(); ++i
) {
1304 v
.push_back ((*i
)[_columns
.tv
]);
1311 EditorRoutes::clear ()
1313 _display
.set_model (Glib::RefPtr
<Gtk::TreeStore
> (0));
1315 _display
.set_model (_model
);
1319 EditorRoutes::name_edit_started (CellEditable
* ce
, const Glib::ustring
&)
1323 /* give it a special name */
1325 Gtk::Entry
*e
= dynamic_cast<Gtk::Entry
*> (ce
);
1328 e
->set_name (X_("RouteNameEditorEntry"));
1333 EditorRoutes::name_edit (std::string
const & path
, std::string
const & new_text
)
1337 TreeIter iter
= _model
->get_iter (path
);
1343 boost::shared_ptr
<Route
> route
= (*iter
)[_columns
.route
];
1345 if (route
&& route
->name() != new_text
) {
1346 route
->set_name (new_text
);
1351 EditorRoutes::solo_changed_so_update_mute ()
1353 update_mute_display ();
1357 EditorRoutes::show_tracks_with_regions_at_playhead ()
1359 boost::shared_ptr
<RouteList
> const r
= _session
->get_routes_with_regions_at (_session
->transport_frame ());
1361 set
<TimeAxisView
*> show
;
1362 for (RouteList::const_iterator i
= r
->begin(); i
!= r
->end(); ++i
) {
1363 TimeAxisView
* tav
= _editor
->axis_view_from_route (*i
);
1369 suspend_redisplay ();
1371 TreeModel::Children rows
= _model
->children ();
1372 for (TreeModel::Children::iterator i
= rows
.begin(); i
!= rows
.end(); ++i
) {
1373 TimeAxisView
* tv
= (*i
)[_columns
.tv
];
1374 (*i
)[_columns
.visible
] = (show
.find (tv
) != show
.end());
1377 resume_redisplay ();