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