]> git.saurik.com Git - wxWidgets.git/blame - src/msw/graphics.cpp
non-PCH build fix (according to Tinderbox).
[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
e49c065d
RD
373wxGDIPlusContext::wxGDIPlusContext()
374{
375 Init();
376}
377
9f339b18 378void wxGDIPlusContext::Init()
6fea499c
SC
379{
380 gGDILoader.EnsureIsLoaded();
9f339b18
SC
381 m_context = NULL;
382 m_state1 = 0;
383 m_state2= 0;
384
385 m_pen = NULL;
386 m_penTransparent = true;
387 m_penImage = NULL;
388 m_penBrush = NULL;
389
390 m_brush = NULL;
391 m_brushTransparent = true;
392 m_brushImage = NULL;
393 m_brushPath = NULL;
394
395 m_textBrush = NULL;
396 m_font = NULL;
397}
398
399void wxGDIPlusContext::SetDefaults()
400{
f868f886 401 m_context->SetSmoothingMode(SmoothingModeHighQuality);
6fea499c
SC
402 m_state1 = m_context->Save();
403 m_state2 = m_context->Save();
6fea499c
SC
404 // set defaults
405
406 m_penTransparent = false;
407 m_pen = new Pen((ARGB)Color::Black);
408 m_penImage = NULL;
409 m_penBrush = NULL;
410
411 m_brushTransparent = false;
412 m_brush = new SolidBrush((ARGB)Color::White);
413 m_brushImage = NULL;
414 m_brushPath = NULL;
415 m_textBrush = new SolidBrush((ARGB)Color::Black);
416 m_font = new Font( L"Arial" , 9 , FontStyleRegular );
417}
418
419wxGDIPlusContext::~wxGDIPlusContext()
420{
421 if ( m_context )
422 {
423 m_context->Restore( m_state2 );
424 m_context->Restore( m_state1 );
425 delete m_context;
426 delete m_pen;
427 delete m_penImage;
428 delete m_penBrush;
429 delete m_brush;
430 delete m_brushImage;
431 delete m_brushPath;
432 delete m_textBrush;
433 delete m_font;
434 }
435}
436
437
9f339b18 438void wxGDIPlusContext::Clip( const wxRegion &region )
6fea499c 439{
9f339b18 440 m_context->SetClip((HRGN)region.GetHRGN(),CombineModeIntersect);
539e2795
SC
441}
442
443void wxGDIPlusContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
444{
9f339b18 445 m_context->SetClip(RectF(x,y,w,h),CombineModeIntersect);
539e2795
SC
446}
447
448void wxGDIPlusContext::ResetClip()
449{
9f339b18 450 m_context->ResetClip();
6fea499c
SC
451}
452
f540e5bd 453void wxGDIPlusContext::StrokePath( const wxGraphicsPath *path )
6fea499c
SC
454{
455 if ( m_penTransparent )
456 return;
457
f540e5bd 458 m_context->DrawPath( m_pen , (GraphicsPath*) path->GetNativePath() );
6fea499c
SC
459}
460
f540e5bd 461void wxGDIPlusContext::FillPath( const wxGraphicsPath *path , int fillStyle )
6fea499c
SC
462{
463 if ( !m_brushTransparent )
464 {
f540e5bd
SC
465 ((GraphicsPath*) path->GetNativePath())->SetFillMode( fillStyle == wxODDEVEN_RULE ? FillModeAlternate : FillModeWinding);
466 m_context->FillPath( m_brush , (GraphicsPath*) path->GetNativePath());
6fea499c
SC
467 }
468}
469
470wxGraphicsPath* wxGDIPlusContext::CreatePath()
471{
472 return new wxGDIPlusPath();
473}
474
475void wxGDIPlusContext::Rotate( wxDouble angle )
476{
ebbe5c66 477 m_context->RotateTransform( RadToDeg(angle) );
6fea499c
SC
478}
479
480void wxGDIPlusContext::Translate( wxDouble dx , wxDouble dy )
481{
482 m_context->TranslateTransform( dx , dy );
483}
484
485void wxGDIPlusContext::Scale( wxDouble xScale , wxDouble yScale )
486{
6fea499c 487 m_context->ScaleTransform(xScale,yScale);
6fea499c
SC
488}
489
490void wxGDIPlusContext::PushState()
491{
492 GraphicsState state = m_context->Save();
493 m_stateStack.push_back(state);
494}
495
496void wxGDIPlusContext::PopState()
497{
498 GraphicsState state = m_stateStack.back();
499 m_stateStack.pop_back();
500 m_context->Restore(state);
501}
502
503void wxGDIPlusContext::SetTextColor( const wxColour &col )
504{
505 delete m_textBrush;
506 m_textBrush = new SolidBrush( Color( col.Alpha() , col.Red() ,
507 col.Green() , col.Blue() ));
508}
509
510void wxGDIPlusContext::SetPen( const wxPen &pen )
511{
512 m_penTransparent = pen.GetStyle() == wxTRANSPARENT;
513 if ( m_penTransparent )
514 return;
515
516 m_pen->SetColor( Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
517 pen.GetColour().Green() , pen.GetColour().Blue() ) );
518
519 // TODO: * m_dc->m_scaleX
520 double penWidth = pen.GetWidth();
521 if (penWidth <= 0.0)
522 penWidth = 0.1;
523
524 m_pen->SetWidth(penWidth);
525
526 LineCap cap;
527 switch ( pen.GetCap() )
528 {
529 case wxCAP_ROUND :
530 cap = LineCapRound;
531 break;
532
533 case wxCAP_PROJECTING :
534 cap = LineCapSquare;
535 break;
536
537 case wxCAP_BUTT :
538 cap = LineCapFlat; // TODO verify
539 break;
540
541 default :
542 cap = LineCapFlat;
543 break;
544 }
545 m_pen->SetLineCap(cap,cap, DashCapFlat);
546
547 LineJoin join;
548 switch ( pen.GetJoin() )
549 {
550 case wxJOIN_BEVEL :
551 join = LineJoinBevel;
552 break;
553
554 case wxJOIN_MITER :
555 join = LineJoinMiter;
556 break;
557
558 case wxJOIN_ROUND :
559 join = LineJoinRound;
560 break;
561
562 default :
563 join = LineJoinMiter;
564 break;
565 }
566
567 m_pen->SetLineJoin(join);
568
569 m_pen->SetDashStyle(DashStyleSolid);
570
571 DashStyle dashStyle = DashStyleSolid;
572 switch ( pen.GetStyle() )
573 {
574 case wxSOLID :
575 break;
576
577 case wxDOT :
578 dashStyle = DashStyleDot;
579 break;
580
581 case wxLONG_DASH :
582 dashStyle = DashStyleDash; // TODO verify
583 break;
584
585 case wxSHORT_DASH :
586 dashStyle = DashStyleDash;
587 break;
588
589 case wxDOT_DASH :
590 dashStyle = DashStyleDashDot;
591 break;
592 case wxUSER_DASH :
593 {
594 dashStyle = DashStyleCustom;
595 wxDash *dashes;
596 int count = pen.GetDashes( &dashes );
597 if ((dashes != NULL) && (count > 0))
598 {
599 REAL *userLengths = new REAL[count];
600 for ( int i = 0; i < count; ++i )
601 {
602 userLengths[i] = dashes[i];
603 }
604 m_pen->SetDashPattern( userLengths, count);
605 delete[] userLengths;
606 }
607 }
608 break;
609 case wxSTIPPLE :
610 {
611 wxBitmap* bmp = pen.GetStipple();
612 if ( bmp && bmp->Ok() )
613 {
614 wxDELETE( m_penImage );
615 wxDELETE( m_penBrush );
616 m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
617 m_penBrush = new TextureBrush(m_penImage);
618 m_pen->SetBrush( m_penBrush );
619 }
620
621 }
622 break;
623 default :
624 if ( pen.GetStyle() >= wxFIRST_HATCH && pen.GetStyle() <= wxLAST_HATCH )
625 {
626 wxDELETE( m_penBrush );
627 HatchStyle style = HatchStyleHorizontal;
628 switch( pen.GetStyle() )
629 {
630 case wxBDIAGONAL_HATCH :
631 style = HatchStyleBackwardDiagonal;
632 break ;
633 case wxCROSSDIAG_HATCH :
634 style = HatchStyleDiagonalCross;
635 break ;
636 case wxFDIAGONAL_HATCH :
637 style = HatchStyleForwardDiagonal;
638 break ;
639 case wxCROSS_HATCH :
640 style = HatchStyleCross;
641 break ;
642 case wxHORIZONTAL_HATCH :
643 style = HatchStyleHorizontal;
644 break ;
645 case wxVERTICAL_HATCH :
646 style = HatchStyleVertical;
647 break ;
648
649 }
650 m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() ,
651 pen.GetColour().Green() , pen.GetColour().Blue() ), Color::Transparent );
652 m_pen->SetBrush( m_penBrush );
653 }
654 break;
655 }
656 if ( dashStyle != DashStyleSolid )
657 m_pen->SetDashStyle(dashStyle);
658}
659
660void wxGDIPlusContext::SetBrush( const wxBrush &brush )
661{
662// m_brush = brush;
663 if ( m_context == NULL )
664 return;
665
666 m_brushTransparent = brush.GetStyle() == wxTRANSPARENT;
667
668 if ( m_brushTransparent )
669 return;
670
671 wxDELETE(m_brush);
672
673 if ( brush.GetStyle() == wxSOLID)
674 {
675 m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
676 brush.GetColour().Green() , brush.GetColour().Blue() ) );
677 }
678 else if ( brush.IsHatch() )
679 {
680 HatchStyle style = HatchStyleHorizontal;
681 switch( brush.GetStyle() )
682 {
683 case wxBDIAGONAL_HATCH :
684 style = HatchStyleBackwardDiagonal;
685 break ;
686 case wxCROSSDIAG_HATCH :
687 style = HatchStyleDiagonalCross;
688 break ;
689 case wxFDIAGONAL_HATCH :
690 style = HatchStyleForwardDiagonal;
691 break ;
692 case wxCROSS_HATCH :
693 style = HatchStyleCross;
694 break ;
695 case wxHORIZONTAL_HATCH :
696 style = HatchStyleHorizontal;
697 break ;
698 case wxVERTICAL_HATCH :
699 style = HatchStyleVertical;
700 break ;
701
702 }
703 m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() ,
704 brush.GetColour().Green() , brush.GetColour().Blue() ), Color::Transparent );
705 }
706 else
707 {
708 wxBitmap* bmp = brush.GetStipple();
709 if ( bmp && bmp->Ok() )
710 {
711 wxDELETE( m_brushImage );
712 m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE());
713 m_brush = new TextureBrush(m_brushImage);
714 }
715 }
716}
717
718void wxGDIPlusContext::SetLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, const wxColour&c1, const wxColour&c2)
719{
720 m_brushTransparent = false ;
721
722 wxDELETE(m_brush);
723
724 m_brush = new LinearGradientBrush( PointF( x1,y1) , PointF( x2,y2),
725 Color( c1.Alpha(), c1.Red(),c1.Green() , c1.Blue() ),
726 Color( c2.Alpha(), c2.Red(),c2.Green() , c2.Blue() ));
727}
728
729void wxGDIPlusContext::SetRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius,
730 const wxColour &oColor, const wxColour &cColor)
731{
732 m_brushTransparent = false ;
733
734 wxDELETE(m_brush);
735 wxDELETE(m_brushPath);
736
737 // Create a path that consists of a single circle.
738 m_brushPath = new GraphicsPath();
739 m_brushPath->AddEllipse( (REAL)(xc-radius), (REAL)(yc-radius), (REAL)(2*radius), (REAL)(2*radius));
740
741 PathGradientBrush *b = new PathGradientBrush(m_brushPath);
742 m_brush = b;
743 b->SetCenterPoint( PointF(xo,yo));
744 b->SetCenterColor(Color( oColor.Alpha(), oColor.Red(),oColor.Green() , oColor.Blue() ));
745
746 Color colors[] = {Color( cColor.Alpha(), cColor.Red(),cColor.Green() , cColor.Blue() )};
747 int count = 1;
748 b->SetSurroundColors(colors, &count);
749}
750
fe31db81
SC
751// the built-in conversions functions create non-premultiplied bitmaps, while GDIPlus needs them in the
752// premultiplied format, therefore in the failing cases we create a new bitmap using the non-premultiplied
753// bytes as parameter
754
6fea499c
SC
755void wxGDIPlusContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
756{
fe31db81
SC
757 Bitmap* image = NULL;
758 Bitmap* helper = NULL;
759 if ( bmp.GetMask() )
760 {
761 Bitmap interim((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE()) ;
762
763 size_t width = interim.GetWidth();
764 size_t height = interim.GetHeight();
765 Rect bounds(0,0,width,height);
766
767 image = new Bitmap(width,height,PixelFormat32bppPARGB) ;
768
769 Bitmap interimMask((HBITMAP)bmp.GetMask()->GetMaskBitmap(),NULL);
770 wxASSERT(interimMask.GetPixelFormat() == PixelFormat1bppIndexed);
771
772 BitmapData dataMask ;
773 interimMask.LockBits(&bounds,ImageLockModeRead,
774 interimMask.GetPixelFormat(),&dataMask);
775
776
777 BitmapData imageData ;
778 image->LockBits(&bounds,ImageLockModeWrite, PixelFormat32bppPARGB, &imageData);
779
780 BYTE maskPattern = 0 ;
781 BYTE maskByte = 0;
782 size_t maskIndex ;
783
784 for ( size_t y = 0 ; y < height ; ++y)
785 {
786 maskIndex = 0 ;
787 for( size_t x = 0 ; x < width; ++x)
788 {
789 if ( x % 8 == 0)
790 {
791 maskPattern = 0x80;
792 maskByte = *((BYTE*)dataMask.Scan0 + dataMask.Stride*y + maskIndex);
793 maskIndex++;
794 }
795 else
796 maskPattern = maskPattern >> 1;
797
798 ARGB *dest = (ARGB*)((BYTE*)imageData.Scan0 + imageData.Stride*y + x*4);
799 if ( (maskByte & maskPattern) == 0 )
800 *dest = 0x00000000;
801 else
802 {
803 Color c ;
804 interim.GetPixel(x,y,&c) ;
805 *dest = (c.GetValue() | Color::AlphaMask);
806 }
807 }
808 }
809
810 image->UnlockBits(&imageData);
811
812 interimMask.UnlockBits(&dataMask);
813 interim.UnlockBits(&dataMask);
814 }
815 else
816 {
817 image = Bitmap::FromHBITMAP((HBITMAP)bmp.GetHBITMAP(),(HPALETTE)bmp.GetPalette()->GetHPALETTE());
818 if ( GetPixelFormatSize(image->GetPixelFormat()) == 32 )
819 {
820 size_t width = image->GetWidth();
821 size_t height = image->GetHeight();
822 Rect bounds(0,0,width,height);
823 BitmapData data ;
824
825 helper = image ;
826 image = NULL ;
827 helper->LockBits(&bounds, ImageLockModeRead,
828 helper->GetPixelFormat(),&data);
829
830 image = new Bitmap(data.Width, data.Height, data.Stride,
831 PixelFormat32bppARGB , (BYTE*) data.Scan0);
832
833 helper->UnlockBits(&data);
834 }
835 }
836 if ( image )
837 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
6fea499c 838 delete image ;
fe31db81 839 delete helper ;
6fea499c
SC
840}
841
842void wxGDIPlusContext::DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h )
843{
fe31db81
SC
844 HICON hIcon = (HICON)icon.GetHICON();
845 ICONINFO iconInfo ;
846 // IconInfo creates the bitmaps for color and mask, we must dispose of them after use
847 if (!GetIconInfo(hIcon,&iconInfo))
848 return;
849
850 BITMAP iconBmpData ;
851 GetObject(iconInfo.hbmColor,sizeof(BITMAP),&iconBmpData);
852 Bitmap interim(iconInfo.hbmColor,NULL);
853
854 Bitmap* image = NULL ;
855
856 if( GetPixelFormatSize(interim.GetPixelFormat())!= 32 )
857 {
858 image = Bitmap::FromHICON(hIcon);
859 }
860 else
861 {
862 size_t width = interim.GetWidth();
863 size_t height = interim.GetHeight();
864 Rect bounds(0,0,width,height);
865 BitmapData data ;
866
867 interim.LockBits(&bounds, ImageLockModeRead,
868 interim.GetPixelFormat(),&data);
869 image = new Bitmap(data.Width, data.Height, data.Stride,
870 PixelFormat32bppARGB , (BYTE*) data.Scan0);
871 interim.UnlockBits(&data);
872 }
873
6fea499c 874 m_context->DrawImage(image,(REAL) x,(REAL) y,(REAL) w,(REAL) h) ;
fe31db81 875
6fea499c 876 delete image ;
fe31db81
SC
877 DeleteObject(iconInfo.hbmColor);
878 DeleteObject(iconInfo.hbmMask);
6fea499c
SC
879}
880
881
882void wxGDIPlusContext::DrawText( const wxString &str, wxDouble x, wxDouble y )
883{
884 if ( str.IsEmpty())
885 return ;
886
887 wxWCharBuffer s = str.wc_str( *wxConvUI );
888 m_context->DrawString( s , -1 , m_font , PointF( x , y ) , m_textBrush );
889 // TODO m_backgroundMode == wxSOLID
890}
891
892void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height,
893 wxDouble *descent, wxDouble *externalLeading ) const
894{
895 wxWCharBuffer s = str.wc_str( *wxConvUI );
896 FontFamily ffamily ;
897
898 m_font->GetFamily(&ffamily) ;
899
900 REAL factorY = m_context->GetDpiY() / 72.0 ;
901
902 REAL rDescent = ffamily.GetCellDescent(FontStyleRegular) *
903 m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
904 REAL rAscent = ffamily.GetCellAscent(FontStyleRegular) *
905 m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
906 REAL rHeight = ffamily.GetLineSpacing(FontStyleRegular) *
907 m_font->GetSize() / ffamily.GetEmHeight(FontStyleRegular);
908
909 if ( height )
910 *height = rHeight * factorY + 0.5 ;
911 if ( descent )
912 *descent = rDescent * factorY + 0.5 ;
913 if ( externalLeading )
914 *externalLeading = (rHeight - rAscent - rDescent) * factorY + 0.5 ;
915 // measuring empty strings is not guaranteed, so do it by hand
916 if ( str.IsEmpty())
917 {
918 if ( width )
919 *width = 0 ;
920 }
921 else
922 {
923 // MeasureString does return a rectangle that is way too large, so it is
924 // not usable here
925 RectF layoutRect(0,0, 100000.0f, 100000.0f);
926 StringFormat strFormat;
927 CharacterRange strRange(0,wcslen(s));
928 strFormat.SetMeasurableCharacterRanges(1,&strRange);
929 Region region ;
930 m_context->MeasureCharacterRanges(s, -1 , m_font,layoutRect, &strFormat,1,&region) ;
931 RectF bbox ;
932 region.GetBounds(&bbox,m_context);
933 if ( width )
934 *width = bbox.GetRight()-bbox.GetLeft()+0.5;
935 }
936}
937
938void wxGDIPlusContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
939{
940 widths.Empty();
941 widths.Add(0, text.length());
942
943 if (text.empty())
944 return;
945
946 wxWCharBuffer ws = text.wc_str( *wxConvUI );
947 size_t len = wcslen( ws ) ;
948 wxASSERT_MSG(text.length() == len , wxT("GetPartialTextExtents not yet implemented for multichar situations"));
949
950 RectF layoutRect(0,0, 100000.0f, 100000.0f);
951 StringFormat strFormat;
952
953 CharacterRange* ranges = new CharacterRange[len] ;
954 Region* regions = new Region[len];
955 for( size_t i = 0 ; i < len ; ++i)
956 {
957 ranges[i].First = i ;
958 ranges[i].Length = 1 ;
959 }
960 strFormat.SetMeasurableCharacterRanges(len,ranges);
961 m_context->MeasureCharacterRanges(ws, -1 , m_font,layoutRect, &strFormat,1,regions) ;
962
963 RectF bbox ;
964 for ( size_t i = 0 ; i < len ; ++i)
965 {
966 regions[i].GetBounds(&bbox,m_context);
967 widths[i] = bbox.GetRight()-bbox.GetLeft();
968 }
969}
970
971void wxGDIPlusContext::SetFont( const wxFont &font )
972{
973 wxASSERT( font.Ok());
974 delete m_font;
975 wxWCharBuffer s = font.GetFaceName().wc_str( *wxConvUI );
976 int size = font.GetPointSize();
977 int style = FontStyleRegular;
978 if ( font.GetStyle() == wxFONTSTYLE_ITALIC )
979 style |= FontStyleItalic;
980 if ( font.GetUnderlined() )
981 style |= FontStyleUnderline;
982 if ( font.GetWeight() == wxFONTWEIGHT_BOLD )
983 style |= FontStyleBold;
984 m_font = new Font( s , size , style );
985}
986
13bc5380 987void* wxGDIPlusContext::GetNativeContext()
539e2795
SC
988{
989 return m_context;
990}
991
6fea499c
SC
992wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc)
993{
994 return new wxGDIPlusContext( (HDC) dc.GetHDC() );
995}
7ba86d93 996
539e2795
SC
997wxGraphicsContext* wxGraphicsContext::Create( wxWindow * window )
998{
9f339b18 999 return new wxGDIPlusContext( (HWND) window->GetHWND() );
539e2795
SC
1000}
1001
1002wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context )
1003{
9f339b18 1004 return new wxGDIPlusContext( (Graphics*) context );
539e2795
SC
1005}
1006
1007
7ba86d93
RD
1008
1009#endif // wxUSE_GRAPHICS_CONTEXT