]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/dcclient.cpp
serbase.cpp added to the list of files
[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"
503f414e 17#include <math.h> // for floating-point functions
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;
7d5af6fa 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();
7d5af6fa 114
861ccde4 115 wxASSERT_MSG( window, _T("DC needs a window") );
7d5af6fa 116
a2053b27 117 GtkWidget *widget = window->m_wxwindow;
7d5af6fa 118
861ccde4 119 wxASSERT_MSG( widget, _T("DC needs a widget") );
7d5af6fa 120
265898fd 121 m_window = widget->window;
7d5af6fa 122
1e133b7d
RR
123 /* not realized ? */
124 if (!m_window)
125 {
6db90681 126 /* don't report problems */
7d5af6fa
VZ
127 m_ok = TRUE;
128
129 return;
1e133b7d 130 }
7d5af6fa 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 );
7d5af6fa 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) */
7d5af6fa 145
bbbbe360 146 m_owner = window;
903f689b 147}
c801d85f 148
4bc67cc5 149wxWindowDC::~wxWindowDC()
c801d85f 150{
265898fd 151 Destroy();
903f689b 152}
c801d85f 153
7d5af6fa 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") );
7d5af6fa 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) );
7d5af6fa 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") );
7d5af6fa 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 191 if (m_window)
7d5af6fa 192 {
6db90681
RR
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) );
7d5af6fa 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") );
7d5af6fa
VZ
203
204 long xx1 = XLOG2DEV(x1);
265898fd 205 long yy1 = YLOG2DEV(y1);
7d5af6fa 206 long xx2 = XLOG2DEV(x2);
265898fd 207 long yy2 = YLOG2DEV(y2);
7d5af6fa 208 long xxc = XLOG2DEV(xc);
0de9b5b2 209 long yyc = YLOG2DEV(yc);
7d5af6fa 210 double dx = xx1 - xxc;
265898fd
RR
211 double dy = yy1 - yyc;
212 double radius = sqrt(dx*dx+dy*dy);
213 long r = (long)radius;
214 double radius1, radius2;
215
7d5af6fa 216 if (xx1 == xx2 && yy1 == yy2)
265898fd
RR
217 {
218 radius1 = 0.0;
219 radius2 = 360.0;
7d5af6fa
VZ
220 }
221 else
222 if (radius == 0.0)
265898fd
RR
223 {
224 radius1 = radius2 = 0.0;
7d5af6fa
VZ
225 }
226 else
265898fd
RR
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 );
7d5af6fa 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 }
7d5af6fa 248
265898fd
RR
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") );
7d5af6fa
VZ
256
257 long xx = XLOG2DEV(x);
265898fd 258 long yy = YLOG2DEV(y);
7d5af6fa 259 long ww = m_signX * XLOG2DEVREL(width);
265898fd 260 long hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 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; }
7d5af6fa 265
6db90681
RR
266 if (m_window)
267 {
268 long start = long(sa * 64.0);
269 long end = long(ea * 64.0);
7d5af6fa 270
6db90681
RR
271 if (m_brush.GetStyle() != wxTRANSPARENT)
272 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
7d5af6fa 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 }
7d5af6fa 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") );
7d5af6fa 285
6db90681 286 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
265898fd 287 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
7d5af6fa 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") );
7d5af6fa 295
265898fd
RR
296 if (m_pen.GetStyle() == wxTRANSPARENT) return;
297 if (n <= 0) return;
7d5af6fa 298
265898fd 299 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
7d5af6fa 300
265898fd
RR
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);
7d5af6fa
VZ
307
308 if (m_window)
6db90681 309 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
7d5af6fa 310
265898fd
RR
311 CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset );
312 }
903f689b 313}
c801d85f 314
b0e0d661 315void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], long xoffset, long yoffset, int WXUNUSED(fillStyle) )
cf7a7e13 316{
93c5dd39 317 wxCHECK_RET( Ok(), _T("invalid window dc") );
7d5af6fa 318
4bc67cc5 319 if (n <= 0) return;
7d5af6fa 320
265898fd
RR
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);
7d5af6fa 327
265898fd
RR
328 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
329 }
7d5af6fa 330
3417c2cd 331 if ((m_brush.GetStyle() != wxTRANSPARENT) && m_window)
265898fd 332 gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n);
7d5af6fa 333
265898fd 334 // To do: Fillstyle
7d5af6fa 335
6db90681
RR
336 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
337 {
265898fd 338 for (i = 0 ; i < n ; i++)
b0e0d661 339 {
7d5af6fa 340 gdk_draw_line( m_window, m_penGC,
b0e0d661
VZ
341 gdkpoints[i%n].x,
342 gdkpoints[i%n].y,
343 gdkpoints[(i+1)%n].x,
344 gdkpoints[(i+1)%n].y);
265898fd 345 }
6db90681 346 }
7d5af6fa 347
265898fd 348 delete[] gdkpoints;
903f689b 349}
c801d85f 350
b0e0d661 351void wxWindowDC::DoDrawRectangle( long x, long y, long width, long height )
c801d85f 352{
93c5dd39 353 wxCHECK_RET( Ok(), _T("invalid window dc") );
c801d85f 354
265898fd
RR
355 long xx = XLOG2DEV(x);
356 long yy = YLOG2DEV(y);
357 long ww = m_signX * XLOG2DEVREL(width);
358 long hh = m_signY * YLOG2DEVREL(height);
7d5af6fa 359
265898fd
RR
360 // CMB: draw nothing if transformed w or h is 0
361 if (ww == 0 || hh == 0) return;
6f65e337 362
265898fd
RR
363 // CMB: handle -ve width and/or height
364 if (ww < 0) { ww = -ww; xx = xx - ww; }
365 if (hh < 0) { hh = -hh; yy = yy - hh; }
6f65e337 366
6db90681
RR
367 if (m_window)
368 {
369 if (m_brush.GetStyle() != wxTRANSPARENT)
370 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
7d5af6fa 371
6db90681
RR
372 if (m_pen.GetStyle() != wxTRANSPARENT)
373 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
374 }
7d5af6fa 375
265898fd
RR
376 CalcBoundingBox( x, y );
377 CalcBoundingBox( x + width, y + height );
903f689b 378}
c801d85f 379
b0e0d661 380void wxWindowDC::DoDrawRoundedRectangle( long x, long y, long width, long height, double radius )
c801d85f 381{
93c5dd39 382 wxCHECK_RET( Ok(), _T("invalid window dc") );
7d5af6fa 383
265898fd 384 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
7d5af6fa
VZ
385
386 long xx = XLOG2DEV(x);
265898fd 387 long yy = YLOG2DEV(y);
7d5af6fa 388 long ww = m_signX * XLOG2DEVREL(width);
265898fd
RR
389 long hh = m_signY * YLOG2DEVREL(height);
390 long rr = XLOG2DEVREL((long)radius);
391
392 // CMB: handle -ve width and/or height
393 if (ww < 0) { ww = -ww; xx = xx - ww; }
394 if (hh < 0) { hh = -hh; yy = yy - hh; }
395
396 // CMB: if radius is zero use DrawRectangle() instead to avoid
397 // X drawing errors with small radii
398 if (rr == 0)
399 {
400 DrawRectangle( x, y, width, height );
401 return;
402 }
403
404 // CMB: draw nothing if transformed w or h is 0
405 if (ww == 0 || hh == 0) return;
406
407 // CMB: adjust size if outline is drawn otherwise the result is
408 // 1 pixel too wide and high
409 if (m_pen.GetStyle() != wxTRANSPARENT)
410 {
411 ww--;
412 hh--;
413 }
414
6db90681 415 if (m_window)
265898fd 416 {
6db90681
RR
417 // CMB: ensure dd is not larger than rectangle otherwise we
418 // get an hour glass shape
419 long dd = 2 * rr;
420 if (dd > ww) dd = ww;
421 if (dd > hh) dd = hh;
422 rr = dd / 2;
423
424 if (m_brush.GetStyle() != wxTRANSPARENT)
425 {
426 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
427 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
428 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
429 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
430 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
431 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
432 }
7d5af6fa 433
6db90681 434 if (m_pen.GetStyle() != wxTRANSPARENT)
7d5af6fa 435 {
6db90681
RR
436 gdk_draw_line( m_window, m_penGC, xx+rr, yy, xx+ww-rr, yy );
437 gdk_draw_line( m_window, m_penGC, xx+rr, yy+hh, xx+ww-rr, yy+hh );
438 gdk_draw_line( m_window, m_penGC, xx, yy+rr, xx, yy+hh-rr );
439 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr, xx+ww, yy+hh-rr );
440 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
441 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
442 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
443 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
7d5af6fa 444 }
265898fd 445 }
7d5af6fa 446
265898fd
RR
447 // this ignores the radius
448 CalcBoundingBox( x, y );
449 CalcBoundingBox( x + width, y + height );
903f689b 450}
c801d85f 451
b0e0d661 452void wxWindowDC::DoDrawEllipse( long x, long y, long width, long height )
c801d85f 453{
93c5dd39 454 wxCHECK_RET( Ok(), _T("invalid window dc") );
7d5af6fa
VZ
455
456 long xx = XLOG2DEV(x);
265898fd 457 long yy = YLOG2DEV(y);
7d5af6fa 458 long ww = m_signX * XLOG2DEVREL(width);
265898fd 459 long hh = m_signY * YLOG2DEVREL(height);
6f65e337 460
265898fd
RR
461 // CMB: handle -ve width and/or height
462 if (ww < 0) { ww = -ww; xx = xx - ww; }
463 if (hh < 0) { hh = -hh; yy = yy - hh; }
7d5af6fa 464
6db90681
RR
465 if (m_window)
466 {
467 if (m_brush.GetStyle() != wxTRANSPARENT)
468 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
7d5af6fa 469
6db90681
RR
470 if (m_pen.GetStyle() != wxTRANSPARENT)
471 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
472 }
7d5af6fa 473
ed880dd4 474 CalcBoundingBox( x - width, y - height );
265898fd 475 CalcBoundingBox( x + width, y + height );
903f689b 476}
c801d85f 477
b0e0d661 478void wxWindowDC::DoDrawIcon( const wxIcon &icon, long x, long y )
c801d85f 479{
b0e0d661
VZ
480 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
481 DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE );
903f689b 482}
c801d85f 483
b0e0d661
VZ
484void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
485 long x, long y,
486 bool useMask )
4bc67cc5 487{
93c5dd39 488 wxCHECK_RET( Ok(), _T("invalid window dc") );
7d5af6fa 489
b0e0d661 490 wxCHECK_RET( bitmap.Ok(), _T("invalid bitmap") );
7d5af6fa 491
6e13c196 492 /* scale/translate size and position */
7d5af6fa 493
265898fd
RR
494 int xx = XLOG2DEV(x);
495 int yy = YLOG2DEV(y);
7d5af6fa 496
4bc67cc5
RR
497 int w = bitmap.GetWidth();
498 int h = bitmap.GetHeight();
7d5af6fa 499
6453876e
RR
500 CalcBoundingBox( x, y );
501 CalcBoundingBox( x + w, y + h );
7d5af6fa 502
6453876e 503 if (!m_window) return;
7d5af6fa 504
4bc67cc5
RR
505 int ww = XLOG2DEVREL(w);
506 int hh = YLOG2DEVREL(h);
7d5af6fa 507
6e13c196 508 /* scale bitmap if required */
7d5af6fa 509
4bc67cc5 510 wxBitmap use_bitmap;
7d5af6fa 511
4bc67cc5 512 if ((w != ww) || (h != hh))
265898fd 513 {
4bc67cc5 514 wxImage image( bitmap );
b0e0d661 515 image = image.Scale( ww, hh );
7d5af6fa 516
b0e0d661 517 use_bitmap = image.ConvertToBitmap();
265898fd 518 }
4bc67cc5 519 else
265898fd 520 {
4bc67cc5 521 use_bitmap = bitmap;
265898fd 522 }
7d5af6fa 523
6e13c196 524 /* apply mask if any */
7d5af6fa 525
463c1fa1 526 GdkBitmap *mask = (GdkBitmap *) NULL;
4bc67cc5 527 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa
VZ
528
529 if (useMask && mask)
463c1fa1
RR
530 {
531 gdk_gc_set_clip_mask( m_penGC, mask );
532 gdk_gc_set_clip_origin( m_penGC, xx, yy );
533 }
7d5af6fa 534
6e13c196 535 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
7d5af6fa 536
4bc67cc5 537 GdkPixmap *pm = use_bitmap.GetPixmap();
6e13c196
RR
538 if (pm)
539 {
540 gdk_draw_pixmap( m_window, m_penGC, pm, 0, 0, xx, yy, -1, -1 );
541 }
542 else
543 {
544 GdkBitmap *bm = use_bitmap.GetBitmap();
545 if (bm)
546 {
547 gdk_draw_bitmap( m_window, m_penGC, bm, 0, 0, xx, yy, -1, -1 );
b0e0d661 548 }
6e13c196 549 }
7d5af6fa 550
6e13c196 551 /* remove mask again if any */
7d5af6fa
VZ
552
553 if (useMask && mask)
463c1fa1
RR
554 {
555 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
556 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
557 }
463c1fa1
RR
558}
559
b0e0d661
VZ
560bool wxWindowDC::DoBlit( long xdest, long ydest, long width, long height,
561 wxDC *source, long xsrc, long ysrc,
562 int logical_func, bool useMask )
c801d85f 563{
6e13c196
RR
564 /* this is the nth try to get this utterly useless function to
565 work. it now completely ignores the scaling or translation
566 of the source dc, but scales correctly on the target dc and
567 knows about possible mask information in a memory dc. */
568
93c5dd39 569 wxCHECK_MSG( Ok(), FALSE, _T("invalid window dc") );
7d5af6fa 570
93c5dd39 571 wxCHECK_MSG( source, FALSE, _T("invalid source dc") );
7d5af6fa 572
6db90681 573 if (!m_window) return FALSE;
7d5af6fa 574
6e13c196
RR
575 wxClientDC *srcDC = (wxClientDC*)source;
576 wxMemoryDC *memDC = (wxMemoryDC*)source;
7d5af6fa 577
6e13c196 578 bool use_bitmap_method = FALSE;
7d5af6fa 579
6e13c196
RR
580 if (srcDC->m_isMemDC)
581 {
b0e0d661 582 if (!memDC->m_selected.Ok()) return FALSE;
7d5af6fa 583
6e13c196 584 /* we use the "XCopyArea" way to copy a memory dc into
b0e0d661
VZ
585 y different window if the memory dc BOTH
586 a) doesn't have any mask or its mask isn't used
587 b) it is clipped
588 c) is not 1-bit */
7d5af6fa 589
f234c60c 590 if (useMask && (memDC->m_selected.GetMask()))
b0e0d661
VZ
591 {
592 /* we HAVE TO use the direct way for memory dcs
593 that have mask since the XCopyArea doesn't know
594 about masks */
595 use_bitmap_method = TRUE;
596 }
597 else if (memDC->m_selected.GetDepth() == 1)
598 {
599 /* we HAVE TO use the direct way for memory dcs
600 that are bitmaps because XCopyArea doesn't cope
601 with different bit depths */
602 use_bitmap_method = TRUE;
603 }
604 else if ((xsrc == 0) && (ysrc == 0) &&
605 (width == memDC->m_selected.GetWidth()) &&
606 (height == memDC->m_selected.GetHeight()))
607 {
7d5af6fa
VZ
608 /* we SHOULD use the direct way if all of the bitmap
609 in the memory dc is copied in which case XCopyArea
610 wouldn't be able able to boost performace by reducing
b0e0d661
VZ
611 the area to be scaled */
612 use_bitmap_method = TRUE;
613 }
614 else
615 {
616 use_bitmap_method = FALSE;
617 }
6e13c196 618 }
7d5af6fa 619
265898fd
RR
620 CalcBoundingBox( xdest, ydest );
621 CalcBoundingBox( xdest + width, ydest + height );
7d5af6fa 622
4bc67cc5
RR
623 int old_logical_func = m_logicalFunction;
624 SetLogicalFunction( logical_func );
7d5af6fa 625
6e13c196 626 if (use_bitmap_method)
6f65e337 627 {
6e13c196 628 /* scale/translate bitmap size */
7d5af6fa 629
b0e0d661
VZ
630 long bm_width = memDC->m_selected.GetWidth();
631 long bm_height = memDC->m_selected.GetHeight();
7d5af6fa 632
b0e0d661
VZ
633 long bm_ww = XLOG2DEVREL( bm_width );
634 long bm_hh = YLOG2DEVREL( bm_height );
7d5af6fa 635
6e13c196 636 /* scale bitmap if required */
7d5af6fa 637
6e13c196 638 wxBitmap use_bitmap;
7d5af6fa 639
6e13c196
RR
640 if ((bm_width != bm_ww) || (bm_height != bm_hh))
641 {
642 wxImage image( memDC->m_selected );
b0e0d661 643 image = image.Scale( bm_ww, bm_hh );
7d5af6fa 644
b0e0d661 645 use_bitmap = image.ConvertToBitmap();
6e13c196
RR
646 }
647 else
e23d0e95 648 {
6e13c196
RR
649 use_bitmap = memDC->m_selected;
650 }
7d5af6fa 651
6e13c196 652 /* scale/translate size and position */
7d5af6fa 653
6e13c196
RR
654 long xx = XLOG2DEV(xdest);
655 long yy = YLOG2DEV(ydest);
7d5af6fa 656
b0e0d661
VZ
657 long ww = XLOG2DEVREL(width);
658 long hh = YLOG2DEVREL(height);
7d5af6fa 659
6e13c196 660 /* apply mask if any */
7d5af6fa 661
6e13c196
RR
662 GdkBitmap *mask = (GdkBitmap *) NULL;
663 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
7d5af6fa
VZ
664
665 if (useMask && mask)
6e13c196
RR
666 {
667 gdk_gc_set_clip_mask( m_penGC, mask );
668 gdk_gc_set_clip_origin( m_penGC, xx, yy );
e23d0e95 669 }
7d5af6fa 670
6e13c196 671 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
7d5af6fa 672
6e13c196
RR
673 GdkPixmap *pm = use_bitmap.GetPixmap();
674 if (pm)
265898fd 675 {
f234c60c 676 gdk_draw_pixmap( m_window, m_penGC, pm, xsrc, ysrc, xx, yy, ww, hh );
6e13c196
RR
677 }
678 else
679 {
680 GdkBitmap *bm = use_bitmap.GetBitmap();
681 if (bm)
682 {
b0e0d661
VZ
683 /* we use the textGC here because blitting a bitmap is done
684 using the current text colour */
f234c60c 685 gdk_draw_bitmap( m_window, m_textGC, bm, xsrc, ysrc, xx, yy, ww, hh );
b0e0d661 686 }
6e13c196 687 }
7d5af6fa 688
6e13c196 689 /* remove mask again if any */
7d5af6fa
VZ
690
691 if (useMask && mask)
6e13c196
RR
692 {
693 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
694 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
265898fd 695 }
6f65e337 696 }
6e13c196
RR
697 else /* use_bitmap_method */
698 {
699 /* scale/translate size and position */
7d5af6fa 700
6e13c196
RR
701 long xx = XLOG2DEV(xdest);
702 long yy = YLOG2DEV(ydest);
7d5af6fa 703
b0e0d661
VZ
704 long ww = XLOG2DEVREL(width);
705 long hh = YLOG2DEVREL(height);
7d5af6fa 706
6e13c196 707 if ((width != ww) || (height != hh))
b0e0d661
VZ
708 {
709 /* draw source window into a bitmap as we cannot scale
710 a window in contrast to a bitmap. this would actually
711 work with memory dcs as well, but we'd lose the mask
712 information and waste one step in this process since
713 a memory already has a bitmap. all this is slightly
714 inefficient as we could take an XImage directly from
715 an X window, but we'd then also have to care that
716 the window is not outside the screen (in which case
717 we'd get a BadMatch or what not).
718 Is a double XGetImage and combined XGetPixel and
719 XPutPixel really faster? I'm not sure. look at wxXt
720 for a different implementation of the same problem. */
7d5af6fa 721
b0e0d661 722 wxBitmap bitmap( width, height );
7d5af6fa 723 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
6e13c196 724 srcDC->GetWindow(),
b0e0d661 725 xsrc, ysrc, width, height );
7d5af6fa 726
b0e0d661 727 /* scale image */
7d5af6fa 728
6e13c196 729 wxImage image( bitmap );
b0e0d661 730 image = image.Scale( ww, hh );
7d5af6fa 731
b0e0d661 732 /* convert to bitmap */
7d5af6fa 733
b0e0d661 734 bitmap = image.ConvertToBitmap();
7d5af6fa 735
b0e0d661 736 /* draw scaled bitmap */
7d5af6fa 737
6e13c196 738 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
7d5af6fa 739
b0e0d661
VZ
740 }
741 else
742 {
743 /* no scaling and not a memory dc with a mask either */
7d5af6fa 744
6e13c196
RR
745 gdk_window_copy_area( m_window, m_penGC, xx, yy,
746 srcDC->GetWindow(),
747 xsrc, ysrc, width, height );
b0e0d661 748 }
6e13c196 749 }
c801d85f 750
4bc67cc5
RR
751 SetLogicalFunction( old_logical_func );
752 return TRUE;
903f689b 753}
c801d85f 754
b0e0d661 755void wxWindowDC::DoDrawText( const wxString &text, long x, long y )
c801d85f 756{
93c5dd39 757 wxCHECK_RET( Ok(), _T("invalid window dc") );
18a2fa37 758
6db90681 759 if (!m_window) return;
7d5af6fa 760
265898fd 761 GdkFont *font = m_font.GetInternalFont( m_scaleY );
6f65e337 762
265898fd
RR
763 x = XLOG2DEV(x);
764 y = YLOG2DEV(y);
18a2fa37 765
bbbbe360 766 /* CMB 21/5/98: draw text background if mode is wxSOLID */
265898fd
RR
767 if (m_backgroundMode == wxSOLID)
768 {
93c5dd39 769 long width = gdk_string_width( font, text.mbc_str() );
265898fd
RR
770 long height = font->ascent + font->descent;
771 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
772 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
773 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
774 }
93c5dd39 775 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
18a2fa37 776
bbbbe360
RR
777 /* CMB 17/7/98: simple underline: ignores scaling and underlying
778 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
779 properties (see wxXt implementation) */
265898fd
RR
780 if (m_font.GetUnderlined())
781 {
93c5dd39 782 long width = gdk_string_width( font, text.mbc_str() );
265898fd
RR
783 long ul_y = y + font->ascent;
784 if (font->descent > 0) ul_y++;
785 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
786 }
7d5af6fa 787
265898fd
RR
788 long w, h;
789 GetTextExtent (text, &w, &h);
790 CalcBoundingBox (x + w, y + h);
791 CalcBoundingBox (x, y);
903f689b 792}
c801d85f 793
ec758a20 794void wxWindowDC::GetTextExtent( const wxString &string, long *width, long *height,
b0e0d661
VZ
795 long *descent, long *externalLeading,
796 wxFont *theFont ) const
c801d85f 797{
265898fd
RR
798 wxFont fontToUse = m_font;
799 if (theFont) fontToUse = *theFont;
7d5af6fa 800
265898fd 801 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
93c5dd39 802 if (width) (*width) = long(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
265898fd
RR
803 if (height) (*height) = long((font->ascent + font->descent) / m_scaleY);
804 if (descent) (*descent) = long(font->descent / m_scaleY);
805 if (externalLeading) (*externalLeading) = 0; // ??
903f689b 806}
c801d85f 807
b0e0d661 808long wxWindowDC::GetCharWidth() const
c801d85f 809{
265898fd
RR
810 GdkFont *font = m_font.GetInternalFont( m_scaleY );
811 return long(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 812}
c801d85f 813
b0e0d661 814long wxWindowDC::GetCharHeight() const
c801d85f 815{
265898fd
RR
816 GdkFont *font = m_font.GetInternalFont( m_scaleY );
817 return long((font->ascent + font->descent) / m_scaleY);
903f689b 818}
c801d85f 819
4bc67cc5 820void wxWindowDC::Clear()
c801d85f 821{
93c5dd39 822 wxCHECK_RET( Ok(), _T("invalid window dc") );
7d5af6fa 823
6db90681 824 if (!m_window) return;
7d5af6fa 825
f234c60c
RR
826 /* - we either are a memory dc or have a window as the
827 owner. anything else shouldn't happen.
828 - we don't use gdk_window_clear() as we don't set
829 the window's background colour anymore. it is too
830 much pain to keep the DC's and the window's back-
831 ground colour in synch. */
7d5af6fa 832
f234c60c 833 if (m_owner)
265898fd 834 {
f234c60c
RR
835 int width,height;
836 m_owner->GetSize( &width, &height );
837 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 838 return;
265898fd 839 }
f234c60c
RR
840
841 if (m_isMemDC)
265898fd
RR
842 {
843 int width,height;
844 GetSize( &width, &height );
845 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 846 return;
265898fd 847 }
903f689b 848}
c801d85f 849
ec758a20 850void wxWindowDC::SetFont( const wxFont &font )
c801d85f 851{
265898fd 852 m_font = font;
903f689b 853}
c801d85f 854
ec758a20 855void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 856{
93c5dd39 857 wxCHECK_RET( Ok(), _T("invalid window dc") );
7d5af6fa 858
265898fd 859 if (m_pen == pen) return;
7d5af6fa 860
265898fd 861 m_pen = pen;
7d5af6fa 862
265898fd 863 if (!m_pen.Ok()) return;
7d5af6fa 864
6db90681 865 if (!m_window) return;
7d5af6fa 866
265898fd 867 gint width = m_pen.GetWidth();
265898fd
RR
868 if (width <= 0)
869 {
112c5086 870 // CMB: if width is non-zero scale it with the dc
265898fd
RR
871 width = 1;
872 }
873 else
874 {
875 // X doesn't allow different width in x and y and so we take
876 // the average
503f414e
VZ
877 double w = 0.5 +
878 ( fabs((double) XLOG2DEVREL(width)) +
879 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
265898fd
RR
880 width = (int)w;
881 }
7d5af6fa
VZ
882
883 static const char dotted[] = {1, 1};
884 static const char short_dashed[] = {2, 2};
885 static const char long_dashed[] = {2, 4};
886 static const char dotted_dashed[] = {3, 3, 1, 3};
887
112c5086
RR
888 // We express dash pattern in pen width unit, so we are
889 // independent of zoom factor and so on...
890 int req_nb_dash;
891 const char *req_dash;
7d5af6fa 892
265898fd
RR
893 GdkLineStyle lineStyle = GDK_LINE_SOLID;
894 switch (m_pen.GetStyle())
895 {
112c5086 896 case wxUSER_DASH:
7d5af6fa
VZ
897 {
898 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
899 req_nb_dash = m_pen.GetDashCount();
900 req_dash = m_pen.GetDash();
901 break;
7d5af6fa
VZ
902 }
903 case wxDOT:
904 {
905 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
906 req_nb_dash = 2;
907 req_dash = dotted;
7d5af6fa
VZ
908 break;
909 }
910 case wxLONG_DASH:
911 {
912 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
913 req_nb_dash = 2;
914 req_dash = long_dashed;
7d5af6fa
VZ
915 break;
916 }
917 case wxSHORT_DASH:
918 {
919 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
920 req_nb_dash = 2;
921 req_dash = short_dashed;
7d5af6fa
VZ
922 break;
923 }
924 case wxDOT_DASH:
925 {
926// lineStyle = GDK_LINE_DOUBLE_DASH;
927 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
928 req_nb_dash = 4;
929 req_dash = dotted_dashed;
7d5af6fa
VZ
930 break;
931 }
932
933 case wxTRANSPARENT:
934 case wxSTIPPLE:
935 case wxSOLID:
936 default:
937 {
938 lineStyle = GDK_LINE_SOLID;
112c5086
RR
939 req_dash = (wxDash*)NULL;
940 req_nb_dash = 0;
7d5af6fa
VZ
941 break;
942 }
265898fd 943 }
7d5af6fa 944
953704c1 945#if (GTK_MINOR_VERSION > 0)
112c5086
RR
946 if (req_dash && req_nb_dash)
947 {
948 char *real_req_dash = new char[req_nb_dash];
949 if (real_req_dash)
950 {
951 for (int i = 0; i < req_nb_dash; i++)
952 real_req_dash[i] = req_dash[i] * width;
7d5af6fa 953 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
112c5086
RR
954 delete[] real_req_dash;
955 }
956 else
957 {
958 // No Memory. We use non-scaled dash pattern...
7d5af6fa 959 gdk_gc_set_dashes( m_penGC, 0, (char*)req_dash, req_nb_dash );
112c5086
RR
960 }
961 }
953704c1 962#endif
7d5af6fa 963
265898fd
RR
964 GdkCapStyle capStyle = GDK_CAP_ROUND;
965 switch (m_pen.GetCap())
966 {
967 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
968 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
969 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
970 }
7d5af6fa 971
265898fd
RR
972 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
973 switch (m_pen.GetJoin())
974 {
975 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
976 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
977 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
978 }
7d5af6fa 979
265898fd 980 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
7d5af6fa 981
265898fd
RR
982 m_pen.GetColour().CalcPixel( m_cmap );
983 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 984}
c801d85f 985
ec758a20 986void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 987{
93c5dd39 988 wxCHECK_RET( Ok(), _T("invalid window dc") );
7d5af6fa 989
265898fd 990 if (m_brush == brush) return;
7d5af6fa 991
265898fd 992 m_brush = brush;
7d5af6fa 993
265898fd 994 if (!m_brush.Ok()) return;
7d5af6fa 995
6db90681 996 if (!m_window) return;
7d5af6fa 997
265898fd
RR
998 m_brush.GetColour().CalcPixel( m_cmap );
999 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
7d5af6fa 1000
956dbab1 1001 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
7d5af6fa 1002
4fcd73bd 1003 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 1004 {
4fcd73bd 1005 if (m_brush.GetStipple()->GetPixmap())
7d5af6fa 1006 {
956dbab1 1007 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 1008 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
7d5af6fa 1009 }
b0e0d661 1010 else
7d5af6fa 1011 {
956dbab1 1012 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 1013 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
7d5af6fa 1014 }
265898fd 1015 }
7d5af6fa 1016
265898fd
RR
1017 if (IS_HATCH(m_brush.GetStyle()))
1018 {
956dbab1 1019 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
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 */
7d5af6fa 1029
93c5dd39 1030 wxCHECK_RET( Ok(), _T("invalid window dc") );
7d5af6fa 1031
265898fd 1032 if (m_backgroundBrush == brush) return;
7d5af6fa 1033
265898fd 1034 m_backgroundBrush = brush;
7d5af6fa 1035
265898fd 1036 if (!m_backgroundBrush.Ok()) return;
7d5af6fa 1037
6db90681 1038 if (!m_window) return;
7d5af6fa 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() );
3417c2cd
RR
1045
1046 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
7d5af6fa 1047
cd25b18c 1048 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 1049 {
fd128b0c 1050 if (m_backgroundBrush.GetStipple()->GetPixmap())
7d5af6fa 1051 {
3417c2cd 1052 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 1053 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
7d5af6fa 1054 }
cd25b18c 1055 else
7d5af6fa 1056 {
3417c2cd 1057 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 1058 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
7d5af6fa 1059 }
265898fd 1060 }
7d5af6fa 1061
265898fd
RR
1062 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1063 {
3417c2cd 1064 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
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") );
7d5af6fa 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;
7d5af6fa 1087 case wxSRC_AND:
3c679789 1088 case wxAND: mode = GDK_AND; break;
7d5af6fa 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;
7d5af6fa
VZ
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 1098 default:
7d5af6fa
VZ
1099 {
1100 wxFAIL_MSG( _T("unsupported logical function") );
1101 break;
1102 }
265898fd 1103 }
7d5af6fa 1104
265898fd 1105 m_logicalFunction = function;
7d5af6fa 1106
6db90681 1107 if (!m_window) return;
7d5af6fa 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") );
7d5af6fa 1117
265898fd 1118 if (m_textForegroundColour == col) return;
7d5af6fa 1119
265898fd
RR
1120 m_textForegroundColour = col;
1121 if (!m_textForegroundColour.Ok()) return;
7d5af6fa 1122
6db90681 1123 if (!m_window) return;
7d5af6fa 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") );
7d5af6fa 1132
265898fd 1133 if (m_textBackgroundColour == col) return;
7d5af6fa 1134
265898fd
RR
1135 m_textBackgroundColour = col;
1136 if (!m_textBackgroundColour.Ok()) return;
7d5af6fa 1137
6db90681 1138 if (!m_window) return;
7d5af6fa 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") );
7d5af6fa 1147
265898fd 1148 m_backgroundMode = mode;
46dc76ba 1149
6db90681 1150 if (!m_window) return;
7d5af6fa 1151
265898fd
RR
1152 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1153 // transparent/solid background mode
7d5af6fa 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") );
7d5af6fa 1170
089e55d6 1171 wxDC::DoSetClippingRegion( x, y, width, height );
7d5af6fa 1172
6db90681 1173 if (!m_window) return;
7d5af6fa 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") );
7d5af6fa 1189
463c1fa1
RR
1190 if (region.Empty())
1191 {
1192 DestroyClippingRegion();
1193 return;
1194 }
7d5af6fa 1195
6db90681 1196 if (!m_window) return;
7d5af6fa 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") );
7d5af6fa 1207
265898fd 1208 wxDC::DestroyClippingRegion();
7d5af6fa 1209
6db90681 1210 if (!m_window) return;
7d5af6fa 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 );
7d5af6fa 1227
a802c3a1
RR
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 );
7d5af6fa 1234
031b2a7b
RR
1235 wxPen tmp_pen( m_pen );
1236 m_pen = wxNullPen;
1237 SetPen( tmp_pen );
7d5af6fa 1238
031b2a7b
RR
1239 wxFont tmp_font( m_font );
1240 m_font = wxNullFont;
1241 SetFont( tmp_font );
7d5af6fa 1242
031b2a7b
RR
1243 wxBrush tmp_brush( m_brush );
1244 m_brush = wxNullBrush;
1245 SetBrush( tmp_brush );
7d5af6fa 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;
7d5af6fa
VZ
1256
1257 if (!hatch_bitmap)
265898fd
RR
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") );
7d5af6fa 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