]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/dcclient.cpp
Made tearoff menus work for gtk :-)
[wxWidgets.git] / src / gtk1 / 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, _T("DC needs a window") );
115
116 GtkWidget *widget = window->m_wxwindow;
117
118 wxASSERT_MSG( widget, _T("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 /* scale/translate size and position */
491
492 int xx = XLOG2DEV(x);
493 int yy = YLOG2DEV(y);
494
495 int w = bitmap.GetWidth();
496 int h = bitmap.GetHeight();
497
498 CalcBoundingBox( x, y );
499 CalcBoundingBox( x + w, y + h );
500
501 if (!m_window) return;
502
503 int ww = XLOG2DEVREL(w);
504 int hh = YLOG2DEVREL(h);
505
506 /* scale bitmap if required */
507
508 wxBitmap use_bitmap;
509
510 if ((w != ww) || (h != hh))
511 {
512 wxImage image( bitmap );
513 image = image.Scale( ww, hh );
514
515 use_bitmap = image.ConvertToBitmap();
516 }
517 else
518 {
519 use_bitmap = bitmap;
520 }
521
522 /* apply mask if any */
523
524 GdkBitmap *mask = (GdkBitmap *) NULL;
525 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
526
527 if (useMask && mask)
528 {
529 gdk_gc_set_clip_mask( m_penGC, mask );
530 gdk_gc_set_clip_origin( m_penGC, xx, yy );
531 }
532
533 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
534
535 GdkPixmap *pm = use_bitmap.GetPixmap();
536 if (pm)
537 {
538 gdk_draw_pixmap( m_window, m_penGC, pm, 0, 0, xx, yy, -1, -1 );
539 }
540 else
541 {
542 GdkBitmap *bm = use_bitmap.GetBitmap();
543 if (bm)
544 {
545 gdk_draw_bitmap( m_window, m_penGC, bm, 0, 0, xx, yy, -1, -1 );
546 }
547 }
548
549 /* remove mask again if any */
550
551 if (useMask && mask)
552 {
553 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
554 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
555 }
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( _T("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 /*
1176 tmp_brush = m_backgroundBrush;
1177 m_backgroundBrush = wxNullBrush;
1178 SetBackground( tmp_brush );
1179 */
1180 tmp_brush = m_backgroundBrush;
1181 m_backgroundBrush = wxNullBrush;
1182 SetBackground( *wxWHITE_BRUSH );
1183 m_backgroundBrush = tmp_brush;
1184
1185 if (!hatch_bitmap)
1186 {
1187 hatch_bitmap = hatches;
1188 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1189 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1190 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1191 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1192 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1193 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1194 }
1195 }
1196
1197 void wxWindowDC::Destroy()
1198 {
1199 if (m_penGC) gdk_gc_unref( m_penGC );
1200 m_penGC = (GdkGC*) NULL;
1201 if (m_brushGC) gdk_gc_unref( m_brushGC );
1202 m_brushGC = (GdkGC*) NULL;
1203 if (m_textGC) gdk_gc_unref( m_textGC );
1204 m_textGC = (GdkGC*) NULL;
1205 if (m_bgGC) gdk_gc_unref( m_bgGC );
1206 m_bgGC = (GdkGC*) NULL;
1207 }
1208
1209 void wxWindowDC::ComputeScaleAndOrigin()
1210 {
1211 /* CMB: copy scale to see if it changes */
1212 double origScaleX = m_scaleX;
1213 double origScaleY = m_scaleY;
1214
1215 wxDC::ComputeScaleAndOrigin();
1216
1217 /* CMB: if scale has changed call SetPen to recalulate the line width */
1218 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
1219 (m_pen.Ok()))
1220 {
1221 /* this is a bit artificial, but we need to force wxDC to think
1222 the pen has changed */
1223 wxPen pen = m_pen;
1224 m_pen = wxNullPen;
1225 SetPen( pen );
1226 }
1227 }
1228
1229 // Resolution in pixels per logical inch
1230 wxSize wxWindowDC::GetPPI() const
1231 {
1232 return wxSize(100, 100);
1233 }
1234
1235 int wxWindowDC::GetDepth() const
1236 {
1237 wxFAIL_MSG(_T("not implemented"));
1238
1239 return -1;
1240 }
1241
1242 #if wxUSE_SPLINES
1243 // ----------------------------------- spline code ----------------------------------------
1244
1245 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1246 double a3, double b3, double a4, double b4);
1247 void wx_clear_stack();
1248 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1249 double *y3, double *x4, double *y4);
1250 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1251 double x4, double y4);
1252 static bool wx_spline_add_point(double x, double y);
1253 static void wx_spline_draw_point_array(wxDC *dc);
1254
1255 wxList wx_spline_point_list;
1256
1257 #define half(z1, z2) ((z1+z2)/2.0)
1258 #define THRESHOLD 5
1259
1260 /* iterative version */
1261
1262 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1263 double b4)
1264 {
1265 register double xmid, ymid;
1266 double x1, y1, x2, y2, x3, y3, x4, y4;
1267
1268 wx_clear_stack();
1269 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1270
1271 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1272 xmid = (double)half(x2, x3);
1273 ymid = (double)half(y2, y3);
1274 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1275 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1276 wx_spline_add_point( x1, y1 );
1277 wx_spline_add_point( xmid, ymid );
1278 } else {
1279 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1280 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1281 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1282 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1283 }
1284 }
1285 }
1286
1287 /* utilities used by spline drawing routines */
1288
1289 typedef struct wx_spline_stack_struct {
1290 double x1, y1, x2, y2, x3, y3, x4, y4;
1291 } Stack;
1292
1293 #define SPLINE_STACK_DEPTH 20
1294 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1295 static Stack *wx_stack_top;
1296 static int wx_stack_count;
1297
1298 void wx_clear_stack()
1299 {
1300 wx_stack_top = wx_spline_stack;
1301 wx_stack_count = 0;
1302 }
1303
1304 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1305 {
1306 wx_stack_top->x1 = x1;
1307 wx_stack_top->y1 = y1;
1308 wx_stack_top->x2 = x2;
1309 wx_stack_top->y2 = y2;
1310 wx_stack_top->x3 = x3;
1311 wx_stack_top->y3 = y3;
1312 wx_stack_top->x4 = x4;
1313 wx_stack_top->y4 = y4;
1314 wx_stack_top++;
1315 wx_stack_count++;
1316 }
1317
1318 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1319 double *x3, double *y3, double *x4, double *y4)
1320 {
1321 if (wx_stack_count == 0)
1322 return (0);
1323 wx_stack_top--;
1324 wx_stack_count--;
1325 *x1 = wx_stack_top->x1;
1326 *y1 = wx_stack_top->y1;
1327 *x2 = wx_stack_top->x2;
1328 *y2 = wx_stack_top->y2;
1329 *x3 = wx_stack_top->x3;
1330 *y3 = wx_stack_top->y3;
1331 *x4 = wx_stack_top->x4;
1332 *y4 = wx_stack_top->y4;
1333 return (1);
1334 }
1335
1336 static bool wx_spline_add_point(double x, double y)
1337 {
1338 wxPoint *point = new wxPoint ;
1339 point->x = (int) x;
1340 point->y = (int) y;
1341 wx_spline_point_list.Append((wxObject*)point);
1342 return TRUE;
1343 }
1344
1345 static void wx_spline_draw_point_array(wxDC *dc)
1346 {
1347 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1348 wxNode *node = wx_spline_point_list.First();
1349 while (node)
1350 {
1351 wxPoint *point = (wxPoint *)node->Data();
1352 delete point;
1353 delete node;
1354 node = wx_spline_point_list.First();
1355 }
1356 }
1357
1358 void wxWindowDC::DoDrawSpline( wxList *points )
1359 {
1360 wxCHECK_RET( Ok(), _T("invalid window dc") );
1361
1362 wxPoint *p;
1363 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1364 double x1, y1, x2, y2;
1365
1366 wxNode *node = points->First();
1367 p = (wxPoint *)node->Data();
1368
1369 x1 = p->x;
1370 y1 = p->y;
1371
1372 node = node->Next();
1373 p = (wxPoint *)node->Data();
1374
1375 x2 = p->x;
1376 y2 = p->y;
1377 cx1 = (double)((x1 + x2) / 2);
1378 cy1 = (double)((y1 + y2) / 2);
1379 cx2 = (double)((cx1 + x2) / 2);
1380 cy2 = (double)((cy1 + y2) / 2);
1381
1382 wx_spline_add_point(x1, y1);
1383
1384 while ((node = node->Next()) != NULL)
1385 {
1386 p = (wxPoint *)node->Data();
1387 x1 = x2;
1388 y1 = y2;
1389 x2 = p->x;
1390 y2 = p->y;
1391 cx4 = (double)(x1 + x2) / 2;
1392 cy4 = (double)(y1 + y2) / 2;
1393 cx3 = (double)(x1 + cx4) / 2;
1394 cy3 = (double)(y1 + cy4) / 2;
1395
1396 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1397
1398 cx1 = cx4;
1399 cy1 = cy4;
1400 cx2 = (double)(cx1 + x2) / 2;
1401 cy2 = (double)(cy1 + y2) / 2;
1402 }
1403
1404 wx_spline_add_point( cx1, cy1 );
1405 wx_spline_add_point( x2, y2 );
1406
1407 wx_spline_draw_point_array( this );
1408 }
1409
1410 #endif // wxUSE_SPLINE
1411
1412 //-----------------------------------------------------------------------------
1413 // wxPaintDC
1414 //-----------------------------------------------------------------------------
1415
1416 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1417
1418 wxPaintDC::wxPaintDC()
1419 : wxWindowDC()
1420 {
1421 }
1422
1423 wxPaintDC::wxPaintDC( wxWindow *win )
1424 : wxWindowDC( win )
1425 {
1426 }
1427
1428 //-----------------------------------------------------------------------------
1429 // wxClientDC
1430 //-----------------------------------------------------------------------------
1431
1432 IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1433
1434 wxClientDC::wxClientDC()
1435 : wxWindowDC()
1436 {
1437 }
1438
1439 wxClientDC::wxClientDC( wxWindow *win )
1440 : wxWindowDC( win )
1441 {
1442 }
1443