]> git.saurik.com Git - wxWidgets.git/blame - src/msw/graphics.cpp
Update ReST docs
[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
95class GDILoader
96{
97public :
98 GDILoader()
99 {
100 m_loaded = false;
101 m_gditoken = NULL;
102 }
103
104 ~GDILoader()
105 {
106 if (m_loaded)
107 {
108 Unload();
109 }
110 }
111 void EnsureIsLoaded()
112 {
113 if (!m_loaded)
114 {
115 Load();
116 }
117 }
118 void Load()
119 {
120 GdiplusStartupInput input;
121 GdiplusStartupOutput output;
122 GdiplusStartup(&m_gditoken,&input,&output);
123 m_loaded = true;
124 }
125 void Unload()
126 {
127 if ( m_gditoken )
128 GdiplusShutdown(m_gditoken);
129 }
130private :
131 bool m_loaded;
132 DWORD m_gditoken;
133
134};
135
136static GDILoader gGDILoader;
137
138class WXDLLEXPORT wxGDIPlusPath : public wxGraphicsPath
139{
6fea499c
SC
140public :
141 wxGDIPlusPath();
142 ~wxGDIPlusPath();
143
144
145 //
146 // These are the path primitives from which everything else can be constructed
147 //
148
149 // begins a new subpath at (x,y)
150 virtual void MoveToPoint( wxDouble x, wxDouble y );
151
152 // adds a straight line from the current point to (x,y)
153 virtual void AddLineToPoint( wxDouble x, wxDouble y );
154
155 // adds a cubic Bezier curve from the current point, using two control points and an end point
156 virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y );
157
158
159 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
160 virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ;
161
162 // gets the last point of the current path, (0,0) if not yet set
163 virtual void GetCurrentPoint( wxDouble& x, wxDouble&y) ;
164
165 // closes the current sub-path
166 virtual void CloseSubpath();
167
168 //
169 // These are convenience functions which - if not available natively will be assembled
170 // using the primitives from above
171 //
172
173 // appends a rectangle as a new closed subpath
174 virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ;
175 /*
176
177 // appends an ellipsis as a new closed subpath fitting the passed rectangle
178 virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ;
179
180 // 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)
181 virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ;
182*/
183
f540e5bd
SC
184 // returns the native path
185 virtual void * GetNativePath() const { return m_path; }
186
187 // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
9f339b18 188 virtual void UnGetNativePath(void * WXUNUSED(path)) {}
f540e5bd 189
6fea499c
SC
190private :
191 GraphicsPath* m_path;
9f339b18 192 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusPath)
6fea499c
SC
193};
194
195class WXDLLEXPORT wxGDIPlusContext : public wxGraphicsContext
196{
6fea499c 197public:
9f339b18
SC
198 wxGDIPlusContext( HDC hdc );
199 wxGDIPlusContext( HWND hwnd );
200 wxGDIPlusContext( Graphics* gr);
6fea499c 201 wxGDIPlusContext();
9f339b18 202
6fea499c
SC
203 virtual ~wxGDIPlusContext();
204
205 virtual void Clip( const wxRegion &region );
539e2795
SC
206 // clips drawings to the rect
207 virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h );
208
209 // resets the clipping to original extent
210 virtual void ResetClip();
211
212 virtual void * GetNativeContext();
213
6fea499c
SC
214 virtual void StrokePath( const wxGraphicsPath *p );
215 virtual void FillPath( const wxGraphicsPath *p , int fillStyle = wxWINDING_RULE );
216
217 virtual wxGraphicsPath* CreatePath();
218 virtual void SetPen( const wxPen &pen );
219 virtual void SetBrush( const wxBrush &brush );
220 virtual void SetLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2) ;
221 virtual void SetRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
222 const wxColour &oColor, const wxColour &cColor);
223
224 virtual void Translate( wxDouble dx , wxDouble dy );
225 virtual void Scale( wxDouble xScale , wxDouble yScale );
226 virtual void Rotate( wxDouble angle );
227
228 virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
229 virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h );
230 virtual void PushState();
231 virtual void PopState();
232
233 virtual void SetFont( const wxFont &font );
234 virtual void SetTextColor( const wxColour &col );
235 virtual void DrawText( const wxString &str, wxDouble x, wxDouble y);
236 virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
237 wxDouble *descent, wxDouble *externalLeading ) const;
238 virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const;
239
240private:
9f339b18
SC
241 void Init();
242 void SetDefaults();
243
6fea499c
SC
244 Graphics* m_context;
245 vector<GraphicsState> m_stateStack;
246 GraphicsState m_state1;
247 GraphicsState m_state2;
248
249 Pen* m_pen;
250 bool m_penTransparent;
251 Image* m_penImage;
252 Brush* m_penBrush;
253
254 Brush* m_brush;
255 bool m_brushTransparent;
256 Image* m_brushImage;
257 GraphicsPath* m_brushPath;
258
259 Brush* m_textBrush;
260 Font* m_font;
261 // wxPen m_pen;
262 // wxBrush m_brush;
9f339b18 263 DECLARE_DYNAMIC_CLASS_NO_COPY(wxGDIPlusContext)
6fea499c
SC
264};
265
9f339b18
SC
266IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusPath,wxGraphicsPath)
267
6fea499c
SC
268wxGDIPlusPath::wxGDIPlusPath()
269{
270 m_path = new GraphicsPath();
271}
272
273wxGDIPlusPath::~wxGDIPlusPath()
274{
275 delete m_path;
276}
277
6fea499c
SC
278//
279// The Primitives
280//
281
282void wxGDIPlusPath::MoveToPoint( wxDouble x , wxDouble y )
283{
284 m_path->StartFigure();
285 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
286}
287
288void wxGDIPlusPath::AddLineToPoint( wxDouble x , wxDouble y )
289{
290 m_path->AddLine((REAL) x,(REAL) y,(REAL) x,(REAL) y);
291}
292
293void wxGDIPlusPath::CloseSubpath()
294{
295 m_path->CloseFigure();
296}
297
298void wxGDIPlusPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y )
299{
300 PointF c1(cx1,cy1);
301 PointF c2(cx2,cy2);
302 PointF end(x,y);
303 PointF start;
304 m_path->GetLastPoint(&start);
305 m_path->AddBezier(start,c1,c2,end);
306}
307
308// gets the last point of the current path, (0,0) if not yet set
309void wxGDIPlusPath::GetCurrentPoint( wxDouble& x, wxDouble&y)
310{
311 PointF start;
312 m_path->GetLastPoint(&start);
313 x = start.X ;
314 y = start.Y ;
315}
316
317void wxGDIPlusPath::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise )
318{
319 double sweepAngle = endAngle - startAngle ;
320 if( abs(sweepAngle) >= 2*M_PI)
321 {
322 sweepAngle = 2 * M_PI;
323 }
324 else
325 {
326 if ( clockwise )
327 {
328 if( sweepAngle < 0 )
329 sweepAngle += 2 * M_PI;
330 }
331 else
332 {
333 if( sweepAngle > 0 )
334 sweepAngle -= 2 * M_PI;
335
336 }
337 }
338 m_path->AddArc((REAL) (x-r),(REAL) (y-r),(REAL) (2*r),(REAL) (2*r),RadToDeg(startAngle),RadToDeg(sweepAngle));
339}
340
341void wxGDIPlusPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
342{
343 m_path->AddRectangle(RectF(x,y,w,h));
344}
345
9f339b18
SC
346//-----------------------------------------------------------------------------
347// wxGDIPlusContext implementation
348//-----------------------------------------------------------------------------
349
350IMPLEMENT_DYNAMIC_CLASS(wxGDIPlusContext,wxGraphicsContext)
351
352wxGDIPlusContext::wxGDIPlusContext( HDC hdc )
6fea499c 353{
9f339b18
SC
354 Init();
355 m_context = new Graphics( hdc);
356 SetDefaults();
6fea499c
SC
357}
358
9f339b18
SC
359wxGDIPlusContext::wxGDIPlusContext( HWND hwnd )
360{
361 Init();
362 m_context = new Graphics( hwnd);
363 SetDefaults();
364}
6fea499c 365
9f339b18
SC
366wxGDIPlusContext::wxGDIPlusContext( Graphics* gr )
367{
368 Init();
369 m_context = gr;
370 SetDefaults();
371}
6fea499c 372
9f339b18 373void wxGDIPlusContext::Init()
6fea499c
SC
374{
375 gGDILoader.EnsureIsLoaded();
9f339b18
SC
376 m_context = NULL;
377 m_state1 = 0;
378 m_state2= 0;
379
380 m_pen = NULL;
381 m_penTransparent = true;
382 m_penImage = NULL;
383 m_penBrush = NULL;
384
385 m_brush = NULL;
386 m_brushTransparent = true;
387 m_brushImage = NULL;
388 m_brushPath = NULL;
389
390 m_textBrush = NULL;
391 m_font = NULL;
392}
393
394void wxGDIPlusContext::SetDefaults()
395{
f868f886 396 m_context->SetSmoothingMode(SmoothingModeHighQuality);
6fea499c
SC
397 m_state1 = m_context->Save();
398 m_state2 = m_context->Save();
6fea499c
SC
399 // set defaults
400
401 m_penTransparent = false;
402 m_pen = new Pen((ARGB)Color::Black);
403 m_penImage = NULL;
404 m_penBrush = NULL;
405
406 m_brushTransparent = false;
407 m_brush = new SolidBrush((ARGB)Color::White);
408 m_brushImage = NULL;
409 m_brushPath = NULL;
410 m_textBrush = new SolidBrush((ARGB)Color::Black);
411 m_font = new Font( L"Arial" , 9 , FontStyleRegular );
412}
413
414wxGDIPlusContext::~wxGDIPlusContext()
415{
416 if ( m_context )
417 {
418 m_context->Restore( m_state2 );
419 m_context->Restore( m_state1 );
420 delete m_context;
421 delete m_pen;
422 delete m_penImage;
423 delete m_penBrush;
424 delete m_brush;
425 delete m_brushImage;
426 delete m_brushPath;
427 delete m_textBrush;
428 delete m_font;
429 }
430}
431
432
9f339b18 433void wxGDIPlusContext::Clip( const wxRegion &region )
6fea499c 434{
9f339b18 435 m_context->SetClip((HRGN)region.GetHRGN(),CombineModeIntersect);
539e2795
SC
436}
437
438void wxGDIPlusContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
439{
9f339b18 440 m_context->SetClip(RectF(x,y,w,h),CombineModeIntersect);
539e2795
SC
441}
442
443void wxGDIPlusContext::ResetClip()
444{
9f339b18 445 m_context->ResetClip();
6fea499c
SC
446}
447
f540e5bd 448void wxGDIPlusContext::StrokePath( const wxGraphicsPath *path )
6fea499c
SC
449{
450 if ( m_penTransparent )
451 return;
452
f540e5bd 453 m_context->DrawPath( m_pen , (GraphicsPath*) path->GetNativePath() );
6fea499c
SC
454}
455
f540e5bd 456void wxGDIPlusContext::FillPath( const wxGraphicsPath *path , int fillStyle )
6fea499c
SC
457{
458 if ( !m_brushTransparent )
459 {
f540e5bd
SC
460 ((GraphicsPath*) path->GetNativePath())->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
461 m_context->FillPath( m_brush , (GraphicsPath*) path->GetNativePath());
6fea499c
SC
462 }
463}
464
465wxGraphicsPath* wxGDIPlusContext::CreatePath()
466{
467 return new wxGDIPlusPath();
468}
469
470void wxGDIPlusContext::Rotate( wxDouble angle )
471{
ebbe5c66 472 m_context->RotateTransform( RadToDeg(angle) );
6fea499c
SC
473}
474
475void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy )
476{
477 m_context->TranslateTransform( dx , dy );
478}
479
480void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale )
481{
6fea499c 482 m_context->ScaleTransform(xScale,yScale);
6fea499c
SC
483}
484
485void wxGDIPlusContext::PushState()
486{
487 GraphicsState state = m_context->Save();
488 m_stateStack.push_back(state);
489}
490
491void wxGDIPlusContext::PopState()
492{
493 GraphicsState state = m_stateStack.back();
494 m_stateStack.pop_back();
495 m_context->Restore(state);
496}
497
498void wxGDIPlusContext::SetTextColor( const wxColour &col )
499{
500 delete m_textBrush;
501 m_textBrush = new SolidBrush( Color( col.Alpha() , col.Red() ,
502 col.Green() , col.Blue() ));
503}
504
505void wxGDIPlusContext::SetPen( const wxPen &pen )
506{
507 m_penTransparent = pen.GetStyle() == wxTRANSPARENT;
508 if ( m_penTransparent )
509 return;
510
511 m_pen->SetColor( Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
512 pen.GetColour().Green() , pen.GetColour().Blue() ) );
513
514 // TODO: * m_dc->m_scaleX
515 double penWidth = pen.GetWidth();
516 if (penWidth <= 0.0)
517 penWidth = 0.1;
518
519 m_pen->SetWidth(penWidth);
520
521 LineCap cap;
522 switch ( pen.GetCap() )
523 {
524 case wxCAP_ROUND :
525 cap = LineCapRound;
526 break;
527
528 case wxCAP_PROJECTING :
529 cap = LineCapSquare;
530 break;
531
532 case wxCAP_BUTT :
533 cap = LineCapFlat; // TODO verify
534 break;
535
536 default :
537 cap = LineCapFlat;
538 break;
539 }
540 m_pen->SetLineCap(cap,cap, DashCapFlat);
541
542 LineJoin join;
543 switch ( pen.GetJoin() )
544 {
545 case wxJOIN_BEVEL :
546 join = LineJoinBevel;
547 break;
548
549 case wxJOIN_MITER :
550 join = LineJoinMiter;
551 break;
552
553 case wxJOIN_ROUND :
554 join = LineJoinRound;
555 break;
556
557 default :
558 join = LineJoinMiter;
559 break;
560 }
561
562 m_pen->SetLineJoin(join);
563
564 m_pen->SetDashStyle(DashStyleSolid);
565
566 DashStyle dashStyle = DashStyleSolid;
567 switch ( pen.GetStyle() )
568 {
569 case wxSOLID :
570 break;
571
572 case wxDOT :
573 dashStyle = DashStyleDot;
574 break;
575
576 case wxLONG_DASH :
577 dashStyle = DashStyleDash; // TODO verify
578 break;
579
580 case wxSHORT_DASH :
581 dashStyle = DashStyleDash;
582 break;
583
584 case wxDOT_DASH :
585 dashStyle = DashStyleDashDot;
586 break;
587 case wxUSER_DASH :
588 {
589 dashStyle = DashStyleCustom;
590 wxDash *dashes;
591 int count = pen.GetDashes( &dashes );
592 if ((dashes != NULL) && (count > 0))
593 {
594 REAL *userLengths = new REAL[count];
595 for ( int i = 0; i < count; ++i )
596 {
597 userLengths[i] = dashes[i];
598 }
599 m_pen->SetDashPattern( userLengths, count);
600 delete[] userLengths;
601 }
602 }
603 break;
604 case wxSTIPPLE :
605 {
606 wxBitmap* bmp = pen.GetStipple();
607 if ( bmp && bmp->Ok() )
608 {
609 wxDELETE( m_penImage );
610 wxDELETE( m_penBrush );
611 m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
612 m_penBrush = new TextureBrush(m_penImage);
613 m_pen->SetBrush( m_penBrush );
614 }
615
616 }
617 break;
618 default :
619 if ( pen.GetStyle() >= wxFIRST_HATCH && pen.GetStyle() <= wxLAST_HATCH )
620 {
621 wxDELETE( m_penBrush );
622 HatchStyle style = HatchStyleHorizontal;
623 switch( pen.GetStyle() )
624 {
625 case wxBDIAGONAL_HATCH :
626 style = HatchStyleBackwardDiagonal;
627 break ;
628 case wxCROSSDIAG_HATCH :
629 style = HatchStyleDiagonalCross;
630 break ;
631 case wxFDIAGONAL_HATCH :
632 style = HatchStyleForwardDiagonal;
633 break ;
634 case wxCROSS_HATCH :
635 style = HatchStyleCross;
636 break ;
637 case wxHORIZONTAL_HATCH :
638 style = HatchStyleHorizontal;
639 break ;
640 case wxVERTICAL_HATCH :
641 style = HatchStyleVertical;
642 break ;
643
644 }
645 m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
646 pen.GetColour().Green() , pen.GetColour().Blue() ), Color::Transparent );
647 m_pen->SetBrush( m_penBrush );
648 }
649 break;
650 }
651 if ( dashStyle != DashStyleSolid )
652 m_pen->SetDashStyle(dashStyle);
653}
654
655void wxGDIPlusContext::SetBrush( const wxBrush &brush )
656{
657// m_brush = brush;
658 if ( m_context == NULL )
659 return;
660
661 m_brushTransparent = brush.GetStyle() == wxTRANSPARENT;
662
663 if ( m_brushTransparent )
664 return;
665
666 wxDELETE(m_brush);
667
668 if ( brush.GetStyle() == wxSOLID)
669 {
670 m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
671 brush.GetColour().Green() , brush.GetColour().Blue() ) );
672 }
673 else if ( brush.IsHatch() )
674 {
675 HatchStyle style = HatchStyleHorizontal;
676 switch( brush.GetStyle() )
677 {
678 case wxBDIAGONAL_HATCH :
679 style = HatchStyleBackwardDiagonal;
680 break ;
681 case wxCROSSDIAG_HATCH :
682 style = HatchStyleDiagonalCross;
683 break ;
684 case wxFDIAGONAL_HATCH :
685 style = HatchStyleForwardDiagonal;
686 break ;
687 case wxCROSS_HATCH :
688 style = HatchStyleCross;
689 break ;
690 case wxHORIZONTAL_HATCH :
691 style = HatchStyleHorizontal;
692 break ;
693 case wxVERTICAL_HATCH :
694 style = HatchStyleVertical;
695 break ;
696
697 }
698 m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
699 brush.GetColour().Green() , brush.GetColour().Blue() ), Color::Transparent );
700 }
701 else
702 {
703 wxBitmap* bmp = brush.GetStipple();
704 if ( bmp && bmp->Ok() )
705 {
706 wxDELETE( m_brushImage );
707 m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
708 m_brush = new TextureBrush(m_brushImage);
709 }
710 }
711}
712
713void wxGDIPlusContext::SetLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2)
714{
715 m_brushTransparent = false ;
716
717 wxDELETE(m_brush);
718
719 m_brush = new LinearGradientBrush( PointF( x1,y1) , PointF( x2,y2),
720 Color( c1.Alpha(), c1.Red(),c1.Green() , c1.Blue() ),
721 Color( c2.Alpha(), c2.Red(),c2.Green() , c2.Blue() ));
722}
723
724void wxGDIPlusContext::SetRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
725 const wxColour &oColor, const wxColour &cColor)
726{
727 m_brushTransparent = false ;
728
729 wxDELETE(m_brush);
730 wxDELETE(m_brushPath);
731
732 // Create a path that consists of a single circle.
733 m_brushPath = new GraphicsPath();
734 m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius), (REAL)(2*radius), (REAL)(2*radius));
735
736 PathGradientBrush *b = new PathGradientBrush(m_brushPath);
737 m_brush = b;
738 b->SetCenterPoint( PointF(xo,yo));
739 b->SetCenterColor(Color( oColor.Alpha(), oColor.Red(),oColor.Green() , oColor.Blue() ));
740
741 Color colors[] = {Color( cColor.Alpha(), cColor.Red(),cColor.Green() , cColor.Blue() )};
742 int count = 1;
743 b->SetSurroundColors(colors, &count);
744}
745
fe31db81
SC
746// the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
747// premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
748// bytes as parameter
749
6fea499c
SC
750void wxGDIPlusContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
751{
fe31db81
SC
752 Bitmap* image = NULL;
753 Bitmap* helper = NULL;
754 if ( bmp.GetMask() )
755 {
756 Bitmap interim((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE()) ;
757
758 size_t width = interim.GetWidth();
759 size_t height = interim.GetHeight();
760 Rect bounds(0,0,width,height);
761
762 image = new Bitmap(width,height,PixelFormat32bppPARGB) ;
763
764 Bitmap interimMask((HBITMAP)bmp.GetMask()->GetMaskBitmap(),NULL);
765 wxASSERT(interimMask.GetPixelFormat() == PixelFormat1bppIndexed);
766
767 BitmapData dataMask ;
768 interimMask.LockBits(&bounds,ImageLockModeRead,
769 interimMask.GetPixelFormat(),&dataMask);
770
771
772 BitmapData imageData ;
773 image->LockBits(&bounds,ImageLockModeWrite, PixelFormat32bppPARGB, &imageData);
774
775 BYTE maskPattern = 0 ;
776 BYTE maskByte = 0;
777 size_t maskIndex ;
778
779 for ( size_t y = 0 ; y < height ; ++y)
780 {
781 maskIndex = 0 ;
782 for( size_t x = 0 ; x < width; ++x)
783 {
784 if ( x % 8 == 0)
785 {
786 maskPattern = 0x80;
787 maskByte = *((BYTE*)dataMask.Scan0 + dataMask.Stride*y + maskIndex);
788 maskIndex++;
789 }
790 else
791 maskPattern = maskPattern >> 1;
792
793 ARGB *dest = (ARGB*)((BYTE*)imageData.Scan0 + imageData.Stride*y + x*4);
794 if ( (maskByte & maskPattern) == 0 )
795 *dest = 0x00000000;
796 else
797 {
798 Color c ;
799 interim.GetPixel(x,y,&c) ;
800 *dest = (c.GetValue() | Color::AlphaMask);
801 }
802 }
803 }
804
805 image->UnlockBits(&imageData);
806
807 interimMask.UnlockBits(&dataMask);
808 interim.UnlockBits(&dataMask);
809 }
810 else
811 {
812 image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE());
813 if ( GetPixelFormatSize(image->GetPixelFormat()) == 32 )
814 {
815 size_t width = image->GetWidth();
816 size_t height = image->GetHeight();
817 Rect bounds(0,0,width,height);
818 BitmapData data ;
819
820 helper = image ;
821 image = NULL ;
822 helper->LockBits(&bounds, ImageLockModeRead,
823 helper->GetPixelFormat(),&data);
824
825 image = new Bitmap(data.Width, data.Height, data.Stride,
826 PixelFormat32bppARGB , (BYTE*) data.Scan0);
827
828 helper->UnlockBits(&data);
829 }
830 }
831 if ( image )
832 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
6fea499c 833 delete image ;
fe31db81 834 delete helper ;
6fea499c
SC
835}
836
837void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
838{
fe31db81
SC
839 HICON hIcon = (HICON)icon.GetHICON();
840 ICONINFO iconInfo ;
841 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
842 if (!GetIconInfo(hIcon,&iconInfo))
843 return;
844
845 BITMAP iconBmpData ;
846 GetObject(iconInfo.hbmColor,sizeof(BITMAP),&iconBmpData);
847 Bitmap interim(iconInfo.hbmColor,NULL);
848
849 Bitmap* image = NULL ;
850
851 if( GetPixelFormatSize(interim.GetPixelFormat())!= 32 )
852 {
853 image = Bitmap::FromHICON(hIcon);
854 }
855 else
856 {
857 size_t width = interim.GetWidth();
858 size_t height = interim.GetHeight();
859 Rect bounds(0,0,width,height);
860 BitmapData data ;
861
862 interim.LockBits(&bounds, ImageLockModeRead,
863 interim.GetPixelFormat(),&data);
864 image = new Bitmap(data.Width, data.Height, data.Stride,
865 PixelFormat32bppARGB , (BYTE*) data.Scan0);
866 interim.UnlockBits(&data);
867 }
868
6fea499c 869 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
fe31db81 870
6fea499c 871 delete image ;
fe31db81
SC
872 DeleteObject(iconInfo.hbmColor);
873 DeleteObject(iconInfo.hbmMask);
6fea499c
SC
874}
875
876
877void wxGDIPlusContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
878{
879 if ( str.IsEmpty())
880 return ;
881
882 wxWCharBuffer s = str.wc_str( *wxConvUI );
883 m_context->DrawString( s , -1 , m_font , PointF( x , y ) , m_textBrush );
884 // TODO m_backgroundMode == wxSOLID
885}
886
887void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
888 wxDouble *descent, wxDouble *externalLeading ) const
889{
890 wxWCharBuffer s = str.wc_str( *wxConvUI );
891 FontFamily ffamily ;
892
893 m_font->GetFamily(&ffamily) ;
894
895 REAL factorY = m_context->GetDpiY() / 72.0 ;
896
897 REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
898 m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
899 REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
900 m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
901 REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
902 m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
903
904 if ( height )
905 *height = rHeight * factorY + 0.5 ;
906 if ( descent )
907 *descent = rDescent * factorY + 0.5 ;
908 if ( externalLeading )
909 *externalLeading = (rHeight - rAscent - rDescent) * factorY + 0.5 ;
910 // measuring empty strings is not guaranteed, so do it by hand
911 if ( str.IsEmpty())
912 {
913 if ( width )
914 *width = 0 ;
915 }
916 else
917 {
918 // MeasureString does return a rectangle that is way too large, so it is
919 // not usable here
920 RectF layoutRect(0,0, 100000.0f, 100000.0f);
921 StringFormat strFormat;
922 CharacterRange strRange(0,wcslen(s));
923 strFormat.SetMeasurableCharacterRanges(1,&strRange);
924 Region region ;
925 m_context->MeasureCharacterRanges(s, -1 , m_font,layoutRect, &strFormat,1,&region) ;
926 RectF bbox ;
927 region.GetBounds(&bbox,m_context);
928 if ( width )
929 *width = bbox.GetRight()-bbox.GetLeft()+0.5;
930 }
931}
932
933void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
934{
935 widths.Empty();
936 widths.Add(0, text.length());
937
938 if (text.empty())
939 return;
940
941 wxWCharBuffer ws = text.wc_str( *wxConvUI );
942 size_t len = wcslen( ws ) ;
943 wxASSERT_MSG(text.length() == len , wxT("GetPartialTextExtents not yet implemented for multichar situations"));
944
945 RectF layoutRect(0,0, 100000.0f, 100000.0f);
946 StringFormat strFormat;
947
948 CharacterRange* ranges = new CharacterRange[len] ;
949 Region* regions = new Region[len];
950 for( size_t i = 0 ; i < len ; ++i)
951 {
952 ranges[i].First = i ;
953 ranges[i].Length = 1 ;
954 }
955 strFormat.SetMeasurableCharacterRanges(len,ranges);
956 m_context->MeasureCharacterRanges(ws, -1 , m_font,layoutRect, &strFormat,1,regions) ;
957
958 RectF bbox ;
959 for ( size_t i = 0 ; i < len ; ++i)
960 {
961 regions[i].GetBounds(&bbox,m_context);
962 widths[i] = bbox.GetRight()-bbox.GetLeft();
963 }
964}
965
966void wxGDIPlusContext::SetFont( const wxFont &font )
967{
968 wxASSERT( font.Ok());
969 delete m_font;
970 wxWCharBuffer s = font.GetFaceName().wc_str( *wxConvUI );
971 int size = font.GetPointSize();
972 int style = FontStyleRegular;
973 if ( font.GetStyle() == wxFONTSTYLE_ITALIC )
974 style |= FontStyleItalic;
975 if ( font.GetUnderlined() )
976 style |= FontStyleUnderline;
977 if ( font.GetWeight() == wxFONTWEIGHT_BOLD )
978 style |= FontStyleBold;
979 m_font = new Font( s , size , style );
980}
981
13bc5380 982void* wxGDIPlusContext::GetNativeContext()
539e2795
SC
983{
984 return m_context;
985}
986
6fea499c
SC
987wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc)
988{
989 return new wxGDIPlusContext( (HDC) dc.GetHDC() );
990}
7ba86d93 991
539e2795
SC
992wxGraphicsContext* wxGraphicsContext::Create( wxWindow * window )
993{
9f339b18 994 return new wxGDIPlusContext( (HWND) window->GetHWND() );
539e2795
SC
995}
996
997wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context )
998{
9f339b18 999 return new wxGDIPlusContext( (Graphics*) context );
539e2795
SC
1000}
1001
1002
7ba86d93
RD
1003
1004#endif // wxUSE_GRAPHICS_CONTEXT