]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/dcclient.cpp
Added support for frames without borders (such as for
[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"
c801d85f
KB
16
17//-----------------------------------------------------------------------------
18// local data
19//-----------------------------------------------------------------------------
20
21#include "bdiag.xbm"
22#include "fdiag.xbm"
23#include "cdiag.xbm"
24#include "horiz.xbm"
25#include "verti.xbm"
26#include "cross.xbm"
27#define num_hatches 6
28
29static GdkPixmap *hatches[num_hatches];
c67daf87 30static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
c801d85f
KB
31
32//-----------------------------------------------------------------------------
33// constants
34//-----------------------------------------------------------------------------
35
36#define RAD2DEG 57.2957795131
37
6f65e337
JS
38//-----------------------------------------------------------------------------
39// temporary implementation of the missing GDK function
40//-----------------------------------------------------------------------------
41#include "gdk/gdkprivate.h"
42void gdk_draw_bitmap (GdkDrawable *drawable,
43 GdkGC *gc,
44 GdkDrawable *src,
45 gint xsrc,
46 gint ysrc,
47 gint xdest,
48 gint ydest,
49 gint width,
50 gint height)
51{
52 GdkWindowPrivate *drawable_private;
53 GdkWindowPrivate *src_private;
54 GdkGCPrivate *gc_private;
55
56 g_return_if_fail (drawable != NULL);
57 g_return_if_fail (src != NULL);
58 g_return_if_fail (gc != NULL);
59
60 drawable_private = (GdkWindowPrivate*) drawable;
61 src_private = (GdkWindowPrivate*) src;
62 if (drawable_private->destroyed || src_private->destroyed)
63 return;
64 gc_private = (GdkGCPrivate*) gc;
65
66 if (width == -1)
67 width = src_private->width;
68 if (height == -1)
69 height = src_private->height;
70
71 XCopyPlane (drawable_private->xdisplay,
72 src_private->xwindow,
73 drawable_private->xwindow,
74 gc_private->xgc,
75 xsrc, ysrc,
76 width, height,
77 xdest, ydest,
78 1);
79}
80
c801d85f
KB
81//-----------------------------------------------------------------------------
82// wxPaintDC
83//-----------------------------------------------------------------------------
84
85IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxDC)
86
87wxPaintDC::wxPaintDC(void)
88{
c67daf87
UR
89 m_penGC = (GdkGC *) NULL;
90 m_brushGC = (GdkGC *) NULL;
91 m_textGC = (GdkGC *) NULL;
92 m_bgGC = (GdkGC *) NULL;
93 m_cmap = (GdkColormap *) NULL;
fc54776e 94 m_isMemDC = FALSE;
903f689b 95}
c801d85f
KB
96
97wxPaintDC::wxPaintDC( wxWindow *window )
98{
c67daf87
UR
99 m_penGC = (GdkGC *) NULL;
100 m_brushGC = (GdkGC *) NULL;
101 m_textGC = (GdkGC *) NULL;
102 m_bgGC = (GdkGC *) NULL;
103 m_cmap = (GdkColormap *) NULL;
e3e65dac 104
c801d85f
KB
105 if (!window) return;
106 GtkWidget *widget = window->m_wxwindow;
107 if (!widget) return;
108 m_window = widget->window;
109 if (!m_window) return;
110 if (window->m_wxwindow)
111 m_cmap = gtk_widget_get_colormap( window->m_wxwindow );
112 else
113 m_cmap = gtk_widget_get_colormap( window->m_widget );
0180d5da 114
fc54776e 115 m_isMemDC = FALSE;
0180d5da 116
c801d85f 117 SetUpDC();
903f689b 118}
c801d85f
KB
119
120wxPaintDC::~wxPaintDC(void)
121{
903f689b 122}
c801d85f
KB
123
124void wxPaintDC::FloodFill( long WXUNUSED(x1), long WXUNUSED(y1),
125 wxColour *WXUNUSED(col), int WXUNUSED(style) )
126{
cf7a7e13 127 wxFAIL_MSG( "wxPaintDC::FloodFill not implemented" );
903f689b 128}
c801d85f
KB
129
130bool wxPaintDC::GetPixel( long WXUNUSED(x1), long WXUNUSED(y1), wxColour *WXUNUSED(col) ) const
131{
cf7a7e13 132 wxFAIL_MSG( "wxPaintDC::GetPixel not implemented" );
c801d85f 133 return FALSE;
903f689b 134}
c801d85f
KB
135
136void wxPaintDC::DrawLine( long x1, long y1, long x2, long y2 )
137{
138 if (!Ok()) return;
139
140 if (m_pen.GetStyle() != wxTRANSPARENT)
141 {
142 gdk_draw_line( m_window, m_penGC,
143 XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
903f689b
RR
144 }
145}
c801d85f
KB
146
147void wxPaintDC::CrossHair( long x, long y )
148{
149 if (!Ok()) return;
150
151 if (m_pen.GetStyle() != wxTRANSPARENT)
152 {
153 int w = 0;
154 int h = 0;
155 GetSize( &w, &h );
156 long xx = XLOG2DEV(x);
157 long yy = YLOG2DEV(y);
158 gdk_draw_line( m_window, m_penGC,
159 0, yy, XLOG2DEVREL(w), yy );
160 gdk_draw_line( m_window, m_penGC,
161 xx, 0, xx, YLOG2DEVREL(h) );
903f689b
RR
162 }
163}
c801d85f
KB
164
165void wxPaintDC::DrawArc( long x1, long y1, long x2, long y2, double xc, double yc )
166{
167 if (!Ok()) return;
168
169 long xx1 = XLOG2DEV(x1);
170 long yy1 = YLOG2DEV(y1);
171 long xx2 = XLOG2DEV(x2);
172 long yy2 = YLOG2DEV(y2);
173 long xxc = XLOG2DEV((long)xc);
174 long yyc = YLOG2DEV((long)yc);
175 double dx = xx1 - xxc;
176 double dy = yy1 - yyc;
177 double radius = sqrt(dx*dx+dy*dy);
178 long r = (long)radius;
179 double radius1, radius2;
180
181 if (xx1 == xx2 && yy1 == yy2)
182 {
183 radius1 = 0.0;
184 radius2 = 360.0;
185 }
186 else
187 if (radius == 0.0)
188 {
189 radius1 = radius2 = 0.0;
190 }
191 else
192 {
193 radius1 = (xx1 - xxc == 0) ?
194 (yy1 - yyc < 0) ? 90.0 : -90.0 :
195 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
196 radius2 = (xx2 - xxc == 0) ?
197 (yy2 - yyc < 0) ? 90.0 : -90.0 :
198 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
903f689b 199 }
c801d85f
KB
200 long alpha1 = long(radius1 * 64.0);
201 long alpha2 = long((radius2 - radius1) * 64.0);
202 while (alpha2 <= 0) alpha2 += 360*64;
203 while (alpha1 > 360*64) alpha1 -= 360*64;
204
205 if (m_brush.GetStyle() != wxTRANSPARENT)
206 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
207
208 if (m_pen.GetStyle() != wxTRANSPARENT)
209 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
210
903f689b 211}
c801d85f
KB
212
213void wxPaintDC::DrawEllipticArc( long x, long y, long width, long height, double sa, double ea )
214{
215 if (!Ok()) return;
216
c801d85f
KB
217 long xx = XLOG2DEV(x);
218 long yy = YLOG2DEV(y);
6f65e337
JS
219 long ww = m_signX * XLOG2DEVREL(width);
220 long hh = m_signY * YLOG2DEVREL(height);
c801d85f 221
6f65e337
JS
222 // CMB: handle -ve width and/or height
223 if (ww < 0) { ww = -ww; xx = xx - ww; }
224 if (hh < 0) { hh = -hh; yy = yy - hh; }
225
226 long start = long(sa * 64.0);
227 long end = long(ea * 64.0);
c801d85f 228 if (m_brush.GetStyle() != wxTRANSPARENT)
6f65e337 229 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
c801d85f
KB
230
231 if (m_pen.GetStyle() != wxTRANSPARENT)
6f65e337 232 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
903f689b 233}
c801d85f
KB
234
235void wxPaintDC::DrawPoint( long x, long y )
236{
237 if (!Ok()) return;
238
239 if (m_pen.GetStyle() != wxTRANSPARENT)
240 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
903f689b 241}
c801d85f
KB
242
243void wxPaintDC::DrawLines( int n, wxPoint points[], long xoffset, long yoffset )
244{
245 if (!Ok()) return;
246
247 if (m_pen.GetStyle() == wxTRANSPARENT) return;
248
249 for (int i = 0; i < n-1; i++)
250 {
251 long x1 = XLOG2DEV(points[i].x + xoffset);
252 long x2 = XLOG2DEV(points[i+1].x + xoffset);
253 long y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
254 long y2 = YLOG2DEV(points[i+1].y + yoffset);
4c681997 255 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
903f689b
RR
256 }
257}
c801d85f
KB
258
259void wxPaintDC::DrawLines( wxList *points, long xoffset, long yoffset )
260{
261 if (!Ok()) return;
262
263 if (m_pen.GetStyle() == wxTRANSPARENT) return;
264
265 wxNode *node = points->First();
266 while (node->Next())
267 {
268 wxPoint *point = (wxPoint*)node->Data();
269 wxPoint *npoint = (wxPoint*)node->Next()->Data();
270 long x1 = XLOG2DEV(point->x + xoffset);
271 long x2 = XLOG2DEV(npoint->x + xoffset);
272 long y1 = YLOG2DEV(point->y + yoffset); // and again...
273 long y2 = YLOG2DEV(npoint->y + yoffset);
4c681997 274 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
c801d85f 275 node = node->Next();
903f689b
RR
276 }
277}
c801d85f 278
cf7a7e13
RR
279void wxPaintDC::DrawPolygon( int n, wxPoint points[], long xoffset, long yoffset, int WXUNUSED(fillStyle) )
280{
281 if (!Ok()) return;
282
b6af8d80
RR
283 if (!n) return; // Nothing to draw
284 GdkPoint *gdkpoints = new GdkPoint[n+1];
285 int i;
286 for (i = 0 ; i < n ; i++)
287 {
288 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
289 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
290 }
291 if (m_brush.GetStyle() != wxTRANSPARENT)
292 gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n);
293 // To do: Fillstyle
294 if (m_pen.GetStyle() != wxTRANSPARENT)
295 for (i = 0 ; i < n ; i++)
296 gdk_draw_line( m_window, m_penGC,
297 gdkpoints[i%n].x,
298 gdkpoints[i%n].y,
299 gdkpoints[(i+1)%n].x,
300 gdkpoints[(i+1)%n].y);
301 delete[] gdkpoints;
903f689b 302}
c801d85f 303
cf7a7e13
RR
304void wxPaintDC::DrawPolygon( wxList *lines, long xoffset, long yoffset, int WXUNUSED(fillStyle))
305{
306 if (!Ok()) return;
307
b6af8d80 308 int n = lines->Number();
b6af8d80
RR
309 GdkPoint *gdkpoints = new GdkPoint[n];
310 wxNode *node = lines->First();
311 int cnt=0;
312 while (node)
313 {
314 wxPoint *p = (wxPoint *) node->Data();
315 gdkpoints[cnt].x = XLOG2DEV(p->x + xoffset);
316 gdkpoints[cnt].y = YLOG2DEV(p->y + yoffset);
317 node = node->Next();
318 cnt++;
319 }
320 if (m_brush.GetStyle() != wxTRANSPARENT)
321 gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n);
322 // To do: Fillstyle
323 if (m_pen.GetStyle() != wxTRANSPARENT)
324 {
325 int i;
326 for (i = 0 ; i < n ; i++)
327 gdk_draw_line( m_window, m_penGC,
328 gdkpoints[i%n].x,
329 gdkpoints[i%n].y,
330 gdkpoints[(i+1)%n].x,
331 gdkpoints[(i+1)%n].y);
332 }
333 delete[] gdkpoints;
903f689b 334}
c801d85f
KB
335
336void wxPaintDC::DrawRectangle( long x, long y, long width, long height )
337{
338 if (!Ok()) return;
339
340 long xx = XLOG2DEV(x);
341 long yy = YLOG2DEV(y);
6f65e337
JS
342 long ww = m_signX * XLOG2DEVREL(width);
343 long hh = m_signY * YLOG2DEVREL(height);
c801d85f 344
6f65e337
JS
345 // CMB: draw nothing if transformed w or h is 0
346 if (ww == 0 || hh == 0) return;
347
348 // CMB: handle -ve width and/or height
349 if (ww < 0) { ww = -ww; xx = xx - ww; }
350 if (hh < 0) { hh = -hh; yy = yy - hh; }
351
c801d85f
KB
352 if (m_brush.GetStyle() != wxTRANSPARENT)
353 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh );
354
355 if (m_pen.GetStyle() != wxTRANSPARENT)
356 gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
903f689b 357}
c801d85f
KB
358
359void wxPaintDC::DrawRoundedRectangle( long x, long y, long width, long height, double radius )
360{
361 if (!Ok()) return;
362
c801d85f
KB
363 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
364
365 long xx = XLOG2DEV(x);
366 long yy = YLOG2DEV(y);
6f65e337
JS
367 long ww = m_signX * XLOG2DEVREL(width);
368 long hh = m_signY * YLOG2DEVREL(height);
c801d85f 369 long rr = XLOG2DEVREL((long)radius);
6f65e337
JS
370
371 // CMB: handle -ve width and/or height
372 if (ww < 0) { ww = -ww; xx = xx - ww; }
373 if (hh < 0) { hh = -hh; yy = yy - hh; }
374
375 // CMB: if radius is zero use DrawRectangle() instead to avoid
376 // X drawing errors with small radii
377 if (rr == 0)
378 {
379 DrawRectangle( x, y, width, height );
380 return;
381 }
382
383 // CMB: draw nothing if transformed w or h is 0
384 if (ww == 0 || hh == 0) return;
385
386 // CMB: adjust size if outline is drawn otherwise the result is
387 // 1 pixel too wide and high
388 if (m_pen.GetStyle() != wxTRANSPARENT)
389 {
390 ww--;
391 hh--;
392 }
393
394 // CMB: ensure dd is not larger than rectangle otherwise we
395 // get an hour glass shape
c801d85f 396 long dd = 2 * rr;
6f65e337
JS
397 if (dd > ww) dd = ww;
398 if (dd > hh) dd = hh;
399 rr = dd / 2;
c801d85f
KB
400
401 if (m_brush.GetStyle() != wxTRANSPARENT)
402 {
6f65e337
JS
403 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
404 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
c801d85f
KB
405 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
406 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
407 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
408 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
903f689b 409 }
c801d85f
KB
410
411 if (m_pen.GetStyle() != wxTRANSPARENT)
412 {
413 gdk_draw_line( m_window, m_penGC, xx+rr, yy, xx+ww-rr, yy );
414 gdk_draw_line( m_window, m_penGC, xx+rr, yy+hh, xx+ww-rr, yy+hh );
415 gdk_draw_line( m_window, m_penGC, xx, yy+rr, xx, yy+hh-rr );
416 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr, xx+ww, yy+hh-rr );
417 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
418 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
419 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
420 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
903f689b
RR
421 }
422}
c801d85f
KB
423
424void wxPaintDC::DrawEllipse( long x, long y, long width, long height )
425{
426 if (!Ok()) return;
427
c801d85f
KB
428 long xx = XLOG2DEV(x);
429 long yy = YLOG2DEV(y);
6f65e337
JS
430 long ww = m_signX * XLOG2DEVREL(width);
431 long hh = m_signY * YLOG2DEVREL(height);
432
433 // CMB: handle -ve width and/or height
434 if (ww < 0) { ww = -ww; xx = xx - ww; }
435 if (hh < 0) { hh = -hh; yy = yy - hh; }
c801d85f
KB
436
437 if (m_brush.GetStyle() != wxTRANSPARENT)
438 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
439
440 if (m_pen.GetStyle() != wxTRANSPARENT)
441 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
903f689b 442}
c801d85f
KB
443
444bool wxPaintDC::CanDrawBitmap(void) const
445{
446 return TRUE;
903f689b 447}
c801d85f
KB
448
449void wxPaintDC::DrawIcon( const wxIcon &icon, long x, long y, bool useMask )
450{
451 if (!Ok()) return;
452
453 if (!icon.Ok()) return;
454
455 int xx = XLOG2DEV(x);
456 int yy = YLOG2DEV(y);
457
c67daf87 458 GdkBitmap *mask = (GdkBitmap *) NULL;
c801d85f
KB
459 if (icon.GetMask()) mask = icon.GetMask()->GetBitmap();
460
461 if (useMask && mask)
462 {
463 gdk_gc_set_clip_mask( m_penGC, mask );
464 gdk_gc_set_clip_origin( m_penGC, xx, yy );
903f689b 465 }
c801d85f
KB
466
467 GdkPixmap *pm = icon.GetPixmap();
468 gdk_draw_pixmap( m_window, m_penGC, pm, 0, 0, xx, yy, -1, -1 );
469
470 if (useMask && mask)
471 {
c67daf87 472 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
c801d85f 473 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
903f689b
RR
474 }
475}
c801d85f
KB
476
477bool wxPaintDC::Blit( long xdest, long ydest, long width, long height,
478 wxDC *source, long xsrc, long ysrc, int WXUNUSED(logical_func), bool WXUNUSED(useMask) )
479{
480 if (!Ok()) return FALSE;
481
fc54776e 482 if (m_isMemDC)
6f65e337
JS
483 {
484 wxMemoryDC* srcDC = (wxMemoryDC*)source;
cf7a7e13 485 GdkBitmap* bmap = srcDC->m_selected.GetBitmap();
6f65e337
JS
486 if (bmap)
487 {
cf7a7e13
RR
488 gdk_draw_bitmap( m_window, m_textGC, bmap,
489 source->DeviceToLogicalX(xsrc),
490 source->DeviceToLogicalY(ysrc),
491 XLOG2DEV(xdest),
492 YLOG2DEV(ydest),
493 source->DeviceToLogicalXRel(width),
494 source->DeviceToLogicalYRel(height) );
6f65e337
JS
495 return TRUE;
496 }
497 }
c801d85f 498
6f65e337 499 wxClientDC *csrc = (wxClientDC*)source;
c801d85f
KB
500 gdk_window_copy_area ( m_window, m_penGC,
501 XLOG2DEV(xdest), YLOG2DEV(ydest),
502 csrc->GetWindow(),
503 source->DeviceToLogicalX(xsrc), source->DeviceToLogicalY(ysrc),
504 source->DeviceToLogicalXRel(width), source->DeviceToLogicalYRel(height) );
505
506/*
507 gdk_window_copy_area ( m_window, m_penGC,
508 XLOG2DEV(xdest), YLOG2DEV(ydest),
509 csrc->GetWindow(),
510 xsrc, ysrc,
511 width, height );
512*/
513
514 return TRUE;
903f689b 515}
c801d85f 516
903f689b 517void wxPaintDC::DrawText( const wxString &text, long x, long y, bool WXUNUSED(use16) )
c801d85f
KB
518{
519 if (!Ok()) return;
18a2fa37 520
c801d85f 521 GdkFont *font = m_font.GetInternalFont( m_scaleY );
6f65e337 522
18a2fa37
KB
523 x = XLOG2DEV(x);
524 y = YLOG2DEV(y);
525
6f65e337
JS
526 // CMB 21/5/98: draw text background if mode is wxSOLID
527 if (m_backgroundMode == wxSOLID)
528 {
529 long width = gdk_string_width( font, text );
530 long height = font->ascent + font->descent;
531 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
532 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
533 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
534 }
18a2fa37
KB
535 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text );
536
537 // CMB 17/7/98: simple underline: ignores scaling and underlying
538 // X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
539 // properties (see wxXt implementation)
540 if (m_font.GetUnderlined())
541 {
542 long width = gdk_string_width( font, text );
543 long ul_y = y + font->ascent;
544 if (font->descent > 0) ul_y++;
545 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
546 }
903f689b 547}
c801d85f
KB
548
549bool wxPaintDC::CanGetTextExtent(void) const
550{
551 return TRUE;
903f689b 552}
c801d85f
KB
553
554void wxPaintDC::GetTextExtent( const wxString &string, long *width, long *height,
c33c4050
RR
555 long *descent, long *externalLeading,
556 wxFont *theFont, bool WXUNUSED(use16) )
c801d85f
KB
557{
558 if (!Ok()) return;
559
c33c4050
RR
560 wxFont fontToUse = m_font;
561 if (theFont) fontToUse = *theFont;
562
563 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
6f65e337
JS
564 if (width) (*width) = long(gdk_string_width( font, string ) / m_scaleX);
565 if (height) (*height) = long((font->ascent + font->descent) / m_scaleY);
c33c4050
RR
566 if (descent) (*descent) = long(font->descent / m_scaleY);
567 if (externalLeading) (*externalLeading) = 0; // ??
903f689b 568}
c801d85f
KB
569
570long wxPaintDC::GetCharWidth(void)
571{
572 if (!Ok()) return 0;
573
574 GdkFont *font = m_font.GetInternalFont( m_scaleY );
c33c4050 575 return long(gdk_string_width( font, "H" ) / m_scaleX);
903f689b 576}
c801d85f
KB
577
578long wxPaintDC::GetCharHeight(void)
579{
580 if (!Ok()) return 0;
581
582 GdkFont *font = m_font.GetInternalFont( m_scaleY );
c33c4050 583 return long((font->ascent + font->descent) / m_scaleY);
903f689b 584}
c801d85f
KB
585
586void wxPaintDC::Clear(void)
587{
588 if (!Ok()) return;
589
fc54776e 590 if (!m_isMemDC)
0180d5da
RR
591 {
592 gdk_window_clear( m_window );
593 }
594 else
595 {
596 int width = 0;
597 int height = 0;
598 GetSize( &width, &height );
54ff4a70 599 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
903f689b
RR
600 }
601}
c801d85f
KB
602
603void wxPaintDC::SetFont( const wxFont &font )
604{
605 if (!Ok()) return;
606
607 m_font = font;
903f689b 608}
c801d85f
KB
609
610void wxPaintDC::SetPen( const wxPen &pen )
611{
612 if (!Ok()) return;
613
614 if (m_pen == pen) return;
615
616 m_pen = pen;
617
618 if (!m_pen.Ok()) return;
619
620 gint width = m_pen.GetWidth();
6f65e337
JS
621 // CMB: if width is non-zero scale it with the dc
622 if (width <= 0)
623 {
624 width = 1;
625 }
626 else
627 {
628 // X doesn't allow different width in x and y and so we take
629 // the average
630 double w = 0.5 + (abs(XLOG2DEVREL(width)) + abs(YLOG2DEVREL(width))) / 2.0;
631 width = (int)w;
632 }
c801d85f
KB
633
634 GdkLineStyle lineStyle = GDK_LINE_SOLID;
635 switch (m_pen.GetStyle())
636 {
903f689b
RR
637 case wxSOLID: { lineStyle = GDK_LINE_SOLID; break; }
638 case wxDOT: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
639 case wxLONG_DASH: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
640 case wxSHORT_DASH: { lineStyle = GDK_LINE_ON_OFF_DASH; break; }
641 case wxDOT_DASH: { lineStyle = GDK_LINE_DOUBLE_DASH; break; }
642 }
c801d85f
KB
643
644 GdkCapStyle capStyle = GDK_CAP_ROUND;
645 switch (m_pen.GetCap())
646 {
903f689b
RR
647 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
648 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
649 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
650 }
c801d85f
KB
651
652 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
653 switch (m_pen.GetJoin())
654 {
903f689b
RR
655 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
656 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
657 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
658 }
c801d85f
KB
659
660 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
661
662 m_pen.GetColour().CalcPixel( m_cmap );
663 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
903f689b 664}
c801d85f
KB
665
666void wxPaintDC::SetBrush( const wxBrush &brush )
667{
668 if (!Ok()) return;
669
670 if (m_brush == brush) return;
671
672 m_brush = brush;
673
674 if (!m_brush.Ok()) return;
675
676 m_brush.GetColour().CalcPixel( m_cmap );
677 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
678
679 GdkFill fillStyle = GDK_SOLID;
680 switch (m_brush.GetStyle())
681 {
682 case wxSOLID:
683 case wxTRANSPARENT:
684 break;
685 default:
686 fillStyle = GDK_STIPPLED;
903f689b 687 }
c801d85f
KB
688
689 gdk_gc_set_fill( m_brushGC, fillStyle );
690
691 if (m_brush.GetStyle() == wxSTIPPLE)
692 {
693 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetPixmap() );
903f689b 694 }
c801d85f
KB
695
696 if (IS_HATCH(m_brush.GetStyle()))
697 {
698 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
699 gdk_gc_set_stipple( m_brushGC, hatches[num] );
903f689b
RR
700 }
701}
c801d85f 702
46dc76ba
RR
703// CMB 21/7/98: Added SetBackground. Sets background brush
704// for Clear() and bg colour for shapes filled with cross-hatch brush
705void wxPaintDC::SetBackground( const wxBrush &brush )
706{
707 if (!Ok()) return;
708
709 if (m_backgroundBrush == brush) return;
710
711 m_backgroundBrush = brush;
712
713 if (!m_backgroundBrush.Ok()) return;
714
715 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
716 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
717 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
718
719 GdkFill fillStyle = GDK_SOLID;
720 switch (m_backgroundBrush.GetStyle())
721 {
722 case wxSOLID:
723 case wxTRANSPARENT:
724 break;
725 default:
726 fillStyle = GDK_STIPPLED;
903f689b 727 }
46dc76ba
RR
728
729 gdk_gc_set_fill( m_bgGC, fillStyle );
730
731 if (m_backgroundBrush.GetStyle() == wxSTIPPLE)
732 {
733 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
903f689b 734 }
46dc76ba
RR
735
736 if (IS_HATCH(m_backgroundBrush.GetStyle()))
737 {
738 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
739 gdk_gc_set_stipple( m_bgGC, hatches[num] );
903f689b
RR
740 }
741}
46dc76ba 742
c801d85f
KB
743void wxPaintDC::SetLogicalFunction( int function )
744{
745 if (m_logicalFunction == function) return;
746 GdkFunction mode = GDK_COPY;
747 switch (function)
748 {
749 case wxXOR: mode = GDK_INVERT; break;
750 case wxINVERT: mode = GDK_INVERT; break;
751 default: break;
903f689b 752 }
c801d85f
KB
753 m_logicalFunction = function;
754 gdk_gc_set_function( m_penGC, mode );
755 gdk_gc_set_function( m_brushGC, mode );
903f689b 756}
c801d85f
KB
757
758void wxPaintDC::SetTextForeground( const wxColour &col )
759{
760 if (!Ok()) return;
761
762 if (m_textForegroundColour == col) return;
763
764 m_textForegroundColour = col;
765 if (!m_textForegroundColour.Ok()) return;
766
767 m_textForegroundColour.CalcPixel( m_cmap );
768 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
903f689b 769}
c801d85f
KB
770
771void wxPaintDC::SetTextBackground( const wxColour &col )
772{
773 if (!Ok()) return;
774
775 if (m_textBackgroundColour == col) return;
776
777 m_textBackgroundColour = col;
778 if (!m_textBackgroundColour.Ok()) return;
779
780 m_textBackgroundColour.CalcPixel( m_cmap );
781 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
903f689b 782}
c801d85f 783
6f65e337 784void wxPaintDC::SetBackgroundMode( int mode )
c801d85f 785{
6f65e337 786 m_backgroundMode = mode;
46dc76ba
RR
787
788 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
789 // transparent/solid background mode
790 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
791 {
792 gdk_gc_set_fill( m_brushGC,
793 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
794 }
903f689b 795}
c801d85f
KB
796
797void wxPaintDC::SetPalette( const wxPalette& WXUNUSED(palette) )
798{
903f689b 799}
c801d85f
KB
800
801void wxPaintDC::SetClippingRegion( long x, long y, long width, long height )
802{
803 wxDC::SetClippingRegion( x, y, width, height );
804
805 GdkRectangle rect;
806 rect.x = XLOG2DEV(x);
807 rect.y = YLOG2DEV(y);
903f689b
RR
808 rect.width = XLOG2DEVREL(width);
809 rect.height = YLOG2DEVREL(height);
c801d85f
KB
810 gdk_gc_set_clip_rectangle( m_penGC, &rect );
811 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
812 gdk_gc_set_clip_rectangle( m_textGC, &rect );
813 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
814
903f689b 815}
c801d85f
KB
816
817void wxPaintDC::DestroyClippingRegion(void)
818{
819 wxDC::DestroyClippingRegion();
820
c67daf87
UR
821 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
822 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
823 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
824 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
903f689b 825}
c801d85f
KB
826
827void wxPaintDC::SetUpDC(void)
828{
829 m_ok = TRUE;
830 m_logicalFunction = wxCOPY;
e3e65dac 831 if (m_penGC) gdk_gc_unref( m_penGC );
c801d85f 832 m_penGC = gdk_gc_new( m_window );
e3e65dac 833 if (m_brushGC) gdk_gc_unref( m_brushGC );
c801d85f 834 m_brushGC = gdk_gc_new( m_window );
e3e65dac 835 if (m_textGC) gdk_gc_unref( m_textGC );
c801d85f 836 m_textGC = gdk_gc_new( m_window );
e3e65dac 837 if (m_bgGC) gdk_gc_unref( m_bgGC );
c801d85f
KB
838 m_bgGC = gdk_gc_new( m_window );
839 SetTextForeground( m_textForegroundColour );
840 SetTextBackground( m_textBackgroundColour );
841 SetPen( m_pen );
842 SetFont( m_font );
843 SetBrush( m_brush );
844
845 gdk_gc_set_background( m_penGC, wxWHITE->GetColor() );
846
847 if (!hatch_bitmap)
848 {
849 hatch_bitmap = hatches;
c67daf87
UR
850 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
851 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
852 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
853 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
854 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
855 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
903f689b
RR
856 }
857}
c801d85f
KB
858
859GdkWindow *wxPaintDC::GetWindow(void)
860{
861 return m_window;
903f689b 862}
c801d85f
KB
863
864// ----------------------------------- spline code ----------------------------------------
865
866void wx_quadratic_spline(double a1, double b1, double a2, double b2,
867 double a3, double b3, double a4, double b4);
868void wx_clear_stack(void);
869int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
870 double *y3, double *x4, double *y4);
871void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
872 double x4, double y4);
873static bool wx_spline_add_point(double x, double y);
874static void wx_spline_draw_point_array(wxDC *dc);
875
876wxList wx_spline_point_list;
877
878#define half(z1, z2) ((z1+z2)/2.0)
879#define THRESHOLD 5
880
881/* iterative version */
882
883void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
884 double b4)
885{
886 register double xmid, ymid;
887 double x1, y1, x2, y2, x3, y3, x4, y4;
888
889 wx_clear_stack();
890 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
891
892 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
893 xmid = (double)half(x2, x3);
894 ymid = (double)half(y2, y3);
895 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
896 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
897 wx_spline_add_point( x1, y1 );
898 wx_spline_add_point( xmid, ymid );
899 } else {
900 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
901 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
902 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
903 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
904 }
905 }
906}
907
908/* utilities used by spline drawing routines */
909
910typedef struct wx_spline_stack_struct {
911 double x1, y1, x2, y2, x3, y3, x4, y4;
912} Stack;
913
914#define SPLINE_STACK_DEPTH 20
915static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
916static Stack *wx_stack_top;
917static int wx_stack_count;
918
919void wx_clear_stack(void)
920{
921 wx_stack_top = wx_spline_stack;
922 wx_stack_count = 0;
923}
924
925void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
926{
927 wx_stack_top->x1 = x1;
928 wx_stack_top->y1 = y1;
929 wx_stack_top->x2 = x2;
930 wx_stack_top->y2 = y2;
931 wx_stack_top->x3 = x3;
932 wx_stack_top->y3 = y3;
933 wx_stack_top->x4 = x4;
934 wx_stack_top->y4 = y4;
935 wx_stack_top++;
936 wx_stack_count++;
937}
938
939int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
940 double *x3, double *y3, double *x4, double *y4)
941{
942 if (wx_stack_count == 0)
943 return (0);
944 wx_stack_top--;
945 wx_stack_count--;
946 *x1 = wx_stack_top->x1;
947 *y1 = wx_stack_top->y1;
948 *x2 = wx_stack_top->x2;
949 *y2 = wx_stack_top->y2;
950 *x3 = wx_stack_top->x3;
951 *y3 = wx_stack_top->y3;
952 *x4 = wx_stack_top->x4;
953 *y4 = wx_stack_top->y4;
954 return (1);
955}
956
957static bool wx_spline_add_point(double x, double y)
958{
959 wxPoint *point = new wxPoint ;
960 point->x = (int) x;
961 point->y = (int) y;
962 wx_spline_point_list.Append((wxObject*)point);
963 return TRUE;
964}
965
966static void wx_spline_draw_point_array(wxDC *dc)
967{
968 dc->DrawLines(&wx_spline_point_list, 0, 0 );
969 wxNode *node = wx_spline_point_list.First();
970 while (node)
971 {
972 wxPoint *point = (wxPoint *)node->Data();
973 delete point;
974 delete node;
975 node = wx_spline_point_list.First();
976 }
977}
978
dfad0599 979void wxPaintDC::DrawSpline( wxList *points )
c801d85f
KB
980{
981 wxPoint *p;
982 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
983 double x1, y1, x2, y2;
984
985 wxNode *node = points->First();
986 p = (wxPoint *)node->Data();
987
988 x1 = p->x;
989 y1 = p->y;
990
991 node = node->Next();
992 p = (wxPoint *)node->Data();
993
994 x2 = p->x;
995 y2 = p->y;
996 cx1 = (double)((x1 + x2) / 2);
997 cy1 = (double)((y1 + y2) / 2);
998 cx2 = (double)((cx1 + x2) / 2);
999 cy2 = (double)((cy1 + y2) / 2);
1000
1001 wx_spline_add_point(x1, y1);
1002
1003 while ((node = node->Next()) != NULL)
1004 {
1005 p = (wxPoint *)node->Data();
1006 x1 = x2;
1007 y1 = y2;
1008 x2 = p->x;
1009 y2 = p->y;
1010 cx4 = (double)(x1 + x2) / 2;
1011 cy4 = (double)(y1 + y2) / 2;
1012 cx3 = (double)(x1 + cx4) / 2;
1013 cy3 = (double)(y1 + cy4) / 2;
1014
1015 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1016
1017 cx1 = cx4;
1018 cy1 = cy4;
1019 cx2 = (double)(cx1 + x2) / 2;
1020 cy2 = (double)(cy1 + y2) / 2;
1021 }
1022
1023 wx_spline_add_point( cx1, cy1 );
1024 wx_spline_add_point( x2, y2 );
1025
1026 wx_spline_draw_point_array( this );
903f689b 1027}