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