Improve wxQtDCImpl to better match Cairo rendering.

This commit is contained in:
Alex Shvartzkop 2024-02-16 00:57:18 +03:00
parent 7037d2ae64
commit 95f9257d62

View file

@ -42,6 +42,49 @@ static void SetBrushColour( QPainter *qtPainter, QColor col )
qtPainter->setBrush( b ); qtPainter->setBrush( b );
} }
class QtDCOffsetHelper
{
public:
QtDCOffsetHelper(QPainter *qpainter)
{
m_shouldOffset = ShouldOffset(qpainter->pen());
if (!m_shouldOffset)
return;
m_qp = qpainter;
m_offset = 0.5;
m_qp->translate(m_offset, m_offset);
}
~QtDCOffsetHelper()
{
if (m_shouldOffset)
m_qp->translate(-m_offset, -m_offset);
}
bool ShouldOffset(const QPen &pen) const
{
if (pen.style() == Qt::NoPen)
return false;
double width = pen.widthF();
// always offset for 1-pixel width
if (width <= 0)
return true;
// offset if pen width is odd integer
const int w = int(width);
return (w & 1) && wxIsSameDouble(width, w);
}
private:
QPainter *m_qp;
double m_offset;
bool m_shouldOffset;
};
wxIMPLEMENT_CLASS(wxQtDCImpl,wxDCImpl); wxIMPLEMENT_CLASS(wxQtDCImpl,wxDCImpl);
wxQtDCImpl::wxQtDCImpl( wxDC *owner ) wxQtDCImpl::wxQtDCImpl( wxDC *owner )
@ -582,11 +625,15 @@ bool wxQtDCImpl::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
void wxQtDCImpl::DoDrawPoint(wxCoord x, wxCoord y) void wxQtDCImpl::DoDrawPoint(wxCoord x, wxCoord y)
{ {
QtDCOffsetHelper helper( m_qtPainter );
m_qtPainter->drawPoint(x, y); m_qtPainter->drawPoint(x, y);
} }
void wxQtDCImpl::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) void wxQtDCImpl::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
{ {
QtDCOffsetHelper helper( m_qtPainter );
m_qtPainter->drawLine(x1, y1, x2, y2); m_qtPainter->drawLine(x1, y1, x2, y2);
} }
@ -600,55 +647,72 @@ void wxQtDCImpl::DoDrawArc(wxCoord x1, wxCoord y1,
QLineF l2( xc, yc, x2, y2 ); QLineF l2( xc, yc, x2, y2 );
QPointF center( xc, yc ); QPointF center( xc, yc );
qreal penWidth = m_qtPainter->pen().width(); qreal lenRadius = l1.length();
qreal lenRadius = l1.length() - penWidth / 2;
QPointF centerToCorner( lenRadius, lenRadius ); QPointF centerToCorner( lenRadius, lenRadius );
QRect rectangle = QRectF( center - centerToCorner, center + centerToCorner ).toRect(); QRect rectangle = QRectF( center - centerToCorner, center + centerToCorner ).toRect();
// Calculate the angles // Calculate the angles
int startAngle = (int)( l1.angle() * 16 ); int startAngle = (int)(l1.angle() * 16);
int endAngle = (int)( l2.angle() * 16 ); int endAngle = (int)(l2.angle() * 16);
while(endAngle < startAngle)
endAngle += 360 * 16;
int spanAngle = endAngle - startAngle; int spanAngle = endAngle - startAngle;
if ( spanAngle < 0 )
{ QtDCOffsetHelper helper( m_qtPainter );
spanAngle = -spanAngle;
}
if ( spanAngle == 0 ) if ( spanAngle == 0 )
m_qtPainter->drawEllipse( rectangle ); m_qtPainter->drawEllipse( rectangle );
else else if (m_qtPainter->brush().style() != Qt::NoBrush)
m_qtPainter->drawPie( rectangle, startAngle, spanAngle ); m_qtPainter->drawPie( rectangle, startAngle, spanAngle );
else
m_qtPainter->drawArc( rectangle, startAngle, spanAngle );
} }
void wxQtDCImpl::DoDrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord h, void wxQtDCImpl::DoDrawEllipticArc(wxCoord x, wxCoord y, wxCoord w, wxCoord h,
double sa, double ea) double sa, double ea)
{ {
int penWidth = m_qtPainter->pen().width(); int startAngle = (int)( sa * 16 );
x += penWidth / 2; int endAngle = (int)( ea * 16 );
y += penWidth / 2;
w -= penWidth;
h -= penWidth;
double spanAngle = sa - ea; while(endAngle < startAngle)
if (spanAngle < -180) endAngle += 360 * 16;
spanAngle += 360;
if (spanAngle > 180)
spanAngle -= 360;
if ( spanAngle == 0 ) int spanAngle = endAngle - startAngle;
m_qtPainter->drawEllipse( x, y, w, h );
QRect rectangle(x, y, w, h);
QtDCOffsetHelper helper( m_qtPainter );
if (spanAngle == 0)
{
m_qtPainter->drawEllipse( rectangle );
}
else else
m_qtPainter->drawPie( x, y, w, h, (int)( sa * 16 ), (int)( ( ea - sa ) * 16 ) ); {
if (m_qtPainter->brush().style() != Qt::NoBrush)
{
QPen savedPen = m_qtPainter->pen();
m_qtPainter->setPen( QPen( Qt::NoPen ) );
m_qtPainter->drawPie( rectangle, startAngle, spanAngle );
m_qtPainter->setPen( savedPen );
}
m_qtPainter->drawArc( rectangle, startAngle, spanAngle );
}
} }
void wxQtDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) void wxQtDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
{ {
int penWidth = m_qtPainter->pen().width(); if (m_qtPainter->pen().style() != Qt::NoPen)
x += penWidth / 2; {
y += penWidth / 2; width -= 1;
width -= penWidth; height -= 1;
height -= penWidth; }
QtDCOffsetHelper helper( m_qtPainter );
m_qtPainter->drawRect( x, y, width, height ); m_qtPainter->drawRect( x, y, width, height );
} }
@ -657,11 +721,13 @@ void wxQtDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
wxCoord width, wxCoord height, wxCoord width, wxCoord height,
double radius) double radius)
{ {
int penWidth = m_qtPainter->pen().width(); if (m_qtPainter->pen().style() != Qt::NoPen)
x += penWidth / 2; {
y += penWidth / 2; width -= 1;
width -= penWidth; height -= 1;
height -= penWidth; }
QtDCOffsetHelper helper( m_qtPainter );
m_qtPainter->drawRoundedRect( x, y, width, height, radius, radius ); m_qtPainter->drawRoundedRect( x, y, width, height, radius, radius );
} }
@ -669,11 +735,7 @@ void wxQtDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
void wxQtDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, void wxQtDCImpl::DoDrawEllipse(wxCoord x, wxCoord y,
wxCoord width, wxCoord height) wxCoord width, wxCoord height)
{ {
const int penWidth = m_qtPainter->pen().width(); QtDCOffsetHelper helper( m_qtPainter );
x += penWidth / 2;
y += penWidth / 2;
width -= penWidth;
height -= penWidth;
m_qtPainter->drawEllipse( x, y, width, height ); m_qtPainter->drawEllipse( x, y, width, height );
} }
@ -689,6 +751,8 @@ void wxQtDCImpl::DoCrossHair(wxCoord x, wxCoord y)
inv.map( w, h, &right, &bottom ); inv.map( w, h, &right, &bottom );
inv.map( 0, 0, &left, &top ); inv.map( 0, 0, &left, &top );
QtDCOffsetHelper helper( m_qtPainter );
m_qtPainter->drawLine( left, y, right, y ); m_qtPainter->drawLine( left, y, right, y );
m_qtPainter->drawLine( x, top, x, bottom ); m_qtPainter->drawLine( x, top, x, bottom );
} }