Code

Reduce libsigc++ usage to partially fix performance regressions
[inkscape.git] / src / ui / tool / control-point-selection.cpp
index d10045c623598dffffaf1ae545837c2aeed5fc0f..de19fef8d0268d47b37aa05f4603f8f3c6f1f260 100644 (file)
@@ -49,8 +49,6 @@ ControlPointSelection::ControlPointSelection(SPDesktop *d, SPCanvasGroup *th_gro
     , _dragging(false)
     , _handles_visible(true)
     , _one_node_handles(false)
-    , _sculpt_enabled(false)
-    , _sculpting(false)
 {
     signal_update.connect( sigc::bind(
         sigc::mem_fun(*this, &ControlPointSelection::_updateTransformHandles),
@@ -80,26 +78,7 @@ std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(c
         return std::pair<iterator, bool>(found, false);
     }
 
-    boost::shared_ptr<connlist_type> clist(new connlist_type());
-
-    // hide event param and always return false
-    clist->push_back(
-        x->signal_grabbed.connect(
-            sigc::bind_return(
-                sigc::bind<0>(
-                    sigc::mem_fun(*this, &ControlPointSelection::_selectionGrabbed),
-                    x),
-                false)));
-    clist->push_back(
-        x->signal_dragged.connect(
-                sigc::mem_fun(*this, &ControlPointSelection::_selectionDragged)));
-    // hide event parameter
-    clist->push_back(
-        x->signal_ungrabbed.connect(
-            sigc::hide(
-                sigc::mem_fun(*this, &ControlPointSelection::_selectionUngrabbed))));
-
-    found = _points.insert(std::make_pair(x, clist)).first;
+    found = _points.insert(x).first;
 
     x->updateState();
     _rot_radius.reset();
@@ -111,11 +90,7 @@ std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(c
 /** Remove a point from the selection. */
 void ControlPointSelection::erase(iterator pos)
 {
-    SelectableControlPoint *erased = pos->first;
-    boost::shared_ptr<connlist_type> clist = pos->second;
-    for (connlist_type::iterator i = clist->begin(); i != clist->end(); ++i) {
-        i->disconnect();
-    }
+    SelectableControlPoint *erased = *pos;
     _points.erase(pos);
     erased->updateState();
     _rot_radius.reset();
@@ -140,11 +115,64 @@ void ControlPointSelection::clear()
         erase(i++);
 }
 
-/** Transform all selected control points by the supplied affine transformation. */
+/** Select all points that this selection can contain. */
+void ControlPointSelection::selectAll()
+{
+    for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+        insert(*i);
+    }
+}
+/** Select all points inside the given rectangle (in desktop coordinates). */
+void ControlPointSelection::selectArea(Geom::Rect const &r)
+{
+    for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+        if (r.contains(**i))
+            insert(*i);
+    }
+}
+/** Unselect all selected points and select all unselected points. */
+void ControlPointSelection::invertSelection()
+{
+    for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+        if ((*i)->selected()) erase(*i);
+        else insert(*i);
+    }
+}
+void ControlPointSelection::spatialGrow(SelectableControlPoint *origin, int dir)
+{
+    bool grow = (dir > 0);
+    Geom::Point p = origin->position();
+    double best_dist = grow ? HUGE_VAL : 0;
+    SelectableControlPoint *match = NULL;
+    for (set_type::iterator i = _all_points.begin(); i != _all_points.end(); ++i) {
+        bool selected = (*i)->selected();
+        if (grow && !selected) {
+            double dist = Geom::distance((*i)->position(), p);
+            if (dist < best_dist) {
+                best_dist = dist;
+                match = *i;
+            }
+        }
+        if (!grow && selected) {
+            double dist = Geom::distance((*i)->position(), p);
+            // use >= to also deselect the origin node when it's the last one selected
+            if (dist >= best_dist) {
+                best_dist = dist;
+                match = *i;
+            }
+        }
+    }
+    if (match) {
+        if (grow) insert(match);
+        else erase(match);
+    }
+}
+
+/** Transform all selected control points by the given affine transformation. */
 void ControlPointSelection::transform(Geom::Matrix const &m)
 {
     for (iterator i = _points.begin(); i != _points.end(); ++i) {
-        SelectableControlPoint *cur = i->first;
+        SelectableControlPoint *cur = *i;
         cur->transform(m);
     }
     // TODO preserving the rotation radius needs some rethinking...
@@ -160,14 +188,14 @@ void ControlPointSelection::align(Geom::Dim2 axis)
 
     Geom::OptInterval bound;
     for (iterator i = _points.begin(); i != _points.end(); ++i) {
-        bound.unionWith(Geom::OptInterval(i->first->position()[d]));
+        bound.unionWith(Geom::OptInterval((*i)->position()[d]));
     }
 
     double new_coord = bound->middle();
     for (iterator i = _points.begin(); i != _points.end(); ++i) {
-        Geom::Point pos = i->first->position();
+        Geom::Point pos = (*i)->position();
         pos[d] = new_coord;
-        i->first->move(pos);
+        (*i)->move(pos);
     }
 }
 
@@ -184,8 +212,8 @@ void ControlPointSelection::distribute(Geom::Dim2 d)
     // first we insert all points into a multimap keyed by the aligned coord to sort them
     // simultaneously we compute the extent of selection
     for (iterator i = _points.begin(); i != _points.end(); ++i) {
-        Geom::Point pos = i->first->position();
-        sm.insert(std::make_pair(pos[d], i->first));
+        Geom::Point pos = (*i)->position();
+        sm.insert(std::make_pair(pos[d], (*i)));
         bound.unionWith(Geom::OptInterval(pos[d]));
     }
 
@@ -207,7 +235,7 @@ Geom::OptRect ControlPointSelection::pointwiseBounds()
 {
     Geom::OptRect bound;
     for (iterator i = _points.begin(); i != _points.end(); ++i) {
-        SelectableControlPoint *cur = i->first;
+        SelectableControlPoint *cur = (*i);
         Geom::Point p = cur->position();
         if (!bound) {
             bound = Geom::Rect(p, p);
@@ -222,7 +250,7 @@ Geom::OptRect ControlPointSelection::bounds()
 {
     Geom::OptRect bound;
     for (iterator i = _points.begin(); i != _points.end(); ++i) {
-        SelectableControlPoint *cur = i->first;
+        SelectableControlPoint *cur = (*i);
         Geom::OptRect r = cur->bounds();
         bound.unionWith(r);
     }
@@ -245,52 +273,35 @@ void ControlPointSelection::restoreTransformHandles()
     _updateTransformHandles(true);
 }
 
-void ControlPointSelection::_selectionGrabbed(SelectableControlPoint *p, GdkEventMotion *event)
+void ControlPointSelection::toggleTransformHandlesMode()
 {
-    hideTransformHandles();
-    _dragging = true;
-    if (held_alt(*event) && _sculpt_enabled) {
-        _sculpting = true;
-        _grabbed_point = p;
+    if (_handles->mode() == TransformHandleSet::MODE_SCALE) {
+        _handles->setMode(TransformHandleSet::MODE_ROTATE_SKEW);
+        if (size() == 1) _handles->rotationCenter().setVisible(false);
     } else {
-        _sculpting = false;
+        _handles->setMode(TransformHandleSet::MODE_SCALE);
     }
 }
 
-void ControlPointSelection::_selectionDragged(Geom::Point const &old_pos, Geom::Point &new_pos,
-    GdkEventMotion *event)
+void ControlPointSelection::_pointGrabbed()
 {
-    Geom::Point delta = new_pos - old_pos;
-    /*if (_sculpting) {
-        // for now we only support the default sculpting profile (bell)
-        // others will be added when preferences will be able to store enumerated values
-        double pressure, alpha;
-        if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &pressure)) {
-            pressure = CLAMP(pressure, 0.2, 0.8);
-        } else {
-            pressure = 0.5;
-        }
-
-        alpha = 1 - 2 * fabs(pressure - 0.5);
-        if (pressure > 0.5) alpha = 1/alpha;
+    hideTransformHandles();
+    _dragging = true;
+}
 
-        for (iterator i = _points.begin(); i != _points.end(); ++i) {
-            SelectableControlPoint *cur = i->first;
-            double dist = Geom::distance(cur->position(), _grabbed_point->position());
-            
-            cur->move(cur->position() + delta);
-        }
-    } else*/ {
-        for (iterator i = _points.begin(); i != _points.end(); ++i) {
-            SelectableControlPoint *cur = i->first;
-            cur->move(cur->position() + delta);
-        }
-        _handles->rotationCenter().move(_handles->rotationCenter().position() + delta);
+void ControlPointSelection::_pointDragged(Geom::Point const &old_pos, Geom::Point &new_pos,
+                                          GdkEventMotion */*event*/)
+{
+    Geom::Point delta = new_pos - old_pos;
+    for (iterator i = _points.begin(); i != _points.end(); ++i) {
+        SelectableControlPoint *cur = (*i);
+        cur->move(cur->position() + delta);
     }
+    _handles->rotationCenter().move(_handles->rotationCenter().position() + delta);
     signal_update.emit();
 }
 
-void ControlPointSelection::_selectionUngrabbed()
+void ControlPointSelection::_pointUngrabbed()
 {
     _dragging = false;
     _grabbed_point = NULL;
@@ -298,6 +309,17 @@ void ControlPointSelection::_selectionUngrabbed()
     signal_commit.emit(COMMIT_MOUSE_MOVE);
 }
 
+bool ControlPointSelection::_pointClicked(SelectableControlPoint *p, GdkEventButton *event)
+{
+    // clicking a selected node should toggle the transform handles between rotate and scale mode,
+    // if they are visible
+    if (held_no_modifiers(*event) && _handles_visible && p->selected()) {
+        toggleTransformHandlesMode();
+        return true;
+    }
+    return false;
+}
+
 void ControlPointSelection::_updateTransformHandles(bool preserve_center)
 {
     if (_dragging) return;
@@ -307,7 +329,7 @@ void ControlPointSelection::_updateTransformHandles(bool preserve_center)
         _handles->setBounds(*b, preserve_center);
         _handles->setVisible(true);
     } else if (_one_node_handles && size() == 1) { // only one control point in selection
-        SelectableControlPoint *p = begin()->first;
+        SelectableControlPoint *p = *begin();
         _handles->setBounds(p->bounds());
         _handles->rotationCenter().move(p->position());
         _handles->rotationCenter().setVisible(false);
@@ -491,13 +513,7 @@ bool ControlPointSelection::event(GdkEvent *event)
         case GDK_h:
         case GDK_H:
             if (held_shift(event->key)) {
-                // TODO make a method for mode switching
-                if (_handles->mode() == TransformHandleSet::MODE_SCALE) {
-                    _handles->setMode(TransformHandleSet::MODE_ROTATE_SKEW);
-                    if (size() == 1) _handles->rotationCenter().setVisible(false);
-                } else {
-                    _handles->setMode(TransformHandleSet::MODE_SCALE);
-                }
+                toggleTransformHandlesMode();
                 return true;
             }
             // any modifiers except shift should cause no action