Commit c047a866 authored by Jan Hambrecht's avatar Jan Hambrecht

From the dark and creepy places they came. They brought

fear and dread. But we all did know:
Where there is light, there must be shadows. So here they
are - shape shadows!


svn path=/trunk/koffice/; revision=775516
parent 8bab92a2
......@@ -66,6 +66,7 @@ set(flake_SRCS
KoSnapStrategy.cpp
KoSnapData.cpp
SnapGuideConfigWidget.cpp
KoShapeShadow.cpp
commands/KoShapeGroupCommand.cpp
commands/KoShapeAlignCommand.cpp
commands/KoShapeBackgroundCommand.cpp
......
......@@ -27,6 +27,7 @@
#include "KoPathShapeLoader.h"
#include "KoShapeSavingContext.h"
#include "KoShapeLoadingContext.h"
#include "KoShapeShadow.h"
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
......@@ -385,7 +386,14 @@ QRectF KoPathShape::boundingRect() const
bb.adjust( -inset.left, -inset.top, inset.right, inset.bottom );
}
//qDebug() << "KoPathShape::boundingRect = " << bb;
return absoluteTransformation( 0 ).mapRect( bb );
bb = absoluteTransformation( 0 ).mapRect( bb );
if( shadow() )
{
KoInsets insets;
shadow()->insets( this, insets );
bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
}
return bb;
}
......
......@@ -37,6 +37,7 @@
#include "KoLineBorder.h"
#include "ShapeDeleter_p.h"
#include "KoShapeStyleWriter.h"
#include "KoShapeShadow.h"
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
......@@ -70,7 +71,8 @@ public:
appData(0),
backgroundBrush(Qt::NoBrush),
border(0),
me(shape)
me(shape),
shadow(0)
{
}
......@@ -86,6 +88,8 @@ public:
if(border->useCount() == 0)
delete border;
}
if( shadow && shadow->removeUser() == 0 )
delete shadow;
}
void shapeChanged(ChangeType type) {
......@@ -122,6 +126,7 @@ public:
QList<KoShapeConnection*> connections;
KoShape *me;
QList<KoShape*> dependees; ///< list of shape dependent on this shape
KoShapeShadow * shadow; ///< the current shape shadow
};
KoShape::KoShape()
......@@ -232,13 +237,25 @@ bool KoShape::hitTest( const QPointF &position ) const
return false;
QPointF point = absoluteTransformation(0).inverted().map( position );
KoInsets insets(0, 0, 0, 0);
QRectF bb( QPointF(), size() );
if(d->border)
{
KoInsets insets;
d->border->borderInsets(this, insets);
bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
}
if( bb.contains( point ) )
return true;
// if there is no shadow we can as well just leave
if( ! d->shadow )
return false;
QSizeF s( size() );
return point.x() >= -insets.left && point.x() <= s.width() + insets.right &&
point.y() >= -insets.top && point.y() <= s.height() + insets.bottom;
// the shadow has an offset to the shape, so we simply
// check if the position minus the shadow offset hits the shape
point = absoluteTransformation(0).inverted().map( position-d->shadow->offset() );
return bb.contains( point );
}
QRectF KoShape::boundingRect() const
......@@ -249,7 +266,14 @@ QRectF KoShape::boundingRect() const
d->border->borderInsets(this, insets);
bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
}
return absoluteTransformation(0).mapRect( bb );
bb = absoluteTransformation(0).mapRect( bb );
if( d->shadow )
{
KoInsets insets;
d->shadow->insets( this, insets );
bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
}
return bb;
}
QMatrix KoShape::absoluteTransformation(const KoViewConverter *converter) const {
......@@ -617,6 +641,22 @@ void KoShape::setBorder(KoShapeBorderModel *border) {
notifyChanged();
}
void KoShape::setShadow( KoShapeShadow * shadow )
{
if( d->shadow )
d->shadow->removeUser();
d->shadow = shadow;
if( d->shadow )
d->shadow->addUser();
d->shapeChanged(ShadowChanged);
notifyChanged();
}
KoShapeShadow * KoShape::shadow() const
{
return d->shadow;
}
const QMatrix& KoShape::matrix() const {
return d->localMatrix;
}
......@@ -687,6 +727,9 @@ QString KoShape::saveStyle( KoGenStyle &style, KoShapeSavingContext &context ) c
{
b->fillStyle( style, context );
}
KoShapeShadow * s = shadow();
if( s )
s->fillStyle( style, context );
KoShapeStyleWriter styleWriter( context );
......@@ -712,6 +755,7 @@ void KoShape::loadStyle( const KoXmlElement & element, KoShapeLoadingContext &co
setBackground( loadOdfFill( element, context ) );
setBorder( loadOdfStroke( element, context ) );
setShadow( loadOdfShadow( element, context ) );
styleStack.restore();
}
......@@ -818,6 +862,28 @@ KoShapeBorderModel * KoShape::loadOdfStroke( const KoXmlElement & element, KoSha
return 0;
}
KoShapeShadow * KoShape::loadOdfShadow( const KoXmlElement & element, KoShapeLoadingContext & context )
{
KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
QString stroke = getStyleProperty( "shadow", element, context );
if( stroke == "visible" || stroke == "hidden" )
{
KoShapeShadow * shadow = new KoShapeShadow();
QColor shadowColor( styleStack.property( KoXmlNS::draw, "shadow-color" ) );
qreal offsetX = KoUnit::parseValue( styleStack.property( KoXmlNS::draw, "shadow-offset-x" ) );
qreal offsetY = KoUnit::parseValue( styleStack.property( KoXmlNS::draw, "shadow-offset-y" ) );
shadow->setOffset( QPointF( offsetX, offsetY ) );
QString opacity = styleStack.property( KoXmlNS::draw, "shadow-opacity" );
if( ! opacity.isEmpty() && opacity.right( 1 ) == "%" )
shadowColor.setAlphaF( opacity.left( opacity.length()-1 ).toFloat() / 100.0 );
shadow->setColor( shadowColor );
return shadow;
}
return 0;
}
QMatrix KoShape::parseOdfTransform( const QString &transform )
{
QMatrix matrix;
......
......@@ -52,6 +52,7 @@ class KoCanvasBase;
class KoShapeLoadingContext;
class KoGenStyle;
class KoShapeControllerBase;
class KoShapeShadow;
/**
*
......@@ -111,7 +112,8 @@ public:
CollisionDetected, ///< used when another shape moved in our boundingrect
Deleted, ///< the shape was deleted
BorderChanged, ///< the shapes border has changed
BackgroundChanged ///< the shapes background has changed
BackgroundChanged, ///< the shapes background has changed
ShadowChanged ///< the shapes shadow has changed
};
/**
......@@ -479,6 +481,12 @@ public:
*/
KoInsets borderInsets() const;
/// Sets the new shadow, removing the old one
void setShadow( KoShapeShadow * shadow );
/// Returns the currently set shadow or 0 if there is now shadow set
KoShapeShadow * shadow() const;
/**
* Setting the shape to keep its aspect-ratio has the effect that user-scaling will
* keep the width/hight ratio intact so as not to distort shapes that rely on that
......@@ -780,6 +788,9 @@ protected:
/// Loads the stroke style
KoShapeBorderModel * loadOdfStroke( const KoXmlElement & element, KoShapeLoadingContext & context );
/// Loads the shadow style
KoShapeShadow * loadOdfShadow( const KoXmlElement & element, KoShapeLoadingContext & context );
/**
* Fills the style stack and returns the value of the given style property (e.g fill, stroke).
*/
......
......@@ -31,6 +31,7 @@
#include "KoShapeGroup.h"
#include "KoToolProxy.h"
#include "KoShapeManagerPaintingStrategy.h"
#include "KoShapeShadow.h"
#include <QPainter>
#include <kdebug.h>
......@@ -237,6 +238,12 @@ void KoShapeManager::paint( QPainter &painter, const KoViewConverter &converter,
void KoShapeManager::paintShape( KoShape * shape, QPainter &painter, const KoViewConverter &converter, bool forPrint )
{
if( shape->shadow() )
{
painter.save();
shape->shadow()->paint( shape, painter, converter );
painter.restore();
}
painter.save();
shape->paint( painter, converter );
painter.restore();
......
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
*
* 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 "KoShapeShadow.h"
#include "KoShape.h"
#include "KoInsets.h"
#include <KoGenStyle.h>
#include <QtGui/QPainter>
class KoShapeShadow::Private
{
public:
Private()
: offset(10,10), color(Qt::black), visible(true), refCount(0)
{
}
QPointF offset;
QColor color;
bool visible;
int refCount;
};
KoShapeShadow::KoShapeShadow()
: d( new Private() )
{
}
KoShapeShadow::~KoShapeShadow()
{
delete d;
}
void KoShapeShadow::fillStyle( KoGenStyle &style, KoShapeSavingContext &context )
{
style.addProperty( "draw:shadow", d->visible ? "visible" : "hidden" );
style.addProperty( "draw:shadow-color", d->color.name() );
if( d->color.alphaF() != 1.0 )
style.addProperty( "draw:shadow-opacity", QString("%1%").arg( d->color.alphaF() * 100.0 ) );
style.addProperty( "draw:shadow-offset-x", QString("%1pt").arg( d->offset.x() ) );
style.addProperty( "draw:shadow-offset-y", QString("%1pt").arg( d->offset.y() ) );
}
void KoShapeShadow::paint(KoShape *shape, QPainter &painter, const KoViewConverter &converter)
{
KoShape::applyConversion( painter, converter );
painter.setPen( Qt::NoPen );
painter.setBrush( QBrush(d->color) );
QMatrix tm;
tm.translate( d->offset.x(), d->offset.y() );
QMatrix tr = shape->absoluteTransformation(&converter);
painter.setMatrix( tr * tm * tr.inverted() * painter.matrix() );
painter.drawPath( shape->outline() );
}
void KoShapeShadow::setOffset( const QPointF & offset )
{
d->offset = offset;
}
QPointF KoShapeShadow::offset() const
{
return d->offset;
}
void KoShapeShadow::setColor( const QColor &color )
{
d->color = color;
}
QColor KoShapeShadow::color() const
{
return d->color;
}
void KoShapeShadow::setVisibility( bool visible )
{
d->visible = visible;
}
bool KoShapeShadow::isVisible() const
{
return d->visible;
}
void KoShapeShadow::insets( const KoShape *shape, KoInsets &insets )
{
Q_UNUSED( shape );
insets.left = ( d->offset.x() < 0.0 ) ? qAbs(d->offset.x()) : 0.0;
insets.top = ( d->offset.y() < 0.0 ) ? qAbs(d->offset.y()) : 0.0;
insets.right = ( d->offset.x() > 0.0 ) ? d->offset.x() : 0.0;
insets.bottom = ( d->offset.y() > 0.0 ) ? d->offset.y() : 0.0;
}
void KoShapeShadow::addUser()
{
d->refCount++;
}
int KoShapeShadow::removeUser()
{
return --d->refCount;
}
int KoShapeShadow::useCount() const
{
return d->refCount;
}
/* This file is part of the KDE project
* Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
*
* 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 KOSHAPESHADOW_H
#define KOSHAPESHADOW_H
#include "flake_export.h"
#include <QtCore/QPointF>
#include <QtGui/QColor>
class KoShape;
class KoGenStyle;
class KoShapeSavingContext;
class QPainter;
class KoViewConverter;
class KoInsets;
class FLAKE_EXPORT KoShapeShadow
{
public:
KoShapeShadow();
~KoShapeShadow();
/**
* Fills the style object
* @param style object
* @param context used for saving
*/
void fillStyle( KoGenStyle &style, KoShapeSavingContext &context );
/**
* Paints the shadow of the shape.
* @param shape the shape to paint around
* @param painter the painter to paint to, the painter will have the topleft of the
* shape as its start coordinate.
* @param converter to convert between internal and view coordinates.
*/
void paint(KoShape *shape, QPainter &painter, const KoViewConverter &converter);
/**
* Sets the shadow offset from the topleft corner of the shape
* @param offset the shadow offset
*/
void setOffset( const QPointF & offset );
/// Returns the shadow offset
QPointF offset() const;
/**
* Sets the shadow color, including the shadow opacity.
* @param color the shadow color and opacity
*/
void setColor( const QColor &color );
/// Returns the shadow color including opacity
QColor color() const;
/// Sets the shadow visibility
void setVisibility( bool visible );
/// Returns if shadow is visible
bool isVisible() const;
/// Returns the insets of the shadow
void insets( const KoShape *shape, KoInsets &insets );
/// Increase reference counter
void addUser();
/// Decrease reference counter
int removeUser();
/// Return reference counter
int useCount() const;
private:
class Private;
Private * const d;
};
#endif // KOSHAPESHADOW_H
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