Commit b58b1719 authored by Thorsten Zachmann's avatar Thorsten Zachmann

Implement hatch background as defined in odf.

With this patch the different styles, freely defined angles and distance between
the lines of the hatch is supported.

This patch also changes the KoColorBackground to also use the d pointer of the
parent which reduces the memory needed for a KoColorBackground.

REVIEW: 106115
BUG: 260534
BUG: 298708
parent 7843387b
......@@ -82,6 +82,7 @@ set(flake_SRCS
KoColorBackground.cpp
KoGradientBackground.cpp
KoOdfGradientBackground.cpp
KoHatchBackground.cpp
KoPatternBackground.cpp
KoShapeConfigWidgetBase.cpp
KoShapeConfigFactoryBase.cpp
......
......@@ -18,6 +18,7 @@
*/
#include "KoColorBackground.h"
#include "KoColorBackground_p.h"
#include "KoShapeSavingContext.h"
#include <KoOdfGraphicStyles.h>
#include <KoOdfLoadingContext.h>
......@@ -26,25 +27,20 @@
#include <QColor>
#include <QPainter>
class KoColorBackground::Private
KoColorBackground::KoColorBackground()
: KoShapeBackground(*(new KoColorBackgroundPrivate()))
{
public:
Private() {
color = Qt::black;
style = Qt::SolidPattern;
};
Qt::BrushStyle style;
QColor color;
};
}
KoColorBackground::KoColorBackground()
: d(new Private())
KoColorBackground::KoColorBackground(KoShapeBackgroundPrivate &dd)
: KoShapeBackground(dd)
{
}
KoColorBackground::KoColorBackground(const QColor &color, Qt::BrushStyle style)
: d(new Private())
: KoShapeBackground(*(new KoColorBackgroundPrivate()))
{
Q_D(KoColorBackground);
if (style < Qt::SolidPattern || style >= Qt::LinearGradientPattern)
style = Qt::SolidPattern;
d->style = style;
......@@ -53,37 +49,42 @@ KoColorBackground::KoColorBackground(const QColor &color, Qt::BrushStyle style)
KoColorBackground::~KoColorBackground()
{
delete d;
}
QColor KoColorBackground::color() const
{
Q_D(const KoColorBackground);
return d->color;
}
void KoColorBackground::setColor(const QColor &color)
{
Q_D(KoColorBackground);
d->color = color;
}
Qt::BrushStyle KoColorBackground::style() const
{
Q_D(const KoColorBackground);
return d->style;
}
void KoColorBackground::paint(QPainter &painter, const KoViewConverter &/*converter*/, KoShapePaintingContext &/*context*/, const QPainterPath &fillPath) const
{
Q_D(const KoColorBackground);
painter.setBrush(QBrush(d->color, d->style));
painter.drawPath(fillPath);
}
void KoColorBackground::fillStyle(KoGenStyle &style, KoShapeSavingContext &context)
{
Q_D(KoColorBackground);
KoOdfGraphicStyles::saveOdfFillStyle(style, context.mainStyles(), QBrush(d->color, d->style));
}
bool KoColorBackground::loadStyle(KoOdfLoadingContext & context, const QSizeF &)
{
Q_D(KoColorBackground);
KoStyleStack &styleStack = context.styleStack();
if (! styleStack.hasProperty(KoXmlNS::draw, "fill"))
return false;
......
......@@ -24,6 +24,7 @@
#include "flake_export.h"
#include <Qt>
class KoColorBackgroundPrivate;
class QColor;
/// A simple solid color shape background
......@@ -53,9 +54,11 @@ public:
// reimplemented from KoShapeBackground
virtual bool loadStyle(KoOdfLoadingContext & context, const QSizeF &shapeSize);
protected:
KoColorBackground(KoShapeBackgroundPrivate &dd);
private:
class Private;
Private * const d;
Q_DECLARE_PRIVATE(KoColorBackground)
};
#endif // KOCOLORBACKGROUND_H
/* 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 KOCOLORBACKGROUND_P_H
#define KOCOLORBACKGROUND_P_H
#include "KoShapeBackground_p.h"
#include <QColor>
class KoColorBackgroundPrivate : public KoShapeBackgroundPrivate
{
public:
KoColorBackgroundPrivate()
: color(Qt::black)
, style(Qt::SolidPattern)
{};
QColor color;
Qt::BrushStyle style;
};
#endif // KOCOLORBACKGROUND_P_H
/* This file is part of the KDE project
*
* Copyright (C) 2012 Thorsten Zachmann <zachmann@kde.org>
*
* 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 "KoHatchBackground.h"
#include "KoColorBackground_p.h"
#include <KoOdfLoadingContext.h>
#include <KoStyleStack.h>
#include <KoShapeSavingContext.h>
#include <KoGenStyles.h>
#include <KoGenStyle.h>
#include <KoXmlNS.h>
#include <KoUnit.h>
#include <KDebug>
#include <QColor>
#include <QString>
#include <QPainter>
class KoHatchBackgroundPrivate : public KoColorBackgroundPrivate
{
public:
KoHatchBackgroundPrivate()
: angle(0.0)
, distance(1.0)
, style(KoHatchBackground::Single)
{}
QColor lineColor;
int angle;
qreal distance;
KoHatchBackground::HatchStyle style;
QString name;
};
KoHatchBackground::KoHatchBackground()
: KoColorBackground(*(new KoHatchBackgroundPrivate()))
{
}
void KoHatchBackground::paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &context, const QPainterPath &fillPath) const
{
Q_D(const KoHatchBackground);
if (d->color.isValid()) {
// paint background color if set by using the color background
KoColorBackground::paint(painter, converter, context, fillPath);
}
const QRectF targetRect = fillPath.boundingRect();
painter.save();
painter.setClipPath(fillPath);
QPen pen(d->lineColor);
// we set the pen width to 0.5 pt for the hatch. This is not defined in the spec.
pen.setWidthF(0.5);
painter.setPen(pen);
QVector<QLineF> lines;
// The different styles are handled by painting the lines multiple times with a different
// angel offset as basically it just means we paint the lines also at a different angle.
// This are the angle offsets we need to apply to the different lines of a style.
// -90 is for single, 0 for the 2nd line in double and -45 for the 3th line in triple.
const int angleOffset[] = {-90, 0, -45 };
// The number of loops is defined by the style.
int loops = (d->style == Single) ? 1 : (d->style == Double) ? 2 : 3;
for (int i = 0; i < loops; ++i) {
int angle = d->angle - angleOffset[i];
qreal cosAngle = ::cos(angle/180.0*M_PI);
// if cos is nearly 0 the lines are horizontal. Use a special case for that
if (qAbs(cosAngle) > 0.00001) {
qreal xDiff = tan(angle/180.0*M_PI) * targetRect.height();
// calculate the distance we need to increase x when creating the lines so that the
// distance between the lines is also correct for rotated lines.
qreal xOffset = qAbs(d->distance / cosAngle);
// if the lines go to the right we need to start more to the left. Get the correct start.
qreal xStart = 0;
while (-xDiff < xStart) {
xStart -= xOffset;
}
// if the lines go to the left we need to stop more at the right. Get the correct end offset
qreal xEndOffset = 0;
if (xDiff < 0) {
while (xDiff < -xEndOffset) {
xEndOffset += xOffset;
}
}
// create line objects.
lines.reserve(lines.size() + int((targetRect.width() + xEndOffset - xStart) / xOffset) + 1);
for (qreal x = xStart; x < targetRect.width() + xEndOffset; x += xOffset) {
lines.append(QLineF(x, 0, x + xDiff, targetRect.height()));
}
}
else {
// horizontal lines
lines.reserve(lines.size() + int(targetRect.height()/d->distance) + 1);
for (qreal y = 0; y < targetRect.height(); y += d->distance) {
lines.append(QLineF(0, y, targetRect.width(), y));
}
}
}
painter.drawLines(lines);
painter.restore();
}
void KoHatchBackground::fillStyle(KoGenStyle &style, KoShapeSavingContext &context)
{
Q_D(KoHatchBackground);
KoGenStyle::Type type = style.type();
KoGenStyle::PropertyType propertyType = (type == KoGenStyle::GraphicStyle || type == KoGenStyle::GraphicAutoStyle ||
type == KoGenStyle::DrawingPageStyle || type == KoGenStyle::DrawingPageAutoStyle )
? KoGenStyle::DefaultType : KoGenStyle::GraphicType;
style.addProperty("draw:fill", "hatch", propertyType);
style.addProperty("draw:fill-hatch-name", saveHatchStyle(context), propertyType);
bool fillHatchSolid = d->color.isValid();
style.addProperty("draw:fill-hatch-solid", fillHatchSolid, propertyType);
if (fillHatchSolid) {
style.addProperty("draw:fill-color", d->color.name(), propertyType);
}
}
QString KoHatchBackground::saveHatchStyle(KoShapeSavingContext &context) const
{
Q_D(const KoHatchBackground);
KoGenStyle hatchStyle(KoGenStyle::HatchStyle /*no family name*/);
hatchStyle.addAttribute("draw:display-name", d->name);
hatchStyle.addAttribute("draw:color", d->lineColor.name());
hatchStyle.addAttributePt("draw:distance", d->distance);
hatchStyle.addAttribute("draw:rotation", QString("%1").arg(d->angle * 10));
switch (d->style) {
case Single:
hatchStyle.addAttribute("draw:style", "single");
break;
case Double:
hatchStyle.addAttribute("draw:style", "double");
break;
case Triple:
hatchStyle.addAttribute("draw:style", "triple");
break;
}
return context.mainStyles().insert(hatchStyle, "hatch");
}
bool KoHatchBackground::loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize)
{
// <draw:hatch draw:name="hatchStyle3" draw:color="#000000" draw:display-name="#000000 Vertical" draw:distance="0.102cm" draw:rotation="900" draw:style="single"/>
Q_D(KoHatchBackground);
Q_UNUSED(shapeSize);
KoStyleStack &styleStack = context.styleStack();
QString fillStyle = styleStack.property(KoXmlNS::draw, "fill");
if (fillStyle == "hatch") {
QString style = styleStack.property(KoXmlNS::draw, "fill-hatch-name");
kDebug(30003) << " hatch style is :" << style;
KoXmlElement* draw = context.stylesReader().drawStyles("hatch")[style];
if (draw) {
kDebug(30003) << "Hatch style found for:" << style;
QString angle = draw->attributeNS(KoXmlNS::draw, "rotation", QString("0"));
if (angle.at(angle.size()-1).isLetter()) {
d->angle = KoUnit::parseAngle(angle);
}
else {
// OO saves the angle value without unit and multiplied by a factor of 10
d->angle = int(angle.toInt() / 10);
}
kDebug(30003) << "angle :" << d->angle;
d->name = draw->attributeNS(KoXmlNS::draw, "display-name");
// use 2mm as default, just in case it is not given in a document so we show something sensible.
d->distance = KoUnit::parseValue(draw->attributeNS(KoXmlNS::draw, "distance", "2mm"));
bool fillHatchSolid = styleStack.property(KoXmlNS::draw, "fill-hatch-solid") == QLatin1String("true");
if (fillHatchSolid) {
QString fillColor = styleStack.property(KoXmlNS::draw, "fill-color");
if (!fillColor.isEmpty()) {
d->color.setNamedColor(fillColor);
}
else {
d->color =QColor();
}
}
else {
d->color = QColor();
}
d->lineColor.setNamedColor(draw->attributeNS(KoXmlNS::draw, "color", QString("#000000")));
QString style = draw->attributeNS(KoXmlNS::draw, "style", QString());
if (style == "double") {
d->style = Double;
}
else if (style == "triple") {
d->style = Triple;
}
else {
d->style = Single;
}
}
return true;
}
return false;
}
/* This file is part of the KDE project
*
* Copyright (C) 2012 Thorsten Zachmann <zachmann@kde.org>
*
* 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 KOHATCHBACKGROUND_H
#define KOHATCHBACKGROUND_H
#include "KoColorBackground.h"
class KoHatchBackgroundPrivate;
/**
* A hatch shape background
*/
class KoHatchBackground : public KoColorBackground
{
public:
enum HatchStyle {
Single,
Double,
Triple
};
KoHatchBackground();
// reimplemented
virtual void paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &context, const QPainterPath &fillPath) const;
// reimplemented
virtual void fillStyle(KoGenStyle &style, KoShapeSavingContext &context);
// reimplemented
virtual bool loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize);
private:
QString saveHatchStyle(KoShapeSavingContext &context) const;
Q_DECLARE_PRIVATE(KoHatchBackground)
};
#endif /* KOHATCHBACKGROUND_H */
......@@ -32,6 +32,7 @@
#include "KoShapeStrokeModel.h"
#include "KoShapeBackground.h"
#include "KoColorBackground.h"
#include "KoHatchBackground.h"
#include "KoGradientBackground.h"
#include "KoPatternBackground.h"
#include "KoShapeManager.h"
......@@ -1559,9 +1560,13 @@ KoShapeBackground *KoShape::loadOdfFill(KoShapeLoadingContext &context) const
{
QString fill = KoShapePrivate::getStyleProperty("fill", context);
KoShapeBackground *bg = 0;
if (fill == "solid" || fill == "hatch") {
if (fill == "solid") {
bg = new KoColorBackground();
} else if (fill == "gradient") {
}
else if (fill == "hatch") {
bg = new KoHatchBackground();
}
else if (fill == "gradient") {
QString styleName = KoShapePrivate::getStyleProperty("fill-gradient-name", context);
KoXmlElement *e = context.odfLoadingContext().stylesReader().drawStyles("gradient")[styleName];
QString style;
......
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