mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-22 06:36:29 +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 ....
|
||||
}
|
||||
|
||||
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;
|
||||
list<ControlPoint*> cp;
|
||||
|
||||
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
|
||||
(*i)->set_selected(false);
|
||||
}
|
||||
for (PointSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
|
||||
|
||||
if (points.empty()) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (PointSelection::iterator r = points.begin(); r != points.end(); ++r) {
|
||||
|
||||
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 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) {
|
||||
(*i)->set_selected (false);
|
||||
}
|
||||
|
||||
double rstart, rend;
|
||||
|
||||
rstart = trackview.editor().frame_to_unit ((*r).start);
|
||||
rend = trackview.editor().frame_to_unit ((*r).end);
|
||||
|
||||
if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) {
|
||||
|
||||
if ((*i)->get_y() >= bot && (*i)->get_y() <= top) {
|
||||
|
||||
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 ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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&);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue