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