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