Fixes to permit drags of multiply-selected automation control points.

git-svn-id: svn://localhost/ardour2/branches/3.0@6450 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2010-01-05 02:22:58 +00:00
parent 14e32ba075
commit 5f8f481172
7 changed files with 132 additions and 67 deletions

View file

@ -1037,50 +1037,54 @@ AutomationLine::get_inverted_selectables (Selection&, list<Selectable*>& /*resul
// hmmm .... // hmmm ....
} }
void /** Take a PointSelection and find ControlPoints that fall within it */
AutomationLine::set_selected_points (PointSelection& points) list<ControlPoint*>
AutomationLine::point_selection_to_control_points (PointSelection const & s)
{ {
double top; list<ControlPoint*> cp;
double bot;
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { for (PointSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
(*i)->set_selected(false);
}
if (points.empty()) { if (i->track != &trackview) {
goto out;
}
for (PointSelection::iterator r = points.begin(); r != points.end(); ++r) {
if ((*r).track != &trackview) {
continue; continue;
} }
/* Curse X11 and its inverted coordinate system! */ /* Curse X11 and its inverted coordinate system! */
bot = (1.0 - (*r).high_fract) * _height; double const bot = (1.0 - i->high_fract) * _height;
top = (1.0 - (*r).low_fract) * _height; double const top = (1.0 - i->low_fract) * _height;
for (vector<ControlPoint*>::iterator j = control_points.begin(); j != control_points.end(); ++j) {
double const rstart = trackview.editor().frame_to_unit (i->start);
double const rend = trackview.editor().frame_to_unit (i->end);
if ((*j)->get_x() >= rstart && (*j)->get_x() <= rend) {
if ((*j)->get_y() >= bot && (*j)->get_y() <= top) {
cp.push_back (*j);
}
}
}
}
return cp;
}
void
AutomationLine::set_selected_points (PointSelection& points)
{
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
(*i)->set_selected (false);
}
double rstart, rend; if (!points.empty()) {
list<ControlPoint*> cp = point_selection_to_control_points (points);
rstart = trackview.editor().frame_to_unit ((*r).start); for (list<ControlPoint*>::iterator i = cp.begin(); i != cp.end(); ++i) {
rend = trackview.editor().frame_to_unit ((*r).end); (*i)->set_selected (true);
if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) {
if ((*i)->get_y() >= bot && (*i)->get_y() <= top) {
(*i)->set_selected(true);
} }
} }
}
}
out:
set_colors (); set_colors ();
} }

View file

@ -64,6 +64,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
void reset (); void reset ();
void clear(); void clear();
std::list<ControlPoint*> point_selection_to_control_points (PointSelection const &);
void set_selected_points (PointSelection&); void set_selected_points (PointSelection&);
void get_selectables (nframes_t& start, nframes_t& end, void get_selectables (nframes_t& start, nframes_t& end,
double botfrac, double topfrac, double botfrac, double topfrac,

View file

@ -25,6 +25,12 @@
class TimeAxisView; 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 struct AutomationSelectable : public Selectable
{ {
nframes_t start; nframes_t start;

View file

@ -1630,7 +1630,13 @@ public:
/* object rubberband select process */ /* 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; ArdourCanvas::SimpleRect *rubberband_rect;

View file

@ -242,15 +242,11 @@ Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*n
return false; return false;
} }
/* select this point and any others that it represents */ /* rectangle 10 pixels surrounding the clicked control point */
nframes64_t const x1 = pixel_to_frame (clicked_control_point->get_x() - 10);
double y1, y2; nframes64_t const x2 = pixel_to_frame (clicked_control_point->get_x() + 10);
nframes64_t x1, x2; double y1 = clicked_control_point->get_y() - 10;
double y2 = clicked_control_point->get_y() + 10;
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;
/* convert the y values to trackview space */ /* convert the y values to trackview space */
double dummy = 0; 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, y1);
_trackview_group->w2i (dummy, y2); _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 void
@ -965,45 +990,68 @@ Editor::invert_selection ()
selection->set (touched); selection->set (touched);
} }
/** @param top Top (lower) y limit in trackview coordinates. /** Find Selectable things within an area.
* @param bottom Bottom (higher) y limit in trackview coordinates. * @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 pair<list<Selectable*>, TrackViewList>
Editor::select_all_within (nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op) Editor::find_selectables_within (nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist)
{ {
list<Selectable*> touched; list<Selectable*> found;
list<Selectable*>::size_type n = 0; TrackViewList tracks;
TrackViewList touched_tracks;
for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) { for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
if ((*iter)->hidden()) { if ((*iter)->hidden()) {
continue; 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()) { if (n != found.size()) {
touched_tracks.push_back (*iter); 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; return false;
} }
if (!touched_tracks.empty()) { if (!t.empty()) {
switch (op) { switch (op) {
case Selection::Add: case Selection::Add:
selection->add (touched_tracks); selection->add (t);
break; break;
case Selection::Toggle: case Selection::Toggle:
selection->toggle (touched_tracks); selection->toggle (t);
break; break;
case Selection::Set: case Selection::Set:
selection->set (touched_tracks); selection->set (t);
break; break;
case Selection::Extend: case Selection::Extend:
/* not defined yet */ /* 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")); begin_reversible_command (_("select all within"));
switch (op) { switch (op) {
case Selection::Add: case Selection::Add:
selection->add (touched); selection->add (s);
break; break;
case Selection::Toggle: case Selection::Toggle:
selection->toggle (touched); selection->toggle (s);
break; break;
case Selection::Set: case Selection::Set:
selection->set (touched); selection->set (s);
break; break;
case Selection::Extend: case Selection::Extend:
/* not defined yet */ /* not defined yet */
@ -1029,7 +1077,7 @@ Editor::select_all_within (nframes64_t start, nframes64_t end, double top, doubl
commit_reversible_command (); commit_reversible_command ();
return !touched.empty(); return !s.empty();
} }
void void

View file

@ -833,14 +833,14 @@ Selection::toggle (const vector<AutomationSelectable*>& autos)
} }
void void
Selection::toggle (list<Selectable*>& selectables) Selection::toggle (list<Selectable*> const & selectables)
{ {
RegionView* rv; RegionView* rv;
AutomationSelectable* as; AutomationSelectable* as;
vector<RegionView*> rvs; vector<RegionView*> rvs;
vector<AutomationSelectable*> autos; 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) { if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
rvs.push_back (rv); rvs.push_back (rv);
} else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) { } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {
@ -863,7 +863,7 @@ Selection::toggle (list<Selectable*>& selectables)
} }
void void
Selection::set (list<Selectable*>& selectables) Selection::set (list<Selectable*> const & selectables)
{ {
clear_regions(); clear_regions();
clear_points (); clear_points ();
@ -872,14 +872,14 @@ Selection::set (list<Selectable*>& selectables)
void void
Selection::add (list<Selectable*>& selectables) Selection::add (list<Selectable*> const & selectables)
{ {
RegionView* rv; RegionView* rv;
AutomationSelectable* as; AutomationSelectable* as;
vector<RegionView*> rvs; vector<RegionView*> rvs;
vector<AutomationSelectable*> autos; 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) { if ((rv = dynamic_cast<RegionView*> (*i)) != 0) {
rvs.push_back (rv); rvs.push_back (rv);
} else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) { } else if ((as = dynamic_cast<AutomationSelectable*> (*i)) != 0) {

View file

@ -108,9 +108,9 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList
bool selected (RegionView*); bool selected (RegionView*);
bool selected (Marker*); bool selected (Marker*);
void set (std::list<Selectable*>&); void set (std::list<Selectable*> const &);
void add (std::list<Selectable*>&); void add (std::list<Selectable*> const &);
void toggle (std::list<Selectable*>&); void toggle (std::list<Selectable*> const &);
void set (TimeAxisView*); void set (TimeAxisView*);
void set (const TrackViewList&); void set (const TrackViewList&);