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