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