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