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