synched Clear() and SetBackgroundColour()
[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( "wxWindowDC::FloodFill not implemented" );
144 }
145
146 bool wxWindowDC::GetPixel( long WXUNUSED(x1), long WXUNUSED(y1), wxColour *WXUNUSED(col) ) const
147 {
148 wxFAIL_MSG( "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(), "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(), "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(), "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(), "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(), "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(), "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(), "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(), "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(), "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(), "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(), "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(), "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(), "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, "invalid window dc" );
599
600 wxCHECK_MSG( source, FALSE, "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 we HAVE TO use the direct way for memory dcs
616 that have mask since the XCopyArea doesn't know
617 about masks and we SHOULD use the direct way if
618 all of the bitmap in the memory dc is copied in
619 which case XCopyArea wouldn't be able able to
620 boost performace by reducing the area to be scaled */
621
622 use_bitmap_method = ( (useMask && (memDC->m_selected.GetMask())) ||
623 ((xsrc == 0) && (ysrc == 0) &&
624 (width == memDC->m_selected.GetWidth()) &&
625 (height == memDC->m_selected.GetHeight()) )
626 );
627 }
628
629 CalcBoundingBox( xdest, ydest );
630 CalcBoundingBox( xdest + width, ydest + height );
631
632 int old_logical_func = m_logicalFunction;
633 SetLogicalFunction( logical_func );
634
635 if (use_bitmap_method)
636 {
637 /* scale/translate bitmap size */
638
639 long bm_width = memDC->m_selected.GetWidth();
640 long bm_height = memDC->m_selected.GetHeight();
641
642 long bm_ww = XLOG2DEVREL( bm_width );
643 long bm_hh = YLOG2DEVREL( bm_height );
644
645 /* scale bitmap if required */
646
647 wxBitmap use_bitmap;
648
649 if ((bm_width != bm_ww) || (bm_height != bm_hh))
650 {
651 wxImage image( memDC->m_selected );
652 image = image.Scale( bm_ww, bm_hh );
653
654 use_bitmap = image.ConvertToBitmap();
655 }
656 else
657 {
658 use_bitmap = memDC->m_selected;
659 }
660
661 /* scale/translate size and position */
662
663 long xx = XLOG2DEV(xdest);
664 long yy = YLOG2DEV(ydest);
665
666 long ww = XLOG2DEVREL(width);
667 long hh = YLOG2DEVREL(height);
668
669 /* apply mask if any */
670
671 GdkBitmap *mask = (GdkBitmap *) NULL;
672 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
673
674 if (useMask && mask)
675 {
676 gdk_gc_set_clip_mask( m_penGC, mask );
677 gdk_gc_set_clip_origin( m_penGC, xx, yy );
678 }
679
680 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
681
682 GdkPixmap *pm = use_bitmap.GetPixmap();
683 if (pm)
684 {
685 gdk_draw_pixmap( m_window, m_penGC, pm, 0, 0, xx, yy, ww, hh );
686 }
687 else
688 {
689 GdkBitmap *bm = use_bitmap.GetBitmap();
690 if (bm)
691 {
692 gdk_draw_bitmap( m_window, m_penGC, bm, 0, 0, xx, yy, ww, hh );
693 }
694 }
695
696 /* remove mask again if any */
697
698 if (useMask && mask)
699 {
700 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
701 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
702 }
703 }
704 else /* use_bitmap_method */
705 {
706 /* scale/translate size and position */
707
708 long xx = XLOG2DEV(xdest);
709 long yy = YLOG2DEV(ydest);
710
711 long ww = XLOG2DEVREL(width);
712 long hh = YLOG2DEVREL(height);
713
714 if ((width != ww) || (height != hh))
715 {
716 /* draw source window into a bitmap as we cannot scale
717 a window in contrast to a bitmap. this would actually
718 work with memory dcs as well, but we'd lose the mask
719 information and waste one step in this process since
720 a memory already has a bitmap. all this is slightly
721 inefficient as we could take an XImage directly from
722 an X window, but we'd then also have to care that
723 the window is not outside the screen (in which case
724 we'd get a BadMatch or what not).
725 Is a double XGetImage and combined XGetPixel and
726 XPutPixel really faster? I'm not sure. look at wxXt
727 for a different implementation of the same problem. */
728
729 wxBitmap bitmap( width, height );
730 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
731 srcDC->GetWindow(),
732 xsrc, ysrc, width, height );
733
734 /* scale image */
735
736 wxImage image( bitmap );
737 image = image.Scale( ww, hh );
738
739 /* convert to bitmap */
740
741 bitmap = image.ConvertToBitmap();
742
743 /* draw scaled bitmap */
744
745 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
746
747 }
748 else
749 {
750 /* no scaling and not a memory dc with a mask either */
751
752 gdk_window_copy_area( m_window, m_penGC, xx, yy,
753 srcDC->GetWindow(),
754 xsrc, ysrc, width, height );
755 }
756 }
757
758 SetLogicalFunction( old_logical_func );
759 return TRUE;
760 }
761
762 void wxWindowDC::DrawText( const wxString &text, long x, long y, bool WXUNUSED(use16) )
763 {
764 wxCHECK_RET( Ok(), "invalid window dc" );
765
766 GdkFont *font = m_font.GetInternalFont( m_scaleY );
767
768 x = XLOG2DEV(x);
769 y = YLOG2DEV(y);
770
771 /* CMB 21/5/98: draw text background if mode is wxSOLID */
772 if (m_backgroundMode == wxSOLID)
773 {
774 long width = gdk_string_width( font, text );
775 long height = font->ascent + font->descent;
776 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
777 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
778 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
779 }
780 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text );
781
782 /* CMB 17/7/98: simple underline: ignores scaling and underlying
783 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
784 properties (see wxXt implementation) */
785 if (m_font.GetUnderlined())
786 {
787 long width = gdk_string_width( font, text );
788 long ul_y = y + font->ascent;
789 if (font->descent > 0) ul_y++;
790 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
791 }
792
793 long w, h;
794 GetTextExtent (text, &w, &h);
795 CalcBoundingBox (x + w, y + h);
796 CalcBoundingBox (x, y);
797 }
798
799 bool wxWindowDC::CanGetTextExtent() const
800 {
801 return TRUE;
802 }
803
804 void wxWindowDC::GetTextExtent( const wxString &string, long *width, long *height,
805 long *descent, long *externalLeading,
806 wxFont *theFont, bool WXUNUSED(use16) )
807 {
808 wxCHECK_RET( Ok(), "invalid window dc" );
809
810 wxFont fontToUse = m_font;
811 if (theFont) fontToUse = *theFont;
812
813 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
814 if (width) (*width) = long(gdk_string_width( font, string ) / m_scaleX);
815 if (height) (*height) = long((font->ascent + font->descent) / m_scaleY);
816 if (descent) (*descent) = long(font->descent / m_scaleY);
817 if (externalLeading) (*externalLeading) = 0; // ??
818 }
819
820 long wxWindowDC::GetCharWidth()
821 {
822 wxCHECK_MSG( Ok(), 0, "invalid window dc" );
823
824 GdkFont *font = m_font.GetInternalFont( m_scaleY );
825 return long(gdk_string_width( font, "H" ) / m_scaleX);
826 }
827
828 long wxWindowDC::GetCharHeight()
829 {
830 wxCHECK_MSG( Ok(), 0, "invalid window dc" );
831
832 GdkFont *font = m_font.GetInternalFont( m_scaleY );
833 return long((font->ascent + font->descent) / m_scaleY);
834 }
835
836 void wxWindowDC::Clear()
837 {
838 wxCHECK_RET( Ok(), "invalid window dc" );
839
840 if (!m_isMemDC)
841 {
842 gdk_window_clear( m_window );
843 }
844 else
845 {
846 int width,height;
847 GetSize( &width, &height );
848 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
849 }
850 }
851
852 void wxWindowDC::SetFont( const wxFont &font )
853 {
854 wxCHECK_RET( Ok(), "invalid window dc" );
855
856 m_font = font;
857 }
858
859 void wxWindowDC::SetPen( const wxPen &pen )
860 {
861 wxCHECK_RET( Ok(), "invalid window dc" );
862
863 if (m_pen == pen) return;
864
865 m_pen = pen;
866
867 if (!m_pen.Ok()) return;
868
869 gint width = m_pen.GetWidth();
870 // CMB: if width is non-zero scale it with the dc
871 if (width <= 0)
872 {
873 width = 1;
874 }
875 else
876 {
877 // X doesn't allow different width in x and y and so we take
878 // the average
879 double w = 0.5 + (abs(XLOG2DEVREL(width)) + abs(YLOG2DEVREL(width))) / 2.0;
880 width = (int)w;
881 }
882
883 GdkLineStyle lineStyle = GDK_LINE_SOLID;
884 switch (m_pen.GetStyle())
885 {
886 case wxSOLID: { lineStyle = GDK_LINE_SOLID; break; }
887 case wxDOT: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
888 case wxLONG_DASH: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
889 case wxSHORT_DASH: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
890 case wxDOT_DASH: { lineStyle = GDK_LINE_DOUBLE_DASH; break; }
891 }
892
893 GdkCapStyle capStyle = GDK_CAP_ROUND;
894 switch (m_pen.GetCap())
895 {
896 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
897 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
898 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
899 }
900
901 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
902 switch (m_pen.GetJoin())
903 {
904 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
905 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
906 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
907 }
908
909 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
910
911 m_pen.GetColour().CalcPixel( m_cmap );
912 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
913 }
914
915 void wxWindowDC::SetBrush( const wxBrush &brush )
916 {
917 wxCHECK_RET( Ok(), "invalid window dc" );
918
919 if (m_brush == brush) return;
920
921 m_brush = brush;
922
923 if (!m_brush.Ok()) return;
924
925 m_brush.GetColour().CalcPixel( m_cmap );
926 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
927
928 GdkFill fillStyle = GDK_SOLID;
929 switch (m_brush.GetStyle())
930 {
931 case wxSOLID:
932 case wxTRANSPARENT:
933 break;
934 default:
935 fillStyle = GDK_STIPPLED;
936 }
937
938 gdk_gc_set_fill( m_brushGC, fillStyle );
939
940 if (m_brush.GetStyle() == wxSTIPPLE)
941 {
942 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetPixmap() );
943 }
944
945 if (IS_HATCH(m_brush.GetStyle()))
946 {
947 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
948 gdk_gc_set_stipple( m_brushGC, hatches[num] );
949 }
950 }
951
952 void wxWindowDC::SetBackground( const wxBrush &brush )
953 {
954 /* CMB 21/7/98: Added SetBackground. Sets background brush
955 * for Clear() and bg colour for shapes filled with cross-hatch brush */
956
957 wxCHECK_RET( Ok(), "invalid window dc" );
958
959 if (m_backgroundBrush == brush) return;
960
961 m_backgroundBrush = brush;
962
963 if (!m_backgroundBrush.Ok()) return;
964
965 if (m_owner)
966 {
967 m_owner->SetBackgroundColour( m_backgroundBrush.GetColour() );
968 }
969
970 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
971 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
972 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
973 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
974 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
975
976 GdkFill fillStyle = GDK_SOLID;
977 switch (m_backgroundBrush.GetStyle())
978 {
979 case wxSOLID:
980 case wxTRANSPARENT:
981 break;
982 default:
983 fillStyle = GDK_STIPPLED;
984 }
985
986 gdk_gc_set_fill( m_bgGC, fillStyle );
987
988 if (m_backgroundBrush.GetStyle() == wxSTIPPLE)
989 {
990 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
991 }
992
993 if (IS_HATCH(m_backgroundBrush.GetStyle()))
994 {
995 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
996 gdk_gc_set_stipple( m_bgGC, hatches[num] );
997 }
998 }
999
1000 void wxWindowDC::SetLogicalFunction( int function )
1001 {
1002 wxCHECK_RET( Ok(), "invalid window dc" );
1003
1004 if (m_logicalFunction == function) return;
1005
1006 GdkFunction mode = GDK_COPY;
1007 switch (function)
1008 {
1009 case wxXOR: mode = GDK_INVERT; break;
1010 case wxINVERT: mode = GDK_INVERT; break;
1011 default: break;
1012 }
1013
1014 m_logicalFunction = function;
1015 gdk_gc_set_function( m_penGC, mode );
1016 gdk_gc_set_function( m_brushGC, mode );
1017 gdk_gc_set_function( m_textGC, mode );
1018 }
1019
1020 void wxWindowDC::SetTextForeground( const wxColour &col )
1021 {
1022 wxCHECK_RET( Ok(), "invalid window dc" );
1023
1024 if (m_textForegroundColour == col) return;
1025
1026 m_textForegroundColour = col;
1027 if (!m_textForegroundColour.Ok()) return;
1028
1029 m_textForegroundColour.CalcPixel( m_cmap );
1030 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1031 }
1032
1033 void wxWindowDC::SetTextBackground( const wxColour &col )
1034 {
1035 wxCHECK_RET( Ok(), "invalid window dc" );
1036
1037 if (m_textBackgroundColour == col) return;
1038
1039 m_textBackgroundColour = col;
1040 if (!m_textBackgroundColour.Ok()) return;
1041
1042 m_textBackgroundColour.CalcPixel( m_cmap );
1043 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1044 }
1045
1046 void wxWindowDC::SetBackgroundMode( int mode )
1047 {
1048 wxCHECK_RET( Ok(), "invalid window dc" );
1049
1050 m_backgroundMode = mode;
1051
1052 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1053 // transparent/solid background mode
1054
1055 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1056 {
1057 gdk_gc_set_fill( m_brushGC,
1058 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1059 }
1060 }
1061
1062 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
1063 {
1064 wxFAIL_MSG( "wxWindowDC::SetPalette not implemented" );
1065 }
1066
1067 void wxWindowDC::SetClippingRegion( long x, long y, long width, long height )
1068 {
1069 wxCHECK_RET( Ok(), "invalid window dc" );
1070
1071 wxDC::SetClippingRegion( x, y, width, height );
1072
1073 GdkRectangle rect;
1074 rect.x = XLOG2DEV(x);
1075 rect.y = YLOG2DEV(y);
1076 rect.width = XLOG2DEVREL(width);
1077 rect.height = YLOG2DEVREL(height);
1078 gdk_gc_set_clip_rectangle( m_penGC, &rect );
1079 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
1080 gdk_gc_set_clip_rectangle( m_textGC, &rect );
1081 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
1082 }
1083
1084 void wxWindowDC::SetClippingRegion( const wxRegion &region )
1085 {
1086 wxCHECK_RET( Ok(), "invalid window dc" );
1087
1088 if (region.Empty())
1089 {
1090 DestroyClippingRegion();
1091 return;
1092 }
1093
1094 gdk_gc_set_clip_region( m_penGC, region.GetRegion() );
1095 gdk_gc_set_clip_region( m_brushGC, region.GetRegion() );
1096 gdk_gc_set_clip_region( m_textGC, region.GetRegion() );
1097 gdk_gc_set_clip_region( m_bgGC, region.GetRegion() );
1098 }
1099
1100 void wxWindowDC::DestroyClippingRegion()
1101 {
1102 wxCHECK_RET( Ok(), "invalid window dc" );
1103
1104 wxDC::DestroyClippingRegion();
1105
1106 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1107 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1108 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1109 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
1110 }
1111
1112 void wxWindowDC::SetUpDC()
1113 {
1114 Destroy();
1115 m_ok = TRUE;
1116 m_logicalFunction = wxCOPY;
1117 m_penGC = gdk_gc_new( m_window );
1118 m_brushGC = gdk_gc_new( m_window );
1119 m_textGC = gdk_gc_new( m_window );
1120 m_bgGC = gdk_gc_new( m_window );
1121
1122 wxColour tmp_col( m_textForegroundColour );
1123 m_textForegroundColour = wxNullColour;
1124 SetTextForeground( tmp_col );
1125 tmp_col = m_textBackgroundColour;
1126 m_textBackgroundColour = wxNullColour;
1127 SetTextBackground( tmp_col );
1128
1129 wxPen tmp_pen( m_pen );
1130 m_pen = wxNullPen;
1131 SetPen( tmp_pen );
1132
1133 wxFont tmp_font( m_font );
1134 m_font = wxNullFont;
1135 SetFont( tmp_font );
1136
1137 wxBrush tmp_brush( m_brush );
1138 m_brush = wxNullBrush;
1139 SetBrush( tmp_brush );
1140
1141 tmp_brush = m_backgroundBrush;
1142 m_backgroundBrush = wxNullBrush;
1143 SetBackground( tmp_brush );
1144
1145 if (!hatch_bitmap)
1146 {
1147 hatch_bitmap = hatches;
1148 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1149 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1150 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1151 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1152 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1153 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1154 }
1155 }
1156
1157 void wxWindowDC::Destroy()
1158 {
1159 if (m_penGC) gdk_gc_unref( m_penGC );
1160 m_penGC = (GdkGC*) NULL;
1161 if (m_brushGC) gdk_gc_unref( m_brushGC );
1162 m_brushGC = (GdkGC*) NULL;
1163 if (m_textGC) gdk_gc_unref( m_textGC );
1164 m_textGC = (GdkGC*) NULL;
1165 if (m_bgGC) gdk_gc_unref( m_bgGC );
1166 m_bgGC = (GdkGC*) NULL;
1167 }
1168
1169 GdkWindow *wxWindowDC::GetWindow()
1170 {
1171 return m_window;
1172 }
1173
1174 // ----------------------------------- spline code ----------------------------------------
1175
1176 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1177 double a3, double b3, double a4, double b4);
1178 void wx_clear_stack();
1179 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1180 double *y3, double *x4, double *y4);
1181 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1182 double x4, double y4);
1183 static bool wx_spline_add_point(double x, double y);
1184 static void wx_spline_draw_point_array(wxDC *dc);
1185
1186 wxList wx_spline_point_list;
1187
1188 #define half(z1, z2) ((z1+z2)/2.0)
1189 #define THRESHOLD 5
1190
1191 /* iterative version */
1192
1193 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1194 double b4)
1195 {
1196 register double xmid, ymid;
1197 double x1, y1, x2, y2, x3, y3, x4, y4;
1198
1199 wx_clear_stack();
1200 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1201
1202 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1203 xmid = (double)half(x2, x3);
1204 ymid = (double)half(y2, y3);
1205 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1206 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1207 wx_spline_add_point( x1, y1 );
1208 wx_spline_add_point( xmid, ymid );
1209 } else {
1210 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1211 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1212 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1213 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1214 }
1215 }
1216 }
1217
1218 /* utilities used by spline drawing routines */
1219
1220 typedef struct wx_spline_stack_struct {
1221 double x1, y1, x2, y2, x3, y3, x4, y4;
1222 } Stack;
1223
1224 #define SPLINE_STACK_DEPTH 20
1225 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1226 static Stack *wx_stack_top;
1227 static int wx_stack_count;
1228
1229 void wx_clear_stack()
1230 {
1231 wx_stack_top = wx_spline_stack;
1232 wx_stack_count = 0;
1233 }
1234
1235 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1236 {
1237 wx_stack_top->x1 = x1;
1238 wx_stack_top->y1 = y1;
1239 wx_stack_top->x2 = x2;
1240 wx_stack_top->y2 = y2;
1241 wx_stack_top->x3 = x3;
1242 wx_stack_top->y3 = y3;
1243 wx_stack_top->x4 = x4;
1244 wx_stack_top->y4 = y4;
1245 wx_stack_top++;
1246 wx_stack_count++;
1247 }
1248
1249 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1250 double *x3, double *y3, double *x4, double *y4)
1251 {
1252 if (wx_stack_count == 0)
1253 return (0);
1254 wx_stack_top--;
1255 wx_stack_count--;
1256 *x1 = wx_stack_top->x1;
1257 *y1 = wx_stack_top->y1;
1258 *x2 = wx_stack_top->x2;
1259 *y2 = wx_stack_top->y2;
1260 *x3 = wx_stack_top->x3;
1261 *y3 = wx_stack_top->y3;
1262 *x4 = wx_stack_top->x4;
1263 *y4 = wx_stack_top->y4;
1264 return (1);
1265 }
1266
1267 static bool wx_spline_add_point(double x, double y)
1268 {
1269 wxPoint *point = new wxPoint ;
1270 point->x = (int) x;
1271 point->y = (int) y;
1272 wx_spline_point_list.Append((wxObject*)point);
1273 return TRUE;
1274 }
1275
1276 static void wx_spline_draw_point_array(wxDC *dc)
1277 {
1278 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1279 wxNode *node = wx_spline_point_list.First();
1280 while (node)
1281 {
1282 wxPoint *point = (wxPoint *)node->Data();
1283 delete point;
1284 delete node;
1285 node = wx_spline_point_list.First();
1286 }
1287 }
1288
1289 void wxWindowDC::DrawSpline( wxList *points )
1290 {
1291 wxCHECK_RET( Ok(), "invalid window dc" );
1292
1293 wxPoint *p;
1294 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1295 double x1, y1, x2, y2;
1296
1297 wxNode *node = points->First();
1298 p = (wxPoint *)node->Data();
1299
1300 x1 = p->x;
1301 y1 = p->y;
1302
1303 node = node->Next();
1304 p = (wxPoint *)node->Data();
1305
1306 x2 = p->x;
1307 y2 = p->y;
1308 cx1 = (double)((x1 + x2) / 2);
1309 cy1 = (double)((y1 + y2) / 2);
1310 cx2 = (double)((cx1 + x2) / 2);
1311 cy2 = (double)((cy1 + y2) / 2);
1312
1313 wx_spline_add_point(x1, y1);
1314
1315 while ((node = node->Next()) != NULL)
1316 {
1317 p = (wxPoint *)node->Data();
1318 x1 = x2;
1319 y1 = y2;
1320 x2 = p->x;
1321 y2 = p->y;
1322 cx4 = (double)(x1 + x2) / 2;
1323 cy4 = (double)(y1 + y2) / 2;
1324 cx3 = (double)(x1 + cx4) / 2;
1325 cy3 = (double)(y1 + cy4) / 2;
1326
1327 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1328
1329 cx1 = cx4;
1330 cy1 = cy4;
1331 cx2 = (double)(cx1 + x2) / 2;
1332 cy2 = (double)(cy1 + y2) / 2;
1333 }
1334
1335 wx_spline_add_point( cx1, cy1 );
1336 wx_spline_add_point( x2, y2 );
1337
1338 wx_spline_draw_point_array( this );
1339 }
1340
1341
1342 //-----------------------------------------------------------------------------
1343 // wxPaintDC
1344 //-----------------------------------------------------------------------------
1345
1346 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1347
1348 wxPaintDC::wxPaintDC()
1349 : wxWindowDC()
1350 {
1351 }
1352
1353 wxPaintDC::wxPaintDC( wxWindow *win )
1354 : wxWindowDC( win )
1355 {
1356 }
1357
1358 //-----------------------------------------------------------------------------
1359 // wxClientDC
1360 //-----------------------------------------------------------------------------
1361
1362 IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1363
1364 wxClientDC::wxClientDC()
1365 : wxWindowDC()
1366 {
1367 }
1368
1369 wxClientDC::wxClientDC( wxWindow *win )
1370 : wxWindowDC( win )
1371 {
1372 }
1373