X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0ebd9515e5df4a756d27eea9ea9ee9ac193dd7bd..6ad0a7d52fc2a0ec7a434d1c7edb6e00d09853a4:/src/common/dcgraph.cpp?ds=sidebyside diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp index c9889d2d39..93ee03514d 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,25 +58,34 @@ wxGCDC::wxGCDC() } void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx ) -{ +{ delete m_graphicContext; m_graphicContext = ctx; - m_matrixOriginal = m_graphicContext->GetTransform(); + 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_matrixOriginal = m_graphicContext->GetTransform(); - 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() { @@ -90,6 +99,7 @@ void wxGCDC::Init() m_brush = *wxWHITE_BRUSH; m_graphicContext = NULL; + m_logicalFunctionSupported = true; } @@ -103,7 +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") ); - m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); + 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 ) @@ -142,6 +163,7 @@ void wxGCDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) { + // region is in device coordinates wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") ); if (region.Empty()) @@ -150,10 +172,13 @@ void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) return; } + wxRegion logRegion( region ); wxCoord x, y, w, h; - region.GetBox( x, y, w, h ); - m_graphicContext->Clip( region ); + logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) ); + logRegion.GetBox( x, y, w, h ); + + m_graphicContext->Clip( logRegion ); if ( m_clipping ) { m_clipX1 = wxMax( m_clipX1, x ); @@ -175,6 +200,12 @@ void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) 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 ); @@ -291,15 +322,18 @@ void wxGCDC::ComputeScaleAndOrigin() { m_scaleX = m_logicalScaleX * m_userScaleX; m_scaleY = m_logicalScaleY * m_userScaleY; - m_deviceOriginX = /* m_deviceOriginX + */ m_logicalOriginX; - m_deviceOriginY = /* m_deviceOriginY + */ m_logicalOriginY; - m_matrixCurrent = m_graphicContext->CreateMatrix(); - m_matrixCurrent.Translate( m_deviceOriginX , m_deviceOriginY ); - m_matrixCurrent.Scale( m_scaleX, m_scaleY ); - - m_graphicContext->SetTransform( m_matrixOriginal ); - m_graphicContext->ConcatTransform( m_matrixCurrent ); + if ( m_graphicContext ) + { + 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 ); + } } void wxGCDC::SetPalette( const wxPalette& WXUNUSED(palette) ) @@ -347,7 +381,7 @@ void wxGCDC::SetBrush( const wxBrush &brush ) m_graphicContext->SetBrush( m_brush ); } } - + void wxGCDC::SetBackground( const wxBrush &brush ) { if (m_backgroundBrush == brush) @@ -364,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), @@ -393,11 +420,8 @@ 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 m_graphicContext->StrokeLine(x1,y1,x2,y2); @@ -409,7 +433,7 @@ 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; @@ -429,7 +453,7 @@ void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; double dx = x1 - xc; @@ -461,7 +485,9 @@ void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, wxGraphicsPath path = m_graphicContext->CreatePath(); if ( fill && ((x1!=x2)||(y1!=y2)) ) path.MoveToPoint( xc, yc ); - path.AddArc( xc, yc , rad , DegToRad(sa) , DegToRad(ea), false ); + // 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( xc, yc ); m_graphicContext->DrawPath(path); @@ -472,23 +498,18 @@ 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; - bool fill = m_brush.GetStyle() != wxTRANSPARENT; - wxGraphicsPath path = m_graphicContext->CreatePath(); m_graphicContext->PushState(); - m_graphicContext->Translate(x+w/2,y+h/2); + 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, h/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(); } @@ -505,11 +526,8 @@ 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) @@ -527,7 +545,7 @@ 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(); @@ -589,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; @@ -642,7 +660,7 @@ 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; // CMB: draw nothing if transformed w or h is 0 @@ -665,7 +683,7 @@ void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, { wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") ); - if ( m_logicalFunction != wxCOPY ) + if ( !m_logicalFunctionSupported ) return; if (radius < 0.0) @@ -675,6 +693,13 @@ void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, if (w == 0 || h == 0) return; + if ( m_graphicContext->ShouldOffset() ) + { + // 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->DrawRoundedRectangle( x,y,w,h,radius); } @@ -682,9 +707,16 @@ 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; + if ( m_graphicContext->ShouldOffset() ) + { + // 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->DrawEllipse(x,y,w,h); } @@ -695,12 +727,23 @@ 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 ) @@ -715,62 +758,27 @@ 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); - - wxBitmap blit; - wxMemoryDC* memdc = wxDynamicCast(source,wxMemoryDC); - if ( memdc ) - { - blit = memdc->GetSelectedBitmap(); + wxRect subrect(source->LogicalToDeviceX(xsrc), + source->LogicalToDeviceY(ysrc), + source->LogicalToDeviceXRel(srcWidth), + source->LogicalToDeviceYRel(srcHeight)); - wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") ); + // 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; - wxCoord bmpwidth = blit.GetWidth(); - wxCoord bmpheight = blit.GetHeight(); + wxBitmap blit = source->GetAsBitmap( &subrect ); - 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; - } - } - } - else - { - wxWindowDC* windc = wxDynamicCast(source,wxWindowDC); - if (windc) - { - wxBitmap bmp; - bmp = windc->GetAsBitmap(); - if (bmp.IsOk()) - blit = bmp.GetSubBitmap( wxRect(xsrc, ysrc, width, height ) ); - } - } - if ( blit.Ok() ) { - m_graphicContext->DrawBitmap( blit, xdest , ydest , width , height ); + m_graphicContext->DrawBitmap( blit, xdest, ydest, + dstWidth, dstHeight); } else { @@ -788,10 +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; - m_graphicContext->DrawText( str, x ,y , 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) @@ -800,10 +811,14 @@ void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y) if ( str.length() == 0 ) return; - if ( m_logicalFunction != wxCOPY ) + + if ( !m_logicalFunctionSupported ) return; - m_graphicContext->DrawText( str, x ,y); + 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 @@ -829,13 +844,13 @@ void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *heig m_graphicContext->GetTextExtent( str, &w, &h, &d, &e ); if ( height ) - *height = h; + *height = (wxCoord)h; if ( descent ) - *descent = d; + *descent = (wxCoord)d; if ( externalLeading ) - *externalLeading =e; + *externalLeading = (wxCoord)e; if ( width ) - *width = w; + *width = (wxCoord)w; if ( theFont ) { @@ -884,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 ); }