class QSignalMapper;
class KoInteractionStrategy;
class KoShapeMoveCommand;
class KoSelection;
class DefaultToolTabbedWidget;
/**
* The default tool (associated with the arrow icon) implements the default
* interactions you have with flake objects.
* The tool provides scaling, moving, selecting, rotation and soon skewing of
* any number of shapes.
* Note that the implementation of those different strategies are delegated
* to the InteractionStrategy class and its subclasses.
*/
class DefaultTool : public KoInteractionTool
{
Q_OBJECT
public:
/**
* Constructor for basic interaction tool where user actions are translated
* and handled by interaction strategies of type KoInteractionStrategy.
* @param canvas the canvas this tool will be working for.
*/
explicit DefaultTool(KoCanvasBase *canvas);
~DefaultTool() override;
enum CanvasResource {
HotPosition = 1410100299
};
public:
bool wantsAutoScroll() const override;
void paint(QPainter &painter, const KoViewConverter &converter) override;
void repaintDecorations() override;
///reimplemented
void copy() const override;
///reimplemented
void deleteSelection() override;
///reimplemented
bool paste() override;
///reimplemented
KoToolSelection *selection() override;
QMenu* popupActionsMenu() override;
/**
* Returns which selection handle is at params point (or NoHandle if none).
* @return which selection handle is at params point (or NoHandle if none).
* @param point the location (in pt) where we should look for a handle
* @param innerHandleMeaning this boolean is altered to true if the point
* is inside the selection rectangle and false if it is just outside.
* The value of innerHandleMeaning is undefined if the handle location is NoHandle
*/
KoFlake::SelectionHandle handleAt(const QPointF &point, bool *innerHandleMeaning = 0);
public Q_SLOTS:
void activate(ToolActivation activation, const QSet &shapes) override;
void deactivate() override;
private Q_SLOTS:
void selectionAlign(int _align);
void selectionDistribute(int _distribute);
void selectionBringToFront();
void selectionSendToBack();
void selectionMoveUp();
void selectionMoveDown();
void selectionGroup();
void selectionUngroup();
+ void selectionTransform(int transformAction);
+
void slotActivateEditFillGradient(bool value);
void slotActivateEditStrokeGradient(bool value);
/// Update actions on selection change
void updateActions();
public: // Events
void mousePressEvent(KoPointerEvent *event) override;
void mouseMoveEvent(KoPointerEvent *event) override;
void mouseReleaseEvent(KoPointerEvent *event) override;
void mouseDoubleClickEvent(KoPointerEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void explicitUserStrokeEndRequest() override;
protected:
QList > createOptionWidgets() override;
KoInteractionStrategy *createStrategy(KoPointerEvent *event) override;
private:
class MoveGradientHandleInteractionFactory;
private:
void setupActions();
void recalcSelectionBox(KoSelection *selection);
void updateCursor();
/// Returns rotation angle of given handle of the current selection
qreal rotationOfHandle(KoFlake::SelectionHandle handle, bool useEdgeRotation);
void addMappedAction(QSignalMapper *mapper, const QString &actionId, int type);
void selectionReorder(KoShapeReorderCommand::MoveShapeType order);
bool moveSelection(int direction, Qt::KeyboardModifiers modifiers);
/// Returns selection rectangle adjusted by handle proximity threshold
QRectF handlesSize();
// convenience method;
KoSelection *koSelection();
void canvasResourceChanged(int key, const QVariant &res) override;
KoFlake::SelectionHandle m_lastHandle;
KoFlake::AnchorPosition m_hotPosition;
bool m_mouseWasInsideHandles;
QPointF m_selectionBox[8];
QPolygonF m_selectionOutline;
QPointF m_lastPoint;
// TODO alter these 3 arrays to be static const instead
QCursor m_sizeCursors[8];
QCursor m_rotateCursors[8];
QCursor m_shearCursors[8];
qreal m_angle;
KoToolSelection *m_selectionHandler;
friend class SelectionHandler;
KoInteractionStrategy *m_customEventStrategy;
QScopedPointer m_contextMenu;
DefaultToolTabbedWidget *m_tabbedOptionWidget;
};
#endif
diff --git a/plugins/tools/defaulttool/defaulttool/ShapeRotateStrategy.cpp b/plugins/tools/defaulttool/defaulttool/ShapeRotateStrategy.cpp
index a9df04da7b..8fd959d3b8 100644
--- a/plugins/tools/defaulttool/defaulttool/ShapeRotateStrategy.cpp
+++ b/plugins/tools/defaulttool/defaulttool/ShapeRotateStrategy.cpp
@@ -1,111 +1,117 @@
/* This file is part of the KDE project
* Copyright (C) 2006-2007 Thomas Zander
* Copyright (C) 2007-2008 Jan Hambrecht
*
* 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 "ShapeRotateStrategy.h"
#include "SelectionDecorator.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
ShapeRotateStrategy::ShapeRotateStrategy(KoToolBase *tool, const QPointF &clicked, Qt::MouseButtons buttons)
: KoInteractionStrategy(tool)
, m_start(clicked)
{
- m_selectedShapes = tool->canvas()->shapeManager()->selection()->selectedEditableShapes();
- Q_FOREACH (KoShape *shape, m_selectedShapes) {
+ /**
+ * The outline of the selection should look as if it is also rotated, so we
+ * add it to the transformed shapes list.
+ */
+ m_transformedShapesAndSelection = tool->canvas()->shapeManager()->selection()->selectedEditableShapes();
+ m_transformedShapesAndSelection << tool->canvas()->shapeManager()->selection();
+
+ Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
m_oldTransforms << shape->transformation();
}
KoFlake::AnchorPosition anchor = !(buttons & Qt::RightButton) ?
KoFlake::Center :
KoFlake::AnchorPosition(tool->canvas()->resourceManager()->resource(KoFlake::HotPosition).toInt());
m_rotationCenter = tool->canvas()->shapeManager()->selection()->absolutePosition(anchor);
tool->setStatusText(i18n("Press ALT to rotate in 45 degree steps."));
}
void ShapeRotateStrategy::handleMouseMove(const QPointF &point, Qt::KeyboardModifiers modifiers)
{
qreal angle = atan2(point.y() - m_rotationCenter.y(), point.x() - m_rotationCenter.x()) -
atan2(m_start.y() - m_rotationCenter.y(), m_start.x() - m_rotationCenter.x());
angle = angle / M_PI * 180; // convert to degrees.
if (modifiers & (Qt::AltModifier | Qt::ControlModifier)) {
// limit to 45 degree angles
qreal modula = qAbs(angle);
while (modula > 45.0) {
modula -= 45.0;
}
if (modula > 22.5) {
modula -= 45.0;
}
angle += (angle > 0 ? -1 : 1) * modula;
}
rotateBy(angle);
}
void ShapeRotateStrategy::rotateBy(qreal angle)
{
QTransform matrix;
matrix.translate(m_rotationCenter.x(), m_rotationCenter.y());
matrix.rotate(angle);
matrix.translate(-m_rotationCenter.x(), -m_rotationCenter.y());
QTransform applyMatrix = matrix * m_rotationMatrix.inverted();
m_rotationMatrix = matrix;
- Q_FOREACH (KoShape *shape, m_selectedShapes) {
+ Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
const QRectF oldDirtyRect = shape->boundingRect();
shape->applyAbsoluteTransformation(applyMatrix);
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
}
}
void ShapeRotateStrategy::paint(QPainter &painter, const KoViewConverter &converter)
{
// paint the rotation center
painter.setPen(QPen(Qt::red));
painter.setBrush(QBrush(Qt::red));
painter.setRenderHint(QPainter::Antialiasing, true);
QRectF circle(0, 0, 5, 5);
circle.moveCenter(converter.documentToView(m_rotationCenter));
painter.drawEllipse(circle);
}
KUndo2Command *ShapeRotateStrategy::createCommand()
{
QList newTransforms;
- Q_FOREACH (KoShape *shape, m_selectedShapes) {
+ Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
newTransforms << shape->transformation();
}
- KoShapeTransformCommand *cmd = new KoShapeTransformCommand(m_selectedShapes, m_oldTransforms, newTransforms);
+ KoShapeTransformCommand *cmd = new KoShapeTransformCommand(m_transformedShapesAndSelection, m_oldTransforms, newTransforms);
cmd->setText(kundo2_i18n("Rotate"));
return cmd;
}
diff --git a/plugins/tools/defaulttool/defaulttool/ShapeRotateStrategy.h b/plugins/tools/defaulttool/defaulttool/ShapeRotateStrategy.h
index 6f20d3eef4..0ff63222d9 100644
--- a/plugins/tools/defaulttool/defaulttool/ShapeRotateStrategy.h
+++ b/plugins/tools/defaulttool/defaulttool/ShapeRotateStrategy.h
@@ -1,68 +1,68 @@
/* This file is part of the KDE project
* Copyright (C) 2006-2007 Thomas Zander
*
* 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.
*/
#ifndef SHAPEROTATESTRATEGY_H
#define SHAPEROTATESTRATEGY_H
#include
#include
#include
#include
#include
class KoToolBase;
class KoShape;
/**
* A strategy for the KoInteractionTool.
* This strategy is invoked when the user starts a rotate of a selection of objects,
* the stategy will then rotate the objects interactively and provide a command afterwards.
*/
class ShapeRotateStrategy : public KoInteractionStrategy
{
public:
/**
* Constructor that starts to rotate the objects.
* @param tool the parent tool which controls this strategy
* @param clicked the initial point that the user depressed (in pt).
*/
ShapeRotateStrategy(KoToolBase *tool, const QPointF &clicked, Qt::MouseButtons buttons);
~ShapeRotateStrategy() override {}
void handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override;
KUndo2Command *createCommand() override;
void finishInteraction(Qt::KeyboardModifiers modifiers) override
{
Q_UNUSED(modifiers);
}
void paint(QPainter &painter, const KoViewConverter &converter) override;
private:
void rotateBy(qreal angle);
QPointF m_start;
QTransform m_rotationMatrix;
QList m_oldTransforms;
QPointF m_rotationCenter;
- QList m_selectedShapes;
+ QList m_transformedShapesAndSelection;
};
#endif
diff --git a/plugins/tools/defaulttool/defaulttool/ShapeShearStrategy.cpp b/plugins/tools/defaulttool/defaulttool/ShapeShearStrategy.cpp
index 0739e84b1f..0a6318a0b8 100644
--- a/plugins/tools/defaulttool/defaulttool/ShapeShearStrategy.cpp
+++ b/plugins/tools/defaulttool/defaulttool/ShapeShearStrategy.cpp
@@ -1,171 +1,178 @@
/* This file is part of the KDE project
* Copyright (C) 2006-2007 Thomas Zander
* Copyright (C) 2006 C. Boemann
* Copyright (C) 2008 Jan Hambrecht
*
* 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"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
ShapeShearStrategy::ShapeShearStrategy(KoToolBase *tool, const QPointF &clicked, KoFlake::SelectionHandle direction)
: KoInteractionStrategy(tool)
, m_start(clicked)
{
KoSelection *sel = tool->canvas()->shapeManager()->selection();
- m_selectedShapes = sel->selectedEditableShapes();
- Q_FOREACH (KoShape *shape, m_selectedShapes) {
+
+ /**
+ * The outline of the selection should look as if it is also shear'ed, so we
+ * add it to the transformed shapes list.
+ */
+ m_transformedShapesAndSelection = sel->selectedEditableShapes();
+ m_transformedShapesAndSelection << sel;
+
+ Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
m_oldTransforms << shape->transformation();
}
// Eventhoug we aren't currently activated by the corner handles we might as well code like it
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
}
m_initialSize = sel->size();
m_solidPoint = QPointF(m_initialSize.width() / 2, m_initialSize.height() / 2);
if (m_top) {
m_solidPoint += QPointF(0, m_initialSize.height() / 2);
} else if (m_bottom) {
m_solidPoint -= QPointF(0, m_initialSize.height() / 2);
}
if (m_left) {
m_solidPoint += QPointF(m_initialSize.width() / 2, 0);
} else if (m_right) {
m_solidPoint -= QPointF(m_initialSize.width() / 2, 0);
}
m_solidPoint = sel->absoluteTransformation(0).map(sel->outlineRect().topLeft() + m_solidPoint);
QPointF edge;
qreal angle = 0.0;
if (m_top) {
edge = sel->absolutePosition(KoFlake::BottomLeft) - sel->absolutePosition(KoFlake::BottomRight);
angle = 180.0;
} else if (m_bottom) {
edge = sel->absolutePosition(KoFlake::TopRight) - sel->absolutePosition(KoFlake::TopLeft);
angle = 0.0;
} else if (m_left) {
edge = sel->absolutePosition(KoFlake::BottomLeft) - sel->absolutePosition(KoFlake::TopLeft);
angle = 90.0;
} else if (m_right) {
edge = sel->absolutePosition(KoFlake::TopRight) - sel->absolutePosition(KoFlake::BottomRight);
angle = 270.0;
}
qreal currentAngle = atan2(edge.y(), edge.x()) / M_PI * 180;
m_initialSelectionAngle = currentAngle - angle;
// use crossproduct of top edge and left edge of selection bounding rect
// to determine if the selection is mirrored
QPointF top = sel->absolutePosition(KoFlake::TopRight) - sel->absolutePosition(KoFlake::TopLeft);
QPointF left = sel->absolutePosition(KoFlake::BottomLeft) - sel->absolutePosition(KoFlake::TopLeft);
m_isMirrored = (top.x() * left.y() - top.y() * left.x()) < 0.0;
}
void ShapeShearStrategy::handleMouseMove(const QPointF &point, Qt::KeyboardModifiers modifiers)
{
Q_UNUSED(modifiers);
QPointF shearVector = point - m_start;
QTransform m;
m.rotate(-m_initialSelectionAngle);
shearVector = m.map(shearVector);
qreal shearX = 0, shearY = 0;
if (m_top || m_left) {
shearVector = - shearVector;
}
if (m_top || m_bottom) {
shearX = shearVector.x() / m_initialSize.height();
}
if (m_left || m_right) {
shearY = shearVector.y() / m_initialSize.width();
}
// if selection is mirrored invert the shear values
if (m_isMirrored) {
shearX *= -1.0;
shearY *= -1.0;
}
QTransform matrix;
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());
QTransform applyMatrix = matrix * m_shearMatrix.inverted();
- Q_FOREACH (KoShape *shape, m_selectedShapes) {
+ Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
const QRectF oldDirtyRect = shape->boundingRect();
shape->applyAbsoluteTransformation(applyMatrix);
shape->updateAbsolute(oldDirtyRect | shape->boundingRect());
}
m_shearMatrix = matrix;
}
void ShapeShearStrategy::paint(QPainter &painter, const KoViewConverter &converter)
{
Q_UNUSED(painter);
Q_UNUSED(converter);
}
KUndo2Command *ShapeShearStrategy::createCommand()
{
QList newTransforms;
- Q_FOREACH (KoShape *shape, m_selectedShapes) {
+ Q_FOREACH (KoShape *shape, m_transformedShapesAndSelection) {
newTransforms << shape->transformation();
}
- KoShapeTransformCommand *cmd = new KoShapeTransformCommand(m_selectedShapes, m_oldTransforms, newTransforms);
+ KoShapeTransformCommand *cmd = new KoShapeTransformCommand(m_transformedShapesAndSelection, m_oldTransforms, newTransforms);
cmd->setText(kundo2_i18n("Shear"));
return cmd;
}
diff --git a/plugins/tools/defaulttool/defaulttool/ShapeShearStrategy.h b/plugins/tools/defaulttool/defaulttool/ShapeShearStrategy.h
index 53667a1304..a24a145dfd 100644
--- a/plugins/tools/defaulttool/defaulttool/ShapeShearStrategy.h
+++ b/plugins/tools/defaulttool/defaulttool/ShapeShearStrategy.h
@@ -1,71 +1,71 @@
/* This file is part of the KDE project
* Copyright (C) 2006-2007 Thomas Zander
*
* 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.
*/
#ifndef SHAPESHEARSTRATEGY_H
#define SHAPESHEARSTRATEGY_H
#include
#include
#include
#include
#include
class KoToolBase;
class KoShape;
/**
* A strategy for the KoInteractionTool.
* This strategy is invoked when the user starts a shear of a selection of objects,
* the stategy will then shear the objects interactively and provide a command afterwards.
*/
class ShapeShearStrategy : public KoInteractionStrategy
{
public:
/**
* Constructor that starts to rotate the objects.
* @param tool the parent tool which controls this strategy
* @param clicked the initial point that the user depressed (in pt).
* @param direction the handle that was grabbed
*/
ShapeShearStrategy(KoToolBase *tool, const QPointF &clicked, KoFlake::SelectionHandle direction);
~ShapeShearStrategy() override {}
void handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override;
KUndo2Command *createCommand() override;
void finishInteraction(Qt::KeyboardModifiers modifiers) override
{
Q_UNUSED(modifiers);
}
void paint(QPainter &painter, const KoViewConverter &converter) override;
private:
QPointF m_start;
QPointF m_solidPoint;
QSizeF m_initialSize;
bool m_top, m_left, m_bottom, m_right;
qreal m_initialSelectionAngle;
QTransform m_shearMatrix;
bool m_isMirrored;
QList m_oldTransforms;
- QList m_selectedShapes;
+ QList m_transformedShapesAndSelection;
};
#endif