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