diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index e4ab55365b..dd5b5b2a96 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -353,6 +353,8 @@ Editor::Editor () , edit_controls_left_menu (0) , edit_controls_right_menu (0) , visual_change_queued(false) + , _tvl_no_redisplay(false) + , _tvl_redisplay_on_resume(false) , _last_update_time (0) , _err_screen_engine (0) , cut_buffer_start (0) @@ -1337,7 +1339,7 @@ Editor::set_session (Session *t) _regions->set_session (_session); _sources->set_session (_session); _snapshots->set_session (_session); - _routes->set_session (_session); + //_routes->set_session (_session); // temp disabled for EditorRoutes update _locations->set_session (_session); _properties_box->set_session (_session); @@ -1353,6 +1355,7 @@ Editor::set_session (Session *t) sfbrowser->set_session (_session); } + initial_display (); compute_fixed_ruler_scale (); /* Make sure we have auto loop and auto punch ranges */ @@ -4762,7 +4765,7 @@ Editor::use_visual_state (VisualState& vs) } } - _routes->update_visibility (); + // TODO push state to PresentationInfo, force update ? } /** This is the core function that controls the zoom level of the canvas. It is called @@ -5410,7 +5413,7 @@ Editor::first_idle () selection->set (rs); /* first idle adds route children (automation tracks), so we need to redisplay here */ - _routes->redisplay (); + redisplay_track_views (); delete dialog; @@ -5586,20 +5589,35 @@ Editor::axis_views_from_routes (boost::shared_ptr r) const void Editor::suspend_route_redisplay () { - if (_routes) { - _routes->suspend_redisplay(); + _tvl_no_redisplay = true; +} + +void +Editor::queue_redisplay_track_views () +{ + if (!_tvl_redisplay_connection.connected ()) { + _tvl_redisplay_connection = Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::redisplay_track_views)); } } void Editor::resume_route_redisplay () { - if (_routes) { - _routes->redisplay(); // queue redisplay - _routes->resume_redisplay(); + _tvl_no_redisplay = false; + if (_tvl_redisplay_on_resume) { + queue_redisplay_track_views (); } } +void +Editor::initial_display () +{ + DisplaySuspender ds; + StripableList s; + _session->get_stripables (s); + add_stripables (s); +} + void Editor::add_vcas (VCAList& vlist) { @@ -5627,10 +5645,10 @@ Editor::add_routes (RouteList& rlist) void Editor::add_stripables (StripableList& sl) { - list new_views; boost::shared_ptr v; boost::shared_ptr r; TrackViewList new_selection; + bool changed = false; bool from_scratch = (track_views.size() == 0); sl.sort (Stripable::Sorter()); @@ -5645,7 +5663,10 @@ Editor::add_stripables (StripableList& sl) VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas); vtv->set_vca (v); - new_views.push_back (vtv); + track_views.push_back (vtv); + + (*s)->gui_changed.connect (*this, invalidator (*this), boost::bind (&Editor::handle_gui_changes, this, _1, _2), gui_context()); + changed = true; } else if ((r = boost::dynamic_pointer_cast (*s)) != 0) { @@ -5666,7 +5687,6 @@ Editor::add_stripables (StripableList& sl) throw unknown_type(); } - new_views.push_back (rtv); track_views.push_back (rtv); new_selection.push_back (rtv); @@ -5674,12 +5694,13 @@ Editor::add_stripables (StripableList& sl) rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added)); rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed)); + (*s)->gui_changed.connect (*this, invalidator (*this), boost::bind (&Editor::handle_gui_changes, this, _1, _2), gui_context()); + changed = true; } } - if (new_views.size() > 0) { - _routes->time_axis_views_added (new_views); - //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */ + if (changed) { + queue_redisplay_track_views (); } /* note: !new_selection.empty() means that we got some routes rather @@ -5719,8 +5740,6 @@ Editor::timeaxisview_deleted (TimeAxisView *tv) RouteTimeAxisView* rtav = dynamic_cast (tv); - _routes->route_removed (tv); - TimeAxisView::Children c = tv->get_child_list (); for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) { if (entered_track == i->get()) { @@ -5806,6 +5825,9 @@ Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection) } if (rtv) { rtv->route()->presentation_info().set_hidden (true); + /* TODO also handle Routegroups IFF (rg->is_hidden() && !rg->is_selection()) + * selection currently unconditionally hides due to above if() clause :( + */ } } } @@ -5819,21 +5841,92 @@ Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view) RouteTimeAxisView* rtv = dynamic_cast (tv); if (rtv) { rtv->route()->presentation_info().set_hidden (false); +#if 0 // TODO see above + RouteGroup* rg = rtv->route ()->route_group (); + if (rg && rg->is_active () && rg->is_hidden () && !rg->is_select ()) { + boost::shared_ptr rl (rg->route_list ()); + for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) { + (*i)->presentation_info().set_hidden (false); + } + } +#endif } if (move_into_view) { ensure_time_axis_view_is_visible (*tv, false); } } -bool -Editor::sync_track_view_list_and_routes () +struct TrackViewStripableSorter { - track_views = TrackViewList (_routes->views ()); + bool operator() (const TimeAxisView* tav_a, const TimeAxisView *tav_b) + { + StripableTimeAxisView const* stav_a = dynamic_cast(tav_a); + StripableTimeAxisView const* stav_b = dynamic_cast(tav_b); + assert (stav_a && stav_b); + + boost::shared_ptr const& a = stav_a->stripable (); + boost::shared_ptr const& b = stav_b->stripable (); + return ARDOUR::Stripable::Sorter () (a, b); + } +}; + +bool +Editor::redisplay_track_views () +{ + if (!_session || _session->deletion_in_progress()) { + return false; + } + + if (_tvl_no_redisplay) { + _tvl_redisplay_on_resume = true; + return false; + } + + TrackViewStripableSorter cmp; + track_views.sort (cmp); + + uint32_t position; + TrackViewList::const_iterator i; + + /* n will be the count of tracks plus children (updated by TimeAxisView::show_at), + * so we will use that to know where to put things. + */ + int n; + for (n = 0, position = 0, i = track_views.begin(); i != track_views.end(); ++i) { + TimeAxisView *tv = (*i); + + if (tv->marked_for_display ()) { + position += tv->show_at (position, n, &edit_controls_vbox); + } else { + tv->hide (); + } + n++; + } + + reset_controls_layout_height (position); + reset_controls_layout_width (); + _full_canvas_height = position; + + if ((vertical_adjustment.get_value() + _visible_canvas_height) > 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. + */ + vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height); + } _summary->set_background_dirty(); _group_tabs->set_dirty (); - return false; // do not call again (until needed) + return false; +} + +void +Editor::handle_gui_changes (string const & what, void*) +{ + if (what == "track_height" || what == "visible_tracks") { + queue_redisplay_track_views (); + } } void diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 4bc060616f..874a85b927 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -868,6 +868,7 @@ private: void popup_note_context_menu (ArdourCanvas::Item*, GdkEvent*); Gtk::Menu _note_context_menu; + void initial_display (); void add_stripables (ARDOUR::StripableList&); void add_routes (ARDOUR::RouteList&); void timeaxisview_deleted (TimeAxisView*); @@ -1222,6 +1223,7 @@ private: /* track views */ TrackViewList track_views; + std::pair trackview_by_y_position (double, bool trackview_relative_offset = true) const; AxisView* axis_view_by_stripable (boost::shared_ptr) const; @@ -1233,6 +1235,14 @@ private: TrackViewList get_tracks_for_range_action () const; + Gtk::VBox list_vpacker; + void queue_redisplay_track_views (); + bool redisplay_track_views (); + + bool _tvl_no_redisplay; + bool _tvl_redisplay_on_resume; + sigc::connection _tvl_redisplay_connection; + sigc::connection super_rapid_screen_update_connection; void center_screen_internal (samplepos_t, float); @@ -1533,6 +1543,7 @@ private: void scroll_forward (float pages=0.8f); void scroll_tracks_down (); void scroll_tracks_up (); + void move_selected_tracks (bool); void set_mark (); void clear_markers (); void clear_xrun_markers (); @@ -1995,6 +2006,7 @@ private: void track_selection_changed (); void update_time_selection_display (); void presentation_info_changed (PBD::PropertyChange const &); + void handle_gui_changes (std::string const&, void*); void region_selection_changed (); void catch_up_on_midi_selection (); sigc::connection editor_regions_selection_changed_connection; @@ -2065,10 +2077,6 @@ private: Glib::RefPtr route_display_selection; - bool sync_track_view_list_and_routes (); - - Gtk::VBox list_vpacker; - /* autoscrolling */ sigc::connection autoscroll_connection; diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 07d9819d1a..c94e93821d 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -327,9 +327,9 @@ Editor::register_actions () reg_sens (editor_actions, "zoom_5_min", _("Zoom to 5 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 5 * 60 * 1000)); reg_sens (editor_actions, "zoom_10_min", _("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)); - act = reg_sens (editor_actions, "move-selected-tracks-up", _("Move Selected Tracks Up"), sigc::bind (sigc::mem_fun(*_routes, &EditorRoutes::move_selected_tracks), true)); + act = reg_sens (editor_actions, "move-selected-tracks-up", _("Move Selected Tracks Up"), sigc::bind (sigc::mem_fun(*this, &Editor::move_selected_tracks), true)); ActionManager::stripable_selection_sensitive_actions.push_back (act); - act = reg_sens (editor_actions, "move-selected-tracks-down", _("Move Selected Tracks Down"), sigc::bind (sigc::mem_fun(*_routes, &EditorRoutes::move_selected_tracks), false)); + act = reg_sens (editor_actions, "move-selected-tracks-down", _("Move Selected Tracks Down"), sigc::bind (sigc::mem_fun(*this, &Editor::move_selected_tracks), false)); ActionManager::stripable_selection_sensitive_actions.push_back (act); act = reg_sens (editor_actions, "scroll-tracks-up", _("Scroll Tracks Up"), sigc::mem_fun(*this, &Editor::scroll_tracks_up)); diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc index 3a9e4f3f63..157188e966 100644 --- a/gtk2_ardour/editor_routes.cc +++ b/gtk2_ardour/editor_routes.cc @@ -618,7 +618,7 @@ EditorRoutes::redisplay_real () * we can't do this here, because we could mess up something that is traversing * the track order and has caused a redisplay of the list. */ - Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes)); + //Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes)); _editor->reset_controls_layout_height (position); _editor->reset_controls_layout_width (); diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 8a73074af2..7e54d8f93f 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -1234,16 +1234,15 @@ Editor::presentation_info_changed (PropertyChange const & what_changed) } } - /* STEP 4: update EditorRoutes treeview */ + /* STEP 4: update Editor::track_views */ PropertyChange soh; - soh.add (Properties::selected); soh.add (Properties::order); soh.add (Properties::hidden); if (what_changed.contains (soh)) { - _routes->sync_treeview_from_presentation_info (what_changed); + queue_redisplay_track_views (); } } @@ -2349,3 +2348,118 @@ Editor::catch_up_on_midi_selection () selection->set (regions); } } + +struct ViewStripable { + TimeAxisView* tav; + boost::shared_ptr stripable; + + ViewStripable (TimeAxisView* t, boost::shared_ptr s) + : tav (t), stripable (s) {} +}; + +void +Editor::move_selected_tracks (bool up) +{ + TimeAxisView* scroll_to = 0; + StripableList sl; + _session->get_stripables (sl); + + if (sl.size() < 2) { + /* nope */ + return; + } + + sl.sort (Stripable::Sorter()); + + std::list view_stripables; + + /* build a list that includes time axis view information */ + + for (StripableList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) { + TimeAxisView* tv = time_axis_view_from_stripable (*sli); + view_stripables.push_back (ViewStripable (tv, *sli)); + } + + /* for each selected stripable, move it above or below the adjacent + * stripable that has a time-axis view representation here. If there's + * no such representation, then + */ + + list::iterator unselected_neighbour; + list::iterator vsi; + + { + PresentationInfo::ChangeSuspender cs; + + if (up) { + unselected_neighbour = view_stripables.end (); + vsi = view_stripables.begin(); + + while (vsi != view_stripables.end()) { + + if (vsi->stripable->is_selected()) { + + if (unselected_neighbour != view_stripables.end()) { + + PresentationInfo::order_t unselected_neighbour_order = unselected_neighbour->stripable->presentation_info().order(); + PresentationInfo::order_t my_order = vsi->stripable->presentation_info().order(); + + unselected_neighbour->stripable->set_presentation_order (my_order); + vsi->stripable->set_presentation_order (unselected_neighbour_order); + + if (!scroll_to) { + scroll_to = vsi->tav; + } + } + + } else { + + if (vsi->tav) { + unselected_neighbour = vsi; + } + + } + + ++vsi; + } + + } else { + + unselected_neighbour = view_stripables.end(); + vsi = unselected_neighbour; + + do { + + --vsi; + + if (vsi->stripable->is_selected()) { + + if (unselected_neighbour != view_stripables.end()) { + + PresentationInfo::order_t unselected_neighbour_order = unselected_neighbour->stripable->presentation_info().order(); + PresentationInfo::order_t my_order = vsi->stripable->presentation_info().order(); + + unselected_neighbour->stripable->set_presentation_order (my_order); + vsi->stripable->set_presentation_order (unselected_neighbour_order); + + if (!scroll_to) { + scroll_to = vsi->tav; + } + } + + } else { + + if (vsi->tav) { + unselected_neighbour = vsi; + } + + } + + } while (vsi != view_stripables.begin()); + } + } + + if (scroll_to) { + ensure_time_axis_view_is_visible (*scroll_to, false); + } +}