summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2010-01-05 02:22:58 +0000
committerCarl Hetherington <carl@carlh.net>2010-01-05 02:22:58 +0000
commit5f8f48117298231b053e62b9940ce753e0235906 (patch)
treeda0716c4b7a81ce03568bff1175ef79a23a59f8c /gtk2_ardour
parent14e32ba0758c776b2660f8b86a9192cddaa3de99 (diff)
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
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/automation_line.cc58
-rw-r--r--gtk2_ardour/automation_line.h1
-rw-r--r--gtk2_ardour/automation_selectable.h6
-rw-r--r--gtk2_ardour/editor.h8
-rw-r--r--gtk2_ardour/editor_selection.cc108
-rw-r--r--gtk2_ardour/selection.cc10
-rw-r--r--gtk2_ardour/selection.h6
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&);