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