]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcgraph.cpp
Compilo
[wxWidgets.git] / src / common / dcgraph.cpp
CommitLineData
1b89a5cd
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/graphcmn.cpp
3// Purpose: graphics context methods common to all platforms
4// Author: Stefan Csomor
5// Modified by:
6c0aace2 6// Created:
1b89a5cd
SC
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"
888dde65 22#include "wx/dcgraph.h"
1b89a5cd
SC
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
fcaea2fa
SC
31#ifdef __WXMAC__
32#include "wx/mac/private.h"
33#endif
1b89a5cd
SC
34//-----------------------------------------------------------------------------
35// constants
36//-----------------------------------------------------------------------------
37
38static const double RAD2DEG = 180.0 / M_PI;
39
40//-----------------------------------------------------------------------------
41// Local functions
42//-----------------------------------------------------------------------------
43
44static inline double DegToRad(double deg)
45{
46 return (deg * M_PI) / 180.0;
47}
48
49//-----------------------------------------------------------------------------
50// wxDC bridge class
51//-----------------------------------------------------------------------------
52
1b89a5cd 53IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDC)
888dde65 54
7b1a66bb
RR
55wxGCDC::wxGCDC(const wxWindowDC& dc) :
56 wxDC( new wxGCDCImpl( this, dc ) )
888dde65 57{
888dde65
RR
58}
59
7b1a66bb
RR
60wxGCDC::wxGCDC( const wxMemoryDC& dc) :
61 wxDC( new wxGCDCImpl( this, dc ) )
888dde65 62{
888dde65 63}
1b89a5cd 64
7b1a66bb
RR
65wxGCDC::wxGCDC() :
66 wxDC( new wxGCDCImpl( this ) )
1b89a5cd 67{
888dde65
RR
68}
69
9412ee9a
SC
70wxGCDC::~wxGCDC()
71{
72}
73
888dde65
RR
74wxGraphicsContext* wxGCDC::GetGraphicsContext()
75{
76 if (!m_pimpl) return NULL;
77 wxGCDCImpl *gc_impl = (wxGCDCImpl*) m_pimpl;
78 return gc_impl->GetGraphicsContext();
1b89a5cd
SC
79}
80
81void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx )
888dde65
RR
82{
83 if (!m_pimpl) return;
84 wxGCDCImpl *gc_impl = (wxGCDCImpl*) m_pimpl;
85 gc_impl->SetGraphicsContext( ctx );
86}
87
88IMPLEMENT_ABSTRACT_CLASS(wxGCDCImpl, wxDCImpl)
89
90wxGCDCImpl::wxGCDCImpl( wxDC *owner ) :
91 wxDCImpl( owner )
92{
93 Init();
94}
95
96void wxGCDCImpl::SetGraphicsContext( wxGraphicsContext* ctx )
6c0aace2 97{
1b89a5cd
SC
98 delete m_graphicContext;
99 m_graphicContext = ctx;
914fd3f1
SC
100 if ( m_graphicContext )
101 {
102 m_matrixOriginal = m_graphicContext->GetTransform();
103 m_ok = true;
fd791571
SC
104 // apply the stored transformations to the passed in context
105 ComputeScaleAndOrigin();
ad667945
SC
106 m_graphicContext->SetFont( m_font , m_textForegroundColour );
107 m_graphicContext->SetPen( m_pen );
108 m_graphicContext->SetBrush( m_brush);
914fd3f1 109 }
1b89a5cd
SC
110}
111
888dde65
RR
112wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxWindowDC& dc ) :
113 wxDCImpl( owner )
1b89a5cd
SC
114{
115 Init();
914fd3f1 116 SetGraphicsContext( wxGraphicsContext::Create(dc) );
7b98cf02 117 m_window = dc.GetWindow();
1b89a5cd
SC
118}
119
888dde65
RR
120wxGCDCImpl::wxGCDCImpl( wxDC *owner, const wxMemoryDC& dc ) :
121 wxDCImpl( owner )
773ccc31
SC
122{
123 Init();
124 SetGraphicsContext( wxGraphicsContext::Create(dc) );
125}
773ccc31 126
888dde65 127void wxGCDCImpl::Init()
1b89a5cd
SC
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;
4280b879 139 m_logicalFunctionSupported = true;
1b89a5cd
SC
140}
141
142
888dde65 143wxGCDCImpl::~wxGCDCImpl()
1b89a5cd
SC
144{
145 delete m_graphicContext;
146}
147
888dde65 148void wxGCDCImpl::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNUSED(useMask) )
1b89a5cd 149{
888dde65
RR
150 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") );
151 wxCHECK_RET( bmp.IsOk(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") );
1b89a5cd 152
f889bdb3
SC
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() );
1b89a5cd
SC
165}
166
888dde65 167void wxGCDCImpl::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
1b89a5cd 168{
888dde65
RR
169 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") );
170 wxCHECK_RET( icon.IsOk(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") );
1b89a5cd 171
1b89a5cd
SC
172 wxCoord w = icon.GetWidth();
173 wxCoord h = icon.GetHeight();
1b89a5cd 174
0ebd9515 175 m_graphicContext->DrawIcon( icon , x, y, w, h );
1b89a5cd
SC
176}
177
888dde65 178bool wxGCDCImpl::StartDoc( const wxString& WXUNUSED(message) )
fcaea2fa 179{
26dfebbd 180 return true;
fcaea2fa
SC
181}
182
888dde65 183void wxGCDCImpl::EndDoc()
fcaea2fa
SC
184{
185}
186
888dde65 187void wxGCDCImpl::StartPage()
fcaea2fa
SC
188{
189}
190
888dde65 191void wxGCDCImpl::EndPage()
fcaea2fa
SC
192{
193}
194
888dde65 195void wxGCDCImpl::Flush()
fcaea2fa
SC
196{
197#ifdef __WXMAC__
198 CGContextFlush( (CGContextRef) m_graphicContext->GetNativeContext() );
199#endif
200}
201
888dde65 202void wxGCDCImpl::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
1b89a5cd 203{
888dde65 204 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") );
1b89a5cd 205
0ebd9515 206 m_graphicContext->Clip( x, y, w, h );
1b89a5cd
SC
207 if ( m_clipping )
208 {
0ebd9515
SC
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) );
1b89a5cd
SC
213 }
214 else
215 {
216 m_clipping = true;
217
0ebd9515
SC
218 m_clipX1 = x;
219 m_clipY1 = y;
220 m_clipX2 = x + w;
221 m_clipY2 = y + h;
1b89a5cd
SC
222 }
223}
224
888dde65 225void wxGCDCImpl::DoSetClippingRegionAsRegion( const wxRegion &region )
1b89a5cd 226{
4bae004c 227 // region is in device coordinates
888dde65 228 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") );
1b89a5cd
SC
229
230 if (region.Empty())
231 {
fcaea2fa 232 //DestroyClippingRegion();
1b89a5cd
SC
233 return;
234 }
235
4bae004c 236 wxRegion logRegion( region );
1b89a5cd 237 wxCoord x, y, w, h;
0ebd9515 238
4bae004c
SC
239 logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) );
240 logRegion.GetBox( x, y, w, h );
241
242 m_graphicContext->Clip( logRegion );
0ebd9515 243 if ( m_clipping )
1b89a5cd 244 {
0ebd9515
SC
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) );
1b89a5cd
SC
249 }
250 else
251 {
0ebd9515 252 m_clipping = true;
1b89a5cd 253
0ebd9515
SC
254 m_clipX1 = x;
255 m_clipY1 = y;
256 m_clipX2 = x + w;
257 m_clipY2 = y + h;
1b89a5cd
SC
258 }
259}
260
888dde65 261void wxGCDCImpl::DestroyClippingRegion()
1b89a5cd
SC
262{
263 m_graphicContext->ResetClip();
cb6e26b8
SC
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 ;
888dde65 267 GetOwner()->GetSize( &width , &height ) ;
fcaea2fa 268 m_graphicContext->Clip( DeviceToLogicalX(0) , DeviceToLogicalY(0) , DeviceToLogicalXRel(width), DeviceToLogicalYRel(height) );
cb6e26b8 269
1b89a5cd
SC
270 m_graphicContext->SetPen( m_pen );
271 m_graphicContext->SetBrush( m_brush );
272
273 m_clipping = false;
274}
275
888dde65 276void wxGCDCImpl::DoGetSizeMM( int* width, int* height ) const
1b89a5cd
SC
277{
278 int w = 0, h = 0;
279
888dde65 280 GetOwner()->GetSize( &w, &h );
1b89a5cd
SC
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
888dde65 287void wxGCDCImpl::SetTextForeground( const wxColour &col )
1b89a5cd 288{
888dde65 289 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") );
1b89a5cd
SC
290
291 if ( col != m_textForegroundColour )
292 {
293 m_textForegroundColour = col;
294 m_graphicContext->SetFont( m_font, m_textForegroundColour );
295 }
296}
297
888dde65 298void wxGCDCImpl::SetTextBackground( const wxColour &col )
1b89a5cd 299{
888dde65 300 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") );
1b89a5cd
SC
301
302 m_textBackgroundColour = col;
303}
304
888dde65 305void wxGCDCImpl::SetMapMode( int mode )
1b89a5cd
SC
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
888dde65 334wxSize wxGCDCImpl::GetPPI() const
1b89a5cd
SC
335{
336 return wxSize(72, 72);
337}
338
888dde65 339int wxGCDCImpl::GetDepth() const
1b89a5cd
SC
340{
341 return 32;
342}
343
888dde65 344void wxGCDCImpl::ComputeScaleAndOrigin()
2dedef25
SC
345{
346 wxDCImpl::ComputeScaleAndOrigin();
1b89a5cd 347
fd791571
SC
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 }
1b89a5cd
SC
359}
360
888dde65 361void wxGCDCImpl::SetPalette( const wxPalette& WXUNUSED(palette) )
1b89a5cd
SC
362{
363
364}
365
888dde65 366void wxGCDCImpl::SetBackgroundMode( int mode )
1b89a5cd
SC
367{
368 m_backgroundMode = mode;
369}
370
888dde65 371void wxGCDCImpl::SetFont( const wxFont &font )
1b89a5cd
SC
372{
373 m_font = font;
374 if ( m_graphicContext )
375 {
376 wxFont f = font;
888dde65 377 if ( f.IsOk() )
0ebd9515 378 f.SetPointSize( /*LogicalToDeviceYRel*/(font.GetPointSize()));
1b89a5cd
SC
379 m_graphicContext->SetFont( f, m_textForegroundColour );
380 }
381}
382
888dde65 383void wxGCDCImpl::SetPen( const wxPen &pen )
1b89a5cd
SC
384{
385 if ( m_pen == pen )
386 return;
387
388 m_pen = pen;
389 if ( m_graphicContext )
390 {
0ebd9515 391 m_graphicContext->SetPen( m_pen );
1b89a5cd
SC
392 }
393}
394
888dde65 395void wxGCDCImpl::SetBrush( const wxBrush &brush )
1b89a5cd
SC
396{
397 if (m_brush == brush)
398 return;
399
400 m_brush = brush;
401 if ( m_graphicContext )
402 {
0ebd9515 403 m_graphicContext->SetBrush( m_brush );
1b89a5cd
SC
404 }
405}
4280b879 406
888dde65 407void wxGCDCImpl::SetBackground( const wxBrush &brush )
1b89a5cd
SC
408{
409 if (m_backgroundBrush == brush)
410 return;
411
412 m_backgroundBrush = brush;
888dde65 413 if (!m_backgroundBrush.IsOk())
1b89a5cd
SC
414 return;
415}
416
888dde65 417void wxGCDCImpl::SetLogicalFunction( int function )
1b89a5cd
SC
418{
419 if (m_logicalFunction == function)
420 return;
421
422 m_logicalFunction = function;
4280b879
SC
423 if ( m_graphicContext->SetLogicalFunction( function ) )
424 m_logicalFunctionSupported=true;
1b89a5cd 425 else
4280b879 426 m_logicalFunctionSupported=false;
1b89a5cd
SC
427}
428
888dde65 429bool wxGCDCImpl::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
1b89a5cd
SC
430 const wxColour& WXUNUSED(col), int WXUNUSED(style))
431{
432 return false;
433}
434
888dde65 435bool wxGCDCImpl::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const
1b89a5cd
SC
436{
437 // wxCHECK_MSG( 0 , false, wxT("wxGCDC(cg)::DoGetPixel - not implemented") );
438 return false;
439}
440
888dde65 441void wxGCDCImpl::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
1b89a5cd 442{
888dde65 443 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") );
1b89a5cd 444
4280b879 445 if ( !m_logicalFunctionSupported )
1b89a5cd 446 return;
1b89a5cd 447
0ebd9515 448 m_graphicContext->StrokeLine(x1,y1,x2,y2);
1b89a5cd
SC
449
450 CalcBoundingBox(x1, y1);
451 CalcBoundingBox(x2, y2);
452}
453
888dde65 454void wxGCDCImpl::DoCrossHair( wxCoord x, wxCoord y )
1b89a5cd 455{
888dde65 456 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") );
1b89a5cd 457
4280b879 458 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
459 return;
460
461 int w = 0, h = 0;
462
888dde65 463 GetOwner()->GetSize( &w, &h );
1b89a5cd 464
0ebd9515
SC
465 m_graphicContext->StrokeLine(0,y,w,y);
466 m_graphicContext->StrokeLine(x,0,x,h);
1b89a5cd 467
0ebd9515
SC
468 CalcBoundingBox(0, 0);
469 CalcBoundingBox(0+w, 0+h);
1b89a5cd
SC
470}
471
888dde65 472void wxGCDCImpl::DoDrawArc( wxCoord x1, wxCoord y1,
1b89a5cd
SC
473 wxCoord x2, wxCoord y2,
474 wxCoord xc, wxCoord yc )
475{
888dde65 476 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") );
1b89a5cd 477
4280b879 478 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
479 return;
480
0ebd9515
SC
481 double dx = x1 - xc;
482 double dy = y1 - yc;
1b89a5cd
SC
483 double radius = sqrt((double)(dx * dx + dy * dy));
484 wxCoord rad = (wxCoord)radius;
485 double sa, ea;
0ebd9515 486 if (x1 == x2 && y1 == y2)
1b89a5cd
SC
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 {
0ebd9515
SC
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;
1b89a5cd
SC
503 }
504
505 bool fill = m_brush.GetStyle() != wxTRANSPARENT;
506
a4e73390 507 wxGraphicsPath path = m_graphicContext->CreatePath();
1b89a5cd 508 if ( fill && ((x1!=x2)||(y1!=y2)) )
0ebd9515 509 path.MoveToPoint( xc, yc );
4bae004c
SC
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 );
1b89a5cd 513 if ( fill && ((x1!=x2)||(y1!=y2)) )
0ebd9515 514 path.AddLineToPoint( xc, yc );
1b89a5cd 515 m_graphicContext->DrawPath(path);
1b89a5cd
SC
516}
517
888dde65 518void wxGCDCImpl::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h,
1b89a5cd
SC
519 double sa, double ea )
520{
888dde65 521 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") );
1b89a5cd 522
4280b879 523 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
524 return;
525
1b89a5cd 526 m_graphicContext->PushState();
d9485f89 527 m_graphicContext->Translate(x+w/2.0,y+h/2.0);
0ebd9515 528 wxDouble factor = ((wxDouble) w) / h;
1b89a5cd 529 m_graphicContext->Scale( factor , 1.0);
d9485f89 530
1b89a5cd
SC
531 // since these angles (ea,sa) are measured counter-clockwise, we invert them to
532 // get clockwise angles
fcaea2fa
SC
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();
d9485f89 550 path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea );
1b89a5cd 551 m_graphicContext->DrawPath( path );
fcaea2fa
SC
552 }
553
1b89a5cd 554 m_graphicContext->PopState();
1b89a5cd
SC
555}
556
888dde65 557void wxGCDCImpl::DoDrawPoint( wxCoord x, wxCoord y )
1b89a5cd 558{
888dde65 559 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") );
1b89a5cd
SC
560
561 DoDrawLine( x , y , x + 1 , y + 1 );
562}
563
888dde65 564void wxGCDCImpl::DoDrawLines(int n, wxPoint points[],
1b89a5cd
SC
565 wxCoord xoffset, wxCoord yoffset)
566{
888dde65 567 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") );
1b89a5cd 568
4280b879 569 if ( !m_logicalFunctionSupported )
1b89a5cd 570 return;
1b89a5cd
SC
571
572 wxPoint2DDouble* pointsD = new wxPoint2DDouble[n];
573 for( int i = 0; i < n; ++i)
574 {
0ebd9515
SC
575 pointsD[i].m_x = points[i].x + xoffset;
576 pointsD[i].m_y = points[i].y + yoffset;
1b89a5cd
SC
577 }
578
579 m_graphicContext->StrokeLines( n , pointsD);
580 delete[] pointsD;
581}
582
583#if wxUSE_SPLINES
888dde65 584void wxGCDCImpl::DoDrawSpline(const wxPointList *points)
1b89a5cd 585{
888dde65 586 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") );
1b89a5cd 587
4280b879 588 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
589 return;
590
a4e73390 591 wxGraphicsPath path = m_graphicContext->CreatePath();
1b89a5cd 592
b0d7707b
RR
593 wxPointList::compatibility_iterator node = points->GetFirst();
594 if (node == wxPointList::compatibility_iterator())
1b89a5cd
SC
595 // empty list
596 return;
597
b0d7707b 598 wxPoint *p = node->GetData();
1b89a5cd
SC
599
600 wxCoord x1 = p->x;
601 wxCoord y1 = p->y;
602
603 node = node->GetNext();
b0d7707b 604 p = node->GetData();
1b89a5cd
SC
605
606 wxCoord x2 = p->x;
607 wxCoord y2 = p->y;
608 wxCoord cx1 = ( x1 + x2 ) / 2;
609 wxCoord cy1 = ( y1 + y2 ) / 2;
610
0ebd9515
SC
611 path.MoveToPoint( x1 , y1 );
612 path.AddLineToPoint( cx1 , cy1 );
1b89a5cd
SC
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 {
b0d7707b 622 p = node->GetData();
1b89a5cd
SC
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
0ebd9515 630 path.AddQuadCurveToPoint(x1 , y1 ,cx4 , cy4 );
1b89a5cd
SC
631
632 cx1 = cx4;
633 cy1 = cy4;
634 }
635
0ebd9515 636 path.AddLineToPoint( x2 , y2 );
1b89a5cd
SC
637
638 m_graphicContext->StrokePath( path );
1b89a5cd
SC
639}
640#endif // wxUSE_SPLINES
641
888dde65 642void wxGCDCImpl::DoDrawPolygon( int n, wxPoint points[],
1b89a5cd
SC
643 wxCoord xoffset, wxCoord yoffset,
644 int fillStyle )
645{
888dde65 646 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") );
1b89a5cd
SC
647
648 if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) )
649 return;
4280b879 650 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
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 {
0ebd9515
SC
660 pointsD[i].m_x = points[i].x + xoffset;
661 pointsD[i].m_y = points[i].y + yoffset;
1b89a5cd
SC
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
888dde65 670void wxGCDCImpl::DoDrawPolyPolygon(int n,
1b89a5cd
SC
671 int count[],
672 wxPoint points[],
673 wxCoord xoffset,
674 wxCoord yoffset,
675 int fillStyle)
676{
677 wxASSERT(n > 1);
a4e73390 678 wxGraphicsPath path = m_graphicContext->CreatePath();
1b89a5cd
SC
679
680 int i = 0;
681 for ( int j = 0; j < n; ++j)
682 {
683 wxPoint start = points[i];
0ebd9515 684 path.MoveToPoint( start.x+ xoffset, start.y+ yoffset);
1b89a5cd
SC
685 ++i;
686 int l = count[j];
687 for ( int k = 1; k < l; ++k)
688 {
0ebd9515 689 path.AddLineToPoint( points[i].x+ xoffset, points[i].y+ yoffset);
1b89a5cd
SC
690 ++i;
691 }
692 // close the polygon
693 if ( start != points[i-1])
0ebd9515 694 path.AddLineToPoint( start.x+ xoffset, start.y+ yoffset);
1b89a5cd
SC
695 }
696 m_graphicContext->DrawPath( path , fillStyle);
1b89a5cd
SC
697}
698
888dde65 699void wxGCDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
1b89a5cd 700{
888dde65 701 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") );
1b89a5cd 702
4280b879 703 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
704 return;
705
1b89a5cd 706 // CMB: draw nothing if transformed w or h is 0
0ebd9515 707 if (w == 0 || h == 0)
1b89a5cd
SC
708 return;
709
5ebfdf41
SC
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
0ebd9515
SC
714 w -= 1;
715 h -= 1;
5ebfdf41 716 }
0ebd9515 717 m_graphicContext->DrawRectangle(x,y,w,h);
1b89a5cd
SC
718}
719
888dde65 720void wxGCDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y,
0ebd9515 721 wxCoord w, wxCoord h,
1b89a5cd
SC
722 double radius)
723{
888dde65 724 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") );
1b89a5cd 725
4280b879 726 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
727 return;
728
729 if (radius < 0.0)
0ebd9515 730 radius = - radius * ((w < h) ? w : h);
1b89a5cd
SC
731
732 // CMB: draw nothing if transformed w or h is 0
0ebd9515 733 if (w == 0 || h == 0)
1b89a5cd
SC
734 return;
735
d9485f89
RD
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 }
0ebd9515 743 m_graphicContext->DrawRoundedRectangle( x,y,w,h,radius);
1b89a5cd
SC
744}
745
888dde65 746void wxGCDCImpl::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
1b89a5cd 747{
888dde65 748 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") );
1b89a5cd 749
4280b879 750 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
751 return;
752
d9485f89
RD
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 }
0ebd9515 760 m_graphicContext->DrawEllipse(x,y,w,h);
1b89a5cd
SC
761}
762
888dde65 763bool wxGCDCImpl::CanDrawBitmap() const
1b89a5cd
SC
764{
765 return true;
766}
767
888dde65 768bool wxGCDCImpl::DoBlit(
1b89a5cd 769 wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
e3b81044 770 wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask,
1b89a5cd
SC
771 wxCoord xsrcMask, wxCoord ysrcMask )
772{
e3b81044
VZ
773 return DoStretchBlit( xdest, ydest, width, height,
774 source, xsrc, ysrc, width, height, logical_func, useMask,
775 xsrcMask,ysrcMask );
776}
777
888dde65 778bool wxGCDCImpl::DoStretchBlit(
e3b81044
VZ
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{
888dde65
RR
784 wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid DC") );
785 wxCHECK_MSG( source->IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid source DC") );
6c0aace2 786
1b89a5cd
SC
787 if ( logical_func == wxNO_OP )
788 return true;
fcaea2fa
SC
789 else if ( !m_graphicContext->SetLogicalFunction( logical_func ) )
790
c64c9cd3
KO
791 {
792 wxFAIL_MSG( wxT("Blitting is only supported with wxCOPY logical operation.") );
793 return false;
794 }
1b89a5cd
SC
795
796 if (xsrcMask == -1 && ysrcMask == -1)
797 {
798 xsrcMask = xsrc;
799 ysrcMask = ysrc;
800 }
801
cce4a2ce
RD
802 wxRect subrect(source->LogicalToDeviceX(xsrc),
803 source->LogicalToDeviceY(ysrc),
e3b81044
VZ
804 source->LogicalToDeviceXRel(srcWidth),
805 source->LogicalToDeviceYRel(srcHeight));
cce4a2ce
RD
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;
6c0aace2 816
64c8307c 817 wxBitmap blit = source->GetAsBitmap( &subrect );
6c0aace2 818
888dde65 819 if ( blit.IsOk() )
c64c9cd3 820 {
cce4a2ce 821 m_graphicContext->DrawBitmap( blit, xdest, ydest,
e3b81044 822 dstWidth, dstHeight);
c64c9cd3 823 }
1b89a5cd
SC
824 else
825 {
c64c9cd3 826 wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") );
1b89a5cd
SC
827 return false;
828 }
829
fcaea2fa
SC
830 // reset logical function
831 m_graphicContext->SetLogicalFunction( m_logicalFunction );
832
1b89a5cd
SC
833 return true;
834}
835
888dde65 836void wxGCDCImpl::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y,
1b89a5cd
SC
837 double angle)
838{
888dde65 839 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") );
1b89a5cd
SC
840
841 if ( str.length() == 0 )
842 return;
4280b879 843 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
844 return;
845
068eb463
SC
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) ) );
1b89a5cd
SC
850}
851
888dde65 852void wxGCDCImpl::DoDrawText(const wxString& str, wxCoord x, wxCoord y)
1b89a5cd 853{
888dde65 854 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") );
1b89a5cd
SC
855
856 if ( str.length() == 0 )
857 return;
4280b879
SC
858
859 if ( !m_logicalFunctionSupported )
1b89a5cd
SC
860 return;
861
068eb463
SC
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) ) );
1b89a5cd
SC
866}
867
888dde65 868bool wxGCDCImpl::CanGetTextExtent() const
1b89a5cd 869{
888dde65 870 wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") );
1b89a5cd
SC
871
872 return true;
873}
874
888dde65 875void wxGCDCImpl::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height,
1b89a5cd 876 wxCoord *descent, wxCoord *externalLeading ,
c94f845b 877 const wxFont *theFont ) const
1b89a5cd 878{
888dde65 879 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") );
1b89a5cd
SC
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 )
fcaea2fa 891 *height = (wxCoord)(h+0.5);
1b89a5cd 892 if ( descent )
fcaea2fa 893 *descent = (wxCoord)(d+0.5);
1b89a5cd 894 if ( externalLeading )
fcaea2fa 895 *externalLeading = (wxCoord)(e+0.5);
1b89a5cd 896 if ( width )
fcaea2fa 897 *width = (wxCoord)(w+0.5);
1b89a5cd
SC
898
899 if ( theFont )
900 {
901 m_graphicContext->SetFont( m_font, m_textForegroundColour );
902 }
903}
904
888dde65 905bool wxGCDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
1b89a5cd 906{
888dde65 907 wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") );
1b89a5cd
SC
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 )
0ebd9515 917 widths[i] = (wxCoord)(widthsD[i] + 0.5);
1b89a5cd
SC
918
919 return true;
920}
921
888dde65 922wxCoord wxGCDCImpl::GetCharWidth(void) const
1b89a5cd
SC
923{
924 wxCoord width;
925 DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL );
926
927 return width;
928}
929
888dde65 930wxCoord wxGCDCImpl::GetCharHeight(void) const
1b89a5cd
SC
931{
932 wxCoord height;
933 DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL );
934
935 return height;
936}
937
888dde65 938void wxGCDCImpl::Clear(void)
1b89a5cd 939{
888dde65 940 wxCHECK_RET( IsOk(), wxT("wxGCDC(cg)::Clear - invalid DC") );
1b89a5cd
SC
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 );
6c0aace2 946 m_graphicContext->SetPen( m_pen );
1b89a5cd
SC
947 m_graphicContext->SetBrush( m_brush );
948}
949
888dde65 950void wxGCDCImpl::DoGetSize(int *width, int *height) const
1b89a5cd 951{
fcaea2fa
SC
952 *width = 10000;
953 *height = 10000;
1b89a5cd
SC
954}
955
888dde65 956void wxGCDCImpl::DoGradientFillLinear(const wxRect& rect,
1b89a5cd
SC
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
0ebd9515 989 if (rect.width == 0 || rect.height == 0)
1b89a5cd
SC
990 return;
991
0ebd9515
SC
992 m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush(
993 start.x,start.y,end.x,end.y, initialColour, destColour));
1b89a5cd 994 m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
0ebd9515 995 m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height);
1b89a5cd
SC
996 m_graphicContext->SetPen(m_pen);
997}
998
888dde65 999void wxGCDCImpl::DoGradientFillConcentric(const wxRect& rect,
1b89a5cd
SC
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
0ebd9515 1013 // make sure the background is filled (todo move into specific platform implementation ?)
1b89a5cd
SC
1014 m_graphicContext->SetPen(*wxTRANSPARENT_PEN);
1015 m_graphicContext->SetBrush( wxBrush( destColour) );
0ebd9515 1016 m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height);
1b89a5cd
SC
1017
1018 m_graphicContext->SetBrush( m_graphicContext->CreateRadialGradientBrush(
0ebd9515
SC
1019 rect.x+circleCenter.x,rect.y+circleCenter.y,
1020 rect.x+circleCenter.x,rect.y+circleCenter.y,
1021 nRadius,initialColour,destColour));
1b89a5cd 1022
0ebd9515 1023 m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height);
1b89a5cd
SC
1024 m_graphicContext->SetPen(m_pen);
1025}
1026
888dde65 1027void wxGCDCImpl::DoDrawCheckMark(wxCoord x, wxCoord y,
1b89a5cd
SC
1028 wxCoord width, wxCoord height)
1029{
888dde65 1030 wxDCImpl::DoDrawCheckMark(x,y,width,height);
1b89a5cd
SC
1031}
1032
1033#endif // wxUSE_GRAPHICS_CONTEXT