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