2009-12-28 01:22:13 +00:00
|
|
|
/***************************************************************************
|
|
|
|
|
|
|
|
cpaint_impl.cpp
|
|
|
|
|
|
|
|
(c) 2000-2009 Benoît Minisini <gambas@users.sourceforge.net>
|
|
|
|
|
|
|
|
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#define __CPAINT_IMPL_CPP
|
|
|
|
|
|
|
|
#ifdef OS_SOLARIS
|
|
|
|
/* Make math.h define M_PI and a few other things */
|
|
|
|
#define __EXTENSIONS__
|
|
|
|
/* Get definition for finite() */
|
|
|
|
#include <ieeefp.h>
|
|
|
|
#endif
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QPen>
|
|
|
|
#include <QBrush>
|
|
|
|
#ifndef NO_X_WINDOW
|
|
|
|
#include <QX11Info>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "gambas.h"
|
|
|
|
|
|
|
|
#include "CConst.h"
|
|
|
|
#include "CFont.h"
|
|
|
|
#include "CWidget.h"
|
|
|
|
#include "CWindow.h"
|
|
|
|
#include "CPicture.h"
|
|
|
|
#include "CImage.h"
|
|
|
|
#include "CDrawingArea.h"
|
|
|
|
#include "CColor.h"
|
|
|
|
#include "CDraw.h"
|
2010-01-01 02:12:35 +00:00
|
|
|
#include "cprinter.h"
|
2010-01-01 21:32:45 +00:00
|
|
|
#include "csvgimage.h"
|
2009-12-28 01:22:13 +00:00
|
|
|
#include "cpaint_impl.h"
|
|
|
|
|
|
|
|
#define EXTRA(d) ((QT_PAINT_EXTRA *)d->extra)
|
|
|
|
|
|
|
|
#define COLOR_TO_INT(color) ((color).rgba() ^ 0xFF000000)
|
|
|
|
#define MASK_COLOR(col) ((col & 0xFF000000) ? Qt::color0 : Qt::color1)
|
|
|
|
|
|
|
|
#define PAINTER(d) EXTRA(d)->painter
|
|
|
|
#define PATH(d) EXTRA(d)->path
|
2009-12-30 16:13:23 +00:00
|
|
|
#define CLIP(d) EXTRA(d)->clip
|
2009-12-28 01:22:13 +00:00
|
|
|
|
2009-12-29 18:08:06 +00:00
|
|
|
static inline qreal to_deg(float angle)
|
|
|
|
{
|
|
|
|
return (qreal)(angle * 180 / M_PI);
|
|
|
|
}
|
|
|
|
|
2009-12-28 01:22:13 +00:00
|
|
|
static bool init_painting(GB_PAINT *d, QPaintDevice *device)
|
|
|
|
{
|
2009-12-29 21:42:40 +00:00
|
|
|
QPen pen;
|
|
|
|
|
2009-12-28 01:22:13 +00:00
|
|
|
d->width = device->width();
|
|
|
|
d->height = device->height();
|
|
|
|
d->resolutionX = device->physicalDpiX();
|
|
|
|
d->resolutionY = device->physicalDpiY();
|
|
|
|
|
|
|
|
if (device->paintingActive())
|
|
|
|
{
|
|
|
|
GB.Error("Device already being painted");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXTRA(d)->painter = new QPainter(device);
|
|
|
|
EXTRA(d)->path = 0;
|
2009-12-30 16:13:23 +00:00
|
|
|
EXTRA(d)->clip = 0;
|
2009-12-28 01:22:13 +00:00
|
|
|
PAINTER(d)->setRenderHints(QPainter::Antialiasing, true);
|
|
|
|
PAINTER(d)->setRenderHints(QPainter::TextAntialiasing, true);
|
|
|
|
PAINTER(d)->setRenderHints(QPainter::SmoothPixmapTransform, true);
|
|
|
|
|
2009-12-29 21:42:40 +00:00
|
|
|
pen = PAINTER(d)->pen();
|
|
|
|
pen.setCapStyle(Qt::FlatCap);
|
2009-12-30 02:15:00 +00:00
|
|
|
pen.setJoinStyle(Qt::MiterJoin);
|
2009-12-29 21:42:40 +00:00
|
|
|
pen.setMiterLimit(10.0);
|
|
|
|
pen.setWidthF(2.0);
|
|
|
|
PAINTER(d)->setPen(pen);
|
2009-12-30 00:12:09 +00:00
|
|
|
PAINTER(d)->setBrush(Qt::black);
|
2009-12-28 01:22:13 +00:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int Begin(GB_PAINT *d)
|
|
|
|
{
|
|
|
|
void *device = d->device;
|
2009-12-29 01:21:39 +00:00
|
|
|
QPaintDevice *target = NULL;
|
2009-12-28 01:22:13 +00:00
|
|
|
|
|
|
|
if (GB.Is(device, CLASS_Picture))
|
|
|
|
{
|
|
|
|
QPixmap *pixmap = ((CPICTURE *)device)->pixmap;
|
|
|
|
|
|
|
|
if (pixmap->isNull())
|
|
|
|
{
|
|
|
|
GB.Error("Bad picture");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
target = pixmap;
|
|
|
|
}
|
|
|
|
else if (GB.Is(device, CLASS_Image))
|
|
|
|
{
|
|
|
|
QImage *image = CIMAGE_get((CIMAGE *)device);
|
|
|
|
|
|
|
|
if (image->isNull())
|
|
|
|
{
|
|
|
|
GB.Error("Bad image");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
target = image;
|
|
|
|
}
|
|
|
|
else if (GB.Is(device, CLASS_DrawingArea))
|
|
|
|
{
|
|
|
|
MyDrawingArea *wid = (MyDrawingArea *)(((CWIDGET *)device)->widget);
|
|
|
|
|
|
|
|
if (wid->isCached())
|
|
|
|
target = wid->background();
|
|
|
|
else if (wid->cache)
|
|
|
|
target = wid->cache;
|
|
|
|
else
|
|
|
|
target = wid;
|
|
|
|
|
|
|
|
wid->drawn++;
|
|
|
|
}
|
2010-01-01 02:12:35 +00:00
|
|
|
else if (GB.Is(device, CLASS_Printer))
|
|
|
|
{
|
|
|
|
CPRINTER *printer = (CPRINTER *)device;
|
|
|
|
|
|
|
|
if (!printer->printing)
|
|
|
|
{
|
|
|
|
GB.Error("Printer is not printing");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
target = printer->printer;
|
|
|
|
}
|
2010-01-01 21:32:45 +00:00
|
|
|
else if (GB.Is(device, CLASS_SvgImage))
|
|
|
|
{
|
|
|
|
CSVGIMAGE *svgimage = (CSVGIMAGE *)device;
|
|
|
|
target = SVGIMAGE_init(svgimage);
|
|
|
|
if (!target)
|
|
|
|
{
|
|
|
|
GB.Error("SvgImage size is not defined");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
2009-12-28 01:22:13 +00:00
|
|
|
|
|
|
|
return init_painting(d, target);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void End(GB_PAINT *d)
|
|
|
|
{
|
|
|
|
void *device = d->device;
|
|
|
|
|
|
|
|
if (GB.Is(device, CLASS_DrawingArea))
|
|
|
|
{
|
|
|
|
MyDrawingArea *wid = (MyDrawingArea *)(((CWIDGET *)device)->widget);
|
|
|
|
|
|
|
|
if (wid)
|
|
|
|
{
|
|
|
|
if (wid->isCached())
|
|
|
|
{
|
|
|
|
wid->setBackground();
|
|
|
|
wid->refreshBackground();
|
|
|
|
}
|
|
|
|
|
|
|
|
wid->drawn--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete EXTRA(d)->path;
|
2009-12-30 16:13:23 +00:00
|
|
|
delete EXTRA(d)->clip;
|
2009-12-28 01:22:13 +00:00
|
|
|
delete EXTRA(d)->painter;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Save(GB_PAINT *d)
|
|
|
|
{
|
|
|
|
PAINTER(d)->save();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Restore(GB_PAINT *d)
|
|
|
|
{
|
|
|
|
PAINTER(d)->restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void apply_font(QFont &font, void *object = 0)
|
|
|
|
{
|
|
|
|
GB_PAINT *d = (GB_PAINT *)DRAW.Paint.GetCurrent();
|
|
|
|
|
|
|
|
PAINTER(d)->setFont(font);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Font(GB_PAINT *d, int set, GB_FONT *font)
|
|
|
|
{
|
|
|
|
if (set)
|
|
|
|
PAINTER(d)->setFont(*((CFONT *)(*font))->font);
|
|
|
|
else
|
|
|
|
*font = CFONT_create(PAINTER(d)->font(), apply_font);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void init_path(GB_PAINT *d)
|
|
|
|
{
|
|
|
|
switch (EXTRA(d)->fillRule)
|
|
|
|
{
|
|
|
|
case GB_PAINT_FILL_RULE_WINDING:
|
|
|
|
PATH(d)->setFillRule(Qt::WindingFill);
|
|
|
|
break;
|
|
|
|
case GB_PAINT_FILL_RULE_EVEN_ODD:
|
|
|
|
default:
|
|
|
|
PATH(d)->setFillRule(Qt::OddEvenFill);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CHECK_PATH(_d) \
|
|
|
|
if (!PATH(_d)) \
|
|
|
|
return; \
|
|
|
|
else \
|
|
|
|
init_path(_d);
|
|
|
|
|
|
|
|
#define PRESERVE_PATH(_d, _p) \
|
|
|
|
if (!(_p)) \
|
|
|
|
{ \
|
|
|
|
delete PATH(_d); \
|
|
|
|
EXTRA(_d)->path = 0; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CREATE_PATH(_d) \
|
|
|
|
if (!PATH(_d)) \
|
|
|
|
EXTRA(_d)->path = new QPainterPath();
|
|
|
|
|
|
|
|
static void Clip(GB_PAINT *d, int preserve)
|
|
|
|
{
|
|
|
|
CHECK_PATH(d);
|
2009-12-30 16:13:23 +00:00
|
|
|
|
|
|
|
QPainterPath path = PAINTER(d)->worldTransform().map(*PATH(d));
|
|
|
|
|
|
|
|
if (CLIP(d))
|
|
|
|
path = CLIP(d)->intersected(path);
|
|
|
|
|
|
|
|
delete EXTRA(d)->clip;
|
|
|
|
EXTRA(d)->clip = new QPainterPath(path);
|
|
|
|
|
2009-12-28 01:22:13 +00:00
|
|
|
PRESERVE_PATH(d, preserve);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ResetClip(GB_PAINT *d)
|
|
|
|
{
|
2009-12-30 16:13:23 +00:00
|
|
|
delete CLIP(d);
|
|
|
|
EXTRA(d)->clip = 0;
|
2009-12-28 01:22:13 +00:00
|
|
|
}
|
|
|
|
|
2009-12-30 16:13:23 +00:00
|
|
|
static void get_path_extents(QPainterPath *path, GB_EXTENTS *ext)
|
2009-12-28 01:22:13 +00:00
|
|
|
{
|
2009-12-30 16:13:23 +00:00
|
|
|
if (!path)
|
|
|
|
{
|
|
|
|
ext->x1 = ext->x2 = ext->y1 = ext->y2 = 0.0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRectF rect = path->boundingRect();
|
2009-12-28 01:22:13 +00:00
|
|
|
|
|
|
|
ext->x1 = (float)rect.left();
|
|
|
|
ext->y1 = (float)rect.top();
|
|
|
|
ext->x2 = (float)rect.right();
|
|
|
|
ext->y2 = (float)rect.bottom();
|
|
|
|
}
|
2009-12-30 16:13:23 +00:00
|
|
|
|
|
|
|
static void ClipExtents(GB_PAINT *d, GB_EXTENTS *ext)
|
|
|
|
{
|
|
|
|
get_path_extents(CLIP(d), ext);
|
|
|
|
}
|
2009-12-28 01:22:13 +00:00
|
|
|
|
|
|
|
static void Fill(GB_PAINT *d, int preserve)
|
|
|
|
{
|
|
|
|
CHECK_PATH(d);
|
2009-12-30 16:13:23 +00:00
|
|
|
|
|
|
|
if (!CLIP(d))
|
|
|
|
PAINTER(d)->fillPath(*PATH(d), PAINTER(d)->brush());
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QPainterPath path = PAINTER(d)->worldTransform().inverted().map(*CLIP(d));
|
|
|
|
path = path.intersected(*PATH(d));
|
|
|
|
PAINTER(d)->fillPath(path, PAINTER(d)->brush());
|
|
|
|
}
|
|
|
|
|
2009-12-28 01:22:13 +00:00
|
|
|
PRESERVE_PATH(d, preserve);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Stroke(GB_PAINT *d, int preserve)
|
|
|
|
{
|
|
|
|
CHECK_PATH(d);
|
2009-12-30 16:13:23 +00:00
|
|
|
|
|
|
|
if (!CLIP(d))
|
|
|
|
PAINTER(d)->strokePath(*PATH(d), PAINTER(d)->pen());
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QPainterPathStroker stroker;
|
|
|
|
QPen pen = PAINTER(d)->pen();
|
|
|
|
|
|
|
|
stroker.setCapStyle(pen.capStyle());
|
|
|
|
stroker.setDashOffset(pen.dashOffset());
|
|
|
|
stroker.setDashPattern(pen.dashPattern());
|
|
|
|
stroker.setJoinStyle(pen.joinStyle());
|
|
|
|
stroker.setMiterLimit(pen.miterLimit());
|
|
|
|
stroker.setWidth(pen.widthF());
|
|
|
|
|
|
|
|
QPainterPath path = PAINTER(d)->worldTransform().inverted().map(*CLIP(d));
|
|
|
|
path = path.intersected(stroker.createStroke(*PATH(d)));
|
|
|
|
PAINTER(d)->fillPath(path, PAINTER(d)->brush());
|
|
|
|
}
|
|
|
|
|
2009-12-28 01:22:13 +00:00
|
|
|
PRESERVE_PATH(d, preserve);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PathExtents(GB_PAINT *d, GB_EXTENTS *ext)
|
|
|
|
{
|
2009-12-30 16:13:23 +00:00
|
|
|
get_path_extents(PATH(d), ext);
|
2009-12-28 01:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int PathContains(GB_PAINT *d, float x, float y)
|
|
|
|
{
|
|
|
|
if (!PATH(d))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
QPointF point((qreal)x, (qreal)y);
|
|
|
|
return PATH(d)->contains(point);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void Dash(GB_PAINT *d, int set, float **dashes, int *count)
|
|
|
|
{
|
|
|
|
QPen pen = PAINTER(d)->pen();
|
|
|
|
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
if (!*count)
|
|
|
|
pen.setStyle(Qt::SolidLine);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QVector<qreal> dv;
|
|
|
|
for (int i = 0; i < *count; i++)
|
|
|
|
dv << (qreal)(*dashes)[i];
|
|
|
|
pen.setStyle(Qt::CustomDashLine);
|
|
|
|
pen.setDashPattern(dv);
|
|
|
|
}
|
|
|
|
PAINTER(d)->setPen(pen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pen.style() == Qt::CustomDashLine)
|
|
|
|
{
|
|
|
|
QVector<qreal> dv = pen.dashPattern();
|
|
|
|
*count = dv.count();
|
|
|
|
GB.Alloc(POINTER(dashes), sizeof(float) * *count);
|
|
|
|
for (int i = 0; i < *count; i++)
|
|
|
|
(*dashes)[i] = (float)dv[i];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*count = 0;
|
|
|
|
*dashes = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DashOffset(GB_PAINT *d, int set, float *offset)
|
|
|
|
{
|
|
|
|
QPen pen = PAINTER(d)->pen();
|
|
|
|
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
pen.setDashOffset((qreal)*offset);
|
|
|
|
PAINTER(d)->setPen(pen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*offset = (float)pen.dashOffset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void FillRule(GB_PAINT *d, int set, int *value)
|
|
|
|
{
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
EXTRA(d)->fillRule = *value;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*value = EXTRA(d)->fillRule;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LineCap(GB_PAINT *d, int set, int *value)
|
|
|
|
{
|
|
|
|
QPen pen = PAINTER(d)->pen();
|
|
|
|
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
switch (*value)
|
|
|
|
{
|
|
|
|
case GB_PAINT_LINE_CAP_ROUND:
|
|
|
|
pen.setCapStyle(Qt::RoundCap); break;
|
|
|
|
case GB_PAINT_LINE_CAP_SQUARE:
|
|
|
|
pen.setCapStyle(Qt::SquareCap); break;
|
|
|
|
case GB_PAINT_LINE_CAP_BUTT:
|
|
|
|
default:
|
|
|
|
pen.setCapStyle(Qt::FlatCap);
|
|
|
|
}
|
|
|
|
PAINTER(d)->setPen(pen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (pen.capStyle())
|
|
|
|
{
|
|
|
|
case Qt::RoundCap: *value = GB_PAINT_LINE_CAP_ROUND; break;
|
|
|
|
case Qt::SquareCap: *value = GB_PAINT_LINE_CAP_SQUARE; break;
|
|
|
|
case Qt::FlatCap: default: *value = GB_PAINT_LINE_CAP_BUTT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LineJoin(GB_PAINT *d, int set, int *value)
|
|
|
|
{
|
|
|
|
QPen pen = PAINTER(d)->pen();
|
|
|
|
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
switch (*value)
|
|
|
|
{
|
|
|
|
case GB_PAINT_LINE_JOIN_ROUND:
|
|
|
|
pen.setJoinStyle(Qt::RoundJoin); break;
|
|
|
|
case GB_PAINT_LINE_JOIN_BEVEL:
|
|
|
|
pen.setJoinStyle(Qt::BevelJoin); break;
|
|
|
|
case GB_PAINT_LINE_JOIN_MITER:
|
|
|
|
default:
|
|
|
|
pen.setJoinStyle(Qt::MiterJoin);
|
|
|
|
}
|
|
|
|
PAINTER(d)->setPen(pen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (pen.joinStyle())
|
|
|
|
{
|
|
|
|
case Qt::RoundJoin: *value = GB_PAINT_LINE_JOIN_ROUND; break;
|
|
|
|
case Qt::BevelJoin: *value = GB_PAINT_LINE_JOIN_BEVEL; break;
|
|
|
|
case Qt::MiterJoin: default: *value = GB_PAINT_LINE_JOIN_MITER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LineWidth(GB_PAINT *d, int set, float *value)
|
|
|
|
{
|
|
|
|
QPen pen = PAINTER(d)->pen();
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
pen.setWidthF((qreal)*value);
|
|
|
|
PAINTER(d)->setPen(pen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*value = (float)pen.widthF();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void MiterLimit(GB_PAINT *d, int set, float *value)
|
|
|
|
{
|
|
|
|
QPen pen = PAINTER(d)->pen();
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
pen.setMiterLimit((qreal)*value);
|
|
|
|
PAINTER(d)->setPen(pen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*value = (float)pen.miterLimit();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void Operator(GB_PAINT *d, int set, int *value)
|
|
|
|
{
|
|
|
|
QPainter::CompositionMode mode;
|
|
|
|
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
switch (*value)
|
|
|
|
{
|
|
|
|
case GB_PAINT_OPERATOR_CLEAR: mode = QPainter::CompositionMode_Clear; break;
|
|
|
|
case GB_PAINT_OPERATOR_SOURCE: mode = QPainter::CompositionMode_Source; break;
|
|
|
|
case GB_PAINT_OPERATOR_IN: mode = QPainter::CompositionMode_SourceIn; break;
|
|
|
|
case GB_PAINT_OPERATOR_OUT: mode = QPainter::CompositionMode_SourceOut; break;
|
|
|
|
case GB_PAINT_OPERATOR_ATOP: mode = QPainter::CompositionMode_SourceAtop; break;
|
|
|
|
case GB_PAINT_OPERATOR_DEST: mode = QPainter::CompositionMode_Destination; break;
|
|
|
|
case GB_PAINT_OPERATOR_DEST_OVER: mode = QPainter::CompositionMode_DestinationOver; break;
|
|
|
|
case GB_PAINT_OPERATOR_DEST_IN: mode = QPainter::CompositionMode_DestinationIn; break;
|
|
|
|
case GB_PAINT_OPERATOR_DEST_OUT: mode = QPainter::CompositionMode_DestinationOut; break;
|
|
|
|
case GB_PAINT_OPERATOR_DEST_ATOP: mode = QPainter::CompositionMode_DestinationAtop; break;
|
|
|
|
case GB_PAINT_OPERATOR_XOR: mode = QPainter::CompositionMode_Xor; break;
|
|
|
|
case GB_PAINT_OPERATOR_ADD: mode = QPainter::CompositionMode_Plus; break;
|
|
|
|
case GB_PAINT_OPERATOR_SATURATE: mode = QPainter::CompositionMode_Multiply; break;
|
|
|
|
case GB_PAINT_OPERATOR_OVER: default: mode = QPainter::CompositionMode_SourceOver;
|
|
|
|
}
|
|
|
|
PAINTER(d)->setCompositionMode(mode);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (PAINTER(d)->compositionMode())
|
|
|
|
{
|
|
|
|
case QPainter::CompositionMode_Clear: *value = GB_PAINT_OPERATOR_CLEAR; break;
|
|
|
|
case QPainter::CompositionMode_Source: *value = GB_PAINT_OPERATOR_SOURCE; break;
|
|
|
|
case QPainter::CompositionMode_SourceIn: *value = GB_PAINT_OPERATOR_IN; break;
|
|
|
|
case QPainter::CompositionMode_SourceOut: *value = GB_PAINT_OPERATOR_OUT; break;
|
|
|
|
case QPainter::CompositionMode_SourceAtop: *value = GB_PAINT_OPERATOR_ATOP; break;
|
|
|
|
case QPainter::CompositionMode_Destination: *value = GB_PAINT_OPERATOR_DEST; break;
|
|
|
|
case QPainter::CompositionMode_DestinationOver: *value = GB_PAINT_OPERATOR_DEST_OVER; break;
|
|
|
|
case QPainter::CompositionMode_DestinationIn: *value = GB_PAINT_OPERATOR_DEST_IN; break;
|
|
|
|
case QPainter::CompositionMode_DestinationOut: *value = GB_PAINT_OPERATOR_DEST_OUT; break;
|
|
|
|
case QPainter::CompositionMode_DestinationAtop: *value = GB_PAINT_OPERATOR_DEST_ATOP; break;
|
|
|
|
case QPainter::CompositionMode_Xor: *value = GB_PAINT_OPERATOR_XOR; break;
|
|
|
|
case QPainter::CompositionMode_Plus: *value = GB_PAINT_OPERATOR_ADD; break;
|
|
|
|
case QPainter::CompositionMode_Multiply: *value = GB_PAINT_OPERATOR_SATURATE; break;
|
|
|
|
case QPainter::CompositionMode_SourceOver: default: *value = GB_PAINT_OPERATOR_OVER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void NewPath(GB_PAINT *d)
|
|
|
|
{
|
|
|
|
PRESERVE_PATH(d, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ClosePath(GB_PAINT *d)
|
|
|
|
{
|
|
|
|
CHECK_PATH(d);
|
|
|
|
PATH(d)->closeSubpath();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void Arc(GB_PAINT *d, float xc, float yc, float radius, float angle, float length)
|
|
|
|
{
|
|
|
|
CREATE_PATH(d);
|
|
|
|
|
|
|
|
QRectF rect;
|
|
|
|
rect.setCoords((qreal)(xc - radius), (qreal)(yc - radius), (qreal)(xc + radius), (qreal)(yc + radius));
|
|
|
|
|
2009-12-29 18:08:06 +00:00
|
|
|
PATH(d)->arcMoveTo(rect, to_deg(angle));
|
|
|
|
PATH(d)->arcTo(rect, to_deg(angle), to_deg(length));
|
2009-12-28 01:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void Rectangle(GB_PAINT *d, float x, float y, float width, float height)
|
|
|
|
{
|
|
|
|
CREATE_PATH(d);
|
|
|
|
PATH(d)->addRect((qreal)x, (qreal)y, (qreal)width, (qreal)height);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void GetCurrentPoint(GB_PAINT *d, float *x, float *y)
|
|
|
|
{
|
|
|
|
if (!PATH(d))
|
|
|
|
{
|
|
|
|
*x = 0;
|
|
|
|
*y = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QPointF pt = PATH(d)->currentPosition();
|
|
|
|
*x = (float)pt.x();
|
|
|
|
*y = (float)pt.y();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void MoveTo(GB_PAINT *d, float x, float y)
|
|
|
|
{
|
|
|
|
CREATE_PATH(d);
|
|
|
|
PATH(d)->moveTo((qreal)x, (qreal)y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LineTo(GB_PAINT *d, float x, float y)
|
|
|
|
{
|
|
|
|
CREATE_PATH(d);
|
|
|
|
PATH(d)->lineTo((qreal)x, (qreal)y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CurveTo(GB_PAINT *d, float x1, float y1, float x2, float y2, float x3, float y3)
|
|
|
|
{
|
|
|
|
CREATE_PATH(d);
|
|
|
|
PATH(d)->cubicTo(QPointF((qreal)x1, (qreal)y1), QPointF((qreal)x2, (qreal)y2), QPointF((qreal)x3, (qreal)y3));
|
|
|
|
}
|
|
|
|
|
2009-12-29 21:42:40 +00:00
|
|
|
static GB_PAINT *_draw_text_p;
|
|
|
|
|
|
|
|
static void draw_text_cb(float x, float y, QString &text)
|
|
|
|
{
|
|
|
|
PATH(_draw_text_p)->addText(x, y, PAINTER(_draw_text_p)->font(), text);
|
|
|
|
}
|
2009-12-28 01:22:13 +00:00
|
|
|
|
2009-12-29 18:08:06 +00:00
|
|
|
static void Text(GB_PAINT *d, const char *text, int len, float w, float h, int align)
|
|
|
|
{
|
2009-12-29 21:42:40 +00:00
|
|
|
QPointF pos;
|
|
|
|
|
2009-12-29 18:08:06 +00:00
|
|
|
CREATE_PATH(d);
|
2009-12-29 21:42:40 +00:00
|
|
|
|
|
|
|
pos = PATH(d)->currentPosition();
|
|
|
|
_draw_text_p = d;
|
2009-12-29 18:08:06 +00:00
|
|
|
|
2009-12-30 21:55:35 +00:00
|
|
|
if (w <= 0 || h <= 0)
|
|
|
|
pos.ry() -= PAINTER(d)->fontMetrics().ascent();
|
|
|
|
|
2009-12-29 21:42:40 +00:00
|
|
|
DRAW_text_with(PAINTER(d), text, len, pos.x(), pos.y(), w, h, align, draw_text_cb);
|
2009-12-28 01:22:13 +00:00
|
|
|
}
|
|
|
|
|
2010-01-01 22:19:11 +00:00
|
|
|
static void TextExtents(GB_PAINT *d, const char *text, int len, GB_EXTENTS *ext)
|
2009-12-28 01:22:13 +00:00
|
|
|
{
|
|
|
|
QRectF rect = PAINTER(d)->boundingRect(QRectF(0, 0, d->width, d->height), Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine | Qt::TextIncludeTrailingSpaces, QString::fromUtf8(text, len));
|
|
|
|
|
|
|
|
ext->x1 = 0;
|
|
|
|
ext->y1 = 0;
|
|
|
|
ext->x2 = (float)rect.width();
|
|
|
|
ext->y2 = (float)rect.height();
|
2010-01-01 22:19:11 +00:00
|
|
|
}
|
2009-12-28 01:22:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
static void Matrix(GB_PAINT *d, int set, GB_TRANSFORM matrix)
|
|
|
|
{
|
|
|
|
QTransform *t = (QTransform *)matrix;
|
|
|
|
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
if (t)
|
|
|
|
PAINTER(d)->setWorldTransform(*t);
|
|
|
|
else
|
|
|
|
PAINTER(d)->resetTransform();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*t = PAINTER(d)->worldTransform();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-29 01:21:39 +00:00
|
|
|
static void SetBrush(GB_PAINT *d, GB_BRUSH brush)
|
2009-12-28 01:22:13 +00:00
|
|
|
{
|
|
|
|
QBrush *b = (QBrush *)brush;
|
|
|
|
PAINTER(d)->setBrush(*b);
|
|
|
|
|
|
|
|
QPen p = PAINTER(d)->pen();
|
|
|
|
p.setBrush(*b);
|
|
|
|
PAINTER(d)->setPen(p);
|
2009-12-29 01:21:39 +00:00
|
|
|
//PAINTER(d)->setBrushOrigin(QPointF((qreal)x, (qreal)y));
|
2009-12-28 01:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void BrushFree(GB_BRUSH brush)
|
|
|
|
{
|
|
|
|
delete (QBrush *)brush;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void BrushColor(GB_BRUSH *brush, GB_COLOR color)
|
|
|
|
{
|
|
|
|
QBrush *br = new QBrush(CCOLOR_make(color));
|
|
|
|
*brush = (GB_BRUSH)br;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void BrushImage(GB_BRUSH *brush, GB_IMAGE image)
|
|
|
|
{
|
|
|
|
QImage *img = CIMAGE_get((CIMAGE *)image);
|
|
|
|
|
|
|
|
QBrush *br = new QBrush(*img);
|
2009-12-30 16:33:46 +00:00
|
|
|
*brush = (GB_BRUSH)br;
|
2009-12-28 01:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void BrushLinearGradient(GB_BRUSH *brush, float x0, float y0, float x1, float y1, int nstop, double *positions, GB_COLOR *colors, int extend)
|
|
|
|
{
|
|
|
|
QLinearGradient gradient;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
gradient.setStart((qreal)x0, (qreal)y0);
|
|
|
|
gradient.setFinalStop((qreal)x1, (qreal)y1);
|
|
|
|
|
|
|
|
for (i = 0; i < nstop; i++)
|
|
|
|
gradient.setColorAt((qreal)positions[i], CCOLOR_make(colors[i]));
|
|
|
|
|
|
|
|
switch (extend)
|
|
|
|
{
|
|
|
|
case GB_PAINT_EXTEND_REPEAT:
|
|
|
|
gradient.setSpread(QGradient::RepeatSpread); break;
|
|
|
|
case GB_PAINT_EXTEND_REFLECT:
|
|
|
|
gradient.setSpread(QGradient::ReflectSpread); break;
|
|
|
|
case GB_PAINT_EXTEND_PAD:
|
|
|
|
default:
|
|
|
|
gradient.setSpread(QGradient::PadSpread);
|
|
|
|
}
|
|
|
|
|
|
|
|
QBrush *br = new QBrush(gradient);
|
|
|
|
*brush = br;
|
|
|
|
}
|
|
|
|
|
2009-12-29 23:18:43 +00:00
|
|
|
static void BrushRadialGradient(GB_BRUSH *brush, float cx, float cy, float r, float fx, float fy, int nstop, double *positions, GB_COLOR *colors, int extend)
|
2009-12-28 01:22:13 +00:00
|
|
|
{
|
|
|
|
QRadialGradient gradient;
|
|
|
|
int i;
|
|
|
|
|
2009-12-29 23:18:43 +00:00
|
|
|
gradient.setCenter((qreal)cx, (qreal)cy);
|
|
|
|
gradient.setRadius((qreal)r);
|
|
|
|
gradient.setFocalPoint((qreal)fx, (qreal)fy);
|
2009-12-28 01:22:13 +00:00
|
|
|
|
|
|
|
for (i = 0; i < nstop; i++)
|
|
|
|
gradient.setColorAt((qreal)positions[i], CCOLOR_make(colors[i]));
|
|
|
|
|
|
|
|
switch (extend)
|
|
|
|
{
|
|
|
|
case GB_PAINT_EXTEND_REPEAT:
|
|
|
|
gradient.setSpread(QGradient::RepeatSpread); break;
|
|
|
|
case GB_PAINT_EXTEND_REFLECT:
|
|
|
|
gradient.setSpread(QGradient::ReflectSpread); break;
|
|
|
|
case GB_PAINT_EXTEND_PAD:
|
|
|
|
default:
|
|
|
|
gradient.setSpread(QGradient::PadSpread);
|
|
|
|
}
|
|
|
|
|
|
|
|
QBrush *br = new QBrush(gradient);
|
|
|
|
*brush = br;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void BrushMatrix(GB_BRUSH brush, int set, GB_TRANSFORM matrix)
|
|
|
|
{
|
|
|
|
QBrush *b = (QBrush *)brush;
|
|
|
|
QTransform *t = (QTransform *)matrix;
|
|
|
|
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
if (t)
|
|
|
|
b->setTransform(*t);
|
|
|
|
else
|
|
|
|
b->setTransform(QTransform());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*t = b->transform();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void TransformCreate(GB_TRANSFORM *matrix)
|
|
|
|
{
|
|
|
|
*matrix = (GB_TRANSFORM)(new QTransform());
|
|
|
|
}
|
|
|
|
|
|
|
|
static void TransformDelete(GB_TRANSFORM *matrix)
|
|
|
|
{
|
|
|
|
delete (QTransform *)*matrix;
|
|
|
|
*matrix = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void TransformInit(GB_TRANSFORM matrix, float xx, float yx, float xy, float yy, float x0, float y0)
|
|
|
|
{
|
|
|
|
QTransform *t = (QTransform *)matrix;
|
|
|
|
QMatrix m((qreal)xx, (qreal)yx, (qreal)xy, (qreal)yy, (qreal)x0, (qreal)y0);
|
|
|
|
QTransform t2(m);
|
|
|
|
*t = t2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void TransformTranslate(GB_TRANSFORM matrix, float tx, float ty)
|
|
|
|
{
|
|
|
|
QTransform *t = (QTransform *)matrix;
|
|
|
|
t->translate((qreal)tx, (qreal)ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void TransformScale(GB_TRANSFORM matrix, float sx, float sy)
|
|
|
|
{
|
|
|
|
QTransform *t = (QTransform *)matrix;
|
|
|
|
t->scale((qreal)sx, (qreal)sy);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void TransformRotate(GB_TRANSFORM matrix, float angle)
|
|
|
|
{
|
|
|
|
QTransform *t = (QTransform *)matrix;
|
2009-12-30 22:48:43 +00:00
|
|
|
t->rotate(to_deg(-angle));
|
2009-12-28 01:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int TransformInvert(GB_TRANSFORM matrix)
|
|
|
|
{
|
|
|
|
QTransform *t = (QTransform *)matrix;
|
|
|
|
bool inv;
|
|
|
|
QTransform it = t->inverted(&inv);
|
|
|
|
if (inv)
|
|
|
|
{
|
|
|
|
*t = it;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void TransformMultiply(GB_TRANSFORM matrix, GB_TRANSFORM matrix2)
|
|
|
|
{
|
|
|
|
QTransform *t = (QTransform *)matrix;
|
|
|
|
QTransform *t2 = (QTransform *)matrix2;
|
|
|
|
|
|
|
|
*t = *t * *t2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GB_PAINT_DESC PAINT_Interface = {
|
|
|
|
// Size of the GB_PAINT structure extra data
|
|
|
|
sizeof(QT_PAINT_EXTRA),
|
|
|
|
Begin,
|
|
|
|
End,
|
|
|
|
Save,
|
|
|
|
Restore,
|
|
|
|
Font,
|
|
|
|
Clip,
|
|
|
|
ResetClip,
|
|
|
|
ClipExtents,
|
|
|
|
Fill,
|
|
|
|
Stroke,
|
|
|
|
PathExtents,
|
|
|
|
PathContains,
|
|
|
|
Dash,
|
|
|
|
DashOffset,
|
|
|
|
FillRule,
|
|
|
|
LineCap,
|
|
|
|
LineJoin,
|
|
|
|
LineWidth,
|
|
|
|
MiterLimit,
|
|
|
|
Operator,
|
|
|
|
NewPath,
|
|
|
|
ClosePath,
|
|
|
|
Arc,
|
|
|
|
Rectangle,
|
|
|
|
GetCurrentPoint,
|
|
|
|
MoveTo,
|
|
|
|
LineTo,
|
|
|
|
CurveTo,
|
|
|
|
Text,
|
2010-01-01 22:19:11 +00:00
|
|
|
TextExtents,
|
2009-12-28 01:22:13 +00:00
|
|
|
Matrix,
|
|
|
|
SetBrush,
|
|
|
|
{
|
|
|
|
BrushFree,
|
|
|
|
BrushColor,
|
|
|
|
BrushImage,
|
|
|
|
BrushLinearGradient,
|
|
|
|
BrushRadialGradient,
|
|
|
|
BrushMatrix,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
TransformCreate,
|
|
|
|
TransformDelete,
|
|
|
|
TransformInit,
|
|
|
|
TransformTranslate,
|
|
|
|
TransformScale,
|
|
|
|
TransformRotate,
|
|
|
|
TransformInvert,
|
|
|
|
TransformMultiply
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void PAINT_begin(void *device)
|
|
|
|
{
|
|
|
|
DRAW.Paint.Begin(device);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PAINT_end()
|
|
|
|
{
|
|
|
|
DRAW.Paint.End();
|
|
|
|
}
|
|
|
|
|
|
|
|
QPainter *PAINT_get_current()
|
|
|
|
{
|
|
|
|
GB_PAINT *d = (GB_PAINT *)DRAW.Paint.GetCurrent();
|
|
|
|
return d ? PAINTER(d) : NULL;
|
|
|
|
}
|
|
|
|
|