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