"Corrected" logical function in wxDC.
[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_XOR; break;
977 case wxINVERT: mode = GDK_INVERT; break;
978 #if (GTK_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 wxSRC_AND:
985 case wxAND: mode = GDK_AND; break;
986 case wxSRC_OR:
987 case wxOR: mode = GDK_OR; break;
988 case wxEQUIV: mode = GDK_EQUIV; break;
989 case wxNAND: mode = GDK_NAND; break;
990 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
991 case wxCOPY: mode = GDK_COPY; break;
992 case wxNO_OP: mode = GDK_NOOP; break;
993 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
994 #endif
995 default:
996 {
997 wxFAIL_MSG( "unsupported logical function" );
998 break;
999 }
1000 }
1001
1002 m_logicalFunction = function;
1003 gdk_gc_set_function( m_penGC, mode );
1004 gdk_gc_set_function( m_brushGC, mode );
1005 gdk_gc_set_function( m_textGC, mode );
1006 }
1007
1008 void wxWindowDC::SetTextForeground( const wxColour &col )
1009 {
1010 wxCHECK_RET( Ok(), _T("invalid window dc") );
1011
1012 if (m_textForegroundColour == col) return;
1013
1014 m_textForegroundColour = col;
1015 if (!m_textForegroundColour.Ok()) return;
1016
1017 m_textForegroundColour.CalcPixel( m_cmap );
1018 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1019 }
1020
1021 void wxWindowDC::SetTextBackground( const wxColour &col )
1022 {
1023 wxCHECK_RET( Ok(), _T("invalid window dc") );
1024
1025 if (m_textBackgroundColour == col) return;
1026
1027 m_textBackgroundColour = col;
1028 if (!m_textBackgroundColour.Ok()) return;
1029
1030 m_textBackgroundColour.CalcPixel( m_cmap );
1031 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1032 }
1033
1034 void wxWindowDC::SetBackgroundMode( int mode )
1035 {
1036 wxCHECK_RET( Ok(), _T("invalid window dc") );
1037
1038 m_backgroundMode = mode;
1039
1040 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1041 // transparent/solid background mode
1042
1043 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1044 {
1045 gdk_gc_set_fill( m_brushGC,
1046 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1047 }
1048 }
1049
1050 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
1051 {
1052 wxFAIL_MSG( _T("wxWindowDC::SetPalette not implemented") );
1053 }
1054
1055 void wxWindowDC::DoSetClippingRegion( long x, long y, long width, long height )
1056 {
1057 wxCHECK_RET( Ok(), _T("invalid window dc") );
1058
1059 wxDC::DoSetClippingRegion( x, y, width, height );
1060
1061 GdkRectangle rect;
1062 rect.x = XLOG2DEV(x);
1063 rect.y = YLOG2DEV(y);
1064 rect.width = XLOG2DEVREL(width);
1065 rect.height = YLOG2DEVREL(height);
1066 gdk_gc_set_clip_rectangle( m_penGC, &rect );
1067 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
1068 gdk_gc_set_clip_rectangle( m_textGC, &rect );
1069 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
1070 }
1071
1072 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
1073 {
1074 wxCHECK_RET( Ok(), _T("invalid window dc") );
1075
1076 if (region.Empty())
1077 {
1078 DestroyClippingRegion();
1079 return;
1080 }
1081
1082 gdk_gc_set_clip_region( m_penGC, region.GetRegion() );
1083 gdk_gc_set_clip_region( m_brushGC, region.GetRegion() );
1084 gdk_gc_set_clip_region( m_textGC, region.GetRegion() );
1085 gdk_gc_set_clip_region( m_bgGC, region.GetRegion() );
1086 }
1087
1088 void wxWindowDC::DestroyClippingRegion()
1089 {
1090 wxCHECK_RET( Ok(), _T("invalid window dc") );
1091
1092 wxDC::DestroyClippingRegion();
1093
1094 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1095 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1096 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1097 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
1098 }
1099
1100 void wxWindowDC::SetUpDC()
1101 {
1102 Destroy();
1103 m_ok = TRUE;
1104 m_logicalFunction = wxCOPY;
1105 m_penGC = gdk_gc_new( m_window );
1106 m_brushGC = gdk_gc_new( m_window );
1107 m_textGC = gdk_gc_new( m_window );
1108 m_bgGC = gdk_gc_new( m_window );
1109
1110 wxColour tmp_col( m_textForegroundColour );
1111 m_textForegroundColour = wxNullColour;
1112 SetTextForeground( tmp_col );
1113 tmp_col = m_textBackgroundColour;
1114 m_textBackgroundColour = wxNullColour;
1115 SetTextBackground( tmp_col );
1116
1117 wxPen tmp_pen( m_pen );
1118 m_pen = wxNullPen;
1119 SetPen( tmp_pen );
1120
1121 wxFont tmp_font( m_font );
1122 m_font = wxNullFont;
1123 SetFont( tmp_font );
1124
1125 wxBrush tmp_brush( m_brush );
1126 m_brush = wxNullBrush;
1127 SetBrush( tmp_brush );
1128
1129 tmp_brush = m_backgroundBrush;
1130 m_backgroundBrush = wxNullBrush;
1131 SetBackground( tmp_brush );
1132
1133 if (!hatch_bitmap)
1134 {
1135 hatch_bitmap = hatches;
1136 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1137 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1138 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1139 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1140 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1141 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1142 }
1143 }
1144
1145 void wxWindowDC::Destroy()
1146 {
1147 if (m_penGC) gdk_gc_unref( m_penGC );
1148 m_penGC = (GdkGC*) NULL;
1149 if (m_brushGC) gdk_gc_unref( m_brushGC );
1150 m_brushGC = (GdkGC*) NULL;
1151 if (m_textGC) gdk_gc_unref( m_textGC );
1152 m_textGC = (GdkGC*) NULL;
1153 if (m_bgGC) gdk_gc_unref( m_bgGC );
1154 m_bgGC = (GdkGC*) NULL;
1155 }
1156
1157 // Resolution in pixels per logical inch
1158 wxSize wxWindowDC::GetPPI() const
1159 {
1160 return wxSize(100, 100);
1161 }
1162
1163 int wxWindowDC::GetDepth() const
1164 {
1165 wxFAIL_MSG(_T("not implemented"));
1166
1167 return -1;
1168 }
1169
1170 #if wxUSE_SPLINES
1171 // ----------------------------------- spline code ----------------------------------------
1172
1173 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1174 double a3, double b3, double a4, double b4);
1175 void wx_clear_stack();
1176 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1177 double *y3, double *x4, double *y4);
1178 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1179 double x4, double y4);
1180 static bool wx_spline_add_point(double x, double y);
1181 static void wx_spline_draw_point_array(wxDC *dc);
1182
1183 wxList wx_spline_point_list;
1184
1185 #define half(z1, z2) ((z1+z2)/2.0)
1186 #define THRESHOLD 5
1187
1188 /* iterative version */
1189
1190 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1191 double b4)
1192 {
1193 register double xmid, ymid;
1194 double x1, y1, x2, y2, x3, y3, x4, y4;
1195
1196 wx_clear_stack();
1197 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1198
1199 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1200 xmid = (double)half(x2, x3);
1201 ymid = (double)half(y2, y3);
1202 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1203 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1204 wx_spline_add_point( x1, y1 );
1205 wx_spline_add_point( xmid, ymid );
1206 } else {
1207 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1208 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1209 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1210 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1211 }
1212 }
1213 }
1214
1215 /* utilities used by spline drawing routines */
1216
1217 typedef struct wx_spline_stack_struct {
1218 double x1, y1, x2, y2, x3, y3, x4, y4;
1219 } Stack;
1220
1221 #define SPLINE_STACK_DEPTH 20
1222 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1223 static Stack *wx_stack_top;
1224 static int wx_stack_count;
1225
1226 void wx_clear_stack()
1227 {
1228 wx_stack_top = wx_spline_stack;
1229 wx_stack_count = 0;
1230 }
1231
1232 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1233 {
1234 wx_stack_top->x1 = x1;
1235 wx_stack_top->y1 = y1;
1236 wx_stack_top->x2 = x2;
1237 wx_stack_top->y2 = y2;
1238 wx_stack_top->x3 = x3;
1239 wx_stack_top->y3 = y3;
1240 wx_stack_top->x4 = x4;
1241 wx_stack_top->y4 = y4;
1242 wx_stack_top++;
1243 wx_stack_count++;
1244 }
1245
1246 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1247 double *x3, double *y3, double *x4, double *y4)
1248 {
1249 if (wx_stack_count == 0)
1250 return (0);
1251 wx_stack_top--;
1252 wx_stack_count--;
1253 *x1 = wx_stack_top->x1;
1254 *y1 = wx_stack_top->y1;
1255 *x2 = wx_stack_top->x2;
1256 *y2 = wx_stack_top->y2;
1257 *x3 = wx_stack_top->x3;
1258 *y3 = wx_stack_top->y3;
1259 *x4 = wx_stack_top->x4;
1260 *y4 = wx_stack_top->y4;
1261 return (1);
1262 }
1263
1264 static bool wx_spline_add_point(double x, double y)
1265 {
1266 wxPoint *point = new wxPoint ;
1267 point->x = (int) x;
1268 point->y = (int) y;
1269 wx_spline_point_list.Append((wxObject*)point);
1270 return TRUE;
1271 }
1272
1273 static void wx_spline_draw_point_array(wxDC *dc)
1274 {
1275 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1276 wxNode *node = wx_spline_point_list.First();
1277 while (node)
1278 {
1279 wxPoint *point = (wxPoint *)node->Data();
1280 delete point;
1281 delete node;
1282 node = wx_spline_point_list.First();
1283 }
1284 }
1285
1286 void wxWindowDC::DoDrawSpline( wxList *points )
1287 {
1288 wxCHECK_RET( Ok(), _T("invalid window dc") );
1289
1290 wxPoint *p;
1291 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1292 double x1, y1, x2, y2;
1293
1294 wxNode *node = points->First();
1295 p = (wxPoint *)node->Data();
1296
1297 x1 = p->x;
1298 y1 = p->y;
1299
1300 node = node->Next();
1301 p = (wxPoint *)node->Data();
1302
1303 x2 = p->x;
1304 y2 = p->y;
1305 cx1 = (double)((x1 + x2) / 2);
1306 cy1 = (double)((y1 + y2) / 2);
1307 cx2 = (double)((cx1 + x2) / 2);
1308 cy2 = (double)((cy1 + y2) / 2);
1309
1310 wx_spline_add_point(x1, y1);
1311
1312 while ((node = node->Next()) != NULL)
1313 {
1314 p = (wxPoint *)node->Data();
1315 x1 = x2;
1316 y1 = y2;
1317 x2 = p->x;
1318 y2 = p->y;
1319 cx4 = (double)(x1 + x2) / 2;
1320 cy4 = (double)(y1 + y2) / 2;
1321 cx3 = (double)(x1 + cx4) / 2;
1322 cy3 = (double)(y1 + cy4) / 2;
1323
1324 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1325
1326 cx1 = cx4;
1327 cy1 = cy4;
1328 cx2 = (double)(cx1 + x2) / 2;
1329 cy2 = (double)(cy1 + y2) / 2;
1330 }
1331
1332 wx_spline_add_point( cx1, cy1 );
1333 wx_spline_add_point( x2, y2 );
1334
1335 wx_spline_draw_point_array( this );
1336 }
1337
1338 #endif // wxUSE_SPLINE
1339
1340 //-----------------------------------------------------------------------------
1341 // wxPaintDC
1342 //-----------------------------------------------------------------------------
1343
1344 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1345
1346 wxPaintDC::wxPaintDC()
1347 : wxWindowDC()
1348 {
1349 }
1350
1351 wxPaintDC::wxPaintDC( wxWindow *win )
1352 : wxWindowDC( win )
1353 {
1354 }
1355
1356 //-----------------------------------------------------------------------------
1357 // wxClientDC
1358 //-----------------------------------------------------------------------------
1359
1360 IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1361
1362 wxClientDC::wxClientDC()
1363 : wxWindowDC()
1364 {
1365 }
1366
1367 wxClientDC::wxClientDC( wxWindow *win )
1368 : wxWindowDC( win )
1369 {
1370 }
1371