Warning, file /office/calligra/libs/flake/KoSnapGuide.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2008-2009 Jan Hambrecht <jaham@gmx.net>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "KoSnapGuide.h"
0021 #include "KoSnapProxy.h"
0022 #include "KoSnapStrategy.h"
0023 
0024 #include <KoPathShape.h>
0025 #include <KoPathPoint.h>
0026 #include <KoViewConverter.h>
0027 #include <KoCanvasBase.h>
0028 
0029 #include <QPainter>
0030 #include <QPainterPath>
0031 
0032 #include <math.h>
0033 
0034 
0035 class Q_DECL_HIDDEN KoSnapGuide::Private
0036 {
0037 public:
0038     Private(KoCanvasBase *parentCanvas)
0039         : canvas(parentCanvas), editedShape(0), currentStrategy(0),
0040         active(true),
0041         snapDistance(10)
0042     {
0043     }
0044 
0045     ~Private()
0046     {
0047         qDeleteAll(strategies);
0048         strategies.clear();
0049     }
0050 
0051     KoCanvasBase *canvas;
0052     KoShape *editedShape;
0053 
0054     QList<KoSnapStrategy*> strategies;
0055     KoSnapStrategy *currentStrategy;
0056 
0057     KoSnapGuide::Strategies usedStrategies;
0058     bool active;
0059     int snapDistance;
0060     QList<KoPathPoint*> ignoredPoints;
0061     QList<KoShape*> ignoredShapes;
0062 };
0063 
0064 KoSnapGuide::KoSnapGuide(KoCanvasBase *canvas)
0065     : d(new Private(canvas))
0066 {
0067     d->strategies.append(new GridSnapStrategy());
0068     d->strategies.append(new NodeSnapStrategy());
0069     d->strategies.append(new OrthogonalSnapStrategy());
0070     d->strategies.append(new ExtensionSnapStrategy());
0071     d->strategies.append(new IntersectionSnapStrategy());
0072     d->strategies.append(new BoundingBoxSnapStrategy());
0073     d->strategies.append(new LineGuideSnapStrategy());
0074 }
0075 
0076 KoSnapGuide::~KoSnapGuide()
0077 {
0078     delete d;
0079 }
0080 
0081 void KoSnapGuide::setEditedShape(KoShape *shape)
0082 {
0083     d->editedShape = shape;
0084 }
0085 
0086 KoShape *KoSnapGuide::editedShape() const
0087 {
0088     return d->editedShape;
0089 }
0090 
0091 void KoSnapGuide::enableSnapStrategies(Strategies strategies)
0092 {
0093     d->usedStrategies = strategies;
0094 }
0095 
0096 KoSnapGuide::Strategies KoSnapGuide::enabledSnapStrategies() const
0097 {
0098     return d->usedStrategies;
0099 }
0100 
0101 bool KoSnapGuide::addCustomSnapStrategy(KoSnapStrategy *customStrategy)
0102 {
0103     if (!customStrategy || customStrategy->type() != CustomSnapping)
0104         return false;
0105 
0106     d->strategies.append(customStrategy);
0107     return true;
0108 }
0109 
0110 void KoSnapGuide::enableSnapping(bool on)
0111 {
0112     d->active = on;
0113 }
0114 
0115 bool KoSnapGuide::isSnapping() const
0116 {
0117     return d->active;
0118 }
0119 
0120 void KoSnapGuide::setSnapDistance(int distance)
0121 {
0122     d->snapDistance = qAbs(distance);
0123 }
0124 
0125 int KoSnapGuide::snapDistance() const
0126 {
0127     return d->snapDistance;
0128 }
0129 
0130 QPointF KoSnapGuide::snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
0131 {
0132     d->currentStrategy = 0;
0133 
0134     if (! d->active || (modifiers & Qt::ShiftModifier))
0135         return mousePosition;
0136 
0137     KoSnapProxy proxy(this);
0138 
0139     qreal minDistance = HUGE_VAL;
0140 
0141     qreal maxSnapDistance = d->canvas->viewConverter()->viewToDocument(QSizeF(d->snapDistance,
0142                 d->snapDistance)).width();
0143 
0144     foreach (KoSnapStrategy *strategy, d->strategies) {
0145         if (d->usedStrategies & strategy->type()
0146                 || strategy->type() == GridSnapping || strategy->type() == CustomSnapping) {
0147             if (! strategy->snap(mousePosition, &proxy, maxSnapDistance))
0148                 continue;
0149 
0150             QPointF snapCandidate = strategy->snappedPosition();
0151             qreal distance = KoSnapStrategy::squareDistance(snapCandidate, mousePosition);
0152             if (distance < minDistance) {
0153                 d->currentStrategy = strategy;
0154                 minDistance = distance;
0155             }
0156         }
0157     }
0158 
0159     if (! d->currentStrategy)
0160         return mousePosition;
0161 
0162     return d->currentStrategy->snappedPosition();
0163 }
0164 
0165 QRectF KoSnapGuide::boundingRect() const
0166 {
0167     QRectF rect;
0168 
0169     if (d->currentStrategy) {
0170         rect = d->currentStrategy->decoration(*d->canvas->viewConverter()).boundingRect();
0171         return rect.adjusted(-2, -2, 2, 2);
0172     } else {
0173         return rect;
0174     }
0175 }
0176 
0177 void KoSnapGuide::paint(QPainter &painter, const KoViewConverter &converter)
0178 {
0179     if (! d->currentStrategy || ! d->active)
0180         return;
0181 
0182     QPainterPath decoration = d->currentStrategy->decoration(converter);
0183 
0184     painter.setBrush(Qt::NoBrush);
0185 
0186     QPen whitePen(Qt::white, 0);
0187     whitePen.setStyle(Qt::SolidLine);
0188     painter.setPen(whitePen);
0189     painter.drawPath(decoration);
0190 
0191     QPen redPen(Qt::red, 0);
0192     redPen.setStyle(Qt::DotLine);
0193     painter.setPen(redPen);
0194     painter.drawPath(decoration);
0195 }
0196 
0197 KoCanvasBase *KoSnapGuide::canvas() const
0198 {
0199     return d->canvas;
0200 }
0201 
0202 void KoSnapGuide::setIgnoredPathPoints(const QList<KoPathPoint*> &ignoredPoints)
0203 {
0204     d->ignoredPoints = ignoredPoints;
0205 }
0206 
0207 QList<KoPathPoint*> KoSnapGuide::ignoredPathPoints() const
0208 {
0209     return d->ignoredPoints;
0210 }
0211 
0212 void KoSnapGuide::setIgnoredShapes(const QList<KoShape*> &ignoredShapes)
0213 {
0214     d->ignoredShapes = ignoredShapes;
0215 }
0216 
0217 QList<KoShape*> KoSnapGuide::ignoredShapes() const
0218 {
0219     return d->ignoredShapes;
0220 }
0221 
0222 void KoSnapGuide::reset()
0223 {
0224     d->currentStrategy = 0;
0225     d->editedShape = 0;
0226     d->ignoredPoints.clear();
0227     d->ignoredShapes.clear();
0228     // remove all custom strategies
0229     int strategyCount = d->strategies.count();
0230     for (int i = strategyCount-1; i >= 0; --i) {
0231         if (d->strategies[i]->type() == CustomSnapping) {
0232             delete d->strategies[i];
0233             d->strategies.removeAt(i);
0234         }
0235     }
0236 }
0237