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