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