You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
433 lines
15 KiB
433 lines
15 KiB
/*
|
|
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
|
|
* Copyright (c) 2004 Clarence Dang <dang@kde.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifndef KIS_PAINTER_H_
|
|
#define KIS_PAINTER_H_
|
|
|
|
#include <kcommand.h>
|
|
|
|
#include "kis_color.h"
|
|
#include "kis_global.h"
|
|
#include "kis_types.h"
|
|
#include "kis_paint_device.h"
|
|
#include "kis_point.h"
|
|
#include "kis_filter.h"
|
|
#include "kis_progress_subject.h"
|
|
#include "kis_paintop.h"
|
|
#include "kis_color.h"
|
|
|
|
#include <koffice_export.h>
|
|
|
|
class QRect;
|
|
class KisTransaction;
|
|
class KisBrush;
|
|
class KisPattern;
|
|
|
|
/**
|
|
* KisPainter contains the graphics primitives necessary to draw on a
|
|
* KisPaintDevice. This is the same kind of abstraction as used in Qt
|
|
* itself, where you have QPainter and QPaintDevice.
|
|
*
|
|
* However, KisPainter works on a tiled image and supports different
|
|
* colour models, and that's a lot more complicated.
|
|
*
|
|
* KisPainter supports transactions that can group various paint operations
|
|
* in one undoable step.
|
|
*
|
|
* For more complex operations, you might want to have a look at the subclasses
|
|
* of KisPainter: KisConvolutionPainter, KisFillPainter and KisGradientPainter
|
|
*/
|
|
class KRITACORE_EXPORT KisPainter : public KisProgressSubject {
|
|
typedef KisProgressSubject super;
|
|
|
|
public:
|
|
/// Construct painter without a device
|
|
KisPainter();
|
|
/// Construct a painter, and begin painting on the device
|
|
KisPainter(KisPaintDeviceSP device);
|
|
virtual ~KisPainter();
|
|
|
|
private:
|
|
// Implement KisProgressSubject
|
|
virtual void cancel() { m_cancelRequested = true; }
|
|
|
|
public:
|
|
/**
|
|
* Start painting on the specified device. Not undoable.
|
|
*/
|
|
void begin(KisPaintDeviceSP device);
|
|
|
|
/**
|
|
* Finish painting on the current device
|
|
*/
|
|
KCommand *end();
|
|
|
|
/// Begin an undoable paint operation
|
|
void beginTransaction(const QString& customName = QString::null);
|
|
|
|
/// Finish the undoable paint operation
|
|
KCommand *endTransaction();
|
|
|
|
/// begin a transaction with the given command
|
|
void beginTransaction( KisTransaction* command);
|
|
|
|
/// Return the current transcation
|
|
KisTransaction * transaction() { return m_transaction; }
|
|
|
|
|
|
/// Returns the current paint device.
|
|
KisPaintDeviceSP device() const { return m_device; }
|
|
|
|
|
|
// -----------------------------------------------------------------
|
|
// Native paint methods that are undo/redo-able,
|
|
// use the color strategies and the composite operations.
|
|
|
|
/**
|
|
* Blast the specified region from src onto the current paint device.
|
|
*/
|
|
void bitBlt(Q_INT32 dx, Q_INT32 dy,
|
|
const KisCompositeOp& op,
|
|
KisPaintDeviceSP src,
|
|
Q_INT32 sx, Q_INT32 sy,
|
|
Q_INT32 sw, Q_INT32 sh)
|
|
{
|
|
bitBlt(dx, dy, op, src, OPACITY_OPAQUE, sx, sy, sw, sh);
|
|
}
|
|
|
|
/**
|
|
* Overloaded version of the previous, differs in that it is possible to specify
|
|
* a value for opacity
|
|
*/
|
|
void bitBlt(Q_INT32 dx, Q_INT32 dy,
|
|
const KisCompositeOp& op,
|
|
KisPaintDeviceSP src,
|
|
Q_UINT8 opacity,
|
|
Q_INT32 sx, Q_INT32 sy,
|
|
Q_INT32 sw, Q_INT32 sh);
|
|
|
|
/**
|
|
* A version of bitBlt that renders using an external mask, ignoring
|
|
* the src device's own selection, if it has one.
|
|
*/
|
|
void bltMask(Q_INT32 dx, Q_INT32 dy,
|
|
const KisCompositeOp &op,
|
|
KisPaintDeviceSP src,
|
|
KisPaintDeviceSP selMask,
|
|
Q_UINT8 opacity,
|
|
Q_INT32 sx, Q_INT32 sy,
|
|
Q_INT32 sw, Q_INT32 sh);
|
|
|
|
/**
|
|
* A version of bitBlt that renders using an external selection mask, ignoring
|
|
* the src device's own selection, if it has one.
|
|
*/
|
|
void bltSelection(Q_INT32 dx, Q_INT32 dy,
|
|
const KisCompositeOp &op,
|
|
KisPaintDeviceSP src,
|
|
KisSelectionSP selMask,
|
|
Q_UINT8 opacity,
|
|
Q_INT32 sx, Q_INT32 sy,
|
|
Q_INT32 sw, Q_INT32 sh);
|
|
|
|
|
|
/**
|
|
* A version of bitBlt that renders using the src device's selection mask, if it has one.
|
|
*/
|
|
void bltSelection(Q_INT32 dx, Q_INT32 dy,
|
|
const KisCompositeOp &op,
|
|
KisPaintDeviceSP src,
|
|
Q_UINT8 opacity,
|
|
Q_INT32 sx, Q_INT32 sy,
|
|
Q_INT32 sw, Q_INT32 sh);
|
|
|
|
|
|
/**
|
|
* The methods below are 'higher' level than the above methods. They need brushes, colors
|
|
* etc. set before they can be called. The methods do not directly tell the image to
|
|
* update, but you can call dirtyRect() to get the rect that needs to be notified by your
|
|
* painting code.
|
|
*
|
|
* Call will RESET the dirtyRect!
|
|
*/
|
|
QRect dirtyRect();
|
|
|
|
/**
|
|
* Add the r to the current dirty rect, and return the dirtyRect after adding r to it.
|
|
*/
|
|
QRect addDirtyRect(QRect r) { m_dirtyRect |= r; return m_dirtyRect; }
|
|
|
|
|
|
|
|
/**
|
|
* Paint a line that connects the dots in points
|
|
*/
|
|
void paintPolyline(const QValueVector <KisPoint> &points,
|
|
int index = 0, int numPoints = -1);
|
|
|
|
/**
|
|
* Draw a line between pos1 and pos2 using the currently set brush and color.
|
|
* If savedDist is less than zero, the brush is painted at pos1 before being
|
|
* painted along the line using the spacing setting.
|
|
* @return the drag distance, that is the remains of the distance between p1 and p2 not covered
|
|
* because the currenlty set brush has a spacing greater than that distance.
|
|
*/
|
|
double paintLine(const KisPoint &pos1,
|
|
const double pressure1,
|
|
const double xTilt1,
|
|
const double yTilt1,
|
|
const KisPoint &pos2,
|
|
const double pressure2,
|
|
const double xTilt2,
|
|
const double yTilt2,
|
|
const double savedDist = -1);
|
|
|
|
/**
|
|
* Draw a Bezier curve between pos1 and pos2 using control points 1 and 2.
|
|
* If savedDist is less than zero, the brush is painted at pos1 before being
|
|
* painted along the curve using the spacing setting.
|
|
* @return the drag distance, that is the remains of the distance between p1 and p2 not covered
|
|
* because the currenlty set brush has a spacing greater than that distance.
|
|
*/
|
|
double paintBezierCurve(const KisPoint &pos1,
|
|
const double pressure1,
|
|
const double xTilt1,
|
|
const double yTilt1,
|
|
const KisPoint &control1,
|
|
const KisPoint &control2,
|
|
const KisPoint &pos2,
|
|
const double pressure2,
|
|
const double xTilt2,
|
|
const double yTilt2,
|
|
const double savedDist = -1);
|
|
|
|
/**
|
|
* Fill the given vector points with the points needed to draw the Bezier curve between
|
|
* pos1 and pos2 using control points 1 and 2, excluding the final pos2.
|
|
*/
|
|
void getBezierCurvePoints(const KisPoint &pos1,
|
|
const KisPoint &control1,
|
|
const KisPoint &control2,
|
|
const KisPoint &pos2,
|
|
vKisPoint& points);
|
|
|
|
|
|
/**
|
|
* Paint the rectangle with given begin and end points
|
|
*/
|
|
void paintRect(const KisPoint &startPoint,
|
|
const KisPoint &endPoint,
|
|
const double pressure,
|
|
const double xTilt,
|
|
const double yTilt);
|
|
|
|
|
|
/**
|
|
* Paint the ellipse with given begin and end points
|
|
*/
|
|
void paintEllipse(const KisPoint &startPoint,
|
|
const KisPoint &endPoint,
|
|
const double pressure,
|
|
const double /*xTilt*/,
|
|
const double /*yTilt*/);
|
|
|
|
/**
|
|
* Paint the polygon with the points given in points. It automatically closes the polygon
|
|
* by drawing the line from the last point to the first.
|
|
*/
|
|
void paintPolygon(const vKisPoint& points);
|
|
|
|
/** Draw a spot at pos using the currently set paint op, brush and color */
|
|
void paintAt(const KisPoint &pos,
|
|
const double pressure,
|
|
const double /*xTilt*/,
|
|
const double /*yTilt*/);
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Set the parameters for the higher level graphics primitives.
|
|
|
|
/// Determines whether the brush spacing should vary when drawing
|
|
/// lines with the pressure
|
|
void setVaryBrushSpacingWithPressureWhenDrawingALine( bool varyBrushSpacingWithPressureWhenDrawingALine )
|
|
{ m_varyBrushSpacingWithPressureWhenDrawingALine = varyBrushSpacingWithPressureWhenDrawingALine; }
|
|
bool varyBrushSpacingWithPressureWhenDrawingALine() { return m_varyBrushSpacingWithPressureWhenDrawingALine; }
|
|
|
|
/// Set the current brush
|
|
void setBrush(KisBrush* brush) { m_brush = brush; }
|
|
/// Returns the currently set brush
|
|
KisBrush * brush() const { return m_brush; }
|
|
|
|
/// Set the current pattern
|
|
void setPattern(KisPattern * pattern) { m_pattern = pattern; }
|
|
/// Returns the currently set pattern
|
|
KisPattern * pattern() const { return m_pattern; }
|
|
|
|
/// Set the color that will be used to paint with
|
|
void setPaintColor(const KisColor& color) { m_paintColor = color;}
|
|
|
|
/// Returns the color that will be used to paint with
|
|
KisColor paintColor() const { return m_paintColor; }
|
|
|
|
/// Set the current background color
|
|
void setBackgroundColor(const KisColor& color) {m_backgroundColor = color; }
|
|
/// Returns the current background color
|
|
KisColor backgroundColor() const { return m_backgroundColor; }
|
|
|
|
/// Set the current fill color
|
|
void setFillColor(const KisColor& color) { m_fillColor = color; }
|
|
/// Returns the current fill color
|
|
KisColor fillColor() const { return m_fillColor; }
|
|
|
|
|
|
/// This enum contains the styles with which we can fill things like polygons and ellipses
|
|
enum FillStyle {
|
|
FillStyleNone,
|
|
FillStyleForegroundColor,
|
|
FillStyleBackgroundColor,
|
|
FillStylePattern,
|
|
FillStyleGradient,
|
|
FillStyleStrokes
|
|
};
|
|
|
|
/// Set the current style with which to fill
|
|
void setFillStyle(FillStyle fillStyle) { m_fillStyle = fillStyle; }
|
|
/// Returns the current fill style
|
|
FillStyle fillStyle() const { return m_fillStyle; }
|
|
|
|
/// The style of the brush stroke around polygons and so
|
|
enum StrokeStyle {
|
|
StrokeStyleNone,
|
|
StrokeStyleBrush
|
|
};
|
|
|
|
/// Set the current brush stroke style
|
|
void setStrokeStyle(StrokeStyle strokeStyle) { m_strokeStyle = strokeStyle; }
|
|
/// Returns the current brush stroke style
|
|
StrokeStyle strokeStyle() const { return m_strokeStyle; }
|
|
|
|
/// Set the opacity which is used in painting (like filling polygons)
|
|
void setOpacity(Q_UINT8 opacity) { m_opacity = opacity; }
|
|
/// Returns the opacity that is used in painting
|
|
Q_UINT8 opacity() const { return m_opacity; }
|
|
|
|
/**
|
|
* Sets the current composite operation. Everything painted will be composited on
|
|
* the destination layer with this composite op.
|
|
**/
|
|
void setCompositeOp(const KisCompositeOp& op) { m_compositeOp = op; }
|
|
/// Returns the current composite operation
|
|
KisCompositeOp compositeOp() const { return m_compositeOp; }
|
|
|
|
/// Sets the current KisFilter, used by the paintops that support it (like KisFilterOp)
|
|
void setFilter(KisFilterSP filter) { m_filter = filter; }
|
|
/// Returns the current KisFilter
|
|
KisFilterSP filter() { return m_filter; }
|
|
|
|
/**
|
|
* The offset for paint operations that use it (like KisDuplicateOp). It will use as source
|
|
* the part of the layer that is at its paintedPosition - duplicateOffset
|
|
*/
|
|
// TODO: this is an hack ! it must be fix, the following functions have nothing to do here
|
|
void setDuplicateOffset(const KisPoint& offset) { m_duplicateOffset = offset; }
|
|
/// Returns the offset for duplication
|
|
KisPoint duplicateOffset(){ return m_duplicateOffset; }
|
|
|
|
inline void setDuplicateHealing(bool v) { m_duplicateHealing = v; }
|
|
inline bool duplicateHealing() { return m_duplicateHealing; }
|
|
|
|
inline void setDuplicateHealingRadius(int r) { m_duplicateHealingRadius = r; }
|
|
inline int duplicateHealingRadius() { return m_duplicateHealingRadius; }
|
|
|
|
inline void setDuplicatePerspectiveCorrection(bool v) { m_duplicatePerspectiveCorrection = v; }
|
|
inline bool duplicatePerspectiveCorrection() { return m_duplicatePerspectiveCorrection; }
|
|
|
|
void setDuplicateStart(const KisPoint start) { m_duplicateStart = start;}
|
|
KisPoint duplicateStart() { return m_duplicateStart;}
|
|
|
|
/// Sets the current pressure for things that like to use this
|
|
void setPressure(double pressure) { m_pressure = pressure; }
|
|
/// Returns the current pressure
|
|
double pressure() { return m_pressure; }
|
|
|
|
/**
|
|
* Set the current paint operation. This is used for all drawing functions.
|
|
* The painter will DELETE the paint op itself!!
|
|
* That means no that you should not delete it yourself (or put it on the stack)
|
|
*/
|
|
void setPaintOp(KisPaintOp * paintOp) { delete m_paintOp; m_paintOp = paintOp; }
|
|
/// Returns the current paint operation
|
|
KisPaintOp * paintOp() const { return m_paintOp; }
|
|
|
|
/// Set a current 'dab'. This usually is a paint device containing a rendered brush
|
|
void setDab(KisPaintDeviceSP dab) { m_dab = dab; }
|
|
/// Get the currently set dab
|
|
KisPaintDeviceSP dab() const { return m_dab; }
|
|
|
|
/// Is cancel Requested by the KisProgressSubject for this painter
|
|
bool cancelRequested() const { return m_cancelRequested; }
|
|
|
|
protected:
|
|
/// Initialize, set everything to '0' or defaults
|
|
void init();
|
|
KisPainter(const KisPainter&);
|
|
KisPainter& operator=(const KisPainter&);
|
|
|
|
/// Calculate the distance that point p is from the line made by connecting l0 and l1
|
|
static double pointToLineDistance(const KisPoint& p, const KisPoint& l0, const KisPoint& l1);
|
|
|
|
/// Fill the polygon defined by points with the fillStyle
|
|
void fillPolygon(const vKisPoint& points, FillStyle fillStyle);
|
|
|
|
protected:
|
|
KisPaintDeviceSP m_device;
|
|
KisTransaction *m_transaction;
|
|
|
|
QRect m_dirtyRect;
|
|
|
|
KisColor m_paintColor;
|
|
KisColor m_backgroundColor;
|
|
KisColor m_fillColor;
|
|
FillStyle m_fillStyle;
|
|
StrokeStyle m_strokeStyle;
|
|
KisBrush *m_brush;
|
|
KisPattern *m_pattern;
|
|
KisPoint m_duplicateOffset;
|
|
KisPoint m_duplicateStart;
|
|
bool m_duplicateHealing;
|
|
int m_duplicateHealingRadius;
|
|
bool m_duplicatePerspectiveCorrection;
|
|
Q_UINT8 m_opacity;
|
|
KisCompositeOp m_compositeOp;
|
|
KisFilterSP m_filter;
|
|
KisPaintOp * m_paintOp;
|
|
double m_pressure;
|
|
bool m_cancelRequested;
|
|
Q_INT32 m_pixelSize;
|
|
KisColorSpace * m_colorSpace;
|
|
KisProfile * m_profile;
|
|
KisPaintDeviceSP m_dab;
|
|
bool m_varyBrushSpacingWithPressureWhenDrawingALine;
|
|
|
|
};
|
|
|
|
|
|
#endif // KIS_PAINTER_H_
|
|
|