]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/dcclient.cpp
wxFileSystem now compiles if wxUSE_HTML (required by 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
6e13c196 503 /* scale/translate size and position */
7d5af6fa 504
265898fd
RR
505 int xx = XLOG2DEV(x);
506 int yy = YLOG2DEV(y);
7d5af6fa 507
4bc67cc5
RR
508 int w = bitmap.GetWidth();
509 int h = bitmap.GetHeight();
7d5af6fa 510
6453876e
RR
511 CalcBoundingBox( x, y );
512 CalcBoundingBox( x + w, y + h );
7d5af6fa 513
6453876e 514 if (!m_window) return;
7d5af6fa 515
4bc67cc5
RR
516 int ww = XLOG2DEVREL(w);
517 int hh = YLOG2DEVREL(h);
7d5af6fa 518
6e13c196 519 /* scale bitmap if required */
7d5af6fa 520
4bc67cc5 521 wxBitmap use_bitmap;
7d5af6fa 522
4bc67cc5 523 if ((w != ww) || (h != hh))
265898fd 524 {
4bc67cc5 525 wxImage image( bitmap );
b0e0d661 526 image = image.Scale( ww, hh );
7d5af6fa 527
b0e0d661 528 use_bitmap = image.ConvertToBitmap();
265898fd 529 }
4bc67cc5 530 else
265898fd 531 {
4bc67cc5 532 use_bitmap = bitmap;
265898fd 533 }
7d5af6fa 534
6e13c196 535 /* apply mask if any */
7d5af6fa 536
463c1fa1 537 GdkBitmap *mask = (GdkBitmap *) NULL;
4bc67cc5 538 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa
VZ
539
540 if (useMask && mask)
463c1fa1
RR
541 {
542 gdk_gc_set_clip_mask( m_penGC, mask );
543 gdk_gc_set_clip_origin( m_penGC, xx, yy );
544 }
7d5af6fa 545
6e13c196 546 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
7d5af6fa 547
4bc67cc5 548 GdkPixmap *pm = use_bitmap.GetPixmap();
6e13c196
RR
549 if (pm)
550 {
551 gdk_draw_pixmap( m_window, m_penGC, pm, 0, 0, xx, yy, -1, -1 );
552 }
553 else
554 {
555 GdkBitmap *bm = use_bitmap.GetBitmap();
556 if (bm)
557 {
558 gdk_draw_bitmap( m_window, m_penGC, bm, 0, 0, xx, yy, -1, -1 );
b0e0d661 559 }
6e13c196 560 }
7d5af6fa 561
6e13c196 562 /* remove mask again if any */
7d5af6fa
VZ
563
564 if (useMask && mask)
463c1fa1
RR
565 {
566 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
567 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
568 }
463c1fa1
RR
569}
570
72cdf4c9
VZ
571bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
572 wxDC *source, wxCoord xsrc, wxCoord ysrc,
b0e0d661 573 int logical_func, bool useMask )
c801d85f 574{
6e13c196
RR
575 /* this is the nth try to get this utterly useless function to
576 work. it now completely ignores the scaling or translation
577 of the source dc, but scales correctly on the target dc and
578 knows about possible mask information in a memory dc. */
579
223d09f6 580 wxCHECK_MSG( Ok(), FALSE, wxT("invalid window dc") );
7d5af6fa 581
223d09f6 582 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
7d5af6fa 583
6db90681 584 if (!m_window) return FALSE;
7d5af6fa 585
6e13c196
RR
586 wxClientDC *srcDC = (wxClientDC*)source;
587 wxMemoryDC *memDC = (wxMemoryDC*)source;
7d5af6fa 588
6e13c196 589 bool use_bitmap_method = FALSE;
7d5af6fa 590
6e13c196
RR
591 if (srcDC->m_isMemDC)
592 {
b0e0d661 593 if (!memDC->m_selected.Ok()) return FALSE;
7d5af6fa 594
6e13c196 595 /* we use the "XCopyArea" way to copy a memory dc into
b0e0d661
VZ
596 y different window if the memory dc BOTH
597 a) doesn't have any mask or its mask isn't used
598 b) it is clipped
599 c) is not 1-bit */
7d5af6fa 600
f234c60c 601 if (useMask && (memDC->m_selected.GetMask()))
b0e0d661
VZ
602 {
603 /* we HAVE TO use the direct way for memory dcs
604 that have mask since the XCopyArea doesn't know
605 about masks */
606 use_bitmap_method = TRUE;
607 }
608 else if (memDC->m_selected.GetDepth() == 1)
609 {
610 /* we HAVE TO use the direct way for memory dcs
611 that are bitmaps because XCopyArea doesn't cope
612 with different bit depths */
613 use_bitmap_method = TRUE;
614 }
615 else if ((xsrc == 0) && (ysrc == 0) &&
616 (width == memDC->m_selected.GetWidth()) &&
617 (height == memDC->m_selected.GetHeight()))
618 {
7d5af6fa
VZ
619 /* we SHOULD use the direct way if all of the bitmap
620 in the memory dc is copied in which case XCopyArea
621 wouldn't be able able to boost performace by reducing
b0e0d661
VZ
622 the area to be scaled */
623 use_bitmap_method = TRUE;
624 }
625 else
626 {
627 use_bitmap_method = FALSE;
628 }
6e13c196 629 }
7d5af6fa 630
265898fd
RR
631 CalcBoundingBox( xdest, ydest );
632 CalcBoundingBox( xdest + width, ydest + height );
7d5af6fa 633
4bc67cc5
RR
634 int old_logical_func = m_logicalFunction;
635 SetLogicalFunction( logical_func );
7d5af6fa 636
6e13c196 637 if (use_bitmap_method)
6f65e337 638 {
6e13c196 639 /* scale/translate bitmap size */
7d5af6fa 640
72cdf4c9
VZ
641 wxCoord bm_width = memDC->m_selected.GetWidth();
642 wxCoord bm_height = memDC->m_selected.GetHeight();
7d5af6fa 643
72cdf4c9
VZ
644 wxCoord bm_ww = XLOG2DEVREL( bm_width );
645 wxCoord bm_hh = YLOG2DEVREL( bm_height );
7d5af6fa 646
6e13c196 647 /* scale bitmap if required */
7d5af6fa 648
6e13c196 649 wxBitmap use_bitmap;
7d5af6fa 650
6e13c196
RR
651 if ((bm_width != bm_ww) || (bm_height != bm_hh))
652 {
653 wxImage image( memDC->m_selected );
b0e0d661 654 image = image.Scale( bm_ww, bm_hh );
7d5af6fa 655
b0e0d661 656 use_bitmap = image.ConvertToBitmap();
6e13c196
RR
657 }
658 else
e23d0e95 659 {
6e13c196
RR
660 use_bitmap = memDC->m_selected;
661 }
7d5af6fa 662
6e13c196 663 /* scale/translate size and position */
7d5af6fa 664
72cdf4c9
VZ
665 wxCoord xx = XLOG2DEV(xdest);
666 wxCoord yy = YLOG2DEV(ydest);
7d5af6fa 667
72cdf4c9
VZ
668 wxCoord ww = XLOG2DEVREL(width);
669 wxCoord hh = YLOG2DEVREL(height);
7d5af6fa 670
6e13c196 671 /* apply mask if any */
7d5af6fa 672
6e13c196
RR
673 GdkBitmap *mask = (GdkBitmap *) NULL;
674 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa
VZ
675
676 if (useMask && mask)
6e13c196
RR
677 {
678 gdk_gc_set_clip_mask( m_penGC, mask );
679 gdk_gc_set_clip_origin( m_penGC, xx, yy );
e23d0e95 680 }
7d5af6fa 681
6e13c196 682 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
7d5af6fa 683
6e13c196
RR
684 GdkPixmap *pm = use_bitmap.GetPixmap();
685 if (pm)
265898fd 686 {
f234c60c 687 gdk_draw_pixmap( m_window, m_penGC, pm, xsrc, ysrc, xx, yy, ww, hh );
6e13c196
RR
688 }
689 else
690 {
691 GdkBitmap *bm = use_bitmap.GetBitmap();
692 if (bm)
693 {
b0e0d661
VZ
694 /* we use the textGC here because blitting a bitmap is done
695 using the current text colour */
f234c60c 696 gdk_draw_bitmap( m_window, m_textGC, bm, xsrc, ysrc, xx, yy, ww, hh );
b0e0d661 697 }
6e13c196 698 }
7d5af6fa 699
6e13c196 700 /* remove mask again if any */
7d5af6fa
VZ
701
702 if (useMask && mask)
6e13c196
RR
703 {
704 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
705 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
265898fd 706 }
6f65e337 707 }
6e13c196
RR
708 else /* use_bitmap_method */
709 {
710 /* scale/translate size and position */
7d5af6fa 711
72cdf4c9
VZ
712 wxCoord xx = XLOG2DEV(xdest);
713 wxCoord yy = YLOG2DEV(ydest);
7d5af6fa 714
72cdf4c9
VZ
715 wxCoord ww = XLOG2DEVREL(width);
716 wxCoord hh = YLOG2DEVREL(height);
7d5af6fa 717
6e13c196 718 if ((width != ww) || (height != hh))
b0e0d661
VZ
719 {
720 /* draw source window into a bitmap as we cannot scale
721 a window in contrast to a bitmap. this would actually
722 work with memory dcs as well, but we'd lose the mask
723 information and waste one step in this process since
724 a memory already has a bitmap. all this is slightly
725 inefficient as we could take an XImage directly from
726 an X window, but we'd then also have to care that
727 the window is not outside the screen (in which case
728 we'd get a BadMatch or what not).
729 Is a double XGetImage and combined XGetPixel and
730 XPutPixel really faster? I'm not sure. look at wxXt
731 for a different implementation of the same problem. */
7d5af6fa 732
b0e0d661 733 wxBitmap bitmap( width, height );
7d5af6fa 734 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
6e13c196 735 srcDC->GetWindow(),
b0e0d661 736 xsrc, ysrc, width, height );
7d5af6fa 737
b0e0d661 738 /* scale image */
7d5af6fa 739
6e13c196 740 wxImage image( bitmap );
b0e0d661 741 image = image.Scale( ww, hh );
7d5af6fa 742
b0e0d661 743 /* convert to bitmap */
7d5af6fa 744
b0e0d661 745 bitmap = image.ConvertToBitmap();
7d5af6fa 746
b0e0d661 747 /* draw scaled bitmap */
7d5af6fa 748
6e13c196 749 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
7d5af6fa 750
b0e0d661
VZ
751 }
752 else
753 {
754 /* no scaling and not a memory dc with a mask either */
7d5af6fa 755
6e13c196
RR
756 gdk_window_copy_area( m_window, m_penGC, xx, yy,
757 srcDC->GetWindow(),
758 xsrc, ysrc, width, height );
b0e0d661 759 }
6e13c196 760 }
c801d85f 761
4bc67cc5
RR
762 SetLogicalFunction( old_logical_func );
763 return TRUE;
903f689b 764}
c801d85f 765
72cdf4c9 766void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
c801d85f 767{
223d09f6 768 wxCHECK_RET( Ok(), wxT("invalid window dc") );
18a2fa37 769
6db90681 770 if (!m_window) return;
7d5af6fa 771
265898fd 772 GdkFont *font = m_font.GetInternalFont( m_scaleY );
6f65e337 773
a1fffa9f
VZ
774 wxCHECK_RET( font, wxT("invalid font") );
775
265898fd
RR
776 x = XLOG2DEV(x);
777 y = YLOG2DEV(y);
18a2fa37 778
bbbbe360 779 /* CMB 21/5/98: draw text background if mode is wxSOLID */
265898fd
RR
780 if (m_backgroundMode == wxSOLID)
781 {
72cdf4c9
VZ
782 wxCoord width = gdk_string_width( font, text.mbc_str() );
783 wxCoord height = font->ascent + font->descent;
265898fd
RR
784 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
785 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
786 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
787 }
93c5dd39 788 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
18a2fa37 789
bbbbe360
RR
790 /* CMB 17/7/98: simple underline: ignores scaling and underlying
791 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
792 properties (see wxXt implementation) */
265898fd
RR
793 if (m_font.GetUnderlined())
794 {
13111b2a
VZ
795 wxCoord width = gdk_string_width( font, text.mbc_str() );
796 wxCoord ul_y = y + font->ascent;
265898fd
RR
797 if (font->descent > 0) ul_y++;
798 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
799 }
7d5af6fa 800
13111b2a 801 wxCoord w, h;
265898fd
RR
802 GetTextExtent (text, &w, &h);
803 CalcBoundingBox (x + w, y + h);
804 CalcBoundingBox (x, y);
903f689b 805}
c801d85f 806
95724b1a
VZ
807void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
808{
809 if (angle == 0.0)
810 {
811 DrawText(text, x, y);
812 return;
813 }
814
815 wxCHECK_RET( Ok(), wxT("invalid window dc") );
816
817 if (!m_window) return;
818
819 GdkFont *font = m_font.GetInternalFont( m_scaleY );
820
821 wxCHECK_RET( font, wxT("invalid font") );
822
9a8c7620 823 // the size of the text
13111b2a
VZ
824 wxCoord w = gdk_string_width( font, text.mbc_str() );
825 wxCoord h = font->ascent + font->descent;
95724b1a 826
9a8c7620
VZ
827 // draw the string normally
828 wxBitmap src(w, h);
95724b1a
VZ
829 wxMemoryDC dc;
830 dc.SelectObject(src);
831 dc.SetFont(GetFont());
832 dc.SetBackground(*wxWHITE_BRUSH);
833 dc.SetBrush(*wxBLACK_BRUSH);
834 dc.Clear();
835 dc.DrawText(text, 0, 0);
836 dc.SetFont(wxNullFont);
9a8c7620 837 dc.SelectObject(wxNullBitmap);
95724b1a
VZ
838
839 // Calculate the size of the rotated bounding box.
9a8c7620
VZ
840 double rad = DegToRad(angle);
841 double dx = cos(rad),
842 dy = sin(rad);
843
844 // the rectngle vertices are counted clockwise with the first one being at
845 // (0, 0) (or, rather, at (x, y))
846 double x2 = w*dx,
847 y2 = -w*dy; // y axis points to the bottom, hence minus
848 double x4 = h*dy,
849 y4 = h*dx;
850 double x3 = x4 + x2,
851 y3 = y4 + y2;
852
853 // calc max and min
854 wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
855 maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
856 minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
857 minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
858
859 // prepare to blit-with-rotate the bitmap to the DC
860 wxImage image(src);
861
862 GdkColor *colText = m_textForegroundColour.GetColor(),
863 *colBack = m_textBackgroundColour.GetColor();
864
865 bool textColSet = TRUE;
866
867 unsigned char *data = image.GetData();
868
869 // paint pixel by pixel
870 for ( wxCoord srcX = 0; srcX < w; srcX++ )
95724b1a 871 {
9a8c7620 872 for ( wxCoord srcY = 0; srcY < h; srcY++ )
95724b1a 873 {
9a8c7620
VZ
874 // transform source coords to dest coords
875 double r = sqrt(srcX*srcX + srcY*srcY);
876 double angleOrig = atan2(srcY, srcX) - rad;
877 wxCoord dstX = (wxCoord)(r*cos(angleOrig) + 0.5),
878 dstY = (wxCoord)(r*sin(angleOrig) + 0.5);
879
880 // black pixel?
881 bool textPixel = data[(srcY*w + srcX)*3] == 0;
882 if ( textPixel || (m_backgroundMode == wxSOLID) )
95724b1a 883 {
9a8c7620
VZ
884 // change colour if needed
885 if ( textPixel != textColSet )
95724b1a 886 {
9a8c7620
VZ
887 gdk_gc_set_foreground( m_textGC, textPixel ? colText
888 : colBack );
889
890 textColSet = textPixel;
95724b1a 891 }
9a8c7620
VZ
892
893 // don't use DrawPoint() because it uses the current pen
894 // colour, and we don't need it here
895 gdk_draw_point( m_window, m_textGC,
896 XLOG2DEV(x + dstX), YLOG2DEV(y + dstY) );
95724b1a
VZ
897 }
898 }
899 }
900
9a8c7620
VZ
901 // it would be better to draw with non underlined font and draw the line
902 // manually here (it would be more straight...)
903#if 0
904 if ( m_font.GetUnderlined() )
905 {
906 gdk_draw_line( m_window, m_textGC,
907 XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
908 XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
909 }
910#endif // 0
911
912 // restore the font colour
913 gdk_gc_set_foreground( m_textGC, colText );
914
915 // update the bounding box
916 CalcBoundingBox(x + minX, y + minY);
917 CalcBoundingBox(x + maxX, y + maxY);
95724b1a
VZ
918}
919
72cdf4c9
VZ
920void wxWindowDC::DoGetTextExtent(const wxString &string,
921 wxCoord *width, wxCoord *height,
922 wxCoord *descent, wxCoord *externalLeading,
923 wxFont *theFont) const
c801d85f 924{
265898fd
RR
925 wxFont fontToUse = m_font;
926 if (theFont) fontToUse = *theFont;
7d5af6fa 927
265898fd 928 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
72cdf4c9
VZ
929 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
930 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
931 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
265898fd 932 if (externalLeading) (*externalLeading) = 0; // ??
903f689b 933}
c801d85f 934
72cdf4c9 935wxCoord wxWindowDC::GetCharWidth() const
c801d85f 936{
265898fd 937 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 938 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 939
72cdf4c9 940 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 941}
c801d85f 942
72cdf4c9 943wxCoord wxWindowDC::GetCharHeight() const
c801d85f 944{
265898fd 945 GdkFont *font = m_font.GetInternalFont( m_scaleY );
58c837a4 946 wxCHECK_MSG( font, -1, wxT("invalid font") );
7beba2fc 947
72cdf4c9 948 return wxCoord((font->ascent + font->descent) / m_scaleY);
903f689b 949}
c801d85f 950
4bc67cc5 951void wxWindowDC::Clear()
c801d85f 952{
223d09f6 953 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 954
6db90681 955 if (!m_window) return;
7d5af6fa 956
f234c60c
RR
957 /* - we either are a memory dc or have a window as the
958 owner. anything else shouldn't happen.
959 - we don't use gdk_window_clear() as we don't set
960 the window's background colour anymore. it is too
961 much pain to keep the DC's and the window's back-
962 ground colour in synch. */
7d5af6fa 963
f234c60c 964 if (m_owner)
265898fd 965 {
f234c60c
RR
966 int width,height;
967 m_owner->GetSize( &width, &height );
968 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 969 return;
265898fd 970 }
f234c60c
RR
971
972 if (m_isMemDC)
265898fd
RR
973 {
974 int width,height;
975 GetSize( &width, &height );
976 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 977 return;
265898fd 978 }
903f689b 979}
c801d85f 980
ec758a20 981void wxWindowDC::SetFont( const wxFont &font )
c801d85f 982{
265898fd 983 m_font = font;
903f689b 984}
c801d85f 985
ec758a20 986void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 987{
223d09f6 988 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 989
265898fd 990 if (m_pen == pen) return;
7d5af6fa 991
265898fd 992 m_pen = pen;
7d5af6fa 993
265898fd 994 if (!m_pen.Ok()) return;
7d5af6fa 995
6db90681 996 if (!m_window) return;
7d5af6fa 997
265898fd 998 gint width = m_pen.GetWidth();
265898fd
RR
999 if (width <= 0)
1000 {
112c5086 1001 // CMB: if width is non-zero scale it with the dc
265898fd
RR
1002 width = 1;
1003 }
1004 else
1005 {
1006 // X doesn't allow different width in x and y and so we take
1007 // the average
503f414e
VZ
1008 double w = 0.5 +
1009 ( fabs((double) XLOG2DEVREL(width)) +
1010 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
265898fd
RR
1011 width = (int)w;
1012 }
7d5af6fa
VZ
1013
1014 static const char dotted[] = {1, 1};
1015 static const char short_dashed[] = {2, 2};
72cdf4c9 1016 static const char wxCoord_dashed[] = {2, 4};
7d5af6fa
VZ
1017 static const char dotted_dashed[] = {3, 3, 1, 3};
1018
112c5086
RR
1019 // We express dash pattern in pen width unit, so we are
1020 // independent of zoom factor and so on...
1021 int req_nb_dash;
1022 const char *req_dash;
7d5af6fa 1023
265898fd
RR
1024 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1025 switch (m_pen.GetStyle())
1026 {
112c5086 1027 case wxUSER_DASH:
7d5af6fa
VZ
1028 {
1029 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1030 req_nb_dash = m_pen.GetDashCount();
1031 req_dash = m_pen.GetDash();
1032 break;
7d5af6fa
VZ
1033 }
1034 case wxDOT:
1035 {
1036 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1037 req_nb_dash = 2;
1038 req_dash = dotted;
7d5af6fa
VZ
1039 break;
1040 }
1041 case wxLONG_DASH:
1042 {
1043 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 1044 req_nb_dash = 2;
72cdf4c9 1045 req_dash = wxCoord_dashed;
7d5af6fa
VZ
1046 break;
1047 }
1048 case wxSHORT_DASH:
1049 {
1050 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1051 req_nb_dash = 2;
1052 req_dash = short_dashed;
7d5af6fa
VZ
1053 break;
1054 }
1055 case wxDOT_DASH:
1056 {
1057// lineStyle = GDK_LINE_DOUBLE_DASH;
1058 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
1059 req_nb_dash = 4;
1060 req_dash = dotted_dashed;
7d5af6fa
VZ
1061 break;
1062 }
1063
1064 case wxTRANSPARENT:
1065 case wxSTIPPLE:
1066 case wxSOLID:
1067 default:
1068 {
1069 lineStyle = GDK_LINE_SOLID;
112c5086
RR
1070 req_dash = (wxDash*)NULL;
1071 req_nb_dash = 0;
7d5af6fa
VZ
1072 break;
1073 }
265898fd 1074 }
7d5af6fa 1075
953704c1 1076#if (GTK_MINOR_VERSION > 0)
112c5086
RR
1077 if (req_dash && req_nb_dash)
1078 {
1079 char *real_req_dash = new char[req_nb_dash];
1080 if (real_req_dash)
1081 {
1082 for (int i = 0; i < req_nb_dash; i++)
1083 real_req_dash[i] = req_dash[i] * width;
7d5af6fa 1084 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
112c5086
RR
1085 delete[] real_req_dash;
1086 }
1087 else
1088 {
1089 // No Memory. We use non-scaled dash pattern...
7d5af6fa 1090 gdk_gc_set_dashes( m_penGC, 0, (char*)req_dash, req_nb_dash );
112c5086
RR
1091 }
1092 }
953704c1 1093#endif
7d5af6fa 1094
265898fd
RR
1095 GdkCapStyle capStyle = GDK_CAP_ROUND;
1096 switch (m_pen.GetCap())
1097 {
1098 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
1099 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1100 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
1101 }
7d5af6fa 1102
265898fd
RR
1103 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1104 switch (m_pen.GetJoin())
1105 {
1106 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
1107 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
1108 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
1109 }
7d5af6fa 1110
265898fd 1111 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
7d5af6fa 1112
265898fd
RR
1113 m_pen.GetColour().CalcPixel( m_cmap );
1114 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 1115}
c801d85f 1116
ec758a20 1117void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 1118{
223d09f6 1119 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1120
265898fd 1121 if (m_brush == brush) return;
7d5af6fa 1122
265898fd 1123 m_brush = brush;
7d5af6fa 1124
265898fd 1125 if (!m_brush.Ok()) return;
7d5af6fa 1126
6db90681 1127 if (!m_window) return;
7d5af6fa 1128
265898fd
RR
1129 m_brush.GetColour().CalcPixel( m_cmap );
1130 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
7d5af6fa 1131
956dbab1 1132 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
7d5af6fa 1133
4fcd73bd 1134 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 1135 {
4fcd73bd 1136 if (m_brush.GetStipple()->GetPixmap())
7d5af6fa 1137 {
956dbab1 1138 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 1139 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
7d5af6fa 1140 }
b0e0d661 1141 else
7d5af6fa 1142 {
956dbab1 1143 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 1144 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
7d5af6fa 1145 }
265898fd 1146 }
7d5af6fa 1147
265898fd
RR
1148 if (IS_HATCH(m_brush.GetStyle()))
1149 {
956dbab1 1150 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
1151 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1152 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1153 }
903f689b 1154}
c801d85f 1155
ec758a20 1156void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 1157{
bbbbe360
RR
1158 /* CMB 21/7/98: Added SetBackground. Sets background brush
1159 * for Clear() and bg colour for shapes filled with cross-hatch brush */
7d5af6fa 1160
223d09f6 1161 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1162
265898fd 1163 if (m_backgroundBrush == brush) return;
7d5af6fa 1164
265898fd 1165 m_backgroundBrush = brush;
7d5af6fa 1166
265898fd 1167 if (!m_backgroundBrush.Ok()) return;
7d5af6fa 1168
6db90681 1169 if (!m_window) return;
7d5af6fa 1170
265898fd
RR
1171 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1172 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 1173 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 1174 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 1175 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
3417c2cd
RR
1176
1177 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
7d5af6fa 1178
cd25b18c 1179 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 1180 {
fd128b0c 1181 if (m_backgroundBrush.GetStipple()->GetPixmap())
7d5af6fa 1182 {
3417c2cd 1183 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 1184 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
7d5af6fa 1185 }
cd25b18c 1186 else
7d5af6fa 1187 {
3417c2cd 1188 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 1189 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
7d5af6fa 1190 }
265898fd 1191 }
7d5af6fa 1192
265898fd
RR
1193 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1194 {
3417c2cd 1195 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
1196 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1197 gdk_gc_set_stipple( m_bgGC, hatches[num] );
bbbbe360 1198 }
903f689b 1199}
46dc76ba 1200
ec758a20 1201void wxWindowDC::SetLogicalFunction( int function )
c801d85f 1202{
223d09f6 1203 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1204
265898fd 1205 if (m_logicalFunction == function) return;
01eaf507 1206
265898fd
RR
1207 GdkFunction mode = GDK_COPY;
1208 switch (function)
1209 {
3c679789
RR
1210 case wxXOR: mode = GDK_XOR; break;
1211 case wxINVERT: mode = GDK_INVERT; break;
01eaf507 1212#if (GTK_MINOR_VERSION > 0)
3c679789
RR
1213 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1214 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1215 case wxCLEAR: mode = GDK_CLEAR; break;
1216 case wxSET: mode = GDK_SET; break;
1217 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
7d5af6fa 1218 case wxSRC_AND:
3c679789 1219 case wxAND: mode = GDK_AND; break;
7d5af6fa 1220 case wxSRC_OR:
3c679789
RR
1221 case wxOR: mode = GDK_OR; break;
1222 case wxEQUIV: mode = GDK_EQUIV; break;
1223 case wxNAND: mode = GDK_NAND; break;
1224 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
7d5af6fa
VZ
1225 case wxCOPY: mode = GDK_COPY; break;
1226 case wxNO_OP: mode = GDK_NOOP; break;
1227 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
c96faa7c 1228#endif
01eaf507 1229 default:
7d5af6fa 1230 {
223d09f6 1231 wxFAIL_MSG( wxT("unsupported logical function") );
7d5af6fa
VZ
1232 break;
1233 }
265898fd 1234 }
7d5af6fa 1235
265898fd 1236 m_logicalFunction = function;
7d5af6fa 1237
6db90681 1238 if (!m_window) return;
7d5af6fa 1239
265898fd
RR
1240 gdk_gc_set_function( m_penGC, mode );
1241 gdk_gc_set_function( m_brushGC, mode );
3bc755fc 1242 gdk_gc_set_function( m_textGC, mode );
903f689b 1243}
c801d85f 1244
ec758a20 1245void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 1246{
223d09f6 1247 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1248
265898fd 1249 if (m_textForegroundColour == col) return;
7d5af6fa 1250
265898fd
RR
1251 m_textForegroundColour = col;
1252 if (!m_textForegroundColour.Ok()) return;
7d5af6fa 1253
6db90681 1254 if (!m_window) return;
7d5af6fa 1255
265898fd
RR
1256 m_textForegroundColour.CalcPixel( m_cmap );
1257 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
903f689b 1258}
c801d85f 1259
ec758a20 1260void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 1261{
223d09f6 1262 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1263
265898fd 1264 if (m_textBackgroundColour == col) return;
7d5af6fa 1265
265898fd
RR
1266 m_textBackgroundColour = col;
1267 if (!m_textBackgroundColour.Ok()) return;
7d5af6fa 1268
6db90681 1269 if (!m_window) return;
7d5af6fa 1270
265898fd
RR
1271 m_textBackgroundColour.CalcPixel( m_cmap );
1272 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
903f689b 1273}
c801d85f 1274
ec758a20 1275void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 1276{
223d09f6 1277 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1278
265898fd 1279 m_backgroundMode = mode;
46dc76ba 1280
6db90681 1281 if (!m_window) return;
7d5af6fa 1282
265898fd
RR
1283 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1284 // transparent/solid background mode
7d5af6fa 1285
265898fd
RR
1286 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1287 {
1288 gdk_gc_set_fill( m_brushGC,
1289 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1290 }
903f689b 1291}
c801d85f 1292
ec758a20 1293void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 1294{
223d09f6 1295 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
903f689b 1296}
c801d85f 1297
72cdf4c9 1298void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 1299{
223d09f6 1300 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1301
089e55d6 1302 wxDC::DoSetClippingRegion( x, y, width, height );
7d5af6fa 1303
6db90681 1304 if (!m_window) return;
7d5af6fa 1305
265898fd
RR
1306 GdkRectangle rect;
1307 rect.x = XLOG2DEV(x);
1308 rect.y = YLOG2DEV(y);
1309 rect.width = XLOG2DEVREL(width);
1310 rect.height = YLOG2DEVREL(height);
1311 gdk_gc_set_clip_rectangle( m_penGC, &rect );
1312 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
1313 gdk_gc_set_clip_rectangle( m_textGC, &rect );
1314 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
903f689b 1315}
c801d85f 1316
b0e0d661 1317void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
463c1fa1 1318{
223d09f6 1319 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1320
463c1fa1
RR
1321 if (region.Empty())
1322 {
1323 DestroyClippingRegion();
1324 return;
1325 }
7d5af6fa 1326
6db90681 1327 if (!m_window) return;
7d5af6fa 1328
463c1fa1
RR
1329 gdk_gc_set_clip_region( m_penGC, region.GetRegion() );
1330 gdk_gc_set_clip_region( m_brushGC, region.GetRegion() );
1331 gdk_gc_set_clip_region( m_textGC, region.GetRegion() );
1332 gdk_gc_set_clip_region( m_bgGC, region.GetRegion() );
1333}
1334
4bc67cc5 1335void wxWindowDC::DestroyClippingRegion()
c801d85f 1336{
223d09f6 1337 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1338
265898fd 1339 wxDC::DestroyClippingRegion();
7d5af6fa 1340
6db90681 1341 if (!m_window) return;
7d5af6fa 1342
265898fd
RR
1343 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1344 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1345 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1346 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
903f689b 1347}
c801d85f 1348
4bc67cc5 1349void wxWindowDC::SetUpDC()
c801d85f 1350{
265898fd
RR
1351 Destroy();
1352 m_ok = TRUE;
1353 m_logicalFunction = wxCOPY;
1354 m_penGC = gdk_gc_new( m_window );
1355 m_brushGC = gdk_gc_new( m_window );
1356 m_textGC = gdk_gc_new( m_window );
1357 m_bgGC = gdk_gc_new( m_window );
7d5af6fa 1358
a802c3a1
RR
1359 wxColour tmp_col( m_textForegroundColour );
1360 m_textForegroundColour = wxNullColour;
1361 SetTextForeground( tmp_col );
1362 tmp_col = m_textBackgroundColour;
1363 m_textBackgroundColour = wxNullColour;
1364 SetTextBackground( tmp_col );
7d5af6fa 1365
031b2a7b
RR
1366 wxPen tmp_pen( m_pen );
1367 m_pen = wxNullPen;
1368 SetPen( tmp_pen );
7d5af6fa 1369
031b2a7b
RR
1370 wxFont tmp_font( m_font );
1371 m_font = wxNullFont;
1372 SetFont( tmp_font );
7d5af6fa 1373
031b2a7b
RR
1374 wxBrush tmp_brush( m_brush );
1375 m_brush = wxNullBrush;
1376 SetBrush( tmp_brush );
7d5af6fa 1377
91b8de8d 1378/*
031b2a7b
RR
1379 tmp_brush = m_backgroundBrush;
1380 m_backgroundBrush = wxNullBrush;
1381 SetBackground( tmp_brush );
91b8de8d
RR
1382*/
1383 tmp_brush = m_backgroundBrush;
1384 m_backgroundBrush = wxNullBrush;
1385 SetBackground( *wxWHITE_BRUSH );
1386 m_backgroundBrush = tmp_brush;
7d5af6fa
VZ
1387
1388 if (!hatch_bitmap)
265898fd
RR
1389 {
1390 hatch_bitmap = hatches;
1391 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1392 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1393 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1394 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1395 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1396 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1397 }
903f689b 1398}
c801d85f 1399
4bc67cc5 1400void wxWindowDC::Destroy()
dbf858b5 1401{
265898fd
RR
1402 if (m_penGC) gdk_gc_unref( m_penGC );
1403 m_penGC = (GdkGC*) NULL;
1404 if (m_brushGC) gdk_gc_unref( m_brushGC );
1405 m_brushGC = (GdkGC*) NULL;
1406 if (m_textGC) gdk_gc_unref( m_textGC );
1407 m_textGC = (GdkGC*) NULL;
1408 if (m_bgGC) gdk_gc_unref( m_bgGC );
1409 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
1410}
1411
238d735d
RR
1412void wxWindowDC::ComputeScaleAndOrigin()
1413{
1414 /* CMB: copy scale to see if it changes */
1415 double origScaleX = m_scaleX;
1416 double origScaleY = m_scaleY;
1417
1418 wxDC::ComputeScaleAndOrigin();
1419
1420 /* CMB: if scale has changed call SetPen to recalulate the line width */
1421 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
1422 (m_pen.Ok()))
1423 {
1424 /* this is a bit artificial, but we need to force wxDC to think
1425 the pen has changed */
1426 wxPen pen = m_pen;
1427 m_pen = wxNullPen;
1428 SetPen( pen );
1429 }
1430}
1431
b0e0d661
VZ
1432// Resolution in pixels per logical inch
1433wxSize wxWindowDC::GetPPI() const
1434{
1435 return wxSize(100, 100);
1436}
1437
1438int wxWindowDC::GetDepth() const
c801d85f 1439{
223d09f6 1440 wxFAIL_MSG(wxT("not implemented"));
b0e0d661
VZ
1441
1442 return -1;
903f689b 1443}
c801d85f 1444
d54e4256 1445#if wxUSE_SPLINES
c801d85f
KB
1446// ----------------------------------- spline code ----------------------------------------
1447
1448void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1449 double a3, double b3, double a4, double b4);
4bc67cc5 1450void wx_clear_stack();
c801d85f
KB
1451int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1452 double *y3, double *x4, double *y4);
1453void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1454 double x4, double y4);
1455static bool wx_spline_add_point(double x, double y);
1456static void wx_spline_draw_point_array(wxDC *dc);
1457
1458wxList wx_spline_point_list;
1459
b0e0d661
VZ
1460#define half(z1, z2) ((z1+z2)/2.0)
1461#define THRESHOLD 5
c801d85f
KB
1462
1463/* iterative version */
1464
1465void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1466 double b4)
1467{
1468 register double xmid, ymid;
1469 double x1, y1, x2, y2, x3, y3, x4, y4;
1470
1471 wx_clear_stack();
1472 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1473
1474 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1475 xmid = (double)half(x2, x3);
1476 ymid = (double)half(y2, y3);
b0e0d661
VZ
1477 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1478 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
c801d85f
KB
1479 wx_spline_add_point( x1, y1 );
1480 wx_spline_add_point( xmid, ymid );
b0e0d661 1481 } else {
c801d85f
KB
1482 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1483 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1484 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1485 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
b0e0d661 1486 }
c801d85f
KB
1487 }
1488}
1489
1490/* utilities used by spline drawing routines */
1491
1492typedef struct wx_spline_stack_struct {
1493 double x1, y1, x2, y2, x3, y3, x4, y4;
1494} Stack;
1495
1496#define SPLINE_STACK_DEPTH 20
1497static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1498static Stack *wx_stack_top;
1499static int wx_stack_count;
1500
4bc67cc5 1501void wx_clear_stack()
c801d85f
KB
1502{
1503 wx_stack_top = wx_spline_stack;
1504 wx_stack_count = 0;
1505}
1506
1507void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1508{
1509 wx_stack_top->x1 = x1;
1510 wx_stack_top->y1 = y1;
1511 wx_stack_top->x2 = x2;
1512 wx_stack_top->y2 = y2;
1513 wx_stack_top->x3 = x3;
1514 wx_stack_top->y3 = y3;
1515 wx_stack_top->x4 = x4;
1516 wx_stack_top->y4 = y4;
1517 wx_stack_top++;
1518 wx_stack_count++;
1519}
1520
1521int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1522 double *x3, double *y3, double *x4, double *y4)
1523{
1524 if (wx_stack_count == 0)
b0e0d661 1525 return (0);
c801d85f
KB
1526 wx_stack_top--;
1527 wx_stack_count--;
1528 *x1 = wx_stack_top->x1;
1529 *y1 = wx_stack_top->y1;
1530 *x2 = wx_stack_top->x2;
1531 *y2 = wx_stack_top->y2;
1532 *x3 = wx_stack_top->x3;
1533 *y3 = wx_stack_top->y3;
1534 *x4 = wx_stack_top->x4;
1535 *y4 = wx_stack_top->y4;
1536 return (1);
1537}
1538
1539static bool wx_spline_add_point(double x, double y)
1540{
1541 wxPoint *point = new wxPoint ;
1542 point->x = (int) x;
1543 point->y = (int) y;
1544 wx_spline_point_list.Append((wxObject*)point);
1545 return TRUE;
1546}
1547
1548static void wx_spline_draw_point_array(wxDC *dc)
1549{
1550 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1551 wxNode *node = wx_spline_point_list.First();
1552 while (node)
1553 {
1554 wxPoint *point = (wxPoint *)node->Data();
1555 delete point;
1556 delete node;
1557 node = wx_spline_point_list.First();
1558 }
1559}
1560
b0e0d661 1561void wxWindowDC::DoDrawSpline( wxList *points )
c801d85f 1562{
223d09f6 1563 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1564
c801d85f
KB
1565 wxPoint *p;
1566 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1567 double x1, y1, x2, y2;
1568
1569 wxNode *node = points->First();
1570 p = (wxPoint *)node->Data();
1571
1572 x1 = p->x;
1573 y1 = p->y;
1574
1575 node = node->Next();
1576 p = (wxPoint *)node->Data();
1577
1578 x2 = p->x;
1579 y2 = p->y;
1580 cx1 = (double)((x1 + x2) / 2);
1581 cy1 = (double)((y1 + y2) / 2);
1582 cx2 = (double)((cx1 + x2) / 2);
1583 cy2 = (double)((cy1 + y2) / 2);
1584
1585 wx_spline_add_point(x1, y1);
1586
1587 while ((node = node->Next()) != NULL)
1588 {
1589 p = (wxPoint *)node->Data();
b0e0d661
VZ
1590 x1 = x2;
1591 y1 = y2;
1592 x2 = p->x;
1593 y2 = p->y;
c801d85f
KB
1594 cx4 = (double)(x1 + x2) / 2;
1595 cy4 = (double)(y1 + y2) / 2;
1596 cx3 = (double)(x1 + cx4) / 2;
1597 cy3 = (double)(y1 + cy4) / 2;
1598
1599 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1600
b0e0d661
VZ
1601 cx1 = cx4;
1602 cy1 = cy4;
c801d85f
KB
1603 cx2 = (double)(cx1 + x2) / 2;
1604 cy2 = (double)(cy1 + y2) / 2;
1605 }
1606
1607 wx_spline_add_point( cx1, cy1 );
1608 wx_spline_add_point( x2, y2 );
1609
1610 wx_spline_draw_point_array( this );
903f689b 1611}
ec758a20 1612
b0e0d661 1613#endif // wxUSE_SPLINE
ec758a20
RR
1614
1615//-----------------------------------------------------------------------------
1616// wxPaintDC
1617//-----------------------------------------------------------------------------
1618
1619IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1620
4bc67cc5 1621wxPaintDC::wxPaintDC()
ec758a20
RR
1622 : wxWindowDC()
1623{
1624}
1625
1626wxPaintDC::wxPaintDC( wxWindow *win )
1627 : wxWindowDC( win )
1628{
1629}
1630
1631//-----------------------------------------------------------------------------
1632// wxClientDC
1633//-----------------------------------------------------------------------------
1634
1635IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1636
4bc67cc5 1637wxClientDC::wxClientDC()
ec758a20
RR
1638 : wxWindowDC()
1639{
1640}
1641
1642wxClientDC::wxClientDC( wxWindow *win )
1643 : wxWindowDC( win )
1644{
1645}
1646