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