ShapeShearStrategy.cpp 6.29 KB
Newer Older
1
/* This file is part of the KDE project
Thomas Zander's avatar
Thomas Zander committed
2
 * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
C. Boemann's avatar
C. Boemann committed
3
 * Copyright (C) 2006 C. Boemann <cbo@boemann.dk>
4
 * Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "ShapeShearStrategy.h"
#include "SelectionDecorator.h"

25
#include <KoToolBase.h>
26 27 28 29 30 31 32
#include <KoCanvasBase.h>
#include <KoPointerEvent.h>
#include <KoShapeManager.h>
#include <commands/KoShapeShearCommand.h>
#include <commands/KoShapeMoveCommand.h>
#include <commands/KoShapeTransformCommand.h>

33
#include <KoSelection.h>
34 35 36
#include <QPointF>

#include <math.h>
37
#include <QDebug>
38
#include <klocalizedstring.h>
39

40 41 42
ShapeShearStrategy::ShapeShearStrategy(KoToolBase *tool, const QPointF &clicked, KoFlake::SelectionHandle direction)
    : KoInteractionStrategy(tool)
    , m_start(clicked)
43
{
Thomas Zander's avatar
Thomas Zander committed
44
    KoSelection *sel = tool->canvas()->shapeManager()->selection();
45 46
    m_selectedShapes = sel->selectedEditableShapes();
    Q_FOREACH (KoShape *shape, m_selectedShapes) {
47 48 49 50
        m_oldTransforms << shape->transformation();
    }

    // Eventhoug we aren't currently activated by the corner handles we might as well code like it
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    switch (direction) {
    case KoFlake::TopMiddleHandle:
        m_top = true; m_bottom = false; m_left = false; m_right = false; break;
    case KoFlake::TopRightHandle:
        m_top = true; m_bottom = false; m_left = false; m_right = true; break;
    case KoFlake::RightMiddleHandle:
        m_top = false; m_bottom = false; m_left = false; m_right = true; break;
    case KoFlake::BottomRightHandle:
        m_top = false; m_bottom = true; m_left = false; m_right = true; break;
    case KoFlake::BottomMiddleHandle:
        m_top = false; m_bottom = true; m_left = false; m_right = false; break;
    case KoFlake::BottomLeftHandle:
        m_top = false; m_bottom = true; m_left = true; m_right = false; break;
    case KoFlake::LeftMiddleHandle:
        m_top = false; m_bottom = false; m_left = true; m_right = false; break;
    case KoFlake::TopLeftHandle:
        m_top = true; m_bottom = false; m_left = true; m_right = false; break;
    default:
        ;// throw exception ?  TODO
70 71
    }
    m_initialSize = sel->size();
72
    m_solidPoint = QPointF(m_initialSize.width() / 2, m_initialSize.height() / 2);
73

74
    if (m_top) {
75
        m_solidPoint += QPointF(0, m_initialSize.height() / 2);
76
    } else if (m_bottom) {
77
        m_solidPoint -= QPointF(0, m_initialSize.height() / 2);
78 79
    }
    if (m_left) {
80
        m_solidPoint += QPointF(m_initialSize.width() / 2, 0);
81
    } else if (m_right) {
82
        m_solidPoint -= QPointF(m_initialSize.width() / 2, 0);
83
    }
84

85 86
    m_solidPoint = sel->absoluteTransformation(0).map(sel->outlineRect().topLeft() + m_solidPoint);

87
    QPointF edge;
88
    qreal angle = 0.0;
89
    if (m_top) {
90
        edge = sel->absolutePosition(KoFlake::BottomLeft) - sel->absolutePosition(KoFlake::BottomRight);
91
        angle = 180.0;
92
    } else if (m_bottom) {
93
        edge = sel->absolutePosition(KoFlake::TopRight) - sel->absolutePosition(KoFlake::TopLeft);
94
        angle = 0.0;
95
    } else if (m_left) {
96
        edge = sel->absolutePosition(KoFlake::BottomLeft) - sel->absolutePosition(KoFlake::TopLeft);
97
        angle = 90.0;
98
    } else if (m_right) {
99
        edge = sel->absolutePosition(KoFlake::TopRight) - sel->absolutePosition(KoFlake::BottomRight);
100 101
        angle = 270.0;
    }
102
    qreal currentAngle = atan2(edge.y(), edge.x()) / M_PI * 180;
103 104 105 106
    m_initialSelectionAngle = currentAngle - angle;

    // use crossproduct of top edge and left edge of selection bounding rect
    // to determine if the selection is mirrored
107 108
    QPointF top = sel->absolutePosition(KoFlake::TopRight) - sel->absolutePosition(KoFlake::TopLeft);
    QPointF left = sel->absolutePosition(KoFlake::BottomLeft) - sel->absolutePosition(KoFlake::TopLeft);
109
    m_isMirrored = (top.x() * left.y() - top.y() * left.x()) < 0.0;
110 111 112 113 114 115 116
}

void ShapeShearStrategy::handleMouseMove(const QPointF &point, Qt::KeyboardModifiers modifiers)
{
    Q_UNUSED(modifiers);
    QPointF shearVector = point - m_start;

117
    QTransform m;
118 119 120
    m.rotate(-m_initialSelectionAngle);
    shearVector = m.map(shearVector);

121
    qreal shearX = 0, shearY = 0;
122

123
    if (m_top || m_left) {
124
        shearVector = - shearVector;
125 126
    }
    if (m_top || m_bottom) {
127
        shearX = shearVector.x() / m_initialSize.height();
128 129
    }
    if (m_left || m_right) {
130
        shearY = shearVector.y() / m_initialSize.width();
131
    }
132 133

    // if selection is mirrored invert the shear values
134
    if (m_isMirrored) {
135 136 137 138
        shearX *= -1.0;
        shearY *= -1.0;
    }

139
    QTransform matrix;
140 141 142 143 144 145
    matrix.translate(m_solidPoint.x(), m_solidPoint.y());
    matrix.rotate(m_initialSelectionAngle);
    matrix.shear(shearX, shearY);
    matrix.rotate(-m_initialSelectionAngle);
    matrix.translate(-m_solidPoint.x(), -m_solidPoint.y());

146
    QTransform applyMatrix = matrix * m_shearMatrix.inverted();
147

148
    Q_FOREACH (KoShape *shape, m_selectedShapes) {
149
        const QRectF oldDirtyRect = shape->boundingRect();
150
        shape->applyAbsoluteTransformation(applyMatrix);
151
        shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
152 153 154 155
    }
    m_shearMatrix = matrix;
}

156 157
void ShapeShearStrategy::paint(QPainter &painter, const KoViewConverter &converter)
{
Dmitry Kazakov's avatar
Dmitry Kazakov committed
158 159
    Q_UNUSED(painter);
    Q_UNUSED(converter);
160 161
}

162 163
KUndo2Command *ShapeShearStrategy::createCommand()
{
164
    QList<QTransform> newTransforms;
165
    Q_FOREACH (KoShape *shape, m_selectedShapes) {
166
        newTransforms << shape->transformation();
167 168 169
    }
    KoShapeTransformCommand *cmd = new KoShapeTransformCommand(m_selectedShapes, m_oldTransforms, newTransforms);
    cmd->setText(kundo2_i18n("Shear"));
170 171
    return cmd;
}