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