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