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