From 934996f618d738d6327ec8b0b494fe694af3ee3e Mon Sep 17 00:00:00 2001 From: Thomas Zander Date: Wed, 3 Jan 2007 19:42:18 +0000 Subject: [PATCH] Add a new feature to Shapes. The KoShape::shapeChanged virtual hook has always been called when one of the properties of a shape changed; I expanded that by making it also get called when another shape is changed in the bounding rect of the shape to allow a shape to update itself if thats needed. Note that I added a collisionDetection() boolean so there is little impact on performance for those that don't want it. This effectively finishes the runAround of KWord to make sure layouting is changed when a shape is moved above it. svn path=/trunk/koffice/; revision=619584 --- libs/flake/KoPathShape.cpp | 2 +- libs/flake/KoShape.cpp | 7 +++--- libs/flake/KoShape.h | 10 ++++++--- libs/flake/KoShapeContainer.cpp | 3 ++- libs/flake/KoShapeManager.cpp | 38 ++++++++++++++++++++++++++++++--- libs/flake/KoShapeManager.h | 6 +++--- libs/kotext/KoTextShape.cpp | 3 ++- 7 files changed, 54 insertions(+), 15 deletions(-) diff --git a/libs/flake/KoPathShape.cpp b/libs/flake/KoPathShape.cpp index 9451e7eb8d..88855f997d 100644 --- a/libs/flake/KoPathShape.cpp +++ b/libs/flake/KoPathShape.cpp @@ -688,7 +688,7 @@ void KoPathShape::closeMerge() void KoPathShape::update() { - updateTree(); + notifyChanged(); } QPointF KoPathShape::normalize() diff --git a/libs/flake/KoShape.cpp b/libs/flake/KoShape.cpp index d637beb049..ca45972ec3 100644 --- a/libs/flake/KoShape.cpp +++ b/libs/flake/KoShape.cpp @@ -50,6 +50,7 @@ KoShape::KoShape() , m_locked( false ) , m_keepAspect( false ) , m_selectable( true ) +, m_detectCollision( false ) , m_userData(0) , m_appData(0) { @@ -165,7 +166,7 @@ void KoShape::recalcMatrix() { m_matrix = transformationMatrix(0); m_invMatrix = m_matrix.inverted(); - updateTree(); + notifyChanged(); } QMatrix KoShape::transformationMatrix(const KoViewConverter *converter) const { @@ -327,11 +328,11 @@ void KoShape::moveBy(double distanceX, double distanceY) { setAbsolutePosition(QPointF(p.x() + distanceX, p.y() + distanceY)); } -void KoShape::updateTree() +void KoShape::notifyChanged() { foreach( KoShapeManager * manager, m_shapeManagers ) { - manager->updateTree( this ); + manager->notifyShapeChanged( this ); } } diff --git a/libs/flake/KoShape.h b/libs/flake/KoShape.h index 9c68992e28..fe25532fe1 100644 --- a/libs/flake/KoShape.h +++ b/libs/flake/KoShape.h @@ -523,7 +523,7 @@ protected: /** * Update the position of the shape in the tree of the KoShapeManager. */ - void updateTree(); + void notifyChanged(); /// Used by shapeChanged() to select which change was made enum ChangeType { @@ -532,7 +532,8 @@ protected: ScaleChanged, ///< used after a scale() ShearChanged, ///< used after a shear() SizeChanged, ///< used after a resize() - ParentChanged ///< used after a setParent() + ParentChanged, ///< used after a setParent() + CollisionDetected ///< used when another shape moved in our boundingrect }; /** @@ -542,6 +543,9 @@ protected: */ virtual void shapeChanged(ChangeType type) { Q_UNUSED(type); } + void setCollisionDetection(bool detect) { m_detectCollision = detect; } + bool collisionDetection() { return m_detectCollision; } + private: double m_scaleX; double m_scaleY; @@ -560,7 +564,7 @@ private: int m_zIndex; KoShapeContainer *m_parent; - bool m_visible, m_locked, m_keepAspect, m_selectable; + bool m_visible, m_locked, m_keepAspect, m_selectable, m_detectCollision; QSet m_shapeManagers; diff --git a/libs/flake/KoShapeContainer.cpp b/libs/flake/KoShapeContainer.cpp index e1f38e9c09..984681b0bf 100644 --- a/libs/flake/KoShapeContainer.cpp +++ b/libs/flake/KoShapeContainer.cpp @@ -115,9 +115,10 @@ void KoShapeContainer::paint(QPainter &painter, const KoViewConverter &converter } void KoShapeContainer::shapeChanged(ChangeType type) { - Q_UNUSED(type); if(m_children == 0) return; + if(! (type == RotationChanged || type == ScaleChanged || type == ShearChanged || type == SizeChanged)) + return; m_children->containerChanged(this); foreach (KoShape *shape, m_children->iterator()) shape->recalcMatrix(); diff --git a/libs/flake/KoShapeManager.cpp b/libs/flake/KoShapeManager.cpp index 25d5cc8c76..21c4242eb5 100644 --- a/libs/flake/KoShapeManager.cpp +++ b/libs/flake/KoShapeManager.cpp @@ -231,8 +231,8 @@ KoShape * KoShapeManager::shapeAt( const QPointF &position, KoFlake::ShapeSelect QList KoShapeManager::shapesAt( const QRectF &rect, bool omitHiddenShapes ) { updateTree(); - //TODO check if object is really in the rect and not - // only the bounding rect of the object. + //TODO check if object (outline) is really in the rect and we are not just + // adding objects by their bounding rect if( omitHiddenShapes ) { QList intersectedShapes( m_tree.intersects( rect ) ); for(int count = intersectedShapes.count()-1; count >= 0; count--) { @@ -256,20 +256,52 @@ void KoShapeManager::repaint( QRectF &rect, const KoShape *shape, bool selection } } -void KoShapeManager::updateTree( KoShape * shape ) +void KoShapeManager::notifyShapeChanged( KoShape * shape ) { m_aggregate4update.insert( shape ); } void KoShapeManager::updateTree() { + // for detecting collisions between shapes. + class DetectCollision { + public: + DetectCollision() {} + void detect(KoRTree &m_tree, KoShape *s) { + foreach(KoShape *shape, m_tree.intersects( s->boundingRect() )) { + if(s->zIndex() <= shape->zIndex()) + // Moving a shape will only make it collide with shapes below it. + continue; + if(shape->collisionDetection() && !shapesWithCollisionDetection.contains(shape)) + shapesWithCollisionDetection.append(shape); + } + } + + void fireSignals() { + foreach(KoShape *shape, shapesWithCollisionDetection) + shape->shapeChanged(KoShape::CollisionDetected); + } + + private: + QList shapesWithCollisionDetection; + }; + DetectCollision detector; + foreach ( KoShape *shape, m_aggregate4update ) + detector.detect(m_tree, shape); + foreach ( KoShape * shape, m_aggregate4update ) { m_tree.remove( shape ); QRectF br( shape->boundingRect() ); m_tree.insert( br, shape ); } + + // do it again to see which shapes we intersect with _after_ moving. + foreach ( KoShape *shape, m_aggregate4update ) + detector.detect(m_tree, shape); m_aggregate4update.clear(); + + detector.fireSignals(); } #include "KoShapeManager.moc" diff --git a/libs/flake/KoShapeManager.h b/libs/flake/KoShapeManager.h index 297ff32665..bc2a0806c6 100644 --- a/libs/flake/KoShapeManager.h +++ b/libs/flake/KoShapeManager.h @@ -128,13 +128,13 @@ public: /** * Update the tree for finding the shapes. * This will remove the shape from the tree and will reinsert it again. - * The update to the tree will be posponed until it is needed so that successive calles + * The update to the tree will be posponed until it is needed so that successive calls * will be merged into one. * @param shape the shape to updated its position in the tree. */ - void updateTree( KoShape * shape ); + void notifyShapeChanged( KoShape * shape ); -protected: +private: /** * Update the tree when there are shapes in m_aggregate4update. This is done so not all * updates to the tree are done when they are asked for but when they are needed. diff --git a/libs/kotext/KoTextShape.cpp b/libs/kotext/KoTextShape.cpp index 91ca8d001d..ab6338bf81 100644 --- a/libs/kotext/KoTextShape.cpp +++ b/libs/kotext/KoTextShape.cpp @@ -42,6 +42,7 @@ KoTextShape::KoTextShape() m_textShapeData->document()->setDocumentLayout(lay); lay->setInlineObjectTextManager(new KoInlineTextObjectManager(lay)); + setCollisionDetection(true); } KoTextShape::~KoTextShape() { @@ -67,7 +68,7 @@ QPointF KoTextShape::convertScreenPos(const QPointF &point) { } void KoTextShape::shapeChanged(ChangeType type) { - if(type == PositionChanged || type == SizeChanged) { + if(type == PositionChanged || type == SizeChanged || type == CollisionDetected) { m_textShapeData->faul(); m_textShapeData->fireResizeEvent(); } -- GitLab