]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/carbon/graphics.cpp
Added outline style sample and vetoing of style sheet changing when loading;
[wxWidgets.git] / src / mac / carbon / graphics.cpp
index 34b4b5629ada5535657f4fa229411fb247cc8ac4..49b58ca394faca31a8ab5ccbc77e5acb42e02bdd 100755 (executable)
 typedef float CGFloat;
 #endif
 
+//-----------------------------------------------------------------------------
+// constants
+//-----------------------------------------------------------------------------
+
+#if !defined( __DARWIN__ ) || defined(__MWERKS__)
+#ifndef M_PI
+const double M_PI = 3.14159265358979;
+#endif
+#endif
+
+static const double RAD2DEG = 180.0 / M_PI;
+
 //
 // Graphics Path
 //
 
 class WXDLLEXPORT wxMacCoreGraphicsPath : public wxGraphicsPath
 {
-    DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsPath)
 public :
     wxMacCoreGraphicsPath();
     ~wxMacCoreGraphicsPath();
@@ -84,11 +95,24 @@ public :
     // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1)
     virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r );
     
-    CGPathRef GetPath() const;
+    // returns the native path
+    virtual void * GetNativePath() const { return m_path; }
+    
+    // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
+    virtual void UnGetNativePath(void *p) {}
+
+    DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsPath)
+    DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsPath)
 private :
     CGMutablePathRef m_path;
 };
 
+//-----------------------------------------------------------------------------
+// wxGraphicsPath implementation
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsPath, wxGraphicsPath)
+
 wxMacCoreGraphicsPath::wxMacCoreGraphicsPath()
 {
     m_path = CGPathCreateMutable();
@@ -149,11 +173,6 @@ void wxMacCoreGraphicsPath::CloseSubpath()
     CGPathCloseSubpath( m_path );
 }
 
-CGPathRef wxMacCoreGraphicsPath::GetPath() const
-{
-    return m_path;
-}
-
 // gets the last point of the current path, (0,0) if not yet set
 void wxMacCoreGraphicsPath::GetCurrentPoint( wxDouble& x, wxDouble&y)
 {
@@ -168,18 +187,18 @@ void wxMacCoreGraphicsPath::GetCurrentPoint( wxDouble& x, wxDouble&y)
 
 class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext
 {
-    DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
-
 public:
     wxMacCoreGraphicsContext( CGContextRef cgcontext );
     
     wxMacCoreGraphicsContext( WindowRef window );
     
+    wxMacCoreGraphicsContext( wxWindow* window );
+    
     wxMacCoreGraphicsContext();
     
     ~wxMacCoreGraphicsContext();
 
-       void Init();
+    void Init();
 
     // creates a path instance that corresponds to the type of graphics context, ie GDIPlus, cairo, CoreGraphics ...
     virtual wxGraphicsPath * CreatePath();
@@ -195,12 +214,12 @@ public:
 
     // clips drawings to the rect
     virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
-       
-       // resets the clipping to original extent
-       virtual void ResetClip();
+    
+    // resets the clipping to original extent
+    virtual void ResetClip();
 
-       virtual void * GetNativeContext();
-       
+    virtual void * GetNativeContext();
+    
     //
     // transformation
     //
@@ -237,7 +256,7 @@ public:
     virtual void SetFont( const wxFont &font );
     
     // sets the text color
-    virtual void SetTextColor( const wxColour &col );
+    virtual void SetTextColour( const wxColour &col );
 
     // strokes along a path with the current pen
     virtual void StrokePath( const wxGraphicsPath *path );
@@ -271,31 +290,39 @@ public:
 
     void SetNativeContext( CGContextRef cg );
     CGPathDrawingMode GetDrawingMode() const { return m_mode; }
+
+
+    virtual bool ShouldOffset() const
+    {
+        int penwidth = m_pen.GetWidth();
+        if ( penwidth == 0 )
+            penwidth = 1;
+        if ( m_pen.GetStyle() == wxTRANSPARENT )
+            penwidth = 0;
+        return ( penwidth % 2 ) == 1; 
+    }
+        
     
+    DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
+    DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsContext)
+
 private:
+    void EnsureIsValid();
+
     CGContextRef m_cgContext;
-       WindowRef m_windowRef;
-       bool m_releaseContext;
+    WindowRef m_windowRef;
+    int m_originX;
+    int m_originY;
+    wxMacCFRefHolder<HIShapeRef> m_clipRgn;
+    bool m_releaseContext;
     CGPathDrawingMode m_mode;
     ATSUStyle m_macATSUIStyle;
     wxPen m_pen;
     wxBrush m_brush;
-       wxFont m_font;
+    wxFont m_font;
     wxColor m_textForegroundColor;
 };
 
-//-----------------------------------------------------------------------------
-// constants
-//-----------------------------------------------------------------------------
-
-#if !defined( __DARWIN__ ) || defined(__MWERKS__)
-#ifndef M_PI
-const double M_PI = 3.14159265358979;
-#endif
-#endif
-
-static const double RAD2DEG = 180.0 / M_PI;
-
 //-----------------------------------------------------------------------------
 // device context implementation
 //
@@ -308,109 +335,159 @@ static const double RAD2DEG = 180.0 / M_PI;
 // state we were called with, the other one after changing to HI Graphics orientation
 // (this one is used for getting back clippings etc)
 
-//-----------------------------------------------------------------------------
-// wxGraphicsPath implementation
-//-----------------------------------------------------------------------------
-
 //-----------------------------------------------------------------------------
 // wxGraphicsContext implementation
 //-----------------------------------------------------------------------------
 
+IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)
+
 void wxMacCoreGraphicsContext::Init()
 {
     m_cgContext = NULL;
     m_mode = kCGPathFill;
     m_macATSUIStyle = NULL;
-       m_releaseContext = false;
+    m_releaseContext = false;
+    HIRect r = CGRectMake(0,0,0,0);
+    m_clipRgn.Set(HIShapeCreateWithRect(&r));
 }
 
 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( CGContextRef cgcontext )
 {
        Init();
        m_cgContext = cgcontext;
-    CGContextSaveGState( m_cgContext );
-    CGContextSaveGState( m_cgContext );
+    // 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)
+    {
+        CGContextSaveGState( m_cgContext );
+        CGContextSaveGState( m_cgContext );
+    }
 }
 
 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( WindowRef window )
 {
-       Init();
-       m_windowRef = window;
-       OSStatus status = QDBeginCGContext( GetWindowPort( window ) , &m_cgContext );
-       wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") );
-       Rect bounds;
-       GetWindowBounds( window, kWindowContentRgn, &bounds );
-       CGContextSaveGState( m_cgContext );
-       CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top );
-       CGContextScaleCTM( m_cgContext , 1 , -1 );
-       CGContextSaveGState( m_cgContext );
-       m_releaseContext = true;
+    Init();
+    m_windowRef = window;
+}
+
+wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( wxWindow* window )
+{
+    Init();
+    m_windowRef = (WindowRef) window->MacGetTopLevelWindowRef();
+    m_originX = m_originY = 0;
+    window->MacWindowToRootWindow( &m_originX , &m_originY );
 }
 
 wxMacCoreGraphicsContext::wxMacCoreGraphicsContext()
 {
-       Init();
+    Init();
 }
 
 wxMacCoreGraphicsContext::~wxMacCoreGraphicsContext()
 {
     if ( m_cgContext )
     {
-        CGContextSynchronize( 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);
+        QDEndCGContext( GetWindowPort( m_windowRef ) , &m_cgContext);
 }
 
+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") );
+        Rect bounds;
+        GetWindowBounds( m_windowRef, kWindowContentRgn, &bounds );
+        CGContextSaveGState( m_cgContext );
+        CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top );
+        CGContextScaleCTM( m_cgContext , 1 , -1 );
+        CGContextTranslateCTM( m_cgContext, m_originX, m_originY );
+        CGContextSaveGState( m_cgContext );
+        m_releaseContext = true;
+        if ( !HIShapeIsEmpty(m_clipRgn) )
+        {
+            HIShapeReplacePathInCGContext( m_clipRgn, m_cgContext );
+            CGContextClip( m_cgContext );
+        }
+    }
+}
+
+
 void wxMacCoreGraphicsContext::Clip( const wxRegion &region )
 {
-       HIShapeRef shape = HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() );
-       HIShapeReplacePathInCGContext( shape, m_cgContext );
-       CGContextClip( m_cgContext );
-       CFRelease( shape );
+    if( m_cgContext )
+    {
+        HIShapeRef shape = HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() );
+        HIShapeReplacePathInCGContext( shape, m_cgContext );
+        CGContextClip( m_cgContext );
+        CFRelease( shape );
+    }
+    else
+    {
+        m_clipRgn.Set(HIShapeCreateWithQDRgn( (RgnHandle) region.GetWXHRGN() ));
+    }
 }
 
 // clips drawings to the rect
 void wxMacCoreGraphicsContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
 {
     HIRect r = CGRectMake( x , y , w , h );
-       CGContextClipToRect( m_cgContext, r );
+    if ( m_cgContext )
+    {
+        CGContextClipToRect( m_cgContext, r );
+    }
+    else
+    {
+        m_clipRgn.Set(HIShapeCreateWithRect(&r));
+    }
 }
-       
-       // resets the clipping to original extent
+    
+    // resets the clipping to original extent
 void wxMacCoreGraphicsContext::ResetClip()
 {
-    CGContextRestoreGState( m_cgContext );
-    CGContextSaveGState( m_cgContext );
+    if ( m_cgContext )
+    {
+        CGContextRestoreGState( m_cgContext );
+        CGContextSaveGState( m_cgContext );
+    }
+    else
+    {
+        HIRect r = CGRectMake(0,0,0,0);
+        m_clipRgn.Set(HIShapeCreateWithRect(&r));
+    }
 }
 
-void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *p )
+void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *path )
 {
-    const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
-    int width = m_pen.GetWidth();
-    if ( width == 0 )
-        width = 1 ;
-    if ( m_pen.GetStyle() == wxTRANSPARENT )
-        width = 0 ;
-        
-    bool offset = ( width % 2 ) == 1 ; 
+    EnsureIsValid();
+       
+    bool offset = ShouldOffset();
 
     if ( offset )
         CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
 
-    CGContextAddPath( m_cgContext , path->GetPath() );
+    CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
     CGContextStrokePath( m_cgContext );
 
     if ( offset )
         CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
 }
 
-void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *p , int fillStyle )
+void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *path , int fillStyle )
 {
-    const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
+    EnsureIsValid();
+    
     CGPathDrawingMode mode = m_mode;
 
     if ( fillStyle == wxODDEVEN_RULE )
@@ -420,30 +497,24 @@ void wxMacCoreGraphicsContext::DrawPath( const wxGraphicsPath *p , int fillStyle
         else if ( mode == kCGPathFillStroke )
             mode = kCGPathEOFillStroke;
     }
-
-    int width = m_pen.GetWidth();
-    if ( width == 0 )
-        width = 1 ;
-    if ( m_pen.GetStyle() == wxTRANSPARENT )
-        width = 0 ;
-        
-    bool offset = ( width % 2 ) == 1 ; 
+       
+    bool offset = ShouldOffset();
 
     if ( offset )
         CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
 
-    CGContextAddPath( m_cgContext , path->GetPath() );
+    CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
     CGContextDrawPath( m_cgContext , mode );
 
     if ( offset )
         CGContextTranslateCTM( m_cgContext, -0.5, -0.5 );
 }
 
-void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *p , int fillStyle )
+void wxMacCoreGraphicsContext::FillPath( const wxGraphicsPath *path , int fillStyle )
 {
-    const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
-
-    CGContextAddPath( m_cgContext , path->GetPath() );
+    EnsureIsValid();
+    
+    CGContextAddPath( m_cgContext , (CGPathRef) path->GetNativePath() );
     if ( fillStyle == wxODDEVEN_RULE )
         CGContextEOFillPath( m_cgContext );
     else
@@ -467,21 +538,29 @@ void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
 
 void wxMacCoreGraphicsContext::Translate( wxDouble dx , wxDouble dy ) 
 {
+    EnsureIsValid();
+    
     CGContextTranslateCTM( m_cgContext, dx, dy );
 }
 
 void wxMacCoreGraphicsContext::Scale( wxDouble xScale , wxDouble yScale )
 {
+    EnsureIsValid();
+    
     CGContextScaleCTM( m_cgContext , xScale , yScale );
 }
 
 void wxMacCoreGraphicsContext::Rotate( wxDouble angle )
 {
+    EnsureIsValid();
+    
     CGContextRotateCTM( m_cgContext , 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 );
     HIViewDrawCGImage( m_cgContext , &r , image );
@@ -490,6 +569,8 @@ void wxMacCoreGraphicsContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDo
 
 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 );
@@ -501,19 +582,23 @@ void wxMacCoreGraphicsContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDoubl
 
 void wxMacCoreGraphicsContext::PushState()
 {
+    EnsureIsValid();
+    
     CGContextSaveGState( m_cgContext );
 }
 
 void wxMacCoreGraphicsContext::PopState() 
 {
+    EnsureIsValid();
+    
     CGContextRestoreGState( m_cgContext );
 }
 
-void wxMacCoreGraphicsContext::SetTextColor( const wxColour &col ) 
+void wxMacCoreGraphicsContext::SetTextColour( const wxColour &col ) 
 {
     m_textForegroundColor = col;
-       // to recreate the native font after color change
-       SetFont( m_font );
+    // to recreate the native font after color change
+    SetFont( m_font );
 }
 
 #pragma mark -
@@ -979,6 +1064,8 @@ void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDoub
 
 void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ) 
 {
+    EnsureIsValid();
+    
     OSStatus status = noErr;
     ATSUTextLayout atsuLayout;
     UniCharCount chars = str.length();
@@ -1229,7 +1316,7 @@ void wxMacCoreGraphicsContext::SetFont( const wxFont &font )
 
     if ( font.Ok() )
     {
-               m_font = font ;
+        m_font = font ;
         OSStatus status;
 
         status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle );
@@ -1266,7 +1353,7 @@ void wxMacCoreGraphicsContext::SetFont( const wxFont &font )
 
 void * wxMacCoreGraphicsContext::GetNativeContext() 
 {
-       return m_cgContext;
+    return m_cgContext;
 }
 
 wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC &dc )
@@ -1276,16 +1363,7 @@ wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC &dc )
 
 wxGraphicsContext* wxGraphicsContext::Create( wxWindow * window )
 {
-       wxGraphicsContext* ctx = new wxMacCoreGraphicsContext( (WindowRef) window->MacGetTopLevelWindowRef() );
-       CGContextRef cg = (CGContextRef) ctx->GetNativeContext() ;
-       CGContextRestoreGState( cg );
-       int x , y;
-    x = y = 0;
-    window->MacWindowToRootWindow( &x , &y );
-       CGContextTranslateCTM( cg, x, y );
-       CGContextSaveGState( cg );
-       return ctx;
-
+    return new wxMacCoreGraphicsContext( window );
 }
 
 wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context )