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