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