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