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