Include changes again. Something is wrong with CVS...
[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 "wx/gtk/win_gtk.h"
18
19 #include <math.h> // for floating-point functions
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 GtkPizza *pizza = GTK_PIZZA( widget );
123 m_window = pizza->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( wxCoord WXUNUSED(x), wxCoord 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( wxCoord WXUNUSED(x1), wxCoord WXUNUSED(y1), wxColour *WXUNUSED(col) ) const
163 {
164 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
165 return FALSE;
166 }
167
168 void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord 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( wxCoord x, wxCoord 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 wxCoord xx = XLOG2DEV(x);
192 wxCoord 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( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
202 wxCoord xc, wxCoord yc )
203 {
204 wxCHECK_RET( Ok(), wxT("invalid window dc") );
205
206 wxCoord xx1 = XLOG2DEV(x1);
207 wxCoord yy1 = YLOG2DEV(y1);
208 wxCoord xx2 = XLOG2DEV(x2);
209 wxCoord yy2 = YLOG2DEV(y2);
210 wxCoord xxc = XLOG2DEV(xc);
211 wxCoord yyc = YLOG2DEV(yc);
212 double dx = xx1 - xxc;
213 double dy = yy1 - yyc;
214 double radius = sqrt((double)(dx*dx+dy*dy));
215 wxCoord r = (wxCoord)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 wxCoord alpha1 = wxCoord(radius1 * 64.0);
238 wxCoord alpha2 = wxCoord((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( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
256 {
257 wxCHECK_RET( Ok(), wxT("invalid window dc") );
258
259 wxCoord xx = XLOG2DEV(x);
260 wxCoord yy = YLOG2DEV(y);
261 wxCoord ww = m_signX * XLOG2DEVREL(width);
262 wxCoord 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 wxCoord start = wxCoord(sa * 64.0);
271 wxCoord end = wxCoord(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( wxCoord x, wxCoord 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[], wxCoord xoffset, wxCoord 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 wxCoord x1 = XLOG2DEV(points[i].x + xoffset);
306 wxCoord x2 = XLOG2DEV(points[i+1].x + xoffset);
307 wxCoord y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
308 wxCoord 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[], wxCoord xoffset, wxCoord 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( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
354 {
355 wxCHECK_RET( Ok(), wxT("invalid window dc") );
356
357 wxCoord xx = XLOG2DEV(x);
358 wxCoord yy = YLOG2DEV(y);
359 wxCoord ww = m_signX * XLOG2DEVREL(width);
360 wxCoord 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( wxCoord x, wxCoord y, wxCoord width, wxCoord 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 wxCoord xx = XLOG2DEV(x);
389 wxCoord yy = YLOG2DEV(y);
390 wxCoord ww = m_signX * XLOG2DEVREL(width);
391 wxCoord hh = m_signY * YLOG2DEVREL(height);
392 wxCoord rr = XLOG2DEVREL((wxCoord)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 wxCoord 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( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
455 {
456 wxCHECK_RET( Ok(), wxT("invalid window dc") );
457
458 wxCoord xx = XLOG2DEV(x);
459 wxCoord yy = YLOG2DEV(y);
460 wxCoord ww = m_signX * XLOG2DEVREL(width);
461 wxCoord 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, wxCoord x, wxCoord 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 wxCoord x, wxCoord 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( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
563 wxDC *source, wxCoord xsrc, wxCoord 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 wxCoord bm_width = memDC->m_selected.GetWidth();
633 wxCoord bm_height = memDC->m_selected.GetHeight();
634
635 wxCoord bm_ww = XLOG2DEVREL( bm_width );
636 wxCoord 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 wxCoord xx = XLOG2DEV(xdest);
657 wxCoord yy = YLOG2DEV(ydest);
658
659 wxCoord ww = XLOG2DEVREL(width);
660 wxCoord 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 wxCoord xx = XLOG2DEV(xdest);
704 wxCoord yy = YLOG2DEV(ydest);
705
706 wxCoord ww = XLOG2DEVREL(width);
707 wxCoord 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, wxCoord x, wxCoord 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 wxCoord width = gdk_string_width( font, text.mbc_str() );
774 wxCoord 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 wxCoord width = gdk_string_width( font, text.mbc_str() );
787 wxCoord 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 wxCoord w, h;
793 GetTextExtent (text, &w, &h);
794 CalcBoundingBox (x + w, y + h);
795 CalcBoundingBox (x, y);
796 }
797
798 void wxWindowDC::DoGetTextExtent(const wxString &string,
799 wxCoord *width, wxCoord *height,
800 wxCoord *descent, wxCoord *externalLeading,
801 wxFont *theFont) const
802 {
803 wxFont fontToUse = m_font;
804 if (theFont) fontToUse = *theFont;
805
806 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
807 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
808 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
809 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
810 if (externalLeading) (*externalLeading) = 0; // ??
811 }
812
813 wxCoord wxWindowDC::GetCharWidth() const
814 {
815 GdkFont *font = m_font.GetInternalFont( m_scaleY );
816 wxCHECK_MSG( font, -1, _T("invalid font") );
817
818 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
819 }
820
821 wxCoord wxWindowDC::GetCharHeight() const
822 {
823 GdkFont *font = m_font.GetInternalFont( m_scaleY );
824 wxCHECK_MSG( font, -1, _T("invalid font") );
825
826 return wxCoord((font->ascent + font->descent) / m_scaleY);
827 }
828
829 void wxWindowDC::Clear()
830 {
831 wxCHECK_RET( Ok(), wxT("invalid window dc") );
832
833 if (!m_window) return;
834
835 /* - we either are a memory dc or have a window as the
836 owner. anything else shouldn't happen.
837 - we don't use gdk_window_clear() as we don't set
838 the window's background colour anymore. it is too
839 much pain to keep the DC's and the window's back-
840 ground colour in synch. */
841
842 if (m_owner)
843 {
844 int width,height;
845 m_owner->GetSize( &width, &height );
846 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
847 return;
848 }
849
850 if (m_isMemDC)
851 {
852 int width,height;
853 GetSize( &width, &height );
854 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
855 return;
856 }
857 }
858
859 void wxWindowDC::SetFont( const wxFont &font )
860 {
861 m_font = font;
862 }
863
864 void wxWindowDC::SetPen( const wxPen &pen )
865 {
866 wxCHECK_RET( Ok(), wxT("invalid window dc") );
867
868 if (m_pen == pen) return;
869
870 m_pen = pen;
871
872 if (!m_pen.Ok()) return;
873
874 if (!m_window) return;
875
876 gint width = m_pen.GetWidth();
877 if (width <= 0)
878 {
879 // CMB: if width is non-zero scale it with the dc
880 width = 1;
881 }
882 else
883 {
884 // X doesn't allow different width in x and y and so we take
885 // the average
886 double w = 0.5 +
887 ( fabs((double) XLOG2DEVREL(width)) +
888 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
889 width = (int)w;
890 }
891
892 static const char dotted[] = {1, 1};
893 static const char short_dashed[] = {2, 2};
894 static const char wxCoord_dashed[] = {2, 4};
895 static const char dotted_dashed[] = {3, 3, 1, 3};
896
897 // We express dash pattern in pen width unit, so we are
898 // independent of zoom factor and so on...
899 int req_nb_dash;
900 const char *req_dash;
901
902 GdkLineStyle lineStyle = GDK_LINE_SOLID;
903 switch (m_pen.GetStyle())
904 {
905 case wxUSER_DASH:
906 {
907 lineStyle = GDK_LINE_ON_OFF_DASH;
908 req_nb_dash = m_pen.GetDashCount();
909 req_dash = m_pen.GetDash();
910 break;
911 }
912 case wxDOT:
913 {
914 lineStyle = GDK_LINE_ON_OFF_DASH;
915 req_nb_dash = 2;
916 req_dash = dotted;
917 break;
918 }
919 case wxLONG_DASH:
920 {
921 lineStyle = GDK_LINE_ON_OFF_DASH;
922 req_nb_dash = 2;
923 req_dash = wxCoord_dashed;
924 break;
925 }
926 case wxSHORT_DASH:
927 {
928 lineStyle = GDK_LINE_ON_OFF_DASH;
929 req_nb_dash = 2;
930 req_dash = short_dashed;
931 break;
932 }
933 case wxDOT_DASH:
934 {
935 // lineStyle = GDK_LINE_DOUBLE_DASH;
936 lineStyle = GDK_LINE_ON_OFF_DASH;
937 req_nb_dash = 4;
938 req_dash = dotted_dashed;
939 break;
940 }
941
942 case wxTRANSPARENT:
943 case wxSTIPPLE:
944 case wxSOLID:
945 default:
946 {
947 lineStyle = GDK_LINE_SOLID;
948 req_dash = (wxDash*)NULL;
949 req_nb_dash = 0;
950 break;
951 }
952 }
953
954 #if (GTK_MINOR_VERSION > 0)
955 if (req_dash && req_nb_dash)
956 {
957 char *real_req_dash = new char[req_nb_dash];
958 if (real_req_dash)
959 {
960 for (int i = 0; i < req_nb_dash; i++)
961 real_req_dash[i] = req_dash[i] * width;
962 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
963 delete[] real_req_dash;
964 }
965 else
966 {
967 // No Memory. We use non-scaled dash pattern...
968 gdk_gc_set_dashes( m_penGC, 0, (char*)req_dash, req_nb_dash );
969 }
970 }
971 #endif
972
973 GdkCapStyle capStyle = GDK_CAP_ROUND;
974 switch (m_pen.GetCap())
975 {
976 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
977 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
978 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
979 }
980
981 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
982 switch (m_pen.GetJoin())
983 {
984 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
985 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
986 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
987 }
988
989 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
990
991 m_pen.GetColour().CalcPixel( m_cmap );
992 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
993 }
994
995 void wxWindowDC::SetBrush( const wxBrush &brush )
996 {
997 wxCHECK_RET( Ok(), wxT("invalid window dc") );
998
999 if (m_brush == brush) return;
1000
1001 m_brush = brush;
1002
1003 if (!m_brush.Ok()) return;
1004
1005 if (!m_window) return;
1006
1007 m_brush.GetColour().CalcPixel( m_cmap );
1008 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
1009
1010 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
1011
1012 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
1013 {
1014 if (m_brush.GetStipple()->GetPixmap())
1015 {
1016 gdk_gc_set_fill( m_brushGC, GDK_TILED );
1017 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
1018 }
1019 else
1020 {
1021 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1022 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
1023 }
1024 }
1025
1026 if (IS_HATCH(m_brush.GetStyle()))
1027 {
1028 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1029 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1030 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1031 }
1032 }
1033
1034 void wxWindowDC::SetBackground( const wxBrush &brush )
1035 {
1036 /* CMB 21/7/98: Added SetBackground. Sets background brush
1037 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1038
1039 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1040
1041 if (m_backgroundBrush == brush) return;
1042
1043 m_backgroundBrush = brush;
1044
1045 if (!m_backgroundBrush.Ok()) return;
1046
1047 if (!m_window) return;
1048
1049 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1050 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
1051 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
1052 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1053 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1054
1055 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
1056
1057 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
1058 {
1059 if (m_backgroundBrush.GetStipple()->GetPixmap())
1060 {
1061 gdk_gc_set_fill( m_bgGC, GDK_TILED );
1062 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
1063 }
1064 else
1065 {
1066 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1067 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
1068 }
1069 }
1070
1071 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1072 {
1073 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1074 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1075 gdk_gc_set_stipple( m_bgGC, hatches[num] );
1076 }
1077 }
1078
1079 void wxWindowDC::SetLogicalFunction( int function )
1080 {
1081 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1082
1083 if (m_logicalFunction == function) return;
1084
1085 GdkFunction mode = GDK_COPY;
1086 switch (function)
1087 {
1088 case wxXOR: mode = GDK_XOR; break;
1089 case wxINVERT: mode = GDK_INVERT; break;
1090 #if (GTK_MINOR_VERSION > 0)
1091 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1092 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1093 case wxCLEAR: mode = GDK_CLEAR; break;
1094 case wxSET: mode = GDK_SET; break;
1095 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1096 case wxSRC_AND:
1097 case wxAND: mode = GDK_AND; break;
1098 case wxSRC_OR:
1099 case wxOR: mode = GDK_OR; break;
1100 case wxEQUIV: mode = GDK_EQUIV; break;
1101 case wxNAND: mode = GDK_NAND; break;
1102 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
1103 case wxCOPY: mode = GDK_COPY; break;
1104 case wxNO_OP: mode = GDK_NOOP; break;
1105 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
1106 #endif
1107 default:
1108 {
1109 wxFAIL_MSG( wxT("unsupported logical function") );
1110 break;
1111 }
1112 }
1113
1114 m_logicalFunction = function;
1115
1116 if (!m_window) return;
1117
1118 gdk_gc_set_function( m_penGC, mode );
1119 gdk_gc_set_function( m_brushGC, mode );
1120 gdk_gc_set_function( m_textGC, mode );
1121 }
1122
1123 void wxWindowDC::SetTextForeground( const wxColour &col )
1124 {
1125 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1126
1127 if (m_textForegroundColour == col) return;
1128
1129 m_textForegroundColour = col;
1130 if (!m_textForegroundColour.Ok()) return;
1131
1132 if (!m_window) return;
1133
1134 m_textForegroundColour.CalcPixel( m_cmap );
1135 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1136 }
1137
1138 void wxWindowDC::SetTextBackground( const wxColour &col )
1139 {
1140 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1141
1142 if (m_textBackgroundColour == col) return;
1143
1144 m_textBackgroundColour = col;
1145 if (!m_textBackgroundColour.Ok()) return;
1146
1147 if (!m_window) return;
1148
1149 m_textBackgroundColour.CalcPixel( m_cmap );
1150 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1151 }
1152
1153 void wxWindowDC::SetBackgroundMode( int mode )
1154 {
1155 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1156
1157 m_backgroundMode = mode;
1158
1159 if (!m_window) return;
1160
1161 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1162 // transparent/solid background mode
1163
1164 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1165 {
1166 gdk_gc_set_fill( m_brushGC,
1167 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1168 }
1169 }
1170
1171 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
1172 {
1173 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1174 }
1175
1176 void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
1177 {
1178 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1179
1180 wxDC::DoSetClippingRegion( x, y, width, height );
1181
1182 if (!m_window) return;
1183
1184 GdkRectangle rect;
1185 rect.x = XLOG2DEV(x);
1186 rect.y = YLOG2DEV(y);
1187 rect.width = XLOG2DEVREL(width);
1188 rect.height = YLOG2DEVREL(height);
1189 gdk_gc_set_clip_rectangle( m_penGC, &rect );
1190 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
1191 gdk_gc_set_clip_rectangle( m_textGC, &rect );
1192 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
1193 }
1194
1195 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
1196 {
1197 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1198
1199 if (region.Empty())
1200 {
1201 DestroyClippingRegion();
1202 return;
1203 }
1204
1205 if (!m_window) return;
1206
1207 gdk_gc_set_clip_region( m_penGC, region.GetRegion() );
1208 gdk_gc_set_clip_region( m_brushGC, region.GetRegion() );
1209 gdk_gc_set_clip_region( m_textGC, region.GetRegion() );
1210 gdk_gc_set_clip_region( m_bgGC, region.GetRegion() );
1211 }
1212
1213 void wxWindowDC::DestroyClippingRegion()
1214 {
1215 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1216
1217 wxDC::DestroyClippingRegion();
1218
1219 if (!m_window) return;
1220
1221 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1222 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1223 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1224 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
1225 }
1226
1227 void wxWindowDC::SetUpDC()
1228 {
1229 Destroy();
1230 m_ok = TRUE;
1231 m_logicalFunction = wxCOPY;
1232 m_penGC = gdk_gc_new( m_window );
1233 m_brushGC = gdk_gc_new( m_window );
1234 m_textGC = gdk_gc_new( m_window );
1235 m_bgGC = gdk_gc_new( m_window );
1236
1237 wxColour tmp_col( m_textForegroundColour );
1238 m_textForegroundColour = wxNullColour;
1239 SetTextForeground( tmp_col );
1240 tmp_col = m_textBackgroundColour;
1241 m_textBackgroundColour = wxNullColour;
1242 SetTextBackground( tmp_col );
1243
1244 wxPen tmp_pen( m_pen );
1245 m_pen = wxNullPen;
1246 SetPen( tmp_pen );
1247
1248 wxFont tmp_font( m_font );
1249 m_font = wxNullFont;
1250 SetFont( tmp_font );
1251
1252 wxBrush tmp_brush( m_brush );
1253 m_brush = wxNullBrush;
1254 SetBrush( tmp_brush );
1255
1256 /*
1257 tmp_brush = m_backgroundBrush;
1258 m_backgroundBrush = wxNullBrush;
1259 SetBackground( tmp_brush );
1260 */
1261 tmp_brush = m_backgroundBrush;
1262 m_backgroundBrush = wxNullBrush;
1263 SetBackground( *wxWHITE_BRUSH );
1264 m_backgroundBrush = tmp_brush;
1265
1266 if (!hatch_bitmap)
1267 {
1268 hatch_bitmap = hatches;
1269 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1270 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1271 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1272 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1273 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1274 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1275 }
1276 }
1277
1278 void wxWindowDC::Destroy()
1279 {
1280 if (m_penGC) gdk_gc_unref( m_penGC );
1281 m_penGC = (GdkGC*) NULL;
1282 if (m_brushGC) gdk_gc_unref( m_brushGC );
1283 m_brushGC = (GdkGC*) NULL;
1284 if (m_textGC) gdk_gc_unref( m_textGC );
1285 m_textGC = (GdkGC*) NULL;
1286 if (m_bgGC) gdk_gc_unref( m_bgGC );
1287 m_bgGC = (GdkGC*) NULL;
1288 }
1289
1290 void wxWindowDC::ComputeScaleAndOrigin()
1291 {
1292 /* CMB: copy scale to see if it changes */
1293 double origScaleX = m_scaleX;
1294 double origScaleY = m_scaleY;
1295
1296 wxDC::ComputeScaleAndOrigin();
1297
1298 /* CMB: if scale has changed call SetPen to recalulate the line width */
1299 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
1300 (m_pen.Ok()))
1301 {
1302 /* this is a bit artificial, but we need to force wxDC to think
1303 the pen has changed */
1304 wxPen pen = m_pen;
1305 m_pen = wxNullPen;
1306 SetPen( pen );
1307 }
1308 }
1309
1310 // Resolution in pixels per logical inch
1311 wxSize wxWindowDC::GetPPI() const
1312 {
1313 return wxSize(100, 100);
1314 }
1315
1316 int wxWindowDC::GetDepth() const
1317 {
1318 wxFAIL_MSG(wxT("not implemented"));
1319
1320 return -1;
1321 }
1322
1323 #if wxUSE_SPLINES
1324 // ----------------------------------- spline code ----------------------------------------
1325
1326 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1327 double a3, double b3, double a4, double b4);
1328 void wx_clear_stack();
1329 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1330 double *y3, double *x4, double *y4);
1331 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1332 double x4, double y4);
1333 static bool wx_spline_add_point(double x, double y);
1334 static void wx_spline_draw_point_array(wxDC *dc);
1335
1336 wxList wx_spline_point_list;
1337
1338 #define half(z1, z2) ((z1+z2)/2.0)
1339 #define THRESHOLD 5
1340
1341 /* iterative version */
1342
1343 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1344 double b4)
1345 {
1346 register double xmid, ymid;
1347 double x1, y1, x2, y2, x3, y3, x4, y4;
1348
1349 wx_clear_stack();
1350 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1351
1352 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1353 xmid = (double)half(x2, x3);
1354 ymid = (double)half(y2, y3);
1355 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1356 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1357 wx_spline_add_point( x1, y1 );
1358 wx_spline_add_point( xmid, ymid );
1359 } else {
1360 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1361 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1362 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1363 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1364 }
1365 }
1366 }
1367
1368 /* utilities used by spline drawing routines */
1369
1370 typedef struct wx_spline_stack_struct {
1371 double x1, y1, x2, y2, x3, y3, x4, y4;
1372 } Stack;
1373
1374 #define SPLINE_STACK_DEPTH 20
1375 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1376 static Stack *wx_stack_top;
1377 static int wx_stack_count;
1378
1379 void wx_clear_stack()
1380 {
1381 wx_stack_top = wx_spline_stack;
1382 wx_stack_count = 0;
1383 }
1384
1385 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1386 {
1387 wx_stack_top->x1 = x1;
1388 wx_stack_top->y1 = y1;
1389 wx_stack_top->x2 = x2;
1390 wx_stack_top->y2 = y2;
1391 wx_stack_top->x3 = x3;
1392 wx_stack_top->y3 = y3;
1393 wx_stack_top->x4 = x4;
1394 wx_stack_top->y4 = y4;
1395 wx_stack_top++;
1396 wx_stack_count++;
1397 }
1398
1399 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1400 double *x3, double *y3, double *x4, double *y4)
1401 {
1402 if (wx_stack_count == 0)
1403 return (0);
1404 wx_stack_top--;
1405 wx_stack_count--;
1406 *x1 = wx_stack_top->x1;
1407 *y1 = wx_stack_top->y1;
1408 *x2 = wx_stack_top->x2;
1409 *y2 = wx_stack_top->y2;
1410 *x3 = wx_stack_top->x3;
1411 *y3 = wx_stack_top->y3;
1412 *x4 = wx_stack_top->x4;
1413 *y4 = wx_stack_top->y4;
1414 return (1);
1415 }
1416
1417 static bool wx_spline_add_point(double x, double y)
1418 {
1419 wxPoint *point = new wxPoint ;
1420 point->x = (int) x;
1421 point->y = (int) y;
1422 wx_spline_point_list.Append((wxObject*)point);
1423 return TRUE;
1424 }
1425
1426 static void wx_spline_draw_point_array(wxDC *dc)
1427 {
1428 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1429 wxNode *node = wx_spline_point_list.First();
1430 while (node)
1431 {
1432 wxPoint *point = (wxPoint *)node->Data();
1433 delete point;
1434 delete node;
1435 node = wx_spline_point_list.First();
1436 }
1437 }
1438
1439 void wxWindowDC::DoDrawSpline( wxList *points )
1440 {
1441 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1442
1443 wxPoint *p;
1444 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1445 double x1, y1, x2, y2;
1446
1447 wxNode *node = points->First();
1448 p = (wxPoint *)node->Data();
1449
1450 x1 = p->x;
1451 y1 = p->y;
1452
1453 node = node->Next();
1454 p = (wxPoint *)node->Data();
1455
1456 x2 = p->x;
1457 y2 = p->y;
1458 cx1 = (double)((x1 + x2) / 2);
1459 cy1 = (double)((y1 + y2) / 2);
1460 cx2 = (double)((cx1 + x2) / 2);
1461 cy2 = (double)((cy1 + y2) / 2);
1462
1463 wx_spline_add_point(x1, y1);
1464
1465 while ((node = node->Next()) != NULL)
1466 {
1467 p = (wxPoint *)node->Data();
1468 x1 = x2;
1469 y1 = y2;
1470 x2 = p->x;
1471 y2 = p->y;
1472 cx4 = (double)(x1 + x2) / 2;
1473 cy4 = (double)(y1 + y2) / 2;
1474 cx3 = (double)(x1 + cx4) / 2;
1475 cy3 = (double)(y1 + cy4) / 2;
1476
1477 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1478
1479 cx1 = cx4;
1480 cy1 = cy4;
1481 cx2 = (double)(cx1 + x2) / 2;
1482 cy2 = (double)(cy1 + y2) / 2;
1483 }
1484
1485 wx_spline_add_point( cx1, cy1 );
1486 wx_spline_add_point( x2, y2 );
1487
1488 wx_spline_draw_point_array( this );
1489 }
1490
1491 #endif // wxUSE_SPLINE
1492
1493 //-----------------------------------------------------------------------------
1494 // wxPaintDC
1495 //-----------------------------------------------------------------------------
1496
1497 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1498
1499 wxPaintDC::wxPaintDC()
1500 : wxWindowDC()
1501 {
1502 }
1503
1504 wxPaintDC::wxPaintDC( wxWindow *win )
1505 : wxWindowDC( win )
1506 {
1507 }
1508
1509 //-----------------------------------------------------------------------------
1510 // wxClientDC
1511 //-----------------------------------------------------------------------------
1512
1513 IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1514
1515 wxClientDC::wxClientDC()
1516 : wxWindowDC()
1517 {
1518 }
1519
1520 wxClientDC::wxClientDC( wxWindow *win )
1521 : wxWindowDC( win )
1522 {
1523 }
1524