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