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