📄 graphics.cpp
字号:
wxMacCFRefHolder<HIShapeRef> m_clipRgn;};//-----------------------------------------------------------------------------// device context implementation//// more and more of the dc functionality should be implemented by calling// the appropricate wxMacCoreGraphicsContext, but we will have to do that step by step// also coordinate conversions should be moved to native matrix ops//-----------------------------------------------------------------------------// we always stock two context states, one at entry, to be able to preserve the// state we were called with, the other one after changing to HI Graphics orientation// (this one is used for getting back clippings etc)//-----------------------------------------------------------------------------// wxMacCoreGraphicsContext implementation//-----------------------------------------------------------------------------IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)void wxMacCoreGraphicsContext::Init(){ m_cgContext = NULL; m_releaseContext = false; m_windowRef = NULL; HIRect r = CGRectMake(0,0,0,0); m_clipRgn.Set(HIShapeCreateWithRect(&r));}wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, CGContextRef cgcontext ) : wxGraphicsContext(renderer){ Init(); SetNativeContext(cgcontext);}wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, WindowRef window ): wxGraphicsContext(renderer){ Init(); m_windowRef = window;}wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxGraphicsRenderer* renderer, wxWindow* window ): wxGraphicsContext(renderer){ Init(); m_windowRef = (WindowRef) window->MacGetTopLevelWindowRef(); int originX , originY; originX = originY = 0; window->MacWindowToRootWindow( &originX , &originY ); Rect bounds; GetWindowBounds( m_windowRef, kWindowContentRgn, &bounds ); m_windowTransform = CGAffineTransformMakeTranslation( 0 , bounds.bottom - bounds.top ); m_windowTransform = CGAffineTransformScale( m_windowTransform , 1 , -1 ); m_windowTransform = CGAffineTransformTranslate( m_windowTransform, originX, originY ) ;}wxMacCoreGraphicsContext::wxMacCoreGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsContext(renderer){ Init();}wxMacCoreGraphicsContext::wxMacCoreGraphicsContext() : wxGraphicsContext(NULL){ Init(); wxLogDebug(wxT("Illegal Constructor called"));}wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext(){ SetNativeContext(NULL);}void wxMacCoreGraphicsContext::EnsureIsValid(){ if ( !m_cgContext ) { OSStatus status = QDBeginCGContext( GetWindowPort( m_windowRef ) , &m_cgContext ); wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") ); CGContextConcatCTM( m_cgContext, m_windowTransform ); CGContextSaveGState( m_cgContext ); m_releaseContext = true; if ( !HIShapeIsEmpty(m_clipRgn) ) { // the clip region is in device coordinates, so we convert this again to user coordinates wxMacCFRefHolder<HIMutableShapeRef> hishape ; hishape.Set( HIShapeCreateMutableCopy( m_clipRgn ) ); CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero,m_windowTransform); HIShapeOffset( hishape, -transformedOrigin.x, -transformedOrigin.y ); HIShapeReplacePathInCGContext( hishape, m_cgContext ); CGContextClip( m_cgContext ); } CGContextSaveGState( m_cgContext ); }}bool wxMacCoreGraphicsContext::SetLogicalFunction( int function ){ if (m_logicalFunction == function) return true; EnsureIsValid(); bool retval = false; if ( function == wxCOPY ) { retval = true;#if wxMAC_USE_CORE_GRAPHICS_BLEND_MODES if ( CGContextSetBlendMode != NULL ) { CGContextSetBlendMode( m_cgContext, kCGBlendModeNormal ); CGContextSetShouldAntialias( m_cgContext, true ); }#endif } else if ( function == wxINVERT || function == wxXOR ) {#if wxMAC_USE_CORE_GRAPHICS_BLEND_MODES if ( CGContextSetBlendMode != NULL ) { // change color to white CGContextSetBlendMode( m_cgContext, kCGBlendModeExclusion ); CGContextSetShouldAntialias( m_cgContext, false ); retval = true; }#endif } if (retval) m_logicalFunction = function; return retval ;}void wxMacCoreGraphicsContext::Clip( const wxRegion ®ion ){ if( m_cgContext ) { HIShapeRef shape = HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() ); HIShapeReplacePathInCGContext( shape, m_cgContext ); CGContextClip( m_cgContext ); CFRelease( shape ); } else { // this offsetting to device coords is not really correct, but since we cannot apply affine transforms // to regions we try at least to have correct translations wxMacCFRefHolder<HIShapeRef> hishape ; hishape.Set( HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() )); HIMutableShapeRef mutableShape = HIShapeCreateMutableCopy( hishape ); CGPoint transformedOrigin = CGPointApplyAffineTransform( CGPointZero, m_windowTransform ); HIShapeOffset( mutableShape, transformedOrigin.x, transformedOrigin.y ); m_clipRgn.Set(mutableShape); }}// clips drawings to the rectvoid wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ){ HIRect r = CGRectMake( x , y , w , h ); if ( m_cgContext ) { CGContextClipToRect( m_cgContext, r ); } else { // the clipping itself must be stored as device coordinates, otherwise // we cannot apply it back correctly r.origin= CGPointApplyAffineTransform( r.origin, m_windowTransform ); m_clipRgn.Set(HIShapeCreateWithRect(&r)); }} // resets the clipping to original extentvoid wxMacCoreGraphicsContext::ResetClip(){ if ( m_cgContext ) { // there is no way for clearing the clip, we can only revert to the stored // state, but then we have to make sure everything else is NOT restored CGAffineTransform transform = CGContextGetCTM( m_cgContext ); CGContextRestoreGState( m_cgContext ); CGContextSaveGState( m_cgContext ); CGAffineTransform transformNew = CGContextGetCTM( m_cgContext ); transformNew = CGAffineTransformInvert( transformNew ) ; CGContextConcatCTM( m_cgContext, transformNew); CGContextConcatCTM( m_cgContext, transform); } else { HIRect r = CGRectMake(0,0,0,0); m_clipRgn.Set(HIShapeCreateWithRect(&r)); }}void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath &path ){ if ( m_pen.IsNull() ) return ; EnsureIsValid(); bool offset = ShouldOffset(); if ( offset ) CGContextTranslateCTM( m_cgContext, 0.5, 0.5 ); ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this); CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() ); CGContextStrokePath( m_cgContext ); if ( offset ) CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );}void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath &path , int fillStyle ){ if ( !m_brush.IsNull() && ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) { // when using shading, we cannot draw pen and brush at the same time // revert to the base implementation of first filling and then stroking wxGraphicsContext::DrawPath( path, fillStyle ); return; } CGPathDrawingMode mode = kCGPathFill ; if ( m_brush.IsNull() ) { if ( m_pen.IsNull() ) return; else mode = kCGPathStroke; } else { if ( m_pen.IsNull() ) { if ( fillStyle == wxODDEVEN_RULE ) mode = kCGPathEOFill; else mode = kCGPathFill; } else { if ( fillStyle == wxODDEVEN_RULE ) mode = kCGPathEOFillStroke; else mode = kCGPathFillStroke; } } EnsureIsValid(); if ( !m_brush.IsNull() ) ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this); if ( !m_pen.IsNull() ) ((wxMacCoreGraphicsPenData*)m_pen.GetRefData())->Apply(this); bool offset = ShouldOffset(); if ( offset ) CGContextTranslateCTM( m_cgContext, 0.5, 0.5 ); CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() ); CGContextDrawPath( m_cgContext , mode ); if ( offset ) CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );}void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath &path , int fillStyle ){ if ( m_brush.IsNull() ) return; EnsureIsValid(); if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) { CGContextSaveGState( m_cgContext ); CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() ); CGContextClip( m_cgContext ); CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() ); CGContextRestoreGState( m_cgContext); } else { ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this); CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() ); if ( fillStyle == wxODDEVEN_RULE ) CGContextEOFillPath( m_cgContext ); else CGContextFillPath( m_cgContext ); }}void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg ){ // we allow either setting or clearing but not replacing wxASSERT( m_cgContext == NULL || cg == NULL ); if ( m_cgContext ) { // TODO : when is this necessary - should we add a Flush() method ? CGContextSynchronize( m_cgContext ); CGContextRestoreGState( m_cgContext ); CGContextRestoreGState( m_cgContext ); if ( m_releaseContext ) QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext); else CGContextRelease(m_cgContext); } m_cgContext = cg; // FIXME: This check is needed because currently we need to use a DC/GraphicsContext // in order to get font properties, like wxFont::GetPixelSize, but since we don't have // a native window attached to use, I create a wxGraphicsContext with a NULL CGContextRef // for this one operation. // When wxFont::GetPixelSize on Mac no longer needs a graphics context, this check // can be removed. if (m_cgContext) { CGContextRetain(m_cgContext); CGContextSaveGState( m_cgContext ); CGContextSaveGState( m_cgContext ); m_releaseContext = false; }}void wxMacCoreGraphicsContext::Translate( wxDouble dx , wxDouble dy ){ if ( m_cgContext ) CGContextTranslateCTM( m_cgContext, dx, dy ); else m_windowTransform = CGAffineTransformTranslate(m_windowTransform,dx,dy);}void wxMacCoreGraphicsContext::Scale( wxDouble xScale , wxDouble yScale ){ if ( m_cgContext ) CGContextScaleCTM( m_cgContext , xScale , yScale ); else m_windowTransform = CGAffineTransformScale(m_windowTransform,xScale,yScale);}void wxMacCoreGraphicsContext::Rotate( wxDouble angle ){ if ( m_cgContext ) CGContextRotateCTM( m_cgContext , angle ); else m_windowTransform = CGAffineTransformRotate(m_windowTransform,angle);}void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ){ EnsureIsValid(); CGImageRef image = (CGImageRef)( bmp.CGImageCreate() ); HIRect r = CGRectMake( x , y , w , h ); if ( bmp.GetDepth() == 1 ) { // is is a mask, the '1' in the mask tell where to draw the current brush if ( !m_brush.IsNull() ) { if ( ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->IsShading() ) { // TODO clip to mask /* CGContextSaveGState( m_cgContext ); CGContextAddPath( m_cgContext , (CGPathRef) path.GetNativePath() ); CGContextClip( m_cgContext ); CGContextDrawShading( m_cgContext, ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->GetShading() ); CGContextRestoreGState( m_cgContext); */ } else { ((wxMacCoreGraphicsBrushData*)m_brush.GetRefData())->Apply(this); HIViewDrawCGImage( m_cgContext , &r , image ); } } } else { HIViewDrawCGImage( m_cgContext , &r , image ); } CGImageRelease( image );}void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ){ EnsureIsValid(); CGRect r = CGRectMake( 00 , 00 , w , h ); CGContextSaveGState( m_cgContext ); CGContextTranslateCTM( m_cgContext, x , y + h ); CGContextScaleCTM( m_cgContext, 1, -1 ); PlotIconRefInContext( m_cgContext , &r , kAlignNone , kTransformNone , NULL , kPlotIconRefNormalFlags , MAC_WXHICON( icon.GetHICON() ) ); CGContextRestoreGState( m_cgContext );}void wxMacCoreGraphicsContext::PushState(){ EnsureIsValid(); CGContextSaveGState( m_cgContext );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -