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