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