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