]> git.saurik.com Git - wxWidgets.git/blob - src/common/graphcmn.cpp
implement {Create,Clone}RefData for gtk wxBitmap
[wxWidgets.git] / src / common / graphcmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/graphcmn.cpp
3 // Purpose: graphics context methods common to all platforms
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created:
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #if defined(__BORLANDC__)
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_GRAPHICS_CONTEXT
20
21 #include "wx/graphics.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/icon.h"
25 #include "wx/bitmap.h"
26 #include "wx/dcmemory.h"
27 #include "wx/region.h"
28 #endif
29
30 #if !defined(wxMAC_USE_CORE_GRAPHICS_BLEND_MODES)
31 #define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 0
32 #endif
33
34 //-----------------------------------------------------------------------------
35 // constants
36 //-----------------------------------------------------------------------------
37
38 static const double RAD2DEG = 180.0 / M_PI;
39
40 //-----------------------------------------------------------------------------
41 // Local functions
42 //-----------------------------------------------------------------------------
43
44 static inline double DegToRad(double deg)
45 {
46 return (deg * M_PI) / 180.0;
47 }
48
49 //-----------------------------------------------------------------------------
50
51 wxPoint2DDouble wxGraphicsPath::GetCurrentPoint()
52 {
53 wxDouble x,y ;
54 GetCurrentPoint(x,y);
55 return wxPoint2DDouble(x,y);
56 }
57
58 void wxGraphicsPath::MoveToPoint( const wxPoint2DDouble& p)
59 {
60 MoveToPoint( p.m_x , p.m_y);
61 }
62
63 void wxGraphicsPath::AddLineToPoint( const wxPoint2DDouble& p)
64 {
65 AddLineToPoint( p.m_x , p.m_y);
66 }
67
68 void wxGraphicsPath::AddCurveToPoint( const wxPoint2DDouble& c1, const wxPoint2DDouble& c2, const wxPoint2DDouble& e)
69 {
70 AddCurveToPoint(c1.m_x, c1.m_y, c2.m_x, c2.m_y, e.m_x, e.m_y);
71 }
72
73 void wxGraphicsPath::AddArc( const wxPoint2DDouble& c, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise)
74 {
75 AddArc(c.m_x, c.m_y, r, startAngle, endAngle, clockwise);
76 }
77
78 //
79 // Emulations
80 //
81
82 void wxGraphicsPath::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y )
83 {
84 // calculate using degree elevation to a cubic bezier
85 wxPoint2DDouble c1 ;
86 wxPoint2DDouble c2 ;
87
88 wxPoint2DDouble start = GetCurrentPoint() ;
89 wxPoint2DDouble end(x,y);
90 wxPoint2DDouble c(cx,cy);
91 c1 = wxDouble(1/3.0) * start + wxDouble(2/3.0) * c;
92 c2 = wxDouble(2/3.0) * c + wxDouble(1/3.0) * end ;
93 AddCurveToPoint(c1.m_x,c1.m_y,c2.m_x,c2.m_y,x,y);
94 }
95
96 void wxGraphicsPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h )
97 {
98 MoveToPoint(x,y);
99 AddLineToPoint(x,y+h);
100 AddLineToPoint(x+w,y+h);
101 AddLineToPoint(x+w,y);
102 CloseSubpath();
103 }
104
105 void wxGraphicsPath::AddCircle( wxDouble x, wxDouble y, wxDouble r )
106 {
107 MoveToPoint(x+r,y);
108 AddArc( x,y,r,0,2*M_PI,false);
109 CloseSubpath();
110 }
111
112 // 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)
113 void wxGraphicsPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r )
114 {
115 wxPoint2DDouble current = GetCurrentPoint();
116 wxPoint2DDouble p1(x1,y1);
117 wxPoint2DDouble p2(x2,y2);
118
119 wxPoint2DDouble v1 = current - p1 ;
120 v1.Normalize();
121 wxPoint2DDouble v2 = p2 - p1 ;
122 v2.Normalize();
123
124 wxDouble alpha = v1.GetVectorAngle() - v2.GetVectorAngle();
125
126 if ( alpha < 0 )
127 alpha = 360 + alpha ;
128 // TODO obtuse angles
129
130 alpha = DegToRad(alpha);
131
132 wxDouble dist = r / sin(alpha/2) * cos(alpha/2) ;
133 // calculate tangential points
134 wxPoint2DDouble t1 = dist*v1 + p1 ;
135 wxPoint2DDouble t2 = dist*v2 + p1 ;
136
137 wxPoint2DDouble nv1 = v1 ;
138 nv1.SetVectorAngle(v1.GetVectorAngle()-90);
139 wxPoint2DDouble c = t1 + r*nv1;
140
141 wxDouble a1 = v1.GetVectorAngle()+90 ;
142 wxDouble a2 = v2.GetVectorAngle()-90 ;
143
144 AddLineToPoint(t1);
145 AddArc(c.m_x,c.m_y,r,DegToRad(a1),DegToRad(a2),true);
146 AddLineToPoint(p2);
147 }
148
149 //-----------------------------------------------------------------------------
150 // wxGraphicsContext Convenience Methods
151 //-----------------------------------------------------------------------------
152
153 void wxGraphicsContext::DrawPath( const wxGraphicsPath *path, int fillStyle )
154 {
155 FillPath( path , fillStyle );
156 StrokePath( path );
157 }
158
159 void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle )
160 {
161 Translate(x,y) ;
162 Rotate( -angle );
163 DrawText( str , 0, 0 );
164 Rotate( angle );
165 Translate(-x,-y) ;
166 }
167
168 void wxGraphicsContext::StrokeLine( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2)
169 {
170 wxGraphicsPath* path = CreatePath();
171 path->MoveToPoint(x1, y1) ;
172 path->AddLineToPoint( x2, y2 );
173 StrokePath( path );
174 delete path;
175 }
176
177 void wxGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h)
178 {
179 wxGraphicsPath* path = CreatePath();
180 path->AddRectangle( x , y , w , h );
181 DrawPath( path );
182 delete path;
183 }
184
185 void wxGraphicsContext::DrawEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h)
186 {
187 wxGraphicsPath* path = CreatePath();
188 if ( w == h )
189 {
190 path->AddCircle( x+w/2,y+w/2,w/2);
191 DrawPath(path);
192 }
193 else
194 {
195 PushState();
196 Translate(x+w/2,y+h/2);
197 wxDouble factor = ((wxDouble) w) / h ;
198 Scale( factor , 1.0) ;
199 path->AddCircle(0,0,h/2);
200 DrawPath(path);
201 PopState();
202 }
203 delete path;
204 }
205
206 void wxGraphicsContext::DrawRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius)
207 {
208 wxGraphicsPath* path = CreatePath();
209 if ( radius == 0)
210 {
211 path->AddRectangle( x , y , w , h );
212 DrawPath( path );
213 }
214 else
215 {
216 PushState();
217 Translate( x , y );
218
219 path->MoveToPoint(w, h / 2);
220 path->AddArcToPoint(w, h, w / 2, h, radius);
221 path->AddArcToPoint(0, h, 0, h / 2, radius);
222 path->AddArcToPoint(0, 0, w / 2, 0, radius);
223 path->AddArcToPoint(w, 0, w, h / 2, radius);
224 path->CloseSubpath();
225 DrawPath( path );
226 PopState();
227 }
228 delete path;
229 }
230
231 void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *points)
232 {
233 wxASSERT(n > 1);
234 wxGraphicsPath* path = CreatePath();
235 path->MoveToPoint(points[0].m_x, points[0].m_y) ;
236 for ( size_t i = 1 ; i < n; ++i)
237 path->AddLineToPoint( points[i].m_x, points[i].m_y );
238 StrokePath( path );
239 delete path;
240 }
241
242 void wxGraphicsContext::DrawLines( size_t n, const wxPoint2DDouble *points, int fillStyle)
243 {
244 wxASSERT(n > 1);
245 wxGraphicsPath* path = CreatePath();
246 path->MoveToPoint(points[0].m_x, points[0].m_y) ;
247 for ( size_t i = 1 ; i < n; ++i)
248 path->AddLineToPoint( points[i].m_x, points[i].m_y );
249 DrawPath( path , fillStyle);
250 delete path;
251 }
252
253 void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *beginPoints, const wxPoint2DDouble *endPoints)
254 {
255 wxASSERT(n > 0);
256 wxGraphicsPath* path = CreatePath();
257 for ( size_t i = 0 ; i < n; ++i)
258 {
259 path->MoveToPoint(beginPoints[i].m_x, beginPoints[i].m_y) ;
260 path->AddLineToPoint( endPoints[i].m_x, endPoints[i].m_y );
261 }
262 StrokePath( path );
263 delete path;
264 }
265
266 IMPLEMENT_ABSTRACT_CLASS(wxGCDC, wxObject)
267
268 //-----------------------------------------------------------------------------
269 // wxDC bridge class
270 //-----------------------------------------------------------------------------
271
272 wxGCDC::wxGCDC()
273 {
274 Init();
275 }
276
277
278 wxGCDC::wxGCDC(const wxWindowDC& dc)
279 {
280 Init();
281 m_graphicContext = wxGraphicsContext::Create(dc);
282 m_ok = true;
283 if ( dc.GetFont().Ok())
284 m_graphicContext->SetFont(dc.GetFont());
285 if ( dc.GetPen().Ok())
286 m_graphicContext->SetPen(dc.GetPen());
287 if ( dc.GetBrush().Ok())
288 m_graphicContext->SetBrush(dc.GetBrush());
289 m_graphicContext->SetTextColor(dc.GetTextForeground());
290 }
291
292 void wxGCDC::Init()
293 {
294 m_ok = false;
295 m_colour = true;
296 m_mm_to_pix_x = mm2pt;
297 m_mm_to_pix_y = mm2pt;
298
299 m_pen = *wxBLACK_PEN;
300 m_font = *wxNORMAL_FONT;
301 m_brush = *wxWHITE_BRUSH;
302
303 m_graphicContext = NULL;
304 }
305
306
307 wxGCDC::~wxGCDC()
308 {
309 delete m_graphicContext;
310 }
311
312 void wxGCDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNUSED(useMask) )
313 {
314 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") );
315 wxCHECK_RET( bmp.Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") );
316
317 wxCoord xx = LogicalToDeviceX(x);
318 wxCoord yy = LogicalToDeviceY(y);
319 wxCoord w = bmp.GetWidth();
320 wxCoord h = bmp.GetHeight();
321 wxCoord ww = LogicalToDeviceXRel(w);
322 wxCoord hh = LogicalToDeviceYRel(h);
323
324 m_graphicContext->DrawBitmap( bmp, xx , yy , ww , hh );
325 }
326
327 void wxGCDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
328 {
329 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") );
330 wxCHECK_RET( icon.Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") );
331
332 wxCoord xx = LogicalToDeviceX(x);
333 wxCoord yy = LogicalToDeviceY(y);
334 wxCoord w = icon.GetWidth();
335 wxCoord h = icon.GetHeight();
336 wxCoord ww = LogicalToDeviceXRel(w);
337 wxCoord hh = LogicalToDeviceYRel(h);
338
339 m_graphicContext->DrawIcon( icon , xx, yy, ww, hh );
340 }
341
342 void wxGCDC::DoSetClippingRegion( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxCoord WXUNUSED(width), wxCoord WXUNUSED(height) )
343 {
344 // TODO Clipping
345 #if 0
346 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") );
347
348 wxCoord xx, yy, ww, hh;
349 xx = LogicalToDeviceX(x);
350 yy = LogicalToDeviceY(y);
351 ww = LogicalToDeviceXRel(width);
352 hh = LogicalToDeviceYRel(height);
353
354 CGContextRef cgContext = ((wxCairoContext*)(m_graphicContext))->GetNativeContext();
355 CGRect clipRect = CGRectMake( xx , yy , ww, hh );
356 CGContextClipToRect( cgContext , clipRect );
357
358 // SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh );
359 // SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn );
360
361 if ( m_clipping )
362 {
363 m_clipX1 = wxMax( m_clipX1, xx );
364 m_clipY1 = wxMax( m_clipY1, yy );
365 m_clipX2 = wxMin( m_clipX2, (xx + ww) );
366 m_clipY2 = wxMin( m_clipY2, (yy + hh) );
367 }
368 else
369 {
370 m_clipping = true;
371
372 m_clipX1 = xx;
373 m_clipY1 = yy;
374 m_clipX2 = xx + ww;
375 m_clipY2 = yy + hh;
376 }
377
378 // TODO: as soon as we don't reset the context for each operation anymore
379 // we have to update the context as well
380 #endif
381
382 }
383
384 void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion &region )
385 {
386 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") );
387
388 if (region.Empty())
389 {
390 DestroyClippingRegion();
391 return;
392 }
393
394 wxCoord x, y, w, h;
395 region.GetBox( x, y, w, h );
396 wxCoord xx, yy, ww, hh;
397 xx = LogicalToDeviceX(x);
398 yy = LogicalToDeviceY(y);
399 ww = LogicalToDeviceXRel(w);
400 hh = LogicalToDeviceYRel(h);
401
402 // if we have a scaling that we cannot map onto native regions
403 // we must use the box
404 if ( ww != w || hh != h )
405 {
406 wxGCDC::DoSetClippingRegion( x, y, w, h );
407 }
408 else
409 {
410 #if 0
411 CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn );
412 if ( xx != x || yy != y )
413 OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y );
414 SectRgn( (RgnHandle)m_macCurrentClipRgn , (RgnHandle)m_macBoundaryClipRgn , (RgnHandle)m_macCurrentClipRgn );
415 #endif
416
417 if ( m_clipping )
418 {
419 m_clipX1 = wxMax( m_clipX1, xx );
420 m_clipY1 = wxMax( m_clipY1, yy );
421 m_clipX2 = wxMin( m_clipX2, (xx + ww) );
422 m_clipY2 = wxMin( m_clipY2, (yy + hh) );
423 }
424 else
425 {
426 m_clipping = true;
427
428 m_clipX1 = xx;
429 m_clipY1 = yy;
430 m_clipX2 = xx + ww;
431 m_clipY2 = yy + hh;
432 }
433 }
434 }
435
436 void wxGCDC::DestroyClippingRegion()
437 {
438 // TODO Clipping
439 #if 0
440 // CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn );
441
442 CGContextRef cgContext = ((wxCairoContext*)(m_graphicContext))->GetNativeContext();
443 CGContextRestoreGState( cgContext );
444 CGContextSaveGState( cgContext );
445
446 m_graphicContext->SetPen( m_pen );
447 m_graphicContext->SetBrush( m_brush );
448
449 m_clipping = false;
450 #endif
451
452 }
453
454 void wxGCDC::DoGetSizeMM( int* width, int* height ) const
455 {
456 int w = 0, h = 0;
457
458 GetSize( &w, &h );
459 if (width)
460 *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) );
461 if (height)
462 *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) );
463 }
464
465 void wxGCDC::SetTextForeground( const wxColour &col )
466 {
467 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") );
468
469 if ( col != m_textForegroundColour )
470 {
471 m_textForegroundColour = col;
472 m_graphicContext->SetTextColor( col );
473 }
474 }
475
476 void wxGCDC::SetTextBackground( const wxColour &col )
477 {
478 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") );
479
480 m_textBackgroundColour = col;
481 }
482
483 void wxGCDC::SetMapMode( int mode )
484 {
485 switch (mode)
486 {
487 case wxMM_TWIPS:
488 SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y );
489 break;
490
491 case wxMM_POINTS:
492 SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y );
493 break;
494
495 case wxMM_METRIC:
496 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
497 break;
498
499 case wxMM_LOMETRIC:
500 SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 );
501 break;
502
503 case wxMM_TEXT:
504 default:
505 SetLogicalScale( 1.0, 1.0 );
506 break;
507 }
508
509 ComputeScaleAndOrigin();
510 }
511
512 void wxGCDC::SetUserScale( double x, double y )
513 {
514 // allow negative ? -> no
515 m_userScaleX = x;
516 m_userScaleY = y;
517 ComputeScaleAndOrigin();
518 }
519
520 void wxGCDC::SetLogicalScale( double x, double y )
521 {
522 // allow negative ?
523 m_logicalScaleX = x;
524 m_logicalScaleY = y;
525 ComputeScaleAndOrigin();
526 }
527
528 void wxGCDC::SetLogicalOrigin( wxCoord x, wxCoord y )
529 {
530 m_logicalOriginX = x * m_signX; // is this still correct ?
531 m_logicalOriginY = y * m_signY;
532 ComputeScaleAndOrigin();
533 }
534
535 void wxGCDC::SetDeviceOrigin( wxCoord x, wxCoord y )
536 {
537 m_deviceOriginX = x;
538 m_deviceOriginY = y;
539 ComputeScaleAndOrigin();
540 }
541
542 void wxGCDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
543 {
544 m_signX = (xLeftRight ? 1 : -1);
545 m_signY = (yBottomUp ? -1 : 1);
546 ComputeScaleAndOrigin();
547 }
548
549 wxSize wxGCDC::GetPPI() const
550 {
551 return wxSize(72, 72);
552 }
553
554 int wxGCDC::GetDepth() const
555 {
556 return 32;
557 }
558
559 void wxGCDC::ComputeScaleAndOrigin()
560 {
561 // this is a bit artificial, but we need to force wxGCDC to think
562 // the pen has changed
563 wxPen pen( GetPen() );
564
565 m_pen = wxNullPen;
566 SetPen( pen );
567 }
568
569 void wxGCDC::SetPalette( const wxPalette& WXUNUSED(palette) )
570 {
571
572 }
573
574 void wxGCDC::SetBackgroundMode( int mode )
575 {
576 m_backgroundMode = mode;
577 }
578
579 void wxGCDC::SetFont( const wxFont &font )
580 {
581 m_font = font;
582 if ( m_graphicContext )
583 m_graphicContext->SetFont( font );
584 }
585
586 void wxGCDC::SetPen( const wxPen &pen )
587 {
588 if ( m_pen == pen )
589 return;
590
591 m_pen = pen;
592 if ( m_graphicContext )
593 {
594 if ( m_pen.GetStyle() == wxSOLID || m_pen.GetStyle() == wxTRANSPARENT )
595 {
596 m_graphicContext->SetPen( m_pen );
597 }
598 else
599 {
600 // we have to compensate for moved device origins etc. otherwise patterned pens are standing still
601 // eg when using a wxScrollWindow and scrolling around
602 int origX = LogicalToDeviceX( 0 );
603 int origY = LogicalToDeviceY( 0 );
604 m_graphicContext->Translate( origX , origY );
605 m_graphicContext->SetPen( m_pen );
606 m_graphicContext->Translate( -origX , -origY );
607 }
608 }
609 }
610
611 void wxGCDC::SetBrush( const wxBrush &brush )
612 {
613 if (m_brush == brush)
614 return;
615
616 m_brush = brush;
617 if ( m_graphicContext )
618 {
619 if ( brush.GetStyle() == wxSOLID || brush.GetStyle() == wxTRANSPARENT )
620 {
621 m_graphicContext->SetBrush( m_brush );
622 }
623 else
624 {
625 // we have to compensate for moved device origins etc. otherwise patterned brushes are standing still
626 // eg when using a wxScrollWindow and scrolling around
627 // TODO on MSW / GDIPlus this still occurs with hatched brushes
628 int origX = LogicalToDeviceX(0);
629 int origY = LogicalToDeviceY(0);
630 m_graphicContext->Translate( origX , origY );
631 m_graphicContext->SetBrush( m_brush );
632 m_graphicContext->Translate( -origX , -origY );
633 }
634 }
635 }
636
637 void wxGCDC::SetBackground( const wxBrush &brush )
638 {
639 if (m_backgroundBrush == brush)
640 return;
641
642 m_backgroundBrush = brush;
643 if (!m_backgroundBrush.Ok())
644 return;
645 }
646
647 void wxGCDC::SetLogicalFunction( int function )
648 {
649 if (m_logicalFunction == function)
650 return;
651
652 m_logicalFunction = function;
653 #if wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
654
655 CGContextRef cgContext = ((wxCairoContext*)(m_graphicContext))->GetNativeContext();
656 if ( m_logicalFunction == wxCOPY )
657 CGContextSetBlendMode( cgContext, kCGBlendModeNormal );
658 else if ( m_logicalFunction == wxINVERT )
659 CGContextSetBlendMode( cgContext, kCGBlendModeExclusion );
660 else
661 CGContextSetBlendMode( cgContext, kCGBlendModeNormal );
662 #endif
663
664 }
665
666 bool wxGCDC::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
667 const wxColour& WXUNUSED(col), int WXUNUSED(style))
668 {
669 return false;
670 }
671
672 bool wxGCDC::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const
673 {
674 // wxCHECK_MSG( 0 , false, wxT("wxGCDC(cg)::DoGetPixel - not implemented") );
675 return false;
676 }
677
678 void wxGCDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
679 {
680 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") );
681
682 #if !wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
683
684 if ( m_logicalFunction != wxCOPY )
685 return;
686 #endif
687
688 wxCoord xx1 = LogicalToDeviceX(x1);
689 wxCoord yy1 = LogicalToDeviceY(y1);
690 wxCoord xx2 = LogicalToDeviceX(x2);
691 wxCoord yy2 = LogicalToDeviceY(y2);
692
693 m_graphicContext->StrokeLine(xx1,yy1,xx2,yy2);
694
695 CalcBoundingBox(x1, y1);
696 CalcBoundingBox(x2, y2);
697 }
698
699 void wxGCDC::DoCrossHair( wxCoord x, wxCoord y )
700 {
701 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") );
702
703 if ( m_logicalFunction != wxCOPY )
704 return;
705
706 int w = 0, h = 0;
707
708 GetSize( &w, &h );
709
710 wxCoord xx = LogicalToDeviceX(x);
711 wxCoord yy = LogicalToDeviceY(y);
712 wxCoord xw = LogicalToDeviceX(w);
713 wxCoord x0 = LogicalToDeviceX(0);
714 wxCoord y0 = LogicalToDeviceY(0);
715 wxCoord yh = LogicalToDeviceY(h);
716
717 m_graphicContext->StrokeLine(x0,yy,xw,yy);
718 m_graphicContext->StrokeLine(xx,y0,xx,yh);
719
720 CalcBoundingBox(x0, y0);
721 CalcBoundingBox(x0+xw, y0+yh);
722 }
723
724 void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1,
725 wxCoord x2, wxCoord y2,
726 wxCoord xc, wxCoord yc )
727 {
728 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") );
729
730 if ( m_logicalFunction != wxCOPY )
731 return;
732
733 wxCoord xx1 = LogicalToDeviceX(x1);
734 wxCoord yy1 = LogicalToDeviceY(y1);
735 wxCoord xx2 = LogicalToDeviceX(x2);
736 wxCoord yy2 = LogicalToDeviceY(y2);
737 wxCoord xxc = LogicalToDeviceX(xc);
738 wxCoord yyc = LogicalToDeviceY(yc);
739
740 double dx = xx1 - xxc;
741 double dy = yy1 - yyc;
742 double radius = sqrt((double)(dx * dx + dy * dy));
743 wxCoord rad = (wxCoord)radius;
744 double sa, ea;
745 if (xx1 == xx2 && yy1 == yy2)
746 {
747 sa = 0.0;
748 ea = 360.0;
749 }
750 else if (radius == 0.0)
751 {
752 sa = ea = 0.0;
753 }
754 else
755 {
756 sa = (xx1 - xxc == 0) ?
757 (yy1 - yyc < 0) ? 90.0 : -90.0 :
758 -atan2(double(yy1 - yyc), double(xx1 - xxc)) * RAD2DEG;
759 ea = (xx2 - xxc == 0) ?
760 (yy2 - yyc < 0) ? 90.0 : -90.0 :
761 -atan2(double(yy2 - yyc), double(xx2 - xxc)) * RAD2DEG;
762 }
763
764 bool fill = m_brush.GetStyle() != wxTRANSPARENT;
765
766 wxGraphicsPath* path = m_graphicContext->CreatePath();
767 if ( fill && ((x1!=x2)||(y1!=y2)) )
768 path->MoveToPoint( xxc, yyc );
769 path->AddArc( xxc, yyc , rad , DegToRad(sa) , DegToRad(ea), false );
770 if ( fill && ((x1!=x2)||(y1!=y2)) )
771 path->AddLineToPoint( xxc, yyc );
772 m_graphicContext->DrawPath(path);
773 delete path;
774 }
775
776 void wxGCDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
777 double sa, double ea )
778 {
779 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") );
780
781 if ( m_logicalFunction != wxCOPY )
782 return;
783
784 wxCoord xx = LogicalToDeviceX(x);
785 wxCoord yy = LogicalToDeviceY(y);
786 wxCoord ww = m_signX * LogicalToDeviceXRel(w);
787 wxCoord hh = m_signY * LogicalToDeviceYRel(h);
788
789 // handle -ve width and/or height
790 if (ww < 0)
791 {
792 ww = -ww;
793 xx = xx - ww;
794 }
795 if (hh < 0)
796 {
797 hh = -hh;
798 yy = yy - hh;
799 }
800
801 bool fill = m_brush.GetStyle() != wxTRANSPARENT;
802
803 wxGraphicsPath* path = m_graphicContext->CreatePath();
804 m_graphicContext->PushState();
805 m_graphicContext->Translate(xx+ww/2,yy+hh/2);
806 wxDouble factor = ((wxDouble) ww) / hh ;
807 m_graphicContext->Scale( factor , 1.0) ;
808 if ( fill && (sa!=ea) )
809 path->MoveToPoint(0,0);
810 // since these angles (ea,sa) are measured counter-clockwise, we invert them to
811 // get clockwise angles
812 path->AddArc( 0, 0, hh/2 , DegToRad(-sa) , DegToRad(-ea), sa > ea );
813 if ( fill && (sa!=ea) )
814 path->AddLineToPoint(0,0);
815 m_graphicContext->DrawPath( path );
816 m_graphicContext->PopState();
817 delete path;
818 }
819
820 void wxGCDC::DoDrawPoint( wxCoord x, wxCoord y )
821 {
822 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") );
823
824 DoDrawLine( x , y , x + 1 , y + 1 );
825 }
826
827 void wxGCDC::DoDrawLines(int n, wxPoint points[],
828 wxCoord xoffset, wxCoord yoffset)
829 {
830 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") );
831
832 #if !wxMAC_USE_CORE_GRAPHICS_BLEND_MODES
833
834 if ( m_logicalFunction != wxCOPY )
835 return;
836 #endif
837
838 wxPoint2DDouble* pointsD = new wxPoint2DDouble[n] ;
839 for( int i = 0 ; i < n; ++i)
840 {
841 pointsD[i].m_x = LogicalToDeviceX(points[i].x + xoffset);
842 pointsD[i].m_y = LogicalToDeviceY(points[i].y + yoffset);
843 }
844
845 m_graphicContext->StrokeLines( n , pointsD) ;
846 delete[] pointsD;
847 }
848
849 #if wxUSE_SPLINES
850 void wxGCDC::DoDrawSpline(wxList *points)
851 {
852 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") );
853
854 if ( m_logicalFunction != wxCOPY )
855 return;
856
857 wxGraphicsPath* path = m_graphicContext->CreatePath();
858
859 wxList::compatibility_iterator node = points->GetFirst();
860 if (node == wxList::compatibility_iterator())
861 // empty list
862 return;
863
864 wxPoint *p = (wxPoint *)node->GetData();
865
866 wxCoord x1 = p->x;
867 wxCoord y1 = p->y;
868
869 node = node->GetNext();
870 p = (wxPoint *)node->GetData();
871
872 wxCoord x2 = p->x;
873 wxCoord y2 = p->y;
874 wxCoord cx1 = ( x1 + x2 ) / 2;
875 wxCoord cy1 = ( y1 + y2 ) / 2;
876
877 path->MoveToPoint( LogicalToDeviceX( x1 ) , LogicalToDeviceY( y1 ) );
878 path->AddLineToPoint( LogicalToDeviceX( cx1 ) , LogicalToDeviceY( cy1 ) );
879 #if !wxUSE_STL
880
881 while ((node = node->GetNext()) != NULL)
882 #else
883
884 while ((node = node->GetNext()))
885 #endif // !wxUSE_STL
886
887 {
888 p = (wxPoint *)node->GetData();
889 x1 = x2;
890 y1 = y2;
891 x2 = p->x;
892 y2 = p->y;
893 wxCoord cx4 = (x1 + x2) / 2;
894 wxCoord cy4 = (y1 + y2) / 2;
895
896 path->AddQuadCurveToPoint(
897 LogicalToDeviceX( x1 ) , LogicalToDeviceY( y1 ) ,
898 LogicalToDeviceX( cx4 ) , LogicalToDeviceY( cy4 ) );
899
900 cx1 = cx4;
901 cy1 = cy4;
902 }
903
904 path->AddLineToPoint( LogicalToDeviceX( x2 ) , LogicalToDeviceY( y2 ) );
905
906 m_graphicContext->StrokePath( path );
907 delete path;
908 }
909 #endif // wxUSE_SPLINES
910
911 void wxGCDC::DoDrawPolygon( int n, wxPoint points[],
912 wxCoord xoffset, wxCoord yoffset,
913 int fillStyle )
914 {
915 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") );
916
917 if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) )
918 return;
919 if ( m_logicalFunction != wxCOPY )
920 return;
921
922 bool closeIt = false ;
923 if (points[n-1] != points[0])
924 closeIt = true ;
925
926 wxPoint2DDouble* pointsD = new wxPoint2DDouble[n+(closeIt?1:0)] ;
927 for( int i = 0 ; i < n; ++i)
928 {
929 pointsD[i].m_x = LogicalToDeviceX(points[i].x + xoffset);
930 pointsD[i].m_y = LogicalToDeviceY(points[i].y + yoffset);
931 }
932 if ( closeIt )
933 pointsD[n] = pointsD[0];
934
935 m_graphicContext->DrawLines( n+(closeIt?1:0) , pointsD, fillStyle) ;
936 delete[] pointsD;
937 }
938
939 void wxGCDC::DoDrawPolyPolygon(int n,
940 int count[],
941 wxPoint points[],
942 wxCoord xoffset,
943 wxCoord yoffset,
944 int fillStyle)
945 {
946 wxASSERT(n > 1);
947 wxGraphicsPath* path = m_graphicContext->CreatePath();
948
949 int i = 0 ;
950 for ( int j = 0 ; j < n ; ++j)
951 {
952 wxPoint start = points[i];
953 path->MoveToPoint(LogicalToDeviceX(start.x+ xoffset), LogicalToDeviceY(start.y+ yoffset)) ;
954 ++i;
955 int l = count[j];
956 for ( int k = 1 ; k < l ; ++k)
957 {
958 path->AddLineToPoint( LogicalToDeviceX(points[i].x+ xoffset), LogicalToDeviceY(points[i].y+ yoffset));
959 ++i ;
960 }
961 // close the polygon
962 if ( start != points[i-1])
963 path->AddLineToPoint( LogicalToDeviceX(start.x+ xoffset), LogicalToDeviceY(start.y+ yoffset));
964 }
965 m_graphicContext->DrawPath( path , fillStyle);
966 delete path;
967 }
968
969 void wxGCDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
970 {
971 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") );
972
973 if ( m_logicalFunction != wxCOPY )
974 return;
975
976 wxCoord xx = LogicalToDeviceX(x);
977 wxCoord yy = LogicalToDeviceY(y);
978 wxCoord ww = m_signX * LogicalToDeviceXRel(width);
979 wxCoord hh = m_signY * LogicalToDeviceYRel(height);
980
981 // CMB: draw nothing if transformed w or h is 0
982 if (ww == 0 || hh == 0)
983 return;
984
985 // CMB: handle -ve width and/or height
986 if (ww < 0)
987 {
988 ww = -ww;
989 xx = xx - ww;
990 }
991 if (hh < 0)
992 {
993 hh = -hh;
994 yy = yy - hh;
995 }
996 m_graphicContext->DrawRectangle( xx,yy,ww,hh);
997 }
998
999 void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
1000 wxCoord width, wxCoord height,
1001 double radius)
1002 {
1003 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") );
1004
1005 if ( m_logicalFunction != wxCOPY )
1006 return;
1007
1008 if (radius < 0.0)
1009 radius = - radius * ((width < height) ? width : height);
1010 wxCoord xx = LogicalToDeviceX(x);
1011 wxCoord yy = LogicalToDeviceY(y);
1012 wxCoord ww = m_signX * LogicalToDeviceXRel(width);
1013 wxCoord hh = m_signY * LogicalToDeviceYRel(height);
1014
1015 // CMB: draw nothing if transformed w or h is 0
1016 if (ww == 0 || hh == 0)
1017 return;
1018
1019 // CMB: handle -ve width and/or height
1020 if (ww < 0)
1021 {
1022 ww = -ww;
1023 xx = xx - ww;
1024 }
1025 if (hh < 0)
1026 {
1027 hh = -hh;
1028 yy = yy - hh;
1029 }
1030
1031 m_graphicContext->DrawRoundedRectangle( xx,yy,ww,hh,radius);
1032 }
1033
1034 void wxGCDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1035 {
1036 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") );
1037
1038 if ( m_logicalFunction != wxCOPY )
1039 return;
1040
1041 wxCoord xx = LogicalToDeviceX(x);
1042 wxCoord yy = LogicalToDeviceY(y);
1043 wxDouble ww = m_signX * LogicalToDeviceXRel(width);
1044 wxCoord hh = m_signY * LogicalToDeviceYRel(height);
1045
1046 // CMB: draw nothing if transformed w or h is 0
1047 if (ww == 0 || hh == 0)
1048 return;
1049
1050 // CMB: handle -ve width and/or height
1051 if (ww < 0)
1052 {
1053 ww = -ww;
1054 xx = xx - ww;
1055 }
1056 if (hh < 0)
1057 {
1058 hh = -hh;
1059 yy = yy - hh;
1060 }
1061
1062 m_graphicContext->DrawEllipse(xx,yy,ww,hh);
1063 }
1064
1065 bool wxGCDC::CanDrawBitmap() const
1066 {
1067 return true;
1068 }
1069
1070 bool wxGCDC::DoBlit(
1071 wxCoord WXUNUSED(xdest), wxCoord WXUNUSED(ydest), wxCoord WXUNUSED(width), wxCoord WXUNUSED(height),
1072 wxDC *source, wxCoord WXUNUSED(xsrc), wxCoord WXUNUSED(ysrc), int logical_func , bool WXUNUSED(useMask),
1073 wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask) )
1074 {
1075 wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid DC") );
1076 wxCHECK_MSG( source->Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid source DC") );
1077
1078 if ( logical_func == wxNO_OP )
1079 return true;
1080
1081 #if 0
1082 if (xsrcMask == -1 && ysrcMask == -1)
1083 {
1084 xsrcMask = xsrc;
1085 ysrcMask = ysrc;
1086 }
1087
1088 wxCoord yysrc = source-> LogicalToDeviceY(ysrc);
1089 wxCoord xxsrc = source-> LogicalToDeviceX(xsrc);
1090 wxCoord wwsrc = source-> LogicalToDeviceXRel(width);
1091 wxCoord hhsrc = source-> LogicalToDeviceYRel(height);
1092
1093 wxCoord yydest = LogicalToDeviceY(ydest);
1094 wxCoord xxdest = LogicalToDeviceX(xdest);
1095 wxCoord wwdest = LogicalToDeviceXRel(width);
1096 wxCoord hhdest = LogicalToDeviceYRel(height);
1097
1098 wxMemoryDC* memdc = dynamic_cast<wxMemoryDC*>(source);
1099 if ( memdc && logical_func == wxCOPY )
1100 {
1101 wxBitmap blit = memdc->GetSelectedObject();
1102
1103 wxASSERT_MSG( blit.Ok() , wxT("Invalid bitmap for blitting") );
1104
1105 wxCoord bmpwidth = blit.GetWidth();
1106 wxCoord bmpheight = blit.GetHeight();
1107
1108 if ( xxsrc != 0 || yysrc != 0 || bmpwidth != wwsrc || bmpheight != hhsrc )
1109 {
1110 wwsrc = wxMin( wwsrc , bmpwidth - xxsrc );
1111 hhsrc = wxMin( hhsrc , bmpheight - yysrc );
1112 if ( wwsrc > 0 && hhsrc > 0 )
1113 {
1114 if ( xxsrc >= 0 && yysrc >= 0 )
1115 {
1116 wxRect subrect( xxsrc, yysrc, wwsrc , hhsrc );
1117 // TODO we perhaps could add a DrawSubBitmap call to dc for performance reasons
1118 blit = blit.GetSubBitmap( subrect );
1119 }
1120 else
1121 {
1122 // in this case we'd probably have to adjust the different coordinates, but
1123 // we have to find out proper contract first
1124 blit = wxNullBitmap;
1125 }
1126 }
1127 else
1128 {
1129 blit = wxNullBitmap;
1130 }
1131 }
1132
1133 if ( blit.Ok() )
1134 {
1135 m_graphicContext->DrawBitmap( blit, xxdest , yydest , wwdest , hhdest );
1136 }
1137
1138 }
1139 else
1140 {
1141 wxFAIL_MSG( wxT("Blitting is only supported from bitmap contexts") );
1142 return false;
1143 }
1144 #endif
1145
1146 return false;
1147 }
1148
1149 void wxGCDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
1150 double angle)
1151 {
1152 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") );
1153
1154 if ( str.length() == 0 )
1155 return;
1156 if ( m_logicalFunction != wxCOPY )
1157 return;
1158
1159 int drawX = LogicalToDeviceX(x);
1160 int drawY = LogicalToDeviceY(y);
1161
1162 m_graphicContext->DrawText( str, drawX ,drawY , DegToRad(angle ));
1163 }
1164
1165 void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y)
1166 {
1167 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") );
1168
1169 if ( str.length() == 0 )
1170 return;
1171 if ( m_logicalFunction != wxCOPY )
1172 return;
1173
1174 int drawX = LogicalToDeviceX(x);
1175 int drawY = LogicalToDeviceY(y);
1176
1177 m_graphicContext->DrawText( str, drawX ,drawY);
1178 }
1179
1180 bool wxGCDC::CanGetTextExtent() const
1181 {
1182 wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") );
1183
1184 return true;
1185 }
1186
1187 void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
1188 wxCoord *descent, wxCoord *externalLeading ,
1189 wxFont *theFont ) const
1190 {
1191 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") );
1192
1193 if ( theFont )
1194 {
1195 m_graphicContext->SetFont( *theFont );
1196 }
1197
1198 wxDouble h , d , e , w;
1199
1200 m_graphicContext->GetTextExtent( str, &w, &h, &d, &e );
1201
1202 if ( height )
1203 *height = DeviceToLogicalYRel( h );
1204 if ( descent )
1205 *descent =DeviceToLogicalYRel( d);
1206 if ( externalLeading )
1207 *externalLeading = DeviceToLogicalYRel( e);
1208 if ( width )
1209 *width = DeviceToLogicalXRel( w );
1210
1211 if ( theFont )
1212 {
1213 m_graphicContext->SetFont( m_font );
1214 }
1215 }
1216
1217 bool wxGCDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
1218 {
1219 wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") );
1220 widths.Clear();
1221 widths.Add(0,text.Length());
1222 if ( text.IsEmpty() )
1223 return true ;
1224
1225 wxArrayDouble widthsD ;
1226
1227 m_graphicContext->GetPartialTextExtents( text, widthsD );
1228 for ( size_t i = 0; i < widths.GetCount(); ++i )
1229 widths[i] = DeviceToLogicalXRel( widthsD[i] + 0.5 ) ;
1230
1231 return true;
1232 }
1233
1234 wxCoord wxGCDC::GetCharWidth(void) const
1235 {
1236 wxCoord width;
1237 DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL );
1238
1239 return width;
1240 }
1241
1242 wxCoord wxGCDC::GetCharHeight(void) const
1243 {
1244 wxCoord height;
1245 DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL );
1246
1247 return height;
1248 }
1249
1250 void wxGCDC::Clear(void)
1251 {
1252 wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::Clear - invalid DC") );
1253 // TODO
1254 }
1255
1256 void wxGCDC::DoGetSize(int *width, int *height) const
1257 {
1258 *width = 1000;
1259 *height = 1000;
1260 }
1261
1262 void wxGCDC::DoGradientFillLinear(const wxRect& rect,
1263 const wxColour& initialColour,
1264 const wxColour& destColour,
1265 wxDirection nDirection )
1266 {
1267 wxPoint start ;
1268 wxPoint end ;
1269 switch( nDirection)
1270 {
1271 case wxWEST :
1272 start = rect.GetRightBottom();
1273 start.x++;
1274 end = rect.GetLeftBottom();
1275 break ;
1276 case wxEAST :
1277 start = rect.GetLeftBottom();
1278 end = rect.GetRightBottom();
1279 end.x++;
1280 break ;
1281 case wxNORTH :
1282 start = rect.GetLeftBottom();
1283 start.y++;
1284 end = rect.GetLeftTop();
1285 break ;
1286 case wxSOUTH :
1287 start = rect.GetLeftTop();
1288 end = rect.GetLeftBottom();
1289 end.y++;
1290 break ;
1291 }
1292
1293 m_graphicContext->SetLinearGradientBrush(
1294 LogicalToDeviceX(start.x),LogicalToDeviceY(start.y),
1295 LogicalToDeviceX(end.x),LogicalToDeviceY(end.y), initialColour, destColour);
1296
1297 wxCoord xx = LogicalToDeviceX(rect.x);
1298 wxCoord yy = LogicalToDeviceY(rect.y);
1299 wxDouble ww = m_signX * LogicalToDeviceXRel(rect.width);
1300 wxCoord hh = m_signY * LogicalToDeviceYRel(rect.height);
1301
1302 if (ww == 0 || hh == 0)
1303 return;
1304
1305 if (ww < 0)
1306 {
1307 ww = -ww;
1308 xx = xx - ww;
1309 }
1310 if (hh < 0)
1311 {
1312 hh = -hh;
1313 yy = yy - hh;
1314 }
1315
1316 m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
1317 m_graphicContext->DrawRectangle(xx,yy,ww,hh);
1318 m_graphicContext->SetPen(m_pen);
1319 }
1320
1321 void wxGCDC::DoGradientFillConcentric(const wxRect& rect,
1322 const wxColour& initialColour,
1323 const wxColour& destColour,
1324 const wxPoint& circleCenter)
1325 {
1326 //Radius
1327 wxInt32 cx = rect.GetWidth() / 2;
1328 wxInt32 cy = rect.GetHeight() / 2;
1329 wxInt32 nRadius;
1330 if (cx < cy)
1331 nRadius = cx;
1332 else
1333 nRadius = cy;
1334
1335 wxCoord xx = LogicalToDeviceX(rect.x);
1336 wxCoord yy = LogicalToDeviceY(rect.y);
1337 wxDouble ww = m_signX * LogicalToDeviceXRel(rect.width);
1338 wxCoord hh = m_signY * LogicalToDeviceYRel(rect.height);
1339
1340 if (ww == 0 || hh == 0)
1341 return;
1342
1343 if (ww < 0)
1344 {
1345 ww = -ww;
1346 xx = xx - ww;
1347 }
1348 if (hh < 0)
1349 {
1350 hh = -hh;
1351 yy = yy - hh;
1352 }
1353
1354 m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
1355 m_graphicContext->SetBrush( wxBrush( destColour) ) ;
1356 m_graphicContext->DrawRectangle( xx,yy,ww,hh);
1357
1358 m_graphicContext->SetRadialGradientBrush(
1359 xx+LogicalToDeviceX(circleCenter.x),yy+LogicalToDeviceY(circleCenter.y),
1360 xx+LogicalToDeviceX(circleCenter.x),yy+LogicalToDeviceY(circleCenter.y),
1361 LogicalToDeviceXRel(nRadius),
1362 initialColour,destColour);
1363
1364 m_graphicContext->DrawRectangle( xx,yy,ww,hh);
1365 m_graphicContext->SetPen(m_pen);
1366 }
1367
1368 void wxGCDC::DoDrawCheckMark(wxCoord x, wxCoord y,
1369 wxCoord width, wxCoord height)
1370 {
1371 wxDCBase::DoDrawCheckMark(x,y,width,height);
1372 }
1373
1374 #endif // wxUSE_GRAPHICS_CONTEXT