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()
void KoPathShape::update()
{
updateTree();
notifyChanged();
}
QPointF KoPathShape::normalize()
......
......@@ -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 );
}
}
......
......@@ -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<KoShapeManager *> m_shapeManagers;
......
......@@ -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();
......
......@@ -231,8 +231,8 @@ KoShape * KoShapeManager::shapeAt( const QPointF &position, KoFlake::ShapeSelect
QList<KoShape *> 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<KoShape*> 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<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 )
{
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"
......@@ -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.
......
......@@ -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();
}
......
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