Made wxClientDC's use safe as per wxMSW.
[wxWidgets.git] / src / gtk / dcclient.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dcclient.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "dcclient.h"
12 #endif
13
14 #include "wx/dcclient.h"
15 #include "wx/dcmemory.h"
16 #include "wx/image.h"
17 #include <math.h>
18
19 #include "gdk/gdk.h"
20 #include "gtk/gtk.h"
21
22 //-----------------------------------------------------------------------------
23 // local data
24 //-----------------------------------------------------------------------------
25
26 #include "bdiag.xbm"
27 #include "fdiag.xbm"
28 #include "cdiag.xbm"
29 #include "horiz.xbm"
30 #include "verti.xbm"
31 #include "cross.xbm"
32 #define num_hatches 6
33
34 static GdkPixmap *hatches[num_hatches];
35 static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
36
37 //-----------------------------------------------------------------------------
38 // constants
39 //-----------------------------------------------------------------------------
40
41 #define RAD2DEG 57.2957795131
42
43 //-----------------------------------------------------------------------------
44 // temporary implementation of the missing GDK function
45 //-----------------------------------------------------------------------------
46
47 #include "gdk/gdkprivate.h"
48
49 void gdk_draw_bitmap (GdkDrawable *drawable,
50 GdkGC *gc,
51 GdkDrawable *src,
52 gint xsrc,
53 gint ysrc,
54 gint xdest,
55 gint ydest,
56 gint width,
57 gint height)
58 {
59 GdkWindowPrivate *drawable_private;
60 GdkWindowPrivate *src_private;
61 GdkGCPrivate *gc_private;
62
63 g_return_if_fail (drawable != NULL);
64 g_return_if_fail (src != NULL);
65 g_return_if_fail (gc != NULL);
66
67 drawable_private = (GdkWindowPrivate*) drawable;
68 src_private = (GdkWindowPrivate*) src;
69 if (drawable_private->destroyed || src_private->destroyed)
70 return;
71
72 gc_private = (GdkGCPrivate*) gc;
73
74 if (width == -1) width = src_private->width;
75 if (height == -1) height = src_private->height;
76
77 XCopyPlane( drawable_private->xdisplay,
78 src_private->xwindow,
79 drawable_private->xwindow,
80 gc_private->xgc,
81 xsrc, ysrc,
82 width, height,
83 xdest, ydest,
84 1 );
85 }
86
87 //-----------------------------------------------------------------------------
88 // wxWindowDC
89 //-----------------------------------------------------------------------------
90
91 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
92
93 wxWindowDC::wxWindowDC()
94 {
95 m_penGC = (GdkGC *) NULL;
96 m_brushGC = (GdkGC *) NULL;
97 m_textGC = (GdkGC *) NULL;
98 m_bgGC = (GdkGC *) NULL;
99 m_cmap = (GdkColormap *) NULL;
100 m_isMemDC = FALSE;
101 m_owner = (wxWindow *)NULL;
102 }
103
104 wxWindowDC::wxWindowDC( wxWindow *window )
105 {
106 m_penGC = (GdkGC *) NULL;
107 m_brushGC = (GdkGC *) NULL;
108 m_textGC = (GdkGC *) NULL;
109 m_bgGC = (GdkGC *) NULL;
110 m_cmap = (GdkColormap *) NULL;
111 m_owner = (wxWindow *)NULL;
112 m_isMemDC = FALSE;
113
114 wxASSERT_MSG( window, "DC needs a window" );
115
116 GtkWidget *widget = window->m_wxwindow;
117
118 wxASSERT_MSG( widget, "DC needs a widget" );
119
120 m_window = widget->window;
121
122 /* not realized ? */
123 if (!m_window)
124 {
125 /* don't report problems */
126 m_ok = TRUE;
127
128 return;
129 }
130
131 if (window->m_wxwindow)
132 m_cmap = gtk_widget_get_colormap( window->m_wxwindow );
133 else
134 m_cmap = gtk_widget_get_colormap( window->m_widget );
135
136 SetUpDC();
137
138 /* this must be done after SetUpDC, bacause SetUpDC calls the
139 repective SetBrush, SetPen, SetBackground etc functions
140 to set up the DC. SetBackground call m_owner->SetBackground
141 and this might not be desired as the standard dc background
142 is white whereas a window might assume gray to be the
143 standard (as e.g. wxStatusBar) */
144
145 m_owner = window;
146 }
147
148 wxWindowDC::~wxWindowDC()
149 {
150 Destroy();
151 }
152
153 void wxWindowDC::DoFloodFill( long WXUNUSED(x), long WXUNUSED(y),
154 const wxColour &WXUNUSED(col), int WXUNUSED(style) )
155 {
156 wxFAIL_MSG( _T("wxWindowDC::DoFloodFill not implemented") );
157 }
158
159 bool wxWindowDC::DoGetPixel( long WXUNUSED(x1), long WXUNUSED(y1), wxColour *WXUNUSED(col) ) const
160 {
161 wxFAIL_MSG( _T("wxWindowDC::DoGetPixel not implemented") );
162 return FALSE;
163 }
164
165 void wxWindowDC::DoDrawLine( long x1, long y1, long x2, long y2 )
166 {
167 wxCHECK_RET( Ok(), _T("invalid window dc") );
168
169 if (m_pen.GetStyle() != wxTRANSPARENT)
170 {
171 if (m_window)
172 gdk_draw_line( m_window, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
173
174 CalcBoundingBox(x1, y1);
175 CalcBoundingBox(x2, y2);
176 }
177 }
178
179 void wxWindowDC::DoCrossHair( long x, long y )
180 {
181 wxCHECK_RET( Ok(), _T("invalid window dc") );
182
183 if (m_pen.GetStyle() != wxTRANSPARENT)
184 {
185 int w = 0;
186 int h = 0;
187 GetSize( &w, &h );
188 long xx = XLOG2DEV(x);
189 long yy = YLOG2DEV(y);
190 if (m_window)
191 {
192 gdk_draw_line( m_window, m_penGC, 0, yy, XLOG2DEVREL(w), yy );
193 gdk_draw_line( m_window, m_penGC, xx, 0, xx, YLOG2DEVREL(h) );
194 }
195 }
196 }
197
198 void wxWindowDC::DoDrawArc( long x1, long y1, long x2, long y2,
199 long xc, long yc )
200 {
201 wxCHECK_RET( Ok(), _T("invalid window dc") );
202
203 long xx1 = XLOG2DEV(x1);
204 long yy1 = YLOG2DEV(y1);
205 long xx2 = XLOG2DEV(x2);
206 long yy2 = YLOG2DEV(y2);
207 long xxc = XLOG2DEV(xc);
208 long yyc = YLOG2DEV(yc);
209 double dx = xx1 - xxc;
210 double dy = yy1 - yyc;
211 double radius = sqrt(dx*dx+dy*dy);
212 long r = (long)radius;
213 double radius1, radius2;
214
215 if (xx1 == xx2 && yy1 == yy2)
216 {
217 radius1 = 0.0;
218 radius2 = 360.0;
219 }
220 else
221 if (radius == 0.0)
222 {
223 radius1 = radius2 = 0.0;
224 }
225 else
226 {
227 radius1 = (xx1 - xxc == 0) ?
228 (yy1 - yyc < 0) ? 90.0 : -90.0 :
229 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
230 radius2 = (xx2 - xxc == 0) ?
231 (yy2 - yyc < 0) ? 90.0 : -90.0 :
232 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
233 }
234 long alpha1 = long(radius1 * 64.0);
235 long alpha2 = long((radius2 - radius1) * 64.0);
236 while (alpha2 <= 0) alpha2 += 360*64;
237 while (alpha1 > 360*64) alpha1 -= 360*64;
238
239 if (m_window)
240 {
241 if (m_brush.GetStyle() != wxTRANSPARENT)
242 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
243
244 if (m_pen.GetStyle() != wxTRANSPARENT)
245 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
246 }
247
248 CalcBoundingBox (x1, y1);
249 CalcBoundingBox (x2, y2);
250 }
251
252 void wxWindowDC::DoDrawEllipticArc( long x, long y, long width, long height, double sa, double ea )
253 {
254 wxCHECK_RET( Ok(), _T("invalid window dc") );
255
256 long xx = XLOG2DEV(x);
257 long yy = YLOG2DEV(y);
258 long ww = m_signX * XLOG2DEVREL(width);
259 long hh = m_signY * YLOG2DEVREL(height);
260
261 // CMB: handle -ve width and/or height
262 if (ww < 0) { ww = -ww; xx = xx - ww; }
263 if (hh < 0) { hh = -hh; yy = yy - hh; }
264
265 if (m_window)
266 {
267 long start = long(sa * 64.0);
268 long end = long(ea * 64.0);
269
270 if (m_brush.GetStyle() != wxTRANSPARENT)
271 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
272
273 if (m_pen.GetStyle() != wxTRANSPARENT)
274 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
275 }
276
277 CalcBoundingBox (x, y);
278 CalcBoundingBox (x + width, y + height);
279 }
280
281 void wxWindowDC::DoDrawPoint( long x, long y )
282 {
283 wxCHECK_RET( Ok(), _T("invalid window dc") );
284
285 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
286 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
287
288 CalcBoundingBox (x, y);
289 }
290
291 void wxWindowDC::DoDrawLines( int n, wxPoint points[], long xoffset, long yoffset )
292 {
293 wxCHECK_RET( Ok(), _T("invalid window dc") );
294
295 if (m_pen.GetStyle() == wxTRANSPARENT) return;
296 if (n <= 0) return;
297
298 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
299
300 for (int i = 0; i < n-1; i++)
301 {
302 long x1 = XLOG2DEV(points[i].x + xoffset);
303 long x2 = XLOG2DEV(points[i+1].x + xoffset);
304 long y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
305 long y2 = YLOG2DEV(points[i+1].y + yoffset);
306 if (m_window)
307 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
308
309 CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset );
310 }
311 }
312
313 void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], long xoffset, long yoffset, int WXUNUSED(fillStyle) )
314 {
315 wxCHECK_RET( Ok(), _T("invalid window dc") );
316
317 if (n <= 0) return;
318
319 GdkPoint *gdkpoints = new GdkPoint[n+1];
320 int i;
321 for (i = 0 ; i < n ; i++)
322 {
323 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
324 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
325
326 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
327 }
328
329 if (m_brush.GetStyle() != wxTRANSPARENT)
330 gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n);
331
332 // To do: Fillstyle
333
334 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
335 {
336 for (i = 0 ; i < n ; i++)
337 {
338 gdk_draw_line( m_window, m_penGC,
339 gdkpoints[i%n].x,
340 gdkpoints[i%n].y,
341 gdkpoints[(i+1)%n].x,
342 gdkpoints[(i+1)%n].y);
343 }
344 }
345
346 delete[] gdkpoints;
347 }
348
349 void wxWindowDC::DoDrawRectangle( long x, long y, long width, long height )
350 {
351 wxCHECK_RET( Ok(), _T("invalid window dc") );
352
353 long xx = XLOG2DEV(x);
354 long yy = YLOG2DEV(y);
355 long ww = m_signX * XLOG2DEVREL(width);
356 long hh = m_signY * YLOG2DEVREL(height);
357
358 // CMB: draw nothing if transformed w or h is 0
359 if (ww == 0 || hh == 0) return;
360
361 // CMB: handle -ve width and/or height
362 if (ww < 0) { ww = -ww; xx = xx - ww; }
363 if (hh < 0) { hh = -hh; yy = yy - hh; }
364
365 if (m_window)
366 {
367 if (m_brush.GetStyle() != wxTRANSPARENT)
368 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
369
370 if (m_pen.GetStyle() != wxTRANSPARENT)
371 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
372 }
373
374 CalcBoundingBox( x, y );
375 CalcBoundingBox( x + width, y + height );
376 }
377
378 void wxWindowDC::DoDrawRoundedRectangle( long x, long y, long width, long height, double radius )
379 {
380 wxCHECK_RET( Ok(), _T("invalid window dc") );
381
382 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
383
384 long xx = XLOG2DEV(x);
385 long yy = YLOG2DEV(y);
386 long ww = m_signX * XLOG2DEVREL(width);
387 long hh = m_signY * YLOG2DEVREL(height);
388 long rr = XLOG2DEVREL((long)radius);
389
390 // CMB: handle -ve width and/or height
391 if (ww < 0) { ww = -ww; xx = xx - ww; }
392 if (hh < 0) { hh = -hh; yy = yy - hh; }
393
394 // CMB: if radius is zero use DrawRectangle() instead to avoid
395 // X drawing errors with small radii
396 if (rr == 0)
397 {
398 DrawRectangle( x, y, width, height );
399 return;
400 }
401
402 // CMB: draw nothing if transformed w or h is 0
403 if (ww == 0 || hh == 0) return;
404
405 // CMB: adjust size if outline is drawn otherwise the result is
406 // 1 pixel too wide and high
407 if (m_pen.GetStyle() != wxTRANSPARENT)
408 {
409 ww--;
410 hh--;
411 }
412
413 if (m_window)
414 {
415 // CMB: ensure dd is not larger than rectangle otherwise we
416 // get an hour glass shape
417 long dd = 2 * rr;
418 if (dd > ww) dd = ww;
419 if (dd > hh) dd = hh;
420 rr = dd / 2;
421
422 if (m_brush.GetStyle() != wxTRANSPARENT)
423 {
424 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
425 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
426 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
427 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
428 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
429 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
430 }
431
432 if (m_pen.GetStyle() != wxTRANSPARENT)
433 {
434 gdk_draw_line( m_window, m_penGC, xx+rr, yy, xx+ww-rr, yy );
435 gdk_draw_line( m_window, m_penGC, xx+rr, yy+hh, xx+ww-rr, yy+hh );
436 gdk_draw_line( m_window, m_penGC, xx, yy+rr, xx, yy+hh-rr );
437 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr, xx+ww, yy+hh-rr );
438 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
439 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
440 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
441 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
442 }
443 }
444
445 // this ignores the radius
446 CalcBoundingBox( x, y );
447 CalcBoundingBox( x + width, y + height );
448 }
449
450 void wxWindowDC::DoDrawEllipse( long x, long y, long width, long height )
451 {
452 wxCHECK_RET( Ok(), _T("invalid window dc") );
453
454 long xx = XLOG2DEV(x);
455 long yy = YLOG2DEV(y);
456 long ww = m_signX * XLOG2DEVREL(width);
457 long hh = m_signY * YLOG2DEVREL(height);
458
459 // CMB: handle -ve width and/or height
460 if (ww < 0) { ww = -ww; xx = xx - ww; }
461 if (hh < 0) { hh = -hh; yy = yy - hh; }
462
463 if (m_window)
464 {
465 if (m_brush.GetStyle() != wxTRANSPARENT)
466 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
467
468 if (m_pen.GetStyle() != wxTRANSPARENT)
469 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
470 }
471
472 CalcBoundingBox( x - width, y - height );
473 CalcBoundingBox( x + width, y + height );
474 }
475
476 void wxWindowDC::DoDrawIcon( const wxIcon &icon, long x, long y )
477 {
478 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
479 DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE );
480 }
481
482 void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
483 long x, long y,
484 bool useMask )
485 {
486 wxCHECK_RET( Ok(), _T("invalid window dc") );
487
488 wxCHECK_RET( bitmap.Ok(), _T("invalid bitmap") );
489
490 if (!m_window) return;
491
492 /* scale/translate size and position */
493
494 int xx = XLOG2DEV(x);
495 int yy = YLOG2DEV(y);
496
497 int w = bitmap.GetWidth();
498 int h = bitmap.GetHeight();
499
500 int ww = XLOG2DEVREL(w);
501 int hh = YLOG2DEVREL(h);
502
503 /* scale bitmap if required */
504
505 wxBitmap use_bitmap;
506
507 if ((w != ww) || (h != hh))
508 {
509 wxImage image( bitmap );
510 image = image.Scale( ww, hh );
511
512 use_bitmap = image.ConvertToBitmap();
513 }
514 else
515 {
516 use_bitmap = bitmap;
517 }
518
519 /* apply mask if any */
520
521 GdkBitmap *mask = (GdkBitmap *) NULL;
522 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
523
524 if (useMask && mask)
525 {
526 gdk_gc_set_clip_mask( m_penGC, mask );
527 gdk_gc_set_clip_origin( m_penGC, xx, yy );
528 }
529
530 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
531
532 GdkPixmap *pm = use_bitmap.GetPixmap();
533 if (pm)
534 {
535 gdk_draw_pixmap( m_window, m_penGC, pm, 0, 0, xx, yy, -1, -1 );
536 }
537 else
538 {
539 GdkBitmap *bm = use_bitmap.GetBitmap();
540 if (bm)
541 {
542 gdk_draw_bitmap( m_window, m_penGC, bm, 0, 0, xx, yy, -1, -1 );
543 }
544 }
545
546 /* remove mask again if any */
547
548 if (useMask && mask)
549 {
550 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
551 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
552 }
553
554 CalcBoundingBox( x, y );
555 CalcBoundingBox( x + w, y + h );
556 }
557
558 bool wxWindowDC::DoBlit( long xdest, long ydest, long width, long height,
559 wxDC *source, long xsrc, long ysrc,
560 int logical_func, bool useMask )
561 {
562 /* this is the nth try to get this utterly useless function to
563 work. it now completely ignores the scaling or translation
564 of the source dc, but scales correctly on the target dc and
565 knows about possible mask information in a memory dc. */
566
567 wxCHECK_MSG( Ok(), FALSE, _T("invalid window dc") );
568
569 wxCHECK_MSG( source, FALSE, _T("invalid source dc") );
570
571 if (!m_window) return FALSE;
572
573 wxClientDC *srcDC = (wxClientDC*)source;
574 wxMemoryDC *memDC = (wxMemoryDC*)source;
575
576 bool use_bitmap_method = FALSE;
577
578 if (srcDC->m_isMemDC)
579 {
580 if (!memDC->m_selected.Ok()) return FALSE;
581
582 /* we use the "XCopyArea" way to copy a memory dc into
583 y different window if the memory dc BOTH
584 a) doesn't have any mask or its mask isn't used
585 b) it is clipped
586 c) is not 1-bit */
587
588 if (useMask && (memDC->m_selected.GetMask()))
589 {
590 /* we HAVE TO use the direct way for memory dcs
591 that have mask since the XCopyArea doesn't know
592 about masks */
593 use_bitmap_method = TRUE;
594 }
595 else if (memDC->m_selected.GetDepth() == 1)
596 {
597 /* we HAVE TO use the direct way for memory dcs
598 that are bitmaps because XCopyArea doesn't cope
599 with different bit depths */
600 use_bitmap_method = TRUE;
601 }
602 else if ((xsrc == 0) && (ysrc == 0) &&
603 (width == memDC->m_selected.GetWidth()) &&
604 (height == memDC->m_selected.GetHeight()))
605 {
606 /* we SHOULD use the direct way if all of the bitmap
607 in the memory dc is copied in which case XCopyArea
608 wouldn't be able able to boost performace by reducing
609 the area to be scaled */
610 use_bitmap_method = TRUE;
611 }
612 else
613 {
614 use_bitmap_method = FALSE;
615 }
616 }
617
618 CalcBoundingBox( xdest, ydest );
619 CalcBoundingBox( xdest + width, ydest + height );
620
621 int old_logical_func = m_logicalFunction;
622 SetLogicalFunction( logical_func );
623
624 if (use_bitmap_method)
625 {
626 /* scale/translate bitmap size */
627
628 long bm_width = memDC->m_selected.GetWidth();
629 long bm_height = memDC->m_selected.GetHeight();
630
631 long bm_ww = XLOG2DEVREL( bm_width );
632 long bm_hh = YLOG2DEVREL( bm_height );
633
634 /* scale bitmap if required */
635
636 wxBitmap use_bitmap;
637
638 if ((bm_width != bm_ww) || (bm_height != bm_hh))
639 {
640 wxImage image( memDC->m_selected );
641 image = image.Scale( bm_ww, bm_hh );
642
643 use_bitmap = image.ConvertToBitmap();
644 }
645 else
646 {
647 use_bitmap = memDC->m_selected;
648 }
649
650 /* scale/translate size and position */
651
652 long xx = XLOG2DEV(xdest);
653 long yy = YLOG2DEV(ydest);
654
655 long ww = XLOG2DEVREL(width);
656 long hh = YLOG2DEVREL(height);
657
658 /* apply mask if any */
659
660 GdkBitmap *mask = (GdkBitmap *) NULL;
661 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
662
663 if (useMask && mask)
664 {
665 gdk_gc_set_clip_mask( m_penGC, mask );
666 gdk_gc_set_clip_origin( m_penGC, xx, yy );
667 }
668
669 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
670
671 GdkPixmap *pm = use_bitmap.GetPixmap();
672 if (pm)
673 {
674 gdk_draw_pixmap( m_window, m_penGC, pm, xsrc, ysrc, xx, yy, ww, hh );
675 }
676 else
677 {
678 GdkBitmap *bm = use_bitmap.GetBitmap();
679 if (bm)
680 {
681 /* we use the textGC here because blitting a bitmap is done
682 using the current text colour */
683 gdk_draw_bitmap( m_window, m_textGC, bm, xsrc, ysrc, xx, yy, ww, hh );
684 }
685 }
686
687 /* remove mask again if any */
688
689 if (useMask && mask)
690 {
691 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
692 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
693 }
694 }
695 else /* use_bitmap_method */
696 {
697 /* scale/translate size and position */
698
699 long xx = XLOG2DEV(xdest);
700 long yy = YLOG2DEV(ydest);
701
702 long ww = XLOG2DEVREL(width);
703 long hh = YLOG2DEVREL(height);
704
705 if ((width != ww) || (height != hh))
706 {
707 /* draw source window into a bitmap as we cannot scale
708 a window in contrast to a bitmap. this would actually
709 work with memory dcs as well, but we'd lose the mask
710 information and waste one step in this process since
711 a memory already has a bitmap. all this is slightly
712 inefficient as we could take an XImage directly from
713 an X window, but we'd then also have to care that
714 the window is not outside the screen (in which case
715 we'd get a BadMatch or what not).
716 Is a double XGetImage and combined XGetPixel and
717 XPutPixel really faster? I'm not sure. look at wxXt
718 for a different implementation of the same problem. */
719
720 wxBitmap bitmap( width, height );
721 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
722 srcDC->GetWindow(),
723 xsrc, ysrc, width, height );
724
725 /* scale image */
726
727 wxImage image( bitmap );
728 image = image.Scale( ww, hh );
729
730 /* convert to bitmap */
731
732 bitmap = image.ConvertToBitmap();
733
734 /* draw scaled bitmap */
735
736 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
737
738 }
739 else
740 {
741 /* no scaling and not a memory dc with a mask either */
742
743 gdk_window_copy_area( m_window, m_penGC, xx, yy,
744 srcDC->GetWindow(),
745 xsrc, ysrc, width, height );
746 }
747 }
748
749 SetLogicalFunction( old_logical_func );
750 return TRUE;
751 }
752
753 void wxWindowDC::DoDrawText( const wxString &text, long x, long y )
754 {
755 wxCHECK_RET( Ok(), _T("invalid window dc") );
756
757 if (!m_window) return;
758
759 GdkFont *font = m_font.GetInternalFont( m_scaleY );
760
761 x = XLOG2DEV(x);
762 y = YLOG2DEV(y);
763
764 /* CMB 21/5/98: draw text background if mode is wxSOLID */
765 if (m_backgroundMode == wxSOLID)
766 {
767 long width = gdk_string_width( font, text.mbc_str() );
768 long height = font->ascent + font->descent;
769 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
770 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
771 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
772 }
773 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
774
775 /* CMB 17/7/98: simple underline: ignores scaling and underlying
776 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
777 properties (see wxXt implementation) */
778 if (m_font.GetUnderlined())
779 {
780 long width = gdk_string_width( font, text.mbc_str() );
781 long ul_y = y + font->ascent;
782 if (font->descent > 0) ul_y++;
783 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
784 }
785
786 long w, h;
787 GetTextExtent (text, &w, &h);
788 CalcBoundingBox (x + w, y + h);
789 CalcBoundingBox (x, y);
790 }
791
792 void wxWindowDC::GetTextExtent( const wxString &string, long *width, long *height,
793 long *descent, long *externalLeading,
794 wxFont *theFont ) const
795 {
796 wxFont fontToUse = m_font;
797 if (theFont) fontToUse = *theFont;
798
799 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
800 if (width) (*width) = long(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
801 if (height) (*height) = long((font->ascent + font->descent) / m_scaleY);
802 if (descent) (*descent) = long(font->descent / m_scaleY);
803 if (externalLeading) (*externalLeading) = 0; // ??
804 }
805
806 long wxWindowDC::GetCharWidth() const
807 {
808 GdkFont *font = m_font.GetInternalFont( m_scaleY );
809 return long(gdk_string_width( font, "H" ) / m_scaleX);
810 }
811
812 long wxWindowDC::GetCharHeight() const
813 {
814 GdkFont *font = m_font.GetInternalFont( m_scaleY );
815 return long((font->ascent + font->descent) / m_scaleY);
816 }
817
818 void wxWindowDC::Clear()
819 {
820 wxCHECK_RET( Ok(), _T("invalid window dc") );
821
822 if (!m_window) return;
823
824 /* - we either are a memory dc or have a window as the
825 owner. anything else shouldn't happen.
826 - we don't use gdk_window_clear() as we don't set
827 the window's background colour anymore. it is too
828 much pain to keep the DC's and the window's back-
829 ground colour in synch. */
830
831 if (m_owner)
832 {
833 int width,height;
834 m_owner->GetSize( &width, &height );
835 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
836 return;
837 }
838
839 if (m_isMemDC)
840 {
841 int width,height;
842 GetSize( &width, &height );
843 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
844 return;
845 }
846 }
847
848 void wxWindowDC::SetFont( const wxFont &font )
849 {
850 m_font = font;
851 }
852
853 void wxWindowDC::SetPen( const wxPen &pen )
854 {
855 wxCHECK_RET( Ok(), _T("invalid window dc") );
856
857 if (m_pen == pen) return;
858
859 m_pen = pen;
860
861 if (!m_pen.Ok()) return;
862
863 if (!m_window) return;
864
865 gint width = m_pen.GetWidth();
866 // CMB: if width is non-zero scale it with the dc
867 if (width <= 0)
868 {
869 width = 1;
870 }
871 else
872 {
873 // X doesn't allow different width in x and y and so we take
874 // the average
875 double w = 0.5 + (abs(XLOG2DEVREL(width)) + abs(YLOG2DEVREL(width))) / 2.0;
876 width = (int)w;
877 }
878
879 GdkLineStyle lineStyle = GDK_LINE_SOLID;
880 switch (m_pen.GetStyle())
881 {
882 case wxSOLID: { lineStyle = GDK_LINE_SOLID; break; }
883 case wxDOT: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
884 case wxLONG_DASH: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
885 case wxSHORT_DASH: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
886 case wxDOT_DASH: { lineStyle = GDK_LINE_DOUBLE_DASH; break; }
887 }
888
889 GdkCapStyle capStyle = GDK_CAP_ROUND;
890 switch (m_pen.GetCap())
891 {
892 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
893 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
894 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
895 }
896
897 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
898 switch (m_pen.GetJoin())
899 {
900 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
901 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
902 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
903 }
904
905 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
906
907 m_pen.GetColour().CalcPixel( m_cmap );
908 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
909 }
910
911 void wxWindowDC::SetBrush( const wxBrush &brush )
912 {
913 wxCHECK_RET( Ok(), _T("invalid window dc") );
914
915 if (m_brush == brush) return;
916
917 m_brush = brush;
918
919 if (!m_brush.Ok()) return;
920
921 if (!m_window) return;
922
923 m_brush.GetColour().CalcPixel( m_cmap );
924 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
925
926 GdkFill fillStyle = GDK_SOLID;
927 switch (m_brush.GetStyle())
928 {
929 case wxSOLID:
930 case wxTRANSPARENT:
931 break;
932 default:
933 fillStyle = GDK_STIPPLED;
934 }
935
936 gdk_gc_set_fill( m_brushGC, fillStyle );
937
938 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
939 {
940 if (m_brush.GetStipple()->GetPixmap())
941 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetPixmap() );
942 else
943 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
944 }
945
946 if (IS_HATCH(m_brush.GetStyle()))
947 {
948 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
949 gdk_gc_set_stipple( m_brushGC, hatches[num] );
950 }
951 }
952
953 void wxWindowDC::SetBackground( const wxBrush &brush )
954 {
955 /* CMB 21/7/98: Added SetBackground. Sets background brush
956 * for Clear() and bg colour for shapes filled with cross-hatch brush */
957
958 wxCHECK_RET( Ok(), _T("invalid window dc") );
959
960 if (m_backgroundBrush == brush) return;
961
962 m_backgroundBrush = brush;
963
964 if (!m_backgroundBrush.Ok()) return;
965
966 if (!m_window) return;
967
968 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
969 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
970 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
971 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
972 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
973
974 GdkFill fillStyle = GDK_SOLID;
975 switch (m_backgroundBrush.GetStyle())
976 {
977 case wxSOLID:
978 case wxTRANSPARENT:
979 break;
980 default:
981 fillStyle = GDK_STIPPLED;
982 }
983
984 gdk_gc_set_fill( m_bgGC, fillStyle );
985
986 if (m_backgroundBrush.GetStyle() == wxSTIPPLE)
987 {
988 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
989 }
990
991 if (IS_HATCH(m_backgroundBrush.GetStyle()))
992 {
993 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
994 gdk_gc_set_stipple( m_bgGC, hatches[num] );
995 }
996 }
997
998 void wxWindowDC::SetLogicalFunction( int function )
999 {
1000 wxCHECK_RET( Ok(), _T("invalid window dc") );
1001
1002 if (m_logicalFunction == function) return;
1003
1004 GdkFunction mode = GDK_COPY;
1005 switch (function)
1006 {
1007 case wxXOR: mode = GDK_XOR; break;
1008 case wxINVERT: mode = GDK_INVERT; break;
1009 #if (GTK_MINOR_VERSION > 0)
1010 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1011 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1012 case wxCLEAR: mode = GDK_CLEAR; break;
1013 case wxSET: mode = GDK_SET; break;
1014 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1015 case wxSRC_AND:
1016 case wxAND: mode = GDK_AND; break;
1017 case wxSRC_OR:
1018 case wxOR: mode = GDK_OR; break;
1019 case wxEQUIV: mode = GDK_EQUIV; break;
1020 case wxNAND: mode = GDK_NAND; break;
1021 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
1022 case wxCOPY: mode = GDK_COPY; break;
1023 case wxNO_OP: mode = GDK_NOOP; break;
1024 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
1025 #endif
1026 default:
1027 {
1028 wxFAIL_MSG( "unsupported logical function" );
1029 break;
1030 }
1031 }
1032
1033 m_logicalFunction = function;
1034
1035 if (!m_window) return;
1036
1037 gdk_gc_set_function( m_penGC, mode );
1038 gdk_gc_set_function( m_brushGC, mode );
1039 gdk_gc_set_function( m_textGC, mode );
1040 }
1041
1042 void wxWindowDC::SetTextForeground( const wxColour &col )
1043 {
1044 wxCHECK_RET( Ok(), _T("invalid window dc") );
1045
1046 if (m_textForegroundColour == col) return;
1047
1048 m_textForegroundColour = col;
1049 if (!m_textForegroundColour.Ok()) return;
1050
1051 if (!m_window) return;
1052
1053 m_textForegroundColour.CalcPixel( m_cmap );
1054 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1055 }
1056
1057 void wxWindowDC::SetTextBackground( const wxColour &col )
1058 {
1059 wxCHECK_RET( Ok(), _T("invalid window dc") );
1060
1061 if (m_textBackgroundColour == col) return;
1062
1063 m_textBackgroundColour = col;
1064 if (!m_textBackgroundColour.Ok()) return;
1065
1066 if (!m_window) return;
1067
1068 m_textBackgroundColour.CalcPixel( m_cmap );
1069 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1070 }
1071
1072 void wxWindowDC::SetBackgroundMode( int mode )
1073 {
1074 wxCHECK_RET( Ok(), _T("invalid window dc") );
1075
1076 m_backgroundMode = mode;
1077
1078 if (!m_window) return;
1079
1080 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1081 // transparent/solid background mode
1082
1083 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1084 {
1085 gdk_gc_set_fill( m_brushGC,
1086 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1087 }
1088 }
1089
1090 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
1091 {
1092 wxFAIL_MSG( _T("wxWindowDC::SetPalette not implemented") );
1093 }
1094
1095 void wxWindowDC::DoSetClippingRegion( long x, long y, long width, long height )
1096 {
1097 wxCHECK_RET( Ok(), _T("invalid window dc") );
1098
1099 wxDC::DoSetClippingRegion( x, y, width, height );
1100
1101 if (!m_window) return;
1102
1103 GdkRectangle rect;
1104 rect.x = XLOG2DEV(x);
1105 rect.y = YLOG2DEV(y);
1106 rect.width = XLOG2DEVREL(width);
1107 rect.height = YLOG2DEVREL(height);
1108 gdk_gc_set_clip_rectangle( m_penGC, &rect );
1109 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
1110 gdk_gc_set_clip_rectangle( m_textGC, &rect );
1111 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
1112 }
1113
1114 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
1115 {
1116 wxCHECK_RET( Ok(), _T("invalid window dc") );
1117
1118 if (region.Empty())
1119 {
1120 DestroyClippingRegion();
1121 return;
1122 }
1123
1124 if (!m_window) return;
1125
1126 gdk_gc_set_clip_region( m_penGC, region.GetRegion() );
1127 gdk_gc_set_clip_region( m_brushGC, region.GetRegion() );
1128 gdk_gc_set_clip_region( m_textGC, region.GetRegion() );
1129 gdk_gc_set_clip_region( m_bgGC, region.GetRegion() );
1130 }
1131
1132 void wxWindowDC::DestroyClippingRegion()
1133 {
1134 wxCHECK_RET( Ok(), _T("invalid window dc") );
1135
1136 wxDC::DestroyClippingRegion();
1137
1138 if (!m_window) return;
1139
1140 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1141 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1142 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1143 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
1144 }
1145
1146 void wxWindowDC::SetUpDC()
1147 {
1148 Destroy();
1149 m_ok = TRUE;
1150 m_logicalFunction = wxCOPY;
1151 m_penGC = gdk_gc_new( m_window );
1152 m_brushGC = gdk_gc_new( m_window );
1153 m_textGC = gdk_gc_new( m_window );
1154 m_bgGC = gdk_gc_new( m_window );
1155
1156 wxColour tmp_col( m_textForegroundColour );
1157 m_textForegroundColour = wxNullColour;
1158 SetTextForeground( tmp_col );
1159 tmp_col = m_textBackgroundColour;
1160 m_textBackgroundColour = wxNullColour;
1161 SetTextBackground( tmp_col );
1162
1163 wxPen tmp_pen( m_pen );
1164 m_pen = wxNullPen;
1165 SetPen( tmp_pen );
1166
1167 wxFont tmp_font( m_font );
1168 m_font = wxNullFont;
1169 SetFont( tmp_font );
1170
1171 wxBrush tmp_brush( m_brush );
1172 m_brush = wxNullBrush;
1173 SetBrush( tmp_brush );
1174
1175 tmp_brush = m_backgroundBrush;
1176 m_backgroundBrush = wxNullBrush;
1177 SetBackground( tmp_brush );
1178
1179 if (!hatch_bitmap)
1180 {
1181 hatch_bitmap = hatches;
1182 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1183 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1184 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1185 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1186 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1187 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1188 }
1189 }
1190
1191 void wxWindowDC::Destroy()
1192 {
1193 if (m_penGC) gdk_gc_unref( m_penGC );
1194 m_penGC = (GdkGC*) NULL;
1195 if (m_brushGC) gdk_gc_unref( m_brushGC );
1196 m_brushGC = (GdkGC*) NULL;
1197 if (m_textGC) gdk_gc_unref( m_textGC );
1198 m_textGC = (GdkGC*) NULL;
1199 if (m_bgGC) gdk_gc_unref( m_bgGC );
1200 m_bgGC = (GdkGC*) NULL;
1201 }
1202
1203 // Resolution in pixels per logical inch
1204 wxSize wxWindowDC::GetPPI() const
1205 {
1206 return wxSize(100, 100);
1207 }
1208
1209 int wxWindowDC::GetDepth() const
1210 {
1211 wxFAIL_MSG(_T("not implemented"));
1212
1213 return -1;
1214 }
1215
1216 #if wxUSE_SPLINES
1217 // ----------------------------------- spline code ----------------------------------------
1218
1219 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1220 double a3, double b3, double a4, double b4);
1221 void wx_clear_stack();
1222 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1223 double *y3, double *x4, double *y4);
1224 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1225 double x4, double y4);
1226 static bool wx_spline_add_point(double x, double y);
1227 static void wx_spline_draw_point_array(wxDC *dc);
1228
1229 wxList wx_spline_point_list;
1230
1231 #define half(z1, z2) ((z1+z2)/2.0)
1232 #define THRESHOLD 5
1233
1234 /* iterative version */
1235
1236 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1237 double b4)
1238 {
1239 register double xmid, ymid;
1240 double x1, y1, x2, y2, x3, y3, x4, y4;
1241
1242 wx_clear_stack();
1243 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1244
1245 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1246 xmid = (double)half(x2, x3);
1247 ymid = (double)half(y2, y3);
1248 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1249 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1250 wx_spline_add_point( x1, y1 );
1251 wx_spline_add_point( xmid, ymid );
1252 } else {
1253 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1254 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1255 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1256 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1257 }
1258 }
1259 }
1260
1261 /* utilities used by spline drawing routines */
1262
1263 typedef struct wx_spline_stack_struct {
1264 double x1, y1, x2, y2, x3, y3, x4, y4;
1265 } Stack;
1266
1267 #define SPLINE_STACK_DEPTH 20
1268 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1269 static Stack *wx_stack_top;
1270 static int wx_stack_count;
1271
1272 void wx_clear_stack()
1273 {
1274 wx_stack_top = wx_spline_stack;
1275 wx_stack_count = 0;
1276 }
1277
1278 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1279 {
1280 wx_stack_top->x1 = x1;
1281 wx_stack_top->y1 = y1;
1282 wx_stack_top->x2 = x2;
1283 wx_stack_top->y2 = y2;
1284 wx_stack_top->x3 = x3;
1285 wx_stack_top->y3 = y3;
1286 wx_stack_top->x4 = x4;
1287 wx_stack_top->y4 = y4;
1288 wx_stack_top++;
1289 wx_stack_count++;
1290 }
1291
1292 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1293 double *x3, double *y3, double *x4, double *y4)
1294 {
1295 if (wx_stack_count == 0)
1296 return (0);
1297 wx_stack_top--;
1298 wx_stack_count--;
1299 *x1 = wx_stack_top->x1;
1300 *y1 = wx_stack_top->y1;
1301 *x2 = wx_stack_top->x2;
1302 *y2 = wx_stack_top->y2;
1303 *x3 = wx_stack_top->x3;
1304 *y3 = wx_stack_top->y3;
1305 *x4 = wx_stack_top->x4;
1306 *y4 = wx_stack_top->y4;
1307 return (1);
1308 }
1309
1310 static bool wx_spline_add_point(double x, double y)
1311 {
1312 wxPoint *point = new wxPoint ;
1313 point->x = (int) x;
1314 point->y = (int) y;
1315 wx_spline_point_list.Append((wxObject*)point);
1316 return TRUE;
1317 }
1318
1319 static void wx_spline_draw_point_array(wxDC *dc)
1320 {
1321 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1322 wxNode *node = wx_spline_point_list.First();
1323 while (node)
1324 {
1325 wxPoint *point = (wxPoint *)node->Data();
1326 delete point;
1327 delete node;
1328 node = wx_spline_point_list.First();
1329 }
1330 }
1331
1332 void wxWindowDC::DoDrawSpline( wxList *points )
1333 {
1334 wxCHECK_RET( Ok(), _T("invalid window dc") );
1335
1336 wxPoint *p;
1337 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1338 double x1, y1, x2, y2;
1339
1340 wxNode *node = points->First();
1341 p = (wxPoint *)node->Data();
1342
1343 x1 = p->x;
1344 y1 = p->y;
1345
1346 node = node->Next();
1347 p = (wxPoint *)node->Data();
1348
1349 x2 = p->x;
1350 y2 = p->y;
1351 cx1 = (double)((x1 + x2) / 2);
1352 cy1 = (double)((y1 + y2) / 2);
1353 cx2 = (double)((cx1 + x2) / 2);
1354 cy2 = (double)((cy1 + y2) / 2);
1355
1356 wx_spline_add_point(x1, y1);
1357
1358 while ((node = node->Next()) != NULL)
1359 {
1360 p = (wxPoint *)node->Data();
1361 x1 = x2;
1362 y1 = y2;
1363 x2 = p->x;
1364 y2 = p->y;
1365 cx4 = (double)(x1 + x2) / 2;
1366 cy4 = (double)(y1 + y2) / 2;
1367 cx3 = (double)(x1 + cx4) / 2;
1368 cy3 = (double)(y1 + cy4) / 2;
1369
1370 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1371
1372 cx1 = cx4;
1373 cy1 = cy4;
1374 cx2 = (double)(cx1 + x2) / 2;
1375 cy2 = (double)(cy1 + y2) / 2;
1376 }
1377
1378 wx_spline_add_point( cx1, cy1 );
1379 wx_spline_add_point( x2, y2 );
1380
1381 wx_spline_draw_point_array( this );
1382 }
1383
1384 #endif // wxUSE_SPLINE
1385
1386 //-----------------------------------------------------------------------------
1387 // wxPaintDC
1388 //-----------------------------------------------------------------------------
1389
1390 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1391
1392 wxPaintDC::wxPaintDC()
1393 : wxWindowDC()
1394 {
1395 }
1396
1397 wxPaintDC::wxPaintDC( wxWindow *win )
1398 : wxWindowDC( win )
1399 {
1400 }
1401
1402 //-----------------------------------------------------------------------------
1403 // wxClientDC
1404 //-----------------------------------------------------------------------------
1405
1406 IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1407
1408 wxClientDC::wxClientDC()
1409 : wxWindowDC()
1410 {
1411 }
1412
1413 wxClientDC::wxClientDC( wxWindow *win )
1414 : wxWindowDC( win )
1415 {
1416 }
1417