#include "wx/graphics.h"
#ifndef WX_PRECOMP
+ #include "wx/dcclient.h"
#include "wx/log.h"
#include "wx/region.h"
#endif
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();
// 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();
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)
{
class WXDLLEXPORT wxMacCoreGraphicsContext : public wxGraphicsContext
{
- DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
-
public:
- wxMacCoreGraphicsContext( CGrafPtr port );
-
wxMacCoreGraphicsContext( CGContextRef cgcontext );
+ wxMacCoreGraphicsContext( WindowRef window );
+
+ wxMacCoreGraphicsContext( wxWindow* window );
+
wxMacCoreGraphicsContext();
~wxMacCoreGraphicsContext();
+ void Init();
// creates a path instance that corresponds to the type of graphics context, ie GDIPlus, cairo, CoreGraphics ...
virtual wxGraphicsPath * CreatePath();
// clips drawings to the region
virtual void Clip( const wxRegion ®ion );
+ // 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();
+
+ virtual void * GetNativeContext();
+
//
// transformation
//
virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
- CGContextRef GetNativeContext();
void SetNativeContext( CGContextRef cg );
CGPathDrawingMode GetDrawingMode() const { return m_mode; }
+ DECLARE_NO_COPY_CLASS(wxMacCoreGraphicsContext)
+ DECLARE_DYNAMIC_CLASS(wxMacCoreGraphicsContext)
+
private:
+ void EnsureIsValid();
+
CGContextRef m_cgContext;
- CGrafPtr m_qdPort;
+ 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;
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
//
// 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
//-----------------------------------------------------------------------------
-wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( CGrafPtr port )
+IMPLEMENT_DYNAMIC_CLASS(wxMacCoreGraphicsContext, wxGraphicsContext)
+
+void wxMacCoreGraphicsContext::Init()
{
- m_qdPort = port;
m_cgContext = NULL;
m_mode = kCGPathFill;
m_macATSUIStyle = NULL;
+ m_releaseContext = false;
+ m_clipRgn.Set(HIShapeCreateEmpty());
}
wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( CGContextRef cgcontext )
{
- m_qdPort = NULL;
- m_cgContext = cgcontext;
- m_mode = kCGPathFill;
- m_macATSUIStyle = NULL;
+ Init();
+ m_cgContext = cgcontext;
CGContextSaveGState( m_cgContext );
CGContextSaveGState( m_cgContext );
}
+wxMacCoreGraphicsContext::wxMacCoreGraphicsContext( WindowRef window )
+{
+ 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()
{
- m_qdPort = NULL;
- m_cgContext = NULL;
- m_mode = kCGPathFill;
- m_macATSUIStyle = NULL;
+ 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_qdPort )
- CGContextRelease( m_cgContext );
+ if ( m_releaseContext )
+ 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 ®ion )
{
-// ClipCGContextToRegion ( m_cgContext, &bounds , (RgnHandle) dc->m_macCurrentClipRgn );
+ 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() ));
+ }
}
-void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *p )
+// clips drawings to the rect
+void 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
+ {
+ m_clipRgn.Set(HIShapeCreateWithRect(&r));
+ }
+}
+
+ // resets the clipping to original extent
+void wxMacCoreGraphicsContext::ResetClip()
{
- const wxMacCoreGraphicsPath* path = dynamic_cast< const wxMacCoreGraphicsPath*>( p );
- CGContextAddPath( m_cgContext , path->GetPath() );
+ if ( m_cgContext )
+ {
+ CGContextRestoreGState( m_cgContext );
+ CGContextSaveGState( m_cgContext );
+ }
+ else
+ {
+ m_clipRgn.Set(HIShapeCreateEmpty());
+ }
+}
+
+void wxMacCoreGraphicsContext::StrokePath( const wxGraphicsPath *path )
+{
+ EnsureIsValid();
+
+ int width = m_pen.GetWidth();
+ if ( width == 0 )
+ width = 1 ;
+ if ( m_pen.GetStyle() == wxTRANSPARENT )
+ width = 0 ;
+
+ bool offset = ( width % 2 ) == 1 ;
+
+ if ( offset )
+ CGContextTranslateCTM( m_cgContext, 0.5, 0.5 );
+
+ 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 )
mode = kCGPathEOFillStroke;
}
- CGContextAddPath( m_cgContext , path->GetPath() );
+ int width = m_pen.GetWidth();
+ if ( width == 0 )
+ width = 1 ;
+ if ( m_pen.GetStyle() == wxTRANSPARENT )
+ width = 0 ;
+
+ bool offset = ( width % 2 ) == 1 ;
+
+ 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 *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
wxGraphicsPath* wxMacCoreGraphicsContext::CreatePath()
{
- // make sure that we now have a real cgref, before doing
- // anything with paths
- CGContextRef cg = GetNativeContext();
- cg = NULL;
-
return new wxMacCoreGraphicsPath();
}
-CGContextRef wxMacCoreGraphicsContext::GetNativeContext()
-{
- return m_cgContext;
-}
-
void wxMacCoreGraphicsContext::SetNativeContext( CGContextRef cg )
{
// we allow either setting or clearing but not replacing
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 );
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 );
void wxMacCoreGraphicsContext::PushState()
{
+ EnsureIsValid();
+
CGContextSaveGState( m_cgContext );
}
void wxMacCoreGraphicsContext::PopState()
{
+ EnsureIsValid();
+
CGContextRestoreGState( m_cgContext );
}
void wxMacCoreGraphicsContext::SetTextColor( const wxColour &col )
{
m_textForegroundColor = col;
+ // to recreate the native font after color change
+ SetFont( m_font );
}
#pragma mark -
void wxMacCoreGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle )
{
+ EnsureIsValid();
+
OSStatus status = noErr;
ATSUTextLayout atsuLayout;
UniCharCount chars = str.length();
if ( font.Ok() )
{
+ m_font = font ;
OSStatus status;
status = ATSUCreateAndCopyStyle( (ATSUStyle) font.MacGetATSUStyle() , (ATSUStyle*) &m_macATSUIStyle );
}
}
+void * wxMacCoreGraphicsContext::GetNativeContext()
+{
+ return m_cgContext;
+}
+
wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC &dc )
{
return new wxMacCoreGraphicsContext((CGContextRef)dc.GetWindow()->MacGetCGContextRef() );
}
+wxGraphicsContext* wxGraphicsContext::Create( wxWindow * window )
+{
+ return new wxMacCoreGraphicsContext( window );
+}
+
+wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context )
+{
+ return new wxMacCoreGraphicsContext((CGContextRef)context);
+}
+
+wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window )
+{
+ return new wxMacCoreGraphicsContext((WindowRef)window);
+}
+
#endif // wxMAC_USE_CORE_GRAPHICS