libs/flake
KoSnapGuide.cppGo to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "KoSnapGuide.h"
00021 #include "KoSnapStrategy.h"
00022
00023 #include <KoPathShape.h>
00024 #include <KoPathPoint.h>
00025 #include <KoViewConverter.h>
00026 #include <KoCanvasBase.h>
00027 #include <KoShapeManager.h>
00028
00029 #include <QtGui/QPainter>
00030
00031 #include <math.h>
00032
00033 class KoSnapGuide::Private
00034 {
00035 public:
00036 Private(KoCanvasBase *parentCanvas)
00037 : canvas(parentCanvas), editedShape(0), currentStrategy(0)
00038 , usedStrategies(0), active(true), snapDistance(10)
00039 {
00040 }
00041
00042 ~Private()
00043 {
00044 qDeleteAll( strategies );
00045 strategies.clear();
00046 }
00047
00048 KoCanvasBase * canvas;
00049 KoShape * editedShape;
00050
00051 QList<KoSnapStrategy*> strategies;
00052 KoSnapStrategy * currentStrategy;
00053
00054 int usedStrategies;
00055 bool active;
00056 int snapDistance;
00057 QList<KoPathPoint*> ignoredPoints;
00058 QList<KoShape*> ignoredShapes;
00059 };
00060
00061 KoSnapGuide::KoSnapGuide(KoCanvasBase * canvas)
00062 : d(new Private(canvas))
00063 {
00064 d->strategies.append(new GridSnapStrategy());
00065 d->strategies.append(new NodeSnapStrategy());
00066 d->strategies.append(new OrthogonalSnapStrategy());
00067 d->strategies.append(new ExtensionSnapStrategy());
00068 d->strategies.append(new IntersectionSnapStrategy());
00069 d->strategies.append(new BoundingBoxSnapStrategy());
00070 d->strategies.append(new LineGuideSnapStrategy());
00071 }
00072
00073 KoSnapGuide::~KoSnapGuide()
00074 {
00075 delete d;
00076 }
00077
00078 void KoSnapGuide::setEditedShape(KoShape * shape)
00079 {
00080 d->editedShape = shape;
00081 }
00082
00083 KoShape * KoSnapGuide::editedShape() const
00084 {
00085 return d->editedShape;
00086 }
00087
00088 void KoSnapGuide::enableSnapStrategies(int strategies)
00089 {
00090 d->usedStrategies = strategies;
00091 }
00092
00093 int KoSnapGuide::enabledSnapStrategies() const
00094 {
00095 return d->usedStrategies;
00096 }
00097
00098 bool KoSnapGuide::addCustomSnapStrategy(KoSnapStrategy * customStrategy)
00099 {
00100 if (!customStrategy || customStrategy->type() != KoSnapStrategy::Custom)
00101 return false;
00102
00103 d->strategies.append(customStrategy);
00104 return true;
00105 }
00106
00107 void KoSnapGuide::enableSnapping(bool on)
00108 {
00109 d->active = on;
00110 }
00111
00112 bool KoSnapGuide::isSnapping() const
00113 {
00114 return d->active;
00115 }
00116
00117 void KoSnapGuide::setSnapDistance(int distance)
00118 {
00119 d->snapDistance = qAbs(distance);
00120 }
00121
00122 int KoSnapGuide::snapDistance() const
00123 {
00124 return d->snapDistance;
00125 }
00126
00127 QPointF KoSnapGuide::snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
00128 {
00129 d->currentStrategy = 0;
00130
00131 if (! d->active || (modifiers & Qt::ShiftModifier))
00132 return mousePosition;
00133
00134 KoSnapProxy proxy(this);
00135
00136 qreal minDistance = HUGE_VAL;
00137
00138 qreal maxSnapDistance = d->canvas->viewConverter()->viewToDocument(QSizeF(d->snapDistance, d->snapDistance)).width();
00139
00140 foreach(KoSnapStrategy * strategy, d->strategies) {
00141 if (d->usedStrategies & strategy->type()
00142 || strategy->type() == KoSnapStrategy::Grid
00143 || strategy->type() == KoSnapStrategy::Custom) {
00144 if (! strategy->snap(mousePosition, &proxy, maxSnapDistance))
00145 continue;
00146
00147 QPointF snapCandidate = strategy->snappedPosition();
00148 qreal distance = KoSnapStrategy::squareDistance(snapCandidate, mousePosition);
00149 if (distance < minDistance) {
00150 d->currentStrategy = strategy;
00151 minDistance = distance;
00152 }
00153 }
00154 }
00155
00156 if (! d->currentStrategy)
00157 return mousePosition;
00158
00159 return d->currentStrategy->snappedPosition();
00160 }
00161
00162 QRectF KoSnapGuide::boundingRect()
00163 {
00164 QRectF rect;
00165
00166 if (d->currentStrategy) {
00167 rect = d->currentStrategy->decoration(*d->canvas->viewConverter()).boundingRect();
00168 return rect.adjusted(-2, -2, 2, 2);
00169 } else {
00170 return rect;
00171 };
00172 }
00173
00174 void KoSnapGuide::paint(QPainter &painter, const KoViewConverter &converter)
00175 {
00176 if (! d->currentStrategy || ! d->active)
00177 return;
00178
00179 QPainterPath decoration = d->currentStrategy->decoration(converter);
00180
00181 painter.setBrush(Qt::NoBrush);
00182
00183 QPen whitePen(Qt::white);
00184 whitePen.setStyle(Qt::SolidLine);
00185 painter.setPen(whitePen);
00186 painter.drawPath(decoration);
00187
00188 QPen redPen(Qt::red);
00189 redPen.setStyle(Qt::DotLine);
00190 painter.setPen(redPen);
00191 painter.drawPath(decoration);
00192 }
00193
00194 KoCanvasBase * KoSnapGuide::canvas() const
00195 {
00196 return d->canvas;
00197 }
00198
00199 void KoSnapGuide::setIgnoredPathPoints(const QList<KoPathPoint*> &ignoredPoints)
00200 {
00201 d->ignoredPoints = ignoredPoints;
00202 }
00203
00204 QList<KoPathPoint*> KoSnapGuide::ignoredPathPoints() const
00205 {
00206 return d->ignoredPoints;
00207 }
00208
00209 void KoSnapGuide::setIgnoredShapes(const QList<KoShape*> &ignoredShapes)
00210 {
00211 d->ignoredShapes = ignoredShapes;
00212 }
00213
00214 QList<KoShape*> KoSnapGuide::ignoredShapes() const
00215 {
00216 return d->ignoredShapes;
00217 }
00218
00219 void KoSnapGuide::reset()
00220 {
00221 d->currentStrategy = 0;
00222 d->editedShape = 0;
00223 d->ignoredPoints.clear();
00224 d->ignoredShapes.clear();
00225
00226 int strategyCount = d->strategies.count();
00227 for(int i = strategyCount-1; i >= 0; --i) {
00228 if (d->strategies[i]->type() == KoSnapStrategy::Custom) {
00229 delete d->strategies[i];
00230 d->strategies.removeAt(i);
00231 }
00232 }
00233 }
00234
00236
00238
00239 KoSnapProxy::KoSnapProxy(KoSnapGuide * snapGuide)
00240 : m_snapGuide(snapGuide)
00241 {
00242 }
00243
00244 QList<QPointF> KoSnapProxy::pointsInRect(const QRectF &rect)
00245 {
00246 QList<QPointF> points;
00247 QList<KoShape*> shapes = shapesInRect(rect);
00248 foreach(KoShape * shape, shapes) {
00249 foreach(const QPointF & point, pointsFromShape(shape)) {
00250 if (rect.contains(point))
00251 points.append(point);
00252 }
00253 }
00254
00255 return points;
00256 }
00257
00258 QList<KoShape*> KoSnapProxy::shapesInRect(const QRectF &rect, bool omitEditedShape)
00259 {
00260 QList<KoShape*> shapes = m_snapGuide->canvas()->shapeManager()->shapesAt(rect);
00261 foreach(KoShape * shape, m_snapGuide->ignoredShapes()) {
00262 int index = shapes.indexOf(shape);
00263 if (index >= 0)
00264 shapes.removeAt(index);
00265 }
00266 if (! omitEditedShape && m_snapGuide->editedShape()) {
00267 QRectF bound = m_snapGuide->editedShape()->boundingRect();
00268 if (rect.intersects(bound) || rect.contains(bound))
00269 shapes.append(m_snapGuide->editedShape());
00270 }
00271 return shapes;
00272 }
00273
00274 QList<QPointF> KoSnapProxy::pointsFromShape(KoShape * shape)
00275 {
00276 QList<QPointF> snapPoints;
00277
00278 if (! shape->isVisible(true))
00279 return snapPoints;
00280
00281
00282 snapPoints += shape->snapData().snapPoints();
00283
00284 KoPathShape * path = dynamic_cast<KoPathShape*>(shape);
00285 if (path) {
00286 QMatrix m = path->absoluteTransformation(0);
00287
00288 QList<KoPathPoint*> ignoredPoints = m_snapGuide->ignoredPathPoints();
00289
00290 int subpathCount = path->subpathCount();
00291 for (int subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex) {
00292 int pointCount = path->pointCountSubpath(subpathIndex);
00293 for (int pointIndex = 0; pointIndex < pointCount; ++pointIndex) {
00294 KoPathPoint * p = path->pointByIndex(KoPathPointIndex(subpathIndex, pointIndex));
00295 if (! p || ignoredPoints.contains(p))
00296 continue;
00297
00298 snapPoints.append(m.map(p->point()));
00299 }
00300 }
00301 }
00302 else
00303 {
00304
00305 QRectF bbox = shape->boundingRect();
00306 snapPoints.append(bbox.topLeft());
00307 snapPoints.append(bbox.topRight());
00308 snapPoints.append(bbox.bottomRight());
00309 snapPoints.append(bbox.bottomLeft());
00310 }
00311
00312 return snapPoints;
00313 }
00314
00315 QList<KoPathSegment> KoSnapProxy::segmentsInRect(const QRectF &rect)
00316 {
00317 QList<KoShape*> shapes = shapesInRect(rect, true);
00318 QList<KoPathPoint*> ignoredPoints = m_snapGuide->ignoredPathPoints();
00319
00320 QList<KoPathSegment> segments;
00321 foreach(KoShape * shape, shapes) {
00322 QList<KoPathSegment> shapeSegments;
00323 QRectF rectOnShape = shape->documentToShape(rect);
00324 KoPathShape * path = dynamic_cast<KoPathShape*>(shape);
00325 if (path) {
00326 shapeSegments = path->segmentsAt(rectOnShape);
00327 } else {
00328 foreach(const KoPathSegment & s, shape->snapData().snapSegments()) {
00329 QRectF controlRect = s.controlPointRect();
00330 if (! rect.intersects(controlRect) && ! controlRect.contains(rect))
00331 continue;
00332 QRectF bound = s.boundingRect();
00333 if (! rect.intersects(bound) && ! bound.contains(rect))
00334 continue;
00335 shapeSegments.append(s);
00336 }
00337 }
00338
00339 QMatrix m = shape->absoluteTransformation(0);
00340
00341 foreach(const KoPathSegment & s, shapeSegments) {
00342 if (ignoredPoints.contains(s.first()) || ignoredPoints.contains(s.second()))
00343 continue;
00344 segments.append(s.mapped(m));
00345 }
00346 }
00347 return segments;
00348 }
00349
00350 QList<KoShape*> KoSnapProxy::shapes(bool omitEditedShape)
00351 {
00352 QList<KoShape*> allShapes = m_snapGuide->canvas()->shapeManager()->shapes();
00353 QList<KoShape*> filteredShapes;
00354 QList<KoShape*> ignoredShapes = m_snapGuide->ignoredShapes();
00355
00356
00357 foreach(KoShape * shape, allShapes) {
00358 if (! shape->isVisible(true))
00359 continue;
00360 if (ignoredShapes.contains(shape))
00361 continue;
00362
00363 filteredShapes.append(shape);
00364 }
00365 if (! omitEditedShape && m_snapGuide->editedShape())
00366 filteredShapes.append(m_snapGuide->editedShape());
00367
00368 return filteredShapes;
00369 }
00370
00371 KoCanvasBase * KoSnapProxy::canvas()
00372 {
00373 return m_snapGuide->canvas();
00374 }
|