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