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