Changeset View
Changeset View
Standalone View
Standalone View
libs/flake/KoShapeManager.cpp
Show All 26 Lines | |||||
27 | #include "KoPointerEvent.h" | 27 | #include "KoPointerEvent.h" | ||
28 | #include "KoShape.h" | 28 | #include "KoShape.h" | ||
29 | #include "KoShape_p.h" | 29 | #include "KoShape_p.h" | ||
30 | #include "KoCanvasBase.h" | 30 | #include "KoCanvasBase.h" | ||
31 | #include "KoShapeContainer.h" | 31 | #include "KoShapeContainer.h" | ||
32 | #include "KoShapeStrokeModel.h" | 32 | #include "KoShapeStrokeModel.h" | ||
33 | #include "KoShapeGroup.h" | 33 | #include "KoShapeGroup.h" | ||
34 | #include "KoToolProxy.h" | 34 | #include "KoToolProxy.h" | ||
35 | #include "KoShapeManagerPaintingStrategy.h" | | |||
36 | #include "KoShapeShadow.h" | 35 | #include "KoShapeShadow.h" | ||
37 | #include "KoShapeLayer.h" | 36 | #include "KoShapeLayer.h" | ||
38 | #include "KoFilterEffect.h" | 37 | #include "KoFilterEffect.h" | ||
39 | #include "KoFilterEffectStack.h" | 38 | #include "KoFilterEffectStack.h" | ||
40 | #include "KoFilterEffectRenderContext.h" | 39 | #include "KoFilterEffectRenderContext.h" | ||
41 | #include "KoShapeBackground.h" | 40 | #include "KoShapeBackground.h" | ||
42 | #include <KoRTree.h> | 41 | #include <KoRTree.h> | ||
43 | #include "KoClipPath.h" | 42 | #include "KoClipPath.h" | ||
43 | #include "KoClipMaskPainter.h" | ||||
44 | #include "KoShapePaintingContext.h" | 44 | #include "KoShapePaintingContext.h" | ||
45 | #include "KoViewConverter.h" | 45 | #include "KoViewConverter.h" | ||
46 | #include "KisQPainterStateSaver.h" | ||||
46 | 47 | | |||
47 | #include <QPainter> | 48 | #include <QPainter> | ||
48 | #include <QTimer> | 49 | #include <QTimer> | ||
49 | #include <FlakeDebug.h> | 50 | #include <FlakeDebug.h> | ||
50 | 51 | | |||
51 | #include "kis_painting_tweaks.h" | 52 | #include "kis_painting_tweaks.h" | ||
52 | 53 | | |||
54 | bool KoShapeManager::Private::shapeUsedInRenderingTree(KoShape *shape) | ||||
55 | { | ||||
56 | return !dynamic_cast<KoShapeGroup*>(shape) && !dynamic_cast<KoShapeLayer*>(shape); | ||||
57 | } | ||||
53 | 58 | | |||
54 | void KoShapeManager::Private::updateTree() | 59 | void KoShapeManager::Private::updateTree() | ||
55 | { | 60 | { | ||
56 | // for detecting collisions between shapes. | 61 | // for detecting collisions between shapes. | ||
57 | DetectCollision detector; | 62 | DetectCollision detector; | ||
58 | bool selectionModified = false; | 63 | bool selectionModified = false; | ||
59 | bool anyModified = false; | 64 | bool anyModified = false; | ||
60 | Q_FOREACH (KoShape *shape, aggregate4update) { | 65 | Q_FOREACH (KoShape *shape, aggregate4update) { | ||
61 | if (shapeIndexesBeforeUpdate.contains(shape)) | 66 | if (shapeIndexesBeforeUpdate.contains(shape)) | ||
62 | detector.detect(tree, shape, shapeIndexesBeforeUpdate[shape]); | 67 | detector.detect(tree, shape, shapeIndexesBeforeUpdate[shape]); | ||
63 | selectionModified = selectionModified || selection->isSelected(shape); | 68 | selectionModified = selectionModified || selection->isSelected(shape); | ||
64 | anyModified = true; | 69 | anyModified = true; | ||
65 | } | 70 | } | ||
66 | 71 | | |||
67 | foreach (KoShape *shape, aggregate4update) { | 72 | foreach (KoShape *shape, aggregate4update) { | ||
73 | if (!shapeUsedInRenderingTree(shape)) continue; | ||||
74 | | ||||
68 | tree.remove(shape); | 75 | tree.remove(shape); | ||
69 | QRectF br(shape->boundingRect()); | 76 | QRectF br(shape->boundingRect()); | ||
70 | strategy->adapt(shape, br); | | |||
71 | tree.insert(br, shape); | 77 | tree.insert(br, shape); | ||
72 | } | 78 | } | ||
73 | 79 | | |||
74 | // do it again to see which shapes we intersect with _after_ moving. | 80 | // do it again to see which shapes we intersect with _after_ moving. | ||
75 | foreach (KoShape *shape, aggregate4update) | 81 | foreach (KoShape *shape, aggregate4update) { | ||
76 | detector.detect(tree, shape, shapeIndexesBeforeUpdate[shape]); | 82 | detector.detect(tree, shape, shapeIndexesBeforeUpdate[shape]); | ||
83 | } | ||||
77 | aggregate4update.clear(); | 84 | aggregate4update.clear(); | ||
78 | shapeIndexesBeforeUpdate.clear(); | 85 | shapeIndexesBeforeUpdate.clear(); | ||
79 | 86 | | |||
80 | detector.fireSignals(); | 87 | detector.fireSignals(); | ||
81 | if (selectionModified) { | 88 | if (selectionModified) { | ||
82 | selection->updateSizeAndPosition(); | | |||
83 | emit q->selectionContentChanged(); | 89 | emit q->selectionContentChanged(); | ||
84 | } | 90 | } | ||
85 | if (anyModified) { | 91 | if (anyModified) { | ||
86 | emit q->contentChanged(); | 92 | emit q->contentChanged(); | ||
87 | } | 93 | } | ||
88 | } | 94 | } | ||
89 | 95 | | |||
90 | void KoShapeManager::Private::paintGroup(KoShapeGroup *group, QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) | 96 | void KoShapeManager::Private::paintGroup(KoShapeGroup *group, QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) | ||
91 | { | 97 | { | ||
92 | QList<KoShape*> shapes = group->shapes(); | 98 | QList<KoShape*> shapes = group->shapes(); | ||
93 | qSort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex); | 99 | qSort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex); | ||
94 | Q_FOREACH (KoShape *child, shapes) { | 100 | Q_FOREACH (KoShape *child, shapes) { | ||
95 | // we paint recursively here, so we do not have to check recursively for visibility | 101 | // we paint recursively here, so we do not have to check recursively for visibility | ||
96 | if (!child->isVisible()) | 102 | if (!child->isVisible()) | ||
97 | continue; | 103 | continue; | ||
98 | KoShapeGroup *childGroup = dynamic_cast<KoShapeGroup*>(child); | 104 | KoShapeGroup *childGroup = dynamic_cast<KoShapeGroup*>(child); | ||
99 | if (childGroup) { | 105 | if (childGroup) { | ||
100 | paintGroup(childGroup, painter, converter, paintContext); | 106 | paintGroup(childGroup, painter, converter, paintContext); | ||
101 | } else { | 107 | } else { | ||
102 | painter.save(); | 108 | painter.save(); | ||
103 | strategy->paint(child, painter, converter, paintContext); | 109 | KoShapeManager::renderSingleShape(child, painter, converter, paintContext); | ||
104 | painter.restore(); | 110 | painter.restore(); | ||
105 | } | 111 | } | ||
106 | } | 112 | } | ||
107 | } | 113 | } | ||
108 | 114 | | |||
109 | KoShapeManager::KoShapeManager(KoCanvasBase *canvas, const QList<KoShape *> &shapes) | 115 | KoShapeManager::KoShapeManager(KoCanvasBase *canvas, const QList<KoShape *> &shapes) | ||
110 | : d(new Private(this, canvas)) | 116 | : d(new Private(this, canvas)) | ||
111 | { | 117 | { | ||
Show All 15 Lines | 132 | Q_FOREACH (KoShape *shape, d->shapes) { | |||
127 | shape->priv()->removeShapeManager(this); | 133 | shape->priv()->removeShapeManager(this); | ||
128 | } | 134 | } | ||
129 | Q_FOREACH (KoShape *shape, d->additionalShapes) { | 135 | Q_FOREACH (KoShape *shape, d->additionalShapes) { | ||
130 | shape->priv()->removeShapeManager(this); | 136 | shape->priv()->removeShapeManager(this); | ||
131 | } | 137 | } | ||
132 | delete d; | 138 | delete d; | ||
133 | } | 139 | } | ||
134 | 140 | | |||
135 | | ||||
136 | void KoShapeManager::setShapes(const QList<KoShape *> &shapes, Repaint repaint) | 141 | void KoShapeManager::setShapes(const QList<KoShape *> &shapes, Repaint repaint) | ||
137 | { | 142 | { | ||
138 | //clear selection | 143 | //clear selection | ||
139 | d->selection->deselectAll(); | 144 | d->selection->deselectAll(); | ||
140 | Q_FOREACH (KoShape *shape, d->shapes) { | 145 | Q_FOREACH (KoShape *shape, d->shapes) { | ||
141 | shape->priv()->removeShapeManager(this); | 146 | shape->priv()->removeShapeManager(this); | ||
142 | } | 147 | } | ||
143 | d->aggregate4update.clear(); | 148 | d->aggregate4update.clear(); | ||
144 | d->tree.clear(); | 149 | d->tree.clear(); | ||
145 | d->shapes.clear(); | 150 | d->shapes.clear(); | ||
151 | | ||||
146 | Q_FOREACH (KoShape *shape, shapes) { | 152 | Q_FOREACH (KoShape *shape, shapes) { | ||
147 | addShape(shape, repaint); | 153 | addShape(shape, repaint); | ||
148 | } | 154 | } | ||
149 | } | 155 | } | ||
150 | 156 | | |||
151 | void KoShapeManager::addShape(KoShape *shape, Repaint repaint) | 157 | void KoShapeManager::addShape(KoShape *shape, Repaint repaint) | ||
152 | { | 158 | { | ||
153 | if (d->shapes.contains(shape)) | 159 | if (d->shapes.contains(shape)) | ||
154 | return; | 160 | return; | ||
155 | shape->priv()->addShapeManager(this); | 161 | shape->priv()->addShapeManager(this); | ||
156 | d->shapes.append(shape); | 162 | d->shapes.append(shape); | ||
157 | if (! dynamic_cast<KoShapeGroup*>(shape) && ! dynamic_cast<KoShapeLayer*>(shape)) { | 163 | | ||
164 | if (d->shapeUsedInRenderingTree(shape)) { | ||||
158 | QRectF br(shape->boundingRect()); | 165 | QRectF br(shape->boundingRect()); | ||
159 | d->tree.insert(br, shape); | 166 | d->tree.insert(br, shape); | ||
160 | } | 167 | } | ||
168 | | ||||
161 | if (repaint == PaintShapeOnAdd) { | 169 | if (repaint == PaintShapeOnAdd) { | ||
162 | shape->update(); | 170 | shape->update(); | ||
163 | } | 171 | } | ||
164 | 172 | | |||
165 | // add the children of a KoShapeContainer | 173 | // add the children of a KoShapeContainer | ||
166 | KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape); | 174 | KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape); | ||
167 | 175 | | |||
168 | if (container) { | 176 | if (container) { | ||
169 | foreach (KoShape *containerShape, container->shapes()) { | 177 | foreach (KoShape *containerShape, container->shapes()) { | ||
170 | addShape(containerShape, repaint); | 178 | addShape(containerShape, repaint); | ||
171 | } | 179 | } | ||
172 | } | 180 | } | ||
173 | 181 | | |||
174 | Private::DetectCollision detector; | 182 | Private::DetectCollision detector; | ||
175 | detector.detect(d->tree, shape, shape->zIndex()); | 183 | detector.detect(d->tree, shape, shape->zIndex()); | ||
176 | detector.fireSignals(); | 184 | detector.fireSignals(); | ||
177 | } | 185 | } | ||
178 | 186 | | |||
179 | void KoShapeManager::addAdditional(KoShape *shape) | | |||
180 | { | | |||
181 | if (shape) { | | |||
182 | if (d->additionalShapes.contains(shape)) { | | |||
183 | return; | | |||
184 | } | | |||
185 | shape->priv()->addShapeManager(this); | | |||
186 | d->additionalShapes.append(shape); | | |||
187 | } | | |||
188 | } | | |||
189 | | ||||
190 | void KoShapeManager::remove(KoShape *shape) | 187 | void KoShapeManager::remove(KoShape *shape) | ||
191 | { | 188 | { | ||
192 | Private::DetectCollision detector; | 189 | Private::DetectCollision detector; | ||
193 | detector.detect(d->tree, shape, shape->zIndex()); | 190 | detector.detect(d->tree, shape, shape->zIndex()); | ||
194 | detector.fireSignals(); | 191 | detector.fireSignals(); | ||
195 | 192 | | |||
196 | shape->update(); | 193 | shape->update(); | ||
197 | shape->priv()->removeShapeManager(this); | 194 | shape->priv()->removeShapeManager(this); | ||
198 | d->selection->deselect(shape); | 195 | d->selection->deselect(shape); | ||
199 | d->aggregate4update.remove(shape); | 196 | d->aggregate4update.remove(shape); | ||
197 | | ||||
198 | if (d->shapeUsedInRenderingTree(shape)) { | ||||
200 | d->tree.remove(shape); | 199 | d->tree.remove(shape); | ||
200 | } | ||||
201 | d->shapes.removeAll(shape); | 201 | d->shapes.removeAll(shape); | ||
202 | 202 | | |||
203 | // remove the children of a KoShapeContainer | 203 | // remove the children of a KoShapeContainer | ||
204 | KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape); | 204 | KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape); | ||
205 | if (container) { | 205 | if (container) { | ||
206 | foreach (KoShape *containerShape, container->shapes()) { | 206 | foreach (KoShape *containerShape, container->shapes()) { | ||
207 | remove(containerShape); | 207 | remove(containerShape); | ||
208 | } | 208 | } | ||
209 | } | 209 | } | ||
210 | } | ||||
210 | 211 | | |||
211 | // This signal is used in the annotation shape. | 212 | KoShapeManager::ShapeInterface::ShapeInterface(KoShapeManager *_q) | ||
212 | // FIXME: Is this really what we want? (and shouldn't it be called shapeDeleted()?) | 213 | : q(_q) | ||
213 | shapeRemoved(shape); | 214 | { | ||
214 | } | 215 | } | ||
215 | 216 | | |||
216 | void KoShapeManager::removeAdditional(KoShape *shape) | 217 | void KoShapeManager::ShapeInterface::notifyShapeDestructed(KoShape *shape) | ||
217 | { | 218 | { | ||
218 | if (shape) { | 219 | q->d->selection->deselect(shape); | ||
219 | shape->priv()->removeShapeManager(this); | 220 | q->d->aggregate4update.remove(shape); | ||
220 | d->additionalShapes.removeAll(shape); | 221 | | ||
222 | // we cannot access RTTI of the semi-destructed shape, so just | ||||
223 | // unlink it lazily | ||||
224 | if (q->d->tree.contains(shape)) { | ||||
225 | q->d->tree.remove(shape); | ||||
221 | } | 226 | } | ||
227 | | ||||
228 | q->d->shapes.removeAll(shape); | ||||
229 | } | ||||
230 | | ||||
231 | | ||||
232 | KoShapeManager::ShapeInterface *KoShapeManager::shapeInterface() | ||||
233 | { | ||||
234 | return &d->shapeInterface; | ||||
222 | } | 235 | } | ||
223 | 236 | | |||
237 | | ||||
224 | void KoShapeManager::paint(QPainter &painter, const KoViewConverter &converter, bool forPrint) | 238 | void KoShapeManager::paint(QPainter &painter, const KoViewConverter &converter, bool forPrint) | ||
225 | { | 239 | { | ||
226 | d->updateTree(); | 240 | d->updateTree(); | ||
227 | painter.setPen(Qt::NoPen); // painters by default have a black stroke, lets turn that off. | 241 | painter.setPen(Qt::NoPen); // painters by default have a black stroke, lets turn that off. | ||
228 | painter.setBrush(Qt::NoBrush); | 242 | painter.setBrush(Qt::NoBrush); | ||
229 | 243 | | |||
230 | QList<KoShape*> unsortedShapes; | 244 | QList<KoShape*> unsortedShapes; | ||
231 | if (painter.hasClipping()) { | 245 | if (painter.hasClipping()) { | ||
Show All 27 Lines | 272 | if (addShapeToList) { | |||
259 | sortedShapes.append(shape); | 273 | sortedShapes.append(shape); | ||
260 | } else if (parent) { | 274 | } else if (parent) { | ||
261 | sortedShapes.append(parent); | 275 | sortedShapes.append(parent); | ||
262 | } | 276 | } | ||
263 | } | 277 | } | ||
264 | 278 | | |||
265 | qSort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex); | 279 | qSort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex); | ||
266 | 280 | | |||
267 | foreach (KoShape *shape, sortedShapes) { | | |||
268 | if (shape->parent() != 0 && shape->parent()->isClipped(shape)) | | |||
269 | continue; | | |||
270 | | ||||
271 | painter.save(); | | |||
272 | | ||||
273 | // apply shape clipping | | |||
274 | KoClipPath::applyClipping(shape, painter, converter); | | |||
275 | | ||||
276 | // let the painting strategy paint the shape | | |||
277 | KoShapePaintingContext paintContext(d->canvas, forPrint); //FIXME | 281 | KoShapePaintingContext paintContext(d->canvas, forPrint); //FIXME | ||
278 | d->strategy->paint(shape, painter, converter, paintContext); | | |||
279 | 282 | | |||
280 | painter.restore(); | 283 | foreach (KoShape *shape, sortedShapes) { | ||
284 | renderSingleShape(shape, painter, converter, paintContext); | ||||
281 | } | 285 | } | ||
282 | 286 | | |||
283 | #ifdef CALLIGRA_RTREE_DEBUG | 287 | #ifdef CALLIGRA_RTREE_DEBUG | ||
284 | // paint tree | 288 | // paint tree | ||
285 | qreal zx = 0; | 289 | qreal zx = 0; | ||
286 | qreal zy = 0; | 290 | qreal zy = 0; | ||
287 | converter.zoom(&zx, &zy); | 291 | converter.zoom(&zx, &zy); | ||
288 | painter.save(); | 292 | painter.save(); | ||
289 | painter.scale(zx, zy); | 293 | painter.scale(zx, zy); | ||
290 | d->tree.paint(painter); | 294 | d->tree.paint(painter); | ||
291 | painter.restore(); | 295 | painter.restore(); | ||
292 | #endif | 296 | #endif | ||
293 | 297 | | |||
294 | if (! forPrint) { | 298 | if (! forPrint) { | ||
295 | KoShapePaintingContext paintContext(d->canvas, forPrint); //FIXME | 299 | KoShapePaintingContext paintContext(d->canvas, forPrint); //FIXME | ||
296 | d->selection->paint(painter, converter, paintContext); | 300 | d->selection->paint(painter, converter, paintContext); | ||
297 | } | 301 | } | ||
298 | } | 302 | } | ||
299 | 303 | | |||
304 | void KoShapeManager::renderSingleShape(KoShape *shape, QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) | ||||
305 | { | ||||
306 | KisQPainterStateSaver saver(&painter); | ||||
307 | | ||||
308 | // apply shape clipping | ||||
309 | KoClipPath::applyClipping(shape, painter, converter); | ||||
310 | | ||||
311 | // apply transformation | ||||
312 | painter.setTransform(shape->absoluteTransformation(&converter) * painter.transform()); | ||||
313 | | ||||
314 | // paint the shape | ||||
315 | paintShape(shape, painter, converter, paintContext); | ||||
316 | } | ||||
317 | | ||||
300 | void KoShapeManager::paintShape(KoShape *shape, QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) | 318 | void KoShapeManager::paintShape(KoShape *shape, QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) | ||
301 | { | 319 | { | ||
302 | qreal transparency = shape->transparency(true); | 320 | qreal transparency = shape->transparency(true); | ||
303 | if (transparency > 0.0) { | 321 | if (transparency > 0.0) { | ||
304 | painter.setOpacity(1.0-transparency); | 322 | painter.setOpacity(1.0-transparency); | ||
305 | } | 323 | } | ||
306 | 324 | | |||
307 | if (shape->shadow()) { | 325 | if (shape->shadow()) { | ||
308 | painter.save(); | 326 | painter.save(); | ||
309 | shape->shadow()->paint(shape, painter, converter); | 327 | shape->shadow()->paint(shape, painter, converter); | ||
310 | painter.restore(); | 328 | painter.restore(); | ||
311 | } | 329 | } | ||
312 | if (!shape->filterEffectStack() || shape->filterEffectStack()->isEmpty()) { | 330 | if (!shape->filterEffectStack() || shape->filterEffectStack()->isEmpty()) { | ||
313 | painter.save(); | 331 | | ||
314 | shape->paint(painter, converter, paintContext); | 332 | QScopedPointer<KoClipMaskPainter> clipMaskPainter; | ||
315 | painter.restore(); | 333 | QPainter *shapePainter = &painter; | ||
334 | | ||||
335 | KoClipMask *clipMask = shape->clipMask(); | ||||
336 | if (clipMask) { | ||||
337 | clipMaskPainter.reset(new KoClipMaskPainter(&painter, shape->boundingRect())); | ||||
338 | shapePainter = clipMaskPainter->shapePainter(); | ||||
339 | } | ||||
340 | | ||||
341 | shapePainter->save(); | ||||
342 | shape->paint(*shapePainter, converter, paintContext); | ||||
343 | shapePainter->restore(); | ||||
316 | if (shape->stroke()) { | 344 | if (shape->stroke()) { | ||
317 | painter.save(); | 345 | shapePainter->save(); | ||
318 | shape->stroke()->paint(shape, painter, converter); | 346 | shape->stroke()->paint(shape, *shapePainter, converter); | ||
319 | painter.restore(); | 347 | shapePainter->restore(); | ||
348 | } | ||||
349 | | ||||
350 | if (clipMask) { | ||||
351 | shape->clipMask()->drawMask(clipMaskPainter->maskPainter(), shape); | ||||
352 | clipMaskPainter->renderOnGlobalPainter(); | ||||
320 | } | 353 | } | ||
354 | | ||||
321 | } else { | 355 | } else { | ||
356 | // TODO: clipping mask is not implemented for this case! | ||||
357 | | ||||
322 | // There are filter effects, then we need to prerender the shape on an image, to filter it | 358 | // There are filter effects, then we need to prerender the shape on an image, to filter it | ||
323 | QRectF shapeBound(QPointF(), shape->size()); | 359 | QRectF shapeBound(QPointF(), shape->size()); | ||
324 | // First step, compute the rectangle used for the image | 360 | // First step, compute the rectangle used for the image | ||
325 | QRectF clipRegion = shape->filterEffectStack()->clipRectForBoundingRect(shapeBound); | 361 | QRectF clipRegion = shape->filterEffectStack()->clipRectForBoundingRect(shapeBound); | ||
326 | // convert clip region to view coordinates | 362 | // convert clip region to view coordinates | ||
327 | QRectF zoomedClipRegion = converter.documentToView(clipRegion); | 363 | QRectF zoomedClipRegion = converter.documentToView(clipRegion); | ||
328 | // determine the offset of the clipping rect from the shapes origin | 364 | // determine the offset of the clipping rect from the shapes origin | ||
329 | QPointF clippingOffset = zoomedClipRegion.topLeft(); | 365 | QPointF clippingOffset = zoomedClipRegion.topLeft(); | ||
Show All 15 Lines | 375 | if (requiredStdInputs.contains("SourceGraphic") || requiredStdInputs.contains("SourceAlpha")) { | |||
345 | imagePainter.setRenderHint(QPainter::Antialiasing, painter.testRenderHint(QPainter::Antialiasing)); | 381 | imagePainter.setRenderHint(QPainter::Antialiasing, painter.testRenderHint(QPainter::Antialiasing)); | ||
346 | 382 | | |||
347 | // Paint the shape on the image | 383 | // Paint the shape on the image | ||
348 | KoShapeGroup *group = dynamic_cast<KoShapeGroup*>(shape); | 384 | KoShapeGroup *group = dynamic_cast<KoShapeGroup*>(shape); | ||
349 | if (group) { | 385 | if (group) { | ||
350 | // the childrens matrix contains the groups matrix as well | 386 | // the childrens matrix contains the groups matrix as well | ||
351 | // so we have to compensate for that before painting the children | 387 | // so we have to compensate for that before painting the children | ||
352 | imagePainter.setTransform(group->absoluteTransformation(&converter).inverted(), true); | 388 | imagePainter.setTransform(group->absoluteTransformation(&converter).inverted(), true); | ||
353 | d->paintGroup(group, imagePainter, converter, paintContext); | 389 | Private::paintGroup(group, imagePainter, converter, paintContext); | ||
354 | } else { | 390 | } else { | ||
355 | imagePainter.save(); | 391 | imagePainter.save(); | ||
356 | shape->paint(imagePainter, converter, paintContext); | 392 | shape->paint(imagePainter, converter, paintContext); | ||
357 | imagePainter.restore(); | 393 | imagePainter.restore(); | ||
358 | if (shape->stroke()) { | 394 | if (shape->stroke()) { | ||
359 | imagePainter.save(); | 395 | imagePainter.save(); | ||
360 | shape->stroke()->paint(shape, imagePainter, converter); | 396 | shape->stroke()->paint(shape, imagePainter, converter); | ||
361 | imagePainter.restore(); | 397 | imagePainter.restore(); | ||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Line(s) | 509 | if (selection == KoFlake::NextUnselected && firstUnselectedShape) | |||
474 | return firstUnselectedShape; | 510 | return firstUnselectedShape; | ||
475 | 511 | | |||
476 | if (d->selection->hitTest(position)) | 512 | if (d->selection->hitTest(position)) | ||
477 | return d->selection; | 513 | return d->selection; | ||
478 | 514 | | |||
479 | return 0; // missed everything | 515 | return 0; // missed everything | ||
480 | } | 516 | } | ||
481 | 517 | | |||
482 | QList<KoShape *> KoShapeManager::shapesAt(const QRectF &rect, bool omitHiddenShapes) | 518 | QList<KoShape *> KoShapeManager::shapesAt(const QRectF &rect, bool omitHiddenShapes, bool containedMode) | ||
483 | { | 519 | { | ||
484 | d->updateTree(); | 520 | d->updateTree(); | ||
485 | QList<KoShape*> intersectedShapes(d->tree.intersects(rect)); | 521 | QList<KoShape*> shapes(containedMode ? d->tree.contained(rect) : d->tree.intersects(rect)); | ||
486 | 522 | | |||
487 | for (int count = intersectedShapes.count() - 1; count >= 0; count--) { | 523 | for (int count = shapes.count() - 1; count >= 0; count--) { | ||
488 | 524 | | |||
489 | KoShape *shape = intersectedShapes.at(count); | 525 | KoShape *shape = shapes.at(count); | ||
490 | 526 | | |||
491 | if (omitHiddenShapes && ! shape->isVisible(true)) { | 527 | if (omitHiddenShapes && !shape->isVisible(true)) { | ||
492 | intersectedShapes.removeAt(count); | 528 | shapes.removeAt(count); | ||
493 | } else { | 529 | } else { | ||
494 | const QPainterPath outline = shape->absoluteTransformation(0).map(shape->outline()); | 530 | const QPainterPath outline = shape->absoluteTransformation(0).map(shape->outline()); | ||
495 | if (! outline.intersects(rect) && ! outline.contains(rect)) { | 531 | | ||
496 | intersectedShapes.removeAt(count); | 532 | if (!containedMode && !outline.intersects(rect) && !outline.contains(rect)) { | ||
533 | shapes.removeAt(count); | ||||
534 | | ||||
535 | } else if (containedMode) { | ||||
536 | | ||||
537 | QPainterPath containingPath; | ||||
538 | containingPath.addRect(rect); | ||||
539 | | ||||
540 | if (!containingPath.contains(outline)) { | ||||
541 | shapes.removeAt(count); | ||||
542 | } | ||||
497 | } | 543 | } | ||
498 | } | 544 | } | ||
499 | } | 545 | } | ||
500 | return intersectedShapes; | 546 | | ||
547 | return shapes; | ||||
501 | } | 548 | } | ||
502 | 549 | | |||
503 | void KoShapeManager::update(QRectF &rect, const KoShape *shape, bool selectionHandles) | 550 | void KoShapeManager::update(QRectF &rect, const KoShape *shape, bool selectionHandles) | ||
504 | { | 551 | { | ||
505 | d->canvas->updateCanvas(rect); | 552 | d->canvas->updateCanvas(rect); | ||
506 | if (selectionHandles && d->selection->isSelected(shape)) { | 553 | if (selectionHandles && d->selection->isSelected(shape)) { | ||
507 | if (d->canvas->toolProxy()) | 554 | if (d->canvas->toolProxy()) | ||
508 | d->canvas->toolProxy()->repaintDecorations(); | 555 | d->canvas->toolProxy()->repaintDecorations(); | ||
Show All 37 Lines | 585 | { | |||
546 | return shapes; | 593 | return shapes; | ||
547 | } | 594 | } | ||
548 | 595 | | |||
549 | KoSelection *KoShapeManager::selection() const | 596 | KoSelection *KoShapeManager::selection() const | ||
550 | { | 597 | { | ||
551 | return d->selection; | 598 | return d->selection; | ||
552 | } | 599 | } | ||
553 | 600 | | |||
554 | void KoShapeManager::suggestChangeTool(KoPointerEvent *event) | | |||
555 | { | | |||
556 | QList<KoShape*> shapes; | | |||
557 | | ||||
558 | KoShape *clicked = shapeAt(event->point); | | |||
559 | if (clicked) { | | |||
560 | if (! selection()->isSelected(clicked)) { | | |||
561 | selection()->deselectAll(); | | |||
562 | selection()->select(clicked); | | |||
563 | } | | |||
564 | shapes.append(clicked); | | |||
565 | } | | |||
566 | | ||||
567 | QList<KoShape*> shapes2; | | |||
568 | foreach (KoShape *shape, shapes) { | | |||
569 | QSet<KoShape*> delegates = shape->toolDelegates(); | | |||
570 | if (delegates.isEmpty()) { | | |||
571 | shapes2.append(shape); | | |||
572 | } else { | | |||
573 | foreach (KoShape *delegatedShape, delegates) { | | |||
574 | shapes2.append(delegatedShape); | | |||
575 | } | | |||
576 | } | | |||
577 | } | | |||
578 | KoToolManager::instance()->switchToolRequested( | | |||
579 | KoToolManager::instance()->preferredToolForSelection(shapes2)); | | |||
580 | } | | |||
581 | | ||||
582 | void KoShapeManager::setPaintingStrategy(KoShapeManagerPaintingStrategy *strategy) | | |||
583 | { | | |||
584 | delete d->strategy; | | |||
585 | d->strategy = strategy; | | |||
586 | } | | |||
587 | | ||||
588 | KoCanvasBase *KoShapeManager::canvas() | 601 | KoCanvasBase *KoShapeManager::canvas() | ||
589 | { | 602 | { | ||
590 | return d->canvas; | 603 | return d->canvas; | ||
591 | } | 604 | } | ||
592 | 605 | | |||
593 | //have to include this because of Q_PRIVATE_SLOT | 606 | //have to include this because of Q_PRIVATE_SLOT | ||
594 | #include "moc_KoShapeManager.cpp" | 607 | #include "moc_KoShapeManager.cpp" |