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