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