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