Commit 934996f6 authored by Thomas Zander's avatar Thomas Zander

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
parent 081f1b9f
...@@ -688,7 +688,7 @@ void KoPathShape::closeMerge() ...@@ -688,7 +688,7 @@ void KoPathShape::closeMerge()
void KoPathShape::update() void KoPathShape::update()
{ {
updateTree(); notifyChanged();
} }
QPointF KoPathShape::normalize() QPointF KoPathShape::normalize()
......
...@@ -50,6 +50,7 @@ KoShape::KoShape() ...@@ -50,6 +50,7 @@ KoShape::KoShape()
, m_locked( false ) , m_locked( false )
, m_keepAspect( false ) , m_keepAspect( false )
, m_selectable( true ) , m_selectable( true )
, m_detectCollision( false )
, m_userData(0) , m_userData(0)
, m_appData(0) , m_appData(0)
{ {
...@@ -165,7 +166,7 @@ void KoShape::recalcMatrix() ...@@ -165,7 +166,7 @@ void KoShape::recalcMatrix()
{ {
m_matrix = transformationMatrix(0); m_matrix = transformationMatrix(0);
m_invMatrix = m_matrix.inverted(); m_invMatrix = m_matrix.inverted();
updateTree(); notifyChanged();
} }
QMatrix KoShape::transformationMatrix(const KoViewConverter *converter) const { QMatrix KoShape::transformationMatrix(const KoViewConverter *converter) const {
...@@ -327,11 +328,11 @@ void KoShape::moveBy(double distanceX, double distanceY) { ...@@ -327,11 +328,11 @@ void KoShape::moveBy(double distanceX, double distanceY) {
setAbsolutePosition(QPointF(p.x() + distanceX, p.y() + distanceY)); setAbsolutePosition(QPointF(p.x() + distanceX, p.y() + distanceY));
} }
void KoShape::updateTree() void KoShape::notifyChanged()
{ {
foreach( KoShapeManager * manager, m_shapeManagers ) foreach( KoShapeManager * manager, m_shapeManagers )
{ {
manager->updateTree( this ); manager->notifyShapeChanged( this );
} }
} }
......
...@@ -523,7 +523,7 @@ protected: ...@@ -523,7 +523,7 @@ protected:
/** /**
* Update the position of the shape in the tree of the KoShapeManager. * 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 /// Used by shapeChanged() to select which change was made
enum ChangeType { enum ChangeType {
...@@ -532,7 +532,8 @@ protected: ...@@ -532,7 +532,8 @@ protected:
ScaleChanged, ///< used after a scale() ScaleChanged, ///< used after a scale()
ShearChanged, ///< used after a shear() ShearChanged, ///< used after a shear()
SizeChanged, ///< used after a resize() 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: ...@@ -542,6 +543,9 @@ protected:
*/ */
virtual void shapeChanged(ChangeType type) { Q_UNUSED(type); } virtual void shapeChanged(ChangeType type) { Q_UNUSED(type); }
void setCollisionDetection(bool detect) { m_detectCollision = detect; }
bool collisionDetection() { return m_detectCollision; }
private: private:
double m_scaleX; double m_scaleX;
double m_scaleY; double m_scaleY;
...@@ -560,7 +564,7 @@ private: ...@@ -560,7 +564,7 @@ private:
int m_zIndex; int m_zIndex;
KoShapeContainer *m_parent; KoShapeContainer *m_parent;
bool m_visible, m_locked, m_keepAspect, m_selectable; bool m_visible, m_locked, m_keepAspect, m_selectable, m_detectCollision;
QSet<KoShapeManager *> m_shapeManagers; QSet<KoShapeManager *> m_shapeManagers;
......
...@@ -115,9 +115,10 @@ void KoShapeContainer::paint(QPainter &painter, const KoViewConverter &converter ...@@ -115,9 +115,10 @@ void KoShapeContainer::paint(QPainter &painter, const KoViewConverter &converter
} }
void KoShapeContainer::shapeChanged(ChangeType type) { void KoShapeContainer::shapeChanged(ChangeType type) {
Q_UNUSED(type);
if(m_children == 0) if(m_children == 0)
return; return;
if(! (type == RotationChanged || type == ScaleChanged || type == ShearChanged || type == SizeChanged))
return;
m_children->containerChanged(this); m_children->containerChanged(this);
foreach (KoShape *shape, m_children->iterator()) foreach (KoShape *shape, m_children->iterator())
shape->recalcMatrix(); shape->recalcMatrix();
......
...@@ -231,8 +231,8 @@ KoShape * KoShapeManager::shapeAt( const QPointF &position, KoFlake::ShapeSelect ...@@ -231,8 +231,8 @@ KoShape * KoShapeManager::shapeAt( const QPointF &position, KoFlake::ShapeSelect
QList<KoShape *> KoShapeManager::shapesAt( const QRectF &rect, bool omitHiddenShapes ) QList<KoShape *> KoShapeManager::shapesAt( const QRectF &rect, bool omitHiddenShapes )
{ {
updateTree(); updateTree();
//TODO check if object is really in the rect and not //TODO check if object (outline) is really in the rect and we are not just
// only the bounding rect of the object. // adding objects by their bounding rect
if( omitHiddenShapes ) { if( omitHiddenShapes ) {
QList<KoShape*> intersectedShapes( m_tree.intersects( rect ) ); QList<KoShape*> intersectedShapes( m_tree.intersects( rect ) );
for(int count = intersectedShapes.count()-1; count >= 0; count--) { for(int count = intersectedShapes.count()-1; count >= 0; count--) {
...@@ -256,20 +256,52 @@ void KoShapeManager::repaint( QRectF &rect, const KoShape *shape, bool selection ...@@ -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 ); m_aggregate4update.insert( shape );
} }
void KoShapeManager::updateTree() void KoShapeManager::updateTree()
{ {
// for detecting collisions between shapes.
class DetectCollision {
public:
DetectCollision() {}
void detect(KoRTree<KoShape *> &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<KoShape*> shapesWithCollisionDetection;
};
DetectCollision detector;
foreach ( KoShape *shape, m_aggregate4update )
detector.detect(m_tree, shape);
foreach ( KoShape * shape, m_aggregate4update ) foreach ( KoShape * shape, m_aggregate4update )
{ {
m_tree.remove( shape ); m_tree.remove( shape );
QRectF br( shape->boundingRect() ); QRectF br( shape->boundingRect() );
m_tree.insert( br, shape ); 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(); m_aggregate4update.clear();
detector.fireSignals();
} }
#include "KoShapeManager.moc" #include "KoShapeManager.moc"
...@@ -128,13 +128,13 @@ public: ...@@ -128,13 +128,13 @@ public:
/** /**
* Update the tree for finding the shapes. * Update the tree for finding the shapes.
* This will remove the shape from the tree and will reinsert it again. * 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. * will be merged into one.
* @param shape the shape to updated its position in the tree. * @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 * 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. * updates to the tree are done when they are asked for but when they are needed.
......
...@@ -42,6 +42,7 @@ KoTextShape::KoTextShape() ...@@ -42,6 +42,7 @@ KoTextShape::KoTextShape()
m_textShapeData->document()->setDocumentLayout(lay); m_textShapeData->document()->setDocumentLayout(lay);
lay->setInlineObjectTextManager(new KoInlineTextObjectManager(lay)); lay->setInlineObjectTextManager(new KoInlineTextObjectManager(lay));
setCollisionDetection(true);
} }
KoTextShape::~KoTextShape() { KoTextShape::~KoTextShape() {
...@@ -67,7 +68,7 @@ QPointF KoTextShape::convertScreenPos(const QPointF &point) { ...@@ -67,7 +68,7 @@ QPointF KoTextShape::convertScreenPos(const QPointF &point) {
} }
void KoTextShape::shapeChanged(ChangeType type) { void KoTextShape::shapeChanged(ChangeType type) {
if(type == PositionChanged || type == SizeChanged) { if(type == PositionChanged || type == SizeChanged || type == CollisionDetected) {
m_textShapeData->faul(); m_textShapeData->faul();
m_textShapeData->fireResizeEvent(); m_textShapeData->fireResizeEvent();
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment