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