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