mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-22 14:46:34 +01:00
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:
parent
14e32ba075
commit
5f8f481172
7 changed files with 132 additions and 67 deletions
|
|
@ -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 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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&);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue