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