]> git.saurik.com Git - wxWidgets.git/blob - src/msw/graphics.cpp
Make animation of combo-popdown optional.
[wxWidgets.git] / src / msw / graphics.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/graphics.cpp
3 // Purpose: wxGCDC class
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 2006-09-30
7 // RCS-ID: $Id$
8 // Copyright: (c) 2006 Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/dc.h"
15
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
38 #if wxUSE_GRAPHICS_CONTEXT
39
40 #include <vector>
41
42 using namespace std;
43
44 //-----------------------------------------------------------------------------
45 // constants
46 //-----------------------------------------------------------------------------
47
48 const double RAD2DEG = 180.0 / M_PI;
49
50 //-----------------------------------------------------------------------------
51 // Local functions
52 //-----------------------------------------------------------------------------
53
54 static inline double dmin(double a, double b) { return a < b ? a : b; }
55 static inline double dmax(double a, double b) { return a > b ? a : b; }
56
57 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
58 static 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"
93 using namespace Gdiplus;
94
95 class WXDLLIMPEXP_CORE wxGDIPlusPath : public wxGraphicsPath
96 {
97 public :
98 wxGDIPlusPath();
99 wxGDIPlusPath(wxGraphicsRenderer* renderer, GraphicsPath* path = NULL);
100 ~wxGDIPlusPath();
101
102 virtual wxGraphicsPath *Clone() const;
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
124 // adds another path
125 virtual void AddPath( const wxGraphicsPath* path );
126
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
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)
150 virtual void UnGetNativePath(void * WXUNUSED(path)) {}
151
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
160 private :
161 GraphicsPath* m_path;
162 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusPath)
163 };
164
165 class WXDLLIMPEXP_CORE wxGDIPlusMatrix : public wxGraphicsMatrix
166 {
167 public :
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;
219 private:
220 Matrix* m_matrix ;
221
222 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusMatrix)
223 } ;
224
225 class WXDLLIMPEXP_CORE wxGDIPlusPen : public wxGraphicsPen
226 {
227 public:
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
238 protected :
239 Pen* m_pen;
240 Image* m_penImage;
241 Brush* m_penBrush;
242
243 wxDouble m_width;
244 private :
245 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusPen)
246 };
247
248 class WXDLLIMPEXP_CORE wxGDIPlusBrush : public wxGraphicsBrush
249 {
250 public:
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
263 protected:
264 virtual void Init();
265
266 private :
267 Brush* m_brush;
268 Image* m_brushImage;
269 GraphicsPath* m_brushPath;
270
271 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusBrush)
272 };
273
274 class wxGDIPlusFont : public wxGraphicsFont
275 {
276 public:
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; }
284 private :
285 Brush* m_textBrush;
286 Font* m_font;
287
288 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusFont)
289 };
290
291 class WXDLLIMPEXP_CORE wxGDIPlusContext : public wxGraphicsContext
292 {
293 public:
294 wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc );
295 wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd );
296 wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr);
297 wxGDIPlusContext();
298
299 virtual ~wxGDIPlusContext();
300
301 virtual void Clip( const wxRegion &region );
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
310 virtual void StrokePath( const wxGraphicsPath *p );
311 virtual void FillPath( const wxGraphicsPath *p , int fillStyle = wxWINDING_RULE );
312
313 virtual void Translate( wxDouble dx , wxDouble dy );
314 virtual void Scale( wxDouble xScale , wxDouble yScale );
315 virtual void Rotate( wxDouble angle );
316
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
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
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
336 private:
337 void Init();
338 void SetDefaults();
339
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
352 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusPen,wxGraphicsPen)
353
354 wxGDIPlusPen::wxGDIPlusPen() : wxGraphicsPen(NULL)
355 {
356 wxLogDebug(wxT("Illegal Constructor called"));
357 }
358
359 wxGDIPlusPen::~wxGDIPlusPen()
360 {
361 delete m_pen;
362 delete m_penImage;
363 delete m_penBrush;
364 }
365
366 void wxGDIPlusPen::Init()
367 {
368 m_pen = NULL ;
369 m_penImage = NULL;
370 m_penBrush = NULL;
371 }
372
373 wxGDIPlusPen::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
515 void wxGDIPlusPen::Apply( wxGraphicsContext* WXUNUSED(context) )
516 {
517 // nothing to do here
518 }
519
520
521 //-----------------------------------------------------------------------------
522 // wxGDIPlusBrush implementation
523 //-----------------------------------------------------------------------------
524
525 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusBrush,wxGraphicsBrush)
526
527 wxGDIPlusBrush::wxGDIPlusBrush( wxGraphicsRenderer* renderer )
528 : wxGraphicsBrush(renderer)
529 {
530 Init();
531 }
532
533 wxGDIPlusBrush::wxGDIPlusBrush( )
534 : wxGraphicsBrush(NULL)
535 {
536 wxLogDebug(wxT("Illegal Constructor called"));
537 }
538
539
540 wxGDIPlusBrush::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
589 wxGDIPlusBrush::~wxGDIPlusBrush()
590 {
591 delete m_brush;
592 delete m_brushImage;
593 delete m_brushPath;
594 };
595
596 void wxGDIPlusBrush::Init()
597 {
598 m_brush = NULL;
599 m_brushImage= NULL;
600 m_brushPath= NULL;
601 }
602
603 void 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
610 void 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
627 void wxGDIPlusBrush::Apply( wxGraphicsContext* WXUNUSED(context) )
628 {
629 // nothing to do here
630 }
631
632 //-----------------------------------------------------------------------------
633 // wxGDIPlusFont implementation
634 //-----------------------------------------------------------------------------
635
636 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusFont,wxGraphicsFont)
637
638 wxGDIPlusFont::wxGDIPlusFont() : wxGraphicsFont( NULL )
639 {
640 wxLogDebug(wxT("Illegal Constructor called"));
641 }
642
643 wxGDIPlusFont::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 }
662
663 wxGDIPlusFont::~wxGDIPlusFont()
664 {
665 delete m_textBrush;
666 delete m_font;
667 }
668
669 void wxGDIPlusFont::Apply( wxGraphicsContext* WXUNUSED(context) )
670 {
671 // nothing to do here
672 }
673
674 //-----------------------------------------------------------------------------
675 // wxGDIPlusPath implementation
676 //-----------------------------------------------------------------------------
677
678 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusPath,wxGraphicsPath)
679
680 wxGDIPlusPath::wxGDIPlusPath(wxGraphicsRenderer* renderer, GraphicsPath* path ) : wxGraphicsPath(renderer)
681 {
682 if ( path )
683 m_path = path;
684 else
685 m_path = new GraphicsPath();
686 }
687
688 wxGDIPlusPath::wxGDIPlusPath() : wxGraphicsPath(NULL)
689 {
690 wxLogDebug(wxT("Illegal Constructor called"));
691 }
692
693
694 wxGDIPlusPath::~wxGDIPlusPath()
695 {
696 delete m_path;
697 }
698
699 wxGraphicsPath* wxGDIPlusPath::Clone() const
700 {
701 return new wxGDIPlusPath( GetRenderer() , m_path->Clone());
702 }
703
704
705
706 //
707 // The Primitives
708 //
709
710 void 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
716 void wxGDIPlusPath::AddLineToPoint( wxDouble x , wxDouble y )
717 {
718 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
719 }
720
721 void wxGDIPlusPath::CloseSubpath()
722 {
723 m_path->CloseFigure();
724 }
725
726 void 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
737 void 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
745 void 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
769 void wxGDIPlusPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
770 {
771 m_path->AddRectangle(RectF(x,y,w,h));
772 }
773
774 void wxGDIPlusPath::AddPath( const wxGraphicsPath* path )
775 {
776 m_path->AddPath( (GraphicsPath*) path->GetNativePath(), FALSE);
777 }
778
779
780 // transforms each point of this path by the matrix
781 void wxGDIPlusPath::Transform( wxGraphicsMatrix* matrix )
782 {
783 m_path->Transform( (Matrix*) matrix->GetNativeMatrix() );
784 }
785
786 // gets the bounding box enclosing all points (possibly including control points)
787 void wxGDIPlusPath::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h)
788 {
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;
795 }
796
797 bool wxGDIPlusPath::Contains( wxDouble x, wxDouble y, int fillStyle )
798 {
799 m_path->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
800 return m_path->IsVisible( (FLOAT) x,(FLOAT) y) == TRUE ;
801 }
802
803 //-----------------------------------------------------------------------------
804 // wxGDIPlusMatrix implementation
805 //-----------------------------------------------------------------------------
806
807 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusMatrix,wxGraphicsMatrix)
808
809 wxGDIPlusMatrix::wxGDIPlusMatrix() : wxGraphicsMatrix(NULL)
810 {
811 wxLogDebug(wxT("Illegal Constructor called"));
812 }
813
814 wxGDIPlusMatrix::wxGDIPlusMatrix(wxGraphicsRenderer* renderer, Matrix* matrix )
815 : wxGraphicsMatrix(renderer)
816 {
817 if ( matrix )
818 m_matrix = matrix ;
819 else
820 m_matrix = new Matrix();
821 }
822
823 wxGDIPlusMatrix::~wxGDIPlusMatrix()
824 {
825 delete m_matrix;
826 }
827
828 wxGraphicsMatrix *wxGDIPlusMatrix::Clone() const
829 {
830 return new wxGDIPlusMatrix( GetRenderer(), m_matrix->Clone());
831 }
832
833 // concatenates the matrix
834 void wxGDIPlusMatrix::Concat( const wxGraphicsMatrix *t )
835 {
836 m_matrix->Multiply( (Matrix*) t->GetNativeMatrix());
837 }
838
839 // copies the passed in matrix
840 void wxGDIPlusMatrix::Copy( const wxGraphicsMatrix *t )
841 {
842 delete m_matrix;
843 m_matrix = ((Matrix*) t->GetNativeMatrix())->Clone();
844 }
845
846 // sets the matrix to the respective values
847 void wxGDIPlusMatrix::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d,
848 wxDouble tx, wxDouble ty)
849 {
850 m_matrix->SetElements(a,b,c,d,tx,ty);
851 }
852
853 // makes this the inverse matrix
854 void wxGDIPlusMatrix::Invert()
855 {
856 m_matrix->Invert();
857 }
858
859 // returns true if the elements of the transformation matrix are equal ?
860 bool wxGDIPlusMatrix::IsEqual( const wxGraphicsMatrix* t) const
861 {
862 return m_matrix->Equals((Matrix*) t->GetNativeMatrix())== TRUE ;
863 }
864
865 // return true if this is the identity matrix
866 bool wxGDIPlusMatrix::IsIdentity()
867 {
868 return m_matrix->IsIdentity() == TRUE ;
869 }
870
871 //
872 // transformation
873 //
874
875 // add the translation to this matrix
876 void wxGDIPlusMatrix::Translate( wxDouble dx , wxDouble dy )
877 {
878 m_matrix->Translate(dx,dy);
879 }
880
881 // add the scale to this matrix
882 void wxGDIPlusMatrix::Scale( wxDouble xScale , wxDouble yScale )
883 {
884 m_matrix->Scale(xScale,yScale);
885 }
886
887 // add the rotation to this matrix (radians)
888 void wxGDIPlusMatrix::Rotate( wxDouble angle )
889 {
890 m_matrix->Rotate( angle );
891 }
892
893 //
894 // apply the transforms
895 //
896
897 // applies that matrix to the point
898 void wxGDIPlusMatrix::TransformPoint( wxDouble *x, wxDouble *y )
899 {
900 PointF pt(*x,*y);
901 m_matrix->TransformPoints(&pt);
902 *x = pt.X;
903 *y = pt.Y;
904 }
905
906 // applies the matrix except for translations
907 void wxGDIPlusMatrix::TransformDistance( wxDouble *dx, wxDouble *dy )
908 {
909 PointF pt(*dx,*dy);
910 m_matrix->TransformVectors(&pt);
911 *dx = pt.X;
912 *dy = pt.Y;
913 }
914
915 // returns the native representation
916 void * wxGDIPlusMatrix::GetNativeMatrix() const
917 {
918 return m_matrix;
919 }
920
921 //-----------------------------------------------------------------------------
922 // wxGDIPlusContext implementation
923 //-----------------------------------------------------------------------------
924
925 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext,wxGraphicsContext)
926
927 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HDC hdc )
928 : wxGraphicsContext(renderer)
929 {
930 Init();
931 m_context = new Graphics( hdc);
932 SetDefaults();
933 }
934
935 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, HWND hwnd )
936 : wxGraphicsContext(renderer)
937 {
938 Init();
939 m_context = new Graphics( hwnd);
940 SetDefaults();
941 }
942
943 wxGDIPlusContext::wxGDIPlusContext( wxGraphicsRenderer* renderer, Graphics* gr )
944 : wxGraphicsContext(renderer)
945 {
946 Init();
947 m_context = gr;
948 SetDefaults();
949 }
950
951 wxGDIPlusContext::wxGDIPlusContext() : wxGraphicsContext(NULL)
952 {
953 Init();
954 }
955
956 void wxGDIPlusContext::Init()
957 {
958 m_context = NULL;
959 m_state1 = 0;
960 m_state2= 0;
961 }
962
963 void wxGDIPlusContext::SetDefaults()
964 {
965 m_context->SetSmoothingMode(SmoothingModeHighQuality);
966 m_state1 = m_context->Save();
967 m_state2 = m_context->Save();
968 }
969
970 wxGDIPlusContext::~wxGDIPlusContext()
971 {
972 SetBrush(NULL);
973 SetFont(NULL);
974 SetPen(NULL);
975
976 if ( m_context )
977 {
978 m_context->Restore( m_state2 );
979 m_context->Restore( m_state1 );
980 delete m_context;
981 }
982 }
983
984
985 void wxGDIPlusContext::Clip( const wxRegion &region )
986 {
987 m_context->SetClip((HRGN)region.GetHRGN(),CombineModeIntersect);
988 }
989
990 void wxGDIPlusContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
991 {
992 m_context->SetClip(RectF(x,y,w,h),CombineModeIntersect);
993 }
994
995 void wxGDIPlusContext::ResetClip()
996 {
997 m_context->ResetClip();
998 }
999
1000 void wxGDIPlusContext::StrokePath( const wxGraphicsPath *path )
1001 {
1002 if ( m_pen )
1003 {
1004 m_context->DrawPath( ((wxGDIPlusPen*)m_pen)->GetGDIPlusPen() , (GraphicsPath*) path->GetNativePath() );
1005 }
1006 }
1007
1008 void wxGDIPlusContext::FillPath( const wxGraphicsPath *path , int fillStyle )
1009 {
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 }
1017
1018 void wxGDIPlusContext::Rotate( wxDouble angle )
1019 {
1020 m_context->RotateTransform( RadToDeg(angle) );
1021 }
1022
1023 void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy )
1024 {
1025 m_context->TranslateTransform( dx , dy );
1026 }
1027
1028 void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale )
1029 {
1030 m_context->ScaleTransform(xScale,yScale);
1031 }
1032
1033 void wxGDIPlusContext::PushState()
1034 {
1035 GraphicsState state = m_context->Save();
1036 m_stateStack.push_back(state);
1037 }
1038
1039 void wxGDIPlusContext::PopState()
1040 {
1041 GraphicsState state = m_stateStack.back();
1042 m_stateStack.pop_back();
1043 m_context->Restore(state);
1044 }
1045
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
1050 void wxGDIPlusContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1051 {
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) ;
1133 delete image ;
1134 delete helper ;
1135 }
1136
1137 void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
1138 {
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
1169 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
1170
1171 delete image ;
1172 DeleteObject(iconInfo.hbmColor);
1173 DeleteObject(iconInfo.hbmMask);
1174 }
1175
1176
1177 void wxGDIPlusContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
1178 {
1179 if ( str.IsEmpty())
1180 return ;
1181
1182 wxWCharBuffer s = str.wc_str( *wxConvUI );
1183 m_context->DrawString( s , -1 , ((wxGDIPlusFont*)m_font)->GetGDIPlusFont() ,
1184 PointF( x , y ) , ((wxGDIPlusFont*)m_font)->GetGDIPlusBrush() );
1185 // TODO m_backgroundMode == wxSOLID
1186 }
1187
1188 void 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 ;
1193 Font* f = ((wxGDIPlusFont*)m_font)->GetGDIPlusFont();
1194
1195 f->GetFamily(&ffamily) ;
1196
1197 REAL factorY = m_context->GetDpiY() / 72.0 ;
1198
1199 REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
1200 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
1201 REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
1202 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
1203 REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
1204 f->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
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 ;
1227 m_context->MeasureCharacterRanges(s, -1 , f,layoutRect, &strFormat,1,&region) ;
1228 RectF bbox ;
1229 region.GetBounds(&bbox,m_context);
1230 if ( width )
1231 *width = bbox.GetRight()-bbox.GetLeft()+0.5;
1232 }
1233 }
1234
1235 void 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
1243 Font* f = ((wxGDIPlusFont*)m_font)->GetGDIPlusFont();
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);
1259 m_context->MeasureCharacterRanges(ws, -1 , f,layoutRect, &strFormat,1,regions) ;
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
1269 void* wxGDIPlusContext::GetNativeContext()
1270 {
1271 return m_context;
1272 }
1273
1274 // concatenates this transform with the current transform of this context
1275 void wxGDIPlusContext::ConcatTransform( const wxGraphicsMatrix* matrix )
1276 {
1277 m_context->MultiplyTransform((Matrix*) matrix->GetNativeMatrix());
1278 }
1279
1280 // sets the transform of this context
1281 void wxGDIPlusContext::SetTransform( const wxGraphicsMatrix* matrix )
1282 {
1283 m_context->SetTransform((Matrix*) matrix->GetNativeMatrix());
1284 }
1285
1286 // gets the matrix of this context
1287 void wxGDIPlusContext::GetTransform( wxGraphicsMatrix* matrix )
1288 {
1289 m_context->GetTransform((Matrix*) matrix->GetNativeMatrix());
1290 }
1291 //-----------------------------------------------------------------------------
1292 // wxGDIPlusRenderer declaration
1293 //-----------------------------------------------------------------------------
1294
1295 class WXDLLIMPEXP_CORE wxGDIPlusRenderer : public wxGraphicsRenderer
1296 {
1297 public :
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 ) ;
1347 protected :
1348 void EnsureIsLoaded();
1349 void Load();
1350 void Unload();
1351
1352 private :
1353 bool m_loaded;
1354 DWORD m_gditoken;
1355
1356 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusRenderer)
1357 } ;
1358
1359 //-----------------------------------------------------------------------------
1360 // wxGDIPlusRenderer implementation
1361 //-----------------------------------------------------------------------------
1362
1363 IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusRenderer,wxGraphicsRenderer)
1364
1365 static wxGDIPlusRenderer gs_GDIPlusRenderer;
1366
1367 wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer()
1368 {
1369 return &gs_GDIPlusRenderer;
1370 }
1371
1372 void wxGDIPlusRenderer::EnsureIsLoaded()
1373 {
1374 if (!m_loaded)
1375 {
1376 Load();
1377 }
1378 }
1379
1380 void wxGDIPlusRenderer::Load()
1381 {
1382 GdiplusStartupInput input;
1383 GdiplusStartupOutput output;
1384 GdiplusStartup(&m_gditoken,&input,&output);
1385 m_loaded = true;
1386 }
1387
1388 void wxGDIPlusRenderer::Unload()
1389 {
1390 if ( m_gditoken )
1391 GdiplusShutdown(m_gditoken);
1392 }
1393
1394 wxGraphicsContext * wxGDIPlusRenderer::CreateContext( const wxWindowDC& dc)
1395 {
1396 EnsureIsLoaded();
1397 return new wxGDIPlusContext(this,(HDC) dc.GetHDC());
1398 }
1399
1400 wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeContext( void * context )
1401 {
1402 EnsureIsLoaded();
1403 return new wxGDIPlusContext(this,(Graphics*) context);
1404 }
1405
1406
1407 wxGraphicsContext * wxGDIPlusRenderer::CreateContextFromNativeWindow( void * window )
1408 {
1409 EnsureIsLoaded();
1410 return new wxGDIPlusContext(this,(HWND) window);
1411 }
1412
1413 wxGraphicsContext * wxGDIPlusRenderer::CreateContext( wxWindow* window )
1414 {
1415 EnsureIsLoaded();
1416 return new wxGDIPlusContext(this, (HWND) window->GetHWND() );
1417 }
1418
1419 // Path
1420
1421 wxGraphicsPath * wxGDIPlusRenderer::CreatePath()
1422 {
1423 EnsureIsLoaded();
1424 return new wxGDIPlusPath( this );
1425 }
1426
1427
1428 // Matrix
1429
1430 wxGraphicsMatrix * 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;
1438 }
1439
1440 wxGraphicsPen* wxGDIPlusRenderer::CreatePen(const wxPen& pen)
1441 {
1442 EnsureIsLoaded();
1443 if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT )
1444 return NULL;
1445 else
1446 return new wxGDIPlusPen( this, pen );
1447 }
1448
1449 wxGraphicsBrush* wxGDIPlusRenderer::CreateBrush(const wxBrush& brush )
1450 {
1451 EnsureIsLoaded();
1452 if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT )
1453 return NULL;
1454 else
1455 return new wxGDIPlusBrush( this, brush );
1456 }
1457
1458 // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2
1459 wxGraphicsBrush* wxGDIPlusRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2,
1460 const wxColour&c1, const wxColour&c2)
1461 {
1462 EnsureIsLoaded();
1463 wxGDIPlusBrush* brush = new wxGDIPlusBrush(this);
1464 brush->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2);
1465 return brush;
1466 }
1467
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
1470 wxGraphicsBrush* 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 }
1478
1479 // sets the font
1480 wxGraphicsFont* 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 }
1488
1489 #endif // wxUSE_GRAPHICS_CONTEXT