File indexing completed on 2024-05-12 16:33:20

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2011 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 "MoveStartOffsetStrategy.h"
0021 #include "ChangeTextOffsetCommand.h"
0022 #include "ArtisticTextShape.h"
0023 #include <KoPathShape.h>
0024 #include <KoPathSegment.h>
0025 #include <KoToolBase.h>
0026 #include <math.h>
0027 
0028 // helper function to calculate the squared distance between two points
0029 qreal squaredDistance(const QPointF &p1, const QPointF &p2)
0030 {
0031     qreal dx = p1.x()-p2.x();
0032     qreal dy = p1.y()-p2.y();
0033     return dx*dx + dy*dy;
0034 }
0035 
0036 MoveStartOffsetStrategy::MoveStartOffsetStrategy(KoToolBase *tool, ArtisticTextShape *text)
0037     : KoInteractionStrategy(tool), m_text(text)
0038 {
0039     m_oldStartOffset = m_text->startOffset();
0040     m_baselineShape = KoPathShape::createShapeFromPainterPath(m_text->baseline());
0041     // cache number of segments and their length
0042     const int subpathCount = m_baselineShape->subpathCount();
0043     for (int i = 0; i < subpathCount; ++i) {
0044         const int subpathPointCount = m_baselineShape->subpathPointCount(i);
0045         for (int j = 0; j < subpathPointCount; ++j) {
0046             KoPathSegment s = m_baselineShape->segmentByIndex(KoPathPointIndex(i, j));
0047             if(s.isValid()) {
0048                 const qreal length = s.length();
0049                 m_segmentLengths.append(length);
0050                 m_totalLength += length;
0051             }
0052         }
0053     }
0054 }
0055 
0056 MoveStartOffsetStrategy::~MoveStartOffsetStrategy()
0057 {
0058     delete m_baselineShape;
0059 }
0060 
0061 void MoveStartOffsetStrategy::handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers /*modifiers*/)
0062 {
0063     // map the global mouse position to local coordinates of our baseline path
0064     const QPointF localMousePoint = m_baselineShape->transformation().inverted().map(mouseLocation);
0065 
0066     // create a roi to check segments at
0067     QRectF grabRect;
0068     grabRect.setHeight(2*grabSensitivity());
0069     grabRect.setWidth(2*grabSensitivity());
0070     grabRect.moveCenter(localMousePoint);
0071 
0072     // get all segments intersecting our roi
0073     QList<KoPathSegment> segments = m_baselineShape->segmentsAt(grabRect);
0074 
0075     // now find the nearest point of all picked segments
0076     KoPathSegment nearestSegment;
0077     qreal nearestPointParam = 0.0;
0078     KoPathPointIndex nearestPathPoint;
0079     qreal minDistance = HUGE_VAL;
0080     foreach(const KoPathSegment &s, segments) {
0081         qreal t = s.nearestPoint(localMousePoint);
0082         qreal distance = squaredDistance(localMousePoint, s.pointAt(t));
0083         if ( distance < minDistance) {
0084             nearestPointParam = t;
0085             nearestSegment = s;
0086             nearestPathPoint = m_baselineShape->pathPointIndex(s.first());
0087             minDistance = distance;
0088         }
0089     }
0090 
0091     // now we need to map back to the length of the baseline path
0092     if (nearestSegment.isValid()) {
0093         // count number of path segments
0094         int segmentCount = 0;
0095         int nearestSegment = 0;
0096         const int subpathCount = m_baselineShape->subpathCount();
0097         for (int i = 0; i < subpathCount; ++i) {
0098             const int subpathPointCount = m_baselineShape->subpathPointCount(i);
0099             if (i == nearestPathPoint.first) {
0100                 nearestSegment = segmentCount + nearestPathPoint.second;
0101             }
0102             segmentCount += m_baselineShape->isClosedSubpath(i) ? subpathPointCount : subpathPointCount-1;
0103         }
0104         qreal length = 0.0;
0105         for (int i = 0; i < nearestSegment; ++i) {
0106             length += m_segmentLengths[i];
0107         }
0108         length += nearestPointParam * m_segmentLengths[nearestSegment];
0109         tool()->repaintDecorations();
0110         m_text->setStartOffset(length / m_totalLength);
0111         tool()->repaintDecorations();
0112     }
0113 }
0114 
0115 KUndo2Command *MoveStartOffsetStrategy::createCommand()
0116 {
0117     return new ChangeTextOffsetCommand(m_text, m_oldStartOffset, m_text->startOffset());
0118 }
0119 
0120 void MoveStartOffsetStrategy::finishInteraction(Qt::KeyboardModifiers /*modifiers*/)
0121 {
0122 
0123 }