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