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