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