[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [calligra] libs/flake/tools: improve visual feedback when dragging path curve
From:       Jan Hambrecht <jaham () gmx ! net>
Date:       2012-06-02 13:01:14
Message-ID: 20120602130114.C4F26A60C4 () git ! kde ! org
[Download RAW message or body]

Git commit 20b1d819faa126a05b85e6b394a26bdbc901ce75 by Jan Hambrecht.
Committed on 02/06/2012 at 14:59.
Pushed by jaham into branch 'master'.

improve visual feedback when dragging path curve

when changing a path curve directly by dragging it,
there was no real feedback for the user to see if
starting to drag would change the curve or doing a
rubberbanbd selection. now the cursor is being updated
to reflect if the mouse is onb a path segment. additionally
a status text is shown in the status bar.
i also refactored the corresponding code a little to reuse
the result of the path segment under the mouse cursor.

BUG: 297470

M  +59   -76   libs/flake/tools/KoPathTool.cpp
M  +7    -6    libs/flake/tools/KoPathTool.h

http://commits.kde.org/calligra/20b1d819faa126a05b85e6b394a26bdbc901ce75

diff --git a/libs/flake/tools/KoPathTool.cpp b/libs/flake/tools/KoPathTool.cpp
index 5129f67..6fb89df 100644
--- a/libs/flake/tools/KoPathTool.cpp
+++ b/libs/flake/tools/KoPathTool.cpp
@@ -1,5 +1,5 @@
 /* This file is part of the KDE project
- * Copyright (C) 2006,2008-2009 Jan Hambrecht <jaham@gmx.net>
+ * Copyright (C) 2006-2012 Jan Hambrecht <jaham@gmx.net>
  * Copyright (C) 2006,2007 Thorsten Zachmann <zachmann@kde.org>
  * Copyright (C) 2007, 2010 Thomas Zander <zander@kde.org>
  * Copyright (C) 2007 Boudewijn Rempt <boud@valdyas.org>
@@ -78,11 +78,27 @@ qreal squaredDistance(const QPointF& p1, const QPointF &p2)
     return dx*dx + dy*dy;
 }
 
+struct KoPathTool::PathSegment {
+    PathSegment()
+        : path(0), segmentStart(0), positionOnSegment(0)
+    {
+    }
+
+    bool isValid() {
+        return  path && segmentStart;
+    }
+
+    KoPathShape *path;
+    KoPathPoint *segmentStart;
+    qreal positionOnSegment;
+};
+
 KoPathTool::KoPathTool(KoCanvasBase *canvas)
         : KoToolBase(canvas)
         , m_activeHandle(0)
         , m_handleRadius(3)
         , m_pointSelection(this)
+        , m_activeSegment(0)
         , m_currentStrategy(0)
 {
     QActionGroup *points = new QActionGroup(this);
@@ -474,14 +490,13 @@ void KoPathTool::mousePressEvent(KoPointerEvent *event)
         if (event->button() & Qt::LeftButton) {
 
             // check if we hit a path segment
-            KoPathShape * clickedShape = 0;
-            KoPathPoint * clickedPoint = 0;
-            qreal clickedPointParam = 0.0;
-            if (segmentAtPoint(event->point, clickedShape, clickedPoint, \
                clickedPointParam)) {
-                KoPathPointIndex index = clickedShape->pathPointIndex(clickedPoint);
-                KoPathPointData data(clickedShape, index);
-                m_currentStrategy = new KoPathSegmentChangeStrategy(this, \
event->point, data, clickedPointParam); +            if (m_activeSegment && \
m_activeSegment->isValid()) { +                KoPathPointIndex index = \
m_activeSegment->path->pathPointIndex(m_activeSegment->segmentStart); +               \
KoPathPointData data(m_activeSegment->path, index); +                \
m_currentStrategy = new KoPathSegmentChangeStrategy(this, event->point, data, \
m_activeSegment->positionOnSegment);  event->accept();
+                delete m_activeSegment;
+                m_activeSegment = 0;
             } else {
                 if ((event->modifiers() & Qt::ControlModifier) == 0) {
                     m_pointSelection.clear();
@@ -510,6 +525,9 @@ void KoPathTool::mouseMoveEvent(KoPointerEvent *event)
         return;
     }
 
+    delete m_activeSegment;
+    m_activeSegment = 0;
+
     foreach(KoPathShape *shape, m_pointSelection.selectedShapes()) {
         QRectF roi = handleGrabRect(shape->documentToShape(event->point));
         KoParameterShape * parameterShape = dynamic_cast<KoParameterShape*>(shape);
@@ -604,13 +622,21 @@ void KoPathTool::mouseMoveEvent(KoPointerEvent *event)
         m_activeHandle->repaint();
     delete m_activeHandle;
     m_activeHandle = 0;
-    uint selectedPointCount = m_pointSelection.size();
-    if (selectedPointCount == 0)
-        emit statusTextChanged("");
-    else if (selectedPointCount == 1)
-        emit statusTextChanged(i18n("Press B to break path at selected point."));
-    else
-        emit statusTextChanged(i18n("Press B to break path at selected segments."));
+
+    PathSegment *hoveredSegment = segmentAtPoint(event->point);
+    if(hoveredSegment) {
+        useCursor(Qt::PointingHandCursor);
+        emit statusTextChanged(i18n("Drag to change curve directly. Double click to \
insert new path point.")); +        m_activeSegment = hoveredSegment;
+    } else {
+        uint selectedPointCount = m_pointSelection.size();
+        if (selectedPointCount == 0)
+            emit statusTextChanged("");
+        else if (selectedPointCount == 1)
+            emit statusTextChanged(i18n("Press B to break path at selected \
point.")); +        else
+            emit statusTextChanged(i18n("Press B to break path at selected \
segments.")); +    }
 }
 
 void KoPathTool::mouseReleaseEvent(KoPointerEvent *event)
@@ -723,59 +749,14 @@ void KoPathTool::mouseDoubleClickEvent(KoPointerEvent *event)
     if (m_currentStrategy)
         return;
 
-    /*
-    // TODO: use global click proximity once added to the canvas resource provider
-    const int clickProximity = 5;
-
-    // convert click proximity to point using the current zoom level
-    QPointF clickOffset = \
                d->canvas->viewConverter()->viewToDocument(QPointF(clickProximity, \
                clickProximity));
-    // the max allowed distance from a segment
-    const qreal maxSquaredDistance = clickOffset.x()*clickOffset.x();
-
-    KoPathShape * clickedShape = 0;
-    KoPathPoint * clickedSegmentStart = 0;
-    qreal clickedPointParam = 0.0;
-
-    foreach(KoPathShape *shape, m_pointSelection.selectedShapes()) {
-        if (dynamic_cast<KoParameterShape*>(shape))
-            continue;
-
-        // convert document point to shape coordinates
-        QPointF point = shape->documentToShape(event->point);
-        // our region of interest, i.e. a region around our mouse position
-        QRectF roi(point - clickOffset, point + clickOffset);
-
-        qreal minSqaredDistance = HUGE_VAL;
-        // check all segments of this shape which intersect the region of interest
-        QList<KoPathSegment> segments = shape->segmentsAt(roi);
-        foreach (const KoPathSegment &s, segments) {
-            qreal nearestPointParam = s.nearestPoint(point);
-            QPointF nearestPoint = s.pointAt(nearestPointParam);
-            QPointF diff = point - nearestPoint;
-            qreal squaredDistance = diff.x()*diff.x() + diff.y()*diff.y();
-            // are we within the allowed distance ?
-            if (squaredDistance > maxSquaredDistance)
-                continue;
-            // are we closer to the last closest point ?
-            if (squaredDistance < minSqaredDistance) {
-                clickedShape = shape;
-                clickedSegmentStart = s.first();
-                clickedPointParam = nearestPointParam;
-            }
-        }
-    }
-    */
-
-    KoPathShape * clickedShape = 0;
-    KoPathPoint * clickedSegmentStart = 0;
-    qreal clickedPointParam = 0.0;
-    if (! segmentAtPoint(event->point, clickedShape, clickedSegmentStart, \
clickedPointParam)) +    PathSegment *s = segmentAtPoint(event->point);
+    if (!s)
         return;
 
-    if (clickedShape && clickedSegmentStart) {
+    if (s->isValid()) {
         QList<KoPathPointData> segments;
-        segments.append(KoPathPointData(clickedShape, \
                clickedShape->pathPointIndex(clickedSegmentStart)));
-        KoPathPointInsertCommand *cmd = new KoPathPointInsertCommand(segments, \
clickedPointParam); +        segments.append(KoPathPointData(s->path, \
s->path->pathPointIndex(s->segmentStart))); +        KoPathPointInsertCommand *cmd = \
new KoPathPointInsertCommand(segments, s->positionOnSegment);  \
d->canvas->addCommand(cmd);  
         foreach (KoPathPoint * p, cmd->insertedPoints()) {
@@ -784,9 +765,10 @@ void KoPathTool::mouseDoubleClickEvent(KoPointerEvent *event)
         updateActions();
         event->accept();
     }
+    delete s;
 }
 
-bool KoPathTool::segmentAtPoint(const QPointF &point, KoPathShape* &shape, \
KoPathPoint* &segmentStart, qreal &pointParam) +KoPathTool::PathSegment* \
KoPathTool::segmentAtPoint(const QPointF &point)  {
     Q_D(KoToolBase);
     // TODO: use global click proximity once added to the canvas resource provider
@@ -797,9 +779,7 @@ bool KoPathTool::segmentAtPoint(const QPointF &point, \
KoPathShape* &shape, KoPat  // the max allowed distance from a segment
     const qreal maxSquaredDistance = clickOffset.x()*clickOffset.x();
 
-    KoPathShape * clickedShape = 0;
-    KoPathPoint * clickedSegmentStart = 0;
-    qreal clickedPointParam = 0.0;
+    PathSegment *segment = new PathSegment;
 
     foreach(KoPathShape *shape, m_pointSelection.selectedShapes()) {
         KoParameterShape * parameterShape = dynamic_cast<KoParameterShape*>(shape);
@@ -824,18 +804,19 @@ bool KoPathTool::segmentAtPoint(const QPointF &point, \
KoPathShape* &shape, KoPat  continue;
             // are we closer to the last closest point ?
             if (squaredDistance < minSqaredDistance) {
-                clickedShape = shape;
-                clickedSegmentStart = s.first();
-                clickedPointParam = nearestPointParam;
+                segment->path = shape;
+                segment->segmentStart = s.first();
+                segment->positionOnSegment = nearestPointParam;
             }
         }
     }
 
-    shape = clickedShape;
-    segmentStart = clickedSegmentStart;
-    pointParam = clickedPointParam;
+    if (!segment->isValid()) {
+        delete segment;
+        segment = 0;
+    }
 
-    return (shape && segmentStart);
+    return segment;
 }
 
 void KoPathTool::activate(ToolActivation toolActivation, const QSet<KoShape*> \
&shapes) @@ -934,6 +915,8 @@ void KoPathTool::deactivate()
     m_pointSelection.setSelectedShapes(QList<KoPathShape*>());
     delete m_activeHandle;
     m_activeHandle = 0;
+    delete m_activeSegment;
+    m_activeSegment = 0;
     delete m_currentStrategy;
     m_currentStrategy = 0;
     d->canvas->snapGuide()->reset();
diff --git a/libs/flake/tools/KoPathTool.h b/libs/flake/tools/KoPathTool.h
index 4a78951..abb4e1a 100644
--- a/libs/flake/tools/KoPathTool.h
+++ b/libs/flake/tools/KoPathTool.h
@@ -1,5 +1,5 @@
 /* This file is part of the KDE project
- * Copyright (C) 2006,2008 Jan Hambrecht <jaham@gmx.net>
+ * Copyright (C) 2006-2012 Jan Hambrecht <jaham@gmx.net>
  * Copyright (C) 2006,2007 Thorsten Zachmann <zachmann@kde.org>
  * Copyright (C) 2007 Thomas Zander <zander@kde.org>
  * Copyright (C) 2007 Boudewijn Rempt <boud@valdyas.org>
@@ -84,8 +84,10 @@ protected:
     virtual QList<QWidget *>  createOptionWidgets();
 
 private:
+    struct PathSegment;
+
     void updateOptionsWidget();
-    bool segmentAtPoint( const QPointF &point, KoPathShape* &shape, KoPathPoint* \
&segmentStart, qreal &pointParam ); +    PathSegment* segmentAtPoint(const QPointF \
&point);  
 private slots:
     void pointTypeChanged(QAction *type);
@@ -110,10 +112,9 @@ private:
     KoPathToolHandle * m_activeHandle;       ///< the currently active handle
     int m_handleRadius;    ///< the radius of the control point handles
     uint m_grabSensitivity; ///< the grab sensitivity
-    /// the point selection
-    KoPathToolSelection m_pointSelection;
-    // needed for interaction strategy
-    QPointF m_lastPoint;
+    KoPathToolSelection m_pointSelection; ///< the point selection
+    QPointF m_lastPoint; ///< needed for interaction strategy
+    PathSegment *m_activeSegment;
 
     // make a frind so that it can test private member/methods
     friend class TestPathTool;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic