890 lines
25 KiB
C++
890 lines
25 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/qt/dc.cpp
|
|
// Author: Peter Most, Javier Torres, Mariano Reingart
|
|
// Copyright: (c) 2009 wxWidgets dev team
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
|
|
#include <QtGui/QBitmap>
|
|
#include <QtGui/QPen>
|
|
#include <QtGui/QPainter>
|
|
#include <QtGui/QPainterPath>
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/icon.h"
|
|
#include "wx/log.h"
|
|
#endif // WX_PRECOMP
|
|
|
|
#include "wx/dc.h"
|
|
#include "wx/qt/dc.h"
|
|
#include "wx/qt/private/converter.h"
|
|
#include "wx/qt/private/utils.h"
|
|
#include "wx/qt/private/compat.h"
|
|
|
|
#include <QtGui/QScreen>
|
|
#include <QtWidgets/QApplication>
|
|
|
|
static void SetPenColour( QPainter *qtPainter, QColor col )
|
|
{
|
|
QPen p = qtPainter->pen();
|
|
p.setColor( col );
|
|
qtPainter->setPen( p );
|
|
}
|
|
|
|
static void SetBrushColour( QPainter *qtPainter, QColor col )
|
|
{
|
|
QBrush b = qtPainter->brush();
|
|
b.setColor( col );
|
|
qtPainter->setBrush( b );
|
|
}
|
|
|
|
wxIMPLEMENT_CLASS(wxQtDCImpl,wxDCImpl);
|
|
|
|
wxQtDCImpl::wxQtDCImpl( wxDC *owner )
|
|
: wxDCImpl( owner )
|
|
{
|
|
m_qtPixmap = nullptr;
|
|
m_qtPainter = nullptr;
|
|
m_rasterColourOp = wxQtNONE;
|
|
m_qtPenColor = new QColor;
|
|
m_qtBrushColor = new QColor;
|
|
m_ok = true;
|
|
}
|
|
|
|
wxQtDCImpl::~wxQtDCImpl()
|
|
{
|
|
if ( m_qtPainter )
|
|
{
|
|
if( m_qtPainter->isActive() )
|
|
{
|
|
m_qtPainter->end();
|
|
}
|
|
delete m_qtPainter;
|
|
}
|
|
|
|
delete m_qtPenColor;
|
|
delete m_qtBrushColor;
|
|
}
|
|
|
|
void wxQtDCImpl::QtPreparePainter( )
|
|
{
|
|
//Do here all QPainter initialization (called after each begin())
|
|
if ( m_qtPainter == nullptr )
|
|
{
|
|
wxLogDebug(wxT("wxQtDCImpl::QtPreparePainter is null!!!"));
|
|
}
|
|
else if ( m_qtPainter->isActive() )
|
|
{
|
|
m_qtPainter->setPen( wxPen().GetHandle() );
|
|
m_qtPainter->setBrush( wxBrush().GetHandle() );
|
|
m_qtPainter->setFont( wxFont().GetHandle() );
|
|
|
|
if (m_clipping)
|
|
{
|
|
m_qtPainter->setClipRegion( m_clippingRegion.GetHandle() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// wxLogDebug(wxT("wxQtDCImpl::QtPreparePainter not active!"));
|
|
}
|
|
}
|
|
|
|
bool wxQtDCImpl::CanDrawBitmap() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool wxQtDCImpl::CanGetTextExtent() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void wxQtDCImpl::DoGetSize(int *width, int *height) const
|
|
{
|
|
QPaintDevice *pDevice = m_qtPainter->device();
|
|
|
|
int deviceWidth;
|
|
int deviceHeight;
|
|
|
|
if ( pDevice )
|
|
{
|
|
deviceWidth = pDevice->width();
|
|
deviceHeight = pDevice->height();
|
|
}
|
|
else
|
|
{
|
|
deviceWidth = 0;
|
|
deviceHeight = 0;
|
|
|
|
}
|
|
if ( width )
|
|
*width = deviceWidth;
|
|
if ( height )
|
|
*height = deviceHeight;
|
|
}
|
|
|
|
void wxQtDCImpl::DoGetSizeMM(int* width, int* height) const
|
|
{
|
|
QPaintDevice *pDevice = m_qtPainter->device();
|
|
|
|
int deviceWidthMM;
|
|
int deviceHeightMM;
|
|
|
|
if ( pDevice )
|
|
{
|
|
deviceWidthMM = pDevice->widthMM();
|
|
deviceHeightMM = pDevice->heightMM();
|
|
}
|
|
else
|
|
{
|
|
deviceWidthMM = 0;
|
|
deviceHeightMM = 0;
|
|
}
|
|
|
|
if ( width )
|
|
*width = deviceWidthMM;
|
|
if ( height )
|
|
*height = deviceHeightMM;
|
|
}
|
|
|
|
int wxQtDCImpl::GetDepth() const
|
|
{
|
|
return m_qtPainter->device()->depth();
|
|
}
|
|
|
|
wxSize wxQtDCImpl::GetPPI() const
|
|
{
|
|
QScreen *srn = QApplication::screens().at(0);
|
|
if (!srn)
|
|
return wxSize(m_qtPainter->device()->logicalDpiX(), m_qtPainter->device()->logicalDpiY());
|
|
qreal dotsPerInch = srn->logicalDotsPerInch();
|
|
return wxSize(round(dotsPerInch), round(dotsPerInch));
|
|
}
|
|
|
|
void wxQtDCImpl::SetFont(const wxFont& font)
|
|
{
|
|
m_font = font;
|
|
|
|
if (m_qtPainter->isActive())
|
|
m_qtPainter->setFont(font.GetHandle());
|
|
}
|
|
|
|
void wxQtDCImpl::SetPen(const wxPen& pen)
|
|
{
|
|
m_pen = pen;
|
|
|
|
if ( !m_pen.IsOk() ) return;
|
|
|
|
m_qtPainter->setPen(pen.GetHandle());
|
|
|
|
ApplyRasterColourOp();
|
|
}
|
|
|
|
void wxQtDCImpl::SetBrush(const wxBrush& brush)
|
|
{
|
|
m_brush = brush;
|
|
|
|
if ( !m_brush.IsOk() ) return;
|
|
|
|
if (brush.GetStyle() == wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE)
|
|
{
|
|
// Use a monochrome mask: use foreground color for the mask
|
|
m_brush.SetColour(m_textForegroundColour);
|
|
}
|
|
|
|
m_qtPainter->setBrush(m_brush.GetHandle());
|
|
|
|
ApplyRasterColourOp();
|
|
}
|
|
|
|
void wxQtDCImpl::SetBackground(const wxBrush& brush)
|
|
{
|
|
m_backgroundBrush = brush;
|
|
|
|
// For consistency with the other ports: clearing the dc with
|
|
// invalid brush (Qt::NoBrush) should use white colour (which
|
|
// happens to be the default colour in Qt too) instead of no
|
|
// colour at all.
|
|
if (!m_backgroundBrush.IsOk())
|
|
m_backgroundBrush = *wxWHITE_BRUSH;
|
|
|
|
if (m_qtPainter->isActive())
|
|
{
|
|
m_qtPainter->setBackground(m_backgroundBrush.GetHandle());
|
|
}
|
|
}
|
|
|
|
void wxQtDCImpl::SetBackgroundMode(int mode)
|
|
{
|
|
/* Do not change QPainter, as wx uses this background mode
|
|
* only for drawing text, where Qt uses it for everything.
|
|
* Always let QPainter mode to transparent, and change it
|
|
* when needed */
|
|
m_backgroundMode = mode;
|
|
}
|
|
|
|
#include <QtGui/QPen>
|
|
#include <QtGui/QPainter>
|
|
#include <QtGui/QScreen>
|
|
#include <QtWidgets/QApplication>
|
|
|
|
#if wxUSE_PALETTE
|
|
void wxQtDCImpl::SetPalette(const wxPalette& WXUNUSED(palette))
|
|
{
|
|
wxMISSING_IMPLEMENTATION(__FUNCTION__);
|
|
}
|
|
#endif // wxUSE_PALETTE
|
|
|
|
void wxQtDCImpl::SetLogicalFunction(wxRasterOperationMode function)
|
|
{
|
|
m_logicalFunction = function;
|
|
|
|
wxQtRasterColourOp rasterColourOp = wxQtNONE;
|
|
switch ( function )
|
|
{
|
|
case wxCLEAR: // 0
|
|
m_qtPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
|
|
rasterColourOp = wxQtBLACK;
|
|
break;
|
|
case wxXOR: // src XOR dst
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_SourceXorDestination );
|
|
break;
|
|
case wxINVERT: // NOT dst => dst XOR WHITE
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_SourceXorDestination );
|
|
rasterColourOp = wxQtWHITE;
|
|
break;
|
|
case wxOR_REVERSE: // src OR (NOT dst) => (NOT (NOT src)) OR (NOT dst)
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_NotSourceOrNotDestination );
|
|
rasterColourOp = wxQtINVERT;
|
|
break;
|
|
case wxAND_REVERSE: // src AND (NOT dst)
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_SourceAndNotDestination );
|
|
break;
|
|
case wxCOPY: // src
|
|
m_qtPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
|
|
break;
|
|
case wxAND: // src AND dst
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_SourceAndDestination );
|
|
break;
|
|
case wxAND_INVERT: // (NOT src) AND dst
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_NotSourceAndDestination );
|
|
break;
|
|
case wxNO_OP: // dst
|
|
m_qtPainter->setCompositionMode( QPainter::CompositionMode_DestinationOver );
|
|
break;
|
|
case wxNOR: // (NOT src) AND (NOT dst)
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_NotSourceAndNotDestination );
|
|
break;
|
|
case wxEQUIV: // (NOT src) XOR dst
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_NotSourceXorDestination );
|
|
break;
|
|
case wxSRC_INVERT: // (NOT src)
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_NotSource );
|
|
break;
|
|
case wxOR_INVERT: // (NOT src) OR dst
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_SourceOrDestination );
|
|
rasterColourOp = wxQtINVERT;
|
|
break;
|
|
case wxNAND: // (NOT src) OR (NOT dst)
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_NotSourceOrNotDestination );
|
|
break;
|
|
case wxOR: // src OR dst
|
|
m_qtPainter->setCompositionMode( QPainter::RasterOp_SourceOrDestination );
|
|
break;
|
|
case wxSET: // 1
|
|
m_qtPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
|
|
rasterColourOp = wxQtWHITE;
|
|
break;
|
|
}
|
|
|
|
if ( rasterColourOp != m_rasterColourOp )
|
|
{
|
|
// Source colour mode changed
|
|
m_rasterColourOp = rasterColourOp;
|
|
|
|
// Restore original colours and apply new mode
|
|
SetPenColour( m_qtPainter, *m_qtPenColor );
|
|
SetBrushColour( m_qtPainter, *m_qtPenColor );
|
|
|
|
ApplyRasterColourOp();
|
|
}
|
|
}
|
|
|
|
void wxQtDCImpl::ApplyRasterColourOp()
|
|
{
|
|
// Save colours
|
|
*m_qtPenColor = m_qtPainter->pen().color();
|
|
*m_qtBrushColor = m_qtPainter->brush().color();
|
|
|
|
// Apply op
|
|
switch ( m_rasterColourOp )
|
|
{
|
|
case wxQtWHITE:
|
|
SetPenColour( m_qtPainter, QColor( Qt::white ) );
|
|
SetBrushColour( m_qtPainter, QColor( Qt::white ) );
|
|
break;
|
|
case wxQtBLACK:
|
|
SetPenColour( m_qtPainter, QColor( Qt::black ) );
|
|
SetBrushColour( m_qtPainter, QColor( Qt::black ) );
|
|
break;
|
|
case wxQtINVERT:
|
|
SetPenColour( m_qtPainter, QColor( ~m_qtPenColor->rgb() ) );
|
|
SetBrushColour( m_qtPainter, QColor( ~m_qtBrushColor->rgb() ) );
|
|
break;
|
|
case wxQtNONE:
|
|
// No op
|
|
break;
|
|
}
|
|
}
|
|
|
|
wxCoord wxQtDCImpl::GetCharHeight() const
|
|
{
|
|
QFontMetrics metrics(m_qtPainter->isActive() ?
|
|
m_qtPainter->font() : QApplication::font());
|
|
return wxCoord( metrics.height() );
|
|
}
|
|
|
|
wxCoord wxQtDCImpl::GetCharWidth() const
|
|
{
|
|
//FIXME: Returning max width, instead of average
|
|
QFontMetrics metrics(m_qtPainter->isActive() ?
|
|
m_qtPainter->font() : QApplication::font());
|
|
return wxCoord( metrics.maxWidth() );
|
|
}
|
|
|
|
void wxQtDCImpl::DoGetTextExtent(const wxString& string,
|
|
wxCoord *x, wxCoord *y,
|
|
wxCoord *descent,
|
|
wxCoord *externalLeading,
|
|
const wxFont *theFont ) const
|
|
{
|
|
if ( x )
|
|
*x = 0;
|
|
if ( y )
|
|
*y = 0;
|
|
if ( descent )
|
|
*descent = 0;
|
|
if ( externalLeading )
|
|
*externalLeading = 0;
|
|
|
|
// We can skip computing the string width and height if it is empty, but
|
|
// not its descent and/or external leading, which still needs to be
|
|
// returned even for an empty string.
|
|
if ( string.empty() && !descent && !externalLeading )
|
|
return;
|
|
|
|
QFont f;
|
|
if (theFont != nullptr)
|
|
f = theFont->GetHandle();
|
|
else
|
|
f = m_font.GetHandle();
|
|
|
|
QFontMetrics metrics(f);
|
|
if (x != nullptr || y != nullptr)
|
|
{
|
|
// note that boundingRect doesn't return "advance width" for spaces
|
|
if (x != nullptr)
|
|
*x = wxQtGetWidthFromMetrics(metrics, wxQtConvertString(string));
|
|
if (y != nullptr)
|
|
*y = metrics.height();
|
|
}
|
|
|
|
if (descent != nullptr)
|
|
*descent = metrics.descent();
|
|
|
|
if (externalLeading != nullptr)
|
|
*externalLeading = metrics.leading();
|
|
}
|
|
|
|
void wxQtDCImpl::Clear()
|
|
{
|
|
int width, height;
|
|
DoGetSize(&width, &height);
|
|
|
|
m_qtPainter->eraseRect( DeviceToLogicalX(0),
|
|
DeviceToLogicalY(0),
|
|
DeviceToLogicalXRel(width),
|
|
DeviceToLogicalYRel(height) );
|
|
}
|
|
|
|
void wxQtDCImpl::UpdateClipBox()
|
|
{
|
|
if ( !m_qtPainter->isActive() )
|
|
return;
|
|
|
|
if ( m_clippingRegion.IsEmpty() )
|
|
{
|
|
int dcwidth, dcheight;
|
|
DoGetSize(&dcwidth, &dcheight);
|
|
|
|
m_qtPainter->setClipRect(DeviceToLogicalX(0),
|
|
DeviceToLogicalY(0),
|
|
DeviceToLogicalXRel(dcwidth),
|
|
DeviceToLogicalYRel(dcheight),
|
|
m_clipping ? Qt::IntersectClip : Qt::ReplaceClip);
|
|
}
|
|
|
|
/* Note: Qt states that QPainter::clipRegion() may be slow, so we
|
|
* keep the region manually, which should be faster. A comment in
|
|
* QPainter::clipBoundingRect() source says: This is not 100% precise,
|
|
* but it fits within the guarantee and it is reasonably fast.
|
|
*/
|
|
m_clippingRegion.QtSetRegion(
|
|
QRegion(m_qtPainter->clipBoundingRect().toRect()) );
|
|
|
|
wxRect clipRect = m_clippingRegion.GetBox();
|
|
|
|
m_clipX1 = clipRect.GetLeft();
|
|
m_clipX2 = clipRect.GetRight() + 1;
|
|
m_clipY1 = clipRect.GetTop();
|
|
m_clipY2 = clipRect.GetBottom() + 1;
|
|
|
|
m_isClipBoxValid = true;
|
|
}
|
|
|
|
bool wxQtDCImpl::DoGetClippingRect(wxRect& rect) const
|
|
{
|
|
// Check if we should try to retrieve the clipping region possibly not set
|
|
// by our SetClippingRegion() but preset or modified by application: this
|
|
// can happen when wxDC logical coordinates are transformed with
|
|
// SetDeviceOrigin(), SetLogicalOrigin(), SetUserScale(), SetLogicalScale().
|
|
if ( !m_isClipBoxValid )
|
|
{
|
|
wxQtDCImpl *self = wxConstCast(this, wxQtDCImpl);
|
|
self->UpdateClipBox();
|
|
}
|
|
|
|
return wxDCImpl::DoGetClippingRect(rect);
|
|
}
|
|
|
|
void wxQtDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y,
|
|
wxCoord width, wxCoord height)
|
|
{
|
|
if ( width < 0 )
|
|
{
|
|
width = -width;
|
|
x -= width - 1;
|
|
}
|
|
if ( height < 0 )
|
|
{
|
|
height = -height;
|
|
y -= height - 1;
|
|
}
|
|
|
|
if ( m_qtPainter->isActive() )
|
|
{
|
|
// Set QPainter clipping (intersection if not the first one)
|
|
m_qtPainter->setClipRect( x, y, width, height,
|
|
m_clipping ? Qt::IntersectClip : Qt::ReplaceClip );
|
|
|
|
m_clipping = true;
|
|
}
|
|
|
|
UpdateClipBox();
|
|
}
|
|
|
|
void wxQtDCImpl::DoSetDeviceClippingRegion(const wxRegion& region)
|
|
{
|
|
if ( m_qtPainter->isActive() )
|
|
{
|
|
// Disable the matrix transformations to match device coordinates
|
|
m_qtPainter->setWorldMatrixEnabled(false);
|
|
// Enable clipping explicitly as QPainter::setClipRegion() doesn't
|
|
// do that for us
|
|
m_qtPainter->setClipping( true );
|
|
// Set QPainter clipping (intersection if not the first one)
|
|
m_qtPainter->setClipRegion( region.GetHandle(),
|
|
m_clipping ? Qt::IntersectClip : Qt::ReplaceClip );
|
|
|
|
m_qtPainter->setWorldMatrixEnabled(true);
|
|
|
|
m_clipping = true;
|
|
}
|
|
|
|
UpdateClipBox();
|
|
}
|
|
|
|
void wxQtDCImpl::DestroyClippingRegion()
|
|
{
|
|
wxDCImpl::DestroyClippingRegion();
|
|
m_clippingRegion.Clear();
|
|
|
|
if (m_qtPainter->isActive())
|
|
m_qtPainter->setClipping( false );
|
|
|
|
m_isClipBoxValid = false;
|
|
}
|
|
|
|
bool wxQtDCImpl::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col,
|
|
wxFloodFillStyle style )
|
|
{
|
|
#if wxUSE_IMAGE
|
|
extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
|
|
const wxColour & col, wxFloodFillStyle style);
|
|
|
|
return wxDoFloodFill( GetOwner(), x, y, col, style);
|
|
#else
|
|
wxUnusedVar(x);
|
|
wxUnusedVar(y);
|
|
wxUnusedVar(col);
|
|
wxUnusedVar(style);
|
|
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool wxQtDCImpl::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
|
|
{
|
|
wxCHECK_MSG( m_qtPainter->isActive(), false, "Invalid wxDC" );
|
|
|
|
if ( col )
|
|
{
|
|
wxCHECK_MSG( m_qtPixmap != nullptr, false, "This DC doesn't support GetPixel()" );
|
|
QPixmap pixmap1px = m_qtPixmap->copy( x, y, 1, 1 );
|
|
QImage image = pixmap1px.toImage();
|
|
QColor pixel = image.pixel( 0, 0 );
|
|
col->Set( pixel.red(), pixel.green(), pixel.blue(), pixel.alpha() );
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawPoint(wxCoord x, wxCoord y)
|
|
{
|
|
m_qtPainter->drawPoint(x, y);
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
|
|
{
|
|
m_qtPainter->drawLine(x1, y1, x2, y2);
|
|
}
|
|
|
|
|
|
void wxQtDCImpl::DoDrawArc(wxCoord x1, wxCoord y1,
|
|
wxCoord x2, wxCoord y2,
|
|
wxCoord xc, wxCoord yc)
|
|
{
|
|
// Calculate the rectangle that contains the circle
|
|
QLineF l1( xc, yc, x1, y1 );
|
|
QLineF l2( xc, yc, x2, y2 );
|
|
QPointF center( xc, yc );
|
|
|
|
qreal penWidth = m_qtPainter->pen().width();
|
|
qreal lenRadius = l1.length() - penWidth / 2;
|
|
QPointF centerToCorner( lenRadius, lenRadius );
|
|
|
|
QRect rectangle = QRectF( center - centerToCorner, center + centerToCorner ).toRect();
|
|
|
|
// Calculate the angles
|
|
int startAngle = (int)( l1.angle() * 16 );
|
|
int endAngle = (int)( l2.angle() * 16 );
|
|
int spanAngle = endAngle - startAngle;
|
|
if ( spanAngle < 0 )
|
|
{
|
|
spanAngle = -spanAngle;
|
|
}
|
|
|
|
if ( spanAngle == 0 )
|
|
m_qtPainter->drawEllipse( rectangle );
|
|
else
|
|
m_qtPainter->drawPie( rectangle, startAngle, spanAngle );
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord h,
|
|
double sa, double ea)
|
|
{
|
|
int penWidth = m_qtPainter->pen().width();
|
|
x += penWidth / 2;
|
|
y += penWidth / 2;
|
|
w -= penWidth;
|
|
h -= penWidth;
|
|
|
|
double spanAngle = sa - ea;
|
|
if (spanAngle < -180)
|
|
spanAngle += 360;
|
|
if (spanAngle > 180)
|
|
spanAngle -= 360;
|
|
|
|
if ( spanAngle == 0 )
|
|
m_qtPainter->drawEllipse( x, y, w, h );
|
|
else
|
|
m_qtPainter->drawPie( x, y, w, h, (int)( sa * 16 ), (int)( ( ea - sa ) * 16 ) );
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
|
|
{
|
|
int penWidth = m_qtPainter->pen().width();
|
|
x += penWidth / 2;
|
|
y += penWidth / 2;
|
|
width -= penWidth;
|
|
height -= penWidth;
|
|
|
|
m_qtPainter->drawRect( x, y, width, height );
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
|
|
wxCoord width, wxCoord height,
|
|
double radius)
|
|
{
|
|
int penWidth = m_qtPainter->pen().width();
|
|
x += penWidth / 2;
|
|
y += penWidth / 2;
|
|
width -= penWidth;
|
|
height -= penWidth;
|
|
|
|
m_qtPainter->drawRoundedRect( x, y, width, height, radius, radius );
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawEllipse(wxCoord x, wxCoord y,
|
|
wxCoord width, wxCoord height)
|
|
{
|
|
const int penWidth = m_qtPainter->pen().width();
|
|
x += penWidth / 2;
|
|
y += penWidth / 2;
|
|
width -= penWidth;
|
|
height -= penWidth;
|
|
|
|
m_qtPainter->drawEllipse( x, y, width, height );
|
|
}
|
|
|
|
void wxQtDCImpl::DoCrossHair(wxCoord x, wxCoord y)
|
|
{
|
|
int w, h;
|
|
DoGetSize( &w, &h );
|
|
|
|
// Map width and height back (inverted transform)
|
|
QTransform inv = m_qtPainter->transform().inverted();
|
|
int left, top, right, bottom;
|
|
inv.map( w, h, &right, &bottom );
|
|
inv.map( 0, 0, &left, &top );
|
|
|
|
m_qtPainter->drawLine( left, y, right, y );
|
|
m_qtPainter->drawLine( x, top, x, bottom );
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y)
|
|
{
|
|
DoDrawBitmap( icon, x, y, true );
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawBitmap(const wxBitmap &bmp, wxCoord x, wxCoord y,
|
|
bool useMask )
|
|
{
|
|
QPixmap pix = *bmp.GetHandle();
|
|
if (pix.depth() == 1) {
|
|
//Monochrome bitmap, draw using text fore/background
|
|
|
|
//Save pen/brush
|
|
QBrush savedBrush = m_qtPainter->background();
|
|
QPen savedPen = m_qtPainter->pen();
|
|
|
|
//Use text colors
|
|
m_qtPainter->setBackground(QBrush(m_textBackgroundColour.GetQColor()));
|
|
m_qtPainter->setPen(QPen(m_textForegroundColour.GetQColor()));
|
|
|
|
//Draw
|
|
m_qtPainter->drawPixmap(x, y, pix);
|
|
|
|
//Restore saved settings
|
|
m_qtPainter->setBackground(savedBrush);
|
|
m_qtPainter->setPen(savedPen);
|
|
}
|
|
else
|
|
{
|
|
if ( useMask && bmp.GetMask() && bmp.GetMask()->GetHandle() )
|
|
pix.setMask(*bmp.GetMask()->GetHandle());
|
|
m_qtPainter->drawPixmap(x, y, pix);
|
|
}
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
|
|
{
|
|
QPen savedPen = m_qtPainter->pen();
|
|
m_qtPainter->setPen(QPen(m_textForegroundColour.GetQColor()));
|
|
|
|
// Disable logical function
|
|
QPainter::CompositionMode savedOp = m_qtPainter->compositionMode();
|
|
m_qtPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
|
|
|
|
if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
|
|
{
|
|
m_qtPainter->setBackgroundMode(Qt::OpaqueMode);
|
|
|
|
//Save pen/brush
|
|
QBrush savedBrush = m_qtPainter->background();
|
|
|
|
//Use text colors
|
|
m_qtPainter->setBackground(QBrush(m_textBackgroundColour.GetQColor()));
|
|
|
|
//Draw
|
|
m_qtPainter->drawText(x, y, 1, 1, Qt::TextDontClip, wxQtConvertString(text));
|
|
|
|
//Restore saved settings
|
|
m_qtPainter->setBackground(savedBrush);
|
|
|
|
|
|
m_qtPainter->setBackgroundMode(Qt::TransparentMode);
|
|
}
|
|
else
|
|
m_qtPainter->drawText(x, y, 1, 1, Qt::TextDontClip, wxQtConvertString(text));
|
|
|
|
m_qtPainter->setPen(savedPen);
|
|
m_qtPainter->setCompositionMode( savedOp );
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawRotatedText(const wxString& text,
|
|
wxCoord x, wxCoord y, double angle)
|
|
{
|
|
if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
|
|
m_qtPainter->setBackgroundMode(Qt::OpaqueMode);
|
|
|
|
//Move and rotate (reverse angle direction in Qt and wx)
|
|
m_qtPainter->translate(x, y);
|
|
m_qtPainter->rotate(-angle);
|
|
|
|
QPen savedPen = m_qtPainter->pen();
|
|
m_qtPainter->setPen(QPen(m_textForegroundColour.GetQColor()));
|
|
|
|
// Disable logical function
|
|
QPainter::CompositionMode savedOp = m_qtPainter->compositionMode();
|
|
m_qtPainter->setCompositionMode( QPainter::CompositionMode_SourceOver );
|
|
|
|
if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
|
|
{
|
|
m_qtPainter->setBackgroundMode(Qt::OpaqueMode);
|
|
|
|
//Save pen/brush
|
|
QBrush savedBrush = m_qtPainter->background();
|
|
|
|
//Use text colors
|
|
m_qtPainter->setBackground(QBrush(m_textBackgroundColour.GetQColor()));
|
|
|
|
//Draw
|
|
m_qtPainter->drawText(x, y, 1, 1, Qt::TextDontClip, wxQtConvertString(text));
|
|
|
|
//Restore saved settings
|
|
m_qtPainter->setBackground(savedBrush);
|
|
|
|
m_qtPainter->setBackgroundMode(Qt::TransparentMode);
|
|
}
|
|
else
|
|
m_qtPainter->drawText(x, y, 1, 1, Qt::TextDontClip, wxQtConvertString(text));
|
|
|
|
//Reset to default
|
|
ComputeScaleAndOrigin();
|
|
m_qtPainter->setPen(savedPen);
|
|
m_qtPainter->setCompositionMode( savedOp );
|
|
}
|
|
|
|
bool wxQtDCImpl::DoBlit(wxCoord xdest, wxCoord ydest,
|
|
wxCoord width, wxCoord height,
|
|
wxDC *source,
|
|
wxCoord xsrc, wxCoord ysrc,
|
|
wxRasterOperationMode rop,
|
|
bool useMask,
|
|
wxCoord WXUNUSED(xsrcMask),
|
|
wxCoord WXUNUSED(ysrcMask) )
|
|
{
|
|
wxQtDCImpl *implSource = (wxQtDCImpl*)source->GetImpl();
|
|
|
|
QPixmap *qtSource = implSource->GetQPixmap();
|
|
|
|
// Not a CHECK on purpose
|
|
if ( !qtSource )
|
|
return false;
|
|
|
|
// Change logical function
|
|
wxRasterOperationMode savedMode = GetLogicalFunction();
|
|
SetLogicalFunction( rop );
|
|
|
|
if ( useMask )
|
|
{
|
|
m_qtPainter->drawPixmap( QRect( xdest, ydest, width, height ),
|
|
*qtSource,
|
|
QRect( xsrc, ysrc, width, height ) );
|
|
}
|
|
else
|
|
{
|
|
QImage qtSourceConverted = qtSource->toImage();
|
|
qtSourceConverted = qtSourceConverted.convertToFormat(QImage::Format_RGB32);
|
|
|
|
m_qtPainter->drawImage( QRect( xdest, ydest, width, height ),
|
|
qtSourceConverted,
|
|
QRect( xsrc, ysrc, width, height ) );
|
|
}
|
|
|
|
SetLogicalFunction( savedMode );
|
|
|
|
return true;
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawLines(int n, const wxPoint points[],
|
|
wxCoord xoffset, wxCoord yoffset )
|
|
{
|
|
if (n > 0)
|
|
{
|
|
QPainterPath path(wxQtConvertPoint(points[0]));
|
|
for (int i = 1; i < n; i++)
|
|
{
|
|
path.lineTo(wxQtConvertPoint(points[i]));
|
|
}
|
|
|
|
m_qtPainter->translate(xoffset, yoffset);
|
|
|
|
QBrush savebrush = m_qtPainter->brush();
|
|
m_qtPainter->setBrush(Qt::NoBrush);
|
|
m_qtPainter->drawPath(path);
|
|
m_qtPainter->setBrush(savebrush);
|
|
|
|
// Reset transform
|
|
ComputeScaleAndOrigin();
|
|
}
|
|
}
|
|
|
|
void wxQtDCImpl::DoDrawPolygon(int n, const wxPoint points[],
|
|
wxCoord xoffset, wxCoord yoffset,
|
|
wxPolygonFillMode fillStyle )
|
|
{
|
|
QPolygon qtPoints;
|
|
for (int i = 0; i < n; i++) {
|
|
qtPoints << wxQtConvertPoint(points[i]);
|
|
}
|
|
|
|
Qt::FillRule fill = (fillStyle == wxWINDING_RULE) ? Qt::WindingFill : Qt::OddEvenFill;
|
|
|
|
m_qtPainter->translate(xoffset, yoffset);
|
|
m_qtPainter->drawPolygon(qtPoints, fill);
|
|
// Reset transform
|
|
ComputeScaleAndOrigin();
|
|
}
|
|
|
|
void wxQtDCImpl::ComputeScaleAndOrigin()
|
|
{
|
|
QTransform t;
|
|
|
|
// First apply device origin
|
|
t.translate( m_deviceOriginX + m_deviceLocalOriginX,
|
|
m_deviceOriginY + m_deviceLocalOriginY );
|
|
|
|
// Second, scale
|
|
m_scaleX = m_logicalScaleX * m_userScaleX;
|
|
m_scaleY = m_logicalScaleY * m_userScaleY;
|
|
t.scale( m_scaleX * m_signX, m_scaleY * m_signY );
|
|
|
|
// Finally, logical origin
|
|
t.translate( -m_logicalOriginX, -m_logicalOriginY );
|
|
|
|
// Apply transform to QPainter, overwriting the previous one
|
|
m_qtPainter->setWorldTransform(t, false);
|
|
|
|
m_isClipBoxValid = false;
|
|
}
|