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