]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/dcclient.cpp
wxFileDialog changed to use (new) wxCHANGE_DIR flag, docs updated
[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
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 {
530 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
531
532 gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc );
533 gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 );
534 }
535 }
536
537 CalcBoundingBox (x1, y1);
538 CalcBoundingBox (x2, y2);
539 }
540
541 void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
542 {
543 wxCHECK_RET( Ok(), wxT("invalid window dc") );
544
545 wxCoord xx = XLOG2DEV(x);
546 wxCoord yy = YLOG2DEV(y);
547 wxCoord ww = m_signX * XLOG2DEVREL(width);
548 wxCoord hh = m_signY * YLOG2DEVREL(height);
549
550 // CMB: handle -ve width and/or height
551 if (ww < 0) { ww = -ww; xx = xx - ww; }
552 if (hh < 0) { hh = -hh; yy = yy - hh; }
553
554 if (m_window)
555 {
556 wxCoord start = wxCoord(sa * 64.0);
557 wxCoord end = wxCoord((ea-sa) * 64.0);
558
559 if (m_brush.GetStyle() != wxTRANSPARENT)
560 {
561 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
562 {
563 gdk_gc_set_ts_origin( m_textGC,
564 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
565 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
566 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, start, end );
567 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
568 } else
569 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
570 {
571 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
572 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
573 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
574 } else
575 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
576 {
577 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
578 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
579 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
580 } else
581 if (m_brush.GetStyle() == wxSTIPPLE)
582 {
583 gdk_gc_set_ts_origin( m_brushGC,
584 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
585 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
586 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
587 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
588 }
589 else
590 {
591 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
592 }
593 }
594
595 if (m_pen.GetStyle() != wxTRANSPARENT)
596 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
597 }
598
599 CalcBoundingBox (x, y);
600 CalcBoundingBox (x + width, y + height);
601 }
602
603 void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
604 {
605 wxCHECK_RET( Ok(), wxT("invalid window dc") );
606
607 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
608 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
609
610 CalcBoundingBox (x, y);
611 }
612
613 void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
614 {
615 wxCHECK_RET( Ok(), wxT("invalid window dc") );
616
617 if (m_pen.GetStyle() == wxTRANSPARENT) return;
618 if (n <= 0) return;
619
620 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
621
622 for (int i = 0; i < n-1; i++)
623 {
624 wxCoord x1 = XLOG2DEV(points[i].x + xoffset);
625 wxCoord x2 = XLOG2DEV(points[i+1].x + xoffset);
626 wxCoord y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
627 wxCoord y2 = YLOG2DEV(points[i+1].y + yoffset);
628
629 if (m_window)
630 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
631
632 CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset );
633 }
634 }
635
636 void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
637 {
638 wxCHECK_RET( Ok(), wxT("invalid window dc") );
639
640 if (n <= 0) return;
641
642 GdkPoint *gdkpoints = new GdkPoint[n+1];
643 int i;
644 for (i = 0 ; i < n ; i++)
645 {
646 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
647 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
648
649 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
650 }
651
652 if (m_window)
653 {
654 if (m_brush.GetStyle() != wxTRANSPARENT)
655 {
656 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
657 {
658 gdk_gc_set_ts_origin( m_textGC,
659 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
660 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
661 gdk_draw_polygon( m_window, m_textGC, TRUE, gdkpoints, n );
662 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
663 } else
664 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
665 {
666 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
667 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
668 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
669 } else
670 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
671 {
672 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
673 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
674 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
675 } else
676 if (m_brush.GetStyle() == wxSTIPPLE)
677 {
678 gdk_gc_set_ts_origin( m_brushGC,
679 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
680 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
681 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
682 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
683 }
684 else
685 {
686 gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n );
687 }
688 }
689
690 if (m_pen.GetStyle() != wxTRANSPARENT)
691 {
692 for (i = 0 ; i < n ; i++)
693 {
694 gdk_draw_line( m_window, m_penGC,
695 gdkpoints[i%n].x,
696 gdkpoints[i%n].y,
697 gdkpoints[(i+1)%n].x,
698 gdkpoints[(i+1)%n].y);
699 }
700 }
701 }
702
703 delete[] gdkpoints;
704 }
705
706 void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
707 {
708 wxCHECK_RET( Ok(), wxT("invalid window dc") );
709
710 wxCoord xx = XLOG2DEV(x);
711 wxCoord yy = YLOG2DEV(y);
712 wxCoord ww = m_signX * XLOG2DEVREL(width);
713 wxCoord hh = m_signY * YLOG2DEVREL(height);
714
715 // CMB: draw nothing if transformed w or h is 0
716 if (ww == 0 || hh == 0) return;
717
718 // CMB: handle -ve width and/or height
719 if (ww < 0) { ww = -ww; xx = xx - ww; }
720 if (hh < 0) { hh = -hh; yy = yy - hh; }
721
722 if (m_window)
723 {
724 if (m_brush.GetStyle() != wxTRANSPARENT)
725 {
726 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
727 {
728 gdk_gc_set_ts_origin( m_textGC,
729 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
730 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
731 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy, ww, hh );
732 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
733 } else
734 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
735 {
736 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
737 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
738 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
739 } else
740 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
741 {
742 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
743 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
744 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
745 } else
746 if (m_brush.GetStyle() == wxSTIPPLE)
747 {
748 gdk_gc_set_ts_origin( m_brushGC,
749 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
750 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
751 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
752 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
753 }
754 else
755 {
756 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
757 }
758 }
759
760 if (m_pen.GetStyle() != wxTRANSPARENT)
761 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
762 }
763
764 CalcBoundingBox( x, y );
765 CalcBoundingBox( x + width, y + height );
766 }
767
768 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
769 {
770 wxCHECK_RET( Ok(), wxT("invalid window dc") );
771
772 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
773
774 wxCoord xx = XLOG2DEV(x);
775 wxCoord yy = YLOG2DEV(y);
776 wxCoord ww = m_signX * XLOG2DEVREL(width);
777 wxCoord hh = m_signY * YLOG2DEVREL(height);
778 wxCoord rr = XLOG2DEVREL((wxCoord)radius);
779
780 // CMB: handle -ve width and/or height
781 if (ww < 0) { ww = -ww; xx = xx - ww; }
782 if (hh < 0) { hh = -hh; yy = yy - hh; }
783
784 // CMB: if radius is zero use DrawRectangle() instead to avoid
785 // X drawing errors with small radii
786 if (rr == 0)
787 {
788 DrawRectangle( x, y, width, height );
789 return;
790 }
791
792 // CMB: draw nothing if transformed w or h is 0
793 if (ww == 0 || hh == 0) return;
794
795 // CMB: adjust size if outline is drawn otherwise the result is
796 // 1 pixel too wide and high
797 if (m_pen.GetStyle() != wxTRANSPARENT)
798 {
799 ww--;
800 hh--;
801 }
802
803 if (m_window)
804 {
805 // CMB: ensure dd is not larger than rectangle otherwise we
806 // get an hour glass shape
807 wxCoord dd = 2 * rr;
808 if (dd > ww) dd = ww;
809 if (dd > hh) dd = hh;
810 rr = dd / 2;
811
812 if (m_brush.GetStyle() != wxTRANSPARENT)
813 {
814 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
815 {
816 gdk_gc_set_ts_origin( m_textGC,
817 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
818 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
819 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx+rr, yy, ww-dd+1, hh );
820 gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
821 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
822 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
823 gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
824 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
825 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
826 } else
827 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
828 {
829 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
830 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
831 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
832 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
833 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
834 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
835 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
836 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
837 } else
838 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
839 {
840 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
841 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
842 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
843 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
844 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
845 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
846 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
847 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
848 } else
849 if (m_brush.GetStyle() == wxSTIPPLE)
850 {
851 gdk_gc_set_ts_origin( m_brushGC,
852 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
853 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
854 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
855 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
856 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
857 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
858 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
859 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
860 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
861 }
862 else
863 {
864 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
865 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
866 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
867 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
868 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
869 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
870 }
871 }
872
873 if (m_pen.GetStyle() != wxTRANSPARENT)
874 {
875 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy, xx+ww-rr, yy );
876 gdk_draw_line( m_window, m_penGC, xx+rr+1, yy+hh, xx+ww-rr, yy+hh );
877 gdk_draw_line( m_window, m_penGC, xx, yy+rr+1, xx, yy+hh-rr );
878 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr+1, xx+ww, yy+hh-rr );
879 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
880 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
881 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
882 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
883 }
884 }
885
886 // this ignores the radius
887 CalcBoundingBox( x, y );
888 CalcBoundingBox( x + width, y + height );
889 }
890
891 void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
892 {
893 wxCHECK_RET( Ok(), wxT("invalid window dc") );
894
895 wxCoord xx = XLOG2DEV(x);
896 wxCoord yy = YLOG2DEV(y);
897 wxCoord ww = m_signX * XLOG2DEVREL(width);
898 wxCoord hh = m_signY * YLOG2DEVREL(height);
899
900 // CMB: handle -ve width and/or height
901 if (ww < 0) { ww = -ww; xx = xx - ww; }
902 if (hh < 0) { hh = -hh; yy = yy - hh; }
903
904 if (m_window)
905 {
906 if (m_brush.GetStyle() != wxTRANSPARENT)
907 {
908 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
909 {
910 gdk_gc_set_ts_origin( m_textGC,
911 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
912 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
913 gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
914 gdk_gc_set_ts_origin( m_textGC, 0, 0 );
915 } else
916 if (IS_15_PIX_HATCH(m_brush.GetStyle()))
917 {
918 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 );
919 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
920 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
921 } else
922 if (IS_16_PIX_HATCH(m_brush.GetStyle()))
923 {
924 gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 );
925 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
926 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
927 } else
928 if (m_brush.GetStyle() == wxSTIPPLE)
929 {
930 gdk_gc_set_ts_origin( m_brushGC,
931 m_deviceOriginX % m_brush.GetStipple()->GetWidth(),
932 m_deviceOriginY % m_brush.GetStipple()->GetHeight() );
933 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
934 gdk_gc_set_ts_origin( m_brushGC, 0, 0 );
935 }
936 else
937 {
938 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
939 }
940 }
941
942 if (m_pen.GetStyle() != wxTRANSPARENT)
943 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
944 }
945
946 CalcBoundingBox( x - width, y - height );
947 CalcBoundingBox( x + width, y + height );
948 }
949
950 void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
951 {
952 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
953 DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE );
954 }
955
956 void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
957 wxCoord x, wxCoord y,
958 bool useMask )
959 {
960 wxCHECK_RET( Ok(), wxT("invalid window dc") );
961
962 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
963
964 bool is_mono = (bitmap.GetBitmap() != NULL);
965
966 /* scale/translate size and position */
967 int xx = XLOG2DEV(x);
968 int yy = YLOG2DEV(y);
969
970 int w = bitmap.GetWidth();
971 int h = bitmap.GetHeight();
972
973 CalcBoundingBox( x, y );
974 CalcBoundingBox( x + w, y + h );
975
976 if (!m_window) return;
977
978 int ww = XLOG2DEVREL(w);
979 int hh = YLOG2DEVREL(h);
980
981 /* compare to current clipping region */
982 if (!m_currentClippingRegion.IsNull())
983 {
984 wxRegion tmp( xx,yy,ww,hh );
985 tmp.Intersect( m_currentClippingRegion );
986 if (tmp.IsEmpty())
987 return;
988 }
989
990 /* scale bitmap if required */
991 wxBitmap use_bitmap;
992 if ((w != ww) || (h != hh))
993 {
994 wxImage image( bitmap );
995 image.Rescale( ww, hh );
996 if (is_mono)
997 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
998 else
999 use_bitmap = image.ConvertToBitmap();
1000 }
1001 else
1002 {
1003 use_bitmap = bitmap;
1004 }
1005
1006 /* apply mask if any */
1007 GdkBitmap *mask = (GdkBitmap *) NULL;
1008 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
1009
1010 if (useMask && mask)
1011 {
1012 GdkBitmap *new_mask = (GdkBitmap*) NULL;
1013 if (!m_currentClippingRegion.IsNull())
1014 {
1015 GdkColor col;
1016 new_mask = gdk_pixmap_new( wxRootWindow->window, ww, hh, 1 );
1017 GdkGC *gc = gdk_gc_new( new_mask );
1018 col.pixel = 0;
1019 gdk_gc_set_foreground( gc, &col );
1020 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1021 col.pixel = 0;
1022 gdk_gc_set_background( gc, &col );
1023 col.pixel = 1;
1024 gdk_gc_set_foreground( gc, &col );
1025 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1026 gdk_gc_set_clip_origin( gc, -xx, -yy );
1027 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1028 gdk_gc_set_stipple( gc, mask );
1029 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
1030 gdk_gc_unref( gc );
1031 }
1032
1033 if (is_mono)
1034 {
1035 if (new_mask)
1036 gdk_gc_set_clip_mask( m_textGC, new_mask );
1037 else
1038 gdk_gc_set_clip_mask( m_textGC, mask );
1039 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1040 }
1041 else
1042 {
1043 if (new_mask)
1044 gdk_gc_set_clip_mask( m_penGC, new_mask );
1045 else
1046 gdk_gc_set_clip_mask( m_penGC, mask );
1047 gdk_gc_set_clip_origin( m_penGC, xx, yy );
1048 }
1049 if (new_mask)
1050 gdk_bitmap_unref( new_mask );
1051 }
1052
1053 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1054 drawing a mono-bitmap (XBitmap) we use the current text GC */
1055 if (is_mono)
1056 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), 0, 0, xx, yy, -1, -1 );
1057 else
1058 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
1059
1060 /* remove mask again if any */
1061 if (useMask && mask)
1062 {
1063 if (is_mono)
1064 {
1065 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1066 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
1067 if (!m_currentClippingRegion.IsNull())
1068 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1069 }
1070 else
1071 {
1072 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1073 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
1074 if (!m_currentClippingRegion.IsNull())
1075 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1076 }
1077 }
1078 }
1079
1080 bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
1081 wxDC *source, wxCoord xsrc, wxCoord ysrc,
1082 int logical_func, bool useMask )
1083 {
1084 /* this is the nth try to get this utterly useless function to
1085 work. it now completely ignores the scaling or translation
1086 of the source dc, but scales correctly on the target dc and
1087 knows about possible mask information in a memory dc. */
1088
1089 wxCHECK_MSG( Ok(), FALSE, wxT("invalid window dc") );
1090
1091 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
1092
1093 if (!m_window) return FALSE;
1094
1095 wxClientDC *srcDC = (wxClientDC*)source;
1096 wxMemoryDC *memDC = (wxMemoryDC*)source;
1097
1098 bool use_bitmap_method = FALSE;
1099 bool is_mono = FALSE;
1100
1101 if (srcDC->m_isMemDC)
1102 {
1103 if (!memDC->m_selected.Ok()) return FALSE;
1104
1105 /* we use the "XCopyArea" way to copy a memory dc into
1106 y different window if the memory dc BOTH
1107 a) doesn't have any mask or its mask isn't used
1108 b) it is clipped
1109 c) is not 1-bit */
1110
1111 if (useMask && (memDC->m_selected.GetMask()))
1112 {
1113 /* we HAVE TO use the direct way for memory dcs
1114 that have mask since the XCopyArea doesn't know
1115 about masks */
1116 use_bitmap_method = TRUE;
1117 }
1118 else if (memDC->m_selected.GetDepth() == 1)
1119 {
1120 /* we HAVE TO use the direct way for memory dcs
1121 that are bitmaps because XCopyArea doesn't cope
1122 with different bit depths */
1123 is_mono = TRUE;
1124 use_bitmap_method = TRUE;
1125 }
1126 else if ((xsrc == 0) && (ysrc == 0) &&
1127 (width == memDC->m_selected.GetWidth()) &&
1128 (height == memDC->m_selected.GetHeight()))
1129 {
1130 /* we SHOULD use the direct way if all of the bitmap
1131 in the memory dc is copied in which case XCopyArea
1132 wouldn't be able able to boost performace by reducing
1133 the area to be scaled */
1134 use_bitmap_method = TRUE;
1135 }
1136 else
1137 {
1138 use_bitmap_method = FALSE;
1139 }
1140 }
1141
1142 CalcBoundingBox( xdest, ydest );
1143 CalcBoundingBox( xdest + width, ydest + height );
1144
1145 /* scale/translate size and position */
1146 wxCoord xx = XLOG2DEV(xdest);
1147 wxCoord yy = YLOG2DEV(ydest);
1148
1149 wxCoord ww = XLOG2DEVREL(width);
1150 wxCoord hh = YLOG2DEVREL(height);
1151
1152 /* compare to current clipping region */
1153 if (!m_currentClippingRegion.IsNull())
1154 {
1155 wxRegion tmp( xx,yy,ww,hh );
1156 tmp.Intersect( m_currentClippingRegion );
1157 if (tmp.IsEmpty())
1158 return TRUE;
1159 }
1160
1161 int old_logical_func = m_logicalFunction;
1162 SetLogicalFunction( logical_func );
1163
1164 if (use_bitmap_method)
1165 {
1166 /* scale/translate bitmap size */
1167 wxCoord bm_width = memDC->m_selected.GetWidth();
1168 wxCoord bm_height = memDC->m_selected.GetHeight();
1169
1170 wxCoord bm_ww = XLOG2DEVREL( bm_width );
1171 wxCoord bm_hh = YLOG2DEVREL( bm_height );
1172
1173 /* scale bitmap if required */
1174 wxBitmap use_bitmap;
1175
1176 if ((bm_width != bm_ww) || (bm_height != bm_hh))
1177 {
1178 wxImage image( memDC->m_selected );
1179 image = image.Scale( bm_ww, bm_hh );
1180
1181 if (is_mono)
1182 use_bitmap = image.ConvertToMonoBitmap(255,255,255);
1183 else
1184 use_bitmap = image.ConvertToBitmap();
1185 }
1186 else
1187 {
1188 use_bitmap = memDC->m_selected;
1189 }
1190
1191 /* apply mask if any */
1192 GdkBitmap *mask = (GdkBitmap *) NULL;
1193 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
1194
1195 if (useMask && mask)
1196 {
1197 GdkBitmap *new_mask = (GdkBitmap*) NULL;
1198 if (!m_currentClippingRegion.IsNull())
1199 {
1200 GdkColor col;
1201 new_mask = gdk_pixmap_new( wxRootWindow->window, bm_ww, bm_hh, 1 );
1202 GdkGC *gc = gdk_gc_new( new_mask );
1203 col.pixel = 0;
1204 gdk_gc_set_foreground( gc, &col );
1205 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1206 col.pixel = 0;
1207 gdk_gc_set_background( gc, &col );
1208 col.pixel = 1;
1209 gdk_gc_set_foreground( gc, &col );
1210 gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
1211 gdk_gc_set_clip_origin( gc, -xx, -yy );
1212 gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED );
1213 gdk_gc_set_stipple( gc, mask );
1214 gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
1215 gdk_gc_unref( gc );
1216 }
1217
1218 if (is_mono)
1219 {
1220 if (new_mask)
1221 gdk_gc_set_clip_mask( m_textGC, new_mask );
1222 else
1223 gdk_gc_set_clip_mask( m_textGC, mask );
1224 gdk_gc_set_clip_origin( m_textGC, xx, yy );
1225 }
1226 else
1227 {
1228 if (new_mask)
1229 gdk_gc_set_clip_mask( m_penGC, new_mask );
1230 else
1231 gdk_gc_set_clip_mask( m_penGC, mask );
1232 gdk_gc_set_clip_origin( m_penGC, xx, yy );
1233 }
1234 if (new_mask)
1235 gdk_bitmap_unref( new_mask );
1236 }
1237
1238 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1239 drawing a mono-bitmap (XBitmap) we use the current text GC */
1240
1241 if (is_mono)
1242 gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh );
1243 else
1244 gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
1245
1246 /* remove mask again if any */
1247 if (useMask && mask)
1248 {
1249 if (is_mono)
1250 {
1251 gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL );
1252 gdk_gc_set_clip_origin( m_textGC, 0, 0 );
1253 if (!m_currentClippingRegion.IsNull())
1254 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1255 }
1256 else
1257 {
1258 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
1259 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
1260 if (!m_currentClippingRegion.IsNull())
1261 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1262 }
1263 }
1264 }
1265 else /* use_bitmap_method */
1266 {
1267 if ((width != ww) || (height != hh))
1268 {
1269 /* draw source window into a bitmap as we cannot scale
1270 a window in contrast to a bitmap. this would actually
1271 work with memory dcs as well, but we'd lose the mask
1272 information and waste one step in this process since
1273 a memory already has a bitmap. all this is slightly
1274 inefficient as we could take an XImage directly from
1275 an X window, but we'd then also have to care that
1276 the window is not outside the screen (in which case
1277 we'd get a BadMatch or what not).
1278 Is a double XGetImage and combined XGetPixel and
1279 XPutPixel really faster? I'm not sure. look at wxXt
1280 for a different implementation of the same problem. */
1281
1282 wxBitmap bitmap( width, height );
1283
1284 /* copy including child window contents */
1285 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
1286 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
1287 srcDC->GetWindow(),
1288 xsrc, ysrc, width, height );
1289 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
1290
1291 /* scale image */
1292 wxImage image( bitmap );
1293 image = image.Scale( ww, hh );
1294
1295 /* convert to bitmap */
1296 bitmap = image.ConvertToBitmap();
1297
1298 /* draw scaled bitmap */
1299 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
1300
1301 }
1302 else
1303 {
1304 /* No scaling and not a memory dc with a mask either */
1305
1306 /* copy including child window contents */
1307 gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
1308 gdk_window_copy_area( m_window, m_penGC, xx, yy,
1309 srcDC->GetWindow(),
1310 xsrc, ysrc, width, height );
1311 gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
1312 }
1313 }
1314
1315 SetLogicalFunction( old_logical_func );
1316 return TRUE;
1317 }
1318
1319 void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
1320 {
1321 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1322
1323 if (!m_window) return;
1324
1325 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1326
1327 wxCHECK_RET( font, wxT("invalid font") );
1328
1329 #ifdef __WXGTK20__
1330 wxCHECK_RET( m_context, wxT("no Pango context") );
1331 #endif
1332
1333 x = XLOG2DEV(x);
1334 y = YLOG2DEV(y);
1335
1336 #ifdef __WXGTK20__
1337 /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */
1338 PangoLayout *layout = pango_layout_new(m_context);
1339 pango_layout_set_font_description(layout, m_fontdesc);
1340 {
1341 wxWX2MBbuf data = text.mb_str(wxConvUTF8);
1342 pango_layout_set_text(layout, data, strlen(data));
1343 }
1344 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
1345 PangoRectangle rect;
1346 pango_layout_line_get_extents(line, NULL, &rect);
1347 wxCoord width = rect.width;
1348 wxCoord height = rect.height;
1349 gdk_draw_layout( m_window, m_textGC, x, y, layout );
1350 #else
1351 wxCoord width = gdk_string_width( font, text.mbc_str() );
1352 wxCoord height = font->ascent + font->descent;
1353 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1354 if (m_backgroundMode == wxSOLID)
1355 {
1356 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
1357 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
1358 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1359 }
1360 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
1361 #endif
1362
1363 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1364 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1365 properties (see wxXt implementation) */
1366 if (m_font.GetUnderlined())
1367 {
1368 wxCoord ul_y = y + font->ascent;
1369 if (font->descent > 0) ul_y++;
1370 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
1371 }
1372
1373 #ifdef __WXGTK20__
1374 g_object_unref( G_OBJECT( layout ) );
1375 #endif
1376
1377 width = wxCoord(width / m_scaleX);
1378 height = wxCoord(height / m_scaleY);
1379 CalcBoundingBox (x + width, y + height);
1380 CalcBoundingBox (x, y);
1381 }
1382
1383 void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
1384 {
1385 if (angle == 0.0)
1386 {
1387 DrawText(text, x, y);
1388 return;
1389 }
1390
1391 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1392
1393 if (!m_window) return;
1394
1395 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1396
1397 wxCHECK_RET( font, wxT("invalid font") );
1398
1399 // the size of the text
1400 wxCoord w = gdk_string_width( font, text.mbc_str() );
1401 wxCoord h = font->ascent + font->descent;
1402
1403 // draw the string normally
1404 wxBitmap src(w, h);
1405 wxMemoryDC dc;
1406 dc.SelectObject(src);
1407 dc.SetFont(GetFont());
1408 dc.SetBackground(*wxWHITE_BRUSH);
1409 dc.SetBrush(*wxBLACK_BRUSH);
1410 dc.Clear();
1411 dc.DrawText(text, 0, 0);
1412 dc.SetFont(wxNullFont);
1413 dc.SelectObject(wxNullBitmap);
1414
1415 // Calculate the size of the rotated bounding box.
1416 double rad = DegToRad(angle);
1417 double dx = cos(rad),
1418 dy = sin(rad);
1419
1420 // the rectngle vertices are counted clockwise with the first one being at
1421 // (0, 0) (or, rather, at (x, y))
1422 double x2 = w*dx,
1423 y2 = -w*dy; // y axis points to the bottom, hence minus
1424 double x4 = h*dy,
1425 y4 = h*dx;
1426 double x3 = x4 + x2,
1427 y3 = y4 + y2;
1428
1429 // calc max and min
1430 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
1431 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
1432 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
1433 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
1434
1435 // prepare to blit-with-rotate the bitmap to the DC
1436 wxImage image(src);
1437
1438 GdkColor *colText = m_textForegroundColour.GetColor(),
1439 *colBack = m_textBackgroundColour.GetColor();
1440
1441 bool textColSet = TRUE;
1442
1443 unsigned char *data = image.GetData();
1444
1445 // paint pixel by pixel
1446 for ( wxCoord srcX = 0; srcX < w; srcX++ )
1447 {
1448 for ( wxCoord srcY = 0; srcY < h; srcY++ )
1449 {
1450 // transform source coords to dest coords
1451 double r = sqrt((double)srcX*srcX + srcY*srcY);
1452 double angleOrig = atan2((double)srcY, (double)srcX) - rad;
1453 wxCoord dstX = (wxCoord)(r*cos(angleOrig) + 0.5),
1454 dstY = (wxCoord)(r*sin(angleOrig) + 0.5);
1455
1456 // black pixel?
1457 bool textPixel = data[(srcY*w + srcX)*3] == 0;
1458 if ( textPixel || (m_backgroundMode == wxSOLID) )
1459 {
1460 // change colour if needed
1461 if ( textPixel != textColSet )
1462 {
1463 gdk_gc_set_foreground( m_textGC, textPixel ? colText
1464 : colBack );
1465
1466 textColSet = textPixel;
1467 }
1468
1469 // don't use DrawPoint() because it uses the current pen
1470 // colour, and we don't need it here
1471 gdk_draw_point( m_window, m_textGC,
1472 XLOG2DEV(x + dstX), YLOG2DEV(y + dstY) );
1473 }
1474 }
1475 }
1476
1477 // it would be better to draw with non underlined font and draw the line
1478 // manually here (it would be more straight...)
1479 #if 0
1480 if ( m_font.GetUnderlined() )
1481 {
1482 gdk_draw_line( m_window, m_textGC,
1483 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
1484 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
1485 }
1486 #endif // 0
1487
1488 // restore the font colour
1489 gdk_gc_set_foreground( m_textGC, colText );
1490
1491 // update the bounding box
1492 CalcBoundingBox(x + minX, y + minY);
1493 CalcBoundingBox(x + maxX, y + maxY);
1494 }
1495
1496 void wxWindowDC::DoGetTextExtent(const wxString &string,
1497 wxCoord *width, wxCoord *height,
1498 wxCoord *descent, wxCoord *externalLeading,
1499 wxFont *theFont) const
1500 {
1501 wxFont fontToUse = m_font;
1502 if (theFont) fontToUse = *theFont;
1503
1504 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
1505 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
1506 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
1507 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
1508 if (externalLeading) (*externalLeading) = 0; // ??
1509 }
1510
1511 wxCoord wxWindowDC::GetCharWidth() const
1512 {
1513 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1514 wxCHECK_MSG( font, -1, wxT("invalid font") );
1515
1516 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
1517 }
1518
1519 wxCoord wxWindowDC::GetCharHeight() const
1520 {
1521 GdkFont *font = m_font.GetInternalFont( m_scaleY );
1522 wxCHECK_MSG( font, -1, wxT("invalid font") );
1523
1524 return wxCoord((font->ascent + font->descent) / m_scaleY);
1525 }
1526
1527 void wxWindowDC::Clear()
1528 {
1529 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1530
1531 if (!m_window) return;
1532
1533 /* - we either are a memory dc or have a window as the
1534 owner. anything else shouldn't happen.
1535 - we don't use gdk_window_clear() as we don't set
1536 the window's background colour anymore. it is too
1537 much pain to keep the DC's and the window's back-
1538 ground colour in synch. */
1539
1540 if (m_owner)
1541 {
1542 int width,height;
1543 m_owner->GetSize( &width, &height );
1544 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1545 return;
1546 }
1547
1548 if (m_isMemDC)
1549 {
1550 int width,height;
1551 GetSize( &width, &height );
1552 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
1553 return;
1554 }
1555 }
1556
1557 void wxWindowDC::SetFont( const wxFont &font )
1558 {
1559 m_font = font;
1560 #ifdef __WXGTK20__
1561 // fix fontdesc?
1562 #endif
1563 }
1564
1565 void wxWindowDC::SetPen( const wxPen &pen )
1566 {
1567 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1568
1569 if (m_pen == pen) return;
1570
1571 m_pen = pen;
1572
1573 if (!m_pen.Ok()) return;
1574
1575 if (!m_window) return;
1576
1577 gint width = m_pen.GetWidth();
1578 if (width <= 0)
1579 {
1580 // CMB: if width is non-zero scale it with the dc
1581 width = 1;
1582 }
1583 else
1584 {
1585 // X doesn't allow different width in x and y and so we take
1586 // the average
1587 double w = 0.5 +
1588 ( fabs((double) XLOG2DEVREL(width)) +
1589 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
1590 width = (int)w;
1591 }
1592
1593 static const wxGTKDash dotted[] = {1, 1};
1594 static const wxGTKDash short_dashed[] = {2, 2};
1595 static const wxGTKDash wxCoord_dashed[] = {2, 4};
1596 static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3};
1597
1598 // We express dash pattern in pen width unit, so we are
1599 // independent of zoom factor and so on...
1600 int req_nb_dash;
1601 const wxGTKDash *req_dash;
1602
1603 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1604 switch (m_pen.GetStyle())
1605 {
1606 case wxUSER_DASH:
1607 {
1608 lineStyle = GDK_LINE_ON_OFF_DASH;
1609 req_nb_dash = m_pen.GetDashCount();
1610 req_dash = (wxGTKDash*)m_pen.GetDash();
1611 break;
1612 }
1613 case wxDOT:
1614 {
1615 lineStyle = GDK_LINE_ON_OFF_DASH;
1616 req_nb_dash = 2;
1617 req_dash = dotted;
1618 break;
1619 }
1620 case wxLONG_DASH:
1621 {
1622 lineStyle = GDK_LINE_ON_OFF_DASH;
1623 req_nb_dash = 2;
1624 req_dash = wxCoord_dashed;
1625 break;
1626 }
1627 case wxSHORT_DASH:
1628 {
1629 lineStyle = GDK_LINE_ON_OFF_DASH;
1630 req_nb_dash = 2;
1631 req_dash = short_dashed;
1632 break;
1633 }
1634 case wxDOT_DASH:
1635 {
1636 // lineStyle = GDK_LINE_DOUBLE_DASH;
1637 lineStyle = GDK_LINE_ON_OFF_DASH;
1638 req_nb_dash = 4;
1639 req_dash = dotted_dashed;
1640 break;
1641 }
1642
1643 case wxTRANSPARENT:
1644 case wxSTIPPLE_MASK_OPAQUE:
1645 case wxSTIPPLE:
1646 case wxSOLID:
1647 default:
1648 {
1649 lineStyle = GDK_LINE_SOLID;
1650 req_dash = (wxGTKDash*)NULL;
1651 req_nb_dash = 0;
1652 break;
1653 }
1654 }
1655
1656 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1657 if (req_dash && req_nb_dash)
1658 {
1659 wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash];
1660 if (real_req_dash)
1661 {
1662 for (int i = 0; i < req_nb_dash; i++)
1663 real_req_dash[i] = req_dash[i] * width;
1664 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
1665 delete[] real_req_dash;
1666 }
1667 else
1668 {
1669 // No Memory. We use non-scaled dash pattern...
1670 gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash );
1671 }
1672 }
1673 #endif
1674
1675 GdkCapStyle capStyle = GDK_CAP_ROUND;
1676 switch (m_pen.GetCap())
1677 {
1678 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1679 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
1680 case wxCAP_ROUND:
1681 default:
1682 {
1683 if (width <= 1)
1684 {
1685 width = 0;
1686 capStyle = GDK_CAP_NOT_LAST;
1687 }
1688 else
1689 {
1690 capStyle = GDK_CAP_ROUND;
1691 }
1692 break;
1693 }
1694 }
1695
1696 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1697 switch (m_pen.GetJoin())
1698 {
1699 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
1700 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
1701 case wxJOIN_ROUND:
1702 default: { joinStyle = GDK_JOIN_ROUND; break; }
1703 }
1704
1705 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
1706
1707 m_pen.GetColour().CalcPixel( m_cmap );
1708 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
1709 }
1710
1711 void wxWindowDC::SetBrush( const wxBrush &brush )
1712 {
1713 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1714
1715 if (m_brush == brush) return;
1716
1717 m_brush = brush;
1718
1719 if (!m_brush.Ok()) return;
1720
1721 if (!m_window) return;
1722
1723 m_brush.GetColour().CalcPixel( m_cmap );
1724 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
1725
1726 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
1727
1728 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
1729 {
1730 if (m_brush.GetStipple()->GetPixmap())
1731 {
1732 gdk_gc_set_fill( m_brushGC, GDK_TILED );
1733 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
1734 }
1735 else
1736 {
1737 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1738 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
1739 }
1740 }
1741
1742 if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
1743 {
1744 gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
1745 gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
1746 }
1747
1748 if (IS_HATCH(m_brush.GetStyle()))
1749 {
1750 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1751 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1752 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1753 }
1754 }
1755
1756 void wxWindowDC::SetBackground( const wxBrush &brush )
1757 {
1758 /* CMB 21/7/98: Added SetBackground. Sets background brush
1759 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1760
1761 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1762
1763 if (m_backgroundBrush == brush) return;
1764
1765 m_backgroundBrush = brush;
1766
1767 if (!m_backgroundBrush.Ok()) return;
1768
1769 if (!m_window) return;
1770
1771 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1772 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
1773 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
1774 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1775 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1776
1777 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
1778
1779 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
1780 {
1781 if (m_backgroundBrush.GetStipple()->GetPixmap())
1782 {
1783 gdk_gc_set_fill( m_bgGC, GDK_TILED );
1784 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
1785 }
1786 else
1787 {
1788 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1789 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
1790 }
1791 }
1792
1793 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1794 {
1795 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1796 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1797 gdk_gc_set_stipple( m_bgGC, hatches[num] );
1798 }
1799 }
1800
1801 void wxWindowDC::SetLogicalFunction( int function )
1802 {
1803 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1804
1805 if (m_logicalFunction == function)
1806 return;
1807
1808 // VZ: shouldn't this be a CHECK?
1809 if (!m_window)
1810 return;
1811
1812 GdkFunction mode = GDK_COPY;
1813 switch (function)
1814 {
1815 case wxXOR: mode = GDK_XOR; break;
1816 case wxINVERT: mode = GDK_INVERT; break;
1817 #if (GTK_MINOR_VERSION > 0)
1818 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1819 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1820 case wxCLEAR: mode = GDK_CLEAR; break;
1821 case wxSET: mode = GDK_SET; break;
1822 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1823 case wxAND: mode = GDK_AND; break;
1824 case wxOR: mode = GDK_OR; break;
1825 case wxEQUIV: mode = GDK_EQUIV; break;
1826 case wxNAND: mode = GDK_NAND; break;
1827 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
1828 case wxCOPY: mode = GDK_COPY; break;
1829 case wxNO_OP: mode = GDK_NOOP; break;
1830 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
1831
1832 // unsupported by GTK
1833 case wxNOR: mode = GDK_COPY; break;
1834 #endif
1835 default:
1836 {
1837 wxFAIL_MSG( wxT("unsupported logical function") );
1838 break;
1839 }
1840 }
1841
1842 m_logicalFunction = function;
1843
1844 gdk_gc_set_function( m_penGC, mode );
1845 gdk_gc_set_function( m_brushGC, mode );
1846
1847 // to stay compatible with wxMSW, we don't apply ROPs to the text
1848 // operations (i.e. DrawText/DrawRotatedText).
1849 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1850 gdk_gc_set_function( m_textGC, mode );
1851 }
1852
1853 void wxWindowDC::SetTextForeground( const wxColour &col )
1854 {
1855 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1856
1857 if (m_textForegroundColour == col) return;
1858
1859 m_textForegroundColour = col;
1860 if (!m_textForegroundColour.Ok()) return;
1861
1862 if (!m_window) return;
1863
1864 m_textForegroundColour.CalcPixel( m_cmap );
1865 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1866 }
1867
1868 void wxWindowDC::SetTextBackground( const wxColour &col )
1869 {
1870 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1871
1872 if (m_textBackgroundColour == col) return;
1873
1874 m_textBackgroundColour = col;
1875 if (!m_textBackgroundColour.Ok()) return;
1876
1877 if (!m_window) return;
1878
1879 m_textBackgroundColour.CalcPixel( m_cmap );
1880 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1881 }
1882
1883 void wxWindowDC::SetBackgroundMode( int mode )
1884 {
1885 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1886
1887 m_backgroundMode = mode;
1888
1889 if (!m_window) return;
1890
1891 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1892 // transparent/solid background mode
1893
1894 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1895 {
1896 gdk_gc_set_fill( m_brushGC,
1897 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1898 }
1899 }
1900
1901 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
1902 {
1903 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1904 }
1905
1906 void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
1907 {
1908 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1909
1910 if (!m_window) return;
1911
1912 wxRect rect;
1913 rect.x = XLOG2DEV(x);
1914 rect.y = YLOG2DEV(y);
1915 rect.width = XLOG2DEVREL(width);
1916 rect.height = YLOG2DEVREL(height);
1917
1918 if (!m_currentClippingRegion.IsNull())
1919 m_currentClippingRegion.Intersect( rect );
1920 else
1921 m_currentClippingRegion.Union( rect );
1922
1923 #if USE_PAINT_REGION
1924 if (!m_paintClippingRegion.IsNull())
1925 m_currentClippingRegion.Intersect( m_paintClippingRegion );
1926 #endif
1927
1928 wxCoord xx, yy, ww, hh;
1929 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1930 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1931
1932 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1933 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1934 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1935 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
1936 }
1937
1938 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
1939 {
1940 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1941
1942 if (region.Empty())
1943 {
1944 DestroyClippingRegion();
1945 return;
1946 }
1947
1948 if (!m_window) return;
1949
1950 if (!m_currentClippingRegion.IsNull())
1951 m_currentClippingRegion.Intersect( region );
1952 else
1953 m_currentClippingRegion.Union( region );
1954
1955 #if USE_PAINT_REGION
1956 if (!m_paintClippingRegion.IsNull())
1957 m_currentClippingRegion.Intersect( m_paintClippingRegion );
1958 #endif
1959
1960 wxCoord xx, yy, ww, hh;
1961 m_currentClippingRegion.GetBox( xx, yy, ww, hh );
1962 wxDC::DoSetClippingRegion( xx, yy, ww, hh );
1963
1964 gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
1965 gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
1966 gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
1967 gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
1968 }
1969
1970 void wxWindowDC::DestroyClippingRegion()
1971 {
1972 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1973
1974 wxDC::DestroyClippingRegion();
1975
1976 m_currentClippingRegion.Clear();
1977
1978 #if USE_PAINT_REGION
1979 if (!m_paintClippingRegion.IsEmpty())
1980 m_currentClippingRegion.Union( m_paintClippingRegion );
1981 #endif
1982
1983 if (!m_window) return;
1984
1985 if (m_currentClippingRegion.IsEmpty())
1986 {
1987 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1988 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1989 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1990 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
1991 }
1992 else
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
2001 void wxWindowDC::Destroy()
2002 {
2003 if (m_penGC) wxFreePoolGC( m_penGC );
2004 m_penGC = (GdkGC*) NULL;
2005 if (m_brushGC) wxFreePoolGC( m_brushGC );
2006 m_brushGC = (GdkGC*) NULL;
2007 if (m_textGC) wxFreePoolGC( m_textGC );
2008 m_textGC = (GdkGC*) NULL;
2009 if (m_bgGC) wxFreePoolGC( m_bgGC );
2010 m_bgGC = (GdkGC*) NULL;
2011 }
2012
2013 void wxWindowDC::ComputeScaleAndOrigin()
2014 {
2015 /* CMB: copy scale to see if it changes */
2016 double origScaleX = m_scaleX;
2017 double origScaleY = m_scaleY;
2018
2019 wxDC::ComputeScaleAndOrigin();
2020
2021 /* CMB: if scale has changed call SetPen to recalulate the line width */
2022 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
2023 (m_pen.Ok()))
2024 {
2025 /* this is a bit artificial, but we need to force wxDC to think
2026 the pen has changed */
2027 wxPen pen = m_pen;
2028 m_pen = wxNullPen;
2029 SetPen( pen );
2030 }
2031 }
2032
2033 // Resolution in pixels per logical inch
2034 wxSize wxWindowDC::GetPPI() const
2035 {
2036 return wxSize(100, 100);
2037 }
2038
2039 int wxWindowDC::GetDepth() const
2040 {
2041 wxFAIL_MSG(wxT("not implemented"));
2042
2043 return -1;
2044 }
2045
2046 #if wxUSE_SPLINES
2047 // ----------------------------------- spline code ----------------------------------------
2048
2049 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
2050 double a3, double b3, double a4, double b4);
2051 void wx_clear_stack();
2052 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
2053 double *y3, double *x4, double *y4);
2054 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
2055 double x4, double y4);
2056 static bool wx_spline_add_point(double x, double y);
2057 static void wx_spline_draw_point_array(wxDC *dc);
2058
2059 wxList wx_spline_point_list;
2060
2061 #define half(z1, z2) ((z1+z2)/2.0)
2062 #define THRESHOLD 5
2063
2064 /* iterative version */
2065
2066 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
2067 double b4)
2068 {
2069 register double xmid, ymid;
2070 double x1, y1, x2, y2, x3, y3, x4, y4;
2071
2072 wx_clear_stack();
2073 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
2074
2075 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
2076 xmid = (double)half(x2, x3);
2077 ymid = (double)half(y2, y3);
2078 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
2079 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
2080 wx_spline_add_point( x1, y1 );
2081 wx_spline_add_point( xmid, ymid );
2082 } else {
2083 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
2084 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
2085 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
2086 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
2087 }
2088 }
2089 }
2090
2091 /* utilities used by spline drawing routines */
2092
2093 typedef struct wx_spline_stack_struct {
2094 double x1, y1, x2, y2, x3, y3, x4, y4;
2095 } Stack;
2096
2097 #define SPLINE_STACK_DEPTH 20
2098 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
2099 static Stack *wx_stack_top;
2100 static int wx_stack_count;
2101
2102 void wx_clear_stack()
2103 {
2104 wx_stack_top = wx_spline_stack;
2105 wx_stack_count = 0;
2106 }
2107
2108 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
2109 {
2110 wx_stack_top->x1 = x1;
2111 wx_stack_top->y1 = y1;
2112 wx_stack_top->x2 = x2;
2113 wx_stack_top->y2 = y2;
2114 wx_stack_top->x3 = x3;
2115 wx_stack_top->y3 = y3;
2116 wx_stack_top->x4 = x4;
2117 wx_stack_top->y4 = y4;
2118 wx_stack_top++;
2119 wx_stack_count++;
2120 }
2121
2122 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
2123 double *x3, double *y3, double *x4, double *y4)
2124 {
2125 if (wx_stack_count == 0)
2126 return (0);
2127 wx_stack_top--;
2128 wx_stack_count--;
2129 *x1 = wx_stack_top->x1;
2130 *y1 = wx_stack_top->y1;
2131 *x2 = wx_stack_top->x2;
2132 *y2 = wx_stack_top->y2;
2133 *x3 = wx_stack_top->x3;
2134 *y3 = wx_stack_top->y3;
2135 *x4 = wx_stack_top->x4;
2136 *y4 = wx_stack_top->y4;
2137 return (1);
2138 }
2139
2140 static bool wx_spline_add_point(double x, double y)
2141 {
2142 wxPoint *point = new wxPoint ;
2143 point->x = (int) x;
2144 point->y = (int) y;
2145 wx_spline_point_list.Append((wxObject*)point);
2146 return TRUE;
2147 }
2148
2149 static void wx_spline_draw_point_array(wxDC *dc)
2150 {
2151 dc->DrawLines(&wx_spline_point_list, 0, 0 );
2152 wxNode *node = wx_spline_point_list.First();
2153 while (node)
2154 {
2155 wxPoint *point = (wxPoint *)node->Data();
2156 delete point;
2157 delete node;
2158 node = wx_spline_point_list.First();
2159 }
2160 }
2161
2162 void wxWindowDC::DoDrawSpline( wxList *points )
2163 {
2164 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2165
2166 wxPoint *p;
2167 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
2168 double x1, y1, x2, y2;
2169
2170 wxNode *node = points->First();
2171 p = (wxPoint *)node->Data();
2172
2173 x1 = p->x;
2174 y1 = p->y;
2175
2176 node = node->Next();
2177 p = (wxPoint *)node->Data();
2178
2179 x2 = p->x;
2180 y2 = p->y;
2181 cx1 = (double)((x1 + x2) / 2);
2182 cy1 = (double)((y1 + y2) / 2);
2183 cx2 = (double)((cx1 + x2) / 2);
2184 cy2 = (double)((cy1 + y2) / 2);
2185
2186 wx_spline_add_point(x1, y1);
2187
2188 while ((node = node->Next()) != NULL)
2189 {
2190 p = (wxPoint *)node->Data();
2191 x1 = x2;
2192 y1 = y2;
2193 x2 = p->x;
2194 y2 = p->y;
2195 cx4 = (double)(x1 + x2) / 2;
2196 cy4 = (double)(y1 + y2) / 2;
2197 cx3 = (double)(x1 + cx4) / 2;
2198 cy3 = (double)(y1 + cy4) / 2;
2199
2200 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
2201
2202 cx1 = cx4;
2203 cy1 = cy4;
2204 cx2 = (double)(cx1 + x2) / 2;
2205 cy2 = (double)(cy1 + y2) / 2;
2206 }
2207
2208 wx_spline_add_point( cx1, cy1 );
2209 wx_spline_add_point( x2, y2 );
2210
2211 wx_spline_draw_point_array( this );
2212 }
2213
2214 #endif // wxUSE_SPLINE
2215
2216 //-----------------------------------------------------------------------------
2217 // wxPaintDC
2218 //-----------------------------------------------------------------------------
2219
2220 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
2221
2222 wxPaintDC::wxPaintDC()
2223 : wxWindowDC()
2224 {
2225 }
2226
2227 wxPaintDC::wxPaintDC( wxWindow *win )
2228 : wxWindowDC( win )
2229 {
2230 #if USE_PAINT_REGION
2231 if (!win->m_clipPaintRegion)
2232 return;
2233
2234 m_paintClippingRegion = win->GetUpdateRegion();
2235 GdkRegion *region = m_paintClippingRegion.GetRegion();
2236 if ( region )
2237 {
2238 m_currentClippingRegion.Union( m_paintClippingRegion );
2239
2240 gdk_gc_set_clip_region( m_penGC, region );
2241 gdk_gc_set_clip_region( m_brushGC, region );
2242 gdk_gc_set_clip_region( m_textGC, region );
2243 gdk_gc_set_clip_region( m_bgGC, region );
2244 }
2245 #endif
2246 }
2247
2248 //-----------------------------------------------------------------------------
2249 // wxClientDC
2250 //-----------------------------------------------------------------------------
2251
2252 IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
2253
2254 wxClientDC::wxClientDC()
2255 : wxWindowDC()
2256 {
2257 }
2258
2259 wxClientDC::wxClientDC( wxWindow *win )
2260 : wxWindowDC( win )
2261 {
2262 }
2263
2264 // ----------------------------------------------------------------------------
2265 // wxDCModule
2266 // ----------------------------------------------------------------------------
2267
2268 class wxDCModule : public wxModule
2269 {
2270 public:
2271 bool OnInit();
2272 void OnExit();
2273
2274 private:
2275 DECLARE_DYNAMIC_CLASS(wxDCModule)
2276 };
2277
2278 IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
2279
2280 bool wxDCModule::OnInit()
2281 {
2282 wxInitGCPool();
2283 return TRUE;
2284 }
2285
2286 void wxDCModule::OnExit()
2287 {
2288 wxCleanUpGCPool();
2289 }