]> git.saurik.com Git - wxWidgets.git/blobdiff - src/mac/carbon/dccg.cpp
cleaning up, adding support for Quartz / Themeing before 10.3
[wxWidgets.git] / src / mac / carbon / dccg.cpp
index 8f6c15bea7c340c20d0c8d39753b48a958935ac2..ee8e6e608eadd04530a10c7b630c79b27f735f8f 100755 (executable)
@@ -105,6 +105,20 @@ wxMacWindowStateSaver::~wxMacWindowStateSaver()
     SetThemeDrawingState( m_themeDrawingState , true ) ;
 }
 
+// minimal implementation only used for appearance drawing < 10.3
+
+wxMacPortSetter::wxMacPortSetter( const wxDC* dc ) :
+    m_ph( (GrafPtr) dc->m_macPort )
+{
+    wxASSERT( dc->Ok() ) ;
+    m_dc = dc ;
+//    dc->MacSetupPort(&m_ph) ;
+}
+wxMacPortSetter::~wxMacPortSetter()
+{
+//    m_dc->MacCleanupPort(&m_ph) ;
+}
+
 //-----------------------------------------------------------------------------
 // Local functions
 //-----------------------------------------------------------------------------
@@ -164,6 +178,8 @@ CGPathRef wxMacCGPath::GetPath() const
     return m_path ;
 }
 
+// we always stock two context states, one at entry, the other one after 
+// changing to HI Graphics orientation (this one is used for getting back clippings etc)
 
 wxMacCGContext::wxMacCGContext( CGrafPtr port ) 
 {
@@ -175,6 +191,8 @@ wxMacCGContext::wxMacCGContext( CGContextRef cgcontext )
 {
     m_qdPort = NULL ;
     m_cgContext = cgcontext ;
+    CGContextSaveGState( m_cgContext ) ;
+    CGContextSaveGState( m_cgContext ) ;
 }
 
 wxMacCGContext::wxMacCGContext()
@@ -185,6 +203,11 @@ wxMacCGContext::wxMacCGContext()
 
 wxMacCGContext::~wxMacCGContext() 
 {
+    if ( m_cgContext )
+    {
+        CGContextRestoreGState( m_cgContext ) ;
+        CGContextRestoreGState( m_cgContext ) ;
+    }
     if ( m_qdPort )
         QDEndCGContext( m_qdPort , &m_cgContext ) ;
 }
@@ -243,9 +266,10 @@ void wxMacCGContext::FillPath( const wxGraphicPath *p , const wxColor &fillColor
     
 wxGraphicPath* wxMacCGContext::CreatePath() 
 { 
-    CGContextRef cg = GetNativeContext() ;
     // make sure that we now have a real cgref, before doing
     // anything with paths
+    CGContextRef cg = GetNativeContext() ;
+    cg = NULL ;
     return new wxMacCGPath() ; 
 }
 
@@ -258,11 +282,13 @@ CGContextRef wxMacCGContext::GetNativeContext()
         Rect bounds ;
         GetPortBounds( (CGrafPtr) m_qdPort , &bounds ) ;
         OSStatus status = QDBeginCGContext( (CGrafPtr) m_qdPort , &m_cgContext ) ;
+        CGContextSaveGState( m_cgContext ) ;
 
         wxASSERT_MSG( status == noErr , wxT("Cannot nest wxDCs on the same window") ) ;
         CGContextTranslateCTM( m_cgContext , 0 , bounds.bottom - bounds.top ) ;
         CGContextScaleCTM( m_cgContext , 1 , -1 ) ;
         
+        CGContextSaveGState( m_cgContext ) ;
         SetPen( m_pen ) ;
         SetBrush( m_brush ) ;
     }
@@ -271,7 +297,9 @@ CGContextRef wxMacCGContext::GetNativeContext()
 
 void wxMacCGContext::SetNativeContext( CGContextRef cg ) 
 { 
+    wxASSERT( m_cgContext == NULL ) ;
     m_cgContext = cg ; 
+    CGContextSaveGState( m_cgContext ) ;
 }
 
 void wxMacCGContext::SetPen( const wxPen &pen )
@@ -550,7 +578,7 @@ wxDC::wxDC()
     m_needComputeScaleY = FALSE;
 
     m_ok = FALSE ;
-
+    m_macPort = 0 ;
     m_macLocalOrigin.x = m_macLocalOrigin.y = 0 ;
 
     m_pen = *wxBLACK_PEN;
@@ -621,6 +649,11 @@ void wxDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord hei
     yy = YLOG2DEVMAC(y);
     ww = XLOG2DEVREL(width);
     hh = YLOG2DEVREL(height);
+
+    CGContextRef cgContext = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
+    CGRect clipRect = CGRectMake( xx ,yy , ww, hh ) ;
+    CGContextClipToRect( cgContext , clipRect ) ;
+
 //    SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ;
 //    SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
     if( m_clipping )
@@ -694,6 +727,11 @@ void wxDC::DoSetClippingRegionAsRegion( const wxRegion &region  )
 void wxDC::DestroyClippingRegion()
 {
 //    CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
+    CGContextRef cgContext = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
+    CGContextRestoreGState( cgContext );    
+    CGContextSaveGState( cgContext );    
+    SetPen( m_pen ) ;
+    SetBrush( m_brush ) ;
     m_clipping = FALSE;
 }
 
@@ -882,8 +920,17 @@ bool wxDC::DoFloodFill(wxCoord x, wxCoord y,
 bool  wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const
 {
     wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel  Invalid DC") );
-    wxFAIL_MSG( wxT("GetPixel not implemented on Core Graphics") ) ;
-    return false ;
+    wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel  Invalid DC") );
+    wxMacPortSaver helper((CGrafPtr)m_macPort) ;
+    RGBColor colour;
+    GetCPixel( 
+        XLOG2DEVMAC(x) + m_macLocalOriginInPort.x - m_macLocalOrigin.x, 
+        YLOG2DEVMAC(y) + m_macLocalOriginInPort.y - m_macLocalOrigin.y, &colour );
+    // Convert from Mac colour to wx
+    col->Set( colour.red   >> 8,
+        colour.green >> 8,
+        colour.blue  >> 8);
+    return true ;
 }
 
 void  wxDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
@@ -987,10 +1034,9 @@ void  wxDC::DoDrawArc( wxCoord x1, wxCoord y1,
     if( (xx1 > xx2) || (yy1 > yy2) ) {
         alpha2 *= -1;
     }
-    Rect r = { yyc - rad, xxc - rad, yyc + rad, xxc + rad };
     wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
     CGContextRef ctx = mctx->GetNativeContext() ;
-    AddEllipticArcToPath( ctx , CGPointMake( xxc , yyc ) , rad , rad , 0 , 180 ) ;
+    AddEllipticArcToPath( ctx , CGPointMake( xxc , yyc ) , rad , rad , alpha1 , alpha2 ) ;
     CGContextDrawPath( ctx , mctx->GetDrawingMode() ) ;
 }
 
@@ -1097,7 +1143,6 @@ void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
     }
     wxGraphicPath* path = m_graphicContext->CreatePath() ;
     path->AddRectangle(xx ,yy , ww , hh ) ;
-    path->CloseSubpath() ;
     m_graphicContext->DrawPath( path ) ;
     delete path ;
 }
@@ -1127,7 +1172,6 @@ void  wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
         hh = -hh;
         yy = yy - hh;
     }
-    Rect rect = { yy , xx , yy + hh , xx + ww } ;
     wxMacCGContext* mctx = ((wxMacCGContext*) m_graphicContext) ;
     CGContextRef ctx = mctx->GetNativeContext() ;
     AddRoundedRectToPath( ctx  , CGRectMake( xx , yy , ww , hh ) , 16 ,16  ) ;
@@ -1198,7 +1242,7 @@ bool  wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
     }
 
     wxMemoryDC* memdc = dynamic_cast<wxMemoryDC*>(source) ;
-    if ( memdc )
+    if ( memdc && logical_func == wxCOPY )
     {
         wxBitmap blit = memdc->GetSelectedObject() ;
         wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") ) ;
@@ -1226,7 +1270,7 @@ bool  wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
     }
     else
     {
-        wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
+        return FALSE ; // wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") ) ;
     }
     return TRUE;
 }
@@ -1333,14 +1377,14 @@ void  wxDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
             drawX , 
             drawY ) ;
         path->AddLineToPoint( 
-            drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent) , 
-            drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent) ) ;
+            (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent)) , 
+            (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent)) ) ;
         path->AddLineToPoint( 
-            drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle/RAD2DEG) * FixedToInt(textAfter) ,
-            drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent) - sin(angle/RAD2DEG) * FixedToInt(textAfter) ) ;
+            (int) (drawX + sin(angle/RAD2DEG) * FixedToInt(ascent + descent ) + cos(angle/RAD2DEG) * FixedToInt(textAfter)) ,
+            (int) (drawY + cos(angle/RAD2DEG) * FixedToInt(ascent + descent) - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
         path->AddLineToPoint( 
-            drawX + cos(angle/RAD2DEG) * FixedToInt(textAfter) , 
-            drawY - sin(angle/RAD2DEG) * FixedToInt(textAfter) ) ;
+            (int) (drawX + cos(angle/RAD2DEG) * FixedToInt(textAfter)) , 
+            (int) (drawY - sin(angle/RAD2DEG) * FixedToInt(textAfter)) ) ;
             
         m_graphicContext->FillPath( path , m_textBackgroundColour ) ;
         delete path ;
@@ -1473,9 +1517,54 @@ bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) con
     if (text.Length() == 0)
         return false;
     
-    wxFAIL_MSG( wxT("Unimplemented for Core Graphics") ) ;
-    
-    return false;
+    ATSUTextLayout atsuLayout ;
+    UniCharCount chars = text.Length() ;
+    UniChar* ubuf = NULL ;
+#if SIZEOF_WCHAR_T == 4
+    wxMBConvUTF16BE converter ;
+#if wxUSE_UNICODE
+    size_t unicharlen = converter.WC2MB( NULL , text.wc_str() , 0 ) ;
+    ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
+    converter.WC2MB( (char*) ubuf , text.wc_str(), unicharlen + 2 ) ;
+#else
+    const wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
+    size_t unicharlen = converter.WC2MB( NULL , wchar.data()  , 0 ) ;
+    ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
+    converter.WC2MB( (char*) ubuf , wchar.data() , unicharlen + 2 ) ;
+#endif
+    chars = unicharlen / 2 ;
+#else
+#if wxUSE_UNICODE
+    ubuf = (UniChar*) text.wc_str() ;
+#else
+    wxWCharBuffer wchar = text.wc_str( wxConvLocal ) ;
+    chars = wxWcslen( wchar.data() ) ;
+    ubuf = (UniChar*) wchar.data() ;
+#endif
+#endif
+
+       OSStatus status;
+    status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) ubuf , 0 , chars , chars , 1 ,
+        &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ;
+        
+       for ( int pos = 0; pos < chars; pos ++ ) {
+                       unsigned long actualNumberOfBounds = 0;
+                       ATSTrapezoid glyphBounds;
+
+                       // We get a single bound, since the text should only require one. If it requires more, there is an issue
+                       OSStatus result; 
+                       result = ATSUGetGlyphBounds( atsuLayout, 0, 0, kATSUFromTextBeginning, pos + 1, kATSUseDeviceOrigins, 1, &glyphBounds, &actualNumberOfBounds );
+                       if (result != noErr || actualNumberOfBounds != 1 )
+                       {
+                               return false;
+                       }
+
+                       widths[pos] = XDEV2LOGREL(FixedToInt( glyphBounds.upperRight.x - glyphBounds.upperLeft.x ));
+                       //unsigned char uch = s[i];
+                       
+       }
+    ::ATSUDisposeTextLayout(atsuLayout);
+    return true;
 }
 
 wxCoord   wxDC::GetCharWidth(void) const
@@ -1498,33 +1587,64 @@ void  wxDC::Clear(void)
 
     if ( m_backgroundBrush.Ok() && m_backgroundBrush.GetStyle() != wxTRANSPARENT)
     {      
-                HIRect rect = CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
+        HIRect rect = CGRectMake( -10000 , -10000 , 20000 , 20000 ) ;
+        CGContextRef cg = dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ;
         switch( m_backgroundBrush.MacGetBrushKind() )
         {
             case kwxMacBrushTheme :
                 {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
+                    if ( HIThemeSetFill != 0 )
+                    {
+                        HIThemeSetFill( m_backgroundBrush.MacGetTheme() , cg ) ;
+                        CGContextFillRect(cg, rect);
+
+                    }
+                    else
+#endif
+                    {
+                                       RGBColor        color;
+                                       GetThemeBrushAsColor( m_backgroundBrush.MacGetTheme() , 32, true, &color );
+                                       CGContextSetRGBFillColor( cg , (float) color.red / 65536,
+                                                       (float) color.green / 65536, (float) color.blue / 65536, 1 );
+                                       CGContextFillRect( cg, rect );
+                    }
+                    // reset to normal value
+                    RGBColor col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
+                    CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
                 }
             break ;
             case kwxMacBrushThemeBackground :
                 {
-                    HIThemeBackgroundDrawInfo drawInfo ;
-                    drawInfo.version = 0 ;
-                    drawInfo.state = kThemeStateActive ;
-                    drawInfo.kind = m_backgroundBrush.MacGetThemeBackground(NULL) ;
-                    HIThemeDrawBackground( &rect , &drawInfo, dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() ,
-                        kHIThemeOrientationNormal) ;
-
+                    wxFAIL_MSG( wxT("There shouldn't be theme backgrounds under Quartz") ) ;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
+                    if ( HIThemeDrawBackground != 0 )
+                    {
+                        HIThemeBackgroundDrawInfo drawInfo ;
+                        drawInfo.version = 0 ;
+                        drawInfo.state = kThemeStateActive ;
+                        drawInfo.kind = m_backgroundBrush.MacGetThemeBackground(NULL) ;
+                        if ( drawInfo.kind == kThemeBackgroundMetal )
+                            HIThemeDrawBackground( &rect , &drawInfo, cg ,
+                                kHIThemeOrientationNormal) ;
+                            HIThemeApplyBackground( &rect , &drawInfo, cg ,
+                                kHIThemeOrientationNormal) ;
+                    }
+                    else
+#endif
+                    {
+                    }
                 }
             break ;
             case kwxMacBrushColour :
             {
                 RGBColor col = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) ;
-                CGContextSetRGBFillColor( dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
-                CGContextFillRect(dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext(), rect);
+                CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
+                CGContextFillRect(cg, rect);
 
                 // reset to normal value
                 col = MAC_WXCOLORREF( GetBrush().GetColour().GetPixel() ) ;
-                CGContextSetRGBFillColor( dynamic_cast<wxMacCGContext*>(m_graphicContext)->GetNativeContext() , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
+                CGContextSetRGBFillColor( cg , col.red / 65536.0 , col.green / 65536.0 , col.blue / 65536.0 , 1.0 ) ;
             }
             break ;
         }