]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dcclient.cpp
PCX handler now working for reading (8bit and 24bit images).
[wxWidgets.git] / src / gtk / dcclient.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: dcclient.cpp
3// Purpose:
4// Author: Robert Roebling
6f65e337 5// RCS-ID: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
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);
3417c2cd 307
6db90681
RR
308 if (m_window)
309 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
b0e0d661 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") );
cf7a7e13 318
4bc67cc5 319 if (n <= 0) return;
265898fd
RR
320
321 GdkPoint *gdkpoints = new GdkPoint[n+1];
322 int i;
323 for (i = 0 ; i < n ; i++)
324 {
325 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
326 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
b0e0d661 327
265898fd
RR
328 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
329 }
330
3417c2cd 331 if ((m_brush.GetStyle() != wxTRANSPARENT) && m_window)
265898fd
RR
332 gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n);
333
334 // To do: Fillstyle
335
6db90681
RR
336 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
337 {
265898fd 338 for (i = 0 ; i < n ; i++)
b0e0d661 339 {
265898fd 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 }
b0e0d661 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);
c801d85f 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 );
c801d85f 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 }
265898fd
RR
375
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") );
265898fd
RR
383
384 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
385
386 long xx = XLOG2DEV(x);
387 long yy = YLOG2DEV(y);
388 long ww = m_signX * XLOG2DEVREL(width);
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 }
265898fd 433
6db90681
RR
434 if (m_pen.GetStyle() != wxTRANSPARENT)
435 {
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 );
444 }
265898fd
RR
445 }
446
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") );
c801d85f 455
265898fd
RR
456 long xx = XLOG2DEV(x);
457 long yy = YLOG2DEV(y);
458 long ww = m_signX * XLOG2DEVREL(width);
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; }
c801d85f 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 );
c801d85f 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 }
b0e0d661 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") );
c801d85f 489
b0e0d661 490 wxCHECK_RET( bitmap.Ok(), _T("invalid bitmap") );
6e13c196
RR
491
492 /* scale/translate size and position */
c801d85f 493
265898fd
RR
494 int xx = XLOG2DEV(x);
495 int yy = YLOG2DEV(y);
c801d85f 496
4bc67cc5
RR
497 int w = bitmap.GetWidth();
498 int h = bitmap.GetHeight();
c801d85f 499
6453876e
RR
500 CalcBoundingBox( x, y );
501 CalcBoundingBox( x + w, y + h );
502
503 if (!m_window) return;
504
4bc67cc5
RR
505 int ww = XLOG2DEVREL(w);
506 int hh = YLOG2DEVREL(h);
507
6e13c196
RR
508 /* scale bitmap if required */
509
4bc67cc5
RR
510 wxBitmap use_bitmap;
511
512 if ((w != ww) || (h != hh))
265898fd 513 {
4bc67cc5 514 wxImage image( bitmap );
b0e0d661
VZ
515 image = image.Scale( ww, hh );
516
517 use_bitmap = image.ConvertToBitmap();
265898fd 518 }
4bc67cc5 519 else
265898fd 520 {
4bc67cc5 521 use_bitmap = bitmap;
265898fd
RR
522 }
523
6e13c196
RR
524 /* apply mask if any */
525
463c1fa1 526 GdkBitmap *mask = (GdkBitmap *) NULL;
4bc67cc5 527 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
463c1fa1
RR
528
529 if (useMask && mask)
530 {
531 gdk_gc_set_clip_mask( m_penGC, mask );
532 gdk_gc_set_clip_origin( m_penGC, xx, yy );
533 }
534
6e13c196
RR
535 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
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
RR
549 }
550
551 /* remove mask again if any */
552
463c1fa1
RR
553 if (useMask && mask)
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") );
e23d0e95 570
93c5dd39 571 wxCHECK_MSG( source, FALSE, _T("invalid source dc") );
6e13c196 572
6db90681
RR
573 if (!m_window) return FALSE;
574
6e13c196
RR
575 wxClientDC *srcDC = (wxClientDC*)source;
576 wxMemoryDC *memDC = (wxMemoryDC*)source;
577
578 bool use_bitmap_method = FALSE;
579
580 if (srcDC->m_isMemDC)
581 {
b0e0d661
VZ
582 if (!memDC->m_selected.Ok()) return FALSE;
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 */
6e13c196 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 {
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
611 the area to be scaled */
612 use_bitmap_method = TRUE;
613 }
614 else
615 {
616 use_bitmap_method = FALSE;
617 }
6e13c196
RR
618 }
619
265898fd
RR
620 CalcBoundingBox( xdest, ydest );
621 CalcBoundingBox( xdest + width, ydest + height );
622
4bc67cc5
RR
623 int old_logical_func = m_logicalFunction;
624 SetLogicalFunction( logical_func );
625
6e13c196 626 if (use_bitmap_method)
6f65e337 627 {
6e13c196
RR
628 /* scale/translate bitmap size */
629
b0e0d661
VZ
630 long bm_width = memDC->m_selected.GetWidth();
631 long bm_height = memDC->m_selected.GetHeight();
632
633 long bm_ww = XLOG2DEVREL( bm_width );
634 long bm_hh = YLOG2DEVREL( bm_height );
635
6e13c196
RR
636 /* scale bitmap if required */
637
638 wxBitmap use_bitmap;
639
640 if ((bm_width != bm_ww) || (bm_height != bm_hh))
641 {
642 wxImage image( memDC->m_selected );
b0e0d661
VZ
643 image = image.Scale( bm_ww, bm_hh );
644
645 use_bitmap = image.ConvertToBitmap();
6e13c196
RR
646 }
647 else
e23d0e95 648 {
6e13c196
RR
649 use_bitmap = memDC->m_selected;
650 }
b0e0d661 651
6e13c196
RR
652 /* scale/translate size and position */
653
654 long xx = XLOG2DEV(xdest);
655 long yy = YLOG2DEV(ydest);
b0e0d661
VZ
656
657 long ww = XLOG2DEVREL(width);
658 long hh = YLOG2DEVREL(height);
659
6e13c196 660 /* apply mask if any */
e23d0e95 661
6e13c196
RR
662 GdkBitmap *mask = (GdkBitmap *) NULL;
663 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
e23d0e95 664
6e13c196
RR
665 if (useMask && mask)
666 {
667 gdk_gc_set_clip_mask( m_penGC, mask );
668 gdk_gc_set_clip_origin( m_penGC, xx, yy );
e23d0e95 669 }
b0e0d661 670
6e13c196
RR
671 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
672
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 }
df875e59 688
6e13c196 689 /* remove mask again if any */
df875e59 690
6e13c196
RR
691 if (useMask && mask)
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 */
700
701 long xx = XLOG2DEV(xdest);
702 long yy = YLOG2DEV(ydest);
b0e0d661
VZ
703
704 long ww = XLOG2DEVREL(width);
705 long hh = YLOG2DEVREL(height);
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. */
6e13c196 721
b0e0d661
VZ
722 wxBitmap bitmap( width, height );
723 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
6e13c196 724 srcDC->GetWindow(),
b0e0d661
VZ
725 xsrc, ysrc, width, height );
726
727 /* scale image */
728
6e13c196 729 wxImage image( bitmap );
b0e0d661
VZ
730 image = image.Scale( ww, hh );
731
732 /* convert to bitmap */
733
734 bitmap = image.ConvertToBitmap();
735
736 /* draw scaled bitmap */
737
6e13c196 738 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
b0e0d661
VZ
739
740 }
741 else
742 {
743 /* no scaling and not a memory dc with a mask either */
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
RR
759 if (!m_window) return;
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 }
787
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;
c33c4050 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") );
c801d85f 823
6db90681
RR
824 if (!m_window) return;
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. */
832
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") );
4bc67cc5 858
265898fd
RR
859 if (m_pen == pen) return;
860
861 m_pen = pen;
862
863 if (!m_pen.Ok()) return;
864
6db90681
RR
865 if (!m_window) return;
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
877 double w = 0.5 + (abs(XLOG2DEVREL(width)) + abs(YLOG2DEVREL(width))) / 2.0;
878 width = (int)w;
879 }
880
112c5086
RR
881 const static char dotted[] = {1, 1};
882 const static char short_dashed[] = {2, 2};
883 const static char long_dashed[] = {2, 4};
884 const static char dotted_dashed[] = {3, 3, 1, 3};
885
886 // We express dash pattern in pen width unit, so we are
887 // independent of zoom factor and so on...
888 int req_nb_dash;
889 const char *req_dash;
890
265898fd
RR
891 GdkLineStyle lineStyle = GDK_LINE_SOLID;
892 switch (m_pen.GetStyle())
893 {
112c5086
RR
894 case wxUSER_DASH:
895 {
896 lineStyle = GDK_LINE_ON_OFF_DASH;
897 req_nb_dash = m_pen.GetDashCount();
898 req_dash = m_pen.GetDash();
899 break;
900 }
901 case wxDOT:
902 {
903 lineStyle = GDK_LINE_ON_OFF_DASH;
904 req_nb_dash = 2;
905 req_dash = dotted;
906 break;
907 }
908 case wxLONG_DASH:
909 {
910 lineStyle = GDK_LINE_ON_OFF_DASH;
911 req_nb_dash = 2;
912 req_dash = long_dashed;
913 break;
914 }
915 case wxSHORT_DASH:
916 {
917 lineStyle = GDK_LINE_ON_OFF_DASH;
918 req_nb_dash = 2;
919 req_dash = short_dashed;
920 break;
921 }
922 case wxDOT_DASH:
923 {
924// lineStyle = GDK_LINE_DOUBLE_DASH;
925 lineStyle = GDK_LINE_ON_OFF_DASH;
926 req_nb_dash = 4;
927 req_dash = dotted_dashed;
928 break;
929 }
930
931 case wxTRANSPARENT:
932 case wxSTIPPLE:
933 case wxSOLID:
934 default:
935 {
936 lineStyle = GDK_LINE_SOLID;
937 req_dash = (wxDash*)NULL;
938 req_nb_dash = 0;
939 break;
940 }
265898fd
RR
941 }
942
953704c1 943#if (GTK_MINOR_VERSION > 0)
112c5086
RR
944 if (req_dash && req_nb_dash)
945 {
946 char *real_req_dash = new char[req_nb_dash];
947 if (real_req_dash)
948 {
949 for (int i = 0; i < req_nb_dash; i++)
950 real_req_dash[i] = req_dash[i] * width;
951 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
952 delete[] real_req_dash;
953 }
954 else
955 {
956 // No Memory. We use non-scaled dash pattern...
957 gdk_gc_set_dashes( m_penGC, 0, (char*)req_dash, req_nb_dash );
958 }
959 }
953704c1 960#endif
112c5086 961
265898fd
RR
962 GdkCapStyle capStyle = GDK_CAP_ROUND;
963 switch (m_pen.GetCap())
964 {
965 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
966 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
967 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
968 }
969
970 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
971 switch (m_pen.GetJoin())
972 {
973 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
974 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
975 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
976 }
977
978 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
979
980 m_pen.GetColour().CalcPixel( m_cmap );
981 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 982}
c801d85f 983
ec758a20 984void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 985{
93c5dd39 986 wxCHECK_RET( Ok(), _T("invalid window dc") );
c801d85f 987
265898fd 988 if (m_brush == brush) return;
c801d85f 989
265898fd 990 m_brush = brush;
c801d85f 991
265898fd 992 if (!m_brush.Ok()) return;
c801d85f 993
6db90681
RR
994 if (!m_window) return;
995
265898fd
RR
996 m_brush.GetColour().CalcPixel( m_cmap );
997 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
c801d85f 998
956dbab1 999 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
c801d85f 1000
4fcd73bd 1001 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 1002 {
4fcd73bd 1003 if (m_brush.GetStipple()->GetPixmap())
956dbab1
RR
1004 {
1005 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 1006 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
956dbab1 1007 }
b0e0d661 1008 else
956dbab1
RR
1009 {
1010 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 1011 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
956dbab1 1012 }
265898fd
RR
1013 }
1014
1015 if (IS_HATCH(m_brush.GetStyle()))
1016 {
956dbab1 1017 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
1018 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1019 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1020 }
903f689b 1021}
c801d85f 1022
ec758a20 1023void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 1024{
bbbbe360
RR
1025 /* CMB 21/7/98: Added SetBackground. Sets background brush
1026 * for Clear() and bg colour for shapes filled with cross-hatch brush */
4bc67cc5 1027
93c5dd39 1028 wxCHECK_RET( Ok(), _T("invalid window dc") );
46dc76ba 1029
265898fd 1030 if (m_backgroundBrush == brush) return;
46dc76ba 1031
265898fd 1032 m_backgroundBrush = brush;
46dc76ba 1033
265898fd 1034 if (!m_backgroundBrush.Ok()) return;
46dc76ba 1035
6db90681
RR
1036 if (!m_window) return;
1037
265898fd
RR
1038 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1039 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 1040 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 1041 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 1042 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
3417c2cd
RR
1043
1044 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
46dc76ba 1045
cd25b18c 1046 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 1047 {
fd128b0c 1048 if (m_backgroundBrush.GetStipple()->GetPixmap())
3417c2cd
RR
1049 {
1050 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 1051 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
3417c2cd 1052 }
cd25b18c 1053 else
3417c2cd
RR
1054 {
1055 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 1056 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
3417c2cd 1057 }
265898fd 1058 }
46dc76ba 1059
265898fd
RR
1060 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1061 {
3417c2cd 1062 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
1063 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1064 gdk_gc_set_stipple( m_bgGC, hatches[num] );
bbbbe360 1065 }
903f689b 1066}
46dc76ba 1067
ec758a20 1068void wxWindowDC::SetLogicalFunction( int function )
c801d85f 1069{
93c5dd39 1070 wxCHECK_RET( Ok(), _T("invalid window dc") );
4bc67cc5 1071
265898fd 1072 if (m_logicalFunction == function) return;
01eaf507 1073
265898fd
RR
1074 GdkFunction mode = GDK_COPY;
1075 switch (function)
1076 {
3c679789
RR
1077 case wxXOR: mode = GDK_XOR; break;
1078 case wxINVERT: mode = GDK_INVERT; break;
01eaf507 1079#if (GTK_MINOR_VERSION > 0)
3c679789
RR
1080 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1081 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1082 case wxCLEAR: mode = GDK_CLEAR; break;
1083 case wxSET: mode = GDK_SET; break;
1084 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
01eaf507 1085 case wxSRC_AND:
3c679789 1086 case wxAND: mode = GDK_AND; break;
01eaf507 1087 case wxSRC_OR:
3c679789
RR
1088 case wxOR: mode = GDK_OR; break;
1089 case wxEQUIV: mode = GDK_EQUIV; break;
1090 case wxNAND: mode = GDK_NAND; break;
1091 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
01eaf507
RR
1092 case wxCOPY: mode = GDK_COPY; break;
1093 case wxNO_OP: mode = GDK_NOOP; break;
1094 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
c96faa7c 1095#endif
01eaf507
RR
1096 default:
1097 {
861ccde4 1098 wxFAIL_MSG( _T("unsupported logical function") );
01eaf507
RR
1099 break;
1100 }
265898fd 1101 }
4bc67cc5 1102
265898fd 1103 m_logicalFunction = function;
6db90681
RR
1104
1105 if (!m_window) return;
1106
265898fd
RR
1107 gdk_gc_set_function( m_penGC, mode );
1108 gdk_gc_set_function( m_brushGC, mode );
3bc755fc 1109 gdk_gc_set_function( m_textGC, mode );
903f689b 1110}
c801d85f 1111
ec758a20 1112void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 1113{
93c5dd39 1114 wxCHECK_RET( Ok(), _T("invalid window dc") );
c801d85f 1115
265898fd 1116 if (m_textForegroundColour == col) return;
c801d85f 1117
265898fd
RR
1118 m_textForegroundColour = col;
1119 if (!m_textForegroundColour.Ok()) return;
c801d85f 1120
6db90681
RR
1121 if (!m_window) return;
1122
265898fd
RR
1123 m_textForegroundColour.CalcPixel( m_cmap );
1124 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
903f689b 1125}
c801d85f 1126
ec758a20 1127void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 1128{
93c5dd39 1129 wxCHECK_RET( Ok(), _T("invalid window dc") );
c801d85f 1130
265898fd 1131 if (m_textBackgroundColour == col) return;
c801d85f 1132
265898fd
RR
1133 m_textBackgroundColour = col;
1134 if (!m_textBackgroundColour.Ok()) return;
c801d85f 1135
6db90681
RR
1136 if (!m_window) return;
1137
265898fd
RR
1138 m_textBackgroundColour.CalcPixel( m_cmap );
1139 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
903f689b 1140}
c801d85f 1141
ec758a20 1142void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 1143{
93c5dd39 1144 wxCHECK_RET( Ok(), _T("invalid window dc") );
4bc67cc5 1145
265898fd 1146 m_backgroundMode = mode;
46dc76ba 1147
6db90681
RR
1148 if (!m_window) return;
1149
265898fd
RR
1150 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1151 // transparent/solid background mode
4bc67cc5 1152
265898fd
RR
1153 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1154 {
1155 gdk_gc_set_fill( m_brushGC,
1156 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1157 }
903f689b 1158}
c801d85f 1159
ec758a20 1160void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 1161{
93c5dd39 1162 wxFAIL_MSG( _T("wxWindowDC::SetPalette not implemented") );
903f689b 1163}
c801d85f 1164
b0e0d661 1165void wxWindowDC::DoSetClippingRegion( long x, long y, long width, long height )
c801d85f 1166{
93c5dd39 1167 wxCHECK_RET( Ok(), _T("invalid window dc") );
4bc67cc5 1168
089e55d6 1169 wxDC::DoSetClippingRegion( x, y, width, height );
c801d85f 1170
6db90681
RR
1171 if (!m_window) return;
1172
265898fd
RR
1173 GdkRectangle rect;
1174 rect.x = XLOG2DEV(x);
1175 rect.y = YLOG2DEV(y);
1176 rect.width = XLOG2DEVREL(width);
1177 rect.height = YLOG2DEVREL(height);
1178 gdk_gc_set_clip_rectangle( m_penGC, &rect );
1179 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
1180 gdk_gc_set_clip_rectangle( m_textGC, &rect );
1181 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
903f689b 1182}
c801d85f 1183
b0e0d661 1184void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
463c1fa1 1185{
93c5dd39 1186 wxCHECK_RET( Ok(), _T("invalid window dc") );
4bc67cc5 1187
463c1fa1
RR
1188 if (region.Empty())
1189 {
1190 DestroyClippingRegion();
1191 return;
1192 }
1193
6db90681
RR
1194 if (!m_window) return;
1195
463c1fa1
RR
1196 gdk_gc_set_clip_region( m_penGC, region.GetRegion() );
1197 gdk_gc_set_clip_region( m_brushGC, region.GetRegion() );
1198 gdk_gc_set_clip_region( m_textGC, region.GetRegion() );
1199 gdk_gc_set_clip_region( m_bgGC, region.GetRegion() );
1200}
1201
4bc67cc5 1202void wxWindowDC::DestroyClippingRegion()
c801d85f 1203{
93c5dd39 1204 wxCHECK_RET( Ok(), _T("invalid window dc") );
4bc67cc5 1205
265898fd 1206 wxDC::DestroyClippingRegion();
c801d85f 1207
6db90681
RR
1208 if (!m_window) return;
1209
265898fd
RR
1210 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1211 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1212 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1213 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
903f689b 1214}
c801d85f 1215
4bc67cc5 1216void wxWindowDC::SetUpDC()
c801d85f 1217{
265898fd
RR
1218 Destroy();
1219 m_ok = TRUE;
1220 m_logicalFunction = wxCOPY;
1221 m_penGC = gdk_gc_new( m_window );
1222 m_brushGC = gdk_gc_new( m_window );
1223 m_textGC = gdk_gc_new( m_window );
1224 m_bgGC = gdk_gc_new( m_window );
a802c3a1
RR
1225
1226 wxColour tmp_col( m_textForegroundColour );
1227 m_textForegroundColour = wxNullColour;
1228 SetTextForeground( tmp_col );
1229 tmp_col = m_textBackgroundColour;
1230 m_textBackgroundColour = wxNullColour;
1231 SetTextBackground( tmp_col );
031b2a7b
RR
1232
1233 wxPen tmp_pen( m_pen );
1234 m_pen = wxNullPen;
1235 SetPen( tmp_pen );
1236
1237 wxFont tmp_font( m_font );
1238 m_font = wxNullFont;
1239 SetFont( tmp_font );
1240
1241 wxBrush tmp_brush( m_brush );
1242 m_brush = wxNullBrush;
1243 SetBrush( tmp_brush );
1244
91b8de8d 1245/*
031b2a7b
RR
1246 tmp_brush = m_backgroundBrush;
1247 m_backgroundBrush = wxNullBrush;
1248 SetBackground( tmp_brush );
91b8de8d
RR
1249*/
1250 tmp_brush = m_backgroundBrush;
1251 m_backgroundBrush = wxNullBrush;
1252 SetBackground( *wxWHITE_BRUSH );
1253 m_backgroundBrush = tmp_brush;
265898fd 1254
265898fd
RR
1255 if (!hatch_bitmap)
1256 {
1257 hatch_bitmap = hatches;
1258 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1259 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1260 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1261 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1262 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1263 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1264 }
903f689b 1265}
c801d85f 1266
4bc67cc5 1267void wxWindowDC::Destroy()
dbf858b5 1268{
265898fd
RR
1269 if (m_penGC) gdk_gc_unref( m_penGC );
1270 m_penGC = (GdkGC*) NULL;
1271 if (m_brushGC) gdk_gc_unref( m_brushGC );
1272 m_brushGC = (GdkGC*) NULL;
1273 if (m_textGC) gdk_gc_unref( m_textGC );
1274 m_textGC = (GdkGC*) NULL;
1275 if (m_bgGC) gdk_gc_unref( m_bgGC );
1276 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
1277}
1278
238d735d
RR
1279void wxWindowDC::ComputeScaleAndOrigin()
1280{
1281 /* CMB: copy scale to see if it changes */
1282 double origScaleX = m_scaleX;
1283 double origScaleY = m_scaleY;
1284
1285 wxDC::ComputeScaleAndOrigin();
1286
1287 /* CMB: if scale has changed call SetPen to recalulate the line width */
1288 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
1289 (m_pen.Ok()))
1290 {
1291 /* this is a bit artificial, but we need to force wxDC to think
1292 the pen has changed */
1293 wxPen pen = m_pen;
1294 m_pen = wxNullPen;
1295 SetPen( pen );
1296 }
1297}
1298
b0e0d661
VZ
1299// Resolution in pixels per logical inch
1300wxSize wxWindowDC::GetPPI() const
1301{
1302 return wxSize(100, 100);
1303}
1304
1305int wxWindowDC::GetDepth() const
c801d85f 1306{
b0e0d661
VZ
1307 wxFAIL_MSG(_T("not implemented"));
1308
1309 return -1;
903f689b 1310}
c801d85f 1311
d54e4256 1312#if wxUSE_SPLINES
c801d85f
KB
1313// ----------------------------------- spline code ----------------------------------------
1314
1315void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1316 double a3, double b3, double a4, double b4);
4bc67cc5 1317void wx_clear_stack();
c801d85f
KB
1318int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1319 double *y3, double *x4, double *y4);
1320void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1321 double x4, double y4);
1322static bool wx_spline_add_point(double x, double y);
1323static void wx_spline_draw_point_array(wxDC *dc);
1324
1325wxList wx_spline_point_list;
1326
b0e0d661
VZ
1327#define half(z1, z2) ((z1+z2)/2.0)
1328#define THRESHOLD 5
c801d85f
KB
1329
1330/* iterative version */
1331
1332void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1333 double b4)
1334{
1335 register double xmid, ymid;
1336 double x1, y1, x2, y2, x3, y3, x4, y4;
1337
1338 wx_clear_stack();
1339 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1340
1341 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1342 xmid = (double)half(x2, x3);
1343 ymid = (double)half(y2, y3);
b0e0d661
VZ
1344 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1345 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
c801d85f
KB
1346 wx_spline_add_point( x1, y1 );
1347 wx_spline_add_point( xmid, ymid );
b0e0d661 1348 } else {
c801d85f
KB
1349 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1350 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1351 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1352 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
b0e0d661 1353 }
c801d85f
KB
1354 }
1355}
1356
1357/* utilities used by spline drawing routines */
1358
1359typedef struct wx_spline_stack_struct {
1360 double x1, y1, x2, y2, x3, y3, x4, y4;
1361} Stack;
1362
1363#define SPLINE_STACK_DEPTH 20
1364static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1365static Stack *wx_stack_top;
1366static int wx_stack_count;
1367
4bc67cc5 1368void wx_clear_stack()
c801d85f
KB
1369{
1370 wx_stack_top = wx_spline_stack;
1371 wx_stack_count = 0;
1372}
1373
1374void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1375{
1376 wx_stack_top->x1 = x1;
1377 wx_stack_top->y1 = y1;
1378 wx_stack_top->x2 = x2;
1379 wx_stack_top->y2 = y2;
1380 wx_stack_top->x3 = x3;
1381 wx_stack_top->y3 = y3;
1382 wx_stack_top->x4 = x4;
1383 wx_stack_top->y4 = y4;
1384 wx_stack_top++;
1385 wx_stack_count++;
1386}
1387
1388int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1389 double *x3, double *y3, double *x4, double *y4)
1390{
1391 if (wx_stack_count == 0)
b0e0d661 1392 return (0);
c801d85f
KB
1393 wx_stack_top--;
1394 wx_stack_count--;
1395 *x1 = wx_stack_top->x1;
1396 *y1 = wx_stack_top->y1;
1397 *x2 = wx_stack_top->x2;
1398 *y2 = wx_stack_top->y2;
1399 *x3 = wx_stack_top->x3;
1400 *y3 = wx_stack_top->y3;
1401 *x4 = wx_stack_top->x4;
1402 *y4 = wx_stack_top->y4;
1403 return (1);
1404}
1405
1406static bool wx_spline_add_point(double x, double y)
1407{
1408 wxPoint *point = new wxPoint ;
1409 point->x = (int) x;
1410 point->y = (int) y;
1411 wx_spline_point_list.Append((wxObject*)point);
1412 return TRUE;
1413}
1414
1415static void wx_spline_draw_point_array(wxDC *dc)
1416{
1417 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1418 wxNode *node = wx_spline_point_list.First();
1419 while (node)
1420 {
1421 wxPoint *point = (wxPoint *)node->Data();
1422 delete point;
1423 delete node;
1424 node = wx_spline_point_list.First();
1425 }
1426}
1427
b0e0d661 1428void wxWindowDC::DoDrawSpline( wxList *points )
c801d85f 1429{
93c5dd39 1430 wxCHECK_RET( Ok(), _T("invalid window dc") );
4bc67cc5 1431
c801d85f
KB
1432 wxPoint *p;
1433 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1434 double x1, y1, x2, y2;
1435
1436 wxNode *node = points->First();
1437 p = (wxPoint *)node->Data();
1438
1439 x1 = p->x;
1440 y1 = p->y;
1441
1442 node = node->Next();
1443 p = (wxPoint *)node->Data();
1444
1445 x2 = p->x;
1446 y2 = p->y;
1447 cx1 = (double)((x1 + x2) / 2);
1448 cy1 = (double)((y1 + y2) / 2);
1449 cx2 = (double)((cx1 + x2) / 2);
1450 cy2 = (double)((cy1 + y2) / 2);
1451
1452 wx_spline_add_point(x1, y1);
1453
1454 while ((node = node->Next()) != NULL)
1455 {
1456 p = (wxPoint *)node->Data();
b0e0d661
VZ
1457 x1 = x2;
1458 y1 = y2;
1459 x2 = p->x;
1460 y2 = p->y;
c801d85f
KB
1461 cx4 = (double)(x1 + x2) / 2;
1462 cy4 = (double)(y1 + y2) / 2;
1463 cx3 = (double)(x1 + cx4) / 2;
1464 cy3 = (double)(y1 + cy4) / 2;
1465
1466 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1467
b0e0d661
VZ
1468 cx1 = cx4;
1469 cy1 = cy4;
c801d85f
KB
1470 cx2 = (double)(cx1 + x2) / 2;
1471 cy2 = (double)(cy1 + y2) / 2;
1472 }
1473
1474 wx_spline_add_point( cx1, cy1 );
1475 wx_spline_add_point( x2, y2 );
1476
1477 wx_spline_draw_point_array( this );
903f689b 1478}
ec758a20 1479
b0e0d661 1480#endif // wxUSE_SPLINE
ec758a20
RR
1481
1482//-----------------------------------------------------------------------------
1483// wxPaintDC
1484//-----------------------------------------------------------------------------
1485
1486IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1487
4bc67cc5 1488wxPaintDC::wxPaintDC()
ec758a20
RR
1489 : wxWindowDC()
1490{
1491}
1492
1493wxPaintDC::wxPaintDC( wxWindow *win )
1494 : wxWindowDC( win )
1495{
1496}
1497
1498//-----------------------------------------------------------------------------
1499// wxClientDC
1500//-----------------------------------------------------------------------------
1501
1502IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1503
4bc67cc5 1504wxClientDC::wxClientDC()
ec758a20
RR
1505 : wxWindowDC()
1506{
1507}
1508
1509wxClientDC::wxClientDC( wxWindow *win )
1510 : wxWindowDC( win )
1511{
1512}
1513