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