]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dcclient.cpp
remove the line for image.h, restore a line commented out by mistake
[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
c801d85f
KB
7// Licence: wxWindows licence
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"
f5368809 17#include <math.h>
c801d85f
KB
18
19//-----------------------------------------------------------------------------
20// local data
21//-----------------------------------------------------------------------------
22
23#include "bdiag.xbm"
24#include "fdiag.xbm"
25#include "cdiag.xbm"
26#include "horiz.xbm"
27#include "verti.xbm"
28#include "cross.xbm"
29#define num_hatches 6
30
31static GdkPixmap *hatches[num_hatches];
c67daf87 32static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
c801d85f
KB
33
34//-----------------------------------------------------------------------------
35// constants
36//-----------------------------------------------------------------------------
37
38#define RAD2DEG 57.2957795131
39
6f65e337
JS
40//-----------------------------------------------------------------------------
41// temporary implementation of the missing GDK function
42//-----------------------------------------------------------------------------
43#include "gdk/gdkprivate.h"
44void gdk_draw_bitmap (GdkDrawable *drawable,
45 GdkGC *gc,
46 GdkDrawable *src,
47 gint xsrc,
48 gint ysrc,
49 gint xdest,
50 gint ydest,
51 gint width,
52 gint height)
53{
265898fd
RR
54 GdkWindowPrivate *drawable_private;
55 GdkWindowPrivate *src_private;
56 GdkGCPrivate *gc_private;
57
58 g_return_if_fail (drawable != NULL);
59 g_return_if_fail (src != NULL);
60 g_return_if_fail (gc != NULL);
61
62 drawable_private = (GdkWindowPrivate*) drawable;
63 src_private = (GdkWindowPrivate*) src;
64 if (drawable_private->destroyed || src_private->destroyed)
65 return;
66
67 gc_private = (GdkGCPrivate*) gc;
68
69 if (width == -1) width = src_private->width;
70 if (height == -1) height = src_private->height;
71
72 XCopyPlane( drawable_private->xdisplay,
73 src_private->xwindow,
74 drawable_private->xwindow,
75 gc_private->xgc,
76 xsrc, ysrc,
77 width, height,
78 xdest, ydest,
79 1 );
6f65e337
JS
80}
81
c801d85f 82//-----------------------------------------------------------------------------
ec758a20 83// wxWindowDC
c801d85f
KB
84//-----------------------------------------------------------------------------
85
ec758a20 86IMPLEMENT_DYNAMIC_CLASS(wxWindowDC,wxDC)
c801d85f 87
4bc67cc5 88wxWindowDC::wxWindowDC()
c801d85f 89{
265898fd
RR
90 m_penGC = (GdkGC *) NULL;
91 m_brushGC = (GdkGC *) NULL;
92 m_textGC = (GdkGC *) NULL;
93 m_bgGC = (GdkGC *) NULL;
94 m_cmap = (GdkColormap *) NULL;
95 m_isMemDC = FALSE;
903f689b 96}
c801d85f 97
ec758a20 98wxWindowDC::wxWindowDC( wxWindow *window )
c801d85f 99{
265898fd
RR
100 m_penGC = (GdkGC *) NULL;
101 m_brushGC = (GdkGC *) NULL;
102 m_textGC = (GdkGC *) NULL;
103 m_bgGC = (GdkGC *) NULL;
104 m_cmap = (GdkColormap *) NULL;
105
106 if (!window) return;
107 GtkWidget *widget = window->m_wxwindow;
108 if (!widget) return;
109 m_window = widget->window;
110 if (!m_window) return;
111 if (window->m_wxwindow)
112 m_cmap = gtk_widget_get_colormap( window->m_wxwindow );
113 else
114 m_cmap = gtk_widget_get_colormap( window->m_widget );
0180d5da 115
265898fd 116 m_isMemDC = FALSE;
0180d5da 117
265898fd 118 SetUpDC();
76ed8f8d 119
903f689b 120}
c801d85f 121
4bc67cc5 122wxWindowDC::~wxWindowDC()
c801d85f 123{
265898fd 124 Destroy();
903f689b 125}
c801d85f 126
463c1fa1
RR
127void wxWindowDC::FloodFill( long WXUNUSED(x), long WXUNUSED(y),
128 const wxColour &WXUNUSED(col), int WXUNUSED(style) )
c801d85f 129{
ec758a20 130 wxFAIL_MSG( "wxWindowDC::FloodFill not implemented" );
903f689b 131}
c801d85f 132
ec758a20 133bool wxWindowDC::GetPixel( long WXUNUSED(x1), long WXUNUSED(y1), wxColour *WXUNUSED(col) ) const
c801d85f 134{
ec758a20 135 wxFAIL_MSG( "wxWindowDC::GetPixel not implemented" );
265898fd 136 return FALSE;
903f689b 137}
c801d85f 138
ec758a20 139void wxWindowDC::DrawLine( long x1, long y1, long x2, long y2 )
c801d85f 140{
4bc67cc5 141 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 142
265898fd
RR
143 if (m_pen.GetStyle() != wxTRANSPARENT)
144 {
145 gdk_draw_line( m_window, m_penGC,
146 XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
ed880dd4
RR
147
148 CalcBoundingBox(x1, y1);
149 CalcBoundingBox(x2, y2);
265898fd 150 }
903f689b 151}
c801d85f 152
ec758a20 153void wxWindowDC::CrossHair( long x, long y )
c801d85f 154{
4bc67cc5 155 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 156
265898fd
RR
157 if (m_pen.GetStyle() != wxTRANSPARENT)
158 {
159 int w = 0;
160 int h = 0;
161 GetSize( &w, &h );
162 long xx = XLOG2DEV(x);
163 long yy = YLOG2DEV(y);
164 gdk_draw_line( m_window, m_penGC, 0, yy, XLOG2DEVREL(w), yy );
165 gdk_draw_line( m_window, m_penGC, xx, 0, xx, YLOG2DEVREL(h) );
166 }
903f689b 167}
c801d85f 168
ec758a20 169void wxWindowDC::DrawArc( long x1, long y1, long x2, long y2, double xc, double yc )
c801d85f 170{
4bc67cc5 171 wxCHECK_RET( Ok(), "invalid window dc" );
265898fd
RR
172
173 long xx1 = XLOG2DEV(x1);
174 long yy1 = YLOG2DEV(y1);
175 long xx2 = XLOG2DEV(x2);
176 long yy2 = YLOG2DEV(y2);
177 long xxc = XLOG2DEV((long)xc);
178 long yyc = YLOG2DEV((long)yc);
179 double dx = xx1 - xxc;
180 double dy = yy1 - yyc;
181 double radius = sqrt(dx*dx+dy*dy);
182 long r = (long)radius;
183 double radius1, radius2;
184
185 if (xx1 == xx2 && yy1 == yy2)
186 {
187 radius1 = 0.0;
188 radius2 = 360.0;
189 }
190 else
191 if (radius == 0.0)
192 {
193 radius1 = radius2 = 0.0;
194 }
195 else
196 {
197 radius1 = (xx1 - xxc == 0) ?
c801d85f
KB
198 (yy1 - yyc < 0) ? 90.0 : -90.0 :
199 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
265898fd 200 radius2 = (xx2 - xxc == 0) ?
c801d85f
KB
201 (yy2 - yyc < 0) ? 90.0 : -90.0 :
202 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
265898fd
RR
203 }
204 long alpha1 = long(radius1 * 64.0);
205 long alpha2 = long((radius2 - radius1) * 64.0);
206 while (alpha2 <= 0) alpha2 += 360*64;
207 while (alpha1 > 360*64) alpha1 -= 360*64;
208
209 if (m_brush.GetStyle() != wxTRANSPARENT)
210 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
c801d85f 211
265898fd
RR
212 if (m_pen.GetStyle() != wxTRANSPARENT)
213 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
214
215 CalcBoundingBox (x1, y1);
216 CalcBoundingBox (x2, y2);
903f689b 217}
c801d85f 218
ec758a20 219void wxWindowDC::DrawEllipticArc( long x, long y, long width, long height, double sa, double ea )
c801d85f 220{
4bc67cc5 221 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 222
265898fd
RR
223 long xx = XLOG2DEV(x);
224 long yy = YLOG2DEV(y);
225 long ww = m_signX * XLOG2DEVREL(width);
226 long hh = m_signY * YLOG2DEVREL(height);
c801d85f 227
265898fd
RR
228 // CMB: handle -ve width and/or height
229 if (ww < 0) { ww = -ww; xx = xx - ww; }
230 if (hh < 0) { hh = -hh; yy = yy - hh; }
6f65e337 231
265898fd
RR
232 long start = long(sa * 64.0);
233 long end = long(ea * 64.0);
234 if (m_brush.GetStyle() != wxTRANSPARENT)
235 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
c801d85f 236
265898fd
RR
237 if (m_pen.GetStyle() != wxTRANSPARENT)
238 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
239
240 CalcBoundingBox (x, y);
241 CalcBoundingBox (x + width, y + height);
903f689b 242}
c801d85f 243
ec758a20 244void wxWindowDC::DrawPoint( long x, long y )
c801d85f 245{
4bc67cc5 246 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 247
265898fd
RR
248 if (m_pen.GetStyle() != wxTRANSPARENT)
249 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
250
251 CalcBoundingBox (x, y);
903f689b 252}
c801d85f 253
ec758a20 254void wxWindowDC::DrawLines( int n, wxPoint points[], long xoffset, long yoffset )
c801d85f 255{
4bc67cc5 256 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 257
265898fd
RR
258 if (m_pen.GetStyle() == wxTRANSPARENT) return;
259 if (n <= 0) return;
c801d85f 260
265898fd
RR
261 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
262
263 for (int i = 0; i < n-1; i++)
264 {
265 long x1 = XLOG2DEV(points[i].x + xoffset);
266 long x2 = XLOG2DEV(points[i+1].x + xoffset);
267 long y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
268 long y2 = YLOG2DEV(points[i+1].y + yoffset);
269 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
270
271 CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset );
272 }
903f689b 273}
c801d85f 274
ec758a20 275void wxWindowDC::DrawLines( wxList *points, long xoffset, long yoffset )
c801d85f 276{
4bc67cc5 277 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 278
265898fd 279 if (m_pen.GetStyle() == wxTRANSPARENT) return;
c801d85f 280
265898fd
RR
281 wxNode *node = points->First();
282 if (!node) return;
283
284 wxPoint *pt = (wxPoint*)node->Data();
285 CalcBoundingBox( pt->x + xoffset, pt->y + yoffset );
286
287 while (node->Next())
288 {
289 wxPoint *point = (wxPoint*)node->Data();
290 wxPoint *npoint = (wxPoint*)node->Next()->Data();
291 long x1 = XLOG2DEV(point->x + xoffset);
292 long x2 = XLOG2DEV(npoint->x + xoffset);
293 long y1 = YLOG2DEV(point->y + yoffset); // and a waste again...
294 long y2 = YLOG2DEV(npoint->y + yoffset);
295 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
296 node = node->Next();
297
298 CalcBoundingBox( npoint->x + xoffset, npoint->y + yoffset );
299 }
903f689b 300}
c801d85f 301
ec758a20 302void wxWindowDC::DrawPolygon( int n, wxPoint points[], long xoffset, long yoffset, int WXUNUSED(fillStyle) )
cf7a7e13 303{
4bc67cc5 304 wxCHECK_RET( Ok(), "invalid window dc" );
cf7a7e13 305
4bc67cc5 306 if (n <= 0) return;
265898fd
RR
307
308 GdkPoint *gdkpoints = new GdkPoint[n+1];
309 int i;
310 for (i = 0 ; i < n ; i++)
311 {
312 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
313 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
314
315 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
316 }
317
318 if (m_brush.GetStyle() != wxTRANSPARENT)
319 gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n);
320
321 // To do: Fillstyle
322
323 if (m_pen.GetStyle() != wxTRANSPARENT)
324 for (i = 0 ; i < n ; i++)
325 {
326 gdk_draw_line( m_window, m_penGC,
327 gdkpoints[i%n].x,
328 gdkpoints[i%n].y,
329 gdkpoints[(i+1)%n].x,
330 gdkpoints[(i+1)%n].y);
331 }
332
333 delete[] gdkpoints;
903f689b 334}
c801d85f 335
ec758a20 336void wxWindowDC::DrawPolygon( wxList *lines, long xoffset, long yoffset, int WXUNUSED(fillStyle))
cf7a7e13 337{
4bc67cc5 338 wxCHECK_RET( Ok(), "invalid window dc" );
265898fd
RR
339
340 int n = lines->Number();
4bc67cc5 341 if (n <= 0) return;
265898fd
RR
342
343 GdkPoint *gdkpoints = new GdkPoint[n];
344 wxNode *node = lines->First();
345 int cnt = 0;
346 while (node)
347 {
348 wxPoint *p = (wxPoint *) node->Data();
349 gdkpoints[cnt].x = XLOG2DEV(p->x + xoffset);
350 gdkpoints[cnt].y = YLOG2DEV(p->y + yoffset);
351 node = node->Next();
352 cnt++;
353
354 CalcBoundingBox( p->x + xoffset, p->y + yoffset );
355 }
356
357 if (m_brush.GetStyle() != wxTRANSPARENT)
358 gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n);
359
360 // To do: Fillstyle
361
362 if (m_pen.GetStyle() != wxTRANSPARENT)
363 {
364 int i;
365 for (i = 0 ; i < n ; i++)
366 {
367 gdk_draw_line( m_window, m_penGC,
368 gdkpoints[i%n].x,
369 gdkpoints[i%n].y,
370 gdkpoints[(i+1)%n].x,
371 gdkpoints[(i+1)%n].y );
372 }
373 }
374 delete[] gdkpoints;
903f689b 375}
c801d85f 376
ec758a20 377void wxWindowDC::DrawRectangle( long x, long y, long width, long height )
c801d85f 378{
4bc67cc5 379 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 380
265898fd
RR
381 long xx = XLOG2DEV(x);
382 long yy = YLOG2DEV(y);
383 long ww = m_signX * XLOG2DEVREL(width);
384 long hh = m_signY * YLOG2DEVREL(height);
c801d85f 385
265898fd
RR
386 // CMB: draw nothing if transformed w or h is 0
387 if (ww == 0 || hh == 0) return;
6f65e337 388
265898fd
RR
389 // CMB: handle -ve width and/or height
390 if (ww < 0) { ww = -ww; xx = xx - ww; }
391 if (hh < 0) { hh = -hh; yy = yy - hh; }
6f65e337 392
265898fd
RR
393 if (m_brush.GetStyle() != wxTRANSPARENT)
394 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
c801d85f 395
265898fd
RR
396 if (m_pen.GetStyle() != wxTRANSPARENT)
397 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
398
399 CalcBoundingBox( x, y );
400 CalcBoundingBox( x + width, y + height );
903f689b 401}
c801d85f 402
ec758a20 403void wxWindowDC::DrawRoundedRectangle( long x, long y, long width, long height, double radius )
c801d85f 404{
4bc67cc5 405 wxCHECK_RET( Ok(), "invalid window dc" );
265898fd
RR
406
407 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
408
409 long xx = XLOG2DEV(x);
410 long yy = YLOG2DEV(y);
411 long ww = m_signX * XLOG2DEVREL(width);
412 long hh = m_signY * YLOG2DEVREL(height);
413 long rr = XLOG2DEVREL((long)radius);
414
415 // CMB: handle -ve width and/or height
416 if (ww < 0) { ww = -ww; xx = xx - ww; }
417 if (hh < 0) { hh = -hh; yy = yy - hh; }
418
419 // CMB: if radius is zero use DrawRectangle() instead to avoid
420 // X drawing errors with small radii
421 if (rr == 0)
422 {
423 DrawRectangle( x, y, width, height );
424 return;
425 }
426
427 // CMB: draw nothing if transformed w or h is 0
428 if (ww == 0 || hh == 0) return;
429
430 // CMB: adjust size if outline is drawn otherwise the result is
431 // 1 pixel too wide and high
432 if (m_pen.GetStyle() != wxTRANSPARENT)
433 {
434 ww--;
435 hh--;
436 }
437
438 // CMB: ensure dd is not larger than rectangle otherwise we
439 // get an hour glass shape
440 long dd = 2 * 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 }
454
455 if (m_pen.GetStyle() != wxTRANSPARENT)
456 {
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 );
465 }
466
467 // this ignores the radius
468 CalcBoundingBox( x, y );
469 CalcBoundingBox( x + width, y + height );
903f689b 470}
c801d85f 471
ec758a20 472void wxWindowDC::DrawEllipse( long x, long y, long width, long height )
c801d85f 473{
4bc67cc5 474 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 475
265898fd
RR
476 long xx = XLOG2DEV(x);
477 long yy = YLOG2DEV(y);
478 long ww = m_signX * XLOG2DEVREL(width);
479 long hh = m_signY * YLOG2DEVREL(height);
6f65e337 480
265898fd
RR
481 // CMB: handle -ve width and/or height
482 if (ww < 0) { ww = -ww; xx = xx - ww; }
483 if (hh < 0) { hh = -hh; yy = yy - hh; }
c801d85f 484
265898fd
RR
485 if (m_brush.GetStyle() != wxTRANSPARENT)
486 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
c801d85f 487
265898fd
RR
488 if (m_pen.GetStyle() != wxTRANSPARENT)
489 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
490
ed880dd4 491 CalcBoundingBox( x - width, y - height );
265898fd 492 CalcBoundingBox( x + width, y + height );
903f689b 493}
c801d85f 494
4bc67cc5 495bool wxWindowDC::CanDrawBitmap() const
c801d85f 496{
4bc67cc5 497 return TRUE;
903f689b 498}
c801d85f 499
463c1fa1 500void wxWindowDC::DrawIcon( const wxIcon &icon, long x, long y )
c801d85f 501{
4bc67cc5
RR
502 DrawBitmap( icon, x, y, TRUE );
503}
504
505void wxWindowDC::DrawBitmap( const wxBitmap &bitmap, long x, long y, bool useMask )
506{
507 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 508
4bc67cc5 509 if (!bitmap.Ok()) return;
c801d85f 510
265898fd
RR
511 int xx = XLOG2DEV(x);
512 int yy = YLOG2DEV(y);
c801d85f 513
4bc67cc5
RR
514 int w = bitmap.GetWidth();
515 int h = bitmap.GetHeight();
c801d85f 516
4bc67cc5
RR
517 int ww = XLOG2DEVREL(w);
518 int hh = YLOG2DEVREL(h);
519
520 wxBitmap use_bitmap;
521
522 if ((w != ww) || (h != hh))
265898fd 523 {
4bc67cc5
RR
524 wxImage image( bitmap );
525 image = image.Scale( ww, hh );
526
527 use_bitmap = image.ConvertToBitmap();
265898fd 528 }
4bc67cc5 529 else
265898fd 530 {
4bc67cc5 531 use_bitmap = bitmap;
265898fd
RR
532 }
533
463c1fa1 534 GdkBitmap *mask = (GdkBitmap *) NULL;
4bc67cc5 535 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
463c1fa1
RR
536
537 if (useMask && mask)
538 {
539 gdk_gc_set_clip_mask( m_penGC, mask );
540 gdk_gc_set_clip_origin( m_penGC, xx, yy );
541 }
542
4bc67cc5 543 GdkPixmap *pm = use_bitmap.GetPixmap();
463c1fa1
RR
544 gdk_draw_pixmap( m_window, m_penGC, pm, 0, 0, xx, yy, -1, -1 );
545
546 if (useMask && mask)
547 {
548 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
549 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
550 }
551
552 CalcBoundingBox( x, y );
4bc67cc5 553 CalcBoundingBox( x + w, y + h );
463c1fa1
RR
554}
555
ec758a20 556bool wxWindowDC::Blit( long xdest, long ydest, long width, long height,
4bc67cc5 557 wxDC *source, long xsrc, long ysrc, int logical_func, bool useMask )
c801d85f 558{
4bc67cc5 559 wxCHECK_MSG( Ok(), FALSE, "invalid window dc" );
e23d0e95 560
265898fd
RR
561 CalcBoundingBox( xdest, ydest );
562 CalcBoundingBox( xdest + width, ydest + height );
563
4bc67cc5
RR
564 int old_logical_func = m_logicalFunction;
565 SetLogicalFunction( logical_func );
566
265898fd 567 wxClientDC *csrc = (wxClientDC*)source;
f96aa4d9 568
265898fd 569 if (csrc->m_isMemDC)
6f65e337 570 {
265898fd 571 wxMemoryDC* srcDC = (wxMemoryDC*)source;
e23d0e95
RR
572 GdkPixmap* pmap = srcDC->m_selected.GetPixmap();
573 if (pmap)
574 {
575 long xx = XLOG2DEV(xdest);
576 long yy = YLOG2DEV(ydest);
577
578 GdkBitmap *mask = (GdkBitmap *) NULL;
579 if (srcDC->m_selected.GetMask()) mask = srcDC->m_selected.GetMask()->GetBitmap();
580
581 if (useMask && mask)
582 {
4bc67cc5
RR
583 gdk_gc_set_clip_mask( m_penGC, mask );
584 gdk_gc_set_clip_origin( m_penGC, xx, yy );
e23d0e95 585 }
031b2a7b 586
4bc67cc5 587 gdk_draw_pixmap( m_window, m_penGC, pmap,
e23d0e95
RR
588 source->DeviceToLogicalX(xsrc),
589 source->DeviceToLogicalY(ysrc),
590 xx,
591 yy,
592 source->DeviceToLogicalXRel(width),
593 source->DeviceToLogicalYRel(height) );
594
595 if (useMask && mask)
596 {
4bc67cc5
RR
597 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
598 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
e23d0e95
RR
599 }
600
4bc67cc5 601 SetLogicalFunction( old_logical_func );
e23d0e95
RR
602 return TRUE;
603 }
604
605 GdkBitmap* bmap = srcDC->m_selected.GetBitmap();
265898fd
RR
606 if (bmap)
607 {
608 long xx = XLOG2DEV(xdest);
609 long yy = YLOG2DEV(ydest);
df875e59 610
265898fd
RR
611 GdkBitmap *mask = (GdkBitmap *) NULL;
612 if (srcDC->m_selected.GetMask()) mask = srcDC->m_selected.GetMask()->GetBitmap();
df875e59 613
265898fd
RR
614 if (useMask && mask)
615 {
4bc67cc5
RR
616 gdk_gc_set_clip_mask( m_penGC, mask );
617 gdk_gc_set_clip_origin( m_penGC, xx, yy );
265898fd
RR
618 }
619
ee5e8025 620 gdk_draw_bitmap( m_window, m_textGC, bmap,
265898fd
RR
621 source->DeviceToLogicalX(xsrc),
622 source->DeviceToLogicalY(ysrc),
623 xx,
624 yy,
625 source->DeviceToLogicalXRel(width),
626 source->DeviceToLogicalYRel(height) );
df875e59 627
265898fd
RR
628 if (useMask && mask)
629 {
4bc67cc5
RR
630 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
631 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
265898fd 632 }
df875e59 633
4bc67cc5 634 SetLogicalFunction( old_logical_func );
265898fd
RR
635 return TRUE;
636 }
6f65e337 637 }
c801d85f 638
4bc67cc5 639 gdk_window_copy_area ( m_window, m_penGC,
265898fd
RR
640 XLOG2DEV(xdest), YLOG2DEV(ydest),
641 csrc->GetWindow(),
642 source->DeviceToLogicalX(xsrc),
643 source->DeviceToLogicalY(ysrc),
644 source->DeviceToLogicalXRel(width),
645 source->DeviceToLogicalYRel(height) );
c801d85f 646
4bc67cc5
RR
647 SetLogicalFunction( old_logical_func );
648 return TRUE;
903f689b 649}
c801d85f 650
ec758a20 651void wxWindowDC::DrawText( const wxString &text, long x, long y, bool WXUNUSED(use16) )
c801d85f 652{
4bc67cc5 653 wxCHECK_RET( Ok(), "invalid window dc" );
18a2fa37 654
265898fd 655 GdkFont *font = m_font.GetInternalFont( m_scaleY );
6f65e337 656
265898fd
RR
657 x = XLOG2DEV(x);
658 y = YLOG2DEV(y);
18a2fa37 659
265898fd
RR
660 // CMB 21/5/98: draw text background if mode is wxSOLID
661 if (m_backgroundMode == wxSOLID)
662 {
663 long width = gdk_string_width( font, text );
664 long height = font->ascent + font->descent;
665 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
666 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
667 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
668 }
669 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text );
18a2fa37 670
265898fd
RR
671 // CMB 17/7/98: simple underline: ignores scaling and underlying
672 // X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
673 // properties (see wxXt implementation)
674 if (m_font.GetUnderlined())
675 {
676 long width = gdk_string_width( font, text );
677 long ul_y = y + font->ascent;
678 if (font->descent > 0) ul_y++;
679 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
680 }
681
682 long w, h;
683 GetTextExtent (text, &w, &h);
684 CalcBoundingBox (x + w, y + h);
685 CalcBoundingBox (x, y);
903f689b 686}
c801d85f 687
4bc67cc5 688bool wxWindowDC::CanGetTextExtent() const
c801d85f 689{
265898fd 690 return TRUE;
903f689b 691}
c801d85f 692
ec758a20 693void wxWindowDC::GetTextExtent( const wxString &string, long *width, long *height,
c33c4050
RR
694 long *descent, long *externalLeading,
695 wxFont *theFont, bool WXUNUSED(use16) )
c801d85f 696{
4bc67cc5 697 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 698
265898fd
RR
699 wxFont fontToUse = m_font;
700 if (theFont) fontToUse = *theFont;
c33c4050 701
265898fd
RR
702 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
703 if (width) (*width) = long(gdk_string_width( font, string ) / m_scaleX);
704 if (height) (*height) = long((font->ascent + font->descent) / m_scaleY);
705 if (descent) (*descent) = long(font->descent / m_scaleY);
706 if (externalLeading) (*externalLeading) = 0; // ??
903f689b 707}
c801d85f 708
4bc67cc5 709long wxWindowDC::GetCharWidth()
c801d85f 710{
4bc67cc5 711 wxCHECK_MSG( Ok(), 0, "invalid window dc" );
c801d85f 712
265898fd
RR
713 GdkFont *font = m_font.GetInternalFont( m_scaleY );
714 return long(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 715}
c801d85f 716
4bc67cc5 717long wxWindowDC::GetCharHeight()
c801d85f 718{
4bc67cc5 719 wxCHECK_MSG( Ok(), 0, "invalid window dc" );
c801d85f 720
265898fd
RR
721 GdkFont *font = m_font.GetInternalFont( m_scaleY );
722 return long((font->ascent + font->descent) / m_scaleY);
903f689b 723}
c801d85f 724
4bc67cc5 725void wxWindowDC::Clear()
c801d85f 726{
4bc67cc5 727 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 728
265898fd
RR
729 if (!m_isMemDC)
730 {
731 gdk_window_clear( m_window );
732 }
733 else
734 {
735 int width,height;
736 GetSize( &width, &height );
737 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
738 }
903f689b 739}
c801d85f 740
ec758a20 741void wxWindowDC::SetFont( const wxFont &font )
c801d85f 742{
4bc67cc5 743 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 744
265898fd 745 m_font = font;
903f689b 746}
c801d85f 747
ec758a20 748void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 749{
4bc67cc5
RR
750 wxCHECK_RET( Ok(), "invalid window dc" );
751
265898fd
RR
752 if (m_pen == pen) return;
753
754 m_pen = pen;
755
756 if (!m_pen.Ok()) return;
757
758 gint width = m_pen.GetWidth();
759 // CMB: if width is non-zero scale it with the dc
760 if (width <= 0)
761 {
762 width = 1;
763 }
764 else
765 {
766 // X doesn't allow different width in x and y and so we take
767 // the average
768 double w = 0.5 + (abs(XLOG2DEVREL(width)) + abs(YLOG2DEVREL(width))) / 2.0;
769 width = (int)w;
770 }
771
772 GdkLineStyle lineStyle = GDK_LINE_SOLID;
773 switch (m_pen.GetStyle())
774 {
775 case wxSOLID: { lineStyle = GDK_LINE_SOLID; break; }
776 case wxDOT: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
777 case wxLONG_DASH: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
778 case wxSHORT_DASH: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
779 case wxDOT_DASH: { lineStyle = GDK_LINE_DOUBLE_DASH; break; }
780 }
781
782 GdkCapStyle capStyle = GDK_CAP_ROUND;
783 switch (m_pen.GetCap())
784 {
785 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
786 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
787 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
788 }
789
790 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
791 switch (m_pen.GetJoin())
792 {
793 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
794 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
795 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
796 }
797
798 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
799
800 m_pen.GetColour().CalcPixel( m_cmap );
801 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 802}
c801d85f 803
ec758a20 804void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 805{
4bc67cc5 806 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 807
265898fd 808 if (m_brush == brush) return;
c801d85f 809
265898fd 810 m_brush = brush;
c801d85f 811
265898fd 812 if (!m_brush.Ok()) return;
c801d85f 813
265898fd
RR
814 m_brush.GetColour().CalcPixel( m_cmap );
815 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
c801d85f 816
265898fd
RR
817 GdkFill fillStyle = GDK_SOLID;
818 switch (m_brush.GetStyle())
819 {
820 case wxSOLID:
821 case wxTRANSPARENT:
822 break;
823 default:
824 fillStyle = GDK_STIPPLED;
825 }
c801d85f 826
265898fd 827 gdk_gc_set_fill( m_brushGC, fillStyle );
c801d85f 828
265898fd
RR
829 if (m_brush.GetStyle() == wxSTIPPLE)
830 {
831 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetPixmap() );
832 }
833
834 if (IS_HATCH(m_brush.GetStyle()))
835 {
836 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
837 gdk_gc_set_stipple( m_brushGC, hatches[num] );
838 }
903f689b 839}
c801d85f 840
ec758a20 841void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 842{
4bc67cc5
RR
843 // CMB 21/7/98: Added SetBackground. Sets background brush
844 // for Clear() and bg colour for shapes filled with cross-hatch brush
845
846 wxCHECK_RET( Ok(), "invalid window dc" );
46dc76ba 847
265898fd 848 if (m_backgroundBrush == brush) return;
46dc76ba 849
265898fd 850 m_backgroundBrush = brush;
46dc76ba 851
265898fd 852 if (!m_backgroundBrush.Ok()) return;
46dc76ba 853
265898fd
RR
854 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
855 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 856 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 857 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 858 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
46dc76ba 859
265898fd
RR
860 GdkFill fillStyle = GDK_SOLID;
861 switch (m_backgroundBrush.GetStyle())
862 {
863 case wxSOLID:
864 case wxTRANSPARENT:
865 break;
866 default:
867 fillStyle = GDK_STIPPLED;
868 }
46dc76ba 869
265898fd 870 gdk_gc_set_fill( m_bgGC, fillStyle );
46dc76ba 871
265898fd
RR
872 if (m_backgroundBrush.GetStyle() == wxSTIPPLE)
873 {
874 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
875 }
46dc76ba 876
265898fd
RR
877 if (IS_HATCH(m_backgroundBrush.GetStyle()))
878 {
879 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
880 gdk_gc_set_stipple( m_bgGC, hatches[num] );
881 }
903f689b 882}
46dc76ba 883
ec758a20 884void wxWindowDC::SetLogicalFunction( int function )
c801d85f 885{
4bc67cc5
RR
886 wxCHECK_RET( Ok(), "invalid window dc" );
887
265898fd 888 if (m_logicalFunction == function) return;
4bc67cc5 889
265898fd
RR
890 GdkFunction mode = GDK_COPY;
891 switch (function)
892 {
893 case wxXOR: mode = GDK_INVERT; break;
894 case wxINVERT: mode = GDK_INVERT; break;
895 default: break;
896 }
4bc67cc5 897
265898fd
RR
898 m_logicalFunction = function;
899 gdk_gc_set_function( m_penGC, mode );
900 gdk_gc_set_function( m_brushGC, mode );
3bc755fc 901 gdk_gc_set_function( m_textGC, mode );
903f689b 902}
c801d85f 903
ec758a20 904void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 905{
4bc67cc5 906 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 907
265898fd 908 if (m_textForegroundColour == col) return;
c801d85f 909
265898fd
RR
910 m_textForegroundColour = col;
911 if (!m_textForegroundColour.Ok()) return;
c801d85f 912
265898fd
RR
913 m_textForegroundColour.CalcPixel( m_cmap );
914 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
903f689b 915}
c801d85f 916
ec758a20 917void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 918{
4bc67cc5 919 wxCHECK_RET( Ok(), "invalid window dc" );
c801d85f 920
265898fd 921 if (m_textBackgroundColour == col) return;
c801d85f 922
265898fd
RR
923 m_textBackgroundColour = col;
924 if (!m_textBackgroundColour.Ok()) return;
c801d85f 925
265898fd
RR
926 m_textBackgroundColour.CalcPixel( m_cmap );
927 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
903f689b 928}
c801d85f 929
ec758a20 930void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 931{
4bc67cc5
RR
932 wxCHECK_RET( Ok(), "invalid window dc" );
933
265898fd 934 m_backgroundMode = mode;
46dc76ba 935
265898fd
RR
936 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
937 // transparent/solid background mode
4bc67cc5 938
265898fd
RR
939 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
940 {
941 gdk_gc_set_fill( m_brushGC,
942 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
943 }
903f689b 944}
c801d85f 945
ec758a20 946void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 947{
4bc67cc5 948 wxFAIL_MSG( "wxWindowDC::SetPalette not implemented" );
903f689b 949}
c801d85f 950
ec758a20 951void wxWindowDC::SetClippingRegion( long x, long y, long width, long height )
c801d85f 952{
4bc67cc5
RR
953 wxCHECK_RET( Ok(), "invalid window dc" );
954
265898fd 955 wxDC::SetClippingRegion( x, y, width, height );
c801d85f 956
265898fd
RR
957 GdkRectangle rect;
958 rect.x = XLOG2DEV(x);
959 rect.y = YLOG2DEV(y);
960 rect.width = XLOG2DEVREL(width);
961 rect.height = YLOG2DEVREL(height);
962 gdk_gc_set_clip_rectangle( m_penGC, &rect );
963 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
964 gdk_gc_set_clip_rectangle( m_textGC, &rect );
965 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
903f689b 966}
c801d85f 967
463c1fa1
RR
968void wxWindowDC::SetClippingRegion( const wxRegion &region )
969{
4bc67cc5
RR
970 wxCHECK_RET( Ok(), "invalid window dc" );
971
463c1fa1
RR
972 if (region.Empty())
973 {
974 DestroyClippingRegion();
975 return;
976 }
977
978 gdk_gc_set_clip_region( m_penGC, region.GetRegion() );
979 gdk_gc_set_clip_region( m_brushGC, region.GetRegion() );
980 gdk_gc_set_clip_region( m_textGC, region.GetRegion() );
981 gdk_gc_set_clip_region( m_bgGC, region.GetRegion() );
982}
983
4bc67cc5 984void wxWindowDC::DestroyClippingRegion()
c801d85f 985{
4bc67cc5
RR
986 wxCHECK_RET( Ok(), "invalid window dc" );
987
265898fd 988 wxDC::DestroyClippingRegion();
c801d85f 989
265898fd
RR
990 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
991 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
992 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
993 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
903f689b 994}
c801d85f 995
4bc67cc5 996void wxWindowDC::SetUpDC()
c801d85f 997{
265898fd
RR
998 Destroy();
999 m_ok = TRUE;
1000 m_logicalFunction = wxCOPY;
1001 m_penGC = gdk_gc_new( m_window );
1002 m_brushGC = gdk_gc_new( m_window );
1003 m_textGC = gdk_gc_new( m_window );
1004 m_bgGC = gdk_gc_new( m_window );
a802c3a1
RR
1005
1006 wxColour tmp_col( m_textForegroundColour );
1007 m_textForegroundColour = wxNullColour;
1008 SetTextForeground( tmp_col );
1009 tmp_col = m_textBackgroundColour;
1010 m_textBackgroundColour = wxNullColour;
1011 SetTextBackground( tmp_col );
031b2a7b
RR
1012
1013 wxPen tmp_pen( m_pen );
1014 m_pen = wxNullPen;
1015 SetPen( tmp_pen );
1016
1017 wxFont tmp_font( m_font );
1018 m_font = wxNullFont;
1019 SetFont( tmp_font );
1020
1021 wxBrush tmp_brush( m_brush );
1022 m_brush = wxNullBrush;
1023 SetBrush( tmp_brush );
1024
1025 tmp_brush = m_backgroundBrush;
1026 m_backgroundBrush = wxNullBrush;
1027 SetBackground( tmp_brush );
265898fd 1028
265898fd
RR
1029 if (!hatch_bitmap)
1030 {
1031 hatch_bitmap = hatches;
1032 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1033 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1034 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1035 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1036 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1037 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1038 }
903f689b 1039}
c801d85f 1040
4bc67cc5 1041void wxWindowDC::Destroy()
dbf858b5 1042{
265898fd
RR
1043 if (m_penGC) gdk_gc_unref( m_penGC );
1044 m_penGC = (GdkGC*) NULL;
1045 if (m_brushGC) gdk_gc_unref( m_brushGC );
1046 m_brushGC = (GdkGC*) NULL;
1047 if (m_textGC) gdk_gc_unref( m_textGC );
1048 m_textGC = (GdkGC*) NULL;
1049 if (m_bgGC) gdk_gc_unref( m_bgGC );
1050 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
1051}
1052
4bc67cc5 1053GdkWindow *wxWindowDC::GetWindow()
c801d85f 1054{
265898fd 1055 return m_window;
903f689b 1056}
c801d85f
KB
1057
1058// ----------------------------------- spline code ----------------------------------------
1059
1060void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1061 double a3, double b3, double a4, double b4);
4bc67cc5 1062void wx_clear_stack();
c801d85f
KB
1063int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1064 double *y3, double *x4, double *y4);
1065void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1066 double x4, double y4);
1067static bool wx_spline_add_point(double x, double y);
1068static void wx_spline_draw_point_array(wxDC *dc);
1069
1070wxList wx_spline_point_list;
1071
1072#define half(z1, z2) ((z1+z2)/2.0)
1073#define THRESHOLD 5
1074
1075/* iterative version */
1076
1077void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1078 double b4)
1079{
1080 register double xmid, ymid;
1081 double x1, y1, x2, y2, x3, y3, x4, y4;
1082
1083 wx_clear_stack();
1084 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1085
1086 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1087 xmid = (double)half(x2, x3);
1088 ymid = (double)half(y2, y3);
1089 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1090 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1091 wx_spline_add_point( x1, y1 );
1092 wx_spline_add_point( xmid, ymid );
1093 } else {
1094 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1095 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1096 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1097 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1098 }
1099 }
1100}
1101
1102/* utilities used by spline drawing routines */
1103
1104typedef struct wx_spline_stack_struct {
1105 double x1, y1, x2, y2, x3, y3, x4, y4;
1106} Stack;
1107
1108#define SPLINE_STACK_DEPTH 20
1109static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1110static Stack *wx_stack_top;
1111static int wx_stack_count;
1112
4bc67cc5 1113void wx_clear_stack()
c801d85f
KB
1114{
1115 wx_stack_top = wx_spline_stack;
1116 wx_stack_count = 0;
1117}
1118
1119void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1120{
1121 wx_stack_top->x1 = x1;
1122 wx_stack_top->y1 = y1;
1123 wx_stack_top->x2 = x2;
1124 wx_stack_top->y2 = y2;
1125 wx_stack_top->x3 = x3;
1126 wx_stack_top->y3 = y3;
1127 wx_stack_top->x4 = x4;
1128 wx_stack_top->y4 = y4;
1129 wx_stack_top++;
1130 wx_stack_count++;
1131}
1132
1133int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1134 double *x3, double *y3, double *x4, double *y4)
1135{
1136 if (wx_stack_count == 0)
1137 return (0);
1138 wx_stack_top--;
1139 wx_stack_count--;
1140 *x1 = wx_stack_top->x1;
1141 *y1 = wx_stack_top->y1;
1142 *x2 = wx_stack_top->x2;
1143 *y2 = wx_stack_top->y2;
1144 *x3 = wx_stack_top->x3;
1145 *y3 = wx_stack_top->y3;
1146 *x4 = wx_stack_top->x4;
1147 *y4 = wx_stack_top->y4;
1148 return (1);
1149}
1150
1151static bool wx_spline_add_point(double x, double y)
1152{
1153 wxPoint *point = new wxPoint ;
1154 point->x = (int) x;
1155 point->y = (int) y;
1156 wx_spline_point_list.Append((wxObject*)point);
1157 return TRUE;
1158}
1159
1160static void wx_spline_draw_point_array(wxDC *dc)
1161{
1162 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1163 wxNode *node = wx_spline_point_list.First();
1164 while (node)
1165 {
1166 wxPoint *point = (wxPoint *)node->Data();
1167 delete point;
1168 delete node;
1169 node = wx_spline_point_list.First();
1170 }
1171}
1172
ec758a20 1173void wxWindowDC::DrawSpline( wxList *points )
c801d85f 1174{
4bc67cc5
RR
1175 wxCHECK_RET( Ok(), "invalid window dc" );
1176
c801d85f
KB
1177 wxPoint *p;
1178 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1179 double x1, y1, x2, y2;
1180
1181 wxNode *node = points->First();
1182 p = (wxPoint *)node->Data();
1183
1184 x1 = p->x;
1185 y1 = p->y;
1186
1187 node = node->Next();
1188 p = (wxPoint *)node->Data();
1189
1190 x2 = p->x;
1191 y2 = p->y;
1192 cx1 = (double)((x1 + x2) / 2);
1193 cy1 = (double)((y1 + y2) / 2);
1194 cx2 = (double)((cx1 + x2) / 2);
1195 cy2 = (double)((cy1 + y2) / 2);
1196
1197 wx_spline_add_point(x1, y1);
1198
1199 while ((node = node->Next()) != NULL)
1200 {
1201 p = (wxPoint *)node->Data();
1202 x1 = x2;
1203 y1 = y2;
1204 x2 = p->x;
1205 y2 = p->y;
1206 cx4 = (double)(x1 + x2) / 2;
1207 cy4 = (double)(y1 + y2) / 2;
1208 cx3 = (double)(x1 + cx4) / 2;
1209 cy3 = (double)(y1 + cy4) / 2;
1210
1211 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1212
1213 cx1 = cx4;
1214 cy1 = cy4;
1215 cx2 = (double)(cx1 + x2) / 2;
1216 cy2 = (double)(cy1 + y2) / 2;
1217 }
1218
1219 wx_spline_add_point( cx1, cy1 );
1220 wx_spline_add_point( x2, y2 );
1221
1222 wx_spline_draw_point_array( this );
903f689b 1223}
ec758a20
RR
1224
1225
1226//-----------------------------------------------------------------------------
1227// wxPaintDC
1228//-----------------------------------------------------------------------------
1229
1230IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1231
4bc67cc5 1232wxPaintDC::wxPaintDC()
ec758a20
RR
1233 : wxWindowDC()
1234{
1235}
1236
1237wxPaintDC::wxPaintDC( wxWindow *win )
1238 : wxWindowDC( win )
1239{
1240}
1241
1242//-----------------------------------------------------------------------------
1243// wxClientDC
1244//-----------------------------------------------------------------------------
1245
1246IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1247
4bc67cc5 1248wxClientDC::wxClientDC()
ec758a20
RR
1249 : wxWindowDC()
1250{
1251}
1252
1253wxClientDC::wxClientDC( wxWindow *win )
1254 : wxWindowDC( win )
1255{
1256}
1257