]> git.saurik.com Git - wxWidgets.git/blame - src/msw/graphics.cpp
wxTLW: don't assert when setting null icons initially (#10138)
[wxWidgets.git] / src / msw / graphics.cpp
CommitLineData
6fea499c 1/////////////////////////////////////////////////////////////////////////////
e0876d73 2// Name: src/msw/graphics.cpp
6fea499c
SC
3// Purpose: wxGCDC class
4// Author: Stefan Csomor
5// Modified by:
e0876d73 6// Created: 2006-09-30
6fea499c 7// RCS-ID: $Id$
e0876d73 8// Copyright: (c) 2006 Stefan Csomor
6fea499c
SC
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#include "wx/dc.h"
15
6fea499c
SC
16#ifdef __BORLANDC__
17#pragma hdrstop
18#endif
19
0024ec50
VZ
20#if wxUSE_GRAPHICS_CONTEXT
21
6fea499c 22#ifndef WX_PRECOMP
bdba6fdc
VZ
23 #include "wx/msw/wrapcdlg.h"
24 #include "wx/image.h"
25 #include "wx/window.h"
bdba6fdc
VZ
26 #include "wx/utils.h"
27 #include "wx/dialog.h"
28 #include "wx/app.h"
29 #include "wx/bitmap.h"
bdba6fdc
VZ
30 #include "wx/log.h"
31 #include "wx/icon.h"
bdba6fdc 32 #include "wx/module.h"
f772729b
SC
33 // include all dc types that are used as a param
34 #include "wx/dc.h"
35 #include "wx/dcclient.h"
36 #include "wx/dcmemory.h"
37 #include "wx/dcprint.h"
6fea499c
SC
38#endif
39
623cf1fa 40#include "wx/private/graphics.h"
bdba6fdc 41#include "wx/msw/wrapgdip.h"
bce28872 42#include "wx/msw/dc.h"
6fea499c 43
bdba6fdc 44#include "wx/stack.h"
6fea499c 45
bdba6fdc 46WX_DECLARE_STACK(GraphicsState, GraphicsStates);
0024ec50 47
6fea499c
SC
48//-----------------------------------------------------------------------------
49// constants
50//-----------------------------------------------------------------------------
51
52const double RAD2DEG = 180.0 / M_PI;
53
54//-----------------------------------------------------------------------------
55// Local functions
56//-----------------------------------------------------------------------------
57
58static inline double dmin(double a, double b) { return a < b ? a : b; }
59static inline double dmax(double a, double b) { return a > b ? a : b; }
60
61static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
62static inline double RadToDeg(double deg) { return (deg * 180.0) / M_PI; }
63
64//-----------------------------------------------------------------------------
65// device context implementation
66//
67// more and more of the dc functionality should be implemented by calling
68// the appropricate wxGDIPlusContext, but we will have to do that step by step
69// also coordinate conversions should be moved to native matrix ops
70//-----------------------------------------------------------------------------
71
72// we always stock two context states, one at entry, to be able to preserve the
73// state we were called with, the other one after changing to HI Graphics orientation
74// (this one is used for getting back clippings etc)
75
76//-----------------------------------------------------------------------------
77// wxGraphicsPath implementation
78//-----------------------------------------------------------------------------
79
80#include "wx/msw/private.h" // needs to be before #include <commdlg.h>
81
82#if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
83#include <commdlg.h>
84#endif
85
eb4083ef 86class wxGDIPlusPathData : public wxGraphicsPathData
6fea499c 87{
6fea499c 88public :
a4e73390
SC
89 wxGDIPlusPathData(wxGraphicsRenderer* renderer, GraphicsPath* path = NULL);
90 ~wxGDIPlusPathData();
6fea499c 91
a4e73390 92 virtual wxGraphicsObjectRefData *Clone() const;
6fea499c
SC
93
94 //
95 // These are the path primitives from which everything else can be constructed
96 //
97
98 // begins a new subpath at (x,y)
99 virtual void MoveToPoint( wxDouble x, wxDouble y );
100
cb3a0d42 101 // adds a straight line from the current point to (x,y)
6fea499c
SC
102 virtual void AddLineToPoint( wxDouble x, wxDouble y );
103
104 // adds a cubic Bezier curve from the current point, using two control points and an end point
105 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
106
107
cb3a0d42 108 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
6fea499c
SC
109 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ;
110
111 // gets the last point of the current path, (0,0) if not yet set
a4e73390 112 virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const;
6fea499c 113
83576e68 114 // adds another path
a4e73390 115 virtual void AddPath( const wxGraphicsPathData* path );
83576e68 116
6fea499c
SC
117 // closes the current sub-path
118 virtual void CloseSubpath();
119
120 //
cb3a0d42 121 // These are convenience functions which - if not available natively will be assembled
6fea499c
SC
122 // using the primitives from above
123 //
124
cb3a0d42 125 // appends a rectangle as a new closed subpath
6fea499c
SC
126 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
127 /*
128
129 // appends an ellipsis as a new closed subpath fitting the passed rectangle
130 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
131
132 // 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)
133 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
134*/
135
cb3a0d42
VZ
136 // returns the native path
137 virtual void * GetNativePath() const { return m_path; }
138
139 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
140 virtual void UnGetNativePath(void * WXUNUSED(path)) const {}
f540e5bd 141
83576e68 142 // transforms each point of this path by the matrix
a4e73390 143 virtual void Transform( const wxGraphicsMatrixData* matrix ) ;
83576e68
SC
144
145 // gets the bounding box enclosing all points (possibly including control points)
a4e73390 146 virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const;
83576e68 147
a4e73390 148 virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxODDEVEN_RULE) const;
83576e68 149
6fea499c
SC
150private :
151 GraphicsPath* m_path;
152};
153
eb4083ef 154class wxGDIPlusMatrixData : public wxGraphicsMatrixData
83576e68
SC
155{
156public :
a4e73390
SC
157 wxGDIPlusMatrixData(wxGraphicsRenderer* renderer, Matrix* matrix = NULL) ;
158 virtual ~wxGDIPlusMatrixData() ;
83576e68 159
a4e73390 160 virtual wxGraphicsObjectRefData* Clone() const ;
83576e68
SC
161
162 // concatenates the matrix
a4e73390 163 virtual void Concat( const wxGraphicsMatrixData *t );
83576e68
SC
164
165 // sets the matrix to the respective values
cb3a0d42 166 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
83576e68
SC
167 wxDouble tx=0.0, wxDouble ty=0.0);
168
248802d0
RD
169 // gets the component valuess of the matrix
170 virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL, wxDouble* c=NULL,
171 wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const;
f4322df6 172
83576e68
SC
173 // makes this the inverse matrix
174 virtual void Invert();
175
176 // returns true if the elements of the transformation matrix are equal ?
a4e73390 177 virtual bool IsEqual( const wxGraphicsMatrixData* t) const ;
83576e68
SC
178
179 // return true if this is the identity matrix
a4e73390 180 virtual bool IsIdentity() const;
83576e68
SC
181
182 //
183 // transformation
184 //
185
186 // add the translation to this matrix
187 virtual void Translate( wxDouble dx , wxDouble dy );
188
189 // add the scale to this matrix
190 virtual void Scale( wxDouble xScale , wxDouble yScale );
191
192 // add the rotation to this matrix (radians)
cb3a0d42 193 virtual void Rotate( wxDouble angle );
83576e68
SC
194
195 //
196 // apply the transforms
197 //
198
199 // applies that matrix to the point
a4e73390 200 virtual void TransformPoint( wxDouble *x, wxDouble *y ) const;
83576e68
SC
201
202 // applies the matrix except for translations
a4e73390 203 virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const;
83576e68
SC
204
205 // returns the native representation
206 virtual void * GetNativeMatrix() const;
207private:
208 Matrix* m_matrix ;
83576e68
SC
209} ;
210
eb4083ef 211class wxGDIPlusPenData : public wxGraphicsObjectRefData
83576e68
SC
212{
213public:
2c820406
SC
214 wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
215 ~wxGDIPlusPenData();
83576e68
SC
216
217 void Init();
218
83576e68
SC
219 virtual wxDouble GetWidth() { return m_width; }
220 virtual Pen* GetGDIPlusPen() { return m_pen; }
221
222protected :
223 Pen* m_pen;
224 Image* m_penImage;
225 Brush* m_penBrush;
226
227 wxDouble m_width;
83576e68
SC
228};
229
eb4083ef 230class wxGDIPlusBrushData : public wxGraphicsObjectRefData
83576e68
SC
231{
232public:
2c820406
SC
233 wxGDIPlusBrushData( wxGraphicsRenderer* renderer );
234 wxGDIPlusBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
235 ~wxGDIPlusBrushData ();
83576e68 236
cb3a0d42 237 void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
83576e68
SC
238 const wxColour&c1, const wxColour&c2 );
239 void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
240 const wxColour &oColor, const wxColour &cColor );
241 virtual Brush* GetGDIPlusBrush() { return m_brush; }
242
243protected:
244 virtual void Init();
245
246private :
247 Brush* m_brush;
248 Image* m_brushImage;
249 GraphicsPath* m_brushPath;
83576e68
SC
250};
251
bce28872
SC
252class WXDLLIMPEXP_CORE wxGDIPlusBitmapData : public wxGraphicsObjectRefData
253{
254public:
255 wxGDIPlusBitmapData( wxGraphicsRenderer* renderer, Bitmap* bitmap );
256 wxGDIPlusBitmapData( wxGraphicsRenderer* renderer, const wxBitmap &bmp );
257 ~wxGDIPlusBitmapData ();
258
259 virtual Bitmap* GetGDIPlusBitmap() { return m_bitmap; }
260
261private :
262 Bitmap* m_bitmap;
263 Bitmap* m_helper;
264};
265
eb4083ef 266class wxGDIPlusFontData : public wxGraphicsObjectRefData
83576e68
SC
267{
268public:
2c820406
SC
269 wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
270 ~wxGDIPlusFontData();
83576e68 271
83576e68
SC
272 virtual Brush* GetGDIPlusBrush() { return m_textBrush; }
273 virtual Font* GetGDIPlusFont() { return m_font; }
274private :
275 Brush* m_textBrush;
276 Font* m_font;
83576e68
SC
277};
278
eb4083ef 279class wxGDIPlusContext : public wxGraphicsContext
6fea499c 280{
6fea499c 281public:
81e0b3d9 282 wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc , wxDouble width, wxDouble height );
83576e68
SC
283 wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd );
284 wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr);
6fea499c 285 wxGDIPlusContext();
9f339b18 286
6fea499c
SC
287 virtual ~wxGDIPlusContext();
288
289 virtual void Clip( const wxRegion &region );
539e2795
SC
290 // clips drawings to the rect
291 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
539e2795 292
cb3a0d42
VZ
293 // resets the clipping to original extent
294 virtual void ResetClip();
295
296 virtual void * GetNativeContext();
297
a4e73390
SC
298 virtual void StrokePath( const wxGraphicsPath& p );
299 virtual void FillPath( const wxGraphicsPath& p , int fillStyle = wxODDEVEN_RULE );
6fea499c 300
0c7bd159
SC
301 // stroke lines connecting each of the points
302 virtual void StrokeLines( size_t n, const wxPoint2DDouble *points);
303
304 // draws a polygon
305 virtual void DrawLines( size_t n, const wxPoint2DDouble *points, int fillStyle = wxODDEVEN_RULE );
306
cb3a0d42
VZ
307 virtual void Translate( wxDouble dx , wxDouble dy );
308 virtual void Scale( wxDouble xScale , wxDouble yScale );
309 virtual void Rotate( wxDouble angle );
6fea499c 310
83576e68 311 // concatenates this transform with the current transform of this context
a4e73390 312 virtual void ConcatTransform( const wxGraphicsMatrix& matrix );
83576e68
SC
313
314 // sets the transform of this context
a4e73390 315 virtual void SetTransform( const wxGraphicsMatrix& matrix );
83576e68
SC
316
317 // gets the matrix of this context
a4e73390 318 virtual wxGraphicsMatrix GetTransform() const;
83576e68 319
bce28872 320 virtual void DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
6fea499c
SC
321 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
322 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
cb3a0d42 323 virtual void PushState();
6fea499c
SC
324 virtual void PopState();
325
6fea499c
SC
326 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y);
327 virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
328 wxDouble *descent, wxDouble *externalLeading ) const;
329 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
d9485f89 330 virtual bool ShouldOffset() const;
fbd5416f 331 virtual void GetSize( wxDouble* width, wxDouble *height );
6fea499c
SC
332
333private:
9f339b18
SC
334 void Init();
335 void SetDefaults();
336
83576e68 337 Graphics* m_context;
bdba6fdc 338 GraphicsStates m_stateStack;
83576e68
SC
339 GraphicsState m_state1;
340 GraphicsState m_state2;
341
81e0b3d9
SC
342 wxDouble m_width;
343 wxDouble m_height;
344
83576e68
SC
345 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext)
346};
347
0c7bd159
SC
348class WXDLLIMPEXP_CORE wxGDIPlusMeasuringContext : public wxGDIPlusContext
349{
350public:
81e0b3d9 351 wxGDIPlusMeasuringContext( wxGraphicsRenderer* renderer ) : wxGDIPlusContext( renderer , m_hdc = GetDC(NULL), 1000, 1000 )
0c7bd159
SC
352 {
353 }
354 wxGDIPlusMeasuringContext()
355 {
356 }
357
358 virtual ~wxGDIPlusMeasuringContext()
359 {
360 ReleaseDC( NULL, m_hdc );
361 }
362
363private:
364 HDC m_hdc ;
365 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusMeasuringContext)
366} ;
367
83576e68
SC
368//-----------------------------------------------------------------------------
369// wxGDIPlusPen implementation
370//-----------------------------------------------------------------------------
371
2c820406 372wxGDIPlusPenData::~wxGDIPlusPenData()
83576e68
SC
373{
374 delete m_pen;
375 delete m_penImage;
376 delete m_penBrush;
377}
378
2c820406 379void wxGDIPlusPenData::Init()
83576e68
SC
380{
381 m_pen = NULL ;
382 m_penImage = NULL;
383 m_penBrush = NULL;
384}
385
2c820406
SC
386wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
387: wxGraphicsObjectRefData(renderer)
cb3a0d42 388{
83576e68
SC
389 Init();
390 m_width = pen.GetWidth();
391 if (m_width <= 0.0)
392 m_width = 0.1;
393
394 m_pen = new Pen(Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
395 pen.GetColour().Green() , pen.GetColour().Blue() ), m_width );
396
397 LineCap cap;
398 switch ( pen.GetCap() )
399 {
400 case wxCAP_ROUND :
401 cap = LineCapRound;
402 break;
403
404 case wxCAP_PROJECTING :
405 cap = LineCapSquare;
406 break;
407
408 case wxCAP_BUTT :
409 cap = LineCapFlat; // TODO verify
410 break;
411
412 default :
413 cap = LineCapFlat;
414 break;
415 }
416 m_pen->SetLineCap(cap,cap, DashCapFlat);
417
418 LineJoin join;
419 switch ( pen.GetJoin() )
420 {
421 case wxJOIN_BEVEL :
422 join = LineJoinBevel;
423 break;
424
425 case wxJOIN_MITER :
426 join = LineJoinMiter;
427 break;
428
429 case wxJOIN_ROUND :
430 join = LineJoinRound;
431 break;
432
433 default :
434 join = LineJoinMiter;
435 break;
436 }
437
438 m_pen->SetLineJoin(join);
439
440 m_pen->SetDashStyle(DashStyleSolid);
441
442 DashStyle dashStyle = DashStyleSolid;
443 switch ( pen.GetStyle() )
444 {
445 case wxSOLID :
446 break;
447
448 case wxDOT :
449 dashStyle = DashStyleDot;
450 break;
451
452 case wxLONG_DASH :
453 dashStyle = DashStyleDash; // TODO verify
454 break;
455
456 case wxSHORT_DASH :
457 dashStyle = DashStyleDash;
458 break;
459
460 case wxDOT_DASH :
461 dashStyle = DashStyleDashDot;
462 break;
463 case wxUSER_DASH :
464 {
465 dashStyle = DashStyleCustom;
466 wxDash *dashes;
467 int count = pen.GetDashes( &dashes );
468 if ((dashes != NULL) && (count > 0))
469 {
470 REAL *userLengths = new REAL[count];
471 for ( int i = 0; i < count; ++i )
472 {
473 userLengths[i] = dashes[i];
474 }
475 m_pen->SetDashPattern( userLengths, count);
476 delete[] userLengths;
477 }
478 }
479 break;
480 case wxSTIPPLE :
481 {
482 wxBitmap* bmp = pen.GetStipple();
483 if ( bmp && bmp->Ok() )
484 {
485 m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
486 m_penBrush = new TextureBrush(m_penImage);
487 m_pen->SetBrush( m_penBrush );
488 }
489
490 }
491 break;
492 default :
493 if ( pen.GetStyle() >= wxFIRST_HATCH && pen.GetStyle() <= wxLAST_HATCH )
494 {
495 HatchStyle style = HatchStyleHorizontal;
496 switch( pen.GetStyle() )
497 {
498 case wxBDIAGONAL_HATCH :
499 style = HatchStyleBackwardDiagonal;
500 break ;
501 case wxCROSSDIAG_HATCH :
502 style = HatchStyleDiagonalCross;
503 break ;
504 case wxFDIAGONAL_HATCH :
505 style = HatchStyleForwardDiagonal;
506 break ;
507 case wxCROSS_HATCH :
508 style = HatchStyleCross;
509 break ;
510 case wxHORIZONTAL_HATCH :
511 style = HatchStyleHorizontal;
512 break ;
513 case wxVERTICAL_HATCH :
514 style = HatchStyleVertical;
515 break ;
516
517 }
518 m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
519 pen.GetColour().Green() , pen.GetColour().Blue() ), Color::Transparent );
520 m_pen->SetBrush( m_penBrush );
521 }
522 break;
cb3a0d42 523 }
83576e68
SC
524 if ( dashStyle != DashStyleSolid )
525 m_pen->SetDashStyle(dashStyle);
526}
527
83576e68
SC
528//-----------------------------------------------------------------------------
529// wxGDIPlusBrush implementation
530//-----------------------------------------------------------------------------
531
2c820406
SC
532wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer )
533: wxGraphicsObjectRefData(renderer)
83576e68
SC
534{
535 Init();
536}
537
2c820406
SC
538wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxBrush &brush )
539: wxGraphicsObjectRefData(renderer)
83576e68
SC
540{
541 Init();
542 if ( brush.GetStyle() == wxSOLID)
543 {
544 m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
545 brush.GetColour().Green() , brush.GetColour().Blue() ) );
546 }
547 else if ( brush.IsHatch() )
548 {
549 HatchStyle style = HatchStyleHorizontal;
550 switch( brush.GetStyle() )
551 {
552 case wxBDIAGONAL_HATCH :
553 style = HatchStyleBackwardDiagonal;
554 break ;
555 case wxCROSSDIAG_HATCH :
556 style = HatchStyleDiagonalCross;
557 break ;
558 case wxFDIAGONAL_HATCH :
559 style = HatchStyleForwardDiagonal;
560 break ;
561 case wxCROSS_HATCH :
562 style = HatchStyleCross;
563 break ;
564 case wxHORIZONTAL_HATCH :
565 style = HatchStyleHorizontal;
566 break ;
567 case wxVERTICAL_HATCH :
568 style = HatchStyleVertical;
569 break ;
570
571 }
572 m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
573 brush.GetColour().Green() , brush.GetColour().Blue() ), Color::Transparent );
574 }
cb3a0d42 575 else
83576e68
SC
576 {
577 wxBitmap* bmp = brush.GetStipple();
578 if ( bmp && bmp->Ok() )
579 {
580 wxDELETE( m_brushImage );
581 m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
582 m_brush = new TextureBrush(m_brushImage);
583 }
584 }
585}
586
2c820406 587wxGDIPlusBrushData::~wxGDIPlusBrushData()
83576e68
SC
588{
589 delete m_brush;
590 delete m_brushImage;
591 delete m_brushPath;
592};
593
2c820406 594void wxGDIPlusBrushData::Init()
83576e68
SC
595{
596 m_brush = NULL;
597 m_brushImage= NULL;
598 m_brushPath= NULL;
599}
600
cb3a0d42 601void wxGDIPlusBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2)
83576e68
SC
602{
603 m_brush = new LinearGradientBrush( PointF( x1,y1) , PointF( x2,y2),
604 Color( c1.Alpha(), c1.Red(),c1.Green() , c1.Blue() ),
605 Color( c2.Alpha(), c2.Red(),c2.Green() , c2.Blue() ));
606}
607
2c820406 608void wxGDIPlusBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
83576e68
SC
609 const wxColour &oColor, const wxColour &cColor)
610{
611 // Create a path that consists of a single circle.
612 m_brushPath = new GraphicsPath();
613 m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius), (REAL)(2*radius), (REAL)(2*radius));
614
615 PathGradientBrush *b = new PathGradientBrush(m_brushPath);
616 m_brush = b;
617 b->SetCenterPoint( PointF(xo,yo));
618 b->SetCenterColor(Color( oColor.Alpha(), oColor.Red(),oColor.Green() , oColor.Blue() ));
619
620 Color colors[] = {Color( cColor.Alpha(), cColor.Red(),cColor.Green() , cColor.Blue() )};
621 int count = 1;
622 b->SetSurroundColors(colors, &count);
623}
624
83576e68
SC
625//-----------------------------------------------------------------------------
626// wxGDIPlusFont implementation
627//-----------------------------------------------------------------------------
628
cb3a0d42 629wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont &font,
2c820406 630 const wxColour& col ) : wxGraphicsObjectRefData( renderer )
83576e68
SC
631{
632 m_textBrush = NULL;
633 m_font = NULL;
634
635 wxWCharBuffer s = font.GetFaceName().wc_str( *wxConvUI );
636 int size = font.GetPointSize();
637 int style = FontStyleRegular;
638 if ( font.GetStyle() == wxFONTSTYLE_ITALIC )
639 style |= FontStyleItalic;
640 if ( font.GetUnderlined() )
641 style |= FontStyleUnderline;
642 if ( font.GetWeight() == wxFONTWEIGHT_BOLD )
643 style |= FontStyleBold;
644 m_font = new Font( s , size , style );
645 m_textBrush = new SolidBrush( Color( col.Alpha() , col.Red() ,
646 col.Green() , col.Blue() ));
647}
6fea499c 648
2c820406 649wxGDIPlusFontData::~wxGDIPlusFontData()
83576e68
SC
650{
651 delete m_textBrush;
652 delete m_font;
653}
6fea499c 654
bce28872
SC
655// the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
656// premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
657// bytes as parameter, since there is no real copying of the data going in, only references are stored
658// m_helper has to be kept alive as well
659
660//-----------------------------------------------------------------------------
661// wxGDIPlusBitmapData implementation
662//-----------------------------------------------------------------------------
663
664wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer* renderer, Bitmap* bitmap ) :
665 wxGraphicsObjectRefData( renderer ), m_bitmap( bitmap )
666{
667 m_helper = NULL;
668}
669
670wxGDIPlusBitmapData::wxGDIPlusBitmapData( wxGraphicsRenderer* renderer,
671 const wxBitmap &bmp) : wxGraphicsObjectRefData( renderer )
672{
673 m_bitmap = NULL;
674 m_helper = NULL;
675
676 Bitmap* image = NULL;
677 if ( bmp.GetMask() )
678 {
679 Bitmap interim((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE()) ;
680
681 size_t width = interim.GetWidth();
682 size_t height = interim.GetHeight();
683 Rect bounds(0,0,width,height);
684
685 image = new Bitmap(width,height,PixelFormat32bppPARGB) ;
686
687 Bitmap interimMask((HBITMAP)bmp.GetMask()->GetMaskBitmap(),NULL);
688 wxASSERT(interimMask.GetPixelFormat() == PixelFormat1bppIndexed);
689
690 BitmapData dataMask ;
691 interimMask.LockBits(&bounds,ImageLockModeRead,
692 interimMask.GetPixelFormat(),&dataMask);
693
694
695 BitmapData imageData ;
696 image->LockBits(&bounds,ImageLockModeWrite, PixelFormat32bppPARGB, &imageData);
697
698 BYTE maskPattern = 0 ;
699 BYTE maskByte = 0;
700 size_t maskIndex ;
701
702 for ( size_t y = 0 ; y < height ; ++y)
703 {
704 maskIndex = 0 ;
705 for( size_t x = 0 ; x < width; ++x)
706 {
707 if ( x % 8 == 0)
708 {
709 maskPattern = 0x80;
710 maskByte = *((BYTE*)dataMask.Scan0 + dataMask.Stride*y + maskIndex);
711 maskIndex++;
712 }
713 else
714 maskPattern = maskPattern >> 1;
715
716 ARGB *dest = (ARGB*)((BYTE*)imageData.Scan0 + imageData.Stride*y + x*4);
717 if ( (maskByte & maskPattern) == 0 )
718 *dest = 0x00000000;
719 else
720 {
721 Color c ;
722 interim.GetPixel(x,y,&c) ;
723 *dest = (c.GetValue() | Color::AlphaMask);
724 }
725 }
726 }
727
728 image->UnlockBits(&imageData);
729
730 interimMask.UnlockBits(&dataMask);
731 interim.UnlockBits(&dataMask);
732 }
733 else
734 {
735 image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE());
736 if ( bmp.HasAlpha() && GetPixelFormatSize(image->GetPixelFormat()) == 32 )
737 {
738 size_t width = image->GetWidth();
739 size_t height = image->GetHeight();
740 Rect bounds(0,0,width,height);
741 static BitmapData data ;
742
743 m_helper = image ;
744 image = NULL ;
745 m_helper->LockBits(&bounds, ImageLockModeRead,
746 m_helper->GetPixelFormat(),&data);
747
748 image = new Bitmap(data.Width, data.Height, data.Stride,
749 PixelFormat32bppPARGB , (BYTE*) data.Scan0);
750
751 m_helper->UnlockBits(&data);
752 }
753 }
754 if ( image )
755 m_bitmap = image;
756}
757
758wxGDIPlusBitmapData::~wxGDIPlusBitmapData()
759{
760 delete m_bitmap;
761 delete m_helper;
762}
763
83576e68
SC
764//-----------------------------------------------------------------------------
765// wxGDIPlusPath implementation
766//-----------------------------------------------------------------------------
6fea499c 767
a4e73390 768wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer* renderer, GraphicsPath* path ) : wxGraphicsPathData(renderer)
83576e68
SC
769{
770 if ( path )
771 m_path = path;
772 else
773 m_path = new GraphicsPath();
774}
775
a4e73390 776wxGDIPlusPathData::~wxGDIPlusPathData()
6fea499c
SC
777{
778 delete m_path;
779}
780
a4e73390 781wxGraphicsObjectRefData* wxGDIPlusPathData::Clone() const
83576e68 782{
a4e73390 783 return new wxGDIPlusPathData( GetRenderer() , m_path->Clone());
83576e68
SC
784}
785
6fea499c
SC
786//
787// The Primitives
788//
789
a4e73390 790void wxGDIPlusPathData::MoveToPoint( wxDouble x , wxDouble y )
6fea499c
SC
791{
792 m_path->StartFigure();
793 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
794}
795
a4e73390 796void wxGDIPlusPathData::AddLineToPoint( wxDouble x , wxDouble y )
6fea499c
SC
797{
798 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
799}
800
a4e73390 801void wxGDIPlusPathData::CloseSubpath()
6fea499c
SC
802{
803 m_path->CloseFigure();
804}
805
a4e73390 806void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
6fea499c
SC
807{
808 PointF c1(cx1,cy1);
809 PointF c2(cx2,cy2);
810 PointF end(x,y);
811 PointF start;
812 m_path->GetLastPoint(&start);
813 m_path->AddBezier(start,c1,c2,end);
814}
815
816// gets the last point of the current path, (0,0) if not yet set
a4e73390 817void wxGDIPlusPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
6fea499c
SC
818{
819 PointF start;
820 m_path->GetLastPoint(&start);
a4e73390
SC
821 *x = start.X ;
822 *y = start.Y ;
6fea499c
SC
823}
824
cb3a0d42 825void wxGDIPlusPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise )
6fea499c
SC
826{
827 double sweepAngle = endAngle - startAngle ;
c5b8c66a 828 if( fabs(sweepAngle) >= 2*M_PI)
6fea499c
SC
829 {
830 sweepAngle = 2 * M_PI;
831 }
832 else
833 {
834 if ( clockwise )
835 {
836 if( sweepAngle < 0 )
837 sweepAngle += 2 * M_PI;
838 }
839 else
840 {
841 if( sweepAngle > 0 )
842 sweepAngle -= 2 * M_PI;
843
844 }
845 }
cb3a0d42 846 m_path->AddArc((REAL) (x-r),(REAL) (y-r),(REAL) (2*r),(REAL) (2*r),RadToDeg(startAngle),RadToDeg(sweepAngle));
6fea499c
SC
847}
848
a4e73390 849void wxGDIPlusPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
6fea499c
SC
850{
851 m_path->AddRectangle(RectF(x,y,w,h));
852}
853
a4e73390 854void wxGDIPlusPathData::AddPath( const wxGraphicsPathData* path )
6fea499c 855{
83576e68 856 m_path->AddPath( (GraphicsPath*) path->GetNativePath(), FALSE);
6fea499c
SC
857}
858
6fea499c 859
83576e68 860// transforms each point of this path by the matrix
cb3a0d42 861void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData* matrix )
9f339b18 862{
83576e68 863 m_path->Transform( (Matrix*) matrix->GetNativeMatrix() );
9f339b18 864}
6fea499c 865
83576e68 866// gets the bounding box enclosing all points (possibly including control points)
a4e73390 867void wxGDIPlusPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
e49c065d 868{
83576e68
SC
869 RectF bounds;
870 m_path->GetBounds( &bounds, NULL, NULL) ;
871 *x = bounds.X;
872 *y = bounds.Y;
873 *w = bounds.Width;
874 *h = bounds.Height;
e49c065d
RD
875}
876
a4e73390 877bool wxGDIPlusPathData::Contains( wxDouble x, wxDouble y, int fillStyle ) const
6fea499c 878{
83576e68
SC
879 m_path->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
880 return m_path->IsVisible( (FLOAT) x,(FLOAT) y) == TRUE ;
881}
9f339b18 882
83576e68 883//-----------------------------------------------------------------------------
a4e73390 884// wxGDIPlusMatrixData implementation
83576e68 885//-----------------------------------------------------------------------------
9f339b18 886
a4e73390
SC
887wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer* renderer, Matrix* matrix )
888 : wxGraphicsMatrixData(renderer)
9f339b18 889{
83576e68
SC
890 if ( matrix )
891 m_matrix = matrix ;
892 else
893 m_matrix = new Matrix();
6fea499c
SC
894}
895
cb3a0d42 896wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
6fea499c 897{
83576e68 898 delete m_matrix;
6fea499c
SC
899}
900
cb3a0d42 901wxGraphicsObjectRefData *wxGDIPlusMatrixData::Clone() const
6fea499c 902{
a4e73390 903 return new wxGDIPlusMatrixData( GetRenderer(), m_matrix->Clone());
539e2795
SC
904}
905
83576e68 906// concatenates the matrix
a4e73390 907void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData *t )
539e2795 908{
83576e68 909 m_matrix->Multiply( (Matrix*) t->GetNativeMatrix());
539e2795 910}
83576e68 911
83576e68 912// sets the matrix to the respective values
cb3a0d42 913void wxGDIPlusMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
83576e68 914 wxDouble tx, wxDouble ty)
6fea499c 915{
83576e68 916 m_matrix->SetElements(a,b,c,d,tx,ty);
6fea499c
SC
917}
918
248802d0
RD
919// gets the component valuess of the matrix
920void wxGDIPlusMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c,
921 wxDouble* d, wxDouble* tx, wxDouble* ty) const
922{
923 REAL elements[6];
924 m_matrix->GetElements(elements);
925 if (a) *a = elements[0];
926 if (b) *b = elements[1];
927 if (c) *c = elements[2];
928 if (d) *d = elements[3];
929 if (tx) *tx= elements[4];
930 if (ty) *ty= elements[5];
931}
932
83576e68 933// makes this the inverse matrix
a4e73390 934void wxGDIPlusMatrixData::Invert()
6fea499c 935{
83576e68 936 m_matrix->Invert();
6fea499c
SC
937}
938
83576e68 939// returns true if the elements of the transformation matrix are equal ?
cb3a0d42 940bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
6fea499c 941{
83576e68 942 return m_matrix->Equals((Matrix*) t->GetNativeMatrix())== TRUE ;
6fea499c
SC
943}
944
83576e68 945// return true if this is the identity matrix
a4e73390 946bool wxGDIPlusMatrixData::IsIdentity() const
6fea499c 947{
83576e68 948 return m_matrix->IsIdentity() == TRUE ;
6fea499c
SC
949}
950
83576e68
SC
951//
952// transformation
953//
954
955// add the translation to this matrix
a4e73390 956void wxGDIPlusMatrixData::Translate( wxDouble dx , wxDouble dy )
6fea499c 957{
83576e68 958 m_matrix->Translate(dx,dy);
6fea499c
SC
959}
960
83576e68 961// add the scale to this matrix
a4e73390 962void wxGDIPlusMatrixData::Scale( wxDouble xScale , wxDouble yScale )
6fea499c 963{
83576e68 964 m_matrix->Scale(xScale,yScale);
6fea499c
SC
965}
966
83576e68 967// add the rotation to this matrix (radians)
a4e73390 968void wxGDIPlusMatrixData::Rotate( wxDouble angle )
6fea499c 969{
83576e68 970 m_matrix->Rotate( angle );
6fea499c
SC
971}
972
83576e68
SC
973//
974// apply the transforms
975//
976
977// applies that matrix to the point
a4e73390 978void wxGDIPlusMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
6fea499c 979{
83576e68
SC
980 PointF pt(*x,*y);
981 m_matrix->TransformPoints(&pt);
982 *x = pt.X;
983 *y = pt.Y;
6fea499c
SC
984}
985
83576e68 986// applies the matrix except for translations
a4e73390 987void wxGDIPlusMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
6fea499c 988{
83576e68
SC
989 PointF pt(*dx,*dy);
990 m_matrix->TransformVectors(&pt);
991 *dx = pt.X;
992 *dy = pt.Y;
6fea499c
SC
993}
994
83576e68 995// returns the native representation
a4e73390 996void * wxGDIPlusMatrixData::GetNativeMatrix() const
6fea499c 997{
83576e68
SC
998 return m_matrix;
999}
6fea499c 1000
83576e68
SC
1001//-----------------------------------------------------------------------------
1002// wxGDIPlusContext implementation
1003//-----------------------------------------------------------------------------
1004
1005IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext,wxGraphicsContext)
0c7bd159
SC
1006IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusMeasuringContext,wxGDIPlusContext)
1007
1008class wxGDIPlusOffsetHelper
1009{
1010public :
1011 wxGDIPlusOffsetHelper( Graphics* gr , bool offset )
1012 {
1013 m_gr = gr;
1014 m_offset = offset;
1015 if ( m_offset )
1016 m_gr->TranslateTransform( 0.5, 0.5 );
1017 }
1018 ~wxGDIPlusOffsetHelper( )
1019 {
1020 if ( m_offset )
1021 m_gr->TranslateTransform( -0.5, -0.5 );
1022 }
1023public :
1024 Graphics* m_gr;
1025 bool m_offset;
1026} ;
83576e68 1027
81e0b3d9 1028wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc, wxDouble width, wxDouble height )
83576e68
SC
1029 : wxGraphicsContext(renderer)
1030{
1031 Init();
1032 m_context = new Graphics( hdc);
81e0b3d9
SC
1033 m_width = width;
1034 m_height = height;
83576e68 1035 SetDefaults();
6fea499c
SC
1036}
1037
83576e68
SC
1038wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd )
1039 : wxGraphicsContext(renderer)
6fea499c 1040{
83576e68
SC
1041 Init();
1042 m_context = new Graphics( hwnd);
81e0b3d9
SC
1043 RECT rect = wxGetWindowRect(hwnd);
1044 m_width = rect.right - rect.left;
1045 m_height = rect.bottom - rect.top;
83576e68
SC
1046 SetDefaults();
1047}
6fea499c 1048
83576e68
SC
1049wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr )
1050 : wxGraphicsContext(renderer)
1051{
1052 Init();
1053 m_context = gr;
1054 SetDefaults();
1055}
6fea499c 1056
83576e68
SC
1057wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL)
1058{
1059 Init();
1060}
6fea499c 1061
83576e68
SC
1062void wxGDIPlusContext::Init()
1063{
1064 m_context = NULL;
1065 m_state1 = 0;
1066 m_state2= 0;
81e0b3d9
SC
1067 m_height = 0;
1068 m_width = 0;
83576e68 1069}
6fea499c 1070
83576e68
SC
1071void wxGDIPlusContext::SetDefaults()
1072{
0c7bd159
SC
1073 m_context->SetTextRenderingHint(TextRenderingHintSystemDefault);
1074 m_context->SetPixelOffsetMode(PixelOffsetModeHalf);
83576e68
SC
1075 m_context->SetSmoothingMode(SmoothingModeHighQuality);
1076 m_state1 = m_context->Save();
1077 m_state2 = m_context->Save();
1078}
6fea499c 1079
83576e68
SC
1080wxGDIPlusContext::~wxGDIPlusContext()
1081{
83576e68 1082 if ( m_context )
6fea499c 1083 {
83576e68
SC
1084 m_context->Restore( m_state2 );
1085 m_context->Restore( m_state1 );
1086 delete m_context;
6fea499c
SC
1087 }
1088}
1089
83576e68
SC
1090
1091void wxGDIPlusContext::Clip( const wxRegion &region )
6fea499c 1092{
93f72bae
SC
1093 Region rgn((HRGN)region.GetHRGN());
1094 m_context->SetClip(&rgn,CombineModeIntersect);
83576e68 1095}
6fea499c 1096
83576e68
SC
1097void wxGDIPlusContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1098{
1099 m_context->SetClip(RectF(x,y,w,h),CombineModeIntersect);
1100}
cb3a0d42 1101
83576e68
SC
1102void wxGDIPlusContext::ResetClip()
1103{
1104 m_context->ResetClip();
1105}
6fea499c 1106
0c7bd159
SC
1107void wxGDIPlusContext::StrokeLines( size_t n, const wxPoint2DDouble *points)
1108{
1109 if ( !m_pen.IsNull() )
1110 {
1111 wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
1112 Point *cpoints = new Point[n];
1113 for (size_t i = 0; i < n; i++)
1114 {
1115 cpoints[i].X = (int)(points[i].m_x );
1116 cpoints[i].Y = (int)(points[i].m_y );
1117
1118 } // for (size_t i = 0; i < n; i++)
1119 m_context->DrawLines( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , cpoints , n ) ;
1120 delete[] cpoints;
1121 }
1122}
1123
1124void wxGDIPlusContext::DrawLines( size_t n, const wxPoint2DDouble *points, int WXUNUSED(fillStyle) )
1125{
1126 wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
1127 Point *cpoints = new Point[n];
1128 for (size_t i = 0; i < n; i++)
1129 {
1130 cpoints[i].X = (int)(points[i].m_x );
1131 cpoints[i].Y = (int)(points[i].m_y );
1132
1133 } // for (int i = 0; i < n; i++)
1134 if ( !m_brush.IsNull() )
1135 m_context->FillPolygon( ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush() , cpoints , n ) ;
1136 if ( !m_pen.IsNull() )
1137 m_context->DrawLines( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , cpoints , n ) ;
1138 delete[] cpoints;
1139}
1140
a4e73390 1141void wxGDIPlusContext::StrokePath( const wxGraphicsPath& path )
83576e68 1142{
2c820406 1143 if ( !m_pen.IsNull() )
83576e68 1144 {
0c7bd159 1145 wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
a4e73390 1146 m_context->DrawPath( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath*) path.GetNativePath() );
83576e68 1147 }
6fea499c
SC
1148}
1149
a4e73390 1150void wxGDIPlusContext::FillPath( const wxGraphicsPath& path , int fillStyle )
6fea499c 1151{
2c820406 1152 if ( !m_brush.IsNull() )
83576e68 1153 {
0c7bd159 1154 wxGDIPlusOffsetHelper helper( m_context , ShouldOffset() );
a4e73390 1155 ((GraphicsPath*) path.GetNativePath())->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
cb3a0d42 1156 m_context->FillPath( ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush() ,
a4e73390 1157 (GraphicsPath*) path.GetNativePath());
83576e68
SC
1158 }
1159}
6fea499c 1160
cb3a0d42 1161void wxGDIPlusContext::Rotate( wxDouble angle )
83576e68
SC
1162{
1163 m_context->RotateTransform( RadToDeg(angle) );
1164}
6fea499c 1165
cb3a0d42 1166void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy )
83576e68
SC
1167{
1168 m_context->TranslateTransform( dx , dy );
1169}
6fea499c 1170
83576e68
SC
1171void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale )
1172{
1173 m_context->ScaleTransform(xScale,yScale);
1174}
6fea499c 1175
83576e68
SC
1176void wxGDIPlusContext::PushState()
1177{
1178 GraphicsState state = m_context->Save();
bdba6fdc 1179 m_stateStack.push(state);
83576e68
SC
1180}
1181
cb3a0d42 1182void wxGDIPlusContext::PopState()
83576e68 1183{
bdba6fdc
VZ
1184 GraphicsState state = m_stateStack.top();
1185 m_stateStack.pop();
83576e68 1186 m_context->Restore(state);
6fea499c
SC
1187}
1188
bce28872 1189void wxGDIPlusContext::DrawBitmap( const wxGraphicsBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
6fea499c 1190{
bce28872
SC
1191 Bitmap* image = static_cast<wxGDIPlusBitmapData*>(bmp.GetRefData())->GetGDIPlusBitmap();
1192 if ( image )
cb3a0d42 1193 {
bce28872 1194 if( image->GetWidth() != (UINT) w || image->GetHeight() != (UINT) h )
fe31db81 1195 {
bce28872
SC
1196 Rect drawRect((REAL) x, (REAL)y, (REAL)w, (REAL)h);
1197 m_context->SetPixelOffsetMode( PixelOffsetModeNone );
1198 m_context->DrawImage(image, drawRect, 0 , 0 , image->GetWidth()-1, image->GetHeight()-1, UnitPixel ) ;
1199 m_context->SetPixelOffsetMode( PixelOffsetModeHalf );
fe31db81 1200 }
bce28872
SC
1201 else
1202 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
fe31db81 1203 }
bce28872 1204}
fe31db81 1205
bce28872
SC
1206void wxGDIPlusContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1207{
1208 wxGraphicsBitmap bitmap = GetRenderer()->CreateBitmap(bmp);
1209 DrawBitmap(bitmap, x, y, w, h);
6fea499c
SC
1210}
1211
cb3a0d42 1212void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
6fea499c 1213{
0c7bd159
SC
1214 // the built-in conversion fails when there is alpha in the HICON (eg XP style icons), we can only
1215 // find out by looking at the bitmap data whether there really was alpha in it
fe31db81
SC
1216 HICON hIcon = (HICON)icon.GetHICON();
1217 ICONINFO iconInfo ;
1218 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1219 if (!GetIconInfo(hIcon,&iconInfo))
1220 return;
1221
fe31db81
SC
1222 Bitmap interim(iconInfo.hbmColor,NULL);
1223
1224 Bitmap* image = NULL ;
1225
0c7bd159
SC
1226 // if it's not 32 bit, it doesn't have an alpha channel, note that since the conversion doesn't
1227 // work correctly, asking IsAlphaPixelFormat at this point fails as well
fe31db81
SC
1228 if( GetPixelFormatSize(interim.GetPixelFormat())!= 32 )
1229 {
1230 image = Bitmap::FromHICON(hIcon);
1231 }
1232 else
1233 {
1234 size_t width = interim.GetWidth();
1235 size_t height = interim.GetHeight();
1236 Rect bounds(0,0,width,height);
1237 BitmapData data ;
1238
1239 interim.LockBits(&bounds, ImageLockModeRead,
1240 interim.GetPixelFormat(),&data);
0c7bd159
SC
1241
1242 bool hasAlpha = false;
1243 for ( size_t y = 0 ; y < height && !hasAlpha ; ++y)
1244 {
1245 for( size_t x = 0 ; x < width && !hasAlpha; ++x)
1246 {
1247 ARGB *dest = (ARGB*)((BYTE*)data.Scan0 + data.Stride*y + x*4);
1248 if ( ( *dest & Color::AlphaMask ) != 0 )
1249 hasAlpha = true;
1250 }
1251 }
1252
1253 if ( hasAlpha )
1254 {
cb3a0d42 1255 image = new Bitmap(data.Width, data.Height, data.Stride,
fe31db81 1256 PixelFormat32bppARGB , (BYTE*) data.Scan0);
0c7bd159
SC
1257 }
1258 else
1259 {
1260 image = Bitmap::FromHICON(hIcon);
1261 }
1262
fe31db81
SC
1263 interim.UnlockBits(&data);
1264 }
1265
6fea499c 1266 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
fe31db81 1267
6fea499c 1268 delete image ;
fe31db81
SC
1269 DeleteObject(iconInfo.hbmColor);
1270 DeleteObject(iconInfo.hbmMask);
6fea499c
SC
1271}
1272
cb3a0d42 1273void wxGDIPlusContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
6fea499c 1274{
1011fbeb
SC
1275 wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::DrawText - no valid font set") );
1276
1277 if ( str.IsEmpty())
6fea499c
SC
1278 return ;
1279
1280 wxWCharBuffer s = str.wc_str( *wxConvUI );
cb3a0d42 1281 m_context->DrawString( s , -1 , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont() ,
0c7bd159 1282 PointF( x , y ) , StringFormat::GenericTypographic() , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusBrush() );
6fea499c
SC
1283}
1284
1285void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1286 wxDouble *descent, wxDouble *externalLeading ) const
1287{
1011fbeb
SC
1288 wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::GetTextExtent - no valid font set") );
1289
6fea499c
SC
1290 wxWCharBuffer s = str.wc_str( *wxConvUI );
1291 FontFamily ffamily ;
2c820406 1292 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
cb3a0d42 1293
83576e68 1294 f->GetFamily(&ffamily) ;
6fea499c
SC
1295
1296 REAL factorY = m_context->GetDpiY() / 72.0 ;
1297
1298 REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
83576e68 1299 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c 1300 REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
83576e68 1301 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c 1302 REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
83576e68 1303 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c
SC
1304
1305 if ( height )
595fda6f 1306 *height = rHeight * factorY;
6fea499c 1307 if ( descent )
595fda6f 1308 *descent = rDescent * factorY;
6fea499c 1309 if ( externalLeading )
595fda6f 1310 *externalLeading = (rHeight - rAscent - rDescent) * factorY;
6fea499c 1311 // measuring empty strings is not guaranteed, so do it by hand
cb3a0d42 1312 if ( str.IsEmpty())
6fea499c
SC
1313 {
1314 if ( width )
1315 *width = 0 ;
1316 }
1317 else
1318 {
6fea499c 1319 RectF layoutRect(0,0, 100000.0f, 100000.0f);
0c7bd159
SC
1320 StringFormat strFormat( StringFormat::GenericTypographic() );
1321 strFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces | strFormat.GetFormatFlags() );
1322
1323 RectF bounds ;
1324 m_context->MeasureString((const wchar_t *) s , wcslen(s) , f, layoutRect, &strFormat, &bounds ) ;
6fea499c 1325 if ( width )
0c7bd159 1326 *width = bounds.Width;
6fea499c
SC
1327 }
1328}
1329
cb3a0d42 1330void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
6fea499c
SC
1331{
1332 widths.Empty();
1333 widths.Add(0, text.length());
1334
1011fbeb
SC
1335 wxCHECK_RET( !m_font.IsNull(), wxT("wxGDIPlusContext::GetPartialTextExtents - no valid font set") );
1336
6fea499c
SC
1337 if (text.empty())
1338 return;
1339
2c820406 1340 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
6fea499c
SC
1341 wxWCharBuffer ws = text.wc_str( *wxConvUI );
1342 size_t len = wcslen( ws ) ;
1343 wxASSERT_MSG(text.length() == len , wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1344
1345 RectF layoutRect(0,0, 100000.0f, 100000.0f);
0c7bd159 1346 StringFormat strFormat( StringFormat::GenericTypographic() );
6fea499c
SC
1347
1348 CharacterRange* ranges = new CharacterRange[len] ;
1349 Region* regions = new Region[len];
0c7bd159 1350 for( size_t i = 0 ; i < len ; ++i)
6fea499c
SC
1351 {
1352 ranges[i].First = i ;
1353 ranges[i].Length = 1 ;
1354 }
1355 strFormat.SetMeasurableCharacterRanges(len,ranges);
0c7bd159 1356 strFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces | strFormat.GetFormatFlags() );
83576e68 1357 m_context->MeasureCharacterRanges(ws, -1 , f,layoutRect, &strFormat,1,regions) ;
6fea499c
SC
1358
1359 RectF bbox ;
0c7bd159 1360 for ( size_t i = 0 ; i < len ; ++i)
6fea499c
SC
1361 {
1362 regions[i].GetBounds(&bbox,m_context);
1363 widths[i] = bbox.GetRight()-bbox.GetLeft();
1364 }
1365}
1366
d9485f89
RD
1367bool wxGDIPlusContext::ShouldOffset() const
1368{
1369 int penwidth = 0 ;
1370 if ( !m_pen.IsNull() )
1371 {
1372 penwidth = (int)((wxGDIPlusPenData*)m_pen.GetRefData())->GetWidth();
1373 if ( penwidth == 0 )
1374 penwidth = 1;
1375 }
1376 return ( penwidth % 2 ) == 1;
1377}
1378
cb3a0d42 1379void* wxGDIPlusContext::GetNativeContext()
6fea499c 1380{
cb3a0d42 1381 return m_context;
6fea499c
SC
1382}
1383
83576e68 1384// concatenates this transform with the current transform of this context
a4e73390 1385void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix& matrix )
539e2795 1386{
a4e73390 1387 m_context->MultiplyTransform((Matrix*) matrix.GetNativeMatrix());
83576e68
SC
1388}
1389
1390// sets the transform of this context
a4e73390 1391void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix& matrix )
83576e68 1392{
a4e73390 1393 m_context->SetTransform((Matrix*) matrix.GetNativeMatrix());
83576e68
SC
1394}
1395
1396// gets the matrix of this context
a4e73390 1397wxGraphicsMatrix wxGDIPlusContext::GetTransform() const
83576e68 1398{
a4e73390
SC
1399 wxGraphicsMatrix matrix = CreateMatrix();
1400 m_context->GetTransform((Matrix*) matrix.GetNativeMatrix());
1401 return matrix;
83576e68 1402}
fbd5416f
SC
1403
1404void wxGDIPlusContext::GetSize( wxDouble* width, wxDouble *height )
1405{
81e0b3d9
SC
1406 *width = m_width;
1407 *height = m_height;
fbd5416f 1408}
83576e68
SC
1409//-----------------------------------------------------------------------------
1410// wxGDIPlusRenderer declaration
1411//-----------------------------------------------------------------------------
1412
eb4083ef 1413class wxGDIPlusRenderer : public wxGraphicsRenderer
83576e68
SC
1414{
1415public :
cb3a0d42 1416 wxGDIPlusRenderer()
83576e68 1417 {
bce82a75 1418 m_loaded = -1;
cb3a0d42 1419 m_gditoken = 0;
83576e68
SC
1420 }
1421
cb3a0d42 1422 virtual ~wxGDIPlusRenderer()
83576e68 1423 {
bce82a75 1424 if ( m_loaded == 1 )
83576e68
SC
1425 {
1426 Unload();
1427 }
1428 }
1429
1430 // Context
1431
1432 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
1433
773ccc31
SC
1434 virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
1435
0b822969
RR
1436 virtual wxGraphicsContext * CreateContext( const wxPrinterDC& dc);
1437
83576e68
SC
1438 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
1439
1440 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
1441
1442 virtual wxGraphicsContext * CreateContext( wxWindow* window );
1443
091ef146
SC
1444 virtual wxGraphicsContext * CreateMeasuringContext();
1445
83576e68
SC
1446 // Path
1447
a4e73390 1448 virtual wxGraphicsPath CreatePath();
83576e68
SC
1449
1450 // Matrix
1451
cb3a0d42 1452 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
83576e68
SC
1453 wxDouble tx=0.0, wxDouble ty=0.0);
1454
1455
2c820406 1456 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
83576e68 1457
2c820406 1458 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
83576e68
SC
1459
1460 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
cb3a0d42 1461 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
83576e68
SC
1462 const wxColour&c1, const wxColour&c2) ;
1463
cb3a0d42 1464 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
83576e68 1465 // with radius r and color cColor
2c820406 1466 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
83576e68
SC
1467 const wxColour &oColor, const wxColour &cColor) ;
1468
1469 // sets the font
2c820406 1470 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
bce28872
SC
1471
1472 // create a native bitmap representation
1473 virtual wxGraphicsBitmap CreateBitmap( const wxBitmap &bitmap );
1474
1475 // create a subimage from a native image representation
1476 virtual wxGraphicsBitmap CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
1477
83576e68 1478protected :
bce82a75 1479 bool EnsureIsLoaded();
83576e68
SC
1480 void Load();
1481 void Unload();
385addaf 1482 friend class wxGDIPlusRendererModule;
83576e68
SC
1483
1484private :
bce82a75 1485 int m_loaded;
cb3a0d42 1486 ULONG_PTR m_gditoken;
83576e68
SC
1487
1488 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer)
1489} ;
1490
1491//-----------------------------------------------------------------------------
1492// wxGDIPlusRenderer implementation
1493//-----------------------------------------------------------------------------
1494
1495IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer,wxGraphicsRenderer)
1496
1497static wxGDIPlusRenderer gs_GDIPlusRenderer;
1498
1499wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1500{
1501 return &gs_GDIPlusRenderer;
1502}
1503
bce82a75 1504bool wxGDIPlusRenderer::EnsureIsLoaded()
83576e68 1505{
bce82a75
VS
1506 // load gdiplus.dll if not yet loaded, but don't bother doing it again
1507 // if we already tried and failed (we don't want to spend lot of time
1508 // returning NULL from wxGraphicsContext::Create(), which may be called
1509 // relatively frequently):
1510 if ( m_loaded == -1 )
83576e68
SC
1511 {
1512 Load();
1513 }
bce82a75
VS
1514
1515 return m_loaded == 1;
83576e68
SC
1516}
1517
bce82a75
VS
1518// call EnsureIsLoaded() and return returnOnFail value if it fails
1519#define ENSURE_LOADED_OR_RETURN(returnOnFail) \
1520 if ( !EnsureIsLoaded() ) \
1521 return (returnOnFail)
1522
1523
83576e68
SC
1524void wxGDIPlusRenderer::Load()
1525{
1526 GdiplusStartupInput input;
1527 GdiplusStartupOutput output;
bce82a75
VS
1528 if ( GdiplusStartup(&m_gditoken,&input,&output) == Gdiplus::Ok )
1529 {
1530 wxLogTrace("gdiplus", "successfully initialized GDI+");
1531 m_loaded = 1;
1532 }
1533 else
1534 {
1535 wxLogTrace("gdiplus", "failed to initialize GDI+, missing gdiplus.dll?");
1536 m_loaded = 0;
1537 }
83576e68
SC
1538}
1539
1540void wxGDIPlusRenderer::Unload()
1541{
1542 if ( m_gditoken )
385addaf 1543 {
83576e68 1544 GdiplusShutdown(m_gditoken);
385addaf
VZ
1545 m_gditoken = NULL;
1546 }
bce82a75 1547 m_loaded = -1; // next Load() will try again
83576e68
SC
1548}
1549
1550wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxWindowDC& dc)
1551{
bce82a75 1552 ENSURE_LOADED_OR_RETURN(NULL);
52018692 1553 wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
81e0b3d9
SC
1554 wxSize sz = dc.GetSize();
1555 return new wxGDIPlusContext(this,(HDC) msw->GetHDC(), sz.x, sz.y);
83576e68
SC
1556}
1557
0b822969
RR
1558wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxPrinterDC& dc)
1559{
bce82a75 1560 ENSURE_LOADED_OR_RETURN(NULL);
0b822969 1561 wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
81e0b3d9
SC
1562 wxSize sz = dc.GetSize();
1563 return new wxGDIPlusContext(this,(HDC) msw->GetHDC(), sz.x, sz.y);
0b822969
RR
1564}
1565
773ccc31
SC
1566wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxMemoryDC& dc)
1567{
bce82a75 1568 ENSURE_LOADED_OR_RETURN(NULL);
52018692 1569 wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
81e0b3d9
SC
1570 wxSize sz = dc.GetSize();
1571 return new wxGDIPlusContext(this,(HDC) msw->GetHDC(), sz.x, sz.y);
773ccc31
SC
1572}
1573
091ef146
SC
1574wxGraphicsContext * wxGDIPlusRenderer::CreateMeasuringContext()
1575{
bce82a75 1576 ENSURE_LOADED_OR_RETURN(NULL);
0c7bd159 1577 return new wxGDIPlusMeasuringContext(this);
091ef146
SC
1578}
1579
83576e68
SC
1580wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeContext( void * context )
1581{
bce82a75 1582 ENSURE_LOADED_OR_RETURN(NULL);
83576e68
SC
1583 return new wxGDIPlusContext(this,(Graphics*) context);
1584}
1585
1586
1587wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window )
1588{
bce82a75 1589 ENSURE_LOADED_OR_RETURN(NULL);
83576e68
SC
1590 return new wxGDIPlusContext(this,(HWND) window);
1591}
1592
1593wxGraphicsContext * wxGDIPlusRenderer::CreateContext( wxWindow* window )
1594{
bce82a75 1595 ENSURE_LOADED_OR_RETURN(NULL);
83576e68
SC
1596 return new wxGDIPlusContext(this, (HWND) window->GetHWND() );
1597}
1598
1599// Path
1600
a4e73390 1601wxGraphicsPath wxGDIPlusRenderer::CreatePath()
83576e68 1602{
bce82a75 1603 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPath);
a4e73390
SC
1604 wxGraphicsPath m;
1605 m.SetRefData( new wxGDIPlusPathData(this));
1606 return m;
83576e68
SC
1607}
1608
1609
1610// Matrix
1611
cb3a0d42 1612wxGraphicsMatrix wxGDIPlusRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
83576e68
SC
1613 wxDouble tx, wxDouble ty)
1614
1615{
bce82a75 1616 ENSURE_LOADED_OR_RETURN(wxNullGraphicsMatrix);
a4e73390
SC
1617 wxGraphicsMatrix m;
1618 wxGDIPlusMatrixData* data = new wxGDIPlusMatrixData( this );
1619 data->Set( a,b,c,d,tx,ty ) ;
1620 m.SetRefData(data);
83576e68 1621 return m;
539e2795
SC
1622}
1623
cb3a0d42 1624wxGraphicsPen wxGDIPlusRenderer::CreatePen(const wxPen& pen)
6fea499c 1625{
bce82a75 1626 ENSURE_LOADED_OR_RETURN(wxNullGraphicsPen);
83576e68 1627 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
2c820406 1628 return wxNullGraphicsPen;
83576e68 1629 else
2c820406
SC
1630 {
1631 wxGraphicsPen p;
1632 p.SetRefData(new wxGDIPlusPenData( this, pen ));
1633 return p;
1634 }
6fea499c 1635}
7ba86d93 1636
cb3a0d42 1637wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
539e2795 1638{
bce82a75 1639 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
83576e68 1640 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
2c820406 1641 return wxNullGraphicsBrush;
83576e68 1642 else
2c820406
SC
1643 {
1644 wxGraphicsBrush p;
1645 p.SetRefData(new wxGDIPlusBrushData( this, brush ));
1646 return p;
1647 }
539e2795
SC
1648}
1649
83576e68 1650// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
cb3a0d42
VZ
1651wxGraphicsBrush wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
1652 const wxColour&c1, const wxColour&c2)
539e2795 1653{
bce82a75 1654 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
2c820406
SC
1655 wxGraphicsBrush p;
1656 wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1657 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
1658 p.SetRefData(d);
1659 return p;
1660 }
539e2795 1661
cb3a0d42 1662// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
83576e68 1663// with radius r and color cColor
2c820406 1664wxGraphicsBrush wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
cb3a0d42 1665 const wxColour &oColor, const wxColour &cColor)
83576e68 1666{
bce82a75 1667 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBrush);
2c820406
SC
1668 wxGraphicsBrush p;
1669 wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1670 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
1671 p.SetRefData(d);
1672 return p;
83576e68 1673}
539e2795 1674
83576e68 1675// sets the font
cb3a0d42 1676wxGraphicsFont wxGDIPlusRenderer::CreateFont( const wxFont &font , const wxColour &col )
83576e68 1677{
bce82a75 1678 ENSURE_LOADED_OR_RETURN(wxNullGraphicsFont);
83576e68 1679 if ( font.Ok() )
cb3a0d42 1680 {
2c820406
SC
1681 wxGraphicsFont p;
1682 p.SetRefData(new wxGDIPlusFontData( this , font, col ));
1683 return p;
1684 }
83576e68 1685 else
2c820406 1686 return wxNullGraphicsFont;
83576e68 1687}
7ba86d93 1688
bce28872
SC
1689wxGraphicsBitmap wxGDIPlusRenderer::CreateBitmap( const wxBitmap &bitmap )
1690{
bce82a75 1691 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
bce28872
SC
1692 if ( bitmap.Ok() )
1693 {
1694 wxGraphicsBitmap p;
1695 p.SetRefData(new wxGDIPlusBitmapData( this , bitmap ));
1696 return p;
1697 }
1698 else
1699 return wxNullGraphicsBitmap;
1700}
1701
1702wxGraphicsBitmap wxGDIPlusRenderer::CreateSubBitmap( const wxGraphicsBitmap &bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1703{
bce82a75 1704 ENSURE_LOADED_OR_RETURN(wxNullGraphicsBitmap);
bce28872
SC
1705 Bitmap* image = static_cast<wxGDIPlusBitmapData*>(bitmap.GetRefData())->GetGDIPlusBitmap();
1706 if ( image )
1707 {
1708 wxGraphicsBitmap p;
1709 p.SetRefData(new wxGDIPlusBitmapData( this , image->Clone( (REAL) x , (REAL) y , (REAL) w , (REAL) h , PixelFormat32bppPARGB) ));
1710 return p;
1711 }
1712 else
1713 return wxNullGraphicsBitmap;
1714}
1715
385addaf
VZ
1716// Shutdown GDI+ at app exit, before possible dll unload
1717class wxGDIPlusRendererModule : public wxModule
1718{
1719public:
1720 virtual bool OnInit() { return true; }
1721 virtual void OnExit() { gs_GDIPlusRenderer.Unload(); }
1722
1723private:
1724 DECLARE_DYNAMIC_CLASS(wxGDIPlusRendererModule)
1725};
1726
1727IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRendererModule, wxModule)
1728
7ba86d93 1729#endif // wxUSE_GRAPHICS_CONTEXT