X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1b89a5cd94246c473b73fea239ee8a6066d410da..8e190f0ed9c242e6df5fd4dd99fdaf6c9dea1cda:/src/common/dcgraph.cpp diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp index 136775cbad..420e9039bb 100644 --- a/src/common/dcgraph.cpp +++ b/src/common/dcgraph.cpp @@ -3,7 +3,7 @@ // Purpose: graphics context methods common to all platforms // Author: Stefan Csomor // Modified by: -// Created: +// Created: // RCS-ID: $Id$ // Copyright: (c) Stefan Csomor // Licence: wxWindows licence @@ -58,23 +58,34 @@ wxGCDC::wxGCDC() } void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx ) -{ +{ delete m_graphicContext; m_graphicContext = ctx; + if ( m_graphicContext ) + { + m_matrixOriginal = m_graphicContext->GetTransform(); + m_ok = true; + // apply the stored transformations to the passed in context + ComputeScaleAndOrigin(); + m_graphicContext->SetFont( m_font , m_textForegroundColour ); + m_graphicContext->SetPen( m_pen ); + m_graphicContext->SetBrush( m_brush); + } } wxGCDC::wxGCDC(const wxWindowDC& dc) { Init(); - m_graphicContext = wxGraphicsContext::Create(dc); - m_ok = true; - if ( dc.GetFont().Ok()) - m_graphicContext->SetFont( m_graphicContext->CreateFont(dc.GetFont(),dc.GetTextForeground())); - if ( dc.GetPen().Ok()) - m_graphicContext->SetPen( m_graphicContext->CreatePen(dc.GetPen())); - if ( dc.GetBrush().Ok()) - m_graphicContext->SetBrush( m_graphicContext->CreateBrush(dc.GetBrush())); + SetGraphicsContext( wxGraphicsContext::Create(dc) ); +} + +#ifdef __WXMSW__ +wxGCDC::wxGCDC(const wxMemoryDC& dc) +{ + Init(); + SetGraphicsContext( wxGraphicsContext::Create(dc) ); } +#endif void wxGCDC::Init() { @@ -88,6 +99,7 @@ void wxGCDC::Init() m_brush = *wxWHITE_BRUSH; m_graphicContext = NULL; + m_logicalFunctionSupported = true; } @@ -101,14 +113,18 @@ void wxGCDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNU wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") ); wxCHECK_RET( bmp.Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") ); - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord w = bmp.GetWidth(); - wxCoord h = bmp.GetHeight(); - wxCoord ww = LogicalToDeviceXRel(w); - wxCoord hh = LogicalToDeviceYRel(h); - - m_graphicContext->DrawBitmap( bmp, xx , yy , ww , hh ); + if ( bmp.GetDepth() == 1 ) + { + m_graphicContext->SetPen(*wxTRANSPARENT_PEN); + m_graphicContext->SetBrush( wxBrush( m_textBackgroundColour , wxSOLID ) ); + m_graphicContext->DrawRectangle( x , y , bmp.GetWidth() , bmp.GetHeight() ); + m_graphicContext->SetBrush( wxBrush( m_textForegroundColour , wxSOLID ) ); + m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); + m_graphicContext->SetBrush( m_graphicContext->CreateBrush(m_brush)); + m_graphicContext->SetPen( m_graphicContext->CreatePen(m_pen)); + } + else + m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); } void wxGCDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) @@ -116,47 +132,38 @@ void wxGCDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") ); wxCHECK_RET( icon.Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") ); - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); wxCoord w = icon.GetWidth(); wxCoord h = icon.GetHeight(); - wxCoord ww = LogicalToDeviceXRel(w); - wxCoord hh = LogicalToDeviceYRel(h); - m_graphicContext->DrawIcon( icon , xx, yy, ww, hh ); + m_graphicContext->DrawIcon( icon , x, y, w, h ); } -void wxGCDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxGCDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") ); - wxCoord xx, yy, ww, hh; - xx = LogicalToDeviceX(x); - yy = LogicalToDeviceY(y); - ww = LogicalToDeviceXRel(width); - hh = LogicalToDeviceYRel(height); - - m_graphicContext->Clip( xx, yy, ww, hh ); + m_graphicContext->Clip( x, y, w, h ); if ( m_clipping ) { - m_clipX1 = wxMax( m_clipX1, xx ); - m_clipY1 = wxMax( m_clipY1, yy ); - m_clipX2 = wxMin( m_clipX2, (xx + ww) ); - m_clipY2 = wxMin( m_clipY2, (yy + hh) ); + m_clipX1 = wxMax( m_clipX1, x ); + m_clipY1 = wxMax( m_clipY1, y ); + m_clipX2 = wxMin( m_clipX2, (x + w) ); + m_clipY2 = wxMin( m_clipY2, (y + h) ); } else { m_clipping = true; - m_clipX1 = xx; - m_clipY1 = yy; - m_clipX2 = xx + ww; - m_clipY2 = yy + hh; + m_clipX1 = x; + m_clipY1 = y; + m_clipX2 = x + w; + m_clipY2 = y + h; } } void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) { + // region is in device coordinates wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") ); if (region.Empty()) @@ -165,45 +172,40 @@ void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) return; } + wxRegion logRegion( region ); wxCoord x, y, w, h; - region.GetBox( x, y, w, h ); - wxCoord xx, yy, ww, hh; - xx = LogicalToDeviceX(x); - yy = LogicalToDeviceY(y); - ww = LogicalToDeviceXRel(w); - hh = LogicalToDeviceYRel(h); - - // if we have a scaling that we cannot map onto native regions - // we must use the box - if ( ww != w || hh != h ) + + logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) ); + logRegion.GetBox( x, y, w, h ); + + m_graphicContext->Clip( logRegion ); + if ( m_clipping ) { - wxGCDC::DoSetClippingRegion( x, y, w, h ); + m_clipX1 = wxMax( m_clipX1, x ); + m_clipY1 = wxMax( m_clipY1, y ); + m_clipX2 = wxMin( m_clipX2, (x + w) ); + m_clipY2 = wxMin( m_clipY2, (y + h) ); } else { - m_graphicContext->Clip( region ); - if ( m_clipping ) - { - m_clipX1 = wxMax( m_clipX1, xx ); - m_clipY1 = wxMax( m_clipY1, yy ); - m_clipX2 = wxMin( m_clipX2, (xx + ww) ); - m_clipY2 = wxMin( m_clipY2, (yy + hh) ); - } - else - { - m_clipping = true; + m_clipping = true; - m_clipX1 = xx; - m_clipY1 = yy; - m_clipX2 = xx + ww; - m_clipY2 = yy + hh; - } + m_clipX1 = x; + m_clipY1 = y; + m_clipX2 = x + w; + m_clipY2 = y + h; } } void wxGCDC::DestroyClippingRegion() { m_graphicContext->ResetClip(); + // currently the clip eg of a window extends to the area between the scrollbars + // so we must explicitely make sure it only covers the area we want it to draw + int width, height ; + GetSize( &width , &height ) ; + m_graphicContext->Clip( DeviceToLogicalX(0) , DeviceToLogicalY(0) , width, height ); + m_graphicContext->SetPen( m_pen ); m_graphicContext->SetBrush( m_brush ); @@ -318,23 +320,19 @@ int wxGCDC::GetDepth() const void wxGCDC::ComputeScaleAndOrigin() { - // CMB: copy scale to see if it changes - double origScaleX = m_scaleX; - double origScaleY = m_scaleY; m_scaleX = m_logicalScaleX * m_userScaleX; m_scaleY = m_logicalScaleY * m_userScaleY; - m_deviceOriginX = m_deviceOriginX + m_logicalOriginX; - m_deviceOriginY = m_deviceOriginY + m_logicalOriginY; - // CMB: if scale has changed call SetPen to recalulate the line width - if (m_scaleX != origScaleX || m_scaleY != origScaleY) + if ( m_graphicContext ) { - // this is a bit artificial, but we need to force wxDC to think - // the pen has changed - wxPen pen(GetPen()); - m_pen = wxNullPen; - SetPen(pen); - SetFont(m_font); + m_matrixCurrent = m_graphicContext->CreateMatrix(); + m_matrixCurrent.Translate( m_deviceOriginX, m_deviceOriginY ); + m_matrixCurrent.Scale( m_scaleX, m_scaleY ); + // the logical origin sets the origin to have new coordinates + m_matrixCurrent.Translate( -m_logicalOriginX, -m_logicalOriginY ); + + m_graphicContext->SetTransform( m_matrixOriginal ); + m_graphicContext->ConcatTransform( m_matrixCurrent ); } } @@ -355,7 +353,7 @@ void wxGCDC::SetFont( const wxFont &font ) { wxFont f = font; if ( f.Ok() ) - f.SetPointSize( LogicalToDeviceYRel(font.GetPointSize())); + f.SetPointSize( /*LogicalToDeviceYRel*/(font.GetPointSize())); m_graphicContext->SetFont( f, m_textForegroundColour ); } } @@ -368,20 +366,7 @@ void wxGCDC::SetPen( const wxPen &pen ) m_pen = pen; if ( m_graphicContext ) { - if ( m_pen.GetStyle() == wxSOLID || m_pen.GetStyle() == wxTRANSPARENT ) - { - m_graphicContext->SetPen( m_pen ); - } - else - { - // we have to compensate for moved device origins etc. otherwise patterned pens are standing still - // eg when using a wxScrollWindow and scrolling around - int origX = LogicalToDeviceX( 0 ); - int origY = LogicalToDeviceY( 0 ); - m_graphicContext->Translate( origX , origY ); - m_graphicContext->SetPen( m_pen ); - m_graphicContext->Translate( -origX , -origY ); - } + m_graphicContext->SetPen( m_pen ); } } @@ -393,24 +378,10 @@ void wxGCDC::SetBrush( const wxBrush &brush ) m_brush = brush; if ( m_graphicContext ) { - if ( brush.GetStyle() == wxSOLID || brush.GetStyle() == wxTRANSPARENT ) - { - m_graphicContext->SetBrush( m_brush ); - } - else - { - // we have to compensate for moved device origins etc. otherwise patterned brushes are standing still - // eg when using a wxScrollWindow and scrolling around - // TODO on MSW / GDIPlus this still occurs with hatched brushes - int origX = LogicalToDeviceX(0); - int origY = LogicalToDeviceY(0); - m_graphicContext->Translate( origX , origY ); - m_graphicContext->SetBrush( m_brush ); - m_graphicContext->Translate( -origX , -origY ); - } + m_graphicContext->SetBrush( m_brush ); } } - + void wxGCDC::SetBackground( const wxBrush &brush ) { if (m_backgroundBrush == brush) @@ -427,17 +398,10 @@ void wxGCDC::SetLogicalFunction( int function ) return; m_logicalFunction = function; -#if wxMAC_USE_CORE_GRAPHICS_BLEND_MODES - - CGContextRef cgContext = ((wxCairoContext*)(m_graphicContext))->GetNativeContext(); - if ( m_logicalFunction == wxCOPY ) - CGContextSetBlendMode( cgContext, kCGBlendModeNormal ); - else if ( m_logicalFunction == wxINVERT ) - CGContextSetBlendMode( cgContext, kCGBlendModeExclusion ); + if ( m_graphicContext->SetLogicalFunction( function ) ) + m_logicalFunctionSupported=true; else - CGContextSetBlendMode( cgContext, kCGBlendModeNormal ); -#endif - + m_logicalFunctionSupported=false; } bool wxGCDC::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), @@ -456,18 +420,10 @@ void wxGCDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") ); -#if !wxMAC_USE_CORE_GRAPHICS_BLEND_MODES - - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; -#endif - wxCoord xx1 = LogicalToDeviceX(x1); - wxCoord yy1 = LogicalToDeviceY(y1); - wxCoord xx2 = LogicalToDeviceX(x2); - wxCoord yy2 = LogicalToDeviceY(y2); - - m_graphicContext->StrokeLine(xx1,yy1,xx2,yy2); + m_graphicContext->StrokeLine(x1,y1,x2,y2); CalcBoundingBox(x1, y1); CalcBoundingBox(x2, y2); @@ -477,25 +433,18 @@ void wxGCDC::DoCrossHair( wxCoord x, wxCoord y ) { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; int w = 0, h = 0; GetSize( &w, &h ); - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord xw = LogicalToDeviceX(w); - wxCoord x0 = LogicalToDeviceX(0); - wxCoord y0 = LogicalToDeviceY(0); - wxCoord yh = LogicalToDeviceY(h); - - m_graphicContext->StrokeLine(x0,yy,xw,yy); - m_graphicContext->StrokeLine(xx,y0,xx,yh); + m_graphicContext->StrokeLine(0,y,w,y); + m_graphicContext->StrokeLine(x,0,x,h); - CalcBoundingBox(x0, y0); - CalcBoundingBox(x0+xw, y0+yh); + CalcBoundingBox(0, 0); + CalcBoundingBox(0+w, 0+h); } void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, @@ -504,22 +453,15 @@ void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - wxCoord xx1 = LogicalToDeviceX(x1); - wxCoord yy1 = LogicalToDeviceY(y1); - wxCoord xx2 = LogicalToDeviceX(x2); - wxCoord yy2 = LogicalToDeviceY(y2); - wxCoord xxc = LogicalToDeviceX(xc); - wxCoord yyc = LogicalToDeviceY(yc); - - double dx = xx1 - xxc; - double dy = yy1 - yyc; + double dx = x1 - xc; + double dy = y1 - yc; double radius = sqrt((double)(dx * dx + dy * dy)); wxCoord rad = (wxCoord)radius; double sa, ea; - if (xx1 == xx2 && yy1 == yy2) + if (x1 == x2 && y1 == y2) { sa = 0.0; ea = 360.0; @@ -530,24 +472,25 @@ void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, } else { - sa = (xx1 - xxc == 0) ? - (yy1 - yyc < 0) ? 90.0 : -90.0 : - -atan2(double(yy1 - yyc), double(xx1 - xxc)) * RAD2DEG; - ea = (xx2 - xxc == 0) ? - (yy2 - yyc < 0) ? 90.0 : -90.0 : - -atan2(double(yy2 - yyc), double(xx2 - xxc)) * RAD2DEG; + sa = (x1 - xc == 0) ? + (y1 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG; + ea = (x2 - xc == 0) ? + (y2 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG; } bool fill = m_brush.GetStyle() != wxTRANSPARENT; - wxGraphicsPath* path = m_graphicContext->CreatePath(); + wxGraphicsPath path = m_graphicContext->CreatePath(); if ( fill && ((x1!=x2)||(y1!=y2)) ) - path->MoveToPoint( xxc, yyc ); - path->AddArc( xxc, yyc , rad , DegToRad(sa) , DegToRad(ea), false ); + path.MoveToPoint( xc, yc ); + // since these angles (ea,sa) are measured counter-clockwise, we invert them to + // get clockwise angles + path.AddArc( xc, yc , rad , DegToRad(-sa) , DegToRad(-ea), false ); if ( fill && ((x1!=x2)||(y1!=y2)) ) - path->AddLineToPoint( xxc, yyc ); + path.AddLineToPoint( xc, yc ); m_graphicContext->DrawPath(path); - delete path; } void wxGCDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, @@ -555,43 +498,20 @@ void wxGCDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord ww = m_signX * LogicalToDeviceXRel(w); - wxCoord hh = m_signY * LogicalToDeviceYRel(h); - - // handle -ve width and/or height - if (ww < 0) - { - ww = -ww; - xx = xx - ww; - } - if (hh < 0) - { - hh = -hh; - yy = yy - hh; - } - - bool fill = m_brush.GetStyle() != wxTRANSPARENT; - - wxGraphicsPath* path = m_graphicContext->CreatePath(); + wxGraphicsPath path = m_graphicContext->CreatePath(); m_graphicContext->PushState(); - m_graphicContext->Translate(xx+ww/2,yy+hh/2); - wxDouble factor = ((wxDouble) ww) / hh; + m_graphicContext->Translate(x+w/2.0,y+h/2.0); + wxDouble factor = ((wxDouble) w) / h; m_graphicContext->Scale( factor , 1.0); - if ( fill && (sa!=ea) ) - path->MoveToPoint(0,0); + // since these angles (ea,sa) are measured counter-clockwise, we invert them to // get clockwise angles - path->AddArc( 0, 0, hh/2 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); - if ( fill && (sa!=ea) ) - path->AddLineToPoint(0,0); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); m_graphicContext->DrawPath( path ); m_graphicContext->PopState(); - delete path; } void wxGCDC::DoDrawPoint( wxCoord x, wxCoord y ) @@ -606,17 +526,14 @@ void wxGCDC::DoDrawLines(int n, wxPoint points[], { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") ); -#if !wxMAC_USE_CORE_GRAPHICS_BLEND_MODES - - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; -#endif wxPoint2DDouble* pointsD = new wxPoint2DDouble[n]; for( int i = 0; i < n; ++i) { - pointsD[i].m_x = LogicalToDeviceX(points[i].x + xoffset); - pointsD[i].m_y = LogicalToDeviceY(points[i].y + yoffset); + pointsD[i].m_x = points[i].x + xoffset; + pointsD[i].m_y = points[i].y + yoffset; } m_graphicContext->StrokeLines( n , pointsD); @@ -628,10 +545,10 @@ void wxGCDC::DoDrawSpline(wxList *points) { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - wxGraphicsPath* path = m_graphicContext->CreatePath(); + wxGraphicsPath path = m_graphicContext->CreatePath(); wxList::compatibility_iterator node = points->GetFirst(); if (node == wxList::compatibility_iterator()) @@ -651,8 +568,8 @@ void wxGCDC::DoDrawSpline(wxList *points) wxCoord cx1 = ( x1 + x2 ) / 2; wxCoord cy1 = ( y1 + y2 ) / 2; - path->MoveToPoint( LogicalToDeviceX( x1 ) , LogicalToDeviceY( y1 ) ); - path->AddLineToPoint( LogicalToDeviceX( cx1 ) , LogicalToDeviceY( cy1 ) ); + path.MoveToPoint( x1 , y1 ); + path.AddLineToPoint( cx1 , cy1 ); #if !wxUSE_STL while ((node = node->GetNext()) != NULL) @@ -670,18 +587,15 @@ void wxGCDC::DoDrawSpline(wxList *points) wxCoord cx4 = (x1 + x2) / 2; wxCoord cy4 = (y1 + y2) / 2; - path->AddQuadCurveToPoint( - LogicalToDeviceX( x1 ) , LogicalToDeviceY( y1 ) , - LogicalToDeviceX( cx4 ) , LogicalToDeviceY( cy4 ) ); + path.AddQuadCurveToPoint(x1 , y1 ,cx4 , cy4 ); cx1 = cx4; cy1 = cy4; } - path->AddLineToPoint( LogicalToDeviceX( x2 ) , LogicalToDeviceY( y2 ) ); + path.AddLineToPoint( x2 , y2 ); m_graphicContext->StrokePath( path ); - delete path; } #endif // wxUSE_SPLINES @@ -693,7 +607,7 @@ void wxGCDC::DoDrawPolygon( int n, wxPoint points[], if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) ) return; - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; bool closeIt = false; @@ -703,8 +617,8 @@ void wxGCDC::DoDrawPolygon( int n, wxPoint points[], wxPoint2DDouble* pointsD = new wxPoint2DDouble[n+(closeIt?1:0)]; for( int i = 0; i < n; ++i) { - pointsD[i].m_x = LogicalToDeviceX(points[i].x + xoffset); - pointsD[i].m_y = LogicalToDeviceY(points[i].y + yoffset); + pointsD[i].m_x = points[i].x + xoffset; + pointsD[i].m_y = points[i].y + yoffset; } if ( closeIt ) pointsD[n] = pointsD[0]; @@ -721,122 +635,89 @@ void wxGCDC::DoDrawPolyPolygon(int n, int fillStyle) { wxASSERT(n > 1); - wxGraphicsPath* path = m_graphicContext->CreatePath(); + wxGraphicsPath path = m_graphicContext->CreatePath(); int i = 0; for ( int j = 0; j < n; ++j) { wxPoint start = points[i]; - path->MoveToPoint(LogicalToDeviceX(start.x+ xoffset), LogicalToDeviceY(start.y+ yoffset)); + path.MoveToPoint( start.x+ xoffset, start.y+ yoffset); ++i; int l = count[j]; for ( int k = 1; k < l; ++k) { - path->AddLineToPoint( LogicalToDeviceX(points[i].x+ xoffset), LogicalToDeviceY(points[i].y+ yoffset)); + path.AddLineToPoint( points[i].x+ xoffset, points[i].y+ yoffset); ++i; } // close the polygon if ( start != points[i-1]) - path->AddLineToPoint( LogicalToDeviceX(start.x+ xoffset), LogicalToDeviceY(start.y+ yoffset)); + path.AddLineToPoint( start.x+ xoffset, start.y+ yoffset); } m_graphicContext->DrawPath( path , fillStyle); - delete path; } -void wxGCDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) +void wxGCDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord ww = m_signX * LogicalToDeviceXRel(width); - wxCoord hh = m_signY * LogicalToDeviceYRel(height); - // CMB: draw nothing if transformed w or h is 0 - if (ww == 0 || hh == 0) + if (w == 0 || h == 0) return; - // CMB: handle -ve width and/or height - if (ww < 0) - { - ww = -ww; - xx = xx - ww; - } - if (hh < 0) + if ( m_graphicContext->ShouldOffset() ) { - hh = -hh; - yy = yy - hh; + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; } - m_graphicContext->DrawRectangle( xx,yy,ww,hh); + m_graphicContext->DrawRectangle(x,y,w,h); } void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, - wxCoord width, wxCoord height, + wxCoord w, wxCoord h, double radius) { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; if (radius < 0.0) - radius = - radius * ((width < height) ? width : height); - wxCoord xx = LogicalToDeviceX(x); - wxCoord yy = LogicalToDeviceY(y); - wxCoord ww = m_signX * LogicalToDeviceXRel(width); - wxCoord hh = m_signY * LogicalToDeviceYRel(height); + radius = - radius * ((w < h) ? w : h); // CMB: draw nothing if transformed w or h is 0 - if (ww == 0 || hh == 0) + if (w == 0 || h == 0) return; - // CMB: handle -ve width and/or height - if (ww < 0) + if ( m_graphicContext->ShouldOffset() ) { - ww = -ww; - xx = xx - ww; + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; } - if (hh < 0) - { - hh = -hh; - yy = yy - hh; - } - - m_graphicContext->DrawRoundedRectangle( xx,yy,ww,hh,radius); + m_graphicContext->DrawRoundedRectangle( x,y,w,h,radius); } -void wxGCDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height) +void wxGCDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h) { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - wxDouble xx = LogicalToDeviceX(x); - wxDouble yy = LogicalToDeviceY(y); - wxDouble ww = m_signX * LogicalToDeviceXRel(width); - wxDouble hh = m_signY * LogicalToDeviceYRel(height); - - // CMB: draw nothing if transformed w or h is 0 - if (ww == 0 || hh == 0) - return; - - // CMB: handle -ve width and/or height - if (ww < 0) + if ( m_graphicContext->ShouldOffset() ) { - ww = -ww; - xx = xx - ww; + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; } - if (hh < 0) - { - hh = -hh; - yy = yy - hh; - } - - m_graphicContext->DrawEllipse(xx,yy,ww,hh); + m_graphicContext->DrawEllipse(x,y,w,h); } bool wxGCDC::CanDrawBitmap() const @@ -846,14 +727,30 @@ bool wxGCDC::CanDrawBitmap() const bool wxGCDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, - wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool WXUNUSED(useMask), + wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask, wxCoord xsrcMask, wxCoord ysrcMask ) { - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid DC") ); - wxCHECK_MSG( source->Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid source DC") ); + return DoStretchBlit( xdest, ydest, width, height, + source, xsrc, ysrc, width, height, logical_func, useMask, + xsrcMask,ysrcMask ); +} + +bool wxGCDC::DoStretchBlit( + wxCoord xdest, wxCoord ydest, wxCoord dstWidth, wxCoord dstHeight, + wxDC *source, wxCoord xsrc, wxCoord ysrc, wxCoord srcWidth, wxCoord srcHeight, + int logical_func , bool WXUNUSED(useMask), + wxCoord xsrcMask, wxCoord ysrcMask ) +{ + wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid DC") ); + wxCHECK_MSG( source->Ok(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid source DC") ); if ( logical_func == wxNO_OP ) return true; + else if ( logical_func != wxCOPY ) + { + wxFAIL_MSG( wxT("Blitting is only supported with wxCOPY logical operation.") ); + return false; + } if (xsrcMask == -1 && ysrcMask == -1) { @@ -861,59 +758,31 @@ bool wxGCDC::DoBlit( ysrcMask = ysrc; } - wxCoord yysrc = source-> LogicalToDeviceY(ysrc); - wxCoord xxsrc = source-> LogicalToDeviceX(xsrc); - wxCoord wwsrc = source-> LogicalToDeviceXRel(width); - wxCoord hhsrc = source-> LogicalToDeviceYRel(height); + wxRect subrect(source->LogicalToDeviceX(xsrc), + source->LogicalToDeviceY(ysrc), + source->LogicalToDeviceXRel(srcWidth), + source->LogicalToDeviceYRel(srcHeight)); - wxCoord yydest = LogicalToDeviceY(ydest); - wxCoord xxdest = LogicalToDeviceX(xdest); - wxCoord wwdest = LogicalToDeviceXRel(width); - wxCoord hhdest = LogicalToDeviceYRel(height); + // if needed clip the subrect down to the size of the source DC + wxCoord sw, sh; + source->GetSize(&sw, &sh); + sw = source->LogicalToDeviceXRel(sw); + sh = source->LogicalToDeviceYRel(sh); + if (subrect.x + subrect.width > sw) + subrect.width = sw - subrect.x; + if (subrect.y + subrect.height > sh) + subrect.height = sh - subrect.y; - wxMemoryDC* memdc = wxDynamicCast(source,wxMemoryDC); - if ( memdc && logical_func == wxCOPY ) - { - wxBitmap blit = memdc->GetSelectedBitmap(); - - wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") ); - - wxCoord bmpwidth = blit.GetWidth(); - wxCoord bmpheight = blit.GetHeight(); - - if ( xxsrc != 0 || yysrc != 0 || bmpwidth != wwsrc || bmpheight != hhsrc ) - { - wwsrc = wxMin( wwsrc , bmpwidth - xxsrc ); - hhsrc = wxMin( hhsrc , bmpheight - yysrc ); - if ( wwsrc > 0 && hhsrc > 0 ) - { - if ( xxsrc >= 0 && yysrc >= 0 ) - { - wxRect subrect( xxsrc, yysrc, wwsrc , hhsrc ); - // TODO we perhaps could add a DrawSubBitmap call to dc for performance reasons - blit = blit.GetSubBitmap( subrect ); - } - else - { - // in this case we'd probably have to adjust the different coordinates, but - // we have to find out proper contract first - blit = wxNullBitmap; - } - } - else - { - blit = wxNullBitmap; - } - } + wxBitmap blit = source->GetAsBitmap( &subrect ); - if ( blit.Ok() ) - { - m_graphicContext->DrawBitmap( blit, xxdest , yydest , wwdest , hhdest ); - } + if ( blit.Ok() ) + { + m_graphicContext->DrawBitmap( blit, xdest, ydest, + dstWidth, dstHeight); } else { - wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts, and only with wxCOPY logical operation.") ); + wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") ); return false; } @@ -927,13 +796,13 @@ void wxGCDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y, if ( str.length() == 0 ) return; - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; - int drawX = LogicalToDeviceX(x); - int drawY = LogicalToDeviceY(y); - - m_graphicContext->DrawText( str, drawX ,drawY , DegToRad(angle )); + if ( m_backgroundMode == wxTRANSPARENT ) + m_graphicContext->DrawText( str, x ,y , DegToRad(angle )); + else + m_graphicContext->DrawText( str, x ,y , DegToRad(angle ), m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); } void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y) @@ -942,13 +811,14 @@ void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y) if ( str.length() == 0 ) return; - if ( m_logicalFunction != wxCOPY ) - return; - int drawX = LogicalToDeviceX(x); - int drawY = LogicalToDeviceY(y); + if ( !m_logicalFunctionSupported ) + return; - m_graphicContext->DrawText( str, drawX ,drawY); + if ( m_backgroundMode == wxTRANSPARENT ) + m_graphicContext->DrawText( str, x ,y); + else + m_graphicContext->DrawText( str, x ,y , m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); } bool wxGCDC::CanGetTextExtent() const @@ -960,7 +830,7 @@ bool wxGCDC::CanGetTextExtent() const void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height, wxCoord *descent, wxCoord *externalLeading , - wxFont *theFont ) const + const wxFont *theFont ) const { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") ); @@ -974,13 +844,13 @@ void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *heig m_graphicContext->GetTextExtent( str, &w, &h, &d, &e ); if ( height ) - *height = DeviceToLogicalYRel((wxCoord)h); + *height = (wxCoord)h; if ( descent ) - *descent = DeviceToLogicalYRel((wxCoord)d); + *descent = (wxCoord)d; if ( externalLeading ) - *externalLeading = DeviceToLogicalYRel((wxCoord)e); + *externalLeading = (wxCoord)e; if ( width ) - *width = DeviceToLogicalXRel((wxCoord)w); + *width = (wxCoord)w; if ( theFont ) { @@ -1000,7 +870,7 @@ bool wxGCDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) c m_graphicContext->GetPartialTextExtents( text, widthsD ); for ( size_t i = 0; i < widths.GetCount(); ++i ) - widths[i] = DeviceToLogicalXRel((wxCoord)(widthsD[i] + 0.5)); + widths[i] = (wxCoord)(widthsD[i] + 0.5); return true; } @@ -1029,7 +899,7 @@ void wxGCDC::Clear(void) wxPen p = *wxTRANSPARENT_PEN; m_graphicContext->SetPen( p ); DoDrawRectangle( 0, 0, 32000 , 32000 ); - m_graphicContext->SetPen( m_pen ); + m_graphicContext->SetPen( m_pen ); m_graphicContext->SetBrush( m_brush ); } @@ -1072,31 +942,13 @@ void wxGCDC::DoGradientFillLinear(const wxRect& rect, break; } - m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush( - LogicalToDeviceX(start.x),LogicalToDeviceY(start.y), - LogicalToDeviceX(end.x),LogicalToDeviceY(end.y), initialColour, destColour)); - - wxDouble xx = LogicalToDeviceX(rect.x); - wxDouble yy = LogicalToDeviceY(rect.y); - wxDouble ww = m_signX * LogicalToDeviceXRel(rect.width); - wxDouble hh = m_signY * LogicalToDeviceYRel(rect.height); - - if (ww == 0 || hh == 0) + if (rect.width == 0 || rect.height == 0) return; - if (ww < 0) - { - ww = -ww; - xx = xx - ww; - } - if (hh < 0) - { - hh = -hh; - yy = yy - hh; - } - + m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush( + start.x,start.y,end.x,end.y, initialColour, destColour)); m_graphicContext->SetPen(*wxTRANSPARENT_PEN); - m_graphicContext->DrawRectangle(xx,yy,ww,hh); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); m_graphicContext->SetPen(m_pen); } @@ -1114,36 +966,17 @@ void wxGCDC::DoGradientFillConcentric(const wxRect& rect, else nRadius = cy; - wxDouble xx = LogicalToDeviceX(rect.x); - wxDouble yy = LogicalToDeviceY(rect.y); - wxDouble ww = m_signX * LogicalToDeviceXRel(rect.width); - wxDouble hh = m_signY * LogicalToDeviceYRel(rect.height); - - if (ww == 0 || hh == 0) - return; - - if (ww < 0) - { - ww = -ww; - xx = xx - ww; - } - if (hh < 0) - { - hh = -hh; - yy = yy - hh; - } - + // make sure the background is filled (todo move into specific platform implementation ?) m_graphicContext->SetPen(*wxTRANSPARENT_PEN); m_graphicContext->SetBrush( wxBrush( destColour) ); - m_graphicContext->DrawRectangle( xx,yy,ww,hh); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); m_graphicContext->SetBrush( m_graphicContext->CreateRadialGradientBrush( - xx+LogicalToDeviceX(circleCenter.x),yy+LogicalToDeviceY(circleCenter.y), - xx+LogicalToDeviceX(circleCenter.x),yy+LogicalToDeviceY(circleCenter.y), - LogicalToDeviceXRel(nRadius), - initialColour,destColour)); + rect.x+circleCenter.x,rect.y+circleCenter.y, + rect.x+circleCenter.x,rect.y+circleCenter.y, + nRadius,initialColour,destColour)); - m_graphicContext->DrawRectangle( xx,yy,ww,hh); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); m_graphicContext->SetPen(m_pen); }