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