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