]> git.saurik.com Git - wxWidgets.git/blame - src/msw/graphics.cpp
Implemented forceTrueColour in SetBestVisual.
[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
cb3a0d42 110 // adds a straight line from the current point to (x,y)
6fea499c
SC
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
cb3a0d42 117 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
6fea499c
SC
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 //
cb3a0d42 130 // These are convenience functions which - if not available natively will be assembled
6fea499c
SC
131 // using the primitives from above
132 //
133
cb3a0d42 134 // appends a rectangle as a new closed subpath
6fea499c
SC
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
cb3a0d42
VZ
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)
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
cb3a0d42 175 virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
83576e68
SC
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)
cb3a0d42 198 virtual void Rotate( wxDouble angle );
83576e68
SC
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
cb3a0d42 242 void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
83576e68
SC
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 );
539e2795 283
cb3a0d42
VZ
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
cb3a0d42
VZ
292 virtual void Translate( wxDouble dx , wxDouble dy );
293 virtual void Scale( wxDouble xScale , wxDouble yScale );
294 virtual void Rotate( wxDouble angle );
6fea499c 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 );
cb3a0d42 307 virtual void PushState();
6fea499c
SC
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)
cb3a0d42 347{
83576e68
SC
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;
cb3a0d42 482 }
83576e68
SC
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 }
cb3a0d42 534 else
83576e68
SC
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
cb3a0d42 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
cb3a0d42 588wxGDIPlusFontData::wxGDIPlusFontData( wxGraphicsRenderer* renderer, const wxFont &font,
2c820406 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
cb3a0d42 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 }
cb3a0d42 696 m_path->AddArc((REAL) (x-r),(REAL) (y-r),(REAL) (2*r),(REAL) (2*r),RadToDeg(startAngle),RadToDeg(sweepAngle));
6fea499c
SC
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
cb3a0d42 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
cb3a0d42 746wxGDIPlusMatrixData::~wxGDIPlusMatrixData()
6fea499c 747{
83576e68 748 delete m_matrix;
6fea499c
SC
749}
750
cb3a0d42 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
cb3a0d42 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 ?
cb3a0d42 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
cb3a0d42 843wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc )
83576e68
SC
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{
93f72bae
SC
899 Region rgn((HRGN)region.GetHRGN());
900 m_context->SetClip(&rgn,CombineModeIntersect);
83576e68 901}
6fea499c 902
83576e68
SC
903void wxGDIPlusContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
904{
905 m_context->SetClip(RectF(x,y,w,h),CombineModeIntersect);
906}
cb3a0d42 907
83576e68
SC
908void wxGDIPlusContext::ResetClip()
909{
910 m_context->ResetClip();
911}
6fea499c 912
a4e73390 913void wxGDIPlusContext::StrokePath( const wxGraphicsPath& path )
83576e68 914{
2c820406 915 if ( !m_pen.IsNull() )
83576e68 916 {
a4e73390 917 m_context->DrawPath( ((wxGDIPlusPenData*)m_pen.GetGraphicsData())->GetGDIPlusPen() , (GraphicsPath*) path.GetNativePath() );
83576e68 918 }
6fea499c
SC
919}
920
a4e73390 921void wxGDIPlusContext::FillPath( const wxGraphicsPath& path , int fillStyle )
6fea499c 922{
2c820406 923 if ( !m_brush.IsNull() )
83576e68 924 {
a4e73390 925 ((GraphicsPath*) path.GetNativePath())->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
cb3a0d42 926 m_context->FillPath( ((wxGDIPlusBrushData*)m_brush.GetRefData())->GetGDIPlusBrush() ,
a4e73390 927 (GraphicsPath*) path.GetNativePath());
83576e68
SC
928 }
929}
6fea499c 930
cb3a0d42 931void wxGDIPlusContext::Rotate( wxDouble angle )
83576e68
SC
932{
933 m_context->RotateTransform( RadToDeg(angle) );
934}
6fea499c 935
cb3a0d42 936void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy )
83576e68
SC
937{
938 m_context->TranslateTransform( dx , dy );
939}
6fea499c 940
83576e68
SC
941void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale )
942{
943 m_context->ScaleTransform(xScale,yScale);
944}
6fea499c 945
83576e68
SC
946void wxGDIPlusContext::PushState()
947{
948 GraphicsState state = m_context->Save();
949 m_stateStack.push_back(state);
950}
951
cb3a0d42 952void wxGDIPlusContext::PopState()
83576e68
SC
953{
954 GraphicsState state = m_stateStack.back();
955 m_stateStack.pop_back();
956 m_context->Restore(state);
6fea499c
SC
957}
958
cb3a0d42
VZ
959// the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
960// premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
fe31db81
SC
961// bytes as parameter
962
cb3a0d42 963void wxGDIPlusContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
6fea499c 964{
fe31db81
SC
965 Bitmap* image = NULL;
966 Bitmap* helper = NULL;
967 if ( bmp.GetMask() )
cb3a0d42 968 {
fe31db81
SC
969 Bitmap interim((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE()) ;
970
971 size_t width = interim.GetWidth();
972 size_t height = interim.GetHeight();
973 Rect bounds(0,0,width,height);
974
975 image = new Bitmap(width,height,PixelFormat32bppPARGB) ;
976
977 Bitmap interimMask((HBITMAP)bmp.GetMask()->GetMaskBitmap(),NULL);
978 wxASSERT(interimMask.GetPixelFormat() == PixelFormat1bppIndexed);
979
980 BitmapData dataMask ;
cb3a0d42 981 interimMask.LockBits(&bounds,ImageLockModeRead,
fe31db81
SC
982 interimMask.GetPixelFormat(),&dataMask);
983
984
985 BitmapData imageData ;
986 image->LockBits(&bounds,ImageLockModeWrite, PixelFormat32bppPARGB, &imageData);
987
988 BYTE maskPattern = 0 ;
989 BYTE maskByte = 0;
990 size_t maskIndex ;
991
992 for ( size_t y = 0 ; y < height ; ++y)
993 {
994 maskIndex = 0 ;
995 for( size_t x = 0 ; x < width; ++x)
996 {
997 if ( x % 8 == 0)
998 {
999 maskPattern = 0x80;
1000 maskByte = *((BYTE*)dataMask.Scan0 + dataMask.Stride*y + maskIndex);
1001 maskIndex++;
1002 }
1003 else
1004 maskPattern = maskPattern >> 1;
1005
1006 ARGB *dest = (ARGB*)((BYTE*)imageData.Scan0 + imageData.Stride*y + x*4);
1007 if ( (maskByte & maskPattern) == 0 )
1008 *dest = 0x00000000;
1009 else
1010 {
1011 Color c ;
1012 interim.GetPixel(x,y,&c) ;
1013 *dest = (c.GetValue() | Color::AlphaMask);
1014 }
1015 }
1016 }
1017
1018 image->UnlockBits(&imageData);
1019
1020 interimMask.UnlockBits(&dataMask);
1021 interim.UnlockBits(&dataMask);
1022 }
1023 else
1024 {
cb3a0d42 1025 image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE());
fe31db81
SC
1026 if ( GetPixelFormatSize(image->GetPixelFormat()) == 32 )
1027 {
1028 size_t width = image->GetWidth();
1029 size_t height = image->GetHeight();
1030 Rect bounds(0,0,width,height);
1031 BitmapData data ;
1032
1033 helper = image ;
1034 image = NULL ;
1035 helper->LockBits(&bounds, ImageLockModeRead,
1036 helper->GetPixelFormat(),&data);
1037
cb3a0d42 1038 image = new Bitmap(data.Width, data.Height, data.Stride,
fe31db81
SC
1039 PixelFormat32bppARGB , (BYTE*) data.Scan0);
1040
1041 helper->UnlockBits(&data);
1042 }
1043 }
1044 if ( image )
1045 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
6fea499c 1046 delete image ;
fe31db81 1047 delete helper ;
6fea499c
SC
1048}
1049
cb3a0d42 1050void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
6fea499c 1051{
fe31db81
SC
1052 HICON hIcon = (HICON)icon.GetHICON();
1053 ICONINFO iconInfo ;
1054 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
1055 if (!GetIconInfo(hIcon,&iconInfo))
1056 return;
1057
1058 BITMAP iconBmpData ;
1059 GetObject(iconInfo.hbmColor,sizeof(BITMAP),&iconBmpData);
1060 Bitmap interim(iconInfo.hbmColor,NULL);
1061
1062 Bitmap* image = NULL ;
1063
1064 if( GetPixelFormatSize(interim.GetPixelFormat())!= 32 )
1065 {
1066 image = Bitmap::FromHICON(hIcon);
1067 }
1068 else
1069 {
1070 size_t width = interim.GetWidth();
1071 size_t height = interim.GetHeight();
1072 Rect bounds(0,0,width,height);
1073 BitmapData data ;
1074
1075 interim.LockBits(&bounds, ImageLockModeRead,
1076 interim.GetPixelFormat(),&data);
cb3a0d42 1077 image = new Bitmap(data.Width, data.Height, data.Stride,
fe31db81
SC
1078 PixelFormat32bppARGB , (BYTE*) data.Scan0);
1079 interim.UnlockBits(&data);
1080 }
1081
6fea499c 1082 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
fe31db81 1083
6fea499c 1084 delete image ;
fe31db81
SC
1085 DeleteObject(iconInfo.hbmColor);
1086 DeleteObject(iconInfo.hbmMask);
6fea499c
SC
1087}
1088
cb3a0d42 1089void wxGDIPlusContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
6fea499c 1090{
2c820406 1091 if ( m_font.IsNull() || str.IsEmpty())
6fea499c
SC
1092 return ;
1093
1094 wxWCharBuffer s = str.wc_str( *wxConvUI );
cb3a0d42 1095 m_context->DrawString( s , -1 , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont() ,
2c820406 1096 PointF( x , y ) , ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusBrush() );
6fea499c
SC
1097 // TODO m_backgroundMode == wxSOLID
1098}
1099
1100void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
1101 wxDouble *descent, wxDouble *externalLeading ) const
1102{
1103 wxWCharBuffer s = str.wc_str( *wxConvUI );
1104 FontFamily ffamily ;
2c820406 1105 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
cb3a0d42 1106
83576e68 1107 f->GetFamily(&ffamily) ;
6fea499c
SC
1108
1109 REAL factorY = m_context->GetDpiY() / 72.0 ;
1110
1111 REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
83576e68 1112 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c 1113 REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
83576e68 1114 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c 1115 REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
83576e68 1116 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
6fea499c
SC
1117
1118 if ( height )
1119 *height = rHeight * factorY + 0.5 ;
1120 if ( descent )
1121 *descent = rDescent * factorY + 0.5 ;
1122 if ( externalLeading )
1123 *externalLeading = (rHeight - rAscent - rDescent) * factorY + 0.5 ;
1124 // measuring empty strings is not guaranteed, so do it by hand
cb3a0d42 1125 if ( str.IsEmpty())
6fea499c
SC
1126 {
1127 if ( width )
1128 *width = 0 ;
1129 }
1130 else
1131 {
1132 // MeasureString does return a rectangle that is way too large, so it is
1133 // not usable here
1134 RectF layoutRect(0,0, 100000.0f, 100000.0f);
1135 StringFormat strFormat;
1136 CharacterRange strRange(0,wcslen(s));
1137 strFormat.SetMeasurableCharacterRanges(1,&strRange);
1138 Region region ;
83576e68 1139 m_context->MeasureCharacterRanges(s, -1 , f,layoutRect, &strFormat,1,&region) ;
6fea499c
SC
1140 RectF bbox ;
1141 region.GetBounds(&bbox,m_context);
1142 if ( width )
1143 *width = bbox.GetRight()-bbox.GetLeft()+0.5;
1144 }
1145}
1146
cb3a0d42 1147void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
6fea499c
SC
1148{
1149 widths.Empty();
1150 widths.Add(0, text.length());
1151
1152 if (text.empty())
1153 return;
1154
2c820406 1155 Font* f = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusFont();
6fea499c
SC
1156 wxWCharBuffer ws = text.wc_str( *wxConvUI );
1157 size_t len = wcslen( ws ) ;
1158 wxASSERT_MSG(text.length() == len , wxT("GetPartialTextExtents not yet implemented for multichar situations"));
1159
1160 RectF layoutRect(0,0, 100000.0f, 100000.0f);
1161 StringFormat strFormat;
1162
1163 CharacterRange* ranges = new CharacterRange[len] ;
1164 Region* regions = new Region[len];
1165 for( size_t i = 0 ; i < len ; ++i)
1166 {
1167 ranges[i].First = i ;
1168 ranges[i].Length = 1 ;
1169 }
1170 strFormat.SetMeasurableCharacterRanges(len,ranges);
83576e68 1171 m_context->MeasureCharacterRanges(ws, -1 , f,layoutRect, &strFormat,1,regions) ;
6fea499c
SC
1172
1173 RectF bbox ;
1174 for ( size_t i = 0 ; i < len ; ++i)
1175 {
1176 regions[i].GetBounds(&bbox,m_context);
1177 widths[i] = bbox.GetRight()-bbox.GetLeft();
1178 }
1179}
1180
cb3a0d42 1181void* wxGDIPlusContext::GetNativeContext()
6fea499c 1182{
cb3a0d42 1183 return m_context;
6fea499c
SC
1184}
1185
83576e68 1186// concatenates this transform with the current transform of this context
a4e73390 1187void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix& matrix )
539e2795 1188{
a4e73390 1189 m_context->MultiplyTransform((Matrix*) matrix.GetNativeMatrix());
83576e68
SC
1190}
1191
1192// sets the transform of this context
a4e73390 1193void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix& matrix )
83576e68 1194{
a4e73390 1195 m_context->SetTransform((Matrix*) matrix.GetNativeMatrix());
83576e68
SC
1196}
1197
1198// gets the matrix of this context
a4e73390 1199wxGraphicsMatrix wxGDIPlusContext::GetTransform() const
83576e68 1200{
a4e73390
SC
1201 wxGraphicsMatrix matrix = CreateMatrix();
1202 m_context->GetTransform((Matrix*) matrix.GetNativeMatrix());
1203 return matrix;
83576e68
SC
1204}
1205//-----------------------------------------------------------------------------
1206// wxGDIPlusRenderer declaration
1207//-----------------------------------------------------------------------------
1208
1209class WXDLLIMPEXP_CORE wxGDIPlusRenderer : public wxGraphicsRenderer
1210{
1211public :
cb3a0d42 1212 wxGDIPlusRenderer()
83576e68
SC
1213 {
1214 m_loaded = false;
cb3a0d42 1215 m_gditoken = 0;
83576e68
SC
1216 }
1217
cb3a0d42 1218 virtual ~wxGDIPlusRenderer()
83576e68
SC
1219 {
1220 if (m_loaded)
1221 {
1222 Unload();
1223 }
1224 }
1225
1226 // Context
1227
1228 virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc);
1229
773ccc31
SC
1230 virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc);
1231
83576e68
SC
1232 virtual wxGraphicsContext * CreateContextFromNativeContext( void * context );
1233
1234 virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window );
1235
1236 virtual wxGraphicsContext * CreateContext( wxWindow* window );
1237
091ef146
SC
1238 virtual wxGraphicsContext * CreateMeasuringContext();
1239
83576e68
SC
1240 // Path
1241
a4e73390 1242 virtual wxGraphicsPath CreatePath();
83576e68
SC
1243
1244 // Matrix
1245
cb3a0d42 1246 virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0,
83576e68
SC
1247 wxDouble tx=0.0, wxDouble ty=0.0);
1248
1249
2c820406 1250 virtual wxGraphicsPen CreatePen(const wxPen& pen) ;
83576e68 1251
2c820406 1252 virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ;
83576e68
SC
1253
1254 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
cb3a0d42 1255 virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
83576e68
SC
1256 const wxColour&c1, const wxColour&c2) ;
1257
cb3a0d42 1258 // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
83576e68 1259 // with radius r and color cColor
2c820406 1260 virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
83576e68
SC
1261 const wxColour &oColor, const wxColour &cColor) ;
1262
1263 // sets the font
2c820406 1264 virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ;
83576e68
SC
1265protected :
1266 void EnsureIsLoaded();
1267 void Load();
1268 void Unload();
1269
1270private :
1271 bool m_loaded;
cb3a0d42 1272 ULONG_PTR m_gditoken;
83576e68
SC
1273
1274 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer)
1275} ;
1276
1277//-----------------------------------------------------------------------------
1278// wxGDIPlusRenderer implementation
1279//-----------------------------------------------------------------------------
1280
1281IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer,wxGraphicsRenderer)
1282
1283static wxGDIPlusRenderer gs_GDIPlusRenderer;
1284
1285wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1286{
1287 return &gs_GDIPlusRenderer;
1288}
1289
1290void wxGDIPlusRenderer::EnsureIsLoaded()
1291{
1292 if (!m_loaded)
1293 {
1294 Load();
1295 }
1296}
1297
1298void wxGDIPlusRenderer::Load()
1299{
1300 GdiplusStartupInput input;
1301 GdiplusStartupOutput output;
1302 GdiplusStartup(&m_gditoken,&input,&output);
1303 m_loaded = true;
1304}
1305
1306void wxGDIPlusRenderer::Unload()
1307{
1308 if ( m_gditoken )
1309 GdiplusShutdown(m_gditoken);
1310}
1311
1312wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxWindowDC& dc)
1313{
1314 EnsureIsLoaded();
1315 return new wxGDIPlusContext(this,(HDC) dc.GetHDC());
1316}
1317
773ccc31
SC
1318wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxMemoryDC& dc)
1319{
1320 EnsureIsLoaded();
1321 return new wxGDIPlusContext(this,(HDC) dc.GetHDC());
1322}
1323
091ef146
SC
1324wxGraphicsContext * wxGDIPlusRenderer::CreateMeasuringContext()
1325{
1326 EnsureIsLoaded();
1327 return NULL;
1328 // TODO use GetDC(NULL) but then we have to release it from the context
1329 //return new wxGDIPlusContext(this,(HDC) dc.GetHDC());
1330}
1331
83576e68
SC
1332wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeContext( void * context )
1333{
1334 EnsureIsLoaded();
1335 return new wxGDIPlusContext(this,(Graphics*) context);
1336}
1337
1338
1339wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window )
1340{
1341 EnsureIsLoaded();
1342 return new wxGDIPlusContext(this,(HWND) window);
1343}
1344
1345wxGraphicsContext * wxGDIPlusRenderer::CreateContext( wxWindow* window )
1346{
1347 EnsureIsLoaded();
1348 return new wxGDIPlusContext(this, (HWND) window->GetHWND() );
1349}
1350
1351// Path
1352
a4e73390 1353wxGraphicsPath wxGDIPlusRenderer::CreatePath()
83576e68
SC
1354{
1355 EnsureIsLoaded();
a4e73390
SC
1356 wxGraphicsPath m;
1357 m.SetRefData( new wxGDIPlusPathData(this));
1358 return m;
83576e68
SC
1359}
1360
1361
1362// Matrix
1363
cb3a0d42 1364wxGraphicsMatrix wxGDIPlusRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d,
83576e68
SC
1365 wxDouble tx, wxDouble ty)
1366
1367{
1368 EnsureIsLoaded();
a4e73390
SC
1369 wxGraphicsMatrix m;
1370 wxGDIPlusMatrixData* data = new wxGDIPlusMatrixData( this );
1371 data->Set( a,b,c,d,tx,ty ) ;
1372 m.SetRefData(data);
83576e68 1373 return m;
539e2795
SC
1374}
1375
cb3a0d42 1376wxGraphicsPen wxGDIPlusRenderer::CreatePen(const wxPen& pen)
6fea499c 1377{
83576e68
SC
1378 EnsureIsLoaded();
1379 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
2c820406 1380 return wxNullGraphicsPen;
83576e68 1381 else
2c820406
SC
1382 {
1383 wxGraphicsPen p;
1384 p.SetRefData(new wxGDIPlusPenData( this, pen ));
1385 return p;
1386 }
6fea499c 1387}
7ba86d93 1388
cb3a0d42 1389wxGraphicsBrush wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
539e2795 1390{
83576e68
SC
1391 EnsureIsLoaded();
1392 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
2c820406 1393 return wxNullGraphicsBrush;
83576e68 1394 else
2c820406
SC
1395 {
1396 wxGraphicsBrush p;
1397 p.SetRefData(new wxGDIPlusBrushData( this, brush ));
1398 return p;
1399 }
539e2795
SC
1400}
1401
83576e68 1402// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
cb3a0d42
VZ
1403wxGraphicsBrush wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
1404 const wxColour&c1, const wxColour&c2)
539e2795 1405{
83576e68 1406 EnsureIsLoaded();
2c820406
SC
1407 wxGraphicsBrush p;
1408 wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1409 d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
1410 p.SetRefData(d);
1411 return p;
1412 }
539e2795 1413
cb3a0d42 1414// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc)
83576e68 1415// with radius r and color cColor
2c820406 1416wxGraphicsBrush wxGDIPlusRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
cb3a0d42 1417 const wxColour &oColor, const wxColour &cColor)
83576e68
SC
1418{
1419 EnsureIsLoaded();
2c820406
SC
1420 wxGraphicsBrush p;
1421 wxGDIPlusBrushData* d = new wxGDIPlusBrushData( this );
1422 d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor);
1423 p.SetRefData(d);
1424 return p;
83576e68 1425}
539e2795 1426
83576e68 1427// sets the font
cb3a0d42 1428wxGraphicsFont wxGDIPlusRenderer::CreateFont( const wxFont &font , const wxColour &col )
83576e68
SC
1429{
1430 EnsureIsLoaded();
1431 if ( font.Ok() )
cb3a0d42 1432 {
2c820406
SC
1433 wxGraphicsFont p;
1434 p.SetRefData(new wxGDIPlusFontData( this , font, col ));
1435 return p;
1436 }
83576e68 1437 else
2c820406 1438 return wxNullGraphicsFont;
83576e68 1439}
7ba86d93
RD
1440
1441#endif // wxUSE_GRAPHICS_CONTEXT