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