keep the owning window
[wxWidgets.git] / src / common / dcgraph.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 #include "wx/dcgraph.h"
23
24 #ifndef WX_PRECOMP
25 #include "wx/icon.h"
26 #include "wx/bitmap.h"
27 #include "wx/dcmemory.h"
28 #include "wx/region.h"
29 #endif
30
31 #ifdef __WXMAC__
32 #include "wx/mac/private.h"
33 #endif
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 // wxDC bridge class
51 //-----------------------------------------------------------------------------
52
53 IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDC)
54
55 wxGCDC::wxGCDC(const wxWindowDC& dc) :
56 wxDC( new wxGCDCImpl( this, dc ) )
57 {
58 }
59
60 wxGCDC::wxGCDC( const wxMemoryDC& dc) :
61 wxDC( new wxGCDCImpl( this, dc ) )
62 {
63 }
64
65 wxGCDC::wxGCDC() :
66 wxDC( new wxGCDCImpl( this ) )
67 {
68 }
69
70 wxGCDC::~wxGCDC()
71 {
72 }
73
74 wxGraphicsContext* wxGCDC::GetGraphicsContext()
75 {
76 if (!m_pimpl) return NULL;
77 wxGCDCImpl *gc_impl = (wxGCDCImpl*) m_pimpl;
78 return gc_impl->GetGraphicsContext();
79 }
80
81 void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx )
82 {
83 if (!m_pimpl) return;
84 wxGCDCImpl *gc_impl = (wxGCDCImpl*) m_pimpl;
85 gc_impl->SetGraphicsContext( ctx );
86 }
87
88 IMPLEMENT_ABSTRACT_CLASS(wxGCDCImpl, wxDCImpl)
89
90 wxGCDCImpl::wxGCDCImpl( wxDC *owner ) :
91 wxDCImpl( owner )
92 {
93 Init();
94 }
95
96 void wxGCDCImpl::SetGraphicsContext( wxGraphicsContext* ctx )
97 {
98 delete m_graphicContext;
99 m_graphicContext = ctx;
100 if ( m_graphicContext )
101 {
102 m_matrixOriginal = m_graphicContext->GetTransform();
103 m_ok = true;
104 // apply the stored transformations to the passed in context
105 ComputeScaleAndOrigin();
106 m_graphicContext->SetFont( m_font , m_textForegroundColour );
107 m_graphicContext->SetPen( m_pen );
108 m_graphicContext->SetBrush( m_brush);
109 }
110 }
111
112 wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxWindowDC& dc ) :
113 wxDCImpl( owner )
114 {
115 Init();
116 SetGraphicsContext( wxGraphicsContext::Create(dc) );
117 m_window = dc.GetWindow();
118 }
119
120 wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxMemoryDC& dc ) :
121 wxDCImpl( owner )
122 {
123 Init();
124 SetGraphicsContext( wxGraphicsContext::Create(dc) );
125 }
126
127 void wxGCDCImpl::Init()
128 {
129 m_ok = false;
130 m_colour = true;
131 m_mm_to_pix_x = mm2pt;
132 m_mm_to_pix_y = mm2pt;
133
134 m_pen = *wxBLACK_PEN;
135 m_font = *wxNORMAL_FONT;
136 m_brush = *wxWHITE_BRUSH;
137
138 m_graphicContext = NULL;
139 m_logicalFunctionSupported = true;
140 }
141
142
143 wxGCDCImpl::~wxGCDCImpl()
144 {
145 delete m_graphicContext;
146 }
147
148 void wxGCDCImpl::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNUSED(useMask) )
149 {
150 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") );
151 wxCHECK_RET( bmp.IsOk(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") );
152
153 if ( bmp.GetDepth() == 1 )
154 {
155 m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
156 m_graphicContext->SetBrush( wxBrush( m_textBackgroundColour , wxSOLID ) );
157 m_graphicContext->DrawRectangle( x , y , bmp.GetWidth() , bmp.GetHeight() );
158 m_graphicContext->SetBrush( wxBrush( m_textForegroundColour , wxSOLID ) );
159 m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() );
160 m_graphicContext->SetBrush( m_graphicContext->CreateBrush(m_brush));
161 m_graphicContext->SetPen( m_graphicContext->CreatePen(m_pen));
162 }
163 else
164 m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() );
165 }
166
167 void wxGCDCImpl::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
168 {
169 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") );
170 wxCHECK_RET( icon.IsOk(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") );
171
172 wxCoord w = icon.GetWidth();
173 wxCoord h = icon.GetHeight();
174
175 m_graphicContext->DrawIcon( icon , x, y, w, h );
176 }
177
178 bool wxGCDCImpl::StartDoc( const wxString& WXUNUSED(message) )
179 {
180 return true;
181 }
182
183 void wxGCDCImpl::EndDoc()
184 {
185 }
186
187 void wxGCDCImpl::StartPage()
188 {
189 }
190
191 void wxGCDCImpl::EndPage()
192 {
193 }
194
195 void wxGCDCImpl::Flush()
196 {
197 #ifdef __WXMAC__
198 CGContextFlush( (CGContextRef) m_graphicContext->GetNativeContext() );
199 #endif
200 }
201
202 void wxGCDCImpl::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
203 {
204 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") );
205
206 m_graphicContext->Clip( x, y, w, h );
207 if ( m_clipping )
208 {
209 m_clipX1 = wxMax( m_clipX1, x );
210 m_clipY1 = wxMax( m_clipY1, y );
211 m_clipX2 = wxMin( m_clipX2, (x + w) );
212 m_clipY2 = wxMin( m_clipY2, (y + h) );
213 }
214 else
215 {
216 m_clipping = true;
217
218 m_clipX1 = x;
219 m_clipY1 = y;
220 m_clipX2 = x + w;
221 m_clipY2 = y + h;
222 }
223 }
224
225 void wxGCDCImpl::DoSetClippingRegionAsRegion( const wxRegion &region )
226 {
227 // region is in device coordinates
228 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") );
229
230 if (region.Empty())
231 {
232 //DestroyClippingRegion();
233 return;
234 }
235
236 wxRegion logRegion( region );
237 wxCoord x, y, w, h;
238
239 logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) );
240 logRegion.GetBox( x, y, w, h );
241
242 m_graphicContext->Clip( logRegion );
243 if ( m_clipping )
244 {
245 m_clipX1 = wxMax( m_clipX1, x );
246 m_clipY1 = wxMax( m_clipY1, y );
247 m_clipX2 = wxMin( m_clipX2, (x + w) );
248 m_clipY2 = wxMin( m_clipY2, (y + h) );
249 }
250 else
251 {
252 m_clipping = true;
253
254 m_clipX1 = x;
255 m_clipY1 = y;
256 m_clipX2 = x + w;
257 m_clipY2 = y + h;
258 }
259 }
260
261 void wxGCDCImpl::DestroyClippingRegion()
262 {
263 m_graphicContext->ResetClip();
264 // currently the clip eg of a window extends to the area between the scrollbars
265 // so we must explicitely make sure it only covers the area we want it to draw
266 int width, height ;
267 GetOwner()->GetSize( &width , &height ) ;
268 m_graphicContext->Clip( DeviceToLogicalX(0) , DeviceToLogicalY(0) , DeviceToLogicalXRel(width), DeviceToLogicalYRel(height) );
269
270 m_graphicContext->SetPen( m_pen );
271 m_graphicContext->SetBrush( m_brush );
272
273 m_clipping = false;
274 }
275
276 void wxGCDCImpl::DoGetSizeMM( int* width, int* height ) const
277 {
278 int w = 0, h = 0;
279
280 GetOwner()->GetSize( &w, &h );
281 if (width)
282 *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) );
283 if (height)
284 *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) );
285 }
286
287 void wxGCDCImpl::SetTextForeground( const wxColour &col )
288 {
289 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") );
290
291 if ( col != m_textForegroundColour )
292 {
293 m_textForegroundColour = col;
294 m_graphicContext->SetFont( m_font, m_textForegroundColour );
295 }
296 }
297
298 void wxGCDCImpl::SetTextBackground( const wxColour &col )
299 {
300 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") );
301
302 m_textBackgroundColour = col;
303 }
304
305 void wxGCDCImpl::SetMapMode( int mode )
306 {
307 switch (mode)
308 {
309 case wxMM_TWIPS:
310 SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y );
311 break;
312
313 case wxMM_POINTS:
314 SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y );
315 break;
316
317 case wxMM_METRIC:
318 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
319 break;
320
321 case wxMM_LOMETRIC:
322 SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 );
323 break;
324
325 case wxMM_TEXT:
326 default:
327 SetLogicalScale( 1.0, 1.0 );
328 break;
329 }
330
331 ComputeScaleAndOrigin();
332 }
333
334 wxSize wxGCDCImpl::GetPPI() const
335 {
336 return wxSize(72, 72);
337 }
338
339 int wxGCDCImpl::GetDepth() const
340 {
341 return 32;
342 }
343
344 void wxGCDCImpl::ComputeScaleAndOrigin()
345 {
346 wxDCImpl::ComputeScaleAndOrigin();
347
348 if ( m_graphicContext )
349 {
350 m_matrixCurrent = m_graphicContext->CreateMatrix();
351 m_matrixCurrent.Translate( m_deviceOriginX, m_deviceOriginY );
352 m_matrixCurrent.Scale( m_scaleX, m_scaleY );
353 // the logical origin sets the origin to have new coordinates
354 m_matrixCurrent.Translate( -m_logicalOriginX, -m_logicalOriginY );
355
356 m_graphicContext->SetTransform( m_matrixOriginal );
357 m_graphicContext->ConcatTransform( m_matrixCurrent );
358 }
359 }
360
361 void wxGCDCImpl::SetPalette( const wxPalette& WXUNUSED(palette) )
362 {
363
364 }
365
366 void wxGCDCImpl::SetBackgroundMode( int mode )
367 {
368 m_backgroundMode = mode;
369 }
370
371 void wxGCDCImpl::SetFont( const wxFont &font )
372 {
373 m_font = font;
374 if ( m_graphicContext )
375 {
376 wxFont f = font;
377 if ( f.IsOk() )
378 f.SetPointSize( /*LogicalToDeviceYRel*/(font.GetPointSize()));
379 m_graphicContext->SetFont( f, m_textForegroundColour );
380 }
381 }
382
383 void wxGCDCImpl::SetPen( const wxPen &pen )
384 {
385 if ( m_pen == pen )
386 return;
387
388 m_pen = pen;
389 if ( m_graphicContext )
390 {
391 m_graphicContext->SetPen( m_pen );
392 }
393 }
394
395 void wxGCDCImpl::SetBrush( const wxBrush &brush )
396 {
397 if (m_brush == brush)
398 return;
399
400 m_brush = brush;
401 if ( m_graphicContext )
402 {
403 m_graphicContext->SetBrush( m_brush );
404 }
405 }
406
407 void wxGCDCImpl::SetBackground( const wxBrush &brush )
408 {
409 if (m_backgroundBrush == brush)
410 return;
411
412 m_backgroundBrush = brush;
413 if (!m_backgroundBrush.IsOk())
414 return;
415 }
416
417 void wxGCDCImpl::SetLogicalFunction( int function )
418 {
419 if (m_logicalFunction == function)
420 return;
421
422 m_logicalFunction = function;
423 if ( m_graphicContext->SetLogicalFunction( function ) )
424 m_logicalFunctionSupported=true;
425 else
426 m_logicalFunctionSupported=false;
427 }
428
429 bool wxGCDCImpl::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
430 const wxColour& WXUNUSED(col), int WXUNUSED(style))
431 {
432 return false;
433 }
434
435 bool wxGCDCImpl::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const
436 {
437 // wxCHECK_MSG( 0 , false, wxT("wxGCDC(cg)::DoGetPixel - not implemented") );
438 return false;
439 }
440
441 void wxGCDCImpl::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
442 {
443 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") );
444
445 if ( !m_logicalFunctionSupported )
446 return;
447
448 m_graphicContext->StrokeLine(x1,y1,x2,y2);
449
450 CalcBoundingBox(x1, y1);
451 CalcBoundingBox(x2, y2);
452 }
453
454 void wxGCDCImpl::DoCrossHair( wxCoord x, wxCoord y )
455 {
456 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") );
457
458 if ( !m_logicalFunctionSupported )
459 return;
460
461 int w = 0, h = 0;
462
463 GetOwner()->GetSize( &w, &h );
464
465 m_graphicContext->StrokeLine(0,y,w,y);
466 m_graphicContext->StrokeLine(x,0,x,h);
467
468 CalcBoundingBox(0, 0);
469 CalcBoundingBox(0+w, 0+h);
470 }
471
472 void wxGCDCImpl::DoDrawArc( wxCoord x1, wxCoord y1,
473 wxCoord x2, wxCoord y2,
474 wxCoord xc, wxCoord yc )
475 {
476 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") );
477
478 if ( !m_logicalFunctionSupported )
479 return;
480
481 double dx = x1 - xc;
482 double dy = y1 - yc;
483 double radius = sqrt((double)(dx * dx + dy * dy));
484 wxCoord rad = (wxCoord)radius;
485 double sa, ea;
486 if (x1 == x2 && y1 == y2)
487 {
488 sa = 0.0;
489 ea = 360.0;
490 }
491 else if (radius == 0.0)
492 {
493 sa = ea = 0.0;
494 }
495 else
496 {
497 sa = (x1 - xc == 0) ?
498 (y1 - yc < 0) ? 90.0 : -90.0 :
499 -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG;
500 ea = (x2 - xc == 0) ?
501 (y2 - yc < 0) ? 90.0 : -90.0 :
502 -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG;
503 }
504
505 bool fill = m_brush.GetStyle() != wxTRANSPARENT;
506
507 wxGraphicsPath path = m_graphicContext->CreatePath();
508 if ( fill && ((x1!=x2)||(y1!=y2)) )
509 path.MoveToPoint( xc, yc );
510 // since these angles (ea,sa) are measured counter-clockwise, we invert them to
511 // get clockwise angles
512 path.AddArc( xc, yc , rad , DegToRad(-sa) , DegToRad(-ea), false );
513 if ( fill && ((x1!=x2)||(y1!=y2)) )
514 path.AddLineToPoint( xc, yc );
515 m_graphicContext->DrawPath(path);
516 }
517
518 void wxGCDCImpl::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
519 double sa, double ea )
520 {
521 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") );
522
523 if ( !m_logicalFunctionSupported )
524 return;
525
526 m_graphicContext->PushState();
527 m_graphicContext->Translate(x+w/2.0,y+h/2.0);
528 wxDouble factor = ((wxDouble) w) / h;
529 m_graphicContext->Scale( factor , 1.0);
530
531 // since these angles (ea,sa) are measured counter-clockwise, we invert them to
532 // get clockwise angles
533 if ( m_brush.GetStyle() != wxTRANSPARENT )
534 {
535 wxGraphicsPath path = m_graphicContext->CreatePath();
536 path.MoveToPoint( 0, 0 );
537 path.AddLineToPoint( h / 2.0 * cos(DegToRad(sa)) , h / 2.0 * sin(DegToRad(-sa)) );
538 path.AddLineToPoint( h / 2.0 * cos(DegToRad(ea)) , h / 2.0 * sin(DegToRad(-ea)) );
539 path.AddLineToPoint( 0, 0 );
540 m_graphicContext->FillPath( path );
541
542 path = m_graphicContext->CreatePath();
543 path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea );
544 m_graphicContext->FillPath( path );
545 m_graphicContext->StrokePath( path );
546 }
547 else
548 {
549 wxGraphicsPath path = m_graphicContext->CreatePath();
550 path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea );
551 m_graphicContext->DrawPath( path );
552 }
553
554 m_graphicContext->PopState();
555 }
556
557 void wxGCDCImpl::DoDrawPoint( wxCoord x, wxCoord y )
558 {
559 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") );
560
561 DoDrawLine( x , y , x + 1 , y + 1 );
562 }
563
564 void wxGCDCImpl::DoDrawLines(int n, wxPoint points[],
565 wxCoord xoffset, wxCoord yoffset)
566 {
567 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") );
568
569 if ( !m_logicalFunctionSupported )
570 return;
571
572 wxPoint2DDouble* pointsD = new wxPoint2DDouble[n];
573 for( int i = 0; i < n; ++i)
574 {
575 pointsD[i].m_x = points[i].x + xoffset;
576 pointsD[i].m_y = points[i].y + yoffset;
577 }
578
579 m_graphicContext->StrokeLines( n , pointsD);
580 delete[] pointsD;
581 }
582
583 #if wxUSE_SPLINES
584 void wxGCDCImpl::DoDrawSpline(const wxPointList *points)
585 {
586 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") );
587
588 if ( !m_logicalFunctionSupported )
589 return;
590
591 wxGraphicsPath path = m_graphicContext->CreatePath();
592
593 wxPointList::compatibility_iterator node = points->GetFirst();
594 if (node == wxPointList::compatibility_iterator())
595 // empty list
596 return;
597
598 wxPoint *p = node->GetData();
599
600 wxCoord x1 = p->x;
601 wxCoord y1 = p->y;
602
603 node = node->GetNext();
604 p = node->GetData();
605
606 wxCoord x2 = p->x;
607 wxCoord y2 = p->y;
608 wxCoord cx1 = ( x1 + x2 ) / 2;
609 wxCoord cy1 = ( y1 + y2 ) / 2;
610
611 path.MoveToPoint( x1 , y1 );
612 path.AddLineToPoint( cx1 , cy1 );
613 #if !wxUSE_STL
614
615 while ((node = node->GetNext()) != NULL)
616 #else
617
618 while ((node = node->GetNext()))
619 #endif // !wxUSE_STL
620
621 {
622 p = node->GetData();
623 x1 = x2;
624 y1 = y2;
625 x2 = p->x;
626 y2 = p->y;
627 wxCoord cx4 = (x1 + x2) / 2;
628 wxCoord cy4 = (y1 + y2) / 2;
629
630 path.AddQuadCurveToPoint(x1 , y1 ,cx4 , cy4 );
631
632 cx1 = cx4;
633 cy1 = cy4;
634 }
635
636 path.AddLineToPoint( x2 , y2 );
637
638 m_graphicContext->StrokePath( path );
639 }
640 #endif // wxUSE_SPLINES
641
642 void wxGCDCImpl::DoDrawPolygon( int n, wxPoint points[],
643 wxCoord xoffset, wxCoord yoffset,
644 int fillStyle )
645 {
646 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") );
647
648 if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) )
649 return;
650 if ( !m_logicalFunctionSupported )
651 return;
652
653 bool closeIt = false;
654 if (points[n-1] != points[0])
655 closeIt = true;
656
657 wxPoint2DDouble* pointsD = new wxPoint2DDouble[n+(closeIt?1:0)];
658 for( int i = 0; i < n; ++i)
659 {
660 pointsD[i].m_x = points[i].x + xoffset;
661 pointsD[i].m_y = points[i].y + yoffset;
662 }
663 if ( closeIt )
664 pointsD[n] = pointsD[0];
665
666 m_graphicContext->DrawLines( n+(closeIt?1:0) , pointsD, fillStyle);
667 delete[] pointsD;
668 }
669
670 void wxGCDCImpl::DoDrawPolyPolygon(int n,
671 int count[],
672 wxPoint points[],
673 wxCoord xoffset,
674 wxCoord yoffset,
675 int fillStyle)
676 {
677 wxASSERT(n > 1);
678 wxGraphicsPath path = m_graphicContext->CreatePath();
679
680 int i = 0;
681 for ( int j = 0; j < n; ++j)
682 {
683 wxPoint start = points[i];
684 path.MoveToPoint( start.x+ xoffset, start.y+ yoffset);
685 ++i;
686 int l = count[j];
687 for ( int k = 1; k < l; ++k)
688 {
689 path.AddLineToPoint( points[i].x+ xoffset, points[i].y+ yoffset);
690 ++i;
691 }
692 // close the polygon
693 if ( start != points[i-1])
694 path.AddLineToPoint( start.x+ xoffset, start.y+ yoffset);
695 }
696 m_graphicContext->DrawPath( path , fillStyle);
697 }
698
699 void wxGCDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
700 {
701 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") );
702
703 if ( !m_logicalFunctionSupported )
704 return;
705
706 // CMB: draw nothing if transformed w or h is 0
707 if (w == 0 || h == 0)
708 return;
709
710 if ( m_graphicContext->ShouldOffset() )
711 {
712 // if we are offsetting the entire rectangle is moved 0.5, so the
713 // border line gets off by 1
714 w -= 1;
715 h -= 1;
716 }
717 m_graphicContext->DrawRectangle(x,y,w,h);
718 }
719
720 void wxGCDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
721 wxCoord w, wxCoord h,
722 double radius)
723 {
724 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") );
725
726 if ( !m_logicalFunctionSupported )
727 return;
728
729 if (radius < 0.0)
730 radius = - radius * ((w < h) ? w : h);
731
732 // CMB: draw nothing if transformed w or h is 0
733 if (w == 0 || h == 0)
734 return;
735
736 if ( m_graphicContext->ShouldOffset() )
737 {
738 // if we are offsetting the entire rectangle is moved 0.5, so the
739 // border line gets off by 1
740 w -= 1;
741 h -= 1;
742 }
743 m_graphicContext->DrawRoundedRectangle( x,y,w,h,radius);
744 }
745
746 void wxGCDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
747 {
748 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") );
749
750 if ( !m_logicalFunctionSupported )
751 return;
752
753 if ( m_graphicContext->ShouldOffset() )
754 {
755 // if we are offsetting the entire rectangle is moved 0.5, so the
756 // border line gets off by 1
757 w -= 1;
758 h -= 1;
759 }
760 m_graphicContext->DrawEllipse(x,y,w,h);
761 }
762
763 bool wxGCDCImpl::CanDrawBitmap() const
764 {
765 return true;
766 }
767
768 bool wxGCDCImpl::DoBlit(
769 wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
770 wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask,
771 wxCoord xsrcMask, wxCoord ysrcMask )
772 {
773 return DoStretchBlit( xdest, ydest, width, height,
774 source, xsrc, ysrc, width, height, logical_func, useMask,
775 xsrcMask,ysrcMask );
776 }
777
778 bool wxGCDCImpl::DoStretchBlit(
779 wxCoord xdest, wxCoord ydest, wxCoord dstWidth, wxCoord dstHeight,
780 wxDC *source, wxCoord xsrc, wxCoord ysrc, wxCoord srcWidth, wxCoord srcHeight,
781 int logical_func , bool WXUNUSED(useMask),
782 wxCoord xsrcMask, wxCoord ysrcMask )
783 {
784 wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid DC") );
785 wxCHECK_MSG( source->IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid source DC") );
786
787 if ( logical_func == wxNO_OP )
788 return true;
789 else if ( !m_graphicContext->SetLogicalFunction( logical_func ) )
790
791 {
792 wxFAIL_MSG( wxT("Blitting is only supported with wxCOPY logical operation.") );
793 return false;
794 }
795
796 if (xsrcMask == -1 && ysrcMask == -1)
797 {
798 xsrcMask = xsrc;
799 ysrcMask = ysrc;
800 }
801
802 wxRect subrect(source->LogicalToDeviceX(xsrc),
803 source->LogicalToDeviceY(ysrc),
804 source->LogicalToDeviceXRel(srcWidth),
805 source->LogicalToDeviceYRel(srcHeight));
806
807 // if needed clip the subrect down to the size of the source DC
808 wxCoord sw, sh;
809 source->GetSize(&sw, &sh);
810 sw = source->LogicalToDeviceXRel(sw);
811 sh = source->LogicalToDeviceYRel(sh);
812 if (subrect.x + subrect.width > sw)
813 subrect.width = sw - subrect.x;
814 if (subrect.y + subrect.height > sh)
815 subrect.height = sh - subrect.y;
816
817 wxBitmap blit = source->GetAsBitmap( &subrect );
818
819 if ( blit.IsOk() )
820 {
821 m_graphicContext->DrawBitmap( blit, xdest, ydest,
822 dstWidth, dstHeight);
823 }
824 else
825 {
826 wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") );
827 return false;
828 }
829
830 // reset logical function
831 m_graphicContext->SetLogicalFunction( m_logicalFunction );
832
833 return true;
834 }
835
836 void wxGCDCImpl::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
837 double angle)
838 {
839 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") );
840
841 if ( str.length() == 0 )
842 return;
843 if ( !m_logicalFunctionSupported )
844 return;
845
846 if ( m_backgroundMode == wxTRANSPARENT )
847 m_graphicContext->DrawText( str, x ,y , DegToRad(angle ));
848 else
849 m_graphicContext->DrawText( str, x ,y , DegToRad(angle ), m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) );
850 }
851
852 void wxGCDCImpl::DoDrawText(const wxString& str, wxCoord x, wxCoord y)
853 {
854 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") );
855
856 if ( str.length() == 0 )
857 return;
858
859 if ( !m_logicalFunctionSupported )
860 return;
861
862 if ( m_backgroundMode == wxTRANSPARENT )
863 m_graphicContext->DrawText( str, x ,y);
864 else
865 m_graphicContext->DrawText( str, x ,y , m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) );
866 }
867
868 bool wxGCDCImpl::CanGetTextExtent() const
869 {
870 wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") );
871
872 return true;
873 }
874
875 void wxGCDCImpl::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
876 wxCoord *descent, wxCoord *externalLeading ,
877 const wxFont *theFont ) const
878 {
879 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") );
880
881 if ( theFont )
882 {
883 m_graphicContext->SetFont( *theFont, m_textForegroundColour );
884 }
885
886 wxDouble h , d , e , w;
887
888 m_graphicContext->GetTextExtent( str, &w, &h, &d, &e );
889
890 if ( height )
891 *height = (wxCoord)(h+0.5);
892 if ( descent )
893 *descent = (wxCoord)(d+0.5);
894 if ( externalLeading )
895 *externalLeading = (wxCoord)(e+0.5);
896 if ( width )
897 *width = (wxCoord)(w+0.5);
898
899 if ( theFont )
900 {
901 m_graphicContext->SetFont( m_font, m_textForegroundColour );
902 }
903 }
904
905 bool wxGCDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
906 {
907 wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") );
908 widths.Clear();
909 widths.Add(0,text.Length());
910 if ( text.IsEmpty() )
911 return true;
912
913 wxArrayDouble widthsD;
914
915 m_graphicContext->GetPartialTextExtents( text, widthsD );
916 for ( size_t i = 0; i < widths.GetCount(); ++i )
917 widths[i] = (wxCoord)(widthsD[i] + 0.5);
918
919 return true;
920 }
921
922 wxCoord wxGCDCImpl::GetCharWidth(void) const
923 {
924 wxCoord width;
925 DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL );
926
927 return width;
928 }
929
930 wxCoord wxGCDCImpl::GetCharHeight(void) const
931 {
932 wxCoord height;
933 DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL );
934
935 return height;
936 }
937
938 void wxGCDCImpl::Clear(void)
939 {
940 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::Clear - invalid DC") );
941 // TODO better implementation / incorporate size info into wxGCDC or context
942 m_graphicContext->SetBrush( m_backgroundBrush );
943 wxPen p = *wxTRANSPARENT_PEN;
944 m_graphicContext->SetPen( p );
945 DoDrawRectangle( 0, 0, 32000 , 32000 );
946 m_graphicContext->SetPen( m_pen );
947 m_graphicContext->SetBrush( m_brush );
948 }
949
950 void wxGCDCImpl::DoGetSize(int *width, int *height) const
951 {
952 *width = 10000;
953 *height = 10000;
954 }
955
956 void wxGCDCImpl::DoGradientFillLinear(const wxRect& rect,
957 const wxColour& initialColour,
958 const wxColour& destColour,
959 wxDirection nDirection )
960 {
961 wxPoint start;
962 wxPoint end;
963 switch( nDirection)
964 {
965 case wxWEST :
966 start = rect.GetRightBottom();
967 start.x++;
968 end = rect.GetLeftBottom();
969 break;
970 case wxEAST :
971 start = rect.GetLeftBottom();
972 end = rect.GetRightBottom();
973 end.x++;
974 break;
975 case wxNORTH :
976 start = rect.GetLeftBottom();
977 start.y++;
978 end = rect.GetLeftTop();
979 break;
980 case wxSOUTH :
981 start = rect.GetLeftTop();
982 end = rect.GetLeftBottom();
983 end.y++;
984 break;
985 default :
986 break;
987 }
988
989 if (rect.width == 0 || rect.height == 0)
990 return;
991
992 m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush(
993 start.x,start.y,end.x,end.y, initialColour, destColour));
994 m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
995 m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height);
996 m_graphicContext->SetPen(m_pen);
997 }
998
999 void wxGCDCImpl::DoGradientFillConcentric(const wxRect& rect,
1000 const wxColour& initialColour,
1001 const wxColour& destColour,
1002 const wxPoint& circleCenter)
1003 {
1004 //Radius
1005 wxInt32 cx = rect.GetWidth() / 2;
1006 wxInt32 cy = rect.GetHeight() / 2;
1007 wxInt32 nRadius;
1008 if (cx < cy)
1009 nRadius = cx;
1010 else
1011 nRadius = cy;
1012
1013 // make sure the background is filled (todo move into specific platform implementation ?)
1014 m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
1015 m_graphicContext->SetBrush( wxBrush( destColour) );
1016 m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height);
1017
1018 m_graphicContext->SetBrush( m_graphicContext->CreateRadialGradientBrush(
1019 rect.x+circleCenter.x,rect.y+circleCenter.y,
1020 rect.x+circleCenter.x,rect.y+circleCenter.y,
1021 nRadius,initialColour,destColour));
1022
1023 m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height);
1024 m_graphicContext->SetPen(m_pen);
1025 }
1026
1027 void wxGCDCImpl::DoDrawCheckMark(wxCoord x, wxCoord y,
1028 wxCoord width, wxCoord height)
1029 {
1030 wxDCImpl::DoDrawCheckMark(x,y,width,height);
1031 }
1032
1033 #endif // wxUSE_GRAPHICS_CONTEXT