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