]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/graphics.cpp
Swap client data pointers in wxRearrangeList too.
[wxWidgets.git] / src / msw / graphics.cpp
index 62d56a1023fa78f40ea0d7ad46f7387e08f7fdf2..d0c3c643ba4645c564838fd01b4b466423daadfb 100644 (file)
 #include "wx/private/graphics.h"
 #include "wx/msw/wrapgdip.h"
 #include "wx/msw/dc.h"
+#include "wx/msw/enhmeta.h"
 #include "wx/dcgraph.h"
 
+#include "wx/msw/private.h" // needs to be before #include <commdlg.h>
+
+#if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
+#include <commdlg.h>
+#endif
+
 #include "wx/stack.h"
 
 WX_DECLARE_STACK(GraphicsState, GraphicsStates);
 
+namespace
+{
+
 //-----------------------------------------------------------------------------
 // constants
 //-----------------------------------------------------------------------------
@@ -56,11 +66,19 @@ const double RAD2DEG = 180.0 / M_PI;
 // Local functions
 //-----------------------------------------------------------------------------
 
-static inline double dmin(double a, double b) { return a < b ? a : b; }
-static inline double dmax(double a, double b) { return a > b ? a : b; }
+inline double dmin(double a, double b) { return a < b ? a : b; }
+inline double dmax(double a, double b) { return a > b ? a : b; }
+
+inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
+inline double RadToDeg(double deg) { return (deg * 180.0) / M_PI; }
+
+// translate a wxColour to a Color
+inline Color wxColourToColor(const wxColour& col)
+{
+    return Color(col.Alpha(), col.Red(), col.Green(), col.Blue());
+}
 
-static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
-static inline double RadToDeg(double deg) { return (deg * 180.0) / M_PI; }
+} // anonymous namespace
 
 //-----------------------------------------------------------------------------
 // device context implementation
@@ -78,12 +96,6 @@ static inline double RadToDeg(double deg) { return (deg * 180.0) / M_PI; }
 // wxGraphicsPath implementation
 //-----------------------------------------------------------------------------
 
-#include "wx/msw/private.h" // needs to be before #include <commdlg.h>
-
-#if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
-#include <commdlg.h>
-#endif
-
 class wxGDIPlusPathData : public wxGraphicsPathData
 {
 public :
@@ -235,16 +247,24 @@ public:
     wxGDIPlusBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
     ~wxGDIPlusBrushData ();
 
-    void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
-        const wxColour&c1, const wxColour&c2 );
-    void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
-        const wxColour &oColor, const wxColour &cColor );
+    void CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+                                   wxDouble x2, wxDouble y2,
+                                   const wxGraphicsGradientStops& stops);
+    void CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+                                   wxDouble xc, wxDouble yc,
+                                   wxDouble radius,
+                                   const wxGraphicsGradientStops& stops);
+
     virtual Brush* GetGDIPlusBrush() { return m_brush; }
 
 protected:
     virtual void Init();
 
-private :
+private:
+    // common part of Create{Linear,Radial}GradientBrush()
+    template <typename T>
+    void SetGradientStops(T *brush, const wxGraphicsGradientStops& stops);
+
     Brush* m_brush;
     Image* m_brushImage;
     GraphicsPath* m_brushPath;
@@ -404,8 +424,7 @@ wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &p
     if (m_width <= 0.0)
         m_width = 0.1;
 
-    m_pen = new Pen(Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
-        pen.GetColour().Green() , pen.GetColour().Blue() ), m_width );
+    m_pen = new Pen(wxColourToColor(pen.GetColour()), m_width );
 
     LineCap cap;
     switch ( pen.GetCap() )
@@ -528,8 +547,12 @@ wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &p
                 break ;
 
             }
-            m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
-                pen.GetColour().Green() , pen.GetColour().Blue() ), Color::Transparent );
+            m_penBrush = new HatchBrush
+                             (
+                                style,
+                                wxColourToColor(pen.GetColour()),
+                                Color::Transparent
+                             );
             m_pen->SetBrush( m_penBrush );
         }
         break;
@@ -554,8 +577,7 @@ wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxB
     Init();
     if ( brush.GetStyle() == wxSOLID)
     {
-        m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
-            brush.GetColour().Green() , brush.GetColour().Blue() ) );
+        m_brush = new SolidBrush(wxColourToColor( brush.GetColour()));
     }
     else if ( brush.IsHatch() )
     {
@@ -582,8 +604,12 @@ wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxB
             break ;
 
         }
-        m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
-            brush.GetColour().Green() , brush.GetColour().Blue() ), Color::Transparent );
+        m_brush = new HatchBrush
+                      (
+                        style,
+                        wxColourToColor(brush.GetColour()),
+                        Color::Transparent
+                      );
     }
     else
     {
@@ -611,28 +637,67 @@ void wxGDIPlusBrushData::Init()
     m_brushPath= NULL;
 }
 
-void wxGDIPlusBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2)
+template <typename T>
+void
+wxGDIPlusBrushData::SetGradientStops(T *brush,
+        const wxGraphicsGradientStops& stops)
 {
-    m_brush = new LinearGradientBrush( PointF( x1,y1) , PointF( x2,y2),
-        Color( c1.Alpha(), c1.Red(),c1.Green() , c1.Blue() ),
-        Color( c2.Alpha(), c2.Red(),c2.Green() , c2.Blue() ));
+    const unsigned numStops = stops.GetCount();
+    if ( numStops <= 2 )
+    {
+        // initial and final colours are set during the brush creation, nothing
+        // more to do
+        return;
+    }
+
+    wxVector<Color> colors(numStops);
+    wxVector<REAL> positions(numStops);
+
+    for ( unsigned i = 0; i < numStops; i++ )
+    {
+        wxGraphicsGradientStop stop = stops.Item(i);
+
+        colors[i] = wxColourToColor(stop.GetColour());
+        positions[i] = stop.GetPosition();
+    }
+
+    brush->SetInterpolationColors(&colors[0], &positions[0], numStops);
+}
+
+void
+wxGDIPlusBrushData::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+                                              wxDouble x2, wxDouble y2,
+                                              const wxGraphicsGradientStops& stops)
+{
+    LinearGradientBrush * const
+        brush = new LinearGradientBrush(PointF(x1, y1) , PointF(x2, y2),
+                                        wxColourToColor(stops.GetStartColour()),
+                                        wxColourToColor(stops.GetEndColour()));
+    m_brush =  brush;
+
+    SetGradientStops(brush, stops);
 }
 
-void wxGDIPlusBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
-                                               const wxColour &oColor, const wxColour &cColor)
+void
+wxGDIPlusBrushData::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+                                              wxDouble xc, wxDouble yc,
+                                              wxDouble radius,
+                                              const wxGraphicsGradientStops& stops)
 {
-    // Create a path that consists of a single circle.
     m_brushPath = new GraphicsPath();
-    m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius), (REAL)(2*radius), (REAL)(2*radius));
+    m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius),
+                             (REAL)(2*radius), (REAL)(2*radius));
 
-    PathGradientBrush *b = new PathGradientBrush(m_brushPath);
-    m_brush = b;
-    b->SetCenterPoint( PointF(xo,yo));
-    b->SetCenterColor(Color( oColor.Alpha(), oColor.Red(),oColor.Green() , oColor.Blue() ));
+    PathGradientBrush * const brush = new PathGradientBrush(m_brushPath);
+    m_brush = brush;
+    brush->SetCenterPoint(PointF(xo, yo));
+    brush->SetCenterColor(wxColourToColor(stops.GetStartColour()));
 
-    Color colors[] = {Color( cColor.Alpha(), cColor.Red(),cColor.Green() , cColor.Blue() )};
+    const Color col(wxColourToColor(stops.GetEndColour()));
     int count = 1;
-    b->SetSurroundColors(colors, &count);
+    brush->SetSurroundColors(&col, &count);
+
+    SetGradientStops(brush, stops);
 }
 
 //-----------------------------------------------------------------------------
@@ -655,8 +720,7 @@ wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont
     if ( font.GetWeight() == wxFONTWEIGHT_BOLD )
         style |= FontStyleBold;
     m_font = new Font( s , size , style );
-    m_textBrush = new SolidBrush( Color( col.Alpha() , col.Red() ,
-        col.Green() , col.Blue() ));
+    m_textBrush = new SolidBrush(wxColourToColor(col));
 }
 
 wxGDIPlusFontData::~wxGDIPlusFontData()
@@ -980,7 +1044,7 @@ void wxGDIPlusMatrixData::Scale( wxDouble xScale , wxDouble yScale )
 // add the rotation to this matrix (radians)
 void wxGDIPlusMatrixData::Rotate( wxDouble angle )
 {
-    m_matrix->Rotate( angle );
+    m_matrix->Rotate( RadToDeg(angle) );
 }
 
 //
@@ -1088,6 +1152,14 @@ void wxGDIPlusContext::SetDefaults()
     m_context->SetSmoothingMode(SmoothingModeHighQuality);
     m_state1 = m_context->Save();
     m_state2 = m_context->Save();
+
+    // Setup page scale, based on DPI ratio.
+    // Antecedent should be 100dpi when the default page unit (UnitDisplay)
+    // is used. Page unit UnitDocument would require 300dpi instead.
+    // Note that calling SetPageScale() does not have effect on non-printing
+    // DCs (that is, any other than wxPrinterDC or wxEnhMetaFileDC).
+    REAL dpiRatio = 100.0 / m_context->GetDpiY();
+    m_context->SetPageScale(dpiRatio);
 }
 
 wxGDIPlusContext::~wxGDIPlusContext()
@@ -1433,6 +1505,8 @@ void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDo
         m_context->MeasureString((const wchar_t *) s , wcslen(s) , f, layoutRect, &strFormat, &bounds ) ;
         if ( width )
             *width = bounds.Width;
+        if ( height )
+            *height = bounds.Height;
     }
 }
 
@@ -1558,6 +1632,8 @@ public :
 
     virtual wxGraphicsContext * CreateContext( const wxPrinterDC& dc);
 
+    virtual wxGraphicsContext * CreateContext( const wxEnhMetaFileDC& dc);
+
     virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
 
     virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
@@ -1580,15 +1656,16 @@ public :
 
     virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
 
-    // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
-    virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
-        const wxColour&c1, const wxColour&c2) ;
-
-    // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
-    // with radius r and color cColor
-    virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
-        const wxColour &oColor, const wxColour &cColor) ;
+    virtual wxGraphicsBrush
+    CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+                              wxDouble x2, wxDouble y2,
+                              const wxGraphicsGradientStops& stops);
 
+    virtual wxGraphicsBrush
+    CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+                              wxDouble xc, wxDouble yc,
+                              wxDouble radius,
+                              const wxGraphicsGradientStops& stops);
     // sets the font
     virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
 
@@ -1597,7 +1674,7 @@ public :
 
     // create a graphics bitmap from a native bitmap
     virtual wxGraphicsBitmap CreateBitmapFromNativeBitmap( void* bitmap );
-    
+
     // create a subimage from a native image representation
     virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h  );
 
@@ -1689,6 +1766,14 @@ wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxPrinterDC& dc)
     return new wxGDIPlusContext(this,(HDC) msw->GetHDC(), sz.x, sz.y);
 }
 
+wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxEnhMetaFileDC& dc)
+{
+    ENSURE_LOADED_OR_RETURN(NULL);
+    wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
+    wxSize sz = dc.GetSize();
+    return new wxGDIPlusContext(this,(HDC) msw->GetHDC(), sz.x, sz.y);
+}
+
 wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxMemoryDC& dc)
 {
     ENSURE_LOADED_OR_RETURN(NULL);
@@ -1773,27 +1858,29 @@ wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
     }
 }
 
-// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
-wxGraphicsBrush wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
-                                                                      const wxColour&c1, const wxColour&c2)
+wxGraphicsBrush
+wxGDIPlusRenderer::CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
+                                             wxDouble x2, wxDouble y2,
+                                             const wxGraphicsGradientStops& stops)
 {
     ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
     wxGraphicsBrush p;
     wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
-    d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
+    d->CreateLinearGradientBrush(x1, y1, x2, y2, stops);
     p.SetRefData(d);
     return p;
  }
 
-// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
-// with radius r and color cColor
-wxGraphicsBrush wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
-                                                                      const wxColour &oColor, const wxColour &cColor)
+wxGraphicsBrush
+wxGDIPlusRenderer::CreateRadialGradientBrush(wxDouble xo, wxDouble yo,
+                                             wxDouble xc, wxDouble yc,
+                                             wxDouble radius,
+                                             const wxGraphicsGradientStops& stops)
 {
     ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
     wxGraphicsBrush p;
     wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
-    d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
+    d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,stops);
     p.SetRefData(d);
     return p;
 }