]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/dcclient.cpp
compilation fix
[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
da048e3d
RR
122 GtkPizza *pizza = GTK_PIZZA( widget );
123 m_window = pizza->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
72cdf4c9 156void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x), wxCoord 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
72cdf4c9 162bool wxWindowDC::DoGetPixel( wxCoord WXUNUSED(x1), wxCoord 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
72cdf4c9 168void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord 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
72cdf4c9 182void wxWindowDC::DoCrossHair( wxCoord x, wxCoord 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 );
72cdf4c9
VZ
191 wxCoord xx = XLOG2DEV(x);
192 wxCoord 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
72cdf4c9
VZ
201void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
202 wxCoord xc, wxCoord yc )
c801d85f 203{
223d09f6 204 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 205
72cdf4c9
VZ
206 wxCoord xx1 = XLOG2DEV(x1);
207 wxCoord yy1 = YLOG2DEV(y1);
208 wxCoord xx2 = XLOG2DEV(x2);
209 wxCoord yy2 = YLOG2DEV(y2);
210 wxCoord xxc = XLOG2DEV(xc);
211 wxCoord 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));
72cdf4c9 215 wxCoord r = (wxCoord)radius;
265898fd
RR
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 236 }
72cdf4c9
VZ
237 wxCoord alpha1 = wxCoord(radius1 * 64.0);
238 wxCoord alpha2 = wxCoord((radius2 - radius1) * 64.0);
265898fd
RR
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
72cdf4c9 255void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
c801d85f 256{
223d09f6 257 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 258
72cdf4c9
VZ
259 wxCoord xx = XLOG2DEV(x);
260 wxCoord yy = YLOG2DEV(y);
261 wxCoord ww = m_signX * XLOG2DEVREL(width);
262 wxCoord 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 {
72cdf4c9
VZ
270 wxCoord start = wxCoord(sa * 64.0);
271 wxCoord end = wxCoord(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
72cdf4c9 284void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord 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
72cdf4c9 294void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord 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 {
72cdf4c9
VZ
305 wxCoord x1 = XLOG2DEV(points[i].x + xoffset);
306 wxCoord x2 = XLOG2DEV(points[i+1].x + xoffset);
307 wxCoord y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
308 wxCoord 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
72cdf4c9 317void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord 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
72cdf4c9 353void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 354{
223d09f6 355 wxCHECK_RET( Ok(), wxT("invalid window dc") );
c801d85f 356
72cdf4c9
VZ
357 wxCoord xx = XLOG2DEV(x);
358 wxCoord yy = YLOG2DEV(y);
359 wxCoord ww = m_signX * XLOG2DEVREL(width);
360 wxCoord 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
72cdf4c9 382void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord 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 387
72cdf4c9
VZ
388 wxCoord xx = XLOG2DEV(x);
389 wxCoord yy = YLOG2DEV(y);
390 wxCoord ww = m_signX * XLOG2DEVREL(width);
391 wxCoord hh = m_signY * YLOG2DEVREL(height);
392 wxCoord rr = XLOG2DEVREL((wxCoord)radius);
265898fd
RR
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
72cdf4c9 421 wxCoord dd = 2 * rr;
6db90681
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
72cdf4c9 454void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 455{
223d09f6 456 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 457
72cdf4c9
VZ
458 wxCoord xx = XLOG2DEV(x);
459 wxCoord yy = YLOG2DEV(y);
460 wxCoord ww = m_signX * XLOG2DEVREL(width);
461 wxCoord 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
72cdf4c9 480void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord 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 486void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
72cdf4c9 487 wxCoord x, wxCoord y,
b0e0d661 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
72cdf4c9
VZ
562bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
563 wxDC *source, wxCoord xsrc, wxCoord ysrc,
b0e0d661 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
72cdf4c9
VZ
632 wxCoord bm_width = memDC->m_selected.GetWidth();
633 wxCoord bm_height = memDC->m_selected.GetHeight();
7d5af6fa 634
72cdf4c9
VZ
635 wxCoord bm_ww = XLOG2DEVREL( bm_width );
636 wxCoord 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
72cdf4c9
VZ
656 wxCoord xx = XLOG2DEV(xdest);
657 wxCoord yy = YLOG2DEV(ydest);
7d5af6fa 658
72cdf4c9
VZ
659 wxCoord ww = XLOG2DEVREL(width);
660 wxCoord 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
72cdf4c9
VZ
703 wxCoord xx = XLOG2DEV(xdest);
704 wxCoord yy = YLOG2DEV(ydest);
7d5af6fa 705
72cdf4c9
VZ
706 wxCoord ww = XLOG2DEVREL(width);
707 wxCoord 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
72cdf4c9 757void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord 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
a1fffa9f
VZ
765 wxCHECK_RET( font, wxT("invalid font") );
766
265898fd
RR
767 x = XLOG2DEV(x);
768 y = YLOG2DEV(y);
18a2fa37 769
bbbbe360 770 /* CMB 21/5/98: draw text background if mode is wxSOLID */
265898fd
RR
771 if (m_backgroundMode == wxSOLID)
772 {
72cdf4c9
VZ
773 wxCoord width = gdk_string_width( font, text.mbc_str() );
774 wxCoord height = font->ascent + font->descent;
265898fd
RR
775 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
776 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
777 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
778 }
93c5dd39 779 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
18a2fa37 780
bbbbe360
RR
781 /* CMB 17/7/98: simple underline: ignores scaling and underlying
782 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
783 properties (see wxXt implementation) */
265898fd
RR
784 if (m_font.GetUnderlined())
785 {
72cdf4c9
VZ
786 wxCoord width = gdk_string_width( font, text.mbc_str() );
787 wxCoord ul_y = y + font->ascent;
265898fd
RR
788 if (font->descent > 0) ul_y++;
789 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
790 }
7d5af6fa 791
72cdf4c9 792 wxCoord w, h;
265898fd
RR
793 GetTextExtent (text, &w, &h);
794 CalcBoundingBox (x + w, y + h);
795 CalcBoundingBox (x, y);
903f689b 796}
c801d85f 797
72cdf4c9
VZ
798void wxWindowDC::DoGetTextExtent(const wxString &string,
799 wxCoord *width, wxCoord *height,
800 wxCoord *descent, wxCoord *externalLeading,
801 wxFont *theFont) const
c801d85f 802{
265898fd
RR
803 wxFont fontToUse = m_font;
804 if (theFont) fontToUse = *theFont;
7d5af6fa 805
265898fd 806 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
72cdf4c9
VZ
807 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
808 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
809 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
265898fd 810 if (externalLeading) (*externalLeading) = 0; // ??
903f689b 811}
c801d85f 812
72cdf4c9 813wxCoord wxWindowDC::GetCharWidth() const
c801d85f 814{
265898fd 815 GdkFont *font = m_font.GetInternalFont( m_scaleY );
7beba2fc
VZ
816 wxCHECK_MSG( font, -1, _T("invalid font") );
817
72cdf4c9 818 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 819}
c801d85f 820
72cdf4c9 821wxCoord wxWindowDC::GetCharHeight() const
c801d85f 822{
265898fd 823 GdkFont *font = m_font.GetInternalFont( m_scaleY );
7beba2fc
VZ
824 wxCHECK_MSG( font, -1, _T("invalid font") );
825
72cdf4c9 826 return wxCoord((font->ascent + font->descent) / m_scaleY);
903f689b 827}
c801d85f 828
4bc67cc5 829void wxWindowDC::Clear()
c801d85f 830{
223d09f6 831 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 832
6db90681 833 if (!m_window) return;
7d5af6fa 834
f234c60c
RR
835 /* - we either are a memory dc or have a window as the
836 owner. anything else shouldn't happen.
837 - we don't use gdk_window_clear() as we don't set
838 the window's background colour anymore. it is too
839 much pain to keep the DC's and the window's back-
840 ground colour in synch. */
7d5af6fa 841
f234c60c 842 if (m_owner)
265898fd 843 {
f234c60c
RR
844 int width,height;
845 m_owner->GetSize( &width, &height );
846 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 847 return;
265898fd 848 }
f234c60c
RR
849
850 if (m_isMemDC)
265898fd
RR
851 {
852 int width,height;
853 GetSize( &width, &height );
854 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
b0e0d661 855 return;
265898fd 856 }
903f689b 857}
c801d85f 858
ec758a20 859void wxWindowDC::SetFont( const wxFont &font )
c801d85f 860{
265898fd 861 m_font = font;
903f689b 862}
c801d85f 863
ec758a20 864void wxWindowDC::SetPen( const wxPen &pen )
c801d85f 865{
223d09f6 866 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 867
265898fd 868 if (m_pen == pen) return;
7d5af6fa 869
265898fd 870 m_pen = pen;
7d5af6fa 871
265898fd 872 if (!m_pen.Ok()) return;
7d5af6fa 873
6db90681 874 if (!m_window) return;
7d5af6fa 875
265898fd 876 gint width = m_pen.GetWidth();
265898fd
RR
877 if (width <= 0)
878 {
112c5086 879 // CMB: if width is non-zero scale it with the dc
265898fd
RR
880 width = 1;
881 }
882 else
883 {
884 // X doesn't allow different width in x and y and so we take
885 // the average
503f414e
VZ
886 double w = 0.5 +
887 ( fabs((double) XLOG2DEVREL(width)) +
888 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
265898fd
RR
889 width = (int)w;
890 }
7d5af6fa
VZ
891
892 static const char dotted[] = {1, 1};
893 static const char short_dashed[] = {2, 2};
72cdf4c9 894 static const char wxCoord_dashed[] = {2, 4};
7d5af6fa
VZ
895 static const char dotted_dashed[] = {3, 3, 1, 3};
896
112c5086
RR
897 // We express dash pattern in pen width unit, so we are
898 // independent of zoom factor and so on...
899 int req_nb_dash;
900 const char *req_dash;
7d5af6fa 901
265898fd
RR
902 GdkLineStyle lineStyle = GDK_LINE_SOLID;
903 switch (m_pen.GetStyle())
904 {
112c5086 905 case wxUSER_DASH:
7d5af6fa
VZ
906 {
907 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
908 req_nb_dash = m_pen.GetDashCount();
909 req_dash = m_pen.GetDash();
910 break;
7d5af6fa
VZ
911 }
912 case wxDOT:
913 {
914 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
915 req_nb_dash = 2;
916 req_dash = dotted;
7d5af6fa
VZ
917 break;
918 }
919 case wxLONG_DASH:
920 {
921 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086 922 req_nb_dash = 2;
72cdf4c9 923 req_dash = wxCoord_dashed;
7d5af6fa
VZ
924 break;
925 }
926 case wxSHORT_DASH:
927 {
928 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
929 req_nb_dash = 2;
930 req_dash = short_dashed;
7d5af6fa
VZ
931 break;
932 }
933 case wxDOT_DASH:
934 {
935// lineStyle = GDK_LINE_DOUBLE_DASH;
936 lineStyle = GDK_LINE_ON_OFF_DASH;
112c5086
RR
937 req_nb_dash = 4;
938 req_dash = dotted_dashed;
7d5af6fa
VZ
939 break;
940 }
941
942 case wxTRANSPARENT:
943 case wxSTIPPLE:
944 case wxSOLID:
945 default:
946 {
947 lineStyle = GDK_LINE_SOLID;
112c5086
RR
948 req_dash = (wxDash*)NULL;
949 req_nb_dash = 0;
7d5af6fa
VZ
950 break;
951 }
265898fd 952 }
7d5af6fa 953
953704c1 954#if (GTK_MINOR_VERSION > 0)
112c5086
RR
955 if (req_dash && req_nb_dash)
956 {
957 char *real_req_dash = new char[req_nb_dash];
958 if (real_req_dash)
959 {
960 for (int i = 0; i < req_nb_dash; i++)
961 real_req_dash[i] = req_dash[i] * width;
7d5af6fa 962 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
112c5086
RR
963 delete[] real_req_dash;
964 }
965 else
966 {
967 // No Memory. We use non-scaled dash pattern...
7d5af6fa 968 gdk_gc_set_dashes( m_penGC, 0, (char*)req_dash, req_nb_dash );
112c5086
RR
969 }
970 }
953704c1 971#endif
7d5af6fa 972
265898fd
RR
973 GdkCapStyle capStyle = GDK_CAP_ROUND;
974 switch (m_pen.GetCap())
975 {
976 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
977 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
978 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
979 }
7d5af6fa 980
265898fd
RR
981 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
982 switch (m_pen.GetJoin())
983 {
984 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
985 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
986 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
987 }
7d5af6fa 988
265898fd 989 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
7d5af6fa 990
265898fd
RR
991 m_pen.GetColour().CalcPixel( m_cmap );
992 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 993}
c801d85f 994
ec758a20 995void wxWindowDC::SetBrush( const wxBrush &brush )
c801d85f 996{
223d09f6 997 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 998
265898fd 999 if (m_brush == brush) return;
7d5af6fa 1000
265898fd 1001 m_brush = brush;
7d5af6fa 1002
265898fd 1003 if (!m_brush.Ok()) return;
7d5af6fa 1004
6db90681 1005 if (!m_window) return;
7d5af6fa 1006
265898fd
RR
1007 m_brush.GetColour().CalcPixel( m_cmap );
1008 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
7d5af6fa 1009
956dbab1 1010 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
7d5af6fa 1011
4fcd73bd 1012 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
265898fd 1013 {
4fcd73bd 1014 if (m_brush.GetStipple()->GetPixmap())
7d5af6fa 1015 {
956dbab1 1016 gdk_gc_set_fill( m_brushGC, GDK_TILED );
cd25b18c 1017 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
7d5af6fa 1018 }
b0e0d661 1019 else
7d5af6fa 1020 {
956dbab1 1021 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
4fcd73bd 1022 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
7d5af6fa 1023 }
265898fd 1024 }
7d5af6fa 1025
265898fd
RR
1026 if (IS_HATCH(m_brush.GetStyle()))
1027 {
956dbab1 1028 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
265898fd
RR
1029 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1030 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1031 }
903f689b 1032}
c801d85f 1033
ec758a20 1034void wxWindowDC::SetBackground( const wxBrush &brush )
46dc76ba 1035{
bbbbe360
RR
1036 /* CMB 21/7/98: Added SetBackground. Sets background brush
1037 * for Clear() and bg colour for shapes filled with cross-hatch brush */
7d5af6fa 1038
223d09f6 1039 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1040
265898fd 1041 if (m_backgroundBrush == brush) return;
7d5af6fa 1042
265898fd 1043 m_backgroundBrush = brush;
7d5af6fa 1044
265898fd 1045 if (!m_backgroundBrush.Ok()) return;
7d5af6fa 1046
6db90681 1047 if (!m_window) return;
7d5af6fa 1048
265898fd
RR
1049 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1050 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
a802c3a1 1051 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
031b2a7b 1052 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
265898fd 1053 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
3417c2cd
RR
1054
1055 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
7d5af6fa 1056
cd25b18c 1057 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
265898fd 1058 {
fd128b0c 1059 if (m_backgroundBrush.GetStipple()->GetPixmap())
7d5af6fa 1060 {
3417c2cd 1061 gdk_gc_set_fill( m_bgGC, GDK_TILED );
fd128b0c 1062 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
7d5af6fa 1063 }
cd25b18c 1064 else
7d5af6fa 1065 {
3417c2cd 1066 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
fd128b0c 1067 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
7d5af6fa 1068 }
265898fd 1069 }
7d5af6fa 1070
265898fd
RR
1071 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1072 {
3417c2cd 1073 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
265898fd
RR
1074 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1075 gdk_gc_set_stipple( m_bgGC, hatches[num] );
bbbbe360 1076 }
903f689b 1077}
46dc76ba 1078
ec758a20 1079void wxWindowDC::SetLogicalFunction( int function )
c801d85f 1080{
223d09f6 1081 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1082
265898fd 1083 if (m_logicalFunction == function) return;
01eaf507 1084
265898fd
RR
1085 GdkFunction mode = GDK_COPY;
1086 switch (function)
1087 {
3c679789
RR
1088 case wxXOR: mode = GDK_XOR; break;
1089 case wxINVERT: mode = GDK_INVERT; break;
01eaf507 1090#if (GTK_MINOR_VERSION > 0)
3c679789
RR
1091 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1092 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1093 case wxCLEAR: mode = GDK_CLEAR; break;
1094 case wxSET: mode = GDK_SET; break;
1095 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
7d5af6fa 1096 case wxSRC_AND:
3c679789 1097 case wxAND: mode = GDK_AND; break;
7d5af6fa 1098 case wxSRC_OR:
3c679789
RR
1099 case wxOR: mode = GDK_OR; break;
1100 case wxEQUIV: mode = GDK_EQUIV; break;
1101 case wxNAND: mode = GDK_NAND; break;
1102 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
7d5af6fa
VZ
1103 case wxCOPY: mode = GDK_COPY; break;
1104 case wxNO_OP: mode = GDK_NOOP; break;
1105 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
c96faa7c 1106#endif
01eaf507 1107 default:
7d5af6fa 1108 {
223d09f6 1109 wxFAIL_MSG( wxT("unsupported logical function") );
7d5af6fa
VZ
1110 break;
1111 }
265898fd 1112 }
7d5af6fa 1113
265898fd 1114 m_logicalFunction = function;
7d5af6fa 1115
6db90681 1116 if (!m_window) return;
7d5af6fa 1117
265898fd
RR
1118 gdk_gc_set_function( m_penGC, mode );
1119 gdk_gc_set_function( m_brushGC, mode );
3bc755fc 1120 gdk_gc_set_function( m_textGC, mode );
903f689b 1121}
c801d85f 1122
ec758a20 1123void wxWindowDC::SetTextForeground( const wxColour &col )
c801d85f 1124{
223d09f6 1125 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1126
265898fd 1127 if (m_textForegroundColour == col) return;
7d5af6fa 1128
265898fd
RR
1129 m_textForegroundColour = col;
1130 if (!m_textForegroundColour.Ok()) return;
7d5af6fa 1131
6db90681 1132 if (!m_window) return;
7d5af6fa 1133
265898fd
RR
1134 m_textForegroundColour.CalcPixel( m_cmap );
1135 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
903f689b 1136}
c801d85f 1137
ec758a20 1138void wxWindowDC::SetTextBackground( const wxColour &col )
c801d85f 1139{
223d09f6 1140 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1141
265898fd 1142 if (m_textBackgroundColour == col) return;
7d5af6fa 1143
265898fd
RR
1144 m_textBackgroundColour = col;
1145 if (!m_textBackgroundColour.Ok()) return;
7d5af6fa 1146
6db90681 1147 if (!m_window) return;
7d5af6fa 1148
265898fd
RR
1149 m_textBackgroundColour.CalcPixel( m_cmap );
1150 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
903f689b 1151}
c801d85f 1152
ec758a20 1153void wxWindowDC::SetBackgroundMode( int mode )
c801d85f 1154{
223d09f6 1155 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1156
265898fd 1157 m_backgroundMode = mode;
46dc76ba 1158
6db90681 1159 if (!m_window) return;
7d5af6fa 1160
265898fd
RR
1161 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1162 // transparent/solid background mode
7d5af6fa 1163
265898fd
RR
1164 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1165 {
1166 gdk_gc_set_fill( m_brushGC,
1167 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1168 }
903f689b 1169}
c801d85f 1170
ec758a20 1171void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
c801d85f 1172{
223d09f6 1173 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
903f689b 1174}
c801d85f 1175
72cdf4c9 1176void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 1177{
223d09f6 1178 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1179
089e55d6 1180 wxDC::DoSetClippingRegion( x, y, width, height );
7d5af6fa 1181
6db90681 1182 if (!m_window) return;
7d5af6fa 1183
265898fd
RR
1184 GdkRectangle rect;
1185 rect.x = XLOG2DEV(x);
1186 rect.y = YLOG2DEV(y);
1187 rect.width = XLOG2DEVREL(width);
1188 rect.height = YLOG2DEVREL(height);
1189 gdk_gc_set_clip_rectangle( m_penGC, &rect );
1190 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
1191 gdk_gc_set_clip_rectangle( m_textGC, &rect );
1192 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
903f689b 1193}
c801d85f 1194
b0e0d661 1195void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
463c1fa1 1196{
223d09f6 1197 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1198
463c1fa1
RR
1199 if (region.Empty())
1200 {
1201 DestroyClippingRegion();
1202 return;
1203 }
7d5af6fa 1204
6db90681 1205 if (!m_window) return;
7d5af6fa 1206
463c1fa1
RR
1207 gdk_gc_set_clip_region( m_penGC, region.GetRegion() );
1208 gdk_gc_set_clip_region( m_brushGC, region.GetRegion() );
1209 gdk_gc_set_clip_region( m_textGC, region.GetRegion() );
1210 gdk_gc_set_clip_region( m_bgGC, region.GetRegion() );
1211}
1212
4bc67cc5 1213void wxWindowDC::DestroyClippingRegion()
c801d85f 1214{
223d09f6 1215 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1216
265898fd 1217 wxDC::DestroyClippingRegion();
7d5af6fa 1218
6db90681 1219 if (!m_window) return;
7d5af6fa 1220
265898fd
RR
1221 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1222 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1223 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1224 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
903f689b 1225}
c801d85f 1226
4bc67cc5 1227void wxWindowDC::SetUpDC()
c801d85f 1228{
265898fd
RR
1229 Destroy();
1230 m_ok = TRUE;
1231 m_logicalFunction = wxCOPY;
1232 m_penGC = gdk_gc_new( m_window );
1233 m_brushGC = gdk_gc_new( m_window );
1234 m_textGC = gdk_gc_new( m_window );
1235 m_bgGC = gdk_gc_new( m_window );
7d5af6fa 1236
a802c3a1
RR
1237 wxColour tmp_col( m_textForegroundColour );
1238 m_textForegroundColour = wxNullColour;
1239 SetTextForeground( tmp_col );
1240 tmp_col = m_textBackgroundColour;
1241 m_textBackgroundColour = wxNullColour;
1242 SetTextBackground( tmp_col );
7d5af6fa 1243
031b2a7b
RR
1244 wxPen tmp_pen( m_pen );
1245 m_pen = wxNullPen;
1246 SetPen( tmp_pen );
7d5af6fa 1247
031b2a7b
RR
1248 wxFont tmp_font( m_font );
1249 m_font = wxNullFont;
1250 SetFont( tmp_font );
7d5af6fa 1251
031b2a7b
RR
1252 wxBrush tmp_brush( m_brush );
1253 m_brush = wxNullBrush;
1254 SetBrush( tmp_brush );
7d5af6fa 1255
91b8de8d 1256/*
031b2a7b
RR
1257 tmp_brush = m_backgroundBrush;
1258 m_backgroundBrush = wxNullBrush;
1259 SetBackground( tmp_brush );
91b8de8d
RR
1260*/
1261 tmp_brush = m_backgroundBrush;
1262 m_backgroundBrush = wxNullBrush;
1263 SetBackground( *wxWHITE_BRUSH );
1264 m_backgroundBrush = tmp_brush;
7d5af6fa
VZ
1265
1266 if (!hatch_bitmap)
265898fd
RR
1267 {
1268 hatch_bitmap = hatches;
1269 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1270 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1271 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1272 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1273 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1274 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1275 }
903f689b 1276}
c801d85f 1277
4bc67cc5 1278void wxWindowDC::Destroy()
dbf858b5 1279{
265898fd
RR
1280 if (m_penGC) gdk_gc_unref( m_penGC );
1281 m_penGC = (GdkGC*) NULL;
1282 if (m_brushGC) gdk_gc_unref( m_brushGC );
1283 m_brushGC = (GdkGC*) NULL;
1284 if (m_textGC) gdk_gc_unref( m_textGC );
1285 m_textGC = (GdkGC*) NULL;
1286 if (m_bgGC) gdk_gc_unref( m_bgGC );
1287 m_bgGC = (GdkGC*) NULL;
dbf858b5
RR
1288}
1289
238d735d
RR
1290void wxWindowDC::ComputeScaleAndOrigin()
1291{
1292 /* CMB: copy scale to see if it changes */
1293 double origScaleX = m_scaleX;
1294 double origScaleY = m_scaleY;
1295
1296 wxDC::ComputeScaleAndOrigin();
1297
1298 /* CMB: if scale has changed call SetPen to recalulate the line width */
1299 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
1300 (m_pen.Ok()))
1301 {
1302 /* this is a bit artificial, but we need to force wxDC to think
1303 the pen has changed */
1304 wxPen pen = m_pen;
1305 m_pen = wxNullPen;
1306 SetPen( pen );
1307 }
1308}
1309
b0e0d661
VZ
1310// Resolution in pixels per logical inch
1311wxSize wxWindowDC::GetPPI() const
1312{
1313 return wxSize(100, 100);
1314}
1315
1316int wxWindowDC::GetDepth() const
c801d85f 1317{
223d09f6 1318 wxFAIL_MSG(wxT("not implemented"));
b0e0d661
VZ
1319
1320 return -1;
903f689b 1321}
c801d85f 1322
d54e4256 1323#if wxUSE_SPLINES
c801d85f
KB
1324// ----------------------------------- spline code ----------------------------------------
1325
1326void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1327 double a3, double b3, double a4, double b4);
4bc67cc5 1328void wx_clear_stack();
c801d85f
KB
1329int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1330 double *y3, double *x4, double *y4);
1331void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1332 double x4, double y4);
1333static bool wx_spline_add_point(double x, double y);
1334static void wx_spline_draw_point_array(wxDC *dc);
1335
1336wxList wx_spline_point_list;
1337
b0e0d661
VZ
1338#define half(z1, z2) ((z1+z2)/2.0)
1339#define THRESHOLD 5
c801d85f
KB
1340
1341/* iterative version */
1342
1343void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1344 double b4)
1345{
1346 register double xmid, ymid;
1347 double x1, y1, x2, y2, x3, y3, x4, y4;
1348
1349 wx_clear_stack();
1350 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1351
1352 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1353 xmid = (double)half(x2, x3);
1354 ymid = (double)half(y2, y3);
b0e0d661
VZ
1355 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1356 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
c801d85f
KB
1357 wx_spline_add_point( x1, y1 );
1358 wx_spline_add_point( xmid, ymid );
b0e0d661 1359 } else {
c801d85f
KB
1360 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1361 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1362 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1363 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
b0e0d661 1364 }
c801d85f
KB
1365 }
1366}
1367
1368/* utilities used by spline drawing routines */
1369
1370typedef struct wx_spline_stack_struct {
1371 double x1, y1, x2, y2, x3, y3, x4, y4;
1372} Stack;
1373
1374#define SPLINE_STACK_DEPTH 20
1375static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1376static Stack *wx_stack_top;
1377static int wx_stack_count;
1378
4bc67cc5 1379void wx_clear_stack()
c801d85f
KB
1380{
1381 wx_stack_top = wx_spline_stack;
1382 wx_stack_count = 0;
1383}
1384
1385void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1386{
1387 wx_stack_top->x1 = x1;
1388 wx_stack_top->y1 = y1;
1389 wx_stack_top->x2 = x2;
1390 wx_stack_top->y2 = y2;
1391 wx_stack_top->x3 = x3;
1392 wx_stack_top->y3 = y3;
1393 wx_stack_top->x4 = x4;
1394 wx_stack_top->y4 = y4;
1395 wx_stack_top++;
1396 wx_stack_count++;
1397}
1398
1399int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1400 double *x3, double *y3, double *x4, double *y4)
1401{
1402 if (wx_stack_count == 0)
b0e0d661 1403 return (0);
c801d85f
KB
1404 wx_stack_top--;
1405 wx_stack_count--;
1406 *x1 = wx_stack_top->x1;
1407 *y1 = wx_stack_top->y1;
1408 *x2 = wx_stack_top->x2;
1409 *y2 = wx_stack_top->y2;
1410 *x3 = wx_stack_top->x3;
1411 *y3 = wx_stack_top->y3;
1412 *x4 = wx_stack_top->x4;
1413 *y4 = wx_stack_top->y4;
1414 return (1);
1415}
1416
1417static bool wx_spline_add_point(double x, double y)
1418{
1419 wxPoint *point = new wxPoint ;
1420 point->x = (int) x;
1421 point->y = (int) y;
1422 wx_spline_point_list.Append((wxObject*)point);
1423 return TRUE;
1424}
1425
1426static void wx_spline_draw_point_array(wxDC *dc)
1427{
1428 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1429 wxNode *node = wx_spline_point_list.First();
1430 while (node)
1431 {
1432 wxPoint *point = (wxPoint *)node->Data();
1433 delete point;
1434 delete node;
1435 node = wx_spline_point_list.First();
1436 }
1437}
1438
b0e0d661 1439void wxWindowDC::DoDrawSpline( wxList *points )
c801d85f 1440{
223d09f6 1441 wxCHECK_RET( Ok(), wxT("invalid window dc") );
7d5af6fa 1442
c801d85f
KB
1443 wxPoint *p;
1444 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1445 double x1, y1, x2, y2;
1446
1447 wxNode *node = points->First();
1448 p = (wxPoint *)node->Data();
1449
1450 x1 = p->x;
1451 y1 = p->y;
1452
1453 node = node->Next();
1454 p = (wxPoint *)node->Data();
1455
1456 x2 = p->x;
1457 y2 = p->y;
1458 cx1 = (double)((x1 + x2) / 2);
1459 cy1 = (double)((y1 + y2) / 2);
1460 cx2 = (double)((cx1 + x2) / 2);
1461 cy2 = (double)((cy1 + y2) / 2);
1462
1463 wx_spline_add_point(x1, y1);
1464
1465 while ((node = node->Next()) != NULL)
1466 {
1467 p = (wxPoint *)node->Data();
b0e0d661
VZ
1468 x1 = x2;
1469 y1 = y2;
1470 x2 = p->x;
1471 y2 = p->y;
c801d85f
KB
1472 cx4 = (double)(x1 + x2) / 2;
1473 cy4 = (double)(y1 + y2) / 2;
1474 cx3 = (double)(x1 + cx4) / 2;
1475 cy3 = (double)(y1 + cy4) / 2;
1476
1477 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1478
b0e0d661
VZ
1479 cx1 = cx4;
1480 cy1 = cy4;
c801d85f
KB
1481 cx2 = (double)(cx1 + x2) / 2;
1482 cy2 = (double)(cy1 + y2) / 2;
1483 }
1484
1485 wx_spline_add_point( cx1, cy1 );
1486 wx_spline_add_point( x2, y2 );
1487
1488 wx_spline_draw_point_array( this );
903f689b 1489}
ec758a20 1490
b0e0d661 1491#endif // wxUSE_SPLINE
ec758a20
RR
1492
1493//-----------------------------------------------------------------------------
1494// wxPaintDC
1495//-----------------------------------------------------------------------------
1496
1497IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1498
4bc67cc5 1499wxPaintDC::wxPaintDC()
ec758a20
RR
1500 : wxWindowDC()
1501{
1502}
1503
1504wxPaintDC::wxPaintDC( wxWindow *win )
1505 : wxWindowDC( win )
1506{
1507}
1508
1509//-----------------------------------------------------------------------------
1510// wxClientDC
1511//-----------------------------------------------------------------------------
1512
1513IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1514
4bc67cc5 1515wxClientDC::wxClientDC()
ec758a20
RR
1516 : wxWindowDC()
1517{
1518}
1519
1520wxClientDC::wxClientDC( wxWindow *win )
1521 : wxWindowDC( win )
1522{
1523}
1524