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