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