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.

596 lines
19 KiB

/***************************************************************************
qsdrvqt.cpp
-------------------
begin : 01-January-2000
copyright : (C) 2000 by Kamil Dobkowski
email : kamildobk@poczta.onet.pl
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include"qsdrvqt.h"
#include<assert.h>
#include<math.h>
#include<qfont.h>
#include<qimage.h>
#include<qwidget.h>
#include<qpaintdevice.h>
#include <qsimplerichtext.h>
#include<iostream.h>
//-------------------------------------------------------------//
QSDrvQt::QSDrvQt()
:QSDrv()
{
dpi = 72;
m_delete_painter = false;
m_paint = NULL;
m_pixmap = NULL;
m_cfill.style = QSGFill::Transparent;
}
//-------------------------------------------------------------//
QSDrvQt::~QSDrvQt()
{
if ( m_delete_painter ) delete m_paint;
delete m_pixmap;
}
//-------------------------------------------------------------//
void QSDrvQt::setDC( QPainter *p, double new_dpi, bool delete_painter )
{
assert( p );
if ( m_delete_painter ) delete m_paint;
m_paint = p;
dpi = new_dpi;
m_delete_painter = delete_painter;
m_paint->moveTo( 0, 0 );
}
//-------------------------------------------------------------//
void QSDrvQt::startDrawing()
{
QSDrv::startDrawing();
}
//-------------------------------------------------------------//
void QSDrvQt::stopDrawing()
{
QSDrv::stopDrawing();
delete m_pixmap;
m_pixmap = NULL;
}
//-------------------------------------------------------------//
void QSDrvQt::clearCanvas( const QSGFill& f, const QSPt2f& pos, const QSPt2f& size )
{
m_paint->fillRect( toInt(pos.x), toInt(pos.y), toInt(size.x), toInt(size.y), toQBrush(f) );
}
//-------------------------------------------------------------//
void QSDrvQt::drawLine( const QSPt2f &begin, const QSPt2f &end )
{
m_paint->drawLine( toInt(begin.x), toInt(begin.y), toInt(end.x), toInt(end.y) );
}
//-------------------------------------------------------------//
void QSDrvQt::drawEllipse( const QSPt2f& p1, const QSPt2f& p2 )
{
m_paint->drawEllipse( toInt(p1.x), toInt(p1.y), toInt(p2.x-p1.x+1), toInt(p2.y-p1.y+1) );
}
//-------------------------------------------------------------//
void QSDrvQt::drawRect( const QSPt2f &p1, const QSPt2f &p2 )
{
m_paint->drawRect( toInt(p1.x), toInt(p1.y), toInt(p2.x-p1.x+1), toInt(p2.y-p1.y+1) );
}
//-------------------------------------------------------------//
void QSDrvQt::drawPoly( const QSPt2f p[], int npoints, const bool edges[], int edgeAutoColor )
{
if ( edges && m_curr_pen.style() != NoPen ) m_paint->setPen( NoPen );
else if ( edgeAutoColor ) set_auto_pen( edgeAutoColor );
if ( npoints > m_vert_array.size() ) m_vert_array.resize(npoints);
for( int i=0; i<npoints; i++ ) m_vert_array.setPoint( i, toInt(p[i].x), toInt(p[i].y) );
m_paint->drawPolygon( m_vert_array, FALSE, 0, npoints );
// draw edges
if ( edges && m_curr_pen.style() != NoPen ) {
if ( npoints*2 > m_edge_array.size() ) m_edge_array.resize(npoints*2);
int nlines = 0;
if ( edges[0] ) {
m_edge_array.putPoints( 0, 2, toInt(p[npoints-1].x),
toInt(p[npoints-1].y),
toInt(p[0].x),
toInt(p[0].y) );
nlines++;
}
for( int i=1; i<npoints; i++ ) if ( edges[i] ) {
m_edge_array.putPoints( nlines*2, 2, m_vert_array, i-1 );
nlines++;
}
if ( edgeAutoColor ) set_auto_pen( edgeAutoColor ); else m_paint->setPen( m_curr_pen );
m_paint->drawLineSegments( m_edge_array, 0, nlines );
}
}
//-------------------------------------------------------------//
void QSDrvQt::set_auto_pen( int autoColor )
{
m_paint->setPen( QPen( QColor(
QMIN(255,QMAX(0,m_cfill.color.r+autoColor)),
QMIN(255,QMAX(0,m_cfill.color.g+autoColor)),
QMIN(255,QMAX(0,m_cfill.color.b+autoColor))),
m_curr_pen.width(),
m_curr_pen.style() ) );
}
//cout << " npoints " << npoints << endl;
//if ( npoints < 3 ) cout << " NPOINTS < 3 " << endl << endl;
//-------------------------------------------------------------//
void QSDrvQt::drawText( const QSPt2f &pos, const QString& text, int align )
{
drawRText( pos, 0, text, align );
}
//-------------------------------------------------------------//
QSPt2f QSDrvQt::textSize( const QString& text )
{
QSimpleRichText label(text,toQFont(m_curr_font,72.0));
label.setWidth( 0x0fffffff );
return QSPt2f(label.widthUsed()*dpi/72.0,label.height()*dpi/72.0);
}
//-------------------------------------------------------------//
void QSDrvQt::drawRText( const QSPt2f &pos, int angle, const QString& text, int align )
{
QSimpleRichText label(text,toQFont(m_curr_font,72.0));
label.setWidth( 0x0fffffff );
label.setWidth( label.widthUsed() );
QColorGroup color; color.setColor( QColorGroup::Text, m_paint->pen().color() );
QPoint pos_aligned = align_rect(QRect(toInt(pos.x),toInt(pos.y),label.widthUsed(),label.height()),align);
bool xform = m_paint->hasWorldXForm();
m_paint->saveWorldMatrix();
m_paint->setWorldXForm( TRUE );
m_paint->translate( toInt(pos.x),
toInt(pos.y));
m_paint->rotate( angle );
m_paint->scale(dpi/72.0,dpi/72.0);
m_paint->translate( pos_aligned.x()-toInt(pos.x),
pos_aligned.y()-toInt(pos.y) );
label.draw( m_paint,
0, 0,
QRect(0,0,label.widthUsed(),label.height()),
color );
m_paint->restoreWorldMatrix();
m_paint->setWorldXForm( xform );
}
//-------------------------------------------------------------//
void QSDrvQt::getRTextBoundingPoly( QSPt2f out[4], const QSPt2f &pos, int angle, const QString& text, int align )
{
QSimpleRichText label(text,toQFont(m_curr_font,72.0));
label.setWidth( 0x0fffffff );
label.setWidth( label.widthUsed() );
QPoint pos_aligned = align_rect(QRect(toInt(pos.x),toInt(pos.y),label.widthUsed(),label.height()),align);
QWMatrix m;
m.translate(toInt(pos.x),
toInt(pos.y));
m.rotate( angle );
m.scale(dpi/72.0,dpi/72.0);
m.translate( pos_aligned.x()-toInt(pos.x),
pos_aligned.y()-toInt(pos.y) );
QPointArray pa = m.map(QPointArray(QRect(0,0,label.widthUsed(),label.height())));
for ( int i=0; i<4; i++ ) out[i].set( pa.point(i).x(), pa.point(i).y() );
}
//-------------------------------------------------------------//
QPoint QSDrvQt::align_rect( const QRect& r, int align )
{
QPoint p(r.x(),r.y());
if ( align & AlignRight ) p.setX( r.x()-r.width() );
else
if ( align & AlignHCenter ) p.setX( p.x()-r.width()/2 );
if ( align & AlignBottom ) p.setY( p.y()-r.height() );
else
if ( align & AlignVCenter ) p.setY( p.y()-r.height()/2 );
return p;
}
//-------------------------------------------------------------//
#define QSG2DRIVERQT_PIXMAP_BUFFER_SIZE 65536
void QSDrvQt::getPixmapBuffer( PixmapBuffer *buff, int pwidth, int pheight )
// always called before drawPixmap
{
if ( m_pixmap ) if ( m_pixmap->width() != pwidth ) {
delete m_pixmap;
m_pixmap = NULL;
}
if ( m_pixmap == NULL ) {
int height = QSG2DRIVERQT_PIXMAP_BUFFER_SIZE / pwidth / 4;
if ( height < 1 ) height = 1;
if ( height > pheight ) height = pheight;
m_pixmap = new QImage( pwidth, height, 32 );
}
buff->lines = m_pixmap->height();
buff->lo = m_pixmap->bytesPerLine();
buff->po = 4;
if ( QImage::systemByteOrder() == QImage::BigEndian ) {
buff->ptr = m_pixmap->bits();
buff->co = 1;
} else {
buff->ptr = m_pixmap->bits()+3;
buff->co = -1;
}
if ( buff->lines > pheight ) buff->lines = pheight;
}
//-------------------------------------------------------------//
void QSDrvQt::drawPixmap( const QSPt2f& pos, PixmapBuffer *buff )
// always draw the last requested m_pixmap buffer.
{
assert( m_pixmap );
// Preferences
m_paint->drawImage( toInt(pos.x), toInt(pos.y), *m_pixmap, 0, 0, m_pixmap->width(), buff->lines, Qt::ColorOnly | Qt::ThresholdDither | Qt::AvoidDither );
}
//-------------------------------------------------------------//
#define SPACE 3 // space length
#define DASH 6
#define DOT 2
#define PAD 0
const int QSDrvQt::defpatterns[4][6] = {
// line, space, line, space, ...
{ DASH, SPACE, DASH, SPACE, DASH, SPACE }, // dash
{ DOT, SPACE, DOT, SPACE, DOT, SPACE }, // dot
{ DASH, SPACE, DOT, SPACE, PAD, PAD }, // dash - dot
{ DASH, SPACE, DOT, SPACE, DOT, SPACE } // dash - dot - dot
};
//-------------------------------------------------------------//
void QSDrvQt::beginPolyline( const QSPt2f& pos )
{
// prepare pattern
const int *lpattern;
switch( m_line.style ) {
case QSGLine::Dash: lpattern = defpatterns[0]; break;
case QSGLine::Dot: lpattern = defpatterns[1]; break;
case QSGLine::DashDot: lpattern = defpatterns[2]; break;
case QSGLine::DashDotDot: lpattern = defpatterns[3]; break;
default: lpattern = NULL; break;
};
m_curr_polyline_style = m_line.style;
// scale pattern using dpi * line_width / 72
double scale = toPixels(QMAX((double )m_line.width,1.0));
if ( lpattern ) for( int i=0; i<6; i++ ) m_curr_polyline_pattern[i] = lpattern[i]*scale;
else m_curr_polyline_pattern[0] = -1.0;
// current position
m_curr_polyline_t = 0.0;
m_curr_polyline_pos = pos;
// pattern length
m_curr_polyline_pattern_length = 0.0;
for( int i=0; i<6; i++ ) m_curr_polyline_pattern_length += m_curr_polyline_pattern[i];
// convert a pattern from lengths to positons 5, 3, 5, 3 -> 5, 8, 13, 16
for( int i=1; i<6; i++ ) m_curr_polyline_pattern[i] += m_curr_polyline_pattern[i-1];
// set qt graphics context - always use solid line
QPen cpen = m_paint->pen();
if ( cpen.style() != Qt::NoPen ) { cpen.setStyle( Qt::SolidLine ); m_paint->setPen( cpen ); }
m_paint->moveTo( int(floor(pos.x+0.5)), int(floor(pos.y+0.5)) );
}
//-------------------------------------------------------------//
void QSDrvQt::drawPolylineTo( const QSPt2f& pos )
{
if ( m_curr_polyline_style != m_line.style ) { endPolyline(); beginPolyline( m_curr_polyline_pos ); }
// obvious cases
if ( m_curr_polyline_pattern[0] == -1.0 ) {
m_paint->lineTo( int(floor(pos.x+0.5)),
int(floor(pos.y+0.5)) );
return;
}
// length of this segment
double length = sqrt( (m_curr_polyline_pos.x-pos.x)*(m_curr_polyline_pos.x-pos.x) +
(m_curr_polyline_pos.y-pos.y)*(m_curr_polyline_pos.y-pos.y) );
// If t changes from min to max, (x,y) changes
// from (curr_polyline_pos.x,curr_polyline_pos.y) to (pos.x,pos.y)
double ax = length > 0.0 ? ( pos.x - m_curr_polyline_pos.x ) / length : 0.0;
double ay = length > 0.0 ? ( pos.y - m_curr_polyline_pos.y ) / length : 0.0;
// find index to m_curr_polyline_pattern at position t
int pattern_index = 0;
m_curr_polyline_t = fmod( m_curr_polyline_t, m_curr_polyline_pattern_length );
for( int i=0; i<6; i++ ) if ( m_curr_polyline_pattern[i] > m_curr_polyline_t ) { pattern_index = i; break; }
// t changes from m_curr_polyline_t to length
double t;
QSPt2f curr_pos;
while(1) {
// draws a m_line to t
t = (pattern_index/6)*m_curr_polyline_pattern_length + m_curr_polyline_pattern[pattern_index%6] - m_curr_polyline_t;
curr_pos.x = m_curr_polyline_pos.x + QMIN(t,length)*ax;
curr_pos.y = m_curr_polyline_pos.y + QMIN(t,length)*ay;
// even position - space, odd position in a pattern - m_line
bool is_space = pattern_index & 0x01;
// draw a m_line or leave a space
if ( is_space ) m_paint->moveTo( int(floor(curr_pos.x+0.5)), int(floor(curr_pos.y+0.5)) );
else m_paint->lineTo( int(floor(curr_pos.x+0.5)), int(floor(curr_pos.y+0.5)) );
pattern_index = pattern_index+1;
// ok. end with this segment
if ( t >= length ) break;
}
m_curr_polyline_t += length;
m_curr_polyline_pos = pos;
}
//-------------------------------------------------------------//
void QSDrvQt::endPolyline()
{
setLine(m_line);
}
//-------------------------------------------------------------//
//QBrush br( Qt::gray );
void QSDrvQt::setFill( const QSGFill &f )
{
//QBrush b = toQBrush(f);
//b.setStyle ( Qt::SolidPattern );
if ( m_cfill != f ) { m_cfill = f; m_paint->setBrush( toQBrush(f) ); }
}
//-------------------------------------------------------------//
void QSDrvQt::setFont( const QSGFont &f )
{
m_curr_font = f;
QFont font = toQFont(f,dpi);
//font.setPixelSizeFloat( toPixels(double(f.size)) );
m_paint->setFont( font );
m_paint->setPen( toQColor(f.color) );
}
//-------------------------------------------------------------//
void QSDrvQt::setLine( const QSGLine &l )
{
m_line = l;
m_curr_pen = toQPen(l);
m_paint->setPen( m_curr_pen );
}
//-------------------------------------------------------------//
QSGFont QSDrvQt::toQSGFont( const QFont &f, const QColor &c, double dpi )
{
QSGFont result;
result.family = f.family() ;
result.size = int(QSCoord::pixelsToPoints(f.pointSizeFloat(),dpi) + 0.5);
result.bold = f.bold();
result.italic = f.italic();
result.color = QSGColor( c.red(), c.green(), c.blue() );
return result;
}
//-------------------------------------------------------------//
QFont QSDrvQt::toQFont( const QSGFont &f, double dpi )
{
QFont result;
result.setFamily( f.family );
result.setPointSizeFloat( QSCoord::pointsToPixels(f.size,dpi) );
result.setBold( f.bold );
result.setItalic( f.italic );
return result;
}
//-------------------------------------------------------------//
QSGColor QSDrvQt::toQSGColor( const QColor &c )
{
return QSGColor( c.red(), c.green(), c.blue() );
}
//-------------------------------------------------------------//
QColor QSDrvQt::toQColor( const QSGColor &c )
{
return QColor( c.r, c.g, c.b );
}
//-------------------------------------------------------------//
QSGFill QSDrvQt::toQSGFill( const QBrush &b )
{
QSGFill result;
switch( b.style() ) {
case Qt::SolidPattern: result.style = QSGFill::Solid; break;
case Qt::HorPattern: result.style = QSGFill::Horiz; break;
case Qt::VerPattern: result.style = QSGFill::Vert; break;
case Qt::CrossPattern: result.style = QSGFill::Cross; break;
case Qt::FDiagPattern: result.style = QSGFill::FDiag; break;
case Qt::BDiagPattern: result.style = QSGFill::BDiag; break;
case Qt::DiagCrossPattern: result.style = QSGFill::DiagCross; break;
case Qt::Dense4Pattern: result.style = QSGFill::Half; break;
default: result.style = QSGFill::Transparent; break;
}
result.color = toQSGColor( b.color() );
return result;
}
//-------------------------------------------------------------//
QBrush QSDrvQt::toQBrush( const QSGFill &f )
{
QBrush result;
switch( f.style ) {
case QSGFill::Solid: result.setStyle( Qt::SolidPattern ); break;
case QSGFill::Horiz: result.setStyle( Qt::HorPattern ); break;
case QSGFill::Vert: result.setStyle( Qt::VerPattern ); break;
case QSGFill::Cross: result.setStyle( Qt::CrossPattern ); break;
case QSGFill::FDiag: result.setStyle( Qt::FDiagPattern ); break;
case QSGFill::BDiag: result.setStyle( Qt::BDiagPattern ); break;
case QSGFill::DiagCross: result.setStyle( Qt::DiagCrossPattern ); break;
case QSGFill::Half: result.setStyle( Qt::Dense4Pattern ); break;
default: result.setStyle( Qt::NoBrush ); break;
}
result.setColor( toQColor(f.color) );
return result;
}
//-------------------------------------------------------------//
QSGLine QSDrvQt::toQSGLine( const QPen &p )
{
QSGLine result;
switch( p.style() ) {
case Qt::NoPen: result.style = QSGLine::Invisible; break;
case Qt::SolidLine: result.style = QSGLine::Solid; break;
case Qt::DashLine: result.style = QSGLine::Dash; break;
case Qt::DotLine: result.style = QSGLine::Dot; break;
case Qt::DashDotLine: result.style = QSGLine::DashDot; break;
case Qt::DashDotDotLine: result.style = QSGLine::DashDotDot; break;
default: result.style = QSGLine::Solid; break;
}
result.width = p.width();
result.color = toQSGColor( p.color() );
return result;
}
//-------------------------------------------------------------//
QPen QSDrvQt::toQPen( const QSGLine &p )
{
Qt::PenStyle s;
switch( p.style ) {
case QSGLine::Invisible: s = Qt::NoPen; break;
case QSGLine::Solid: s = Qt::SolidLine; break;
case QSGLine::Dash: s = Qt::DashLine; break;
case QSGLine::Dot: s = Qt::DotLine; break;
case QSGLine::DashDot: s = Qt::DashDotLine; break;
case QSGLine::DashDotDot: s = Qt::DashDotDotLine; break;
default: s = Qt::SolidLine; break;
}
//return QPen( toQColor( p.color ), p.width, s, Qt::SquareCap, Qt::BevelJoin );
return QPen( toQColor( p.color ), p.width, s );
}
//-------------------------------------------------------------//
QSGFont QSDrvQt::currentFont()
{
return toQSGFont( m_paint->font(), m_paint->pen().color() );
}
//-------------------------------------------------------------//
QSGFill QSDrvQt::currentFill()
{
return toQSGFill( m_paint->brush() );
}
//-------------------------------------------------------------//
QSGLine QSDrvQt::currentLine()
{
return toQSGLine( m_paint->pen() );
}
//-------------------------------------------------------------//
QSDrvQt *QSDrvQt::copy()
{
QSDrvQt *new_drv = new QSDrvQt();
new_drv->copySettingsFrom( this );
return new_drv;
}
//-------------------------------------------------------------//
void QSDrvQt::copySettingsFrom( const QSDrvQt *drv )
{
QSDrv::copySettingsFrom( drv );
setDC( copyPainter(drv->painter()), drv->dpi, true );
}
//-------------------------------------------------------------//
QPainter *QSDrvQt::copyPainter( const QPainter *painter )
{
QPainter *new_painter = new QPainter( painter->device() );
new_painter->setRasterOp( painter->rasterOp() );
new_painter->setWindow( painter->window() );
new_painter->setViewport( painter->viewport() );
new_painter->setWorldMatrix( painter->worldMatrix() );
new_painter->setViewXForm( painter->hasViewXForm() );
new_painter->setWorldXForm( painter->hasWorldXForm() );
return new_painter;
}