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