diff options
-rw-r--r-- | gtk2_ardour/automation_line.cc | 58 | ||||
-rw-r--r-- | gtk2_ardour/automation_line.h | 1 | ||||
-rw-r--r-- | gtk2_ardour/automation_selectable.h | 6 | ||||
-rw-r--r-- | gtk2_ardour/editor.h | 8 | ||||
-rw-r--r-- | gtk2_ardour/editor_selection.cc | 108 | ||||
-rw-r--r-- | gtk2_ardour/selection.cc | 10 | ||||
-rw-r--r-- | gtk2_ardour/selection.h | 6 |
7 files changed, 131 insertions, 66 deletions
diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index c6cedb1c48..b304dcf2d4 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -1037,50 +1037,54 @@ AutomationLine::get_inverted_selectables (Selection&, list<Selectable*>& /*resul // hmmm .... } -void -AutomationLine::set_selected_points (PointSelection& points) +/** Take a PointSelection and find ControlPoints that fall within it */ +list<ControlPoint*> +AutomationLine::point_selection_to_control_points (PointSelection const & s) { - double top; - double bot; - - for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->set_selected(false); - } - - if (points.empty()) { - goto out; - } - - for (PointSelection::iterator r = points.begin(); r != points.end(); ++r) { + list<ControlPoint*> cp; + + for (PointSelection::const_iterator i = s.begin(); i != s.end(); ++i) { - if ((*r).track != &trackview) { + if (i->track != &trackview) { continue; } /* Curse X11 and its inverted coordinate system! */ - bot = (1.0 - (*r).high_fract) * _height; - top = (1.0 - (*r).low_fract) * _height; + double const bot = (1.0 - i->high_fract) * _height; + double const top = (1.0 - i->low_fract) * _height; - for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { + for (vector<ControlPoint*>::iterator j = control_points.begin(); j != control_points.end(); ++j) { - double rstart, rend; + double const rstart = trackview.editor().frame_to_unit (i->start); + double const rend = trackview.editor().frame_to_unit (i->end); - rstart = trackview.editor().frame_to_unit ((*r).start); - rend = trackview.editor().frame_to_unit ((*r).end); + if ((*j)->get_x() >= rstart && (*j)->get_x() <= rend) { + if ((*j)->get_y() >= bot && (*j)->get_y() <= top) { + cp.push_back (*j); + } + } + } - if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) { + } - if ((*i)->get_y() >= bot && (*i)->get_y() <= top) { + return cp; +} - (*i)->set_selected(true); - } - } +void +AutomationLine::set_selected_points (PointSelection& points) +{ + for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { + (*i)->set_selected (false); + } + if (!points.empty()) { + list<ControlPoint*> cp = point_selection_to_control_points (points); + for (list<ControlPoint*>::iterator i = cp.begin(); i != cp.end(); ++i) { + (*i)->set_selected (true); } } - out: set_colors (); } diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index 484ecfd3ee..a4b0013d37 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -64,6 +64,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible void reset (); void clear(); + std::list<ControlPoint*> point_selection_to_control_points (PointSelection const &); void set_selected_points (PointSelection&); void get_selectables (nframes_t& start, nframes_t& end, double botfrac, double topfrac, diff --git a/gtk2_ardour/automation_selectable.h b/gtk2_ardour/automation_selectable.h index 92e73a3c33..7104f6adf4 100644 --- a/gtk2_ardour/automation_selectable.h +++ b/gtk2_ardour/automation_selectable.h @@ -25,6 +25,12 @@ class TimeAxisView; +/** A selected automation point, expressed as a rectangle on a track (so that x coordinates + * are frames and y coordinates are a fraction of track height). This representation falls + * between the visible GUI control points and the back-end "actual" automation points, + * some of which may not be visible; it is not trivial to convert from one of these to the other, + * so the AutomationSelectable is a kind of "best and worst of both worlds". + */ struct AutomationSelectable : public Selectable { nframes_t start; diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 14e6b1b68d..a43bfa4383 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1630,7 +1630,13 @@ public: /* object rubberband select process */ - bool select_all_within (nframes64_t start, nframes64_t end, gdouble topy, gdouble boty, const TrackViewList&, Selection::Operation op); + std::pair<std::list<Selectable*>, TrackViewList> find_selectables_within ( + nframes64_t, nframes64_t, double, double, TrackViewList const & + ); + + bool select_selectables_and_tracks (std::list<Selectable*> const &, TrackViewList const &, Selection::Operation); + + bool select_all_within (nframes64_t, nframes64_t, double, double, TrackViewList const &, Selection::Operation op); ArdourCanvas::SimpleRect *rubberband_rect; diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 140856efd2..ab9cce74e1 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -242,15 +242,11 @@ Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*n return false; } - /* select this point and any others that it represents */ - - double y1, y2; - nframes64_t x1, x2; - - x1 = pixel_to_frame (clicked_control_point->get_x() - 10); - x2 = pixel_to_frame (clicked_control_point->get_x() + 10); - y1 = clicked_control_point->get_y() - 10; - y2 = clicked_control_point->get_y() + 10; + /* rectangle 10 pixels surrounding the clicked control point */ + nframes64_t const x1 = pixel_to_frame (clicked_control_point->get_x() - 10); + nframes64_t const x2 = pixel_to_frame (clicked_control_point->get_x() + 10); + double y1 = clicked_control_point->get_y() - 10; + double y2 = clicked_control_point->get_y() + 10; /* convert the y values to trackview space */ double dummy = 0; @@ -259,7 +255,36 @@ Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*n _trackview_group->w2i (dummy, y1); _trackview_group->w2i (dummy, y2); - return select_all_within (x1, x2, y1, y2, selection->tracks, op); + /* find any other points nearby */ + pair<list<Selectable*>, TrackViewList> const f = find_selectables_within (x1, x2, y1, y2, selection->tracks); + + PointSelection ps; + for (list<Selectable*>::const_iterator i = f.first.begin(); i != f.first.end(); ++i) { + AutomationSelectable* a = dynamic_cast<AutomationSelectable*> (*i); + if (a) { + ps.push_back (*a); + } + } + + list<ControlPoint*> const cp = clicked_control_point->line().point_selection_to_control_points (ps); + list<ControlPoint*>::const_iterator i = cp.begin (); + while (i != cp.end() && (*i)->selected() == false) { + ++i; + } + + if (i != cp.end()) { + /* one of the control points that we just clicked on is already selected, + so leave the selection alone. + */ + + for (list<Selectable*>::const_iterator i = f.first.begin(); i != f.first.end(); ++i) { + delete *i; + } + + return true; + } + + return select_selectables_and_tracks (f.first, f.second, op); } void @@ -965,45 +990,68 @@ Editor::invert_selection () selection->set (touched); } -/** @param top Top (lower) y limit in trackview coordinates. - * @param bottom Bottom (higher) y limit in trackview coordinates. +/** Find Selectable things within an area. + * @param start Start temporal position (session frames) + * @param end End temporal position (session frames) + * @param top Top (lower) y position (trackview coordinates) + * @param bot Bottom (higher) y position (trackview coordinates) + * @return Selectable things and tracks that they are on. */ -bool -Editor::select_all_within (nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op) +pair<list<Selectable*>, TrackViewList> +Editor::find_selectables_within (nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist) { - list<Selectable*> touched; - list<Selectable*>::size_type n = 0; - TrackViewList touched_tracks; + list<Selectable*> found; + TrackViewList tracks; for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) { + if ((*iter)->hidden()) { continue; } - n = touched.size(); + list<Selectable*>::size_type const n = found.size (); - (*iter)->get_selectables (start, end, top, bot, touched); + (*iter)->get_selectables (start, end, top, bot, found); - if (n != touched.size()) { - touched_tracks.push_back (*iter); + if (n != found.size()) { + tracks.push_back (*iter); } } - if (touched.empty()) { + return make_pair (found, tracks); +} + +/** @param top Top (lower) y limit in trackview coordinates. + * @param bottom Bottom (higher) y limit in trackview coordinates. + */ +bool +Editor::select_all_within ( + nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op + ) +{ + pair<list<Selectable*>, TrackViewList> const f = find_selectables_within (start, end, top, bot, tracklist); + return select_selectables_and_tracks (f.first, f.second, op); +} + +/** Select a list of Selectables and also a list of Tracks; nothing will be selected if there are no Selectables */ +bool +Editor::select_selectables_and_tracks (list<Selectable*> const & s, TrackViewList const & t, Selection::Operation op) +{ + if (s.empty()) { return false; } - if (!touched_tracks.empty()) { + if (!t.empty()) { switch (op) { case Selection::Add: - selection->add (touched_tracks); + selection->add (t); break; case Selection::Toggle: - selection->toggle (touched_tracks); + selection->toggle (t); break; case Selection::Set: - selection->set (touched_tracks); + selection->set (t); break; case Selection::Extend: /* not defined yet */ @@ -1014,13 +1062,13 @@ Editor::select_all_within (nframes64_t start, nframes64_t end, double top, doubl begin_reversible_command (_("select all within")); switch (op) { case Selection::Add: - selection->add (touched); + selection->add (s); break; case Selection::Toggle: - selection->toggle (touched); + selection->toggle (s); break; case Selection::Set: - selection->set (touched); + selection->set (s); break; case Selection::Extend: /* not defined yet */ @@ -1029,7 +1077,7 @@ Editor::select_all_within (nframes64_t start, nframes64_t end, double top, doubl commit_reversible_command (); - return !touched.empty(); + return !s.empty(); } void diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index 065100a2d8..a7658ed2b9 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -833,14 +833,14 @@ Selection::toggle (const vector<AutomationSelectable*>& autos) } void -Selection::toggle (list<Selectable*>& selectables) +Selection::toggle (list<Selectable*> const & selectables) { RegionView* rv; AutomationSelectable* as; vector<RegionView*> rvs; vector<AutomationSelectable*> autos; - for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) { + for (std::list<Selectable*>::const_iterator i = selectables.begin(); i != selectables.end(); ++i) { if ((rv = dynamic_cast<RegionView*> (*i)) != 0) { rvs.push_back (rv); } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) { @@ -863,7 +863,7 @@ Selection::toggle (list<Selectable*>& selectables) } void -Selection::set (list<Selectable*>& selectables) +Selection::set (list<Selectable*> const & selectables) { clear_regions(); clear_points (); @@ -872,14 +872,14 @@ Selection::set (list<Selectable*>& selectables) void -Selection::add (list<Selectable*>& selectables) +Selection::add (list<Selectable*> const & selectables) { RegionView* rv; AutomationSelectable* as; vector<RegionView*> rvs; vector<AutomationSelectable*> autos; - for (std::list<Selectable*>::iterator i = selectables.begin(); i != selectables.end(); ++i) { + for (std::list<Selectable*>::const_iterator i = selectables.begin(); i != selectables.end(); ++i) { if ((rv = dynamic_cast<RegionView*> (*i)) != 0) { rvs.push_back (rv); } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) { diff --git a/gtk2_ardour/selection.h b/gtk2_ardour/selection.h index 3a6e7ff3ae..ca678fd832 100644 --- a/gtk2_ardour/selection.h +++ b/gtk2_ardour/selection.h @@ -108,9 +108,9 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList bool selected (RegionView*); bool selected (Marker*); - void set (std::list<Selectable*>&); - void add (std::list<Selectable*>&); - void toggle (std::list<Selectable*>&); + void set (std::list<Selectable*> const &); + void add (std::list<Selectable*> const &); + void toggle (std::list<Selectable*> const &); void set (TimeAxisView*); void set (const TrackViewList&); |