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