]> git.saurik.com Git - wxWidgets.git/blame - src/msw/graphics.cpp
Fixed typo.
[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
20#ifndef WX_PRECOMP
21#include "wx/msw/wrapcdlg.h"
22#include "wx/image.h"
23#include "wx/window.h"
24#include "wx/dc.h"
25#include "wx/utils.h"
26#include "wx/dialog.h"
27#include "wx/app.h"
28#include "wx/bitmap.h"
29#include "wx/dcmemory.h"
30#include "wx/log.h"
31#include "wx/icon.h"
32#include "wx/dcprint.h"
33#include "wx/module.h"
34#endif
35
36#include "wx/graphics.h"
37
7ba86d93
RD
38#if wxUSE_GRAPHICS_CONTEXT
39
6fea499c
SC
40#include <vector>
41
42using namespace std;
43
44//-----------------------------------------------------------------------------
45// constants
46//-----------------------------------------------------------------------------
47
48const double RAD2DEG = 180.0 / M_PI;
49
50//-----------------------------------------------------------------------------
51// Local functions
52//-----------------------------------------------------------------------------
53
54static inline double dmin(double a, double b) { return a < b ? a : b; }
55static inline double dmax(double a, double b) { return a > b ? a : b; }
56
57static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
58static inline double RadToDeg(double deg) { return (deg * 180.0) / M_PI; }
59
60//-----------------------------------------------------------------------------
61// device context implementation
62//
63// more and more of the dc functionality should be implemented by calling
64// the appropricate wxGDIPlusContext, but we will have to do that step by step
65// also coordinate conversions should be moved to native matrix ops
66//-----------------------------------------------------------------------------
67
68// we always stock two context states, one at entry, to be able to preserve the
69// state we were called with, the other one after changing to HI Graphics orientation
70// (this one is used for getting back clippings etc)
71
72//-----------------------------------------------------------------------------
73// wxGraphicsPath implementation
74//-----------------------------------------------------------------------------
75
76#include "wx/msw/private.h" // needs to be before #include <commdlg.h>
77
78#if wxUSE_COMMON_DIALOGS && !defined(__WXMICROWIN__)
79#include <commdlg.h>
80#endif
81
82// TODO remove this dependency (gdiplus needs the macros)
83
84#ifndef max
85#define max(a,b) (((a) > (b)) ? (a) : (b))
86#endif
87
88#ifndef min
89#define min(a,b) (((a) < (b)) ? (a) : (b))
90#endif
91
92#include "gdiplus.h"
93using namespace Gdiplus;
94
a4e73390 95class WXDLLIMPEXP_CORE wxGDIPlusPathData : public wxGraphicsPathData
6fea499c 96{
6fea499c 97public :
a4e73390
SC
98 wxGDIPlusPathData(wxGraphicsRenderer* renderer, GraphicsPath* path = NULL);
99 ~wxGDIPlusPathData();
6fea499c 100
a4e73390 101 virtual wxGraphicsObjectRefData *Clone() const;
6fea499c
SC
102
103 //
104 // These are the path primitives from which everything else can be constructed
105 //
106
107 // begins a new subpath at (x,y)
108 virtual void MoveToPoint( wxDouble x, wxDouble y );
109
110 // adds a straight line from the current point to (x,y)
111 virtual void AddLineToPoint( wxDouble x, wxDouble y );
112
113 // adds a cubic Bezier curve from the current point, using two control points and an end point
114 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
115
116
117 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
118 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ;
119
120 // gets the last point of the current path, (0,0) if not yet set
a4e73390 121 virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const;
6fea499c 122
83576e68 123 // adds another path
a4e73390 124 virtual void AddPath( const wxGraphicsPathData* path );
83576e68 125
6fea499c
SC
126 // closes the current sub-path
127 virtual void CloseSubpath();
128
129 //
130 // These are convenience functions which - if not available natively will be assembled
131 // using the primitives from above
132 //
133
134 // appends a rectangle as a new closed subpath
135 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
136 /*
137
138 // appends an ellipsis as a new closed subpath fitting the passed rectangle
139 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
140
141 // 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)
142 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
143*/
144
f540e5bd
SC
145 // returns the native path
146 virtual void * GetNativePath() const { return m_path; }
147
148 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
a4e73390 149 virtual void UnGetNativePath(void * WXUNUSED(path)) const {}
f540e5bd 150
83576e68 151 // transforms each point of this path by the matrix
a4e73390 152 virtual void Transform( const wxGraphicsMatrixData* matrix ) ;
83576e68
SC
153
154 // gets the bounding box enclosing all points (possibly including control points)
a4e73390 155 virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const;
83576e68 156
a4e73390 157 virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxODDEVEN_RULE) const;
83576e68 158
6fea499c
SC
159private :
160 GraphicsPath* m_path;
161};
162
a4e73390 163class WXDLLIMPEXP_CORE wxGDIPlusMatrixData : public wxGraphicsMatrixData
83576e68
SC
164{
165public :
a4e73390
SC
166 wxGDIPlusMatrixData(wxGraphicsRenderer* renderer, Matrix* matrix = NULL) ;
167 virtual ~wxGDIPlusMatrixData() ;
83576e68 168
a4e73390 169 virtual wxGraphicsObjectRefData* Clone() const ;
83576e68
SC
170
171 // concatenates the matrix
a4e73390 172 virtual void Concat( const wxGraphicsMatrixData *t );
83576e68
SC
173
174 // sets the matrix to the respective values
175 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
176 wxDouble tx=0.0, wxDouble ty=0.0);
177
178 // makes this the inverse matrix
179 virtual void Invert();
180
181 // returns true if the elements of the transformation matrix are equal ?
a4e73390 182 virtual bool IsEqual( const wxGraphicsMatrixData* t) const ;
83576e68
SC
183
184 // return true if this is the identity matrix
a4e73390 185 virtual bool IsIdentity() const;
83576e68
SC
186
187 //
188 // transformation
189 //
190
191 // add the translation to this matrix
192 virtual void Translate( wxDouble dx , wxDouble dy );
193
194 // add the scale to this matrix
195 virtual void Scale( wxDouble xScale , wxDouble yScale );
196
197 // add the rotation to this matrix (radians)
198 virtual void Rotate( wxDouble angle );
199
200 //
201 // apply the transforms
202 //
203
204 // applies that matrix to the point
a4e73390 205 virtual void TransformPoint( wxDouble *x, wxDouble *y ) const;
83576e68
SC
206
207 // applies the matrix except for translations
a4e73390 208 virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const;
83576e68
SC
209
210 // returns the native representation
211 virtual void * GetNativeMatrix() const;
212private:
213 Matrix* m_matrix ;
83576e68
SC
214} ;
215
2c820406 216class WXDLLIMPEXP_CORE wxGDIPlusPenData : public wxGraphicsObjectRefData
83576e68
SC
217{
218public:
2c820406
SC
219 wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &pen );
220 ~wxGDIPlusPenData();
83576e68
SC
221
222 void Init();
223
83576e68
SC
224 virtual wxDouble GetWidth() { return m_width; }
225 virtual Pen* GetGDIPlusPen() { return m_pen; }
226
227protected :
228 Pen* m_pen;
229 Image* m_penImage;
230 Brush* m_penBrush;
231
232 wxDouble m_width;
83576e68
SC
233};
234
2c820406 235class WXDLLIMPEXP_CORE wxGDIPlusBrushData : public wxGraphicsObjectRefData
83576e68
SC
236{
237public:
2c820406
SC
238 wxGDIPlusBrushData( wxGraphicsRenderer* renderer );
239 wxGDIPlusBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush );
240 ~wxGDIPlusBrushData ();
83576e68 241
83576e68
SC
242 void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
243 const wxColour&c1, const wxColour&c2 );
244 void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
245 const wxColour &oColor, const wxColour &cColor );
246 virtual Brush* GetGDIPlusBrush() { return m_brush; }
247
248protected:
249 virtual void Init();
250
251private :
252 Brush* m_brush;
253 Image* m_brushImage;
254 GraphicsPath* m_brushPath;
83576e68
SC
255};
256
2c820406 257class WXDLLIMPEXP_CORE wxGDIPlusFontData : public wxGraphicsObjectRefData
83576e68
SC
258{
259public:
2c820406
SC
260 wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col );
261 ~wxGDIPlusFontData();
83576e68 262
83576e68
SC
263 virtual Brush* GetGDIPlusBrush() { return m_textBrush; }
264 virtual Font* GetGDIPlusFont() { return m_font; }
265private :
266 Brush* m_textBrush;
267 Font* m_font;
83576e68
SC
268};
269
270class WXDLLIMPEXP_CORE wxGDIPlusContext : public wxGraphicsContext
6fea499c 271{
6fea499c 272public:
83576e68
SC
273 wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc );
274 wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd );
275 wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr);
6fea499c 276 wxGDIPlusContext();
9f339b18 277
6fea499c
SC
278 virtual ~wxGDIPlusContext();
279
280 virtual void Clip( const wxRegion &region );
539e2795
SC
281 // clips drawings to the rect
282 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
283
284 // resets the clipping to original extent
285 virtual void ResetClip();
286
287 virtual void * GetNativeContext();
288
a4e73390
SC
289 virtual void StrokePath( const wxGraphicsPath& p );
290 virtual void FillPath( const wxGraphicsPath& p , int fillStyle = wxODDEVEN_RULE );
6fea499c 291
6fea499c
SC
292 virtual void Translate( wxDouble dx , wxDouble dy );
293 virtual void Scale( wxDouble xScale , wxDouble yScale );
294 virtual void Rotate( wxDouble angle );
295
83576e68 296 // concatenates this transform with the current transform of this context
a4e73390 297 virtual void ConcatTransform( const wxGraphicsMatrix& matrix );
83576e68
SC
298
299 // sets the transform of this context
a4e73390 300 virtual void SetTransform( const wxGraphicsMatrix& matrix );
83576e68
SC
301
302 // gets the matrix of this context
a4e73390 303 virtual wxGraphicsMatrix GetTransform() const;
83576e68 304
6fea499c
SC
305 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
306 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
307 virtual void PushState();
308 virtual void PopState();
309
6fea499c
SC
310 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y);
311 virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
312 wxDouble *descent, wxDouble *externalLeading ) const;
313 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
314
315private:
9f339b18
SC
316 void Init();
317 void SetDefaults();
318
83576e68
SC
319 Graphics* m_context;
320 vector<GraphicsState> m_stateStack;
321 GraphicsState m_state1;
322 GraphicsState m_state2;
323
324 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext)
325};
326
327//-----------------------------------------------------------------------------
328// wxGDIPlusPen implementation
329//-----------------------------------------------------------------------------
330
2c820406 331wxGDIPlusPenData::~wxGDIPlusPenData()
83576e68
SC
332{
333 delete m_pen;
334 delete m_penImage;
335 delete m_penBrush;
336}
337
2c820406 338void wxGDIPlusPenData::Init()
83576e68
SC
339{
340 m_pen = NULL ;
341 m_penImage = NULL;
342 m_penBrush = NULL;
343}
344
2c820406
SC
345wxGDIPlusPenData::wxGDIPlusPenData( wxGraphicsRenderer* renderer, const wxPen &pen )
346: wxGraphicsObjectRefData(renderer)
83576e68
SC
347{
348 Init();
349 m_width = pen.GetWidth();
350 if (m_width <= 0.0)
351 m_width = 0.1;
352
353 m_pen = new Pen(Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
354 pen.GetColour().Green() , pen.GetColour().Blue() ), m_width );
355
356 LineCap cap;
357 switch ( pen.GetCap() )
358 {
359 case wxCAP_ROUND :
360 cap = LineCapRound;
361 break;
362
363 case wxCAP_PROJECTING :
364 cap = LineCapSquare;
365 break;
366
367 case wxCAP_BUTT :
368 cap = LineCapFlat; // TODO verify
369 break;
370
371 default :
372 cap = LineCapFlat;
373 break;
374 }
375 m_pen->SetLineCap(cap,cap, DashCapFlat);
376
377 LineJoin join;
378 switch ( pen.GetJoin() )
379 {
380 case wxJOIN_BEVEL :
381 join = LineJoinBevel;
382 break;
383
384 case wxJOIN_MITER :
385 join = LineJoinMiter;
386 break;
387
388 case wxJOIN_ROUND :
389 join = LineJoinRound;
390 break;
391
392 default :
393 join = LineJoinMiter;
394 break;
395 }
396
397 m_pen->SetLineJoin(join);
398
399 m_pen->SetDashStyle(DashStyleSolid);
400
401 DashStyle dashStyle = DashStyleSolid;
402 switch ( pen.GetStyle() )
403 {
404 case wxSOLID :
405 break;
406
407 case wxDOT :
408 dashStyle = DashStyleDot;
409 break;
410
411 case wxLONG_DASH :
412 dashStyle = DashStyleDash; // TODO verify
413 break;
414
415 case wxSHORT_DASH :
416 dashStyle = DashStyleDash;
417 break;
418
419 case wxDOT_DASH :
420 dashStyle = DashStyleDashDot;
421 break;
422 case wxUSER_DASH :
423 {
424 dashStyle = DashStyleCustom;
425 wxDash *dashes;
426 int count = pen.GetDashes( &dashes );
427 if ((dashes != NULL) && (count > 0))
428 {
429 REAL *userLengths = new REAL[count];
430 for ( int i = 0; i < count; ++i )
431 {
432 userLengths[i] = dashes[i];
433 }
434 m_pen->SetDashPattern( userLengths, count);
435 delete[] userLengths;
436 }
437 }
438 break;
439 case wxSTIPPLE :
440 {
441 wxBitmap* bmp = pen.GetStipple();
442 if ( bmp && bmp->Ok() )
443 {
444 m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
445 m_penBrush = new TextureBrush(m_penImage);
446 m_pen->SetBrush( m_penBrush );
447 }
448
449 }
450 break;
451 default :
452 if ( pen.GetStyle() >= wxFIRST_HATCH && pen.GetStyle() <= wxLAST_HATCH )
453 {
454 HatchStyle style = HatchStyleHorizontal;
455 switch( pen.GetStyle() )
456 {
457 case wxBDIAGONAL_HATCH :
458 style = HatchStyleBackwardDiagonal;
459 break ;
460 case wxCROSSDIAG_HATCH :
461 style = HatchStyleDiagonalCross;
462 break ;
463 case wxFDIAGONAL_HATCH :
464 style = HatchStyleForwardDiagonal;
465 break ;
466 case wxCROSS_HATCH :
467 style = HatchStyleCross;
468 break ;
469 case wxHORIZONTAL_HATCH :
470 style = HatchStyleHorizontal;
471 break ;
472 case wxVERTICAL_HATCH :
473 style = HatchStyleVertical;
474 break ;
475
476 }
477 m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
478 pen.GetColour().Green() , pen.GetColour().Blue() ), Color::Transparent );
479 m_pen->SetBrush( m_penBrush );
480 }
481 break;
482 }
483 if ( dashStyle != DashStyleSolid )
484 m_pen->SetDashStyle(dashStyle);
485}
486
83576e68
SC
487//-----------------------------------------------------------------------------
488// wxGDIPlusBrush implementation
489//-----------------------------------------------------------------------------
490
2c820406
SC
491wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer )
492: wxGraphicsObjectRefData(renderer)
83576e68
SC
493{
494 Init();
495}
496
2c820406
SC
497wxGDIPlusBrushData::wxGDIPlusBrushData( wxGraphicsRenderer* renderer , const wxBrush &brush )
498: wxGraphicsObjectRefData(renderer)
83576e68
SC
499{
500 Init();
501 if ( brush.GetStyle() == wxSOLID)
502 {
503 m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
504 brush.GetColour().Green() , brush.GetColour().Blue() ) );
505 }
506 else if ( brush.IsHatch() )
507 {
508 HatchStyle style = HatchStyleHorizontal;
509 switch( brush.GetStyle() )
510 {
511 case wxBDIAGONAL_HATCH :
512 style = HatchStyleBackwardDiagonal;
513 break ;
514 case wxCROSSDIAG_HATCH :
515 style = HatchStyleDiagonalCross;
516 break ;
517 case wxFDIAGONAL_HATCH :
518 style = HatchStyleForwardDiagonal;
519 break ;
520 case wxCROSS_HATCH :
521 style = HatchStyleCross;
522 break ;
523 case wxHORIZONTAL_HATCH :
524 style = HatchStyleHorizontal;
525 break ;
526 case wxVERTICAL_HATCH :
527 style = HatchStyleVertical;
528 break ;
529
530 }
531 m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
532 brush.GetColour().Green() , brush.GetColour().Blue() ), Color::Transparent );
533 }
534 else
535 {
536 wxBitmap* bmp = brush.GetStipple();
537 if ( bmp && bmp->Ok() )
538 {
539 wxDELETE( m_brushImage );
540 m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
541 m_brush = new TextureBrush(m_brushImage);
542 }
543 }
544}
545
2c820406 546wxGDIPlusBrushData::~wxGDIPlusBrushData()
83576e68
SC
547{
548 delete m_brush;
549 delete m_brushImage;
550 delete m_brushPath;
551};
552
2c820406 553void wxGDIPlusBrushData::Init()
83576e68
SC
554{
555 m_brush = NULL;
556 m_brushImage= NULL;
557 m_brushPath= NULL;
558}
559
2c820406 560void wxGDIPlusBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2)
83576e68
SC
561{
562 m_brush = new LinearGradientBrush( PointF( x1,y1) , PointF( x2,y2),
563 Color( c1.Alpha(), c1.Red(),c1.Green() , c1.Blue() ),
564 Color( c2.Alpha(), c2.Red(),c2.Green() , c2.Blue() ));
565}
566
2c820406 567void wxGDIPlusBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
83576e68
SC
568 const wxColour &oColor, const wxColour &cColor)
569{
570 // Create a path that consists of a single circle.
571 m_brushPath = new GraphicsPath();
572 m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius), (REAL)(2*radius), (REAL)(2*radius));
573
574 PathGradientBrush *b = new PathGradientBrush(m_brushPath);
575 m_brush = b;
576 b->SetCenterPoint( PointF(xo,yo));
577 b->SetCenterColor(Color( oColor.Alpha(), oColor.Red(),oColor.Green() , oColor.Blue() ));
578
579 Color colors[] = {Color( cColor.Alpha(), cColor.Red(),cColor.Green() , cColor.Blue() )};
580 int count = 1;
581 b->SetSurroundColors(colors, &count);
582}
583
83576e68
SC
584//-----------------------------------------------------------------------------
585// wxGDIPlusFont implementation
586//-----------------------------------------------------------------------------
587
2c820406
SC
588wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont &font,
589 const wxColour& col ) : wxGraphicsObjectRefData( renderer )
83576e68
SC
590{
591 m_textBrush = NULL;
592 m_font = NULL;
593
594 wxWCharBuffer s = font.GetFaceName().wc_str( *wxConvUI );
595 int size = font.GetPointSize();
596 int style = FontStyleRegular;
597 if ( font.GetStyle() == wxFONTSTYLE_ITALIC )
598 style |= FontStyleItalic;
599 if ( font.GetUnderlined() )
600 style |= FontStyleUnderline;
601 if ( font.GetWeight() == wxFONTWEIGHT_BOLD )
602 style |= FontStyleBold;
603 m_font = new Font( s , size , style );
604 m_textBrush = new SolidBrush( Color( col.Alpha() , col.Red() ,
605 col.Green() , col.Blue() ));
606}
6fea499c 607
2c820406 608wxGDIPlusFontData::~wxGDIPlusFontData()
83576e68
SC
609{
610 delete m_textBrush;
611 delete m_font;
612}
6fea499c 613
83576e68
SC
614//-----------------------------------------------------------------------------
615// wxGDIPlusPath implementation
616//-----------------------------------------------------------------------------
6fea499c 617
a4e73390 618wxGDIPlusPathData::wxGDIPlusPathData(wxGraphicsRenderer* renderer, GraphicsPath* path ) : wxGraphicsPathData(renderer)
83576e68
SC
619{
620 if ( path )
621 m_path = path;
622 else
623 m_path = new GraphicsPath();
624}
625
a4e73390 626wxGDIPlusPathData::~wxGDIPlusPathData()
6fea499c
SC
627{
628 delete m_path;
629}
630
a4e73390 631wxGraphicsObjectRefData* wxGDIPlusPathData::Clone() const
83576e68 632{
a4e73390 633 return new wxGDIPlusPathData( GetRenderer() , m_path->Clone());
83576e68
SC
634}
635
6fea499c
SC
636//
637// The Primitives
638//
639
a4e73390 640void wxGDIPlusPathData::MoveToPoint( wxDouble x , wxDouble y )
6fea499c
SC
641{
642 m_path->StartFigure();
643 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
644}
645
a4e73390 646void wxGDIPlusPathData::AddLineToPoint( wxDouble x , wxDouble y )
6fea499c
SC
647{
648 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
649}
650
a4e73390 651void wxGDIPlusPathData::CloseSubpath()
6fea499c
SC
652{
653 m_path->CloseFigure();
654}
655
a4e73390 656void wxGDIPlusPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
6fea499c
SC
657{
658 PointF c1(cx1,cy1);
659 PointF c2(cx2,cy2);
660 PointF end(x,y);
661 PointF start;
662 m_path->GetLastPoint(&start);
663 m_path->AddBezier(start,c1,c2,end);
664}
665
666// gets the last point of the current path, (0,0) if not yet set
a4e73390 667void wxGDIPlusPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const
6fea499c
SC
668{
669 PointF start;
670 m_path->GetLastPoint(&start);
a4e73390
SC
671 *x = start.X ;
672 *y = start.Y ;
6fea499c
SC
673}
674
a4e73390 675void wxGDIPlusPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise )
6fea499c
SC
676{
677 double sweepAngle = endAngle - startAngle ;
678 if( abs(sweepAngle) >= 2*M_PI)
679 {
680 sweepAngle = 2 * M_PI;
681 }
682 else
683 {
684 if ( clockwise )
685 {
686 if( sweepAngle < 0 )
687 sweepAngle += 2 * M_PI;
688 }
689 else
690 {
691 if( sweepAngle > 0 )
692 sweepAngle -= 2 * M_PI;
693
694 }
695 }
696 m_path->AddArc((REAL) (x-r),(REAL) (y-r),(REAL) (2*r),(REAL) (2*r),RadToDeg(startAngle),RadToDeg(sweepAngle));
697}
698
a4e73390 699void wxGDIPlusPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
6fea499c
SC
700{
701 m_path->AddRectangle(RectF(x,y,w,h));
702}
703
a4e73390 704void wxGDIPlusPathData::AddPath( const wxGraphicsPathData* path )
6fea499c 705{
83576e68 706 m_path->AddPath( (GraphicsPath*) path->GetNativePath(), FALSE);
6fea499c
SC
707}
708
6fea499c 709
83576e68 710// transforms each point of this path by the matrix
a4e73390 711void wxGDIPlusPathData::Transform( const wxGraphicsMatrixData* matrix )
9f339b18 712{
83576e68 713 m_path->Transform( (Matrix*) matrix->GetNativeMatrix() );
9f339b18 714}
6fea499c 715
83576e68 716// gets the bounding box enclosing all points (possibly including control points)
a4e73390 717void wxGDIPlusPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const
e49c065d 718{
83576e68
SC
719 RectF bounds;
720 m_path->GetBounds( &bounds, NULL, NULL) ;
721 *x = bounds.X;
722 *y = bounds.Y;
723 *w = bounds.Width;
724 *h = bounds.Height;
e49c065d
RD
725}
726
a4e73390 727bool wxGDIPlusPathData::Contains( wxDouble x, wxDouble y, int fillStyle ) const
6fea499c 728{
83576e68
SC
729 m_path->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
730 return m_path->IsVisible( (FLOAT) x,(FLOAT) y) == TRUE ;
731}
9f339b18 732
83576e68 733//-----------------------------------------------------------------------------
a4e73390 734// wxGDIPlusMatrixData implementation
83576e68 735//-----------------------------------------------------------------------------
9f339b18 736
a4e73390
SC
737wxGDIPlusMatrixData::wxGDIPlusMatrixData(wxGraphicsRenderer* renderer, Matrix* matrix )
738 : wxGraphicsMatrixData(renderer)
9f339b18 739{
83576e68
SC
740 if ( matrix )
741 m_matrix = matrix ;
742 else
743 m_matrix = new Matrix();
6fea499c
SC
744}
745
a4e73390 746wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
6fea499c 747{
83576e68 748 delete m_matrix;
6fea499c
SC
749}
750
a4e73390 751wxGraphicsObjectRefData *wxGDIPlusMatrixData::Clone() const
6fea499c 752{
a4e73390 753 return new wxGDIPlusMatrixData( GetRenderer(), m_matrix->Clone());
539e2795
SC
754}
755
83576e68 756// concatenates the matrix
a4e73390 757void wxGDIPlusMatrixData::Concat( const wxGraphicsMatrixData *t )
539e2795 758{
83576e68 759 m_matrix->Multiply( (Matrix*) t->GetNativeMatrix());
539e2795 760}
83576e68 761
83576e68 762// sets the matrix to the respective values
a4e73390 763void wxGDIPlusMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
83576e68 764 wxDouble tx, wxDouble ty)
6fea499c 765{
83576e68 766 m_matrix->SetElements(a,b,c,d,tx,ty);
6fea499c
SC
767}
768
83576e68 769// makes this the inverse matrix
a4e73390 770void wxGDIPlusMatrixData::Invert()
6fea499c 771{
83576e68 772 m_matrix->Invert();
6fea499c
SC
773}
774
83576e68 775// returns true if the elements of the transformation matrix are equal ?
a4e73390 776bool wxGDIPlusMatrixData::IsEqual( const wxGraphicsMatrixData* t) const
6fea499c 777{
83576e68 778 return m_matrix->Equals((Matrix*) t->GetNativeMatrix())== TRUE ;
6fea499c
SC
779}
780
83576e68 781// return true if this is the identity matrix
a4e73390 782bool wxGDIPlusMatrixData::IsIdentity() const
6fea499c 783{
83576e68 784 return m_matrix->IsIdentity() == TRUE ;
6fea499c
SC
785}
786
83576e68
SC
787//
788// transformation
789//
790
791// add the translation to this matrix
a4e73390 792void wxGDIPlusMatrixData::Translate( wxDouble dx , wxDouble dy )
6fea499c 793{
83576e68 794 m_matrix->Translate(dx,dy);
6fea499c
SC
795}
796
83576e68 797// add the scale to this matrix
a4e73390 798void wxGDIPlusMatrixData::Scale( wxDouble xScale , wxDouble yScale )
6fea499c 799{
83576e68 800 m_matrix->Scale(xScale,yScale);
6fea499c
SC
801}
802
83576e68 803// add the rotation to this matrix (radians)
a4e73390 804void wxGDIPlusMatrixData::Rotate( wxDouble angle )
6fea499c 805{
83576e68 806 m_matrix->Rotate( angle );
6fea499c
SC
807}
808
83576e68
SC
809//
810// apply the transforms
811//
812
813// applies that matrix to the point
a4e73390 814void wxGDIPlusMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const
6fea499c 815{
83576e68
SC
816 PointF pt(*x,*y);
817 m_matrix->TransformPoints(&pt);
818 *x = pt.X;
819 *y = pt.Y;
6fea499c
SC
820}
821
83576e68 822// applies the matrix except for translations
a4e73390 823void wxGDIPlusMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const
6fea499c 824{
83576e68
SC
825 PointF pt(*dx,*dy);
826 m_matrix->TransformVectors(&pt);
827 *dx = pt.X;
828 *dy = pt.Y;
6fea499c
SC
829}
830
83576e68 831// returns the native representation
a4e73390 832void * wxGDIPlusMatrixData::GetNativeMatrix() const
6fea499c 833{
83576e68
SC
834 return m_matrix;
835}
6fea499c 836
83576e68
SC
837//-----------------------------------------------------------------------------
838// wxGDIPlusContext implementation
839//-----------------------------------------------------------------------------
840
841IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext,wxGraphicsContext)
842
843wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc )
844 : wxGraphicsContext(renderer)
845{
846 Init();
847 m_context = new Graphics( hdc);
848 SetDefaults();
6fea499c
SC
849}
850
83576e68
SC
851wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd )
852 : wxGraphicsContext(renderer)
6fea499c 853{
83576e68
SC
854 Init();
855 m_context = new Graphics( hwnd);
856 SetDefaults();
857}
6fea499c 858
83576e68
SC
859wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr )
860 : wxGraphicsContext(renderer)
861{
862 Init();
863 m_context = gr;
864 SetDefaults();
865}
6fea499c 866
83576e68
SC
867wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL)
868{
869 Init();
870}
6fea499c 871
83576e68
SC
872void wxGDIPlusContext::Init()
873{
874 m_context = NULL;
875 m_state1 = 0;
876 m_state2= 0;
877}
6fea499c 878
83576e68
SC
879void wxGDIPlusContext::SetDefaults()
880{
881 m_context->SetSmoothingMode(SmoothingModeHighQuality);
882 m_state1 = m_context->Save();
883 m_state2 = m_context->Save();
884}
6fea499c 885
83576e68
SC
886wxGDIPlusContext::~wxGDIPlusContext()
887{
83576e68 888 if ( m_context )
6fea499c 889 {
83576e68
SC
890 m_context->Restore( m_state2 );
891 m_context->Restore( m_state1 );
892 delete m_context;
6fea499c
SC
893 }
894}
895
83576e68
SC
896
897void wxGDIPlusContext::Clip( const wxRegion &region )
6fea499c 898{
83576e68
SC
899 m_context->SetClip((HRGN)region.GetHRGN(),CombineModeIntersect);
900}
6fea499c 901
83576e68
SC
902void wxGDIPlusContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
903{
904 m_context->SetClip(RectF(x,y,w,h),CombineModeIntersect);
905}
906
907void wxGDIPlusContext::ResetClip()
908{
909 m_context->ResetClip();
910}
6fea499c 911
a4e73390 912void wxGDIPlusContext::StrokePath( const wxGraphicsPath& path )
83576e68 913{
2c820406 914 if ( !m_pen.IsNull() )
83576e68 915 {
a4e73390 916 m_context->DrawPath( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath*) path.GetNativePath() );
83576e68 917 }
6fea499c
SC
918}
919
a4e73390 920void wxGDIPlusContext::FillPath( const wxGraphicsPath& path , int fillStyle )
6fea499c 921{
2c820406 922 if ( !m_brush.IsNull() )
83576e68 923 {
a4e73390 924 ((GraphicsPath*) path.GetNativePath())->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
2c820406 925 m_context->FillPath( ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush() ,
a4e73390 926 (GraphicsPath*) path.GetNativePath());
83576e68
SC
927 }
928}
6fea499c 929
83576e68
SC
930void wxGDIPlusContext::Rotate( wxDouble angle )
931{
932 m_context->RotateTransform( RadToDeg(angle) );
933}
6fea499c 934
83576e68
SC
935void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy )
936{
937 m_context->TranslateTransform( dx , dy );
938}
6fea499c 939
83576e68
SC
940void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale )
941{
942 m_context->ScaleTransform(xScale,yScale);
943}
6fea499c 944
83576e68
SC
945void wxGDIPlusContext::PushState()
946{
947 GraphicsState state = m_context->Save();
948 m_stateStack.push_back(state);
949}
950
951void wxGDIPlusContext::PopState()
952{
953 GraphicsState state = m_stateStack.back();
954 m_stateStack.pop_back();
955 m_context->Restore(state);
6fea499c
SC
956}
957
fe31db81
SC
958// the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
959// premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
960// bytes as parameter
961
6fea499c
SC
962void wxGDIPlusContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
963{
fe31db81
SC
964 Bitmap* image = NULL;
965 Bitmap* helper = NULL;
966 if ( bmp.GetMask() )
967 {
968 Bitmap interim((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE()) ;
969
970 size_t width = interim.GetWidth();
971 size_t height = interim.GetHeight();
972 Rect bounds(0,0,width,height);
973
974 image = new Bitmap(width,height,PixelFormat32bppPARGB) ;
975
976 Bitmap interimMask((HBITMAP)bmp.GetMask()->GetMaskBitmap(),NULL);
977 wxASSERT(interimMask.GetPixelFormat() == PixelFormat1bppIndexed);
978
979 BitmapData dataMask ;
980 interimMask.LockBits(&bounds,ImageLockModeRead,
981 interimMask.GetPixelFormat(),&dataMask);
982
983
984 BitmapData imageData ;
985 image->LockBits(&bounds,ImageLockModeWrite, PixelFormat32bppPARGB, &imageData);
986
987 BYTE maskPattern = 0 ;
988 BYTE maskByte = 0;
989 size_t maskIndex ;
990
991 for ( size_t y = 0 ; y < height ; ++y)
992 {
993 maskIndex = 0 ;
994 for( size_t x = 0 ; x < width; ++x)
995 {
996 if ( x % 8 == 0)
997 {
998 maskPattern = 0x80;
999 maskByte = *((BYTE*)dataMask.Scan0 + dataMask.Stride*y + maskIndex);
1000 maskIndex++;
1001 }
1002 else
1003 maskPattern = maskPattern >> 1;
1004
1005 ARGB *dest = (ARGB*)((BYTE*)imageData.Scan0 + imageData.Stride*y + x*4);
1006 if ( (maskByte & maskPattern) == 0 )
1007 *dest = 0x00000000;
1008 else
1009 {
1010 Color c ;
1011 interim.GetPixel(x,y,&c) ;
1012 *dest = (c.GetValue() | Color::AlphaMask);
1013 }
1014 }
1015 }
1016
1017 image->UnlockBits(&imageData);
1018
1019 interimMask.UnlockBits(&dataMask);
1020 interim.UnlockBits(&dataMask);
1021 }
1022 else
1023 {
1024 image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE());
1025 if ( GetPixelFormatSize(image->GetPixelFormat()) == 32 )
1026 {
1027 size_t width = image->GetWidth();
1028 size_t height = image->GetHeight();
1029 Rect bounds(0,0,width,height);
1030 BitmapData data ;
1031
1032 helper = image ;
1033 image = NULL ;
1034 helper->LockBits(&bounds, ImageLockModeRead,
1035 helper->GetPixelFormat(),&data);
1036
1037 image = new Bitmap(data.Width, data.Height, data.Stride,
1038 PixelFormat32bppARGB , (BYTE*) data.Scan0);
1039
1040 helper->UnlockBits(&data);
1041 }
1042 }
1043 if ( image )
1044 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
6fea499c 1045 delete image ;
fe31db81 1046 delete helper ;
6fea499c
SC
1047}
1048
1049void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1050{
fe31db81
SC
1051 HICON hIcon = (HICON)icon.GetHICON();
1052 ICONINFO iconInfo ;
1053 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1054 if (!GetIconInfo(hIcon,&iconInfo))
1055 return;
1056
1057 BITMAP iconBmpData ;
1058 GetObject(iconInfo.hbmColor,sizeof(BITMAP),&iconBmpData);
1059 Bitmap interim(iconInfo.hbmColor,NULL);
1060
1061 Bitmap* image = NULL ;
1062
1063 if( GetPixelFormatSize(interim.GetPixelFormat())!= 32 )
1064 {
1065 image = Bitmap::FromHICON(hIcon);
1066 }
1067 else
1068 {
1069 size_t width = interim.GetWidth();
1070 size_t height = interim.GetHeight();
1071 Rect bounds(0,0,width,height);
1072 BitmapData data ;
1073
1074 interim.LockBits(&bounds, ImageLockModeRead,
1075 interim.GetPixelFormat(),&data);
1076 image = new Bitmap(data.Width, data.Height, data.Stride,
1077 PixelFormat32bppARGB , (BYTE*) data.Scan0);
1078 interim.UnlockBits(&data);
1079 }
1080
6fea499c 1081 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
fe31db81 1082
6fea499c 1083 delete image ;
fe31db81
SC
1084 DeleteObject(iconInfo.hbmColor);
1085 DeleteObject(iconInfo.hbmMask);
6fea499c
SC
1086}
1087
6fea499c
SC
1088void wxGDIPlusContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
1089{
2c820406 1090 if ( m_font.IsNull() || str.IsEmpty())
6fea499c
SC
1091 return ;
1092
1093 wxWCharBuffer s = str.wc_str( *wxConvUI );
2c820406
SC
1094 m_context->DrawString( s , -1 , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont() ,
1095 PointF( x , y ) , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusBrush() );
6fea499c
SC
1096 // TODO m_backgroundMode == wxSOLID
1097}
1098
1099void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1100 wxDouble *descent, wxDouble *externalLeading ) const
1101{
1102 wxWCharBuffer s = str.wc_str( *wxConvUI );
1103 FontFamily ffamily ;
2c820406 1104 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
6fea499c 1105
83576e68 1106 f->GetFamily(&ffamily) ;
6fea499c
SC
1107
1108 REAL factorY = m_context->GetDpiY() / 72.0 ;
1109
1110 REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
83576e68 1111 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c 1112 REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
83576e68 1113 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c 1114 REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
83576e68 1115 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c
SC
1116
1117 if ( height )
1118 *height = rHeight * factorY + 0.5 ;
1119 if ( descent )
1120 *descent = rDescent * factorY + 0.5 ;
1121 if ( externalLeading )
1122 *externalLeading = (rHeight - rAscent - rDescent) * factorY + 0.5 ;
1123 // measuring empty strings is not guaranteed, so do it by hand
1124 if ( str.IsEmpty())
1125 {
1126 if ( width )
1127 *width = 0 ;
1128 }
1129 else
1130 {
1131 // MeasureString does return a rectangle that is way too large, so it is
1132 // not usable here
1133 RectF layoutRect(0,0, 100000.0f, 100000.0f);
1134 StringFormat strFormat;
1135 CharacterRange strRange(0,wcslen(s));
1136 strFormat.SetMeasurableCharacterRanges(1,&strRange);
1137 Region region ;
83576e68 1138 m_context->MeasureCharacterRanges(s, -1 , f,layoutRect, &strFormat,1,&region) ;
6fea499c
SC
1139 RectF bbox ;
1140 region.GetBounds(&bbox,m_context);
1141 if ( width )
1142 *width = bbox.GetRight()-bbox.GetLeft()+0.5;
1143 }
1144}
1145
1146void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
1147{
1148 widths.Empty();
1149 widths.Add(0, text.length());
1150
1151 if (text.empty())
1152 return;
1153
2c820406 1154 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
6fea499c
SC
1155 wxWCharBuffer ws = text.wc_str( *wxConvUI );
1156 size_t len = wcslen( ws ) ;
1157 wxASSERT_MSG(text.length() == len , wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1158
1159 RectF layoutRect(0,0, 100000.0f, 100000.0f);
1160 StringFormat strFormat;
1161
1162 CharacterRange* ranges = new CharacterRange[len] ;
1163 Region* regions = new Region[len];
1164 for( size_t i = 0 ; i < len ; ++i)
1165 {
1166 ranges[i].First = i ;
1167 ranges[i].Length = 1 ;
1168 }
1169 strFormat.SetMeasurableCharacterRanges(len,ranges);
83576e68 1170 m_context->MeasureCharacterRanges(ws, -1 , f,layoutRect, &strFormat,1,regions) ;
6fea499c
SC
1171
1172 RectF bbox ;
1173 for ( size_t i = 0 ; i < len ; ++i)
1174 {
1175 regions[i].GetBounds(&bbox,m_context);
1176 widths[i] = bbox.GetRight()-bbox.GetLeft();
1177 }
1178}
1179
83576e68 1180void* wxGDIPlusContext::GetNativeContext()
6fea499c 1181{
83576e68 1182 return m_context;
6fea499c
SC
1183}
1184
83576e68 1185// concatenates this transform with the current transform of this context
a4e73390 1186void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix& matrix )
539e2795 1187{
a4e73390 1188 m_context->MultiplyTransform((Matrix*) matrix.GetNativeMatrix());
83576e68
SC
1189}
1190
1191// sets the transform of this context
a4e73390 1192void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix& matrix )
83576e68 1193{
a4e73390 1194 m_context->SetTransform((Matrix*) matrix.GetNativeMatrix());
83576e68
SC
1195}
1196
1197// gets the matrix of this context
a4e73390 1198wxGraphicsMatrix wxGDIPlusContext::GetTransform() const
83576e68 1199{
a4e73390
SC
1200 wxGraphicsMatrix matrix = CreateMatrix();
1201 m_context->GetTransform((Matrix*) matrix.GetNativeMatrix());
1202 return matrix;
83576e68
SC
1203}
1204//-----------------------------------------------------------------------------
1205// wxGDIPlusRenderer declaration
1206//-----------------------------------------------------------------------------
1207
1208class WXDLLIMPEXP_CORE wxGDIPlusRenderer : public wxGraphicsRenderer
1209{
1210public :
1211 wxGDIPlusRenderer()
1212 {
1213 m_loaded = false;
1214 m_gditoken = NULL;
1215 }
1216
1217 virtual ~wxGDIPlusRenderer()
1218 {
1219 if (m_loaded)
1220 {
1221 Unload();
1222 }
1223 }
1224
1225 // Context
1226
1227 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
1228
1229 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
1230
1231 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
1232
1233 virtual wxGraphicsContext * CreateContext( wxWindow* window );
1234
1235 // Path
1236
a4e73390 1237 virtual wxGraphicsPath CreatePath();
83576e68
SC
1238
1239 // Matrix
1240
a4e73390 1241 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
83576e68
SC
1242 wxDouble tx=0.0, wxDouble ty=0.0);
1243
1244
2c820406 1245 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
83576e68 1246
2c820406 1247 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
83576e68
SC
1248
1249 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
2c820406 1250 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
83576e68
SC
1251 const wxColour&c1, const wxColour&c2) ;
1252
1253 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1254 // with radius r and color cColor
2c820406 1255 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
83576e68
SC
1256 const wxColour &oColor, const wxColour &cColor) ;
1257
1258 // sets the font
2c820406 1259 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
83576e68
SC
1260protected :
1261 void EnsureIsLoaded();
1262 void Load();
1263 void Unload();
1264
1265private :
1266 bool m_loaded;
1267 DWORD m_gditoken;
1268
1269 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer)
1270} ;
1271
1272//-----------------------------------------------------------------------------
1273// wxGDIPlusRenderer implementation
1274//-----------------------------------------------------------------------------
1275
1276IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer,wxGraphicsRenderer)
1277
1278static wxGDIPlusRenderer gs_GDIPlusRenderer;
1279
1280wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1281{
1282 return &gs_GDIPlusRenderer;
1283}
1284
1285void wxGDIPlusRenderer::EnsureIsLoaded()
1286{
1287 if (!m_loaded)
1288 {
1289 Load();
1290 }
1291}
1292
1293void wxGDIPlusRenderer::Load()
1294{
1295 GdiplusStartupInput input;
1296 GdiplusStartupOutput output;
1297 GdiplusStartup(&m_gditoken,&input,&output);
1298 m_loaded = true;
1299}
1300
1301void wxGDIPlusRenderer::Unload()
1302{
1303 if ( m_gditoken )
1304 GdiplusShutdown(m_gditoken);
1305}
1306
1307wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxWindowDC& dc)
1308{
1309 EnsureIsLoaded();
1310 return new wxGDIPlusContext(this,(HDC) dc.GetHDC());
1311}
1312
1313wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeContext( void * context )
1314{
1315 EnsureIsLoaded();
1316 return new wxGDIPlusContext(this,(Graphics*) context);
1317}
1318
1319
1320wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window )
1321{
1322 EnsureIsLoaded();
1323 return new wxGDIPlusContext(this,(HWND) window);
1324}
1325
1326wxGraphicsContext * wxGDIPlusRenderer::CreateContext( wxWindow* window )
1327{
1328 EnsureIsLoaded();
1329 return new wxGDIPlusContext(this, (HWND) window->GetHWND() );
1330}
1331
1332// Path
1333
a4e73390 1334wxGraphicsPath wxGDIPlusRenderer::CreatePath()
83576e68
SC
1335{
1336 EnsureIsLoaded();
a4e73390
SC
1337 wxGraphicsPath m;
1338 m.SetRefData( new wxGDIPlusPathData(this));
1339 return m;
83576e68
SC
1340}
1341
1342
1343// Matrix
1344
a4e73390 1345wxGraphicsMatrix wxGDIPlusRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
83576e68
SC
1346 wxDouble tx, wxDouble ty)
1347
1348{
1349 EnsureIsLoaded();
a4e73390
SC
1350 wxGraphicsMatrix m;
1351 wxGDIPlusMatrixData* data = new wxGDIPlusMatrixData( this );
1352 data->Set( a,b,c,d,tx,ty ) ;
1353 m.SetRefData(data);
83576e68 1354 return m;
539e2795
SC
1355}
1356
2c820406 1357wxGraphicsPen wxGDIPlusRenderer::CreatePen(const wxPen& pen)
6fea499c 1358{
83576e68
SC
1359 EnsureIsLoaded();
1360 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
2c820406 1361 return wxNullGraphicsPen;
83576e68 1362 else
2c820406
SC
1363 {
1364 wxGraphicsPen p;
1365 p.SetRefData(new wxGDIPlusPenData( this, pen ));
1366 return p;
1367 }
6fea499c 1368}
7ba86d93 1369
2c820406 1370wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
539e2795 1371{
83576e68
SC
1372 EnsureIsLoaded();
1373 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
2c820406 1374 return wxNullGraphicsBrush;
83576e68 1375 else
2c820406
SC
1376 {
1377 wxGraphicsBrush p;
1378 p.SetRefData(new wxGDIPlusBrushData( this, brush ));
1379 return p;
1380 }
539e2795
SC
1381}
1382
83576e68 1383// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
2c820406 1384wxGraphicsBrush wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
83576e68 1385 const wxColour&c1, const wxColour&c2)
539e2795 1386{
83576e68 1387 EnsureIsLoaded();
2c820406
SC
1388 wxGraphicsBrush p;
1389 wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1390 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
1391 p.SetRefData(d);
1392 return p;
1393 }
539e2795 1394
83576e68
SC
1395// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
1396// with radius r and color cColor
2c820406 1397wxGraphicsBrush wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
83576e68
SC
1398 const wxColour &oColor, const wxColour &cColor)
1399{
1400 EnsureIsLoaded();
2c820406
SC
1401 wxGraphicsBrush p;
1402 wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1403 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
1404 p.SetRefData(d);
1405 return p;
83576e68 1406}
539e2795 1407
83576e68 1408// sets the font
2c820406 1409wxGraphicsFont wxGDIPlusRenderer::CreateFont( const wxFont &font , const wxColour &col )
83576e68
SC
1410{
1411 EnsureIsLoaded();
1412 if ( font.Ok() )
2c820406
SC
1413 {
1414 wxGraphicsFont p;
1415 p.SetRefData(new wxGDIPlusFontData( this , font, col ));
1416 return p;
1417 }
83576e68 1418 else
2c820406 1419 return wxNullGraphicsFont;
83576e68 1420}
7ba86d93
RD
1421
1422#endif // wxUSE_GRAPHICS_CONTEXT