diff --git a/krita/data/actions/InteractionTool.action b/krita/data/actions/InteractionTool.action
--- a/krita/data/actions/InteractionTool.action
+++ b/krita/data/actions/InteractionTool.action
@@ -122,5 +122,87 @@
false
Align Bottom
+
+
+ Distribute Left
+ l
+ Distribute left edges equidistantly
+
+ object_distribute_horizontal_left
+
+
+ false
+
+
+ Distribute Centers Horizontally
+ c
+ Distribute centers equidistantly horizontally
+
+ object_distribute_horizontal_center
+
+
+ false
+
+
+ Distribute Right
+ r
+ Distribute right edges equidistantly
+
+ object_distribute_horizontal_right
+
+
+ false
+
+
+ Distribute Horizontal Gap
+ g
+ Make horizontal gaps between objects equal
+
+ object_distribute_horizontal_gaps
+
+
+ false
+
+
+
+ Distribute Top
+ t
+ Distribute top edges equidistantly
+
+ object_distribute_vertical_top
+
+
+ false
+
+
+ Distribute Centers Vertically
+ c
+ Distribute centers equidistantly vertically
+
+ object_distribute_vertical_center
+
+
+ false
+
+
+ Distribute Bottom
+ b
+ Distribute bottom edges equidistantly
+
+ object_distribute_vertical_bottom
+
+
+ false
+
+
+ Distribute Vertical Gap
+ g
+ Make vertical gaps between objects equal
+
+ object_distribute_vertical_gaps
+
+
+ false
+
diff --git a/krita/krita.action b/krita/krita.action
--- a/krita/krita.action
+++ b/krita/krita.action
@@ -388,18 +388,6 @@
true
-
-
- Paste at cursor
-
- Paste at cursor
- Paste at cursor
- 0
- 0
-
- false
-
-
&Invert Selection
diff --git a/krita/krita.xmlgui b/krita/krita.xmlgui
--- a/krita/krita.xmlgui
+++ b/krita/krita.xmlgui
@@ -2,7 +2,7 @@
+
+
+ Paste at Cursor
+
+ Paste at cursor
+ Paste at cursor
+ 0
+ 0
+ Ctrl+Alt+V
+ false
+
+
Paste into &New Image
diff --git a/krita/pics/misc-dark/dark_geometry.svg b/krita/pics/misc-dark/dark_geometry.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_geometry.svg
@@ -0,0 +1,70 @@
+
+
diff --git a/krita/pics/misc-dark/dark_path-break-point.svg b/krita/pics/misc-dark/dark_path-break-point.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_path-break-point.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-dark/dark_path-break-segment.svg b/krita/pics/misc-dark/dark_path-break-segment.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_path-break-segment.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathpoint-corner.svg b/krita/pics/misc-dark/dark_pathpoint-corner.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathpoint-corner.svg
@@ -0,0 +1,94 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathpoint-curve.svg b/krita/pics/misc-dark/dark_pathpoint-curve.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathpoint-curve.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathpoint-insert.svg b/krita/pics/misc-dark/dark_pathpoint-insert.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathpoint-insert.svg
@@ -0,0 +1,80 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathpoint-join.svg b/krita/pics/misc-dark/dark_pathpoint-join.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathpoint-join.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathpoint-line.svg b/krita/pics/misc-dark/dark_pathpoint-line.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathpoint-line.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathpoint-merge.svg b/krita/pics/misc-dark/dark_pathpoint-merge.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathpoint-merge.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathpoint-remove.svg b/krita/pics/misc-dark/dark_pathpoint-remove.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathpoint-remove.svg
@@ -0,0 +1,91 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathpoint-smooth.svg b/krita/pics/misc-dark/dark_pathpoint-smooth.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathpoint-smooth.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathpoint-symmetric.svg b/krita/pics/misc-dark/dark_pathpoint-symmetric.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathpoint-symmetric.svg
@@ -0,0 +1,94 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathsegment-curve.svg b/krita/pics/misc-dark/dark_pathsegment-curve.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathsegment-curve.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/krita/pics/misc-dark/dark_pathsegment-line.svg b/krita/pics/misc-dark/dark_pathsegment-line.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-dark/dark_pathsegment-line.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/krita/pics/misc-dark/misc-dark-icons.qrc b/krita/pics/misc-dark/misc-dark-icons.qrc
--- a/krita/pics/misc-dark/misc-dark-icons.qrc
+++ b/krita/pics/misc-dark/misc-dark-icons.qrc
@@ -2,6 +2,7 @@
dark_draw-eraser.svg
+ dark_geometry.svg
dark_ox16-action-object-align-horizontal-center-calligra.svg
dark_ox16-action-object-align-horizontal-left-calligra.svg
dark_ox16-action-object-align-horizontal-right-calligra.svg
@@ -28,5 +29,19 @@
dark_onionOff.svg
dark_onionOn.svg
dark_onion_skin_options.svg
+ dark_onion_skin_options.svg
+ dark_path-break-point.svg
+ dark_path-break-segment.svg
+ dark_pathpoint-corner.svg
+ dark_pathpoint-curve.svg
+ dark_pathpoint-insert.svg
+ dark_pathpoint-join.svg
+ dark_pathpoint-line.svg
+ dark_pathpoint-merge.svg
+ dark_pathpoint-remove.svg
+ dark_pathpoint-smooth.svg
+ dark_pathpoint-symmetric.svg
+ dark_pathsegment-curve.svg
+ dark_pathsegment-line.svg
diff --git a/krita/pics/misc-light/light_geometry.svg b/krita/pics/misc-light/light_geometry.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_geometry.svg
@@ -0,0 +1,70 @@
+
+
diff --git a/krita/pics/misc-light/light_path-break-point.svg b/krita/pics/misc-light/light_path-break-point.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_path-break-point.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-light/light_path-break-segment.svg b/krita/pics/misc-light/light_path-break-segment.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_path-break-segment.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-light/light_pathpoint-corner.svg b/krita/pics/misc-light/light_pathpoint-corner.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathpoint-corner.svg
@@ -0,0 +1,94 @@
+
+
diff --git a/krita/pics/misc-light/light_pathpoint-curve.svg b/krita/pics/misc-light/light_pathpoint-curve.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathpoint-curve.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-light/light_pathpoint-insert.svg b/krita/pics/misc-light/light_pathpoint-insert.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathpoint-insert.svg
@@ -0,0 +1,80 @@
+
+
diff --git a/krita/pics/misc-light/light_pathpoint-join.svg b/krita/pics/misc-light/light_pathpoint-join.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathpoint-join.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-light/light_pathpoint-line.svg b/krita/pics/misc-light/light_pathpoint-line.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathpoint-line.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-light/light_pathpoint-merge.svg b/krita/pics/misc-light/light_pathpoint-merge.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathpoint-merge.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-light/light_pathpoint-remove.svg b/krita/pics/misc-light/light_pathpoint-remove.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathpoint-remove.svg
@@ -0,0 +1,91 @@
+
+
diff --git a/krita/pics/misc-light/light_pathpoint-smooth.svg b/krita/pics/misc-light/light_pathpoint-smooth.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathpoint-smooth.svg
@@ -0,0 +1,79 @@
+
+
diff --git a/krita/pics/misc-light/light_pathpoint-symmetric.svg b/krita/pics/misc-light/light_pathpoint-symmetric.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathpoint-symmetric.svg
@@ -0,0 +1,94 @@
+
+
diff --git a/krita/pics/misc-light/light_pathsegment-curve.svg b/krita/pics/misc-light/light_pathsegment-curve.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathsegment-curve.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/krita/pics/misc-light/light_pathsegment-line.svg b/krita/pics/misc-light/light_pathsegment-line.svg
new file mode 100644
--- /dev/null
+++ b/krita/pics/misc-light/light_pathsegment-line.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/krita/pics/misc-light/misc-light-icons.qrc b/krita/pics/misc-light/misc-light-icons.qrc
--- a/krita/pics/misc-light/misc-light-icons.qrc
+++ b/krita/pics/misc-light/misc-light-icons.qrc
@@ -2,6 +2,7 @@
light_draw-eraser.svg
+ light_geometry.svg
light_ox16-action-object-align-horizontal-center-calligra.svg
light_ox16-action-object-align-horizontal-left-calligra.svg
light_ox16-action-object-align-horizontal-right-calligra.svg
@@ -28,5 +29,18 @@
light_onionOff.svg
light_onionOn.svg
light_onion_skin_options.svg
+ light_path-break-point.svg
+ light_path-break-segment.svg
+ light_pathpoint-corner.svg
+ light_pathpoint-curve.svg
+ light_pathpoint-insert.svg
+ light_pathpoint-join.svg
+ light_pathpoint-line.svg
+ light_pathpoint-merge.svg
+ light_pathpoint-remove.svg
+ light_pathpoint-smooth.svg
+ light_pathpoint-symmetric.svg
+ light_pathsegment-curve.svg
+ light_pathsegment-line.svg
diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt
--- a/libs/CMakeLists.txt
+++ b/libs/CMakeLists.txt
@@ -8,7 +8,7 @@
add_subdirectory( flake )
add_subdirectory( basicflakes )
add_subdirectory( pigment )
-add_subdirectory( kundo2 )
+add_subdirectory( command )
add_subdirectory( brush )
add_subdirectory( psd )
add_subdirectory( color )
diff --git a/libs/basicflakes/CMakeLists.txt b/libs/basicflakes/CMakeLists.txt
--- a/libs/basicflakes/CMakeLists.txt
+++ b/libs/basicflakes/CMakeLists.txt
@@ -25,7 +25,8 @@
target_link_libraries(kritabasicflakes
PUBLIC
- kritawidgets
+ kritaui
+ kritawidgets
kritaflake
kritapigment
)
diff --git a/libs/basicflakes/tools/KoCreatePathTool.h b/libs/basicflakes/tools/KoCreatePathTool.h
--- a/libs/basicflakes/tools/KoCreatePathTool.h
+++ b/libs/basicflakes/tools/KoCreatePathTool.h
@@ -23,6 +23,7 @@
#include "kritabasicflakes_export.h"
+#include
#include
#include
@@ -72,7 +73,7 @@
public Q_SLOTS:
/// reimplemented
- virtual void activate(ToolActivation toolActivation, const QSet &shapes);
+ virtual void activate(ToolActivation activation, const QSet &shapes);
/// reimplemented
virtual void deactivate();
/// reimplemented
@@ -101,8 +102,6 @@
virtual QList > createOptionWidgets();
private:
- KoShapeStroke *createStroke();
-
Q_DECLARE_PRIVATE(KoCreatePathTool)
Q_PRIVATE_SLOT(d_func(), void angleDeltaChanged(int))
Q_PRIVATE_SLOT(d_func(), void angleSnapChanged(int))
diff --git a/libs/basicflakes/tools/KoCreatePathTool.cpp b/libs/basicflakes/tools/KoCreatePathTool.cpp
--- a/libs/basicflakes/tools/KoCreatePathTool.cpp
+++ b/libs/basicflakes/tools/KoCreatePathTool.cpp
@@ -22,16 +22,18 @@
#include "KoCreatePathTool.h"
#include "KoCreatePathTool_p.h"
+#include
#include "KoPointerEvent.h"
#include "KoPathShape.h"
#include "KoSelection.h"
#include "KoDocumentResourceManager.h"
#include "KoShapePaintingContext.h"
#include "KoShapeStroke.h"
-#include "KoStrokeConfigWidget.h"
#include "KoCanvasBase.h"
#include "kis_int_parse_spin_box.h"
#include
+#include "kis_canvas_resource_provider.h"
+#include
#include
@@ -57,62 +59,39 @@
if (pathStarted()) {
- KoShapeStroke *stroke(createStroke());
-
- if (stroke) {
- d->shape->setStroke(stroke);
- }
-
painter.save();
paintPath(*(d->shape), painter, converter);
painter.restore();
- painter.save();
-
- painter.setTransform(d->shape->absoluteTransformation(&converter) * painter.transform());
-
- KoShape::applyConversion(painter, converter);
+ KisHandlePainterHelper helper =
+ KoShape::createHandlePainterHelper(&painter, d->shape, converter, d->handleRadius);
- QPen pen(QBrush(Qt::blue), 1);
- pen.setCosmetic(true);
- painter.setPen(pen);
- painter.setBrush(Qt::white);
+ const bool firstPointActive = d->firstPoint == d->activePoint;
- const bool firstPoint = (d->firstPoint == d->activePoint);
-
- if (d->pointIsDragged || firstPoint) {
+ if (d->pointIsDragged || firstPointActive) {
const bool onlyPaintActivePoints = false;
KoPathPoint::PointTypes paintFlags = KoPathPoint::ControlPoint2;
if (d->activePoint->activeControlPoint1()) {
paintFlags |= KoPathPoint::ControlPoint1;
}
- d->activePoint->paint(painter, d->handleRadius, paintFlags, onlyPaintActivePoints);
- }
-
- // check if we have to color the first point
- if (d->mouseOverFirstPoint) {
- painter.setBrush(Qt::red);
- } else {
- painter.setBrush(Qt::white);
+ helper.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles());
+ d->activePoint->paint(helper, paintFlags, onlyPaintActivePoints);
}
- d->firstPoint->paint(painter, d->handleRadius, KoPathPoint::Node);
-
- painter.restore();
+ if (!firstPointActive) {
+ helper.setHandleStyle(d->mouseOverFirstPoint ?
+ KisHandleStyle::highlightedPrimaryHandles() :
+ KisHandleStyle::primarySelection());
+ d->firstPoint->paint(helper, KoPathPoint::Node);
+ }
}
if (d->hoveredPoint) {
- painter.save();
- painter.setTransform(d->hoveredPoint->parent()->absoluteTransformation(&converter), true);
- KoShape::applyConversion(painter, converter);
- QPen pen(QBrush(Qt::blue), 1);
- pen.setCosmetic(true);
- painter.setPen(pen);
- painter.setBrush(Qt::white);
- d->hoveredPoint->paint(painter, d->handleRadius, KoPathPoint::Node);
- painter.restore();
+ KisHandlePainterHelper helper = KoShape::createHandlePainterHelper(&painter, d->hoveredPoint->parent(), converter, d->handleRadius);
+ helper.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles());
+ d->hoveredPoint->paint(helper, KoPathPoint::Node);
}
painter.save();
@@ -199,7 +178,10 @@
d->shape = pathShape;
pathShape->setShapeId(KoPathShapeId);
- KoShapeStroke *stroke = new KoShapeStroke(canvas()->resourceManager()->activeStroke());
+ KoShapeStrokeSP stroke(new KoShapeStroke());
+ const qreal size = canvas()->resourceManager()->resource(KisCanvasResourceProvider::Size).toReal();
+
+ stroke->setLineWidth(canvas()->unit().fromUserValue(size));
stroke->setColor(canvas()->resourceManager()->foregroundColor().toQColor());
pathShape->setStroke(stroke);
@@ -218,7 +200,7 @@
canvas()->updateCanvas(handlePaintRect(point));
canvas()->updateCanvas(canvas()->snapGuide()->boundingRect());
- canvas()->snapGuide()->setEditedShape(pathShape);
+ canvas()->snapGuide()->setAdditionalEditedShape(pathShape);
d->angleSnapStrategy = new AngleSnapStrategy(d->angleSnappingDelta, d->angleSnapStatus);
canvas()->snapGuide()->addCustomSnapStrategy(d->angleSnapStrategy);
@@ -407,8 +389,10 @@
}
}
-void KoCreatePathTool::activate(ToolActivation, const QSet &)
+void KoCreatePathTool::activate(ToolActivation activation, const QSet &shapes)
{
+ KoToolBase::activate(activation, shapes);
+
Q_D(KoCreatePathTool);
useCursor(Qt::ArrowCursor);
@@ -423,6 +407,7 @@
void KoCreatePathTool::deactivate()
{
cancelPath();
+ KoToolBase::deactivate();
}
void KoCreatePathTool::documentResourceChanged(int key, const QVariant & res)
@@ -451,7 +436,6 @@
d->existingStartPoint.validate(canvas());
d->existingEndPoint.validate(canvas());
- pathShape->setStroke(createStroke());
if (d->connectPaths(pathShape, d->existingStartPoint, d->existingEndPoint)) {
if (d->existingStartPoint.isValid()) {
startShape = d->existingStartPoint.path;
@@ -506,28 +490,11 @@
angleWidget->setWindowTitle(i18n("Angle Constraints"));
list.append(angleWidget);
- d->strokeWidget = new KoStrokeConfigWidget(0);
- d->strokeWidget->setWindowTitle(i18n("Line"));
- d->strokeWidget->setCanvas(canvas());
- d->strokeWidget->setActive(false);
- list.append(d->strokeWidget);
-
connect(angleEdit, SIGNAL(valueChanged(int)), this, SLOT(angleDeltaChanged(int)));
connect(angleSnap, SIGNAL(stateChanged(int)), this, SLOT(angleSnapChanged(int)));
return list;
}
-KoShapeStroke *KoCreatePathTool::createStroke()
-{
- Q_D(KoCreatePathTool);
-
- KoShapeStroke *stroke = 0;
- if (d->strokeWidget) {
- stroke = d->strokeWidget->createShapeStroke();
- }
- return stroke;
-}
-
//have to include this because of Q_PRIVATE_SLOT
#include
diff --git a/libs/basicflakes/tools/KoCreatePathTool_p.h b/libs/basicflakes/tools/KoCreatePathTool_p.h
--- a/libs/basicflakes/tools/KoCreatePathTool_p.h
+++ b/libs/basicflakes/tools/KoCreatePathTool_p.h
@@ -190,8 +190,8 @@
listeningToModifiers(false),
angleSnapStrategy(0),
angleSnappingDelta(15),
- angleSnapStatus(false),
- strokeWidget(0) {
+ angleSnapStatus(false)
+ {
}
KoPathShape *shape;
@@ -209,7 +209,6 @@
AngleSnapStrategy *angleSnapStrategy;
int angleSnappingDelta;
bool angleSnapStatus;
- KoStrokeConfigWidget *strokeWidget;
void repaintActivePoint() const {
const bool isFirstPoint = (activePoint == firstPoint);
diff --git a/libs/basicflakes/tools/KoPencilTool.h b/libs/basicflakes/tools/KoPencilTool.h
--- a/libs/basicflakes/tools/KoPencilTool.h
+++ b/libs/basicflakes/tools/KoPencilTool.h
@@ -20,6 +20,7 @@
#ifndef _KOPENCILTOOL_H_
#define _KOPENCILTOOL_H_
+#include "KoFlakeTypes.h"
#include "KoToolBase.h"
class KoPathShape;
@@ -44,7 +45,7 @@
void mouseReleaseEvent(KoPointerEvent *event);
void keyPressEvent(QKeyEvent *event);
- virtual void activate(ToolActivation toolActivation, const QSet &shapes);
+ virtual void activate(ToolActivation activation, const QSet &shapes);
void deactivate();
protected:
@@ -57,14 +58,18 @@
*/
virtual void addPathShape(KoPathShape* path, bool closePath);
- KoShapeStroke* createStroke();
+ KoShapeStrokeSP createStroke();
void setFittingError(qreal fittingError);
qreal getFittingError();
private Q_SLOTS:
void selectMode(int mode);
void setOptimize(int state);
void setDelta(double delta);
+
+protected Q_SLOTS:
+ virtual void slotUpdatePencilCursor();
+
private:
qreal lineAngle(const QPointF &p1, const QPointF &p2);
diff --git a/libs/basicflakes/tools/KoPencilTool.cpp b/libs/basicflakes/tools/KoPencilTool.cpp
--- a/libs/basicflakes/tools/KoPencilTool.cpp
+++ b/libs/basicflakes/tools/KoPencilTool.cpp
@@ -34,7 +34,8 @@
#include
#include
#include
-#include
+#include
+#include
#include
@@ -64,6 +65,7 @@
, m_existingStartPoint(0)
, m_existingEndPoint(0)
, m_hoveredPoint(0)
+ , m_strokeWidget(0)
{
}
@@ -93,15 +95,11 @@
}
if (m_hoveredPoint) {
- painter.save();
- painter.setTransform(m_hoveredPoint->parent()->absoluteTransformation(&converter), true);
- KoShape::applyConversion(painter, converter);
-
- painter.setPen(QPen(Qt::blue, 0)); //TODO make configurable
- painter.setBrush(Qt::white); //TODO make configurable
- m_hoveredPoint->paint(painter, handleRadius(), KoPathPoint::Node);
+ KisHandlePainterHelper helper =
+ KoShape::createHandlePainterHelper(&painter, m_hoveredPoint->parent(), converter, handleRadius());
- painter.restore();
+ helper.setHandleStyle(KisHandleStyle::primarySelection());
+ m_hoveredPoint->paint(helper, KoPathPoint::Node);
}
}
@@ -111,7 +109,9 @@
void KoPencilTool::mousePressEvent(KoPointerEvent *event)
{
- if (! m_shape) {
+ KoShapeStrokeSP stroke = createStroke();
+
+ if (!m_shape && stroke && stroke->isVisible()) {
m_shape = new KoPathShape();
m_shape->setShapeId(KoPathShapeId);
m_shape->setStroke(createStroke());
@@ -178,11 +178,17 @@
}
}
-void KoPencilTool::activate(ToolActivation, const QSet &)
+void KoPencilTool::activate(ToolActivation activation, const QSet &shapes)
{
+ KoToolBase::activate(activation, shapes);
+
m_points.clear();
m_close = false;
- useCursor(Qt::ArrowCursor);
+ slotUpdatePencilCursor();
+
+ if (m_strokeWidget) {
+ m_strokeWidget->activate();
+ }
}
void KoPencilTool::deactivate()
@@ -193,6 +199,18 @@
m_existingStartPoint = 0;
m_existingEndPoint = 0;
m_hoveredPoint = 0;
+
+ if (m_strokeWidget) {
+ m_strokeWidget->deactivate();
+ }
+
+ KoToolBase::deactivate();
+}
+
+void KoPencilTool::slotUpdatePencilCursor()
+{
+ KoShapeStrokeSP stroke = createStroke();
+ useCursor((stroke && stroke->isVisible()) ? Qt::ArrowCursor : Qt::ForbiddenCursor);
}
void KoPencilTool::addPoint(const QPointF & point)
@@ -353,9 +371,13 @@
optionWidget->setWindowTitle(i18n("Pencil"));
widgets.append(optionWidget);
- m_strokeWidget = new KoStrokeConfigWidget(0);
+ m_strokeWidget = new KoStrokeConfigWidget(canvas(), 0);
+ m_strokeWidget->setNoSelectionTrackingMode(true);
m_strokeWidget->setWindowTitle(i18n("Line"));
- m_strokeWidget->setCanvas(canvas());
+ connect(m_strokeWidget, SIGNAL(sigStrokeChanged()), SLOT(slotUpdatePencilCursor()));
+ if (isActivated()) {
+ m_strokeWidget->activate();
+ }
widgets.append(m_strokeWidget);
return widgets;
}
@@ -417,9 +439,9 @@
m_combineAngle = delta;
}
-KoShapeStroke* KoPencilTool::createStroke()
+KoShapeStrokeSP KoPencilTool::createStroke()
{
- KoShapeStroke *stroke = 0;
+ KoShapeStrokeSP stroke;
if (m_strokeWidget) {
stroke = m_strokeWidget->createShapeStroke();
}
diff --git a/libs/command/CMakeLists.txt b/libs/command/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/libs/command/CMakeLists.txt
@@ -0,0 +1,28 @@
+set(kritacommand_LIB_SRCS
+ kundo2stack.cpp
+ kundo2group.cpp
+ kundo2view.cpp
+ kundo2model.cpp
+ kundo2magicstring.cpp
+ kundo2commandextradata.cpp
+ kis_undo_store.cpp
+ kis_undo_stores.cpp
+ kis_command_utils.cpp
+)
+
+add_library(kritacommand SHARED ${kritacommand_LIB_SRCS})
+generate_export_header(kritacommand BASE_NAME kritacommand)
+
+target_link_libraries(kritacommand
+ PUBLIC
+ kritawidgetutils
+ KF5::I18n
+ KF5::ConfigGui
+ Qt5::Core
+ Qt5::Widgets
+)
+
+set_target_properties(kritacommand PROPERTIES
+ VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
+)
+install(TARGETS kritacommand ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/libs/kundo2/Mainpage.dox b/libs/command/Mainpage.dox
rename from libs/kundo2/Mainpage.dox
rename to libs/command/Mainpage.dox
diff --git a/libs/image/tests/kis_algebra_2d_test.h b/libs/command/kis_command_ids.h
copy from libs/image/tests/kis_algebra_2d_test.h
copy to libs/command/kis_command_ids.h
--- a/libs/image/tests/kis_algebra_2d_test.h
+++ b/libs/command/kis_command_ids.h
@@ -16,21 +16,26 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __KIS_ALGEBRA_2D_TEST_H
-#define __KIS_ALGEBRA_2D_TEST_H
+#ifndef KIS_COMMAND_IDS_H
+#define KIS_COMMAND_IDS_H
-#include
+namespace KisCommandUtils {
+enum CommandId {
+ MoveShapeId = 9999,
+ ResizeShapeId,
+ TransformShapeId,
+ ChangeShapeTransparencyId,
+ ChangeShapeBackgroundId,
+ ChangeShapeStrokeId,
+ ChangeShapeMarkersId,
+ ChangeShapeParameterId,
+ ChangeEllipseShapeId,
+ ChangeRectangleShapeId,
+ ChangePathShapePointId,
+ ChangePathShapeControlPointId
+};
-class KisAlgebra2DTest : public QObject
-{
- Q_OBJECT
-private Q_SLOTS:
- void testHalfPlane();
- void testOuterCircle();
+}
- void testQuadraticEquation();
- void testIntersections();
- void testWeirdIntersections();
-};
+#endif // KIS_COMMAND_IDS_H
-#endif /* __KIS_ALGEBRA_2D_TEST_H */
diff --git a/libs/image/kis_command_utils.h b/libs/command/kis_command_utils.h
rename from libs/image/kis_command_utils.h
rename to libs/command/kis_command_utils.h
--- a/libs/image/kis_command_utils.h
+++ b/libs/command/kis_command_utils.h
@@ -21,11 +21,11 @@
#include "kundo2command.h"
#include "kis_undo_stores.h"
-#include "kritaimage_export.h"
+#include "kritacommand_export.h"
namespace KisCommandUtils
{
- struct KRITAIMAGE_EXPORT AggregateCommand : public KUndo2Command {
+ struct KRITACOMMAND_EXPORT AggregateCommand : public KUndo2Command {
AggregateCommand();
void redo();
@@ -40,17 +40,35 @@
KisSurrogateUndoStore m_store;
};
- struct KRITAIMAGE_EXPORT SkipFirstRedoWrapper : public KUndo2Command {
+ struct KRITACOMMAND_EXPORT SkipFirstRedoWrapper : public KUndo2Command {
SkipFirstRedoWrapper(KUndo2Command *child = 0, KUndo2Command *parent = 0);
- void redo();
- void undo();
+ void redo() override;
+ void undo() override;
private:
bool m_firstRedo;
QScopedPointer m_child;
};
- struct KRITAIMAGE_EXPORT FlipFlopCommand : public KUndo2Command {
+ struct KRITACOMMAND_EXPORT SkipFirstRedoBase : public KUndo2Command {
+ SkipFirstRedoBase(bool skipFirstRedo, KUndo2Command *parent = 0);
+ SkipFirstRedoBase(bool skipFirstRedo, const KUndo2MagicString &text, KUndo2Command *parent = 0);
+
+ void redo() final;
+ void undo() final;
+
+ void setSkipOneRedo(bool value);
+
+ protected:
+ virtual void redoImpl() = 0;
+ virtual void undoImpl() = 0;
+
+ private:
+ bool m_firstRedo;
+ };
+
+
+ struct KRITACOMMAND_EXPORT FlipFlopCommand : public KUndo2Command {
FlipFlopCommand(bool finalize, KUndo2Command *parent = 0);
void redo();
@@ -67,7 +85,7 @@
bool m_firstRedo;
};
- struct KRITAIMAGE_EXPORT CompositeCommand : public KUndo2Command {
+ struct KRITACOMMAND_EXPORT CompositeCommand : public KUndo2Command {
CompositeCommand(KUndo2Command *parent = 0);
~CompositeCommand();
diff --git a/libs/image/kis_command_utils.cpp b/libs/command/kis_command_utils.cpp
rename from libs/image/kis_command_utils.cpp
rename to libs/command/kis_command_utils.cpp
--- a/libs/image/kis_command_utils.cpp
+++ b/libs/command/kis_command_utils.cpp
@@ -45,7 +45,7 @@
}
SkipFirstRedoWrapper::SkipFirstRedoWrapper(KUndo2Command *child, KUndo2Command *parent)
- : KUndo2Command(parent), m_firstRedo(true), m_child(child) {}
+ : KUndo2Command(child->text(), parent), m_firstRedo(true), m_child(child) {}
void SkipFirstRedoWrapper::redo()
{
@@ -67,6 +67,39 @@
}
}
+ SkipFirstRedoBase::SkipFirstRedoBase(bool skipFirstRedo, KUndo2Command *parent)
+ : KUndo2Command(parent),
+ m_firstRedo(skipFirstRedo)
+ {
+ }
+
+ SkipFirstRedoBase::SkipFirstRedoBase(bool skipFirstRedo, const KUndo2MagicString &text, KUndo2Command *parent)
+ : KUndo2Command(text, parent),
+ m_firstRedo(skipFirstRedo)
+ {
+ }
+
+ void SkipFirstRedoBase::redo()
+ {
+ if (m_firstRedo) {
+ m_firstRedo = false;
+ } else {
+ redoImpl();
+ KUndo2Command::redo();
+ }
+ }
+
+ void SkipFirstRedoBase::undo()
+ {
+ KUndo2Command::undo();
+ undoImpl();
+ }
+
+ void SkipFirstRedoBase::setSkipOneRedo(bool value)
+ {
+ m_firstRedo = true;
+ }
+
FlipFlopCommand::FlipFlopCommand(bool finalize, KUndo2Command *parent)
: KUndo2Command(parent),
m_finalize(finalize),
diff --git a/libs/image/kis_undo_store.h b/libs/command/kis_undo_store.h
rename from libs/image/kis_undo_store.h
rename to libs/command/kis_undo_store.h
--- a/libs/image/kis_undo_store.h
+++ b/libs/command/kis_undo_store.h
@@ -22,7 +22,7 @@
#include
#include
-#include
+#include
class KUndo2Command;
class KUndo2MagicString;
@@ -54,7 +54,7 @@
* KisDocument::createUndoStore() is just a factory method, the document
* doesn't store the undo store itself.
*/
-class KRITAIMAGE_EXPORT KisUndoStore
+class KRITACOMMAND_EXPORT KisUndoStore
{
public:
KisUndoStore();
diff --git a/libs/image/kis_undo_store.cpp b/libs/command/kis_undo_store.cpp
rename from libs/image/kis_undo_store.cpp
rename to libs/command/kis_undo_store.cpp
diff --git a/libs/image/kis_undo_stores.h b/libs/command/kis_undo_stores.h
rename from libs/image/kis_undo_stores.h
rename to libs/command/kis_undo_stores.h
--- a/libs/image/kis_undo_stores.h
+++ b/libs/command/kis_undo_stores.h
@@ -30,7 +30,7 @@
* internal stack. Used for wrapping around legacy code into
* a single command.
*/
-class KRITAIMAGE_EXPORT KisSurrogateUndoStore : public KisUndoStore
+class KRITACOMMAND_EXPORT KisSurrogateUndoStore : public KisUndoStore
{
public:
KisSurrogateUndoStore();
@@ -60,7 +60,7 @@
* @brief The KisDumbUndoStore class doesn't actually save commands,
* so you cannot undo or redo!
*/
-class KRITAIMAGE_EXPORT KisDumbUndoStore : public KisUndoStore
+class KRITACOMMAND_EXPORT KisDumbUndoStore : public KisUndoStore
{
public:
const KUndo2Command* presentCommand();
diff --git a/libs/image/kis_undo_stores.cpp b/libs/command/kis_undo_stores.cpp
rename from libs/image/kis_undo_stores.cpp
rename to libs/command/kis_undo_stores.cpp
diff --git a/libs/kundo2/kundo2command.h b/libs/command/kundo2command.h
rename from libs/kundo2/kundo2command.h
rename to libs/command/kundo2command.h
diff --git a/libs/kundo2/kundo2commandextradata.h b/libs/command/kundo2commandextradata.h
rename from libs/kundo2/kundo2commandextradata.h
rename to libs/command/kundo2commandextradata.h
--- a/libs/kundo2/kundo2commandextradata.h
+++ b/libs/command/kundo2commandextradata.h
@@ -19,10 +19,10 @@
#ifndef __KUNDO2COMMANDEXTRADATA_H
#define __KUNDO2COMMANDEXTRADATA_H
-#include "kritaundo2_export.h"
+#include "kritacommand_export.h"
-class KRITAUNDO2_EXPORT KUndo2CommandExtraData
+class KRITACOMMAND_EXPORT KUndo2CommandExtraData
{
public:
virtual ~KUndo2CommandExtraData();
diff --git a/libs/kundo2/kundo2commandextradata.cpp b/libs/command/kundo2commandextradata.cpp
rename from libs/kundo2/kundo2commandextradata.cpp
rename to libs/command/kundo2commandextradata.cpp
diff --git a/libs/kundo2/kundo2group.h b/libs/command/kundo2group.h
rename from libs/kundo2/kundo2group.h
rename to libs/command/kundo2group.h
--- a/libs/kundo2/kundo2group.h
+++ b/libs/command/kundo2group.h
@@ -45,15 +45,15 @@
#include
#include
-#include "kritaundo2_export.h"
+#include "kritacommand_export.h"
class KUndo2GroupPrivate;
class KUndo2QStack;
class QAction;
#ifndef QT_NO_UNDOGROUP
-class KRITAUNDO2_EXPORT KUndo2Group : public QObject
+class KRITACOMMAND_EXPORT KUndo2Group : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(KUndo2Group)
diff --git a/libs/kundo2/kundo2group.cpp b/libs/command/kundo2group.cpp
rename from libs/kundo2/kundo2group.cpp
rename to libs/command/kundo2group.cpp
diff --git a/libs/kundo2/kundo2magicstring.h b/libs/command/kundo2magicstring.h
rename from libs/kundo2/kundo2magicstring.h
rename to libs/command/kundo2magicstring.h
--- a/libs/kundo2/kundo2magicstring.h
+++ b/libs/command/kundo2magicstring.h
@@ -26,7 +26,7 @@
#include
-#include "kritaundo2_export.h"
+#include "kritacommand_export.h"
/**
* \class KUndo2MagicString is a special wrapper for a string that is
@@ -48,7 +48,7 @@
* because in many languages you cannot combine words without
* knowing the proper case.
*/
-class KRITAUNDO2_EXPORT KUndo2MagicString
+class KRITACOMMAND_EXPORT KUndo2MagicString
{
public:
/**
diff --git a/libs/kundo2/kundo2magicstring.cpp b/libs/command/kundo2magicstring.cpp
rename from libs/kundo2/kundo2magicstring.cpp
rename to libs/command/kundo2magicstring.cpp
diff --git a/libs/kundo2/kundo2model.h b/libs/command/kundo2model.h
rename from libs/kundo2/kundo2model.h
rename to libs/command/kundo2model.h
diff --git a/libs/kundo2/kundo2model.cpp b/libs/command/kundo2model.cpp
rename from libs/kundo2/kundo2model.cpp
rename to libs/command/kundo2model.cpp
diff --git a/libs/kundo2/kundo2qstack.h b/libs/command/kundo2qstack.h
rename from libs/kundo2/kundo2qstack.h
rename to libs/command/kundo2qstack.h
diff --git a/libs/kundo2/kundo2stack.h b/libs/command/kundo2stack.h
rename from libs/kundo2/kundo2stack.h
rename to libs/command/kundo2stack.h
--- a/libs/kundo2/kundo2stack.h
+++ b/libs/command/kundo2stack.h
@@ -68,7 +68,7 @@
#include
-#include "kritaundo2_export.h"
+#include "kritacommand_export.h"
class QAction;
class KUndo2CommandPrivate;
@@ -94,7 +94,7 @@
* from QObject only for the sake of signal/slots capabilities.
* Nothing else.
*/
-class KRITAUNDO2_EXPORT KUndo2Command
+class KRITACOMMAND_EXPORT KUndo2Command
{
KUndo2CommandPrivate *d;
int timedID;
@@ -162,7 +162,7 @@
#ifndef QT_NO_UNDOSTACK
-class KRITAUNDO2_EXPORT KUndo2QStack : public QObject
+class KRITACOMMAND_EXPORT KUndo2QStack : public QObject
{
Q_OBJECT
// Q_DECLARE_PRIVATE(KUndo2QStack)
@@ -256,7 +256,7 @@
friend class KUndo2Group;
};
-class KRITAUNDO2_EXPORT KUndo2Stack : public KUndo2QStack
+class KRITACOMMAND_EXPORT KUndo2Stack : public KUndo2QStack
{
public:
explicit KUndo2Stack(QObject *parent = 0);
diff --git a/libs/kundo2/kundo2stack.cpp b/libs/command/kundo2stack.cpp
rename from libs/kundo2/kundo2stack.cpp
rename to libs/command/kundo2stack.cpp
diff --git a/libs/kundo2/kundo2stack_p.h b/libs/command/kundo2stack_p.h
rename from libs/kundo2/kundo2stack_p.h
rename to libs/command/kundo2stack_p.h
diff --git a/libs/kundo2/kundo2view.h b/libs/command/kundo2view.h
rename from libs/kundo2/kundo2view.h
rename to libs/command/kundo2view.h
--- a/libs/kundo2/kundo2view.h
+++ b/libs/command/kundo2view.h
@@ -62,16 +62,16 @@
#include
#include
-#include "kritaundo2_export.h"
+#include "kritacommand_export.h"
#ifndef QT_NO_UNDOVIEW
class KUndo2ViewPrivate;
class KUndo2QStack;
class KUndo2Group;
class QIcon;
-class KRITAUNDO2_EXPORT KUndo2View : public QListView
+class KRITACOMMAND_EXPORT KUndo2View : public QListView
{
Q_OBJECT
Q_PROPERTY(QString emptyLabel READ emptyLabel WRITE setEmptyLabel)
diff --git a/libs/kundo2/kundo2view.cpp b/libs/command/kundo2view.cpp
rename from libs/kundo2/kundo2view.cpp
rename to libs/command/kundo2view.cpp
diff --git a/libs/flake/CMakeLists.txt b/libs/flake/CMakeLists.txt
--- a/libs/flake/CMakeLists.txt
+++ b/libs/flake/CMakeLists.txt
@@ -29,23 +29,21 @@
KoPathPoint.cpp
KoPathSegment.cpp
KoSelection.cpp
+ KoSelectedShapesProxy.cpp
+ KoSelectedShapesProxySimple.cpp
KoShape.cpp
KoShapeAnchor.cpp
KoShapeBasedDocumentBase.cpp
KoShapeApplicationData.cpp
KoShapeContainer.cpp
KoShapeContainerModel.cpp
- KoShapeContainerDefaultModel.cpp
KoShapeGroup.cpp
- KoShapeManagerPaintingStrategy.cpp
KoShapeManager.cpp
KoShapePaintingContext.cpp
KoFrameShape.cpp
KoUnavailShape.cpp
- KoMarkerData.cpp
KoMarker.cpp
KoMarkerCollection.cpp
- KoMarkerSharedLoadingData.cpp
KoToolBase.cpp
KoCanvasController.cpp
KoCanvasControllerWidget.cpp
@@ -79,11 +77,12 @@
KoOdfGradientBackground.cpp
KoHatchBackground.cpp
KoPatternBackground.cpp
+ KoVectorPatternBackground.cpp
KoShapeConfigWidgetBase.cpp
KoDrag.cpp
+ KoSvgPaste.cpp
KoDragOdfSaveHelper.cpp
KoShapeOdfSaveHelper.cpp
- KoShapePaste.cpp
KoConnectionPoint.cpp
KoConnectionShape.cpp
KoConnectionShapeLoadingUpdater.cpp
@@ -115,6 +114,8 @@
KoTosContainer.cpp
KoTosContainerModel.cpp
KoClipPath.cpp
+ KoClipMask.cpp
+ KoClipMaskPainter.cpp
KoCurveFit.cpp
commands/KoShapeGroupCommand.cpp
commands/KoShapeAlignCommand.cpp
@@ -124,6 +125,7 @@
commands/KoShapeDistributeCommand.cpp
commands/KoShapeLockCommand.cpp
commands/KoShapeMoveCommand.cpp
+ commands/KoShapeResizeCommand.cpp
commands/KoShapeShearCommand.cpp
commands/KoShapeSizeCommand.cpp
commands/KoShapeStrokeCommand.cpp
@@ -157,6 +159,8 @@
commands/KoShapeUnclipCommand.cpp
commands/KoPathShapeMarkerCommand.cpp
commands/KoShapeConnectionChangeCommand.cpp
+ commands/KoMultiPathPointMergeCommand.cpp
+ commands/KoMultiPathPointJoinCommand.cpp
tools/KoCreateShapeStrategy.cpp
tools/KoPathToolFactory.cpp
tools/KoPathTool.cpp
@@ -176,6 +180,7 @@
tools/KoPanToolFactory.cpp
tools/KoInteractionTool.cpp
tools/KoInteractionStrategy.cpp
+ tools/KoInteractionStrategyFactory.cpp
tools/KoCreateShapesTool.cpp
tools/KoCreateShapesToolFactory.cpp
tools/KoShapeRubberSelectStrategy.cpp
@@ -190,12 +195,12 @@
svg/SvgParser.cpp
svg/SvgStyleParser.cpp
svg/SvgGradientHelper.cpp
- svg/SvgPatternHelper.cpp
svg/SvgFilterHelper.cpp
svg/SvgCssHelper.cpp
svg/SvgClipPathHelper.cpp
svg/SvgLoadingContext.cpp
svg/SvgShapeFactory.cpp
+ svg/parsers/SvgTransformParser.cpp
FlakeDebug.cpp
tests/MockShapes.cpp
@@ -217,7 +222,7 @@
$
)
-target_link_libraries(kritaflake kritapigment kritawidgetutils kritaodf kritaundo2 KF5::WidgetsAddons Qt5::Svg)
+target_link_libraries(kritaflake kritapigment kritawidgetutils kritaodf kritacommand KF5::WidgetsAddons Qt5::Svg)
set_target_properties(kritaflake PROPERTIES
VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION}
diff --git a/libs/flake/KoBakedShapeRenderer.h b/libs/flake/KoBakedShapeRenderer.h
new file mode 100644
--- /dev/null
+++ b/libs/flake/KoBakedShapeRenderer.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016 Dmitry Kazakov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KOBAKEDSHAPERENDERER_H
+#define KOBAKEDSHAPERENDERER_H
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+
+struct KoBakedShapeRenderer {
+ KoBakedShapeRenderer(const QPainterPath &dstShapeOutline, const QTransform &dstShapeTransform,
+ const QTransform &bakedTransform,
+ const QRectF &referenceRect,
+ bool contentIsObb, const QRectF &bakedShapeBoundingRect,
+ bool referenceIsObb,
+ const QTransform &patternTransform)
+ : m_dstShapeOutline(dstShapeOutline),
+ m_dstShapeTransform(dstShapeTransform),
+ m_contentIsObb(contentIsObb),
+ m_referenceIsObb(referenceIsObb),
+ m_patternTransform(patternTransform)
+ {
+ KIS_SAFE_ASSERT_RECOVER_NOOP(!contentIsObb || !bakedShapeBoundingRect.isEmpty());
+
+ const QRectF dstShapeBoundingRect = dstShapeOutline.boundingRect();
+
+ QTransform relativeToBakedShape;
+
+ if (referenceIsObb || contentIsObb) {
+ m_relativeToShape = KisAlgebra2D::mapToRect(dstShapeBoundingRect);
+ relativeToBakedShape = KisAlgebra2D::mapToRect(bakedShapeBoundingRect);
+ }
+
+
+ m_referenceRectUser =
+ referenceIsObb ?
+ m_relativeToShape.mapRect(referenceRect).toAlignedRect() :
+ referenceRect.toAlignedRect();
+
+ m_patch = QImage(m_referenceRectUser.size(), QImage::Format_ARGB32);
+ m_patch.fill(0);
+ m_patchPainter.begin(&m_patch);
+
+ m_patchPainter.translate(-m_referenceRectUser.topLeft());
+ m_patchPainter.setClipRect(m_referenceRectUser);
+
+ if (contentIsObb) {
+ m_patchPainter.setTransform(m_relativeToShape, true);
+ m_patchPainter.setTransform(relativeToBakedShape.inverted(), true);
+ }
+
+ m_patchPainter.setTransform(bakedTransform.inverted(), true);
+ }
+
+ QPainter* bakeShapePainter() {
+ return &m_patchPainter;
+ }
+
+ void renderShape(QPainter &painter) {
+ painter.save();
+
+ painter.setTransform(m_dstShapeTransform, true);
+ painter.setClipPath(m_dstShapeOutline);
+
+ QTransform brushTransform;
+
+ QPointF patternOffset = m_referenceRectUser.topLeft();
+
+ brushTransform =
+ brushTransform *
+ QTransform::fromTranslate(patternOffset.x(), patternOffset.y());
+
+ if (m_contentIsObb) {
+ brushTransform = brushTransform * m_relativeToShape.inverted();
+ }
+
+ brushTransform = brushTransform * m_patternTransform;
+
+ if (m_contentIsObb) {
+ brushTransform = brushTransform * m_relativeToShape;
+ }
+
+ QBrush brush(m_patch);
+ brush.setTransform(brushTransform);
+
+ painter.setBrush(brush);
+ painter.drawPath(m_dstShapeOutline);
+
+ painter.restore();
+ }
+
+ QImage patchImage() const {
+ return m_patch;
+ }
+
+
+private:
+ QPainterPath m_dstShapeOutline;
+ QTransform m_dstShapeTransform;
+
+ bool m_contentIsObb;
+ bool m_referenceIsObb;
+ const QTransform &m_patternTransform;
+
+ QImage m_patch;
+ QPainter m_patchPainter;
+
+ QTransform m_relativeToShape;
+ QRect m_referenceRectUser;
+};
+
+#endif // KOBAKEDSHAPERENDERER_H
diff --git a/libs/flake/KoCanvasBase.h b/libs/flake/KoCanvasBase.h
--- a/libs/flake/KoCanvasBase.h
+++ b/libs/flake/KoCanvasBase.h
@@ -39,6 +39,7 @@
class KoCanvasController;
class KoShape;
class KoSnapGuide;
+class KoSelectedShapesProxy;
class QWidget;
class QCursor;
@@ -110,12 +111,24 @@
virtual void addCommand(KUndo2Command *command) = 0;
/**
- * return the current shapeManager
+ * Return the current shapeManager. WARNING: the shape manager can switch
+ * in time, e.g. when a layer is changed. Please don't keep any persistent
+ * connections to it. Instead please use selectedShapesProxy(),
+ * which is guaranteed to be the same throughout the life of the canvas.
+ *
* @return the current shapeManager
*/
virtual KoShapeManager *shapeManager() const = 0;
/**
+ * @brief selectedShapesProxy() is a special interface for keeping a persistent connections
+ * to selectionChanged() and selectionContentChanged() signals. While shapeManager() can change
+ * throughout the life time of the cavas, selectedShapesProxy() is guaranteed to stay the same.
+ * @return persistent KoSelectedShapesProxy object
+ */
+ virtual KoSelectedShapesProxy *selectedShapesProxy() const = 0;
+
+ /**
* Tell the canvas to repaint the specified rectangle. The coordinates
* are document coordinates, not view coordinates.
*/
diff --git a/libs/flake/KoCanvasBase.cpp b/libs/flake/KoCanvasBase.cpp
--- a/libs/flake/KoCanvasBase.cpp
+++ b/libs/flake/KoCanvasBase.cpp
@@ -31,6 +31,7 @@
#include "KoShapeManager.h"
#include "KoToolProxy.h"
#include "KoSelection.h"
+#include "KoSelectedShapesProxy.h"
class Q_DECL_HIDDEN KoCanvasBase::Private
{
@@ -94,6 +95,7 @@
if (resourceManager()) resourceManager()->disconnect(object);
if (shapeManager()) shapeManager()->disconnect(object);
if (toolProxy()) toolProxy()->disconnect(object);
+ if (selectedShapesProxy()) selectedShapesProxy()->disconnect(object);
}
diff --git a/libs/flake/KoCanvasController.h b/libs/flake/KoCanvasController.h
--- a/libs/flake/KoCanvasController.h
+++ b/libs/flake/KoCanvasController.h
@@ -299,6 +299,12 @@
QPoint documentOffset() const;
+ /**
+ * @return the current position of the cursor fetched from QCursor::pos() and
+ * converted into document coordinates
+ */
+ virtual QPointF currentCursorPosition() const = 0;
+
protected:
void setDocumentSize(const QSize &sz);
QSize documentSize() const;
@@ -465,6 +471,7 @@
virtual void updateDocumentSize(const QSize &/*sz*/, bool /*recalculateCenter*/) {}
virtual void setZoomWithWheel(bool /*zoom*/) {}
virtual void setVastScrolling(qreal /*factor*/) {}
+ QPointF currentCursorPosition() const override { return QPointF(); }
};
diff --git a/libs/flake/KoCanvasControllerWidget.h b/libs/flake/KoCanvasControllerWidget.h
--- a/libs/flake/KoCanvasControllerWidget.h
+++ b/libs/flake/KoCanvasControllerWidget.h
@@ -139,6 +139,8 @@
virtual void setVastScrolling(qreal factor);
+ QPointF currentCursorPosition() const override;
+
/**
* \internal
*/
@@ -171,8 +173,6 @@
/// reimplemented from QWidget
virtual void wheelEvent(QWheelEvent *event);
/// reimplemented from QWidget
- virtual void keyPressEvent(QKeyEvent *event);
- /// reimplemented from QWidget
virtual bool focusNextPrevChild(bool next);
private:
diff --git a/libs/flake/KoCanvasControllerWidget.cpp b/libs/flake/KoCanvasControllerWidget.cpp
--- a/libs/flake/KoCanvasControllerWidget.cpp
+++ b/libs/flake/KoCanvasControllerWidget.cpp
@@ -484,6 +484,13 @@
d->vastScrollingFactor = factor;
}
+QPointF KoCanvasControllerWidget::currentCursorPosition() const
+{
+ QWidget *canvasWidget = d->canvas->canvasWidget();
+ const KoViewConverter *converter = d->canvas->viewConverter();
+ return converter->viewToDocument(canvasWidget->mapFromGlobal(QCursor::pos()) + d->canvas->canvasController()->documentOffset() - canvasWidget->pos());
+}
+
void KoCanvasControllerWidget::pan(const QPoint &distance)
{
QPoint sourcePoint = scrollBarValue();
@@ -531,11 +538,6 @@
d->viewportWidget->handleDragLeaveEvent(event);
}
-void KoCanvasControllerWidget::keyPressEvent(QKeyEvent *event)
-{
- KoToolManager::instance()->priv()->switchToolByShortcut(event);
-}
-
void KoCanvasControllerWidget::wheelEvent(QWheelEvent *event)
{
if (d->zoomWithWheel != ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier)) {
diff --git a/libs/flake/KoCanvasControllerWidgetViewport_p.cpp b/libs/flake/KoCanvasControllerWidgetViewport_p.cpp
--- a/libs/flake/KoCanvasControllerWidgetViewport_p.cpp
+++ b/libs/flake/KoCanvasControllerWidgetViewport_p.cpp
@@ -42,7 +42,6 @@
#include "KoSelection.h"
#include "KoCanvasBase.h"
#include "KoShapeLayer.h"
-#include "KoShapePaste.h"
#include "KoShapePaintingContext.h"
#include "KoToolProxy.h"
#include "KoCanvasControllerWidget.h"
@@ -97,19 +96,22 @@
m_drawShadow = drawShadow;
}
-
void Viewport::handleDragEnterEvent(QDragEnterEvent *event)
{
// if not a canvas set then ignore this, makes it possible to assume
// we have a canvas in all the support methods.
- if (!(m_parent->canvas() && m_parent->canvas()->canvasWidget()))
+ if (!(m_parent->canvas() && m_parent->canvas()->canvasWidget())) {
+ event->ignore();
return;
+ }
// only allow dropping when active layer is editable
KoSelection *selection = m_parent->canvas()->shapeManager()->selection();
KoShapeLayer *activeLayer = selection->activeLayer();
- if (activeLayer && (!activeLayer->isEditable() || activeLayer->isGeometryProtected()))
+ if (activeLayer && (!activeLayer->isEditable() || activeLayer->isGeometryProtected())) {
+ event->ignore();
return;
+ }
const QMimeData *data = event->mimeData();
if (data->hasFormat(SHAPETEMPLATE_MIMETYPE) ||
@@ -161,19 +163,6 @@
m_draggedShape->setAbsolutePosition(correctPosition(event->pos()));
m_parent->canvas()->shapeManager()->addShape(m_draggedShape);
- }
- else if (data->hasFormat(KoOdf::mimeType(KoOdf::Text))) {
- KoShapeManager *sm = m_parent->canvas()->shapeManager();
- KoShapePaste paste(m_parent->canvas(), sm->selection()->activeLayer());
- if (paste.paste(KoOdf::Text, data)) {
- QList shapes = paste.pastedShapes();
- if (shapes.count() == 1) {
- m_draggedShape = shapes.first();
- m_draggedShape->setZIndex(KoShapePrivate::MaxZIndex);
- event->setDropAction(Qt::CopyAction);
- }
- event->accept();
- }
} else {
event->ignore();
}
diff --git a/libs/flake/KoCanvasResourceManager.h b/libs/flake/KoCanvasResourceManager.h
--- a/libs/flake/KoCanvasResourceManager.h
+++ b/libs/flake/KoCanvasResourceManager.h
@@ -68,7 +68,6 @@
enum CanvasResource {
ForegroundColor, ///< The active forground color selected for this canvas.
BackgroundColor, ///< The active background color selected for this canvas.
- ActiveStroke, ///< The active stroke selected for this canvas
PageSize, ///< The size of the (current) page in postscript points.
Unit, ///< The unit of this canvas
CurrentPage, ///< The current page number
@@ -166,12 +165,6 @@
*/
KoColor backgroundColor() const;
- /// Sets the stroke resource
- void setActiveStroke(const KoShapeStroke &stroke);
-
- /// Returns the stroke resource
- KoShapeStroke activeStroke() const;
-
/**
* Return the resource determined by param key as a boolean.
* @param key the indentifying key for the resource
diff --git a/libs/flake/KoCanvasResourceManager.cpp b/libs/flake/KoCanvasResourceManager.cpp
--- a/libs/flake/KoCanvasResourceManager.cpp
+++ b/libs/flake/KoCanvasResourceManager.cpp
@@ -119,23 +119,6 @@
return resource(key).value();
}
-
-void KoCanvasResourceManager::setActiveStroke(const KoShapeStroke &stroke)
-{
- QVariant v;
- v.setValue(stroke);
- setResource(ActiveStroke, v);
-}
-
-KoShapeStroke KoCanvasResourceManager::activeStroke() const
-{
- if (!d->manager.hasResource(ActiveStroke)) {
- KoShapeStroke empty;
- return empty;
- }
- return resource(ActiveStroke).value();
-}
-
bool KoCanvasResourceManager::boolResource(int key) const
{
return d->manager.boolResource(key);
diff --git a/libs/ui/kis_aspect_ratio_locker.h b/libs/flake/KoClipMask.h
copy from libs/ui/kis_aspect_ratio_locker.h
copy to libs/flake/KoClipMask.h
--- a/libs/ui/kis_aspect_ratio_locker.h
+++ b/libs/flake/KoClipMask.h
@@ -16,43 +16,53 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __KIS_ASPECT_RATIO_LOCKER_H
-#define __KIS_ASPECT_RATIO_LOCKER_H
+#ifndef KOCLIPMASK_H
+#define KOCLIPMASK_H
+#include "kritaflake_export.h"
+
+#include
#include
-#include
-#include "kritaui_export.h"
+#include
+
+class KoShape;
+class QRectF;
+class QTransform;
+class QPointF;
+class QPainter;
-class QSpinBox;
-class QDoubleSpinBox;
-class KisSliderSpinBox;
-class KisDoubleSliderSpinBox;
-class KoAspectButton;
-class KRITAUI_EXPORT KisAspectRatioLocker : public QObject
+class KRITAFLAKE_EXPORT KoClipMask
{
- Q_OBJECT
public:
- KisAspectRatioLocker(QObject *parent = 0);
- ~KisAspectRatioLocker();
+ KoClipMask();
+ ~KoClipMask();
+
+ KoClipMask *clone() const;
+
+ KoFlake::CoordinateSystem coordinates() const;
+ void setCoordinates(KoFlake::CoordinateSystem value);
- template
- void connectSpinBoxes(SpinBoxType *spinOne, SpinBoxType *spinTwo, KoAspectButton *aspectButton);
+ KoFlake::CoordinateSystem contentCoordinates() const;
+ void setContentCoordinates(KoFlake::CoordinateSystem value);
- void setBlockUpdateSignalOnDrag(bool block);
+ QRectF maskRect() const;
+ void setMaskRect(const QRectF &value);
-private Q_SLOTS:
- void slotSpinOneChanged();
- void slotSpinTwoChanged();
- void slotAspectButtonChanged();
+ QList shapes() const;
+ void setShapes(const QList &value);
-Q_SIGNALS:
- void sliderValueChanged();
- void aspectButtonChanged();
+ bool isEmpty() const;
+
+ void setExtraShapeOffset(const QPointF &value);
+
+ void drawMask(QPainter *painter, KoShape *shape);
private:
+ KoClipMask(const KoClipMask &rhs);
+
struct Private;
const QScopedPointer m_d;
};
-#endif /* __KIS_ASPECT_RATIO_LOCKER_H */
+#endif // KOCLIPMASK_H
diff --git a/libs/flake/KoClipMask.cpp b/libs/flake/KoClipMask.cpp
new file mode 100644
--- /dev/null
+++ b/libs/flake/KoClipMask.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016 Dmitry Kazakov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "KoClipMask.h"
+
+#include
+#include
+#include
+#include
+#include "kis_algebra_2d.h"
+
+#include
+#include
+
+struct Q_DECL_HIDDEN KoClipMask::Private {
+ Private() {}
+ Private(const Private &rhs)
+ : coordinates(rhs.coordinates),
+ contentCoordinates(rhs.contentCoordinates),
+ maskRect(rhs.maskRect),
+ extraShapeTransform(rhs.extraShapeTransform)
+ {
+ Q_FOREACH (KoShape *shape, rhs.shapes) {
+ KoShape *clonedShape = shape->cloneShape();
+ KIS_ASSERT_RECOVER(clonedShape) { continue; }
+
+ shapes << clonedShape;
+ }
+ }
+
+ ~Private() {
+ qDeleteAll(shapes);
+ shapes.clear();
+ }
+
+
+ KoFlake::CoordinateSystem coordinates = KoFlake::ObjectBoundingBox;
+ KoFlake::CoordinateSystem contentCoordinates = KoFlake::UserSpaceOnUse;
+
+ QRectF maskRect = QRectF(-0.1, -0.1, 1.2, 1.2);
+
+ QList shapes;
+ QTransform extraShapeTransform; // TODO: not used anymore, use direct shape transform instead
+
+};
+
+KoClipMask::KoClipMask()
+ : m_d(new Private)
+{
+}
+
+KoClipMask::~KoClipMask()
+{
+}
+
+KoClipMask::KoClipMask(const KoClipMask &rhs)
+ : m_d(new Private(*rhs.m_d))
+{
+}
+
+KoClipMask *KoClipMask::clone() const
+{
+ return new KoClipMask(*this);
+}
+
+KoFlake::CoordinateSystem KoClipMask::coordinates() const
+{
+ return m_d->coordinates;
+}
+
+void KoClipMask::setCoordinates(KoFlake::CoordinateSystem value)
+{
+ m_d->coordinates = value;
+}
+
+KoFlake::CoordinateSystem KoClipMask::contentCoordinates() const
+{
+ return m_d->contentCoordinates;
+}
+
+void KoClipMask::setContentCoordinates(KoFlake::CoordinateSystem value)
+{
+ m_d->contentCoordinates = value;
+}
+
+QRectF KoClipMask::maskRect() const
+{
+ return m_d->maskRect;
+}
+
+void KoClipMask::setMaskRect(const QRectF &value)
+{
+ m_d->maskRect = value;
+}
+
+QList KoClipMask::shapes() const
+{
+ return m_d->shapes;
+}
+
+void KoClipMask::setShapes(const QList &value)
+{
+ m_d->shapes = value;
+}
+
+bool KoClipMask::isEmpty() const
+{
+ return m_d->shapes.isEmpty();
+}
+
+void KoClipMask::setExtraShapeOffset(const QPointF &value)
+{
+ /**
+ * TODO: when we implement source shapes sharing, please wrap the shapes
+ * into a group and apply this transform to the group instead
+ */
+
+ if (m_d->contentCoordinates == KoFlake::UserSpaceOnUse) {
+ const QTransform t = QTransform::fromTranslate(value.x(), value.y());
+
+ Q_FOREACH (KoShape *shape, m_d->shapes) {
+ shape->applyAbsoluteTransformation(t);
+ }
+ }
+
+ if (m_d->coordinates == KoFlake::UserSpaceOnUse) {
+ m_d->maskRect.translate(value);
+ }
+}
+
+void KoClipMask::drawMask(QPainter *painter, KoShape *shape)
+{
+ painter->save();
+
+ QPainterPath clipPathInShapeSpace;
+
+ if (m_d->coordinates == KoFlake::ObjectBoundingBox) {
+ QTransform relativeToShape = KisAlgebra2D::mapToRect(shape->outlineRect());
+ clipPathInShapeSpace.addPolygon(relativeToShape.map(m_d->maskRect));
+ } else {
+ clipPathInShapeSpace.addRect(m_d->maskRect);
+ clipPathInShapeSpace = m_d->extraShapeTransform.map(clipPathInShapeSpace);
+ }
+
+ painter->setClipPath(clipPathInShapeSpace, Qt::IntersectClip);
+
+ if (m_d->contentCoordinates == KoFlake::ObjectBoundingBox) {
+ QTransform relativeToShape = KisAlgebra2D::mapToRect(shape->outlineRect());
+
+ painter->setTransform(relativeToShape, true);
+ } else {
+ painter->setTransform(m_d->extraShapeTransform, true);
+ }
+
+ KoViewConverter converter;
+ KoShapePainter p;
+ p.setShapes(m_d->shapes);
+ p.paint(*painter, converter);
+
+ painter->restore();
+}
diff --git a/libs/image/tests/kis_algebra_2d_test.h b/libs/flake/KoClipMaskPainter.h
copy from libs/image/tests/kis_algebra_2d_test.h
copy to libs/flake/KoClipMaskPainter.h
--- a/libs/image/tests/kis_algebra_2d_test.h
+++ b/libs/flake/KoClipMaskPainter.h
@@ -16,21 +16,31 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __KIS_ALGEBRA_2D_TEST_H
-#define __KIS_ALGEBRA_2D_TEST_H
+#ifndef KOCLIPMASKPAINTER_H
+#define KOCLIPMASKPAINTER_H
-#include
+#include "kritaflake_export.h"
-class KisAlgebra2DTest : public QObject
+#include
+
+class QPainter;
+class QRectF;
+
+
+class KRITAFLAKE_EXPORT KoClipMaskPainter
{
- Q_OBJECT
-private Q_SLOTS:
- void testHalfPlane();
- void testOuterCircle();
-
- void testQuadraticEquation();
- void testIntersections();
- void testWeirdIntersections();
+public:
+ KoClipMaskPainter(QPainter *painter, const QRectF &globalClipRect);
+ ~KoClipMaskPainter();
+
+ QPainter* shapePainter();
+ QPainter* maskPainter();
+
+ void renderOnGlobalPainter();
+
+private:
+ struct Private;
+ const QScopedPointer m_d;
};
-#endif /* __KIS_ALGEBRA_2D_TEST_H */
+#endif // KOCLIPMASKPAINTER_H
diff --git a/libs/flake/KoClipMaskPainter.cpp b/libs/flake/KoClipMaskPainter.cpp
new file mode 100644
--- /dev/null
+++ b/libs/flake/KoClipMaskPainter.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016 Dmitry Kazakov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "KoClipMaskPainter.h"
+
+#include
+#include
+
+#include "kis_assert.h"
+
+struct Q_DECL_HIDDEN KoClipMaskPainter::Private
+{
+ QPainter *globalPainter;
+
+ QImage shapeImage;
+ QImage maskImage;
+
+ QPainter shapePainter;
+ QPainter maskPainter;
+
+ QRect alignedGlobalClipRect;
+};
+
+KoClipMaskPainter::KoClipMaskPainter(QPainter *painter, const QRectF &globalClipRect)
+ : m_d(new Private)
+{
+ m_d->globalPainter = painter;
+ m_d->alignedGlobalClipRect = globalClipRect.toAlignedRect();
+
+ m_d->shapeImage = QImage(m_d->alignedGlobalClipRect.size(), QImage::Format_ARGB32);
+ m_d->maskImage = QImage(m_d->alignedGlobalClipRect.size(), QImage::Format_ARGB32);
+
+ m_d->shapeImage.fill(0);
+ m_d->maskImage.fill(0);
+
+ QTransform moveToBufferTransform =
+ QTransform::fromTranslate(-m_d->alignedGlobalClipRect.x(),
+ -m_d->alignedGlobalClipRect.y());
+
+ m_d->shapePainter.begin(&m_d->shapeImage);
+ m_d->shapePainter.setTransform(moveToBufferTransform);
+ m_d->shapePainter.setTransform(painter->transform(), true);
+ if (painter->hasClipping()) {
+ m_d->shapePainter.setClipPath(painter->clipPath());
+ }
+ m_d->shapePainter.setOpacity(painter->opacity());
+ m_d->shapePainter.setBrush(painter->brush());
+ m_d->shapePainter.setPen(painter->pen());
+
+ m_d->maskPainter.begin(&m_d->maskImage);
+ m_d->maskPainter.setTransform(moveToBufferTransform);
+ m_d->maskPainter.setTransform(painter->transform(), true);
+ if (painter->hasClipping()) {
+ m_d->maskPainter.setClipPath(painter->clipPath());
+ }
+ m_d->maskPainter.setOpacity(painter->opacity());
+ m_d->maskPainter.setBrush(painter->brush());
+ m_d->maskPainter.setPen(painter->pen());
+}
+
+KoClipMaskPainter::~KoClipMaskPainter()
+{
+}
+
+QPainter *KoClipMaskPainter::shapePainter()
+{
+ return &m_d->shapePainter;
+}
+
+QPainter *KoClipMaskPainter::maskPainter()
+{
+ return &m_d->maskPainter;
+}
+
+void KoClipMaskPainter::renderOnGlobalPainter()
+{
+ KIS_ASSERT_RECOVER_RETURN(m_d->maskImage.size() == m_d->shapeImage.size());
+
+ for (int y = 0; y < m_d->maskImage.height(); y++) {
+ QRgb *shapeData = reinterpret_cast(m_d->shapeImage.scanLine(y));
+ QRgb *maskData = reinterpret_cast(m_d->maskImage.scanLine(y));
+
+ for (int x = 0; x < m_d->maskImage.width(); x++) {
+
+ const qreal normCoeff = 1.0 / 255.0 * 255.0;
+
+ qreal maskValue = qreal(qAlpha(*maskData)) *
+ (0.2125 * qRed(*maskData) +
+ 0.7154 * qGreen(*maskData) +
+ 0.0721 * qBlue(*maskData));
+
+ int alpha = qRound(maskValue * qAlpha(*shapeData) * normCoeff);
+
+ *shapeData = (alpha << 24) | (*shapeData & 0x00ffffff);
+
+ shapeData++;
+ maskData++;
+ }
+ }
+
+ KIS_ASSERT_RECOVER_RETURN(m_d->shapeImage.size() == m_d->alignedGlobalClipRect.size());
+ QPainterPath globalClipPath;
+
+ if (m_d->globalPainter->hasClipping()) {
+ globalClipPath = m_d->globalPainter->transform().map(m_d->globalPainter->clipPath());
+ }
+
+ m_d->globalPainter->save();
+
+ m_d->globalPainter->setTransform(QTransform());
+
+ if (!globalClipPath.isEmpty()) {
+ m_d->globalPainter->setClipPath(globalClipPath);
+ }
+
+ m_d->globalPainter->drawImage(m_d->alignedGlobalClipRect.topLeft(), m_d->shapeImage);
+ m_d->globalPainter->restore();
+}
+
diff --git a/libs/flake/KoClipPath.h b/libs/flake/KoClipPath.h
--- a/libs/flake/KoClipPath.h
+++ b/libs/flake/KoClipPath.h
@@ -21,9 +21,11 @@
#define KOCLIPPATH_H
#include "kritaflake_export.h"
+
+#include
#include
-#include
#include
+#include
class KoShape;
class KoPathShape;
@@ -33,43 +35,24 @@
class QPainterPath;
class QSizeF;
-/// Shared clip path data
-class KRITAFLAKE_EXPORT KoClipData : public QSharedData
-{
-public:
- /// Creates clip path data from a single path shape, takes ownership of the path shape
- explicit KoClipData(KoPathShape *clipPathShape);
-
- /// Creates clip path data from multiple path shapes, takes ownership of the path shapes
- explicit KoClipData(const QList &clipPathShapes);
-
- /// Destroys the clip path data
- ~KoClipData();
-
- /// Returns the clip path shapes
- QList clipPathShapes() const;
-
- /// Gives up ownership of clip path shapes
- void removeClipShapesOwnership();
-
-private:
- class Private;
- Private * const d;
-};
-
/// Clip path used to clip shapes
class KRITAFLAKE_EXPORT KoClipPath
{
public:
+
/**
* Create a new shape clipping using the given clip data
- * @param clippedShape the shape to clip
- * @param clipData shared clipping data containing the clip paths
+ * @param clipShapes define the clipping shapes, owned by KoClipPath!
+ * @param coordinates shows if ObjectBoundingBox or UserSpaceOnUse coordinate
+ * system is used.
*/
- KoClipPath(KoShape *clippedShape, KoClipData *clipData);
-
+ KoClipPath(QList clipShapes, KoFlake::CoordinateSystem coordinates);
~KoClipPath();
+ KoClipPath *clone() const;
+
+ KoFlake::CoordinateSystem coordinates() const;
+
/// Sets the clip rule to be used for the clip path
void setClipRule(Qt::FillRule clipRule);
@@ -85,6 +68,8 @@
/// Returns the clip path shapes
QList clipPathShapes() const;
+ QList clipShapes() const;
+
/**
* Returns the transformation from the clip data path shapes to the
* current document coordinates of the specified clipped shape.
@@ -98,8 +83,11 @@
static void applyClipping(KoShape *clippedShape, QPainter &painter, const KoViewConverter &converter);
private:
+ KoClipPath(const KoClipPath &rhs);
+
+private:
class Private;
- Private * const d;
+ const QScopedPointer d;
};
#endif // KOCLIPPATH_H
diff --git a/libs/flake/KoClipPath.cpp b/libs/flake/KoClipPath.cpp
--- a/libs/flake/KoClipPath.cpp
+++ b/libs/flake/KoClipPath.cpp
@@ -20,144 +20,161 @@
#include "KoClipPath.h"
#include "KoPathShape.h"
#include "KoViewConverter.h"
+#include "KoShapeGroup.h"
#include
#include
#include
#include
+#include
+
+
QTransform scaleToPercent(const QSizeF &size)
{
const qreal w = qMax(static_cast(1e-5), size.width());
const qreal h = qMax(static_cast(1e-5), size.height());
- return QTransform().scale(100/w, 100/h);
+ return QTransform().scale(1.0/w, 1.0/h);
}
QTransform scaleFromPercent(const QSizeF &size)
{
const qreal w = qMax(static_cast(1e-5), size.width());
const qreal h = qMax(static_cast(1e-5), size.height());
- return QTransform().scale(w/100, h/100);
+ return QTransform().scale(w/1.0, h/1.0);
}
-class Q_DECL_HIDDEN KoClipData::Private
+class Q_DECL_HIDDEN KoClipPath::Private
{
public:
- Private() : deleteClipShapes(true)
+ Private()
+ {}
+
+ Private(const Private &rhs)
+ : clipPath(rhs.clipPath),
+ clipRule(rhs.clipRule),
+ coordinates(rhs.coordinates),
+ initialTransformToShape(rhs.initialTransformToShape),
+ initialShapeSize(rhs.initialShapeSize)
{
+ Q_FOREACH (KoShape *shape, rhs.shapes) {
+ KoShape *clonedShape = shape->cloneShape();
+ KIS_ASSERT_RECOVER(clonedShape) { continue; }
+
+ shapes.append(clonedShape);
+ }
}
~Private()
{
- if (deleteClipShapes)
- qDeleteAll(clipPathShapes);
+ qDeleteAll(shapes);
+ shapes.clear();
}
- QList clipPathShapes;
- bool deleteClipShapes;
-};
-
-KoClipData::KoClipData(KoPathShape *clipPathShape)
- : d(new Private())
-{
- Q_ASSERT(clipPathShape);
- d->clipPathShapes.append(clipPathShape);
-}
-
-KoClipData::KoClipData(const QList &clipPathShapes)
- : d(new Private())
-{
- Q_ASSERT(clipPathShapes.count());
- d->clipPathShapes = clipPathShapes;
-}
-
-KoClipData::~KoClipData()
-{
- delete d;
-}
-
-QList KoClipData::clipPathShapes() const
-{
- return d->clipPathShapes;
-}
-
-void KoClipData::removeClipShapesOwnership()
-{
- d->deleteClipShapes = false;
-}
-
-class Q_DECL_HIDDEN KoClipPath::Private
-{
-public:
- Private(KoClipData *data)
- : clipData(data)
- {}
-
- ~Private()
- {
+ void collectShapePath(QPainterPath *result, const KoShape *shape) {
+ if (const KoPathShape *pathShape = dynamic_cast(shape)) {
+ // different shapes add up to the final path using Windind Fill rule (acc. to SVG 1.1)
+ QTransform t = pathShape->absoluteTransformation(0);
+ result->addPath(t.map(pathShape->outline()));
+ } else if (const KoShapeGroup *groupShape = dynamic_cast(shape)) {
+ QList shapes = groupShape->shapes();
+ qSort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
+
+ Q_FOREACH (const KoShape *child, shapes) {
+ collectShapePath(result, child);
+ }
+ }
}
- void compileClipPath(KoShape *clippedShape)
+
+ void compileClipPath()
{
- QList clipShapes = clipData->clipPathShapes();
- if (!clipShapes.count())
+ QList clipShapes = this->shapes;
+ if (clipShapes.isEmpty())
return;
- initialShapeSize = clippedShape->outline().boundingRect().size();
- initialTransformToShape = clippedShape->absoluteTransformation(0).inverted();
+ clipPath = QPainterPath();
+ clipPath.setFillRule(Qt::WindingFill);
+
+ qSort(clipShapes.begin(), clipShapes.end(), KoShape::compareShapeZIndex);
- QTransform transformToShape = initialTransformToShape * scaleToPercent(initialShapeSize);
+ Q_FOREACH (KoShape *path, clipShapes) {
+ if (!path) continue;
- Q_FOREACH (KoPathShape *path, clipShapes) {
- if (!path)
- continue;
- // map clip path to shape coordinates of clipped shape
- QTransform m = path->absoluteTransformation(0) * transformToShape;
- if (clipPath.isEmpty())
- clipPath = m.map(path->outline());
- else
- clipPath |= m.map(path->outline());
+ collectShapePath(&clipPath, path);
}
}
- QExplicitlySharedDataPointer clipData; ///< the clip path data
+ QList shapes;
QPainterPath clipPath; ///< the compiled clip path in shape coordinates of the clipped shape
+ Qt::FillRule clipRule = Qt::WindingFill;
+ KoFlake::CoordinateSystem coordinates = KoFlake::ObjectBoundingBox;
QTransform initialTransformToShape; ///< initial transformation to shape coordinates of the clipped shape
QSizeF initialShapeSize; ///< initial size of clipped shape
};
-KoClipPath::KoClipPath(KoShape *clippedShape, KoClipData *clipData)
- : d( new Private(clipData) )
+KoClipPath::KoClipPath(QList clipShapes, KoFlake::CoordinateSystem coordinates)
+ : d(new Private())
+{
+ d->shapes = clipShapes;
+ d->coordinates = coordinates;
+ d->compileClipPath();
+}
+
+KoClipPath::KoClipPath(const KoClipPath &rhs)
+ : d(new Private(*rhs.d))
{
- d->compileClipPath(clippedShape);
}
KoClipPath::~KoClipPath()
{
- delete d;
+}
+
+KoClipPath *KoClipPath::clone() const
+{
+ return new KoClipPath(*this);
}
void KoClipPath::setClipRule(Qt::FillRule clipRule)
{
- d->clipPath.setFillRule(clipRule);
+ d->clipRule = clipRule;
}
Qt::FillRule KoClipPath::clipRule() const
{
- return d->clipPath.fillRule();
+ return d->clipRule;
+}
+
+KoFlake::CoordinateSystem KoClipPath::coordinates() const
+{
+ return d->coordinates;
}
void KoClipPath::applyClipping(KoShape *clippedShape, QPainter &painter, const KoViewConverter &converter)
{
QPainterPath clipPath;
KoShape *shape = clippedShape;
while (shape) {
if (shape->clipPath()) {
- QTransform m = scaleFromPercent(shape->outline().boundingRect().size()) * shape->absoluteTransformation(0);
- if (clipPath.isEmpty())
- clipPath = m.map(shape->clipPath()->path());
- else
- clipPath |= m.map(shape->clipPath()->path());
+ QPainterPath path = shape->clipPath()->path();
+
+ QTransform t;
+
+ if (shape->clipPath()->coordinates() == KoFlake::ObjectBoundingBox) {
+ const QRectF shapeLocalBoundingRect = shape->outline().boundingRect();
+ t = KisAlgebra2D::mapToRect(shapeLocalBoundingRect) * shape->absoluteTransformation(0);
+
+ } else {
+ t = shape->absoluteTransformation(0);
+ }
+
+ path = t.map(path);
+
+ if (clipPath.isEmpty()) {
+ clipPath = path;
+ } else {
+ clipPath &= path;
+ }
}
shape = shape->parent();
}
@@ -183,7 +200,23 @@
QList KoClipPath::clipPathShapes() const
{
- return d->clipData->clipPathShapes();
+ // TODO: deprecate this method!
+
+ QList shapes;
+
+ Q_FOREACH (KoShape *shape, d->shapes) {
+ KoPathShape *pathShape = dynamic_cast(shape);
+ if (pathShape) {
+ shapes << pathShape;
+ }
+ }
+
+ return shapes;
+}
+
+QList KoClipPath::clipShapes() const
+{
+ return d->shapes;
}
QTransform KoClipPath::clipDataTransformation(KoShape *clippedShape) const
diff --git a/libs/flake/KoColorBackground.h b/libs/flake/KoColorBackground.h
--- a/libs/flake/KoColorBackground.h
+++ b/libs/flake/KoColorBackground.h
@@ -38,6 +38,8 @@
virtual ~KoColorBackground();
+ bool compareTo(const KoShapeBackground *other) const override;
+
/// Returns the background color
QColor color() const;
diff --git a/libs/flake/KoColorBackground.cpp b/libs/flake/KoColorBackground.cpp
--- a/libs/flake/KoColorBackground.cpp
+++ b/libs/flake/KoColorBackground.cpp
@@ -52,6 +52,14 @@
{
}
+bool KoColorBackground::compareTo(const KoShapeBackground *other) const
+{
+ Q_D(const KoColorBackground);
+
+ const KoColorBackground *bg = dynamic_cast(other);
+ return bg && bg->color() == d->color;
+}
+
QColor KoColorBackground::color() const
{
Q_D(const KoColorBackground);
diff --git a/libs/flake/KoConnectionShape.h b/libs/flake/KoConnectionShape.h
--- a/libs/flake/KoConnectionShape.h
+++ b/libs/flake/KoConnectionShape.h
@@ -54,6 +54,8 @@
KoConnectionShape();
virtual ~KoConnectionShape();
+ KoShape* cloneShape() const override;
+
// reimplemented
virtual void saveOdf(KoShapeSavingContext &context) const;
@@ -124,6 +126,9 @@
void updateConnections();
protected:
+ KoConnectionShape(const KoConnectionShape &rhs);
+
+
/// reimplemented
void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
diff --git a/libs/flake/KoConnectionShape.cpp b/libs/flake/KoConnectionShape.cpp
--- a/libs/flake/KoConnectionShape.cpp
+++ b/libs/flake/KoConnectionShape.cpp
@@ -49,6 +49,20 @@
{
}
+KoConnectionShapePrivate::KoConnectionShapePrivate(const KoConnectionShapePrivate &rhs, KoConnectionShape *q)
+ : KoParameterShapePrivate(rhs, q),
+ path(rhs.path),
+ shape1(0), // FIXME: it should point to the new shapes!!!
+ shape2(0), // FIXME: it should point to the new shapes!!!
+ connectionPointId1(rhs.connectionPointId1),
+ connectionPointId2(rhs.connectionPointId2),
+ connectionType(rhs.connectionType),
+ forceUpdate(rhs.forceUpdate),
+ hasCustomPath(rhs.hasCustomPath)
+{
+
+}
+
QPointF KoConnectionShapePrivate::escapeDirection(int handleId) const
{
Q_Q(const KoConnectionShape);
@@ -59,7 +73,7 @@
KoConnectionPoint::EscapeDirection ed = attachedShape->connectionPoint(connectionPointId).escapeDirection;
if (ed == KoConnectionPoint::AllDirections) {
QPointF handlePoint = q->shapeToDocument(handles[handleId]);
- QPointF centerPoint = attachedShape->absolutePosition(KoFlake::CenteredPosition);
+ QPointF centerPoint = attachedShape->absolutePosition(KoFlake::Center);
/*
* Determine the best escape direction from the position of the handle point
@@ -74,11 +88,11 @@
* of the orthogonal direction.
*/
// define our edge points in the right order
- const KoFlake::Position corners[4] = {
- KoFlake::BottomRightCorner,
- KoFlake::BottomLeftCorner,
- KoFlake::TopLeftCorner,
- KoFlake::TopRightCorner
+ const KoFlake::AnchorPosition corners[4] = {
+ KoFlake::BottomRight,
+ KoFlake::BottomLeft,
+ KoFlake::TopLeft,
+ KoFlake::TopRight
};
QPointF vHandle = handlePoint-centerPoint;
@@ -116,15 +130,15 @@
}
} else if (ed == KoConnectionPoint::HorizontalDirections) {
QPointF handlePoint = q->shapeToDocument(handles[handleId]);
- QPointF centerPoint = attachedShape->absolutePosition(KoFlake::CenteredPosition);
+ QPointF centerPoint = attachedShape->absolutePosition(KoFlake::Center);
// use horizontal direction pointing away from center point
if (handlePoint.x() < centerPoint.x())
direction = QPointF(-1.0, 0.0);
else
direction = QPointF(1.0, 0.0);
} else if (ed == KoConnectionPoint::VerticalDirections) {
QPointF handlePoint = q->shapeToDocument(handles[handleId]);
- QPointF centerPoint = attachedShape->absolutePosition(KoFlake::CenteredPosition);
+ QPointF centerPoint = attachedShape->absolutePosition(KoFlake::Center);
// use vertical direction pointing away from center point
if (handlePoint.y() < centerPoint.y())
direction = QPointF(0.0, -1.0);
@@ -299,7 +313,7 @@
}
KoConnectionShape::KoConnectionShape()
- : KoParameterShape(*(new KoConnectionShapePrivate(this)))
+ : KoParameterShape(new KoConnectionShapePrivate(this))
{
Q_D(KoConnectionShape);
d->handles.push_back(QPointF(0, 0));
@@ -313,6 +327,12 @@
clearConnectionPoints();
}
+KoConnectionShape::KoConnectionShape(const KoConnectionShape &rhs)
+ : KoParameterShape(new KoConnectionShapePrivate(*rhs.d_func(), this))
+{
+}
+
+
KoConnectionShape::~KoConnectionShape()
{
Q_D(KoConnectionShape);
@@ -322,6 +342,11 @@
d->shape2->removeDependee(this);
}
+KoShape *KoConnectionShape::cloneShape() const
+{
+ return new KoConnectionShape(*this);
+}
+
void KoConnectionShape::saveOdf(KoShapeSavingContext & context) const
{
Q_D(const KoConnectionShape);
@@ -445,7 +470,7 @@
if (d->hasCustomPath) {
KoPathShapeLoader loader(this);
loader.parseSvg(element.attributeNS(KoXmlNS::svg, "d"), true);
- if (m_subpaths.size() > 0) {
+ if (d->subpaths.size() > 0) {
QRectF viewBox = loadOdfViewbox(element);
if (viewBox.isEmpty()) {
// there should be a viewBox to transform the path data
@@ -503,8 +528,8 @@
p2 = d->handles[EndHandle];
}
- QPointF relativeBegin = m_subpaths.first()->first()->point();
- QPointF relativeEnd = m_subpaths.last()->last()->point();
+ QPointF relativeBegin = d->subpaths.first()->first()->point();
+ QPointF relativeEnd = d->subpaths.last()->last()->point();
QPointF diffRelative(relativeBegin - relativeEnd);
QPointF diffAbsolute(p1 - p2);
diff --git a/libs/flake/KoConnectionShapeFactory.cpp b/libs/flake/KoConnectionShapeFactory.cpp
--- a/libs/flake/KoConnectionShapeFactory.cpp
+++ b/libs/flake/KoConnectionShapeFactory.cpp
@@ -31,6 +31,8 @@
#include
#include
+#include "kis_pointer_utils.h"
+
KoConnectionShapeFactory::KoConnectionShapeFactory()
: KoShapeFactoryBase(KOCONNECTIONSHAPEID, i18n("Tie"))
{
@@ -44,7 +46,7 @@
KoShape* KoConnectionShapeFactory::createDefaultShape(KoDocumentResourceManager *) const
{
KoConnectionShape * shape = new KoConnectionShape();
- shape->setStroke(new KoShapeStroke());
+ shape->setStroke(toQShared(new KoShapeStroke()));
shape->setShapeId(KoPathShapeId);
return shape;
}
diff --git a/libs/flake/KoConnectionShape_p.h b/libs/flake/KoConnectionShape_p.h
--- a/libs/flake/KoConnectionShape_p.h
+++ b/libs/flake/KoConnectionShape_p.h
@@ -25,6 +25,7 @@
{
public:
explicit KoConnectionShapePrivate(KoConnectionShape *q);
+ explicit KoConnectionShapePrivate(const KoConnectionShapePrivate &rhs, KoConnectionShape *q);
/// Returns escape direction of given handle
QPointF escapeDirection(int handleId) const;
diff --git a/libs/flake/KoDocumentResourceManager.h b/libs/flake/KoDocumentResourceManager.h
--- a/libs/flake/KoDocumentResourceManager.h
+++ b/libs/flake/KoDocumentResourceManager.h
@@ -73,8 +73,6 @@
UndoStack, ///< The document-wide undo stack (KUndo2Stack)
ImageCollection, ///< The KoImageCollection for the document
OdfDocument, ///< The document this canvas shows (KoDocumentBase)
- PasteOffset, ///< Application wide paste offset
- PasteAtCursor, ///< Application wide paste at cursor setting
HandleRadius, ///< The handle radius used for drawing handles of any kind
GrabSensitivity, ///< The grab sensitivity used for grabbing handles of any kind
MarkerCollection, ///< The collection holding all markers
@@ -222,20 +220,6 @@
/// Returns the actual grab sensitivity
int grabSensitivity() const;
- /**
- * Offset used for pasting shapes to a document.
- */
- void setPasteOffset(qreal pasteOffset);
- /// Returns the current paste offset
- qreal pasteOffset() const;
-
- /**
- * Enables/disables pasting shape at cursor position
- */
- void enablePasteAtCursor(bool enable);
- /// Returns current state of paste at cursor setting
- bool pasteAtCursor() const;
-
KUndo2Stack *undoStack() const;
void setUndoStack(KUndo2Stack *undoStack);
diff --git a/libs/flake/KoDocumentResourceManager.cpp b/libs/flake/KoDocumentResourceManager.cpp
--- a/libs/flake/KoDocumentResourceManager.cpp
+++ b/libs/flake/KoDocumentResourceManager.cpp
@@ -125,53 +125,32 @@
void KoDocumentResourceManager::setHandleRadius(int handleRadius)
{
// do not allow arbitrary small handles
- if (handleRadius < 3)
- handleRadius = 3;
+ if (handleRadius < 5)
+ handleRadius = 5;
setResource(HandleRadius, QVariant(handleRadius));
}
int KoDocumentResourceManager::handleRadius() const
{
if (hasResource(HandleRadius))
return intResource(HandleRadius);
- return 3; // default value.
+ return 5; // default value (and is used just about everywhere)
}
void KoDocumentResourceManager::setGrabSensitivity(int grabSensitivity)
{
// do not allow arbitrary small grab sensitivity
- if (grabSensitivity < 3)
- grabSensitivity = 3;
+ if (grabSensitivity < 5)
+ grabSensitivity = 5;
setResource(GrabSensitivity, QVariant(grabSensitivity));
}
int KoDocumentResourceManager::grabSensitivity() const
{
if (hasResource(GrabSensitivity))
return intResource(GrabSensitivity);
- return 3; // default value
+ return 5; // default value (and is used just about everywhere)
}
-void KoDocumentResourceManager::setPasteOffset(qreal pasteOffset)
-{
- setResource(PasteOffset, QVariant(pasteOffset));
-}
-
-qreal KoDocumentResourceManager::pasteOffset() const
-{
- return resource(PasteOffset).toDouble();
-}
-
-void KoDocumentResourceManager::enablePasteAtCursor(bool enable)
-{
- setResource(PasteAtCursor, QVariant(enable));
-}
-
-bool KoDocumentResourceManager::pasteAtCursor() const
-{
- return resource(PasteAtCursor).toBool();
-}
-
-
void KoDocumentResourceManager::setUndoStack(KUndo2Stack *undoStack)
{
QVariant variant;
diff --git a/libs/flake/KoDrag.h b/libs/flake/KoDrag.h
--- a/libs/flake/KoDrag.h
+++ b/libs/flake/KoDrag.h
@@ -22,11 +22,14 @@
#include "kritaflake_export.h"
+#include
+
class QMimeData;
class QString;
class QByteArray;
class KoDragOdfSaveHelper;
class KoDragPrivate;
+class KoShape;
/**
* Class for simplifying adding a odf to the clip board
@@ -42,15 +45,11 @@
KoDrag();
~KoDrag();
+
/**
- * Set odf mime type
- *
- * This calls helper.writeBody();
- *
- * @param mimeType used for creating the odf document
- * @param helper helper for saving the body of the odf document
+ * Load SVG data into the current mime data
*/
- bool setOdf(const char *mimeType, KoDragOdfSaveHelper &helper);
+ bool setSvg(const QList shapes);
/**
* Add additional mimeTypes
diff --git a/libs/flake/KoDrag.cpp b/libs/flake/KoDrag.cpp
--- a/libs/flake/KoDrag.cpp
+++ b/libs/flake/KoDrag.cpp
@@ -38,6 +38,11 @@
#include
#include "KoShapeSavingContext.h"
+#include
+#include
+#include
+
+
class KoDragPrivate {
public:
KoDragPrivate() : mimeData(0) { }
@@ -55,73 +60,31 @@
delete d;
}
-bool KoDrag::setOdf(const char *mimeType, KoDragOdfSaveHelper &helper)
+bool KoDrag::setSvg(const QList originalShapes)
{
- struct Finally {
- Finally(KoStore *s) : store(s) { }
- ~Finally() {
- delete store;
- }
- KoStore *store;
- };
-
- QBuffer buffer;
- KoStore *store = KoStore::createStore(&buffer, KoStore::Write, mimeType);
- Finally finally(store); // delete store when we exit this scope
- Q_ASSERT(store);
- Q_ASSERT(!store->bad());
-
- KoOdfWriteStore odfStore(store);
- KoEmbeddedDocumentSaver embeddedSaver;
-
- KoXmlWriter *manifestWriter = odfStore.manifestWriter(mimeType);
- KoXmlWriter *contentWriter = odfStore.contentWriter();
-
- if (!contentWriter) {
- return false;
- }
-
- KoGenStyles mainStyles;
- KoXmlWriter *bodyWriter = odfStore.bodyWriter();
- KoShapeSavingContext *context = helper.context(bodyWriter, mainStyles, embeddedSaver);
+ QRectF boundingRect;
+ QList shapes;
- if (!helper.writeBody()) {
- return false;
+ Q_FOREACH (KoShape *shape, originalShapes) {
+ boundingRect |= shape->boundingRect();
+ shapes.append(shape->cloneShape());
}
- mainStyles.saveOdfStyles(KoGenStyles::DocumentAutomaticStyles, contentWriter);
+ qSort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
- odfStore.closeContentWriter();
-
- //add manifest line for content.xml
- manifestWriter->addManifestEntry("content.xml", "text/xml");
-
-
- if (!mainStyles.saveOdfStylesDotXml(store, manifestWriter)) {
- return false;
- }
-
- if (!context->saveDataCenter(store, manifestWriter)) {
- debugFlake << "save data centers failed";
- return false;
- }
+ QBuffer buffer;
+ QLatin1String mimeType("image/svg+xml");
- // Save embedded objects
- KoDocumentBase::SavingContext documentContext(odfStore, embeddedSaver);
- if (!embeddedSaver.saveEmbeddedDocuments(documentContext)) {
- debugFlake << "save embedded documents failed";
- return false;
- }
+ buffer.open(QIODevice::WriteOnly);
- // Write out manifest file
- if (!odfStore.closeManifestWriter()) {
- return false;
- }
+ const QSizeF pageSize(boundingRect.right(), boundingRect.bottom());
+ SvgWriter writer(shapes, pageSize);
+ writer.save(buffer);
- delete store; // make sure the buffer if fully flushed.
- finally.store = 0;
- setData(mimeType, buffer.buffer());
+ buffer.close();
+ qDeleteAll(shapes);
+ setData(mimeType, buffer.data());
return true;
}
diff --git a/libs/flake/KoFlake.h b/libs/flake/KoFlake.h
--- a/libs/flake/KoFlake.h
+++ b/libs/flake/KoFlake.h
@@ -24,14 +24,38 @@
#include "kritaflake_export.h"
class QGradient;
+class QRectF;
class QPointF;
class QSizeF;
+class KoShape;
+class QTransform;
+
+#include
+
/**
* Flake reference
*/
namespace KoFlake
{
+ enum FillVariant {
+ Fill,
+ StrokeFill
+ };
+
+ enum FillType {
+ None,
+ Solid,
+ Gradient,
+ Pattern
+ };
+
+ enum MarkerPosition {
+ StartMarker,
+ MidMarker,
+ EndMarker
+ };
+
/// the selection type for KoSelection::selectedObjects()
enum SelectionType {
FullSelection, ///< Create a list of all user-shapes in the selection. This excludes KoShapeGroup grouping objects that may be selected.
@@ -62,26 +86,39 @@
ShapeOnTop ///< return the shape highest z-ordering, regardless of selection.
};
- /// position. See KoShape::absolutePosition()
- enum Position {
- TopLeftCorner, ///< the top left corner
- TopRightCorner, ///< the top right corner
- BottomLeftCorner, ///< the bottom left corner
- BottomRightCorner, ///< the bottom right corner
- CenteredPosition ///< the centred corner
- };
-
/**
* Used to see which style type is active
*/
enum StyleType {
Background, ///< the background / fill style is active
Foreground ///< the foreground / stroke style is active
};
+ enum AnchorPosition {
+ TopLeft,
+ Top,
+ TopRight,
+ Left,
+ Center,
+ Right,
+ BottomLeft,
+ Bottom,
+ BottomRight,
+ NoAnchor,
+ NumAnchorPositions
+ };
+
+ KRITAFLAKE_EXPORT QPointF anchorToPoint(AnchorPosition anchor, const QRectF rect, bool *valid = 0);
+
+ enum CanvasResource {
+ HotPosition = 1410100299
+ };
+
/// clones the given gradient
KRITAFLAKE_EXPORT QGradient *cloneGradient(const QGradient *gradient);
+ KRITAFLAKE_EXPORT QGradient *mergeGradient(const QGradient *coordsSource, const QGradient *fillSource);
+
/**
* Convert absolute to relative position
*
@@ -101,6 +138,13 @@
* @return absolute position
*/
KRITAFLAKE_EXPORT QPointF toAbsolute(const QPointF &relative, const QSizeF &size);
+
+ KRITAFLAKE_EXPORT Qt::Orientation significantScaleOrientation(qreal scaleX, qreal scaleY);
+
+ KRITAFLAKE_EXPORT void resizeShape(KoShape *shape, qreal scaleX, qreal scaleY,
+ const QPointF &absoluteStillPoint,
+ bool useGlobalMode,
+ bool usePostScaling, const QTransform &postScalingCoveringTransform);
}
#endif
diff --git a/libs/flake/KoFlake.cpp b/libs/flake/KoFlake.cpp
--- a/libs/flake/KoFlake.cpp
+++ b/libs/flake/KoFlake.cpp
@@ -25,6 +25,7 @@
#include
#include
+#include "kis_global.h"
QGradient *KoFlake::cloneGradient(const QGradient *gradient)
{
@@ -63,6 +64,67 @@
return clone;
}
+QGradient *KoFlake::mergeGradient(const QGradient *coordsSource, const QGradient *fillSource)
+{
+ QPointF start;
+ QPointF end;
+ QPointF focalPoint;
+
+ switch (coordsSource->type()) {
+ case QGradient::LinearGradient: {
+ const QLinearGradient *lg = static_cast(coordsSource);
+ start = lg->start();
+ focalPoint = start;
+ end = lg->finalStop();
+ break;
+ }
+ case QGradient::RadialGradient: {
+ const QRadialGradient *rg = static_cast(coordsSource);
+ start = rg->center();
+ end = start + QPointF(rg->radius(), 0);
+ focalPoint = rg->focalPoint();
+ break;
+ }
+ case QGradient::ConicalGradient: {
+ const QConicalGradient *cg = static_cast(coordsSource);
+
+ start = cg->center();
+ focalPoint = start;
+
+ QLineF l (start, start + QPointF(1.0, 0));
+ l.setAngle(cg->angle());
+ end = l.p2();
+ break;
+ }
+ default:
+ return 0;
+ }
+
+ QGradient *clone = 0;
+
+ switch (fillSource->type()) {
+ case QGradient::LinearGradient:
+ clone = new QLinearGradient(start, end);
+ break;
+ case QGradient::RadialGradient:
+ clone = new QRadialGradient(start, kisDistance(start, end), focalPoint);
+ break;
+ case QGradient::ConicalGradient: {
+ QLineF l(start, end);
+ clone = new QConicalGradient(l.p1(), l.angle());
+ break;
+ }
+ default:
+ return 0;
+ }
+
+ clone->setCoordinateMode(fillSource->coordinateMode());
+ clone->setSpread(fillSource->spread());
+ clone->setStops(fillSource->stops());
+
+ return clone;
+}
+
QPointF KoFlake::toRelative(const QPointF &absolute, const QSizeF &size)
{
return QPointF(size.width() == 0 ? 0: absolute.x() / size.width(),
@@ -73,3 +135,202 @@
{
return QPointF(relative.x() * size.width(), relative.y() * size.height());
}
+
+#include
+#include
+#include "kis_debug.h"
+#include "kis_algebra_2d.h"
+
+namespace {
+
+qreal getScaleByPointsPair(qreal x1, qreal x2, qreal expX1, qreal expX2)
+{
+ static const qreal eps = 1e-10;
+
+ const qreal diff = x2 - x1;
+ const qreal expDiff = expX2 - expX1;
+
+ return qAbs(diff) > eps ? expDiff / diff : 1.0;
+}
+
+void findMinMaxPoints(const QPolygonF &poly, int *minPoint, int *maxPoint, std::function dimension)
+{
+ KIS_ASSERT_RECOVER_RETURN(minPoint);
+ KIS_ASSERT_RECOVER_RETURN(maxPoint);
+
+ qreal minValue = dimension(poly[*minPoint]);
+ qreal maxValue = dimension(poly[*maxPoint]);
+
+ for (int i = 0; i < poly.size(); i++) {
+ const qreal value = dimension(poly[i]);
+
+ if (value < minValue) {
+ *minPoint = i;
+ minValue = value;
+ }
+
+ if (value > maxValue) {
+ *maxPoint = i;
+ maxValue = value;
+ }
+ }
+}
+
+}
+
+
+Qt::Orientation KoFlake::significantScaleOrientation(qreal scaleX, qreal scaleY)
+{
+ const qreal scaleXDeviation = qAbs(1.0 - scaleX);
+ const qreal scaleYDeviation = qAbs(1.0 - scaleY);
+
+ return scaleXDeviation > scaleYDeviation ? Qt::Horizontal : Qt::Vertical;
+}
+
+void KoFlake::resizeShape(KoShape *shape, qreal scaleX, qreal scaleY,
+ const QPointF &absoluteStillPoint,
+ bool useGlobalMode,
+ bool usePostScaling, const QTransform &postScalingCoveringTransform)
+{
+ QPointF localStillPoint = shape->absoluteTransformation(0).inverted().map(absoluteStillPoint);
+
+ QPointF relativeStillPoint = KisAlgebra2D::absoluteToRelative(localStillPoint, shape->outlineRect());
+ QPointF parentalStillPointBefore = shape->transformation().map(localStillPoint);
+
+ if (usePostScaling) {
+ const QTransform scale = QTransform::fromScale(scaleX, scaleY);
+
+ if (!useGlobalMode) {
+ shape->setTransformation(shape->transformation() *
+ postScalingCoveringTransform.inverted() *
+ scale * postScalingCoveringTransform);
+ } else {
+ const QTransform uniformGlobalTransform =
+ shape->absoluteTransformation(0) *
+ scale *
+ shape->absoluteTransformation(0).inverted() *
+ shape->transformation();
+
+ shape->setTransformation(uniformGlobalTransform);
+ }
+ } else {
+ using namespace KisAlgebra2D;
+
+ if (useGlobalMode) {
+ const QTransform scale = QTransform::fromScale(scaleX, scaleY);
+ const QTransform uniformGlobalTransform =
+ shape->absoluteTransformation(0) *
+ scale *
+ shape->absoluteTransformation(0).inverted();
+
+ const QRectF rect = shape->outlineRect();
+
+ /**
+ * The basic idea of such global scaling:
+ *
+ * 1) We choose two the most distant points of the original outline rect
+ * 2) Calculate their expected position if transformed using `uniformGlobalTransform`
+ * 3) NOTE1: we do not transform the entire shape using `uniformGlobalTransform`,
+ * because it will cause massive shearing. We transform only two points
+ * and adjust other points using dumb scaling.
+ * 4) NOTE2: given that `scale` transform is much more simpler than
+ * `uniformGlobalTransform`, we cannot guarantee equivalent changes on
+ * both globalScaleX and globalScaleY at the same time. We can guarantee
+ * only one of them. Therefore we select the most "important" axis and
+ * guarantee scael along it. The scale along the other direction is not
+ * controlled.
+ * 5) After we have the two most distant points, we can just calculate the scale
+ * by dividing difference between their expected and original positions. This
+ * formula can be derived from equation:
+ *
+ * localPoint_i * ScaleMatrix = localPoint_i * UniformGlobalTransform = expectedPoint_i
+ */
+
+ // choose the most significant scale direction
+ Qt::Orientation significantOrientation = significantScaleOrientation(scaleX, scaleY);
+
+ std::function dimension;
+
+ if (significantOrientation == Qt::Horizontal) {
+ dimension = [] (const QPointF &pt) {
+ return pt.x();
+ };
+
+ } else {
+ dimension = [] (const QPointF &pt) {
+ return pt.y();
+ };
+ }
+
+ // find min and max points (in absolute coordinates),
+ // by default use top-left and bottom-right
+ QPolygonF localPoints(rect);
+ QPolygonF globalPoints = shape->absoluteTransformation(0).map(localPoints);
+
+ int minPointIndex = 0;
+ int maxPointIndex = 2;
+
+ findMinMaxPoints(globalPoints, &minPointIndex, &maxPointIndex, dimension);
+
+ // calculate the scale using the extremum points
+ const QPointF minPoint = localPoints[minPointIndex];
+ const QPointF maxPoint = localPoints[maxPointIndex];
+
+ const QPointF minPointExpected = uniformGlobalTransform.map(minPoint);
+ const QPointF maxPointExpected = uniformGlobalTransform.map(maxPoint);
+
+ scaleX = getScaleByPointsPair(minPoint.x(), maxPoint.x(),
+ minPointExpected.x(), maxPointExpected.x());
+ scaleY = getScaleByPointsPair(minPoint.y(), maxPoint.y(),
+ minPointExpected.y(), maxPointExpected.y());
+ }
+
+ const QSizeF oldSize(shape->size());
+ const QSizeF newSize(oldSize.width() * qAbs(scaleX), oldSize.height() * qAbs(scaleY));
+
+ const QTransform mirrorTransform = QTransform::fromScale(signPZ(scaleX), signPZ(scaleY));
+
+ shape->setSize(newSize);
+
+ if (!mirrorTransform.isIdentity()) {
+ shape->setTransformation(mirrorTransform * shape->transformation());
+ }
+
+ }
+
+ QPointF newLocalStillPoint = KisAlgebra2D::relativeToAbsolute(relativeStillPoint, shape->outlineRect());
+ QPointF parentalStillPointAfter = shape->transformation().map(newLocalStillPoint);
+
+ QPointF diff = parentalStillPointBefore - parentalStillPointAfter;
+ shape->setTransformation(shape->transformation() * QTransform::fromTranslate(diff.x(), diff.y()));
+}
+
+QPointF KoFlake::anchorToPoint(AnchorPosition anchor, const QRectF rect, bool *valid)
+{
+ static QVector anchorTable;
+
+ if (anchorTable.isEmpty()) {
+ anchorTable << QPointF(0.0,0.0);
+ anchorTable << QPointF(0.5,0.0);
+ anchorTable << QPointF(1.0,0.0);
+
+ anchorTable << QPointF(0.0,0.5);
+ anchorTable << QPointF(0.5,0.5);
+ anchorTable << QPointF(1.0,0.5);
+
+ anchorTable << QPointF(0.0,1.0);
+ anchorTable << QPointF(0.5,1.0);
+ anchorTable << QPointF(1.0,1.0);
+ }
+
+ if (anchor == NoAnchor) {
+ if (valid) {
+ *valid = false;
+ }
+ return rect.topLeft();
+ } else if (valid) {
+ *valid = true;
+ }
+
+ return KisAlgebra2D::relativeToAbsolute(anchorTable[int(anchor)], rect);
+}
diff --git a/libs/image/tests/kis_algebra_2d_test.h b/libs/flake/KoFlakeCoordinateSystem.h
copy from libs/image/tests/kis_algebra_2d_test.h
copy to libs/flake/KoFlakeCoordinateSystem.h
--- a/libs/image/tests/kis_algebra_2d_test.h
+++ b/libs/flake/KoFlakeCoordinateSystem.h
@@ -16,21 +16,39 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __KIS_ALGEBRA_2D_TEST_H
-#define __KIS_ALGEBRA_2D_TEST_H
+#ifndef KOFLAKECOORDINATE_SYSTEM_H
+#define KOFLAKECOORDINATE_SYSTEM_H
-#include
+#include
-class KisAlgebra2DTest : public QObject
-{
- Q_OBJECT
-private Q_SLOTS:
- void testHalfPlane();
- void testOuterCircle();
-
- void testQuadraticEquation();
- void testIntersections();
- void testWeirdIntersections();
+namespace KoFlake {
+
+enum CoordinateSystem {
+ UserSpaceOnUse,
+ ObjectBoundingBox
};
-#endif /* __KIS_ALGEBRA_2D_TEST_H */
+inline CoordinateSystem coordinatesFromString(const QString &value, CoordinateSystem defaultValue)
+{
+ CoordinateSystem result = defaultValue;
+
+ if (value == "userSpaceOnUse") {
+ result = UserSpaceOnUse;
+ } else if (value == "objectBoundingBox") {
+ result = ObjectBoundingBox;
+ }
+
+ return result;
+}
+
+inline QString coordinateToString(CoordinateSystem value)
+{
+ return
+ value == ObjectBoundingBox?
+ "objectBoundingBox" :
+ "userSpaceOnUse";
+}
+}
+
+#endif // KOFLAKECOORDINATE_SYSTEM_H
+
diff --git a/libs/image/tests/kis_algebra_2d_test.h b/libs/flake/KoFlakeTypes.h
copy from libs/image/tests/kis_algebra_2d_test.h
copy to libs/flake/KoFlakeTypes.h
--- a/libs/image/tests/kis_algebra_2d_test.h
+++ b/libs/flake/KoFlakeTypes.h
@@ -16,21 +16,16 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __KIS_ALGEBRA_2D_TEST_H
-#define __KIS_ALGEBRA_2D_TEST_H
+#ifndef KOFLAKETYPES_H
+#define KOFLAKETYPES_H
-#include
+class KoShapeStroke;
+class KoShapeStrokeModel;
-class KisAlgebra2DTest : public QObject
-{
- Q_OBJECT
-private Q_SLOTS:
- void testHalfPlane();
- void testOuterCircle();
+template class QSharedPointer;
- void testQuadraticEquation();
- void testIntersections();
- void testWeirdIntersections();
-};
+typedef QSharedPointer KoShapeStrokeModelSP;
+typedef QSharedPointer KoShapeStrokeSP;
+
+#endif // KOFLAKETYPES_H
-#endif /* __KIS_ALGEBRA_2D_TEST_H */
diff --git a/libs/flake/KoFlakeUtils.h b/libs/flake/KoFlakeUtils.h
new file mode 100644
--- /dev/null
+++ b/libs/flake/KoFlakeUtils.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016 Dmitry Kazakov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KOFLAKEUTILS_H
+#define KOFLAKEUTILS_H
+
+#include
+#include
+#include
+
+#include "kis_global.h"
+#include "KoShapeStrokeCommand.h"
+
+
+namespace KoFlake {
+
+template
+ auto modifyShapesStrokes(QList shapes, ModifyFunction modifyFunction)
+ -> decltype(modifyFunction(KoShapeStrokeSP()), (KUndo2Command*)(0))
+ {
+ if (shapes.isEmpty()) return 0;
+
+ QList newStrokes;
+
+ Q_FOREACH(KoShape *shape, shapes) {
+ KoShapeStrokeSP shapeStroke = shape->stroke() ?
+ qSharedPointerDynamicCast(shape->stroke()) :
+ KoShapeStrokeSP();
+
+ KoShapeStrokeSP newStroke =
+ toQShared(shapeStroke ?
+ new KoShapeStroke(*shapeStroke) :
+ new KoShapeStroke());
+
+ modifyFunction(newStroke);
+
+ newStrokes << newStroke;
+ }
+
+ return new KoShapeStrokeCommand(shapes, newStrokes);
+}
+
+template
+bool compareShapePropertiesEqual(const QList shapes, const Policy &policy)
+{
+ if (shapes.size() == 1) return true;
+
+ typename Policy::PointerType bg =
+ policy.getProperty(shapes.first());
+
+ Q_FOREACH (KoShape *shape, shapes) {
+ if (
+ !(
+ (!bg && !policy.getProperty(shape)) ||
+ (bg && policy.compareTo(bg, policy.getProperty(shape)))
+ )) {
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+template
+bool compareShapePropertiesEqual(const QList shapes)
+{
+ return compareShapePropertiesEqual(shapes, Policy());
+}
+
+}
+
+#endif // KOFLAKEUTILS_H
+
diff --git a/libs/flake/KoGradientBackground.h b/libs/flake/KoGradientBackground.h
--- a/libs/flake/KoGradientBackground.h
+++ b/libs/flake/KoGradientBackground.h
@@ -47,6 +47,8 @@
/// Destroys the background
virtual ~KoGradientBackground();
+ bool compareTo(const KoShapeBackground *other) const override;
+
/// Sets the transform matrix
void setTransform(const QTransform &matrix);
diff --git a/libs/flake/KoGradientBackground.cpp b/libs/flake/KoGradientBackground.cpp
--- a/libs/flake/KoGradientBackground.cpp
+++ b/libs/flake/KoGradientBackground.cpp
@@ -69,6 +69,16 @@
delete d->gradient;
}
+bool KoGradientBackground::compareTo(const KoShapeBackground *other) const
+{
+ Q_D(const KoGradientBackground);
+ const KoGradientBackground *otherGradient = dynamic_cast(other);
+
+ return otherGradient &&
+ d->matrix == otherGradient->d_func()->matrix &&
+ *d->gradient == *otherGradient->d_func()->gradient;
+}
+
void KoGradientBackground::setTransform(const QTransform &matrix)
{
Q_D(KoGradientBackground);
@@ -101,10 +111,40 @@
{
Q_D(const KoGradientBackground);
if (!d->gradient) return;
- QBrush brush(*d->gradient);
- brush.setTransform(d->matrix);
- painter.setBrush(brush);
+ if (d->gradient->coordinateMode() == QGradient::ObjectBoundingMode) {
+
+ /**
+ * NOTE: important hack!
+ *
+ * Qt has different notation of QBrush::setTransform() in comparison
+ * to what SVG defines. SVG defines gradientToUser matrix to be postmultiplied
+ * by QBrush::transform(), but Qt does exectly reverse!
+ *
+ * That most probably has beed caused by the fact that Qt uses transposed
+ * matrices and someone just mistyped the stuff long ago :(
+ *
+ * So here we basically emulate this feature by converting the gradient into
+ * QGradient::LogicalMode and doing transformations manually.
+ */
+
+ const QRectF boundingRect = fillPath.boundingRect();
+ QTransform gradientToUser(boundingRect.width(), 0, 0, boundingRect.height(),
+ boundingRect.x(), boundingRect.y());
+
+ // TODO: how about slicing the object?
+ QGradient g = *d->gradient;
+ g.setCoordinateMode(QGradient::LogicalMode);
+
+ QBrush b(g);
+ b.setTransform(d->matrix * gradientToUser);
+ painter.setBrush(b);
+ } else {
+ QBrush b(*d->gradient);
+ b.setTransform(d->matrix);
+ painter.setBrush(b);
+ }
+
painter.drawPath(fillPath);
}
diff --git a/libs/flake/KoGradientHelper.h b/libs/flake/KoGradientHelper.h
--- a/libs/flake/KoGradientHelper.h
+++ b/libs/flake/KoGradientHelper.h
@@ -34,6 +34,6 @@
/// Calculates color at given position from given gradient stops
KRITAFLAKE_EXPORT QColor colorAt(qreal position, const QGradientStops &stops);
-};
+}
#endif
diff --git a/libs/flake/KoImageData.h b/libs/flake/KoImageData.h
--- a/libs/flake/KoImageData.h
+++ b/libs/flake/KoImageData.h
@@ -68,6 +68,8 @@
inline bool operator!=(const KoImageData &other) const { return !operator==(other); }
bool operator==(const KoImageData &other) const;
+ KoShapeUserData* clone() const override;
+
void setImage(const QString &location, KoStore *store, KoImageCollection *collection = 0);
/**
diff --git a/libs/flake/KoImageData.cpp b/libs/flake/KoImageData.cpp
--- a/libs/flake/KoImageData.cpp
+++ b/libs/flake/KoImageData.cpp
@@ -350,6 +350,11 @@
return *this;
}
+KoShapeUserData *KoImageData::clone() const
+{
+ return new KoImageData(*this);
+}
+
qint64 KoImageData::key() const
{
return d->key;
diff --git a/libs/flake/KoMarker.h b/libs/flake/KoMarker.h
--- a/libs/flake/KoMarker.h
+++ b/libs/flake/KoMarker.h
@@ -24,52 +24,93 @@
#include
#include "kritaflake_export.h"
+#include
class KoXmlElement;
class KoShapeLoadingContext;
class KoShapeSavingContext;
class QString;
class QPainterPath;
+class KoShape;
+class QPainter;
+class KoShapeStroke;
class KRITAFLAKE_EXPORT KoMarker : public QSharedData
{
public:
KoMarker();
~KoMarker();
/**
- * Load the marker
+ * Display name of the marker
*
- * @param element The xml element containing the marker
- * @param context The shape loading context
+ * @return Display name of the marker
*/
- bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context);
+ QString name() const;
+
+ KoMarker(const KoMarker &rhs);
+ bool operator==(const KoMarker &other) const;
+
+ enum MarkerCoordinateSystem {
+ StrokeWidth,
+ UserSpaceOnUse
+ };
+
+ void setCoordinateSystem(MarkerCoordinateSystem value);
+ MarkerCoordinateSystem coordinateSystem() const;
+
+ static MarkerCoordinateSystem coordinateSystemFromString(const QString &value);
+ static QString coordinateSystemToString(MarkerCoordinateSystem value);
+
+ void setReferencePoint(const QPointF &value);
+ QPointF referencePoint() const;
+
+ void setReferenceSize(const QSizeF &size);
+ QSizeF referenceSize() const;
+
+ bool hasAutoOtientation() const;
+ void setAutoOrientation(bool value);
+
+ // measured in radians!
+ qreal explicitOrientation() const;
+
+ // measured in radians!
+ void setExplicitOrientation(qreal value);
+
+ void setShapes(const QList &shapes);
+ QList shapes() const;
/**
- * Save the marker
- *
- * @return The reference of the marker.
+ * @brief paintAtOrigin paints the marker at the position \p pos.
+ * Scales and rotates the masrker if needed.
*/
- QString saveOdf(KoShapeSavingContext &context) const;
+ void paintAtPosition(QPainter *painter, const QPointF &pos, qreal strokeWidth, qreal nodeAngle);
/**
- * Display name of the marker
- *
- * @return Display name of the marker
+ * Return maximum distance that the marker can take outside the shape itself
*/
- QString name() const;
+ qreal maxInset(qreal strokeWidth) const;
/**
- * Get the path of the marker
- *
- * It calculates the offset depending on the line width
- *
- * @param The width of the line the marker is attached to.
- * @return the path of the marker
+ * Bounding rect of the marker in local coordinates. It is assumed that the marker
+ * is painted with the reference point placed at position (0,0)
*/
- QPainterPath path(qreal width) const;
+ QRectF boundingRect(qreal strokeWidth, qreal nodeAngle) const;
- bool operator==(const KoMarker &other) const;
+ /**
+ * Outline of the marker in local coordinates. It is assumed that the marker
+ * is painted with the reference point placed at position (0,0)
+ */
+ QPainterPath outline(qreal strokeWidth, qreal nodeAngle) const;
+
+ /**
+ * Draws a preview of the marker in \p previewRect of \p painter
+ */
+ void drawPreview(QPainter *painter, const QRectF &previewRect,
+ const QPen &pen, KoFlake::MarkerPosition position);
+
+
+ void applyShapeStroke(KoShape *shape, KoShapeStroke *stroke, const QPointF &pos, qreal strokeWidth, qreal nodeAngle);
private:
class Private;
diff --git a/libs/flake/KoMarker.cpp b/libs/flake/KoMarker.cpp
--- a/libs/flake/KoMarker.cpp
+++ b/libs/flake/KoMarker.cpp
@@ -28,21 +28,108 @@
#include "KoShapeLoadingContext.h"
#include "KoShapeSavingContext.h"
#include "KoOdfWorkaround.h"
+#include "KoShapePainter.h"
+#include "KoViewConverter.h"
+#include
+#include
+#include
+
#include
#include
#include
+#include
+
+#include "kis_global.h"
+#include "kis_algebra_2d.h"
+
class Q_DECL_HIDDEN KoMarker::Private
{
public:
Private()
+ : coordinateSystem(StrokeWidth),
+ referenceSize(3,3),
+ hasAutoOrientation(false),
+ explicitOrientation(0)
{}
+ ~Private() {
+ qDeleteAll(shapes);
+ }
+
+ bool operator==(const KoMarker::Private &other) const
+ {
+ // WARNING: comparison of shapes is extremely fuzzy! Don't
+ // trust it in life-critical cases!
+
+ return name == other.name &&
+ coordinateSystem == other.coordinateSystem &&
+ referencePoint == other.referencePoint &&
+ referenceSize == other.referenceSize &&
+ hasAutoOrientation == other.hasAutoOrientation &&
+ explicitOrientation == other.explicitOrientation &&
+ compareShapesTo(other.shapes);
+ }
+
+ Private(const Private &rhs)
+ : name(rhs.name),
+ coordinateSystem(rhs.coordinateSystem),
+ referencePoint(rhs.referencePoint),
+ referenceSize(rhs.referenceSize),
+ hasAutoOrientation(rhs.hasAutoOrientation),
+ explicitOrientation(rhs.explicitOrientation)
+ {
+ Q_FOREACH (KoShape *shape, rhs.shapes) {
+ shapes << shape->cloneShape();
+ }
+ }
+
QString name;
- QString d;
- QPainterPath path;
- QRect viewBox;
+ MarkerCoordinateSystem coordinateSystem;
+ QPointF referencePoint;
+ QSizeF referenceSize;
+
+ bool hasAutoOrientation;
+ qreal explicitOrientation;
+
+ QList shapes;
+ QScopedPointer shapePainter;
+
+ bool compareShapesTo(const QList other) const {
+ if (shapes.size() != other.size()) return false;
+
+ for (int i = 0; i < shapes.size(); i++) {
+ if (shapes[i]->outline() != other[i]->outline() ||
+ shapes[i]->absoluteTransformation(0) != other[i]->absoluteTransformation(0)) {
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ QTransform markerTransform(qreal strokeWidth, qreal nodeAngle, const QPointF &pos = QPointF()) {
+ const QTransform translate = QTransform::fromTranslate(-referencePoint.x(), -referencePoint.y());
+
+ QTransform t = translate;
+
+ if (coordinateSystem == StrokeWidth) {
+ t *= QTransform::fromScale(strokeWidth, strokeWidth);
+ }
+
+ const qreal angle = hasAutoOrientation ? nodeAngle : explicitOrientation;
+ if (angle != 0.0) {
+ QTransform r;
+ r.rotateRadians(angle);
+ t *= r;
+ }
+
+ t *= QTransform::fromTranslate(pos.x(), pos.y());
+
+ return t;
+ }
};
KoMarker::KoMarker()
@@ -55,71 +142,276 @@
delete d;
}
-bool KoMarker::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
+QString KoMarker::name() const
+{
+ return d->name;
+}
+
+KoMarker::KoMarker(const KoMarker &rhs)
+ : QSharedData(rhs),
+ d(new Private(*rhs.d))
+{
+}
+
+bool KoMarker::operator==(const KoMarker &other) const
{
- Q_UNUSED(context);
- // A shape uses draw:marker-end="Arrow" draw:marker-end-width="0.686cm" draw:marker-end-center="true" which marker and how the marker is used
+ return *d == *other.d;
+}
- //
- //
+void KoMarker::setCoordinateSystem(KoMarker::MarkerCoordinateSystem value)
+{
+ d->coordinateSystem = value;
+}
- d->d =element.attributeNS(KoXmlNS::svg, "d");
- if (d->d.isEmpty()) {
- return false;
+KoMarker::MarkerCoordinateSystem KoMarker::coordinateSystem() const
+{
+ return d->coordinateSystem;
+}
+
+KoMarker::MarkerCoordinateSystem KoMarker::coordinateSystemFromString(const QString &value)
+{
+ MarkerCoordinateSystem result = StrokeWidth;
+
+ if (value == "userSpaceOnUse") {
+ result = UserSpaceOnUse;
}
-#ifndef NWORKAROUND_ODF_BUGS
- KoOdfWorkaround::fixMarkerPath(d->d);
-#endif
+ return result;
+}
+
+QString KoMarker::coordinateSystemToString(KoMarker::MarkerCoordinateSystem value)
+{
+ return
+ value == StrokeWidth ?
+ "strokeWidth" :
+ "userSpaceOnUse";
+}
+
+void KoMarker::setReferencePoint(const QPointF &value)
+{
+ d->referencePoint = value;
+}
- KoPathShape pathShape;
- KoPathShapeLoader loader(&pathShape);
- loader.parseSvg(d->d, true);
+QPointF KoMarker::referencePoint() const
+{
+ return d->referencePoint;
+}
- d->path = pathShape.outline();
- d->viewBox = KoPathShape::loadOdfViewbox(element);
+void KoMarker::setReferenceSize(const QSizeF &size)
+{
+ d->referenceSize = size;
+}
- QString displayName(element.attributeNS(KoXmlNS::draw, "display-name"));
- if (displayName.isEmpty()) {
- displayName = element.attributeNS(KoXmlNS::draw, "name");
+QSizeF KoMarker::referenceSize() const
+{
+ return d->referenceSize;
+}
+
+bool KoMarker::hasAutoOtientation() const
+{
+ return d->hasAutoOrientation;
+}
+
+void KoMarker::setAutoOrientation(bool value)
+{
+ d->hasAutoOrientation = value;
+}
+
+qreal KoMarker::explicitOrientation() const
+{
+ return d->explicitOrientation;
+}
+
+void KoMarker::setExplicitOrientation(qreal value)
+{
+ d->explicitOrientation = value;
+}
+
+void KoMarker::setShapes(const QList &shapes)
+{
+ d->shapes = shapes;
+
+ if (d->shapePainter) {
+ d->shapePainter->setShapes(shapes);
}
- d->name = displayName;
- return true;
}
-QString KoMarker::saveOdf(KoShapeSavingContext &context) const
+QList KoMarker::shapes() const
{
- KoGenStyle style(KoGenStyle::MarkerStyle);
- style.addAttribute("draw:display-name", d->name);
- style.addAttribute("svg:d", d->d);
- const QString viewBox = QString::fromLatin1("%1 %2 %3 %4")
- .arg(d->viewBox.x()).arg(d->viewBox.y())
- .arg(d->viewBox.width()).arg(d->viewBox.height());
- style.addAttribute(QLatin1String("svg:viewBox"), viewBox);
- QString name = QString(QUrl::toPercentEncoding(d->name, "", " ")).replace('%', '_');
- return context.mainStyles().insert(style, name, KoGenStyles::DontAddNumberToName);
+ return d->shapes;
}
-QString KoMarker::name() const
+void KoMarker::paintAtPosition(QPainter *painter, const QPointF &pos, qreal strokeWidth, qreal nodeAngle)
{
- return d->name;
+ QTransform oldTransform = painter->transform();
+
+ KoViewConverter converter;
+
+ if (!d->shapePainter) {
+ d->shapePainter.reset(new KoShapePainter());
+ d->shapePainter->setShapes(d->shapes);
+ }
+
+ painter->setTransform(d->markerTransform(strokeWidth, nodeAngle, pos), true);
+ d->shapePainter->paint(*painter, converter);
+
+ painter->setTransform(oldTransform);
}
-QPainterPath KoMarker::path(qreal width) const
+qreal KoMarker::maxInset(qreal strokeWidth) const
{
- if (!d->viewBox.isValid() || width == 0) {
- return QPainterPath();
+ QRectF shapesBounds = boundingRect(strokeWidth, 0.0); // normalized to 0,0
+ qreal result = 0.0;
+
+ result = qMax(KisAlgebra2D::norm(shapesBounds.topLeft()), result);
+ result = qMax(KisAlgebra2D::norm(shapesBounds.topRight()), result);
+ result = qMax(KisAlgebra2D::norm(shapesBounds.bottomLeft()), result);
+ result = qMax(KisAlgebra2D::norm(shapesBounds.bottomRight()), result);
+
+ if (d->coordinateSystem == StrokeWidth) {
+ result *= strokeWidth;
}
- // TODO: currently the , properties of viewbox are ignored, why? OOo-compat?
- qreal height = width * d->viewBox.height() / d->viewBox.width();
+ return result;
+}
+
+QRectF KoMarker::boundingRect(qreal strokeWidth, qreal nodeAngle) const
+{
+ QRectF shapesBounds = KoShape::boundingRect(d->shapes);
+
+ const QTransform t = d->markerTransform(strokeWidth, nodeAngle);
- QTransform transform;
- transform.scale(width / d->viewBox.width(), height / d->viewBox.height());
- return transform.map(d->path);
+ if (!t.isIdentity()) {
+ shapesBounds = t.mapRect(shapesBounds);
+ }
+
+ return shapesBounds;
}
-bool KoMarker::operator==(const KoMarker &other) const
+QPainterPath KoMarker::outline(qreal strokeWidth, qreal nodeAngle) const
{
- return (d->d == other.d->d && d->viewBox ==other.d->viewBox);
+ QPainterPath outline;
+ Q_FOREACH (KoShape *shape, d->shapes) {
+ outline |= shape->absoluteTransformation(0).map(shape->outline());
+ }
+
+ const QTransform t = d->markerTransform(strokeWidth, nodeAngle);
+
+ if (!t.isIdentity()) {
+ outline = t.map(outline);
+ }
+
+ return outline;
+}
+
+void KoMarker::drawPreview(QPainter *painter, const QRectF &previewRect, const QPen &pen, KoFlake::MarkerPosition position)
+{
+ const QRectF outlineRect = outline(pen.widthF(), 0).boundingRect(); // normalized to 0,0
+ QPointF marker;
+ QPointF start;
+ QPointF end;
+
+ if (position == KoFlake::StartMarker) {
+ marker = QPointF(-outlineRect.left() + previewRect.left(), previewRect.center().y());
+ start = marker;
+ end = QPointF(previewRect.right(), start.y());
+ } else if (position == KoFlake::MidMarker) {
+ start = QPointF(previewRect.left(), previewRect.center().y());
+ marker = QPointF(-outlineRect.center().x() + previewRect.center().x(), start.y());
+ end = QPointF(previewRect.right(), start.y());
+ } else if (position == KoFlake::EndMarker) {
+ start = QPointF(previewRect.left(), previewRect.center().y());
+ marker = QPointF(-outlineRect.right() + previewRect.right(), start.y());
+ end = marker;
+ }
+
+ painter->save();
+ painter->setPen(pen);
+ painter->setClipRect(previewRect);
+
+ painter->drawLine(start, end);
+ paintAtPosition(painter, marker, pen.widthF(), 0);
+
+ painter->restore();
+}
+
+void KoMarker::applyShapeStroke(KoShape *parentShape, KoShapeStroke *stroke, const QPointF &pos, qreal strokeWidth, qreal nodeAngle)
+{
+ const QGradient *originalGradient = stroke->lineBrush().gradient();
+
+ if (!originalGradient) {
+ QList linearizedShapes = KoShape::linearizeSubtree(d->shapes);
+ Q_FOREACH(KoShape *shape, linearizedShapes) {
+ // update the stroke
+ KoShapeStrokeSP shapeStroke = shape->stroke() ?
+ qSharedPointerDynamicCast(shape->stroke()) :
+ KoShapeStrokeSP();
+
+ if (shapeStroke) {
+ shapeStroke = toQShared(new KoShapeStroke(*shapeStroke));
+
+ shapeStroke->setLineBrush(QBrush());
+ shapeStroke->setColor(stroke->color());
+
+ shape->setStroke(shapeStroke);
+ }
+
+ // update the background
+ if (shape->background()) {
+ QSharedPointer bg(new KoColorBackground(stroke->color()));
+ shape->setBackground(bg);
+ }
+ }
+ } else {
+ QScopedPointer g(KoFlake::cloneGradient(originalGradient));
+ KIS_ASSERT_RECOVER_RETURN(g);
+
+ const QTransform markerTransformInverted =
+ d->markerTransform(strokeWidth, nodeAngle, pos).inverted();
+
+ QTransform gradientToUser;
+
+ // Unwrap the gradient to work in global mode
+ if (g->coordinateMode() == QGradient::ObjectBoundingMode) {
+ QRectF boundingRect =
+ parentShape ?
+ parentShape->outline().boundingRect() :
+ this->boundingRect(strokeWidth, nodeAngle);
+
+ boundingRect = KisAlgebra2D::ensureRectNotSmaller(boundingRect, QSizeF(1.0, 1.0));
+
+ gradientToUser = QTransform(boundingRect.width(), 0, 0, boundingRect.height(),
+ boundingRect.x(), boundingRect.y());
+
+ g->setCoordinateMode(QGradient::LogicalMode);
+ }
+
+ QList linearizedShapes = KoShape::linearizeSubtree(d->shapes);
+ Q_FOREACH(KoShape *shape, linearizedShapes) {
+ // shape-unwinding transform
+ QTransform t = gradientToUser * markerTransformInverted * shape->absoluteTransformation(0).inverted();
+
+ // update the stroke
+ KoShapeStrokeSP shapeStroke = shape->stroke() ?
+ qSharedPointerDynamicCast(shape->stroke()) :
+ KoShapeStrokeSP();
+
+ if (shapeStroke) {
+ shapeStroke = toQShared(new KoShapeStroke(*shapeStroke));
+
+ QBrush brush(*g);
+ brush.setTransform(t);
+ shapeStroke->setLineBrush(brush);
+ shapeStroke->setColor(Qt::transparent);
+ shape->setStroke(shapeStroke);
+ }
+
+ // update the background
+ if (shape->background()) {
+
+ QSharedPointer bg(new KoGradientBackground(KoFlake::cloneGradient(g.data()), t));
+ shape->setBackground(bg);
+ }
+ }
+ }
}
diff --git a/libs/flake/KoMarkerCollection.h b/libs/flake/KoMarkerCollection.h
--- a/libs/flake/KoMarkerCollection.h
+++ b/libs/flake/KoMarkerCollection.h
@@ -38,10 +38,6 @@
explicit KoMarkerCollection(QObject *parent = 0);
virtual ~KoMarkerCollection();
- bool loadOdf(KoShapeLoadingContext &context);
- // For now we only save the used markers and that is done with a KoSharedSavingData when a marker usage is encountered.
- //void saveOdf(KoShapeSavingContext &context) const;
-
QList markers() const;
/**
@@ -57,10 +53,11 @@
*/
KoMarker * addMarker(KoMarker *marker);
+ void loadMarkersFromFile(const QString &svgFile);
+
private:
/// load the markers that are available per default.
void loadDefaultMarkers();
- void loadOdfMarkers(const QHash &markers, KoShapeLoadingContext &context, QHash &lookupTable);
class Private;
Private * const d;
diff --git a/libs/flake/KoMarkerCollection.cpp b/libs/flake/KoMarkerCollection.cpp
--- a/libs/flake/KoMarkerCollection.cpp
+++ b/libs/flake/KoMarkerCollection.cpp
@@ -21,15 +21,22 @@
#include
+#include
#include "KoMarker.h"
-#include "KoMarkerSharedLoadingData.h"
#include
-#include
-#include
-#include
-#include
-#include
#include
+#include
+#include
+#include
+#include
+#include
+
+#include "kis_debug.h"
+
+// WARNING: there is a bug in GCC! It doesn't warn that we are
+// deleting an uninitialized type here!
+#include
+
class Q_DECL_HIDDEN KoMarkerCollection::Private
{
@@ -56,66 +63,58 @@
delete d;
}
-bool KoMarkerCollection::loadOdf(KoShapeLoadingContext &context)
+void KoMarkerCollection::loadMarkersFromFile(const QString &svgFile)
{
- debugFlake;
- QHash lookupTable;
+ QFile file(svgFile);
+ if (!file.exists()) return;
- const QHash markers = context.odfLoadingContext().stylesReader().drawStyles("marker");
- loadOdfMarkers(markers, context, lookupTable);
+ if (!file.open(QIODevice::ReadOnly)) return;
- KoMarkerSharedLoadingData * sharedMarkerData = new KoMarkerSharedLoadingData(lookupTable);
- context.addSharedData(MARKER_SHARED_LOADING_ID, sharedMarkerData);
+ QXmlStreamReader reader(&file);
+ reader.setNamespaceProcessing(false);
- return true;
-}
+ QString errorMsg;
+ int errorLine = 0;
+ int errorColumn;
-void KoMarkerCollection::loadDefaultMarkers()
-{
- // use the same mechanism for loading the markers that are available
- // per default as when loading the normal markers.
- KoOdfStylesReader markerReader;
- KoOdfLoadingContext odfContext(markerReader, 0);
- KoShapeLoadingContext shapeContext(odfContext, 0);
KoXmlDocument doc;
- QString filePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, "styles/markers.xml");
+ bool ok = doc.setContent(&reader, &errorMsg, &errorLine, &errorColumn);
+ if (!ok) {
+ errKrita << "Parsing error in " << svgFile << "! Aborting!" << endl
+ << " In line: " << errorLine << ", column: " << errorColumn << endl
+ << " Error message: " << errorMsg << endl;
+ errKrita << i18n("Parsing error in the main document at line %1, column %2\nError message: %3"
+ , errorLine , errorColumn , errorMsg);
+ return;
+ }
- if (!filePath.isEmpty()) {
- QFile file(filePath);
- QString errorMessage;
- if (KoOdfReadStore::loadAndParse(&file, doc, errorMessage, filePath)) {
- markerReader.createStyleMap(doc, true);
+ KoDocumentResourceManager manager;
+ SvgParser parser(&manager);
+ parser.setResolution(QRectF(0,0,100,100), 72); // initialize with default values
+ parser.setXmlBaseDir(QFileInfo(svgFile).absolutePath());
- QHash lookupTable;
- const QHash defaultMarkers = markerReader.drawStyles("marker");
- loadOdfMarkers(defaultMarkers, shapeContext, lookupTable);
- }
- else {
- warnFlake << "reading of" << filePath << "failed:" << errorMessage;
- }
- }
- else {
- debugFlake << "markers.xml not found";
+ parser.setFileFetcher(
+ [](const QString &fileName) {
+ QFile file(fileName);
+ if (!file.exists()) return QByteArray();
+
+ file.open(QIODevice::ReadOnly);
+ return file.readAll();
+ });
+
+ QSizeF fragmentSize;
+ QList shapes = parser.parseSvg(doc.documentElement(), &fragmentSize);
+ qDeleteAll(shapes);
+
+ Q_FOREACH (const QExplicitlySharedDataPointer &marker, parser.knownMarkers()) {
+ addMarker(marker.data());
}
}
-void KoMarkerCollection::loadOdfMarkers(const QHash &markers, KoShapeLoadingContext &context, QHash &lookupTable)
+void KoMarkerCollection::loadDefaultMarkers()
{
- QHash::const_iterator it(markers.constBegin());
- for (; it != markers.constEnd(); ++it) {
- KoMarker *marker = new KoMarker();
- if (marker->loadOdf(*(it.value()), context)) {
- KoMarker *m = addMarker(marker);
- lookupTable.insert(it.key(), m);
- debugFlake << "loaded marker" << it.key() << marker << m;
- if (m != marker) {
- delete marker;
- }
- }
- else {
- delete marker;
- }
- }
+ QString filePath = KoResourcePaths::findResource("data", "styles/markers.svg");
+ loadMarkersFromFile(filePath);
}
QList KoMarkerCollection::markers() const
diff --git a/libs/flake/KoMarkerData.h b/libs/flake/KoMarkerData.h
deleted file mode 100644
--- a/libs/flake/KoMarkerData.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2011 Thorsten Zachmann
-
- 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 KOMARKERDATA_H
-#define KOMARKERDATA_H
-
-#include
-
-#include "kritaflake_export.h"
-
-class KoGenStyle;
-class KoMarker;
-class KoShapeLoadingContext;
-class KoShapeSavingContext;
-
-class KRITAFLAKE_EXPORT KoMarkerData
-{
-public:
- /// Property enum
- enum MarkerPosition {
- MarkerStart, ///< it is the marker where the Path starts
- MarkerEnd ///< it is the marker where the Path ends
- };
-
- KoMarkerData(KoMarker *marker, qreal width, MarkerPosition position, bool center);
- explicit KoMarkerData(MarkerPosition position);
- KoMarkerData(const KoMarkerData &other);
- ~KoMarkerData();
-
- /**
- * Get the marker
- *
- * @return the marker or 0 if no marker is set
- */
- KoMarker *marker() const;
-
- /**
- * Set the marker
- *
- * @param marker The marker that is set or 0 to remove the marker
- */
- void setMarker(KoMarker *marker);
-
- /**
- * Get the with of the marker according to the pen width
- */
- qreal width(qreal penWidth) const;
-
- /**
- * Set the width of the marker
- *
- * This calculates a base width for the marker so the width of the marker changes
- * with the width of the line.
- *
- * @param width The width of the marker
- * @param penWidth The width of the used pen
- */
- void setWidth(qreal width, qreal penWidth);
-
- /**
- * Get the position of the marker
- *
- * @return Position of the marker
- */
- MarkerPosition position() const;
-
- /**
- * Set the position of the marker
- *
- * @param position Position of the marker
- */
- void setPosition(MarkerPosition position);
-
- /**
- * Get the center property of the marker
- *
- * If the marker is centered at the start of the stroke the line will get longer.
- *
- * @return Returns true if the marker is centered at the start of the stroke.
- */
- bool center() const;
-
- /**
- * Set the center property of the marker
- *
- * @param center If set to true the marker should be centered at the start of the stroke.
- */
- void setCenter(bool center);
-
- /**
- * Compare the marker data
- */
- KoMarkerData &operator=(const KoMarkerData &other);
-
- /**
- * Load the marker data
- *
- * @param penWidth the used pen width of the line
- * @param context The shape loading context
- */
- bool loadOdf(qreal penWidth, KoShapeLoadingContext &context);
-
- /**
- * Save the marker data to the style
- *
- * @param style The style that we add the marker data to
- * @param penWidth the used pen width of the line
- * @param context The shape saving context
- */
- void saveStyle(KoGenStyle &style, qreal penWidth, KoShapeSavingContext &context) const;
-
-private:
- // make private to be sure it is not used
- KoMarkerData();
-
- class Private;
- Private * const d;
-};
-
-#endif /* KOMARKERDATA_H */
diff --git a/libs/flake/KoMarkerData.cpp b/libs/flake/KoMarkerData.cpp
deleted file mode 100644
--- a/libs/flake/KoMarkerData.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2011 Thorsten Zachmann
-
- 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 "KoMarkerData.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include "KoShapeLoadingContext.h"
-#include "KoMarker.h"
-#include "KoMarkerSharedLoadingData.h"
-
-/**
- * This defines the factor the width of the arrow is widened
- * when the width of the line is changed.
- */
-static const qreal ResizeFactor = 1.5;
-
-static const struct {
- const char * m_markerPositionLoad;
- const char * m_markerWidthLoad;
- const char * m_markerCenterLoad;
- const char * m_markerPositionSave;
- const char * m_markerWidthSave;
- const char * m_markerCenterSave;
-} markerOdfData[] = {
- { "marker-start", "marker-start-width", "marker-start-center", "draw:marker-start", "draw:marker-start-width", "draw:marker-start-center" },
- { "marker-end" , "marker-end-width", "marker-end-center", "draw:marker-end" , "draw:marker-end-width", "draw:marker-end-center" }
-};
-
-class Q_DECL_HIDDEN KoMarkerData::Private
-{
-public:
- Private(KoMarker *marker, qreal baseWidth, KoMarkerData::MarkerPosition position, bool center)
- : marker(marker)
- , baseWidth(baseWidth)
- , position(position)
- , center(center)
- {}
-
- QExplicitlySharedDataPointer marker;
- qreal baseWidth;
- MarkerPosition position;
- bool center;
-};
-
-KoMarkerData::KoMarkerData(KoMarker *marker, qreal width, MarkerPosition position, bool center)
-: d(new Private(marker, width, position, center))
-{
-}
-
-KoMarkerData::KoMarkerData(MarkerPosition position)
-: d(new Private(0, 0, position, false))
-{
-}
-
-KoMarkerData::KoMarkerData()
-: d(0)
-{
- Q_ASSERT(0);
-}
-
-KoMarkerData::KoMarkerData(const KoMarkerData &other)
-: d(new Private(other.d->marker.data(), other.d->baseWidth, other.d->position, other.d->center))
-{
-}
-
-KoMarkerData::~KoMarkerData()
-{
- delete d;
-}
-
-
-KoMarker *KoMarkerData::marker() const
-{
- return d->marker.data();
-}
-
-void KoMarkerData::setMarker(KoMarker *marker)
-{
- d->marker = QExplicitlySharedDataPointer(marker);
-}
-
-qreal KoMarkerData::width(qreal penWidth) const
-{
- return d->baseWidth + penWidth * ResizeFactor;
-}
-
-void KoMarkerData::setWidth(qreal width, qreal penWidth)
-{
- d->baseWidth = qMax(qreal(0.0), width - penWidth * ResizeFactor);
-}
-
-KoMarkerData::MarkerPosition KoMarkerData::position() const
-{
- return d->position;
-}
-
-void KoMarkerData::setPosition(MarkerPosition position)
-{
- d->position = position;
-}
-
-bool KoMarkerData::center() const
-{
- return d->center;
-}
-
-void KoMarkerData::setCenter(bool center)
-{
- d->center = center;
-}
-
-KoMarkerData &KoMarkerData::operator=(const KoMarkerData &other)
-{
- if (this != &other) {
- d->marker = other.d->marker;
- d->baseWidth = other.d->baseWidth;
- d->position = other.d->position;
- d->center = other.d->center;
- }
- return (*this);
-}
-
-bool KoMarkerData::loadOdf(qreal penWidth, KoShapeLoadingContext &context)
-{
- KoMarkerSharedLoadingData *markerShared = dynamic_cast(context.sharedData(MARKER_SHARED_LOADING_ID));
- if (markerShared) {
- KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
- // draw:marker-end="Arrow" draw:marker-end-width="0.686cm" draw:marker-end-center="true"
- const QString markerStart(styleStack.property(KoXmlNS::draw, markerOdfData[d->position].m_markerPositionLoad));
- const QString markerStartWidth(styleStack.property(KoXmlNS::draw, markerOdfData[d->position].m_markerWidthLoad));
- if (!markerStart.isEmpty() && !markerStartWidth.isEmpty()) {
- KoMarker *marker = markerShared->marker(markerStart);
- if (marker) {
- setMarker(marker);
- qreal markerWidth = KoUnit::parseValue(markerStartWidth);
- setWidth(markerWidth, penWidth);
- setCenter(styleStack.property(KoXmlNS::draw, markerOdfData[d->position].m_markerCenterLoad) == "true");
- }
- }
- }
- return true;
-}
-
-void KoMarkerData::saveStyle(KoGenStyle &style, qreal penWidth, KoShapeSavingContext &context) const
-{
- if (d->marker) {
- QString markerRef = d->marker->saveOdf(context);
- style.addProperty(markerOdfData[d->position].m_markerPositionSave, markerRef, KoGenStyle::GraphicType);
- style.addPropertyPt(markerOdfData[d->position].m_markerWidthSave, width(penWidth), KoGenStyle::GraphicType);
- style.addProperty(markerOdfData[d->position].m_markerCenterSave, d->center, KoGenStyle::GraphicType);
- }
-}
diff --git a/libs/flake/KoMarkerSharedLoadingData.h b/libs/flake/KoMarkerSharedLoadingData.h
deleted file mode 100644
--- a/libs/flake/KoMarkerSharedLoadingData.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2011 Thorsten Zachmann
-
- 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 KOMARKERSHAREDLOADINGDATA_H
-#define KOMARKERSHAREDLOADINGDATA_H
-
-#include "KoSharedLoadingData.h"
-
-#include
-
-#define MARKER_SHARED_LOADING_ID "KoMarkerShareadLoadingId"
-
-class KoMarker;
-class QString;
-
-class KoMarkerSharedLoadingData : public KoSharedLoadingData
-{
-public:
- KoMarkerSharedLoadingData(const QHash &lookupTable);
- virtual ~KoMarkerSharedLoadingData();
-
- KoMarker *marker(const QString &name) const;
-
-private:
- class Private;
- Private * const d;
-};
-
-#endif /* KOMARKERSHAREDLOADINGDATA_H */
diff --git a/libs/flake/KoMarkerSharedLoadingData.cpp b/libs/flake/KoMarkerSharedLoadingData.cpp
deleted file mode 100644
--- a/libs/flake/KoMarkerSharedLoadingData.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/* This file is part of the KDE project
- Copyright (C) 2011 Thorsten Zachmann
-
- 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 "KoMarkerSharedLoadingData.h"
-
-#include
-
-class KoMarkerSharedLoadingData::Private
-{
-public:
- QHash lookupTable;
-};
-
-KoMarkerSharedLoadingData::KoMarkerSharedLoadingData(const QHash &lookupTable)
-: d(new Private())
-{
- d->lookupTable = lookupTable;
-}
-
-KoMarkerSharedLoadingData::~KoMarkerSharedLoadingData()
-{
- delete d;
-}
-
-KoMarker *KoMarkerSharedLoadingData::marker(const QString &name) const
-{
- return d->lookupTable.value(name, 0);
-}
diff --git a/libs/flake/KoOdfGradientBackground.h b/libs/flake/KoOdfGradientBackground.h
--- a/libs/flake/KoOdfGradientBackground.h
+++ b/libs/flake/KoOdfGradientBackground.h
@@ -39,6 +39,8 @@
// destructor
virtual ~KoOdfGradientBackground();
+ bool compareTo(const KoShapeBackground *other) const override;
+
/// reimplemented from KoShapeBackground
virtual void fillStyle(KoGenStyle& style, KoShapeSavingContext& context);
/// reimplemented from KoShapeBackground
diff --git a/libs/flake/KoOdfGradientBackground.cpp b/libs/flake/KoOdfGradientBackground.cpp
--- a/libs/flake/KoOdfGradientBackground.cpp
+++ b/libs/flake/KoOdfGradientBackground.cpp
@@ -65,6 +65,12 @@
}
+bool KoOdfGradientBackground::compareTo(const KoShapeBackground *other) const
+{
+ Q_UNUSED(other);
+ return false;
+}
+
bool KoOdfGradientBackground::loadOdf(const KoXmlElement& e)
{
diff --git a/libs/flake/KoParameterShape.h b/libs/flake/KoParameterShape.h
--- a/libs/flake/KoParameterShape.h
+++ b/libs/flake/KoParameterShape.h
@@ -25,6 +25,7 @@
#include "kritaflake_export.h"
class KoParameterShapePrivate;
+class KisHandlePainterHelper;
/**
* KoParameterShape is the base class for all parametric shapes
@@ -83,7 +84,7 @@
* @param converter the view converter for applying the actual zoom
* @param handleRadius the radius of the handles used for painting
*/
- void paintHandles(QPainter &painter, const KoViewConverter &converter, int handleRadius);
+ void paintHandles(KisHandlePainterHelper &handlesHelper);
/**
* @brief Paint the given handles
@@ -93,7 +94,7 @@
* @param handleId of the handle which should be repainted
* @param handleRadius the radius of the handle used for painting
*/
- void paintHandle(QPainter &painter, const KoViewConverter &converter, int handleId, int handleRadius);
+ void paintHandle(KisHandlePainterHelper &handlesHelper, int handleId);
/// reimplemented from KoShape
virtual void setSize(const QSizeF &size);
@@ -137,7 +138,7 @@
void setHandles(const QList &handles);
/// constructor
- KoParameterShape(KoParameterShapePrivate &);
+ KoParameterShape(KoParameterShapePrivate *);
/**
* @brief Updates the internal state of a KoParameterShape.
@@ -157,7 +158,7 @@
*/
virtual void updatePath(const QSizeF &size) = 0;
-private:
+protected:
Q_DECLARE_PRIVATE(KoParameterShape)
};
diff --git a/libs/flake/KoParameterShape.cpp b/libs/flake/KoParameterShape.cpp
--- a/libs/flake/KoParameterShape.cpp
+++ b/libs/flake/KoParameterShape.cpp
@@ -21,15 +21,29 @@
#include "KoParameterShape.h"
#include "KoParameterShape_p.h"
+#include
+
#include
#include
+KoParameterShapePrivate::KoParameterShapePrivate(KoParameterShape *shape)
+ : KoPathShapePrivate(shape),
+ parametric(true)
+{
+}
+
+KoParameterShapePrivate::KoParameterShapePrivate(const KoParameterShapePrivate &rhs, KoParameterShape *q)
+ : KoPathShapePrivate(rhs, q),
+ handles(rhs.handles)
+{
+}
+
KoParameterShape::KoParameterShape()
- : KoPathShape(*(new KoParameterShapePrivate(this)))
+ : KoPathShape(new KoParameterShapePrivate(this))
{
}
-KoParameterShape::KoParameterShape(KoParameterShapePrivate &dd)
+KoParameterShape::KoParameterShape(KoParameterShapePrivate *dd)
: KoPathShape(dd)
{
}
@@ -52,7 +66,6 @@
updatePath(size());
update();
- d->shapeChanged(ParameterChanged);
}
@@ -76,42 +89,20 @@
return d->handles.value(handleId);
}
-void KoParameterShape::paintHandles(QPainter & painter, const KoViewConverter & converter, int handleRadius)
+void KoParameterShape::paintHandles(KisHandlePainterHelper &handlesHelper)
{
Q_D(KoParameterShape);
- applyConversion(painter, converter);
-
- QTransform worldMatrix = painter.worldTransform();
- painter.setTransform(QTransform());
-
- QTransform matrix;
- matrix.rotate(45.0);
- QPolygonF poly(d->handleRect(QPointF(0, 0), handleRadius));
- poly = matrix.map(poly);
QList::const_iterator it(d->handles.constBegin());
for (; it != d->handles.constEnd(); ++it) {
- QPointF moveVector = worldMatrix.map(*it);
- poly.translate(moveVector.x(), moveVector.y());
- painter.drawPolygon(poly);
- poly.translate(-moveVector.x(), -moveVector.y());
+ handlesHelper.drawGradientHandle(*it);
}
}
-void KoParameterShape::paintHandle(QPainter & painter, const KoViewConverter & converter, int handleId, int handleRadius)
+void KoParameterShape::paintHandle(KisHandlePainterHelper &handlesHelper, int handleId)
{
Q_D(KoParameterShape);
- applyConversion(painter, converter);
-
- QTransform worldMatrix = painter.worldTransform();
- painter.setTransform(QTransform());
-
- QTransform matrix;
- matrix.rotate(45.0);
- QPolygonF poly(d->handleRect(QPointF(0, 0), handleRadius));
- poly = matrix.map(poly);
- poly.translate(worldMatrix.map(d->handles[handleId]));
- painter.drawPolygon(poly);
+ handlesHelper.drawGradientHandle(d->handles[handleId]);
}
void KoParameterShape::setSize(const QSizeF &newSize)
@@ -163,6 +154,8 @@
{
Q_D(KoParameterShape);
d->handles = handles;
+
+ d->shapeChanged(ParameterChanged);
}
int KoParameterShape::handleCount() const
diff --git a/libs/flake/KoParameterShape_p.h b/libs/flake/KoParameterShape_p.h
--- a/libs/flake/KoParameterShape_p.h
+++ b/libs/flake/KoParameterShape_p.h
@@ -21,19 +21,20 @@
#ifndef KOPARAMETERSHAPE_P_H
#define KOPARAMETERSHAPE_P_H
+#include "kritaflake_export.h"
+#include
#include "KoPathShape_p.h"
#include
#include
-class KoParameterShapePrivate : public KoPathShapePrivate
+class KoParameterShape;
+
+class KRITAFLAKE_EXPORT KoParameterShapePrivate : public KoPathShapePrivate
{
public:
- explicit KoParameterShapePrivate(KoParameterShape *shape)
- : KoPathShapePrivate(shape),
- parametric(true)
- {
- }
+ explicit KoParameterShapePrivate(KoParameterShape *shape);
+ explicit KoParameterShapePrivate(const KoParameterShapePrivate &rhs, KoParameterShape *q);
bool parametric;
diff --git a/libs/flake/KoPathPoint.h b/libs/flake/KoPathPoint.h
--- a/libs/flake/KoPathPoint.h
+++ b/libs/flake/KoPathPoint.h
@@ -31,6 +31,7 @@
class QTransform;
class QRectF;
class QPainter;
+class KisHandlePainterHelper;
/**
* @brief A KoPathPoint represents a point in a path.
@@ -80,6 +81,7 @@
* @brief Copy Constructor
*/
KoPathPoint(const KoPathPoint &pathPoint);
+ KoPathPoint(const KoPathPoint &pathPoint, KoPathShape *newParent);
/**
* @brief Assignment operator.
@@ -212,7 +214,7 @@
* @param active If true only the given active points are painted
* If false all given points are used.
*/
- void paint(QPainter &painter, int handleRadius, PointTypes types, bool active = true);
+ void paint(KisHandlePainterHelper &handlesHelper, PointTypes types, bool active = true);
/**
* @brief Sets the parent path shape.
diff --git a/libs/flake/KoPathPoint.cpp b/libs/flake/KoPathPoint.cpp
--- a/libs/flake/KoPathPoint.cpp
+++ b/libs/flake/KoPathPoint.cpp
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
@@ -51,15 +52,21 @@
KoPathPoint::KoPathPoint(const KoPathPoint &pathPoint)
: d(new Private())
{
- d->shape = pathPoint.d->shape;
+ d->shape = 0;
d->point = pathPoint.d->point;
d->controlPoint1 = pathPoint.d->controlPoint1;
d->controlPoint2 = pathPoint.d->controlPoint2;
d->properties = pathPoint.d->properties;
d->activeControlPoint1 = pathPoint.d->activeControlPoint1;
d->activeControlPoint2 = pathPoint.d->activeControlPoint2;
}
+KoPathPoint::KoPathPoint(const KoPathPoint &pathPoint, KoPathShape *newParent)
+ : KoPathPoint(pathPoint)
+{
+ d->shape = newParent;
+}
+
KoPathPoint::KoPathPoint()
: d(new Private())
{
@@ -255,49 +262,40 @@
d->shape->notifyChanged();
}
-void KoPathPoint::paint(QPainter &painter, int handleRadius, PointTypes types, bool active)
+void KoPathPoint::paint(KisHandlePainterHelper &handlesHelper, PointTypes types, bool active)
{
- QRectF handle(-handleRadius, -handleRadius, 2*handleRadius, 2*handleRadius);
-
bool drawControlPoint1 = types & ControlPoint1 && (!active || activeControlPoint1());
bool drawControlPoint2 = types & ControlPoint2 && (!active || activeControlPoint2());
// draw lines at the bottom
- if (drawControlPoint2)
- painter.drawLine(point(), controlPoint2());
-
- if (drawControlPoint1)
- painter.drawLine(point(), controlPoint1());
-
-
- QTransform worldMatrix = painter.worldTransform();
+ if (drawControlPoint2) {
+ handlesHelper.drawConnectionLine(point(), controlPoint2());
+ }
- painter.setWorldTransform(QTransform());
+ if (drawControlPoint1) {
+ handlesHelper.drawConnectionLine(point(), controlPoint1());
+ }
// the point is lowest
if (types & Node) {
- if (properties() & IsSmooth)
- painter.drawRect(handle.translated(worldMatrix.map(point())));
- else if (properties() & IsSymmetric) {
- QTransform matrix;
- matrix.rotate(45.0);
- QPolygonF poly(handle);
- poly = matrix.map(poly);
- poly.translate(worldMatrix.map(point()));
- painter.drawPolygon(poly);
- } else
- painter.drawEllipse(handle.translated(worldMatrix.map(point())));
+ if (properties() & IsSmooth) {
+ handlesHelper.drawHandleRect(point());
+ } else if (properties() & IsSymmetric) {
+ handlesHelper.drawGradientHandle(point());
+ } else {
+ handlesHelper.drawHandleCircle(point());
+ }
}
// then comes control point 2
- if (drawControlPoint2)
- painter.drawEllipse(handle.translated(worldMatrix.map(controlPoint2())));
+ if (drawControlPoint2) {
+ handlesHelper.drawHandleSmallCircle(controlPoint2());
+ }
// then comes control point 1
- if (drawControlPoint1)
- painter.drawEllipse(handle.translated(worldMatrix.map(controlPoint1())));
-
- painter.setWorldTransform(worldMatrix);
+ if (drawControlPoint1) {
+ handlesHelper.drawHandleSmallCircle(controlPoint1());
+ }
}
void KoPathPoint::setParent(KoPathShape* parent)
diff --git a/libs/flake/KoPathPointData.h b/libs/flake/KoPathPointData.h
--- a/libs/flake/KoPathPointData.h
+++ b/libs/flake/KoPathPointData.h
@@ -22,11 +22,12 @@
#define KOPATHPOINTDATA_H
#include "KoPathShape.h"
+#include
/**
* @brief Describe a KoPathPoint by a KoPathShape and its indices
*/
-class KoPathPointData
+class KoPathPointData : public boost::equality_comparable
{
public:
/// contructor
diff --git a/libs/flake/KoPathShape.h b/libs/flake/KoPathShape.h
--- a/libs/flake/KoPathShape.h
+++ b/libs/flake/KoPathShape.h
@@ -29,14 +29,14 @@
#include
#include "KoTosContainer.h"
-#include "KoMarkerData.h"
#define KoPathShapeId "KoPathShape"
class KoPathSegment;
class KoPathPoint;
class KoPathShapePrivate;
class KoMarker;
+class KisHandlePainterHelper;
typedef QPair KoPathPointIndex;
@@ -85,15 +85,20 @@
*/
virtual ~KoPathShape();
+ KoShape *cloneShape() const;
+
/// reimplemented
virtual void paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext);
- virtual void paintPoints(QPainter &painter, const KoViewConverter &converter, int handleRadius);
+ virtual void paintPoints(KisHandlePainterHelper &handlesHelper);
+
+ /// reimplemented
+ QRectF outlineRect() const override;
/// reimplemented
- virtual QPainterPath outline() const;
+ QPainterPath outline() const override;
/// reimplemented
- virtual QRectF boundingRect() const;
+ QRectF boundingRect() const override;
/// reimplemented
- virtual QSizeF size() const;
+ QSizeF size() const override;
QPainterPath pathStroke(const QPen &pen) const;
/**
@@ -409,9 +414,9 @@
/**
* @brief Combines two path shapes by appending the data of the specified path.
* @param path the path to combine with
- * @return true if combining was successful, else false
+ * @return index of the first segment inserted or -1 on failure
*/
- bool combine(KoPathShape *path);
+ int combine(KoPathShape *path);
/**
* @brief Creates separate path shapes, one for each existing subpath.
@@ -450,20 +455,22 @@
/// Returns the viewbox from the given xml element.
static QRect loadOdfViewbox(const KoXmlElement &element);
- /// Marker setter
- void setMarker(const KoMarkerData &markerData);
+ void setMarker(KoMarker *marker, KoFlake::MarkerPosition pos);
+ KoMarker* marker(KoFlake::MarkerPosition pos) const;
+ bool hasMarkers() const;
- /// Marker setter
- void setMarker(KoMarker *marker, KoMarkerData::MarkerPosition position);
+ bool autoFillMarkers() const;
+ void setAutoFillMarkers(bool value);
- /// returns the list of all the markers of the path
- KoMarker *marker(KoMarkerData::MarkerPosition position) const;
-
- KoMarkerData markerData(KoMarkerData::MarkerPosition position) const;
+private:
+ /// constructor: to be used in cloneShape(), not in descendants!
+ /// \internal
+ KoPathShape(const KoPathShape &rhs);
protected:
- /// constructor \internal
- KoPathShape(KoPathShapePrivate &);
+ /// constructor:to be used in descendant shapes
+ /// \internal
+ KoPathShape(KoPathShapePrivate *);
/// reimplemented
virtual QString saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const;
@@ -494,8 +501,6 @@
*/
QTransform resizeMatrix( const QSizeF &newSize ) const;
- KoSubpathList m_subpaths;
-
private:
Q_DECLARE_PRIVATE(KoPathShape)
};
diff --git a/libs/flake/KoPathShape.cpp b/libs/flake/KoPathShape.cpp
--- a/libs/flake/KoPathShape.cpp
+++ b/libs/flake/KoPathShape.cpp
@@ -36,7 +36,6 @@
#include "KoShapeContainer.h"
#include "KoFilterEffectStack.h"
#include "KoMarker.h"
-#include "KoMarkerSharedLoadingData.h"
#include "KoShapeStroke.h"
#include "KoInsets.h"
@@ -51,6 +50,8 @@
#include
#include
+#include "kis_global.h"
+
#include // for qIsNaN
static bool qIsNaNPoint(const QPointF &p) {
return qIsNaN(p.x()) || qIsNaN(p.y());
@@ -60,11 +61,27 @@
KoPathShapePrivate::KoPathShapePrivate(KoPathShape *q)
: KoTosContainerPrivate(q),
fillRule(Qt::OddEvenFill),
- startMarker(KoMarkerData::MarkerStart),
- endMarker(KoMarkerData::MarkerEnd)
+ autoFillMarkers(false)
{
}
+KoPathShapePrivate::KoPathShapePrivate(const KoPathShapePrivate &rhs, KoPathShape *q)
+ : KoTosContainerPrivate(rhs, q),
+ fillRule(rhs.fillRule),
+ markersNew(rhs.markersNew),
+ autoFillMarkers(rhs.autoFillMarkers)
+{
+ Q_FOREACH (KoSubpath *subPath, rhs.subpaths) {
+ KoSubpath *clonedSubPath = new KoSubpath();
+
+ Q_FOREACH (KoPathPoint *point, *subPath) {
+ *clonedSubPath << new KoPathPoint(*point, q);
+ }
+
+ subpaths << clonedSubPath;
+ }
+}
+
QRectF KoPathShapePrivate::handleRect(const QPointF &p, qreal radius) const
{
return QRectF(p.x() - radius, p.y() - radius, 2*radius, 2*radius);
@@ -97,29 +114,39 @@
}
KoPathShape::KoPathShape()
- :KoTosContainer(*(new KoPathShapePrivate(this)))
+ :KoTosContainer(new KoPathShapePrivate(this))
{
}
-KoPathShape::KoPathShape(KoPathShapePrivate &dd)
+KoPathShape::KoPathShape(KoPathShapePrivate *dd)
: KoTosContainer(dd)
{
}
+KoPathShape::KoPathShape(const KoPathShape &rhs)
+ : KoTosContainer(new KoPathShapePrivate(*rhs.d_func(), this))
+{
+}
+
KoPathShape::~KoPathShape()
{
clear();
}
+KoShape *KoPathShape::cloneShape() const
+{
+ return new KoPathShape(*this);
+}
+
void KoPathShape::saveContourOdf(KoShapeSavingContext &context, const QSizeF &scaleFactor) const
{
Q_D(const KoPathShape);
- if (m_subpaths.length() <= 1) {
+ if (d->subpaths.length() <= 1) {
QTransform matrix;
matrix.scale(scaleFactor.width(), scaleFactor.height());
QString points;
- KoSubpath *subPath = m_subpaths.first();
+ KoSubpath *subPath = d->subpaths.first();
KoSubpath::const_iterator pointIt(subPath->constBegin());
KoPathPoint *currPoint= 0;
@@ -303,13 +330,13 @@
style.addProperty("svg:fill-rule", d->fillRule == Qt::OddEvenFill ? "evenodd" : "nonzero");
- KoShapeStroke *lineBorder = dynamic_cast(stroke());
+ QSharedPointer lineBorder = qSharedPointerDynamicCast(stroke());
qreal lineWidth = 0;
if (lineBorder) {
lineWidth = lineBorder->lineWidth();
}
- d->startMarker.saveStyle(style, lineWidth, context);
- d->endMarker.saveStyle(style, lineWidth, context);
+
+ Q_UNUSED(lineWidth)
return KoTosContainer::saveStyle(style, context);
}
@@ -332,14 +359,13 @@
#endif
}
- KoShapeStroke *lineBorder = dynamic_cast(stroke());
+ QSharedPointer lineBorder = qSharedPointerDynamicCast(stroke());
qreal lineWidth = 0;
if (lineBorder) {
lineWidth = lineBorder->lineWidth();
}
- d->startMarker.loadOdf(lineWidth, context);
- d->endMarker.loadOdf(lineWidth, context);
+ Q_UNUSED(lineWidth);
}
QRect KoPathShape::loadOdfViewbox(const KoXmlElement & element)
@@ -361,12 +387,14 @@
void KoPathShape::clear()
{
- Q_FOREACH (KoSubpath *subpath, m_subpaths) {
+ Q_D(KoPathShape);
+
+ Q_FOREACH (KoSubpath *subpath, d->subpaths) {
Q_FOREACH (KoPathPoint *point, *subpath)
delete point;
delete subpath;
}
- m_subpaths.clear();
+ d->subpaths.clear();
}
void KoPathShape::paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext)
@@ -387,13 +415,13 @@
void KoPathShapePrivate::paintDebug(QPainter &painter)
{
Q_Q(KoPathShape);
- KoSubpathList::const_iterator pathIt(q->m_subpaths.constBegin());
+ KoSubpathList::const_iterator pathIt(subpaths.constBegin());
int i = 0;
QPen pen(Qt::black, 0);
painter.save();
painter.setPen(pen);
- for (; pathIt != q->m_subpaths.constEnd(); ++pathIt) {
+ for (; pathIt != subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it) {
++i;
@@ -422,33 +450,40 @@
void KoPathShapePrivate::debugPath() const
{
Q_Q(const KoPathShape);
- KoSubpathList::const_iterator pathIt(q->m_subpaths.constBegin());
- for (; pathIt != q->m_subpaths.constEnd(); ++pathIt) {
+ KoSubpathList::const_iterator pathIt(subpaths.constBegin());
+ for (; pathIt != subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it) {
debugFlake << "p:" << (*pathIt) << "," << *it << "," << (*it)->point() << "," << (*it)->properties();
}
}
}
#endif
-void KoPathShape::paintPoints(QPainter &painter, const KoViewConverter &converter, int handleRadius)
+void KoPathShape::paintPoints(KisHandlePainterHelper &handlesHelper)
{
- applyConversion(painter, converter);
+ Q_D(KoPathShape);
- KoSubpathList::const_iterator pathIt(m_subpaths.constBegin());
+ KoSubpathList::const_iterator pathIt(d->subpaths.constBegin());
- for (; pathIt != m_subpaths.constEnd(); ++pathIt) {
+ for (; pathIt != d->subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it)
- (*it)->paint(painter, handleRadius, KoPathPoint::Node);
+ (*it)->paint(handlesHelper, KoPathPoint::Node);
}
}
+QRectF KoPathShape::outlineRect() const
+{
+ return outline().boundingRect();
+}
+
QPainterPath KoPathShape::outline() const
{
+ Q_D(const KoPathShape);
+
QPainterPath path;
- Q_FOREACH (KoSubpath * subpath, m_subpaths) {
+ Q_FOREACH (KoSubpath * subpath, d->subpaths) {
KoPathPoint * lastPoint = subpath->first();
bool activeCP = false;
Q_FOREACH (KoPathPoint * currPoint, *subpath) {
@@ -513,7 +548,7 @@
QTransform transform = absoluteTransformation(0);
// calculate the bounding rect of the transformed outline
QRectF bb;
- KoShapeStroke *lineBorder = dynamic_cast(stroke());
+ const QSharedPointer lineBorder = qSharedPointerDynamicCast(stroke());
QPen pen;
if (lineBorder) {
pen.setWidthF(lineBorder->lineWidth());
@@ -533,6 +568,10 @@
qreal top = qMin(tl.y(),br.y());
qreal bottom = qMax(tl.y(),br.y());
bb.adjust(left, top, right, bottom);
+
+ // TODO: take care about transformations!
+ // take care about markers!
+ bb = kisGrowRect(bb, stroke()->strokeMaxMarkersInset(this));
}
if (shadow()) {
KoInsets insets;
@@ -550,7 +589,7 @@
{
// don't call boundingRect here as it uses absoluteTransformation
// which itself uses size() -> leads to infinite reccursion
- return outline().boundingRect().size();
+ return outlineRect().size();
}
void KoPathShape::setSize(const QSizeF &newSize)
@@ -585,65 +624,69 @@
KoPathPoint * KoPathShape::moveTo(const QPointF &p)
{
+ Q_D(KoPathShape);
+
KoPathPoint * point = new KoPathPoint(this, p, KoPathPoint::StartSubpath | KoPathPoint::StopSubpath);
KoSubpath * path = new KoSubpath;
path->push_back(point);
- m_subpaths.push_back(path);
+ d->subpaths.push_back(path);
return point;
}
KoPathPoint * KoPathShape::lineTo(const QPointF &p)
{
Q_D(KoPathShape);
- if (m_subpaths.empty()) {
+ if (d->subpaths.empty()) {
moveTo(QPointF(0, 0));
}
KoPathPoint * point = new KoPathPoint(this, p, KoPathPoint::StopSubpath);
- KoPathPoint * lastPoint = m_subpaths.last()->last();
+ KoPathPoint * lastPoint = d->subpaths.last()->last();
d->updateLast(&lastPoint);
- m_subpaths.last()->push_back(point);
+ d->subpaths.last()->push_back(point);
return point;
}
KoPathPoint * KoPathShape::curveTo(const QPointF &c1, const QPointF &c2, const QPointF &p)
{
Q_D(KoPathShape);
- if (m_subpaths.empty()) {
+ if (d->subpaths.empty()) {
moveTo(QPointF(0, 0));
}
- KoPathPoint * lastPoint = m_subpaths.last()->last();
+ KoPathPoint * lastPoint = d->subpaths.last()->last();
d->updateLast(&lastPoint);
lastPoint->setControlPoint2(c1);
KoPathPoint * point = new KoPathPoint(this, p, KoPathPoint::StopSubpath);
point->setControlPoint1(c2);
- m_subpaths.last()->push_back(point);
+ d->subpaths.last()->push_back(point);
return point;
}
KoPathPoint * KoPathShape::curveTo(const QPointF &c, const QPointF &p)
{
Q_D(KoPathShape);
- if (m_subpaths.empty())
+ if (d->subpaths.empty())
moveTo(QPointF(0, 0));
- KoPathPoint * lastPoint = m_subpaths.last()->last();
+ KoPathPoint * lastPoint = d->subpaths.last()->last();
d->updateLast(&lastPoint);
lastPoint->setControlPoint2(c);
KoPathPoint * point = new KoPathPoint(this, p, KoPathPoint::StopSubpath);
- m_subpaths.last()->push_back(point);
+ d->subpaths.last()->push_back(point);
return point;
}
KoPathPoint * KoPathShape::arcTo(qreal rx, qreal ry, qreal startAngle, qreal sweepAngle)
{
- if (m_subpaths.empty()) {
+ Q_D(KoPathShape);
+
+ if (d->subpaths.empty()) {
moveTo(QPointF(0, 0));
}
- KoPathPoint * lastPoint = m_subpaths.last()->last();
+ KoPathPoint * lastPoint = d->subpaths.last()->last();
if (lastPoint->properties() & KoPathPoint::CloseSubpath) {
- lastPoint = m_subpaths.last()->first();
+ lastPoint = d->subpaths.last()->first();
}
QPointF startpoint(lastPoint->point());
@@ -662,12 +705,10 @@
int pointCnt = 0;
// check Parameters
- if (sweepAngle == 0)
+ if (sweepAngle == 0.0)
return pointCnt;
- if (sweepAngle > 360)
- sweepAngle = 360;
- else if (sweepAngle < -360)
- sweepAngle = - 360;
+
+ sweepAngle = qBound(-360.0, sweepAngle, 360.0);
if (rx == 0 || ry == 0) {
//TODO
@@ -720,19 +761,19 @@
void KoPathShape::close()
{
Q_D(KoPathShape);
- if (m_subpaths.empty()) {
+ if (d->subpaths.empty()) {
return;
}
- d->closeSubpath(m_subpaths.last());
+ d->closeSubpath(d->subpaths.last());
}
void KoPathShape::closeMerge()
{
Q_D(KoPathShape);
- if (m_subpaths.empty()) {
+ if (d->subpaths.empty()) {
return;
}
- d->closeMergeSubpath(m_subpaths.last());
+ d->closeMergeSubpath(d->subpaths.last());
}
QPointF KoPathShape::normalize()
@@ -752,8 +793,8 @@
void KoPathShapePrivate::map(const QTransform &matrix)
{
Q_Q(KoPathShape);
- KoSubpathList::const_iterator pathIt(q->m_subpaths.constBegin());
- for (; pathIt != q->m_subpaths.constEnd(); ++pathIt) {
+ KoSubpathList::const_iterator pathIt(subpaths.constBegin());
+ for (; pathIt != subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it) {
(*it)->map(matrix);
@@ -768,15 +809,15 @@
if ((*lastPoint)->properties() & KoPathPoint::StopSubpath
&& (*lastPoint)->properties() & KoPathPoint::CloseSubpath) {
// get the first point of the subpath
- KoPathPoint *subpathStart = q->m_subpaths.last()->first();
+ KoPathPoint *subpathStart = subpaths.last()->first();
// clone the first point of the subpath...
- KoPathPoint * newLastPoint = new KoPathPoint(*subpathStart);
+ KoPathPoint * newLastPoint = new KoPathPoint(*subpathStart, q);
// ... and make it a normal point
newLastPoint->setProperties(KoPathPoint::Normal);
// now start a new subpath with the cloned start point
KoSubpath *path = new KoSubpath;
path->push_back(newLastPoint);
- q->m_subpaths.push_back(path);
+ subpaths.push_back(path);
*lastPoint = newLastPoint;
} else {
// the subpath was not closed so the formerly last point
@@ -788,10 +829,12 @@
QList KoPathShape::pointsAt(const QRectF &r) const
{
+ Q_D(const KoPathShape);
+
QList result;
- KoSubpathList::const_iterator pathIt(m_subpaths.constBegin());
- for (; pathIt != m_subpaths.constEnd(); ++pathIt) {
+ KoSubpathList::const_iterator pathIt(d->subpaths.constBegin());
+ for (; pathIt != d->subpaths.constEnd(); ++pathIt) {
KoSubpath::const_iterator it((*pathIt)->constBegin());
for (; it != (*pathIt)->constEnd(); ++it) {
if (r.contains((*it)->point()))
@@ -807,10 +850,12 @@
QList