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