using namespace std;
using namespace ARDOUR;
+using namespace ARDOUR_UI_UTILS;
using namespace PBD;
using namespace Gtk;
using namespace Gtkmm2ext;
, _ignore_reorder (false)
, _no_redisplay (false)
, _adding_routes (false)
+ , _route_deletion_in_progress (false)
, _menu (0)
, old_focus (0)
, selection_countdown (0)
_display.set_headers_visible (true);
_display.get_selection()->set_mode (SELECTION_SINGLE);
_display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
+ _display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::selection_changed));
_display.set_reorderable (true);
_display.set_name (X_("EditGroupList"));
_display.set_rules_hint (true);
active_col->set_fixed_width (30);
active_col->set_alignment (ALIGN_CENTER);
- _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
+ _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::row_deleted));
_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
_display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
void
EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
{
+ DisplaySuspender ds;
// Get the model row that has been toggled.
Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
void
EditorRoutes::redisplay ()
{
- if (_no_redisplay || !_session || _session->deletion_in_progress()) {
+ if (_no_redisplay || !_session || _session->deletion_in_progress() || _redisplaying) {
return;
}
+ _redisplaying = true; // tv->show_at() below causes recursive redisplay via handle_gui_changes()
TreeModel::Children rows = _model->children();
TreeModel::Children::iterator i;
/* show or hide the TimeAxisView */
if (visible) {
position += tv->show_at (position, n, &_editor->edit_controls_vbox);
- tv->clip_to_viewport ();
} else {
tv->hide ();
}
_editor->reset_controls_layout_height (position);
_editor->reset_controls_layout_width ();
- _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
- _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
+ _editor->_full_canvas_height = position;
- if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
+ if ((_editor->vertical_adjustment.get_value() + _editor->_visible_canvas_height) > _editor->vertical_adjustment.get_upper()) {
/*
We're increasing the size of the canvas while the bottom is visible.
We scroll down to keep in step with the controls layout.
*/
- _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
+ _editor->vertical_adjustment.set_value (_editor->_full_canvas_height - _editor->_visible_canvas_height);
}
+ _redisplaying = false;
}
void
-EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
+EditorRoutes::row_deleted (Gtk::TreeModel::Path const &)
{
- /* this happens as the second step of a DnD within the treeview as well
- as when a row/route is actually deleted.
+ /* this happens as the second step of a DnD within the treeview, and
+ when a route is actually removed. we don't differentiate between
+ the two cases.
+
+ note that the sync_orders_keys() step may not actually change any
+ RID's (e.g. the last track may be removed, so all other tracks keep
+ the same RID), which means that no redisplay would happen. so we
+ have to force a redisplay.
*/
+
DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
+
+ DisplaySuspender ds;
sync_order_keys_from_treeview ();
}
void
EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
{
+ /* reordering implies that RID's will change, so sync_order_keys() will
+ cause a redisplay.
+ */
+
DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
sync_order_keys_from_treeview ();
}
return;
}
+ DisplaySuspender ds;
TreeIter iter;
if ((iter = _model->get_iter (path))) {
void
EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
{
- TreeModel::Row row;
PBD::Unwinder<bool> at (_adding_routes, true);
- suspend_redisplay ();
+ bool from_scratch = (_model->children().size() == 0);
+ Gtk::TreeModel::Children::iterator insert_iter = _model->children().end();
+
+ for (Gtk::TreeModel::Children::iterator it = _model->children().begin(); it != _model->children().end(); ++it) {
+ boost::shared_ptr<Route> r = (*it)[_columns.route];
+
+ if (r->order_key() == (routes.front()->route()->order_key() + routes.size())) {
+ insert_iter = it;
+ break;
+ }
+ }
+
+ if(!from_scratch) {
+ _editor->selection->tracks.clear();
+ }
+
+ DisplaySuspender ds;
_display.set_model (Glib::RefPtr<ListStore>());
boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
- row = *(_model->append ());
+ TreeModel::Row row = *(_model->insert (insert_iter));
row[_columns.text] = (*x)->route()->name();
row[_columns.visible] = (*x)->marked_for_display();
row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
row[_columns.name_editable] = true;
+ if (!from_scratch) {
+ _editor->selection->add(*x);
+ }
+
boost::weak_ptr<Route> wr ((*x)->route());
(*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
}
- if ((*x)->is_midi_track()) {
- boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
+ if ((*x)->is_midi_track()) {
+ boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
- t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
- }
-
+ t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
+ }
+
(*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
(*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
(*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
update_input_active_display ();
update_active_display ();
- resume_redisplay ();
_display.set_model (_model);
/* now update route order keys from the treeview/track display order */
/* Optional :make tracks change height while it happens, instead
of on first-idle
*/
- //update_canvas_now ();
redisplay ();
}
for (ri = rows.begin(); ri != rows.end(); ++ri) {
if ((*ri)[_columns.tv] == tv) {
+ PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
_model->erase (ri);
break;
}
void
EditorRoutes::update_active_display ()
{
- TreeModel::Children rows = _model->children();
- TreeModel::Children::iterator i;
-
- for (i = rows.begin(); i != rows.end(); ++i) {
- boost::shared_ptr<Route> route = (*i)[_columns.route];
- (*i)[_columns.active] = route->active ();
+ if (_queue_mute_rec_solo_etc == 0) {
+ Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
}
+ _queue_mute_rec_solo_etc |= 16;
}
void
TreeModel::Children rows = _model->children();
TreeModel::Children::iterator i;
- suspend_redisplay ();
+ DisplaySuspender ds ();
for (i = rows.begin(); i != rows.end(); ++i) {
TimeAxisView *tv = (*i)[_columns.tv];
*/
sync_order_keys_from_treeview ();
-
- resume_redisplay ();
}
void
TreeModel::Children rows = _model->children();
TreeModel::Children::iterator i;
- suspend_redisplay ();
+ DisplaySuspender ds;
for (i = rows.begin(); i != rows.end(); ++i) {
row[_columns.visible] = false;
}
-
- resume_redisplay ();
-
- /* XXX this seems like a hack and half, but its not clear where to put this
- otherwise.
- */
-
- //reset_scrolling_region ();
}
void
TreeModel::Children rows = _model->children();
TreeModel::Children::iterator i;
- suspend_redisplay ();
+ DisplaySuspender ds;
for (i = rows.begin(); i != rows.end(); ++i) {
*/
sync_order_keys_from_treeview ();
-
- resume_redisplay ();
}
void
TreeModel::Children rows = _model->children();
TreeModel::Children::iterator i;
- suspend_redisplay ();
+ DisplaySuspender ds;
for (i = rows.begin(); i != rows.end(); ++i) {
*/
sync_order_keys_from_treeview ();
-
- resume_redisplay ();
}
void
//Scroll editor canvas to selected track
if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
- // Get the model row.
Gtk::TreeModel::Row row = *_model->get_iter (path);
-
TimeAxisView *tv = row[_columns.tv];
- int y_pos = tv->y_position();
-
- //Clamp the y pos so that we do not extend beyond the canvas full height.
- if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
- y_pos = _editor->full_canvas_height - _editor->_canvas_height;
- }
-
- //Only scroll to if the track is visible
- if(y_pos != -1){
- _editor->reset_y_origin (y_pos);
+ if (tv) {
+ _editor->ensure_time_axis_view_is_visible (*tv, true);
}
}
return false;
}
+void
+EditorRoutes::selection_changed ()
+{
+ if (_display.get_selection()->count_selected_rows() > 0) {
+
+ TreeIter iter;
+ TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows ();
+ TrackViewList selected;
+
+ _editor->get_selection().clear_regions ();
+
+ for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
+
+ if ((iter = _model->get_iter (*i))) {
+
+ TimeAxisView* tv = (*iter)[_columns.tv];
+ selected.push_back (tv);
+ }
+
+ }
+
+ _editor->get_selection().set (selected);
+ _editor->ensure_time_axis_view_is_visible (*(selected.front()), true);
+
+ } else {
+ _editor->get_selection().clear_tracks ();
+ }
+}
+
bool
EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
{
void
EditorRoutes::initial_display ()
{
- suspend_redisplay ();
+ DisplaySuspender ds;
_model->clear ();
if (!_session) {
- resume_redisplay ();
return;
}
_editor->add_routes (r);
}
-
- resume_redisplay ();
}
void
void
EditorRoutes::update_rec_display ()
{
+ if (_queue_mute_rec_solo_etc == 0) {
+ Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
+ }
+ _queue_mute_rec_solo_etc |= 32;
+}
+
+bool
+EditorRoutes::idle_update_mute_rec_solo_etc()
+{
+ const int what = _queue_mute_rec_solo_etc;
+ _queue_mute_rec_solo_etc = 0;
TreeModel::Children rows = _model->children();
TreeModel::Children::iterator i;
for (i = rows.begin(); i != rows.end(); ++i) {
boost::shared_ptr<Route> route = (*i)[_columns.route];
-
- if (boost::dynamic_pointer_cast<Track> (route)) {
- boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
-
- if (route->record_enabled()) {
- if (_session->record_status() == Session::Recording) {
- (*i)[_columns.rec_state] = 1;
+ if (what & 1) {
+ (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
+ }
+ if (what & 2) {
+ (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
+ }
+ if (what & 4) {
+ (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
+ }
+ if (what & 8) {
+ (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
+ }
+ if (what & 16) {
+ (*i)[_columns.active] = route->active ();
+ }
+ if (what & 32) { // rec
+
+ if (boost::dynamic_pointer_cast<Track> (route)) {
+ boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
+
+ if (route->record_enabled()) {
+ if (_session->record_status() == Session::Recording) {
+ (*i)[_columns.rec_state] = 1;
+ } else {
+ (*i)[_columns.rec_state] = 2;
+ }
+ } else if (mt && mt->step_editing()) {
+ (*i)[_columns.rec_state] = 3;
} else {
- (*i)[_columns.rec_state] = 2;
+ (*i)[_columns.rec_state] = 0;
}
- } else if (mt && mt->step_editing()) {
- (*i)[_columns.rec_state] = 3;
- } else {
- (*i)[_columns.rec_state] = 0;
- }
- (*i)[_columns.name_editable] = !route->record_enabled ();
+ (*i)[_columns.name_editable] = !route->record_enabled ();
+ }
}
}
+ return false; // do not call again (until needed)
}
+
void
EditorRoutes::update_mute_display ()
{
- TreeModel::Children rows = _model->children();
- TreeModel::Children::iterator i;
-
- for (i = rows.begin(); i != rows.end(); ++i) {
- boost::shared_ptr<Route> route = (*i)[_columns.route];
- (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
+ if (_queue_mute_rec_solo_etc == 0) {
+ Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
}
+ _queue_mute_rec_solo_etc |= 1;
}
void
EditorRoutes::update_solo_display (bool /* selfsoloed */)
{
- TreeModel::Children rows = _model->children();
- TreeModel::Children::iterator i;
-
- for (i = rows.begin(); i != rows.end(); ++i) {
- boost::shared_ptr<Route> route = (*i)[_columns.route];
- (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
+ if (_queue_mute_rec_solo_etc == 0) {
+ Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
}
+ _queue_mute_rec_solo_etc |= 2;
}
void
EditorRoutes::update_solo_isolate_display ()
{
- TreeModel::Children rows = _model->children();
- TreeModel::Children::iterator i;
-
- for (i = rows.begin(); i != rows.end(); ++i) {
- boost::shared_ptr<Route> route = (*i)[_columns.route];
- (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
+ if (_queue_mute_rec_solo_etc == 0) {
+ Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
}
+ _queue_mute_rec_solo_etc |= 4;
}
void
EditorRoutes::update_solo_safe_display ()
{
- TreeModel::Children rows = _model->children();
- TreeModel::Children::iterator i;
-
- for (i = rows.begin(); i != rows.end(); ++i) {
- boost::shared_ptr<Route> route = (*i)[_columns.route];
- (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
+ if (_queue_mute_rec_solo_etc == 0) {
+ Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
}
+ _queue_mute_rec_solo_etc |= 4;
}
list<TimeAxisView*>
}
}
- suspend_redisplay ();
+ DisplaySuspender ds;
TreeModel::Children rows = _model->children ();
for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
TimeAxisView* tv = (*i)[_columns.tv];
(*i)[_columns.visible] = (show.find (tv) != show.end());
}
-
- resume_redisplay ();
}
-