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