Removed usage of GdkImlib
[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 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
81 //-----------------------------------------------------------------------------
82 // wxPaintDC
83 //-----------------------------------------------------------------------------
84
85 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxDC)
86
87 wxPaintDC::wxPaintDC(void)
88 {
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;
94 m_isMemDC = FALSE;
95 }
96
97 wxPaintDC::wxPaintDC( wxWindow *window )
98 {
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;
104
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 );
114
115 m_isMemDC = FALSE;
116
117 SetUpDC();
118 }
119
120 wxPaintDC::~wxPaintDC(void)
121 {
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
147 void 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) );
162 }
163 }
164
165 void 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;
199 }
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
211 }
212
213 void wxPaintDC::DrawEllipticArc( long x, long y, long width, long height, double sa, double ea )
214 {
215 if (!Ok()) return;
216
217 long xx = XLOG2DEV(x);
218 long yy = YLOG2DEV(y);
219 long ww = m_signX * XLOG2DEVREL(width);
220 long hh = m_signY * YLOG2DEVREL(height);
221
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);
228 if (m_brush.GetStyle() != wxTRANSPARENT)
229 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
230
231 if (m_pen.GetStyle() != wxTRANSPARENT)
232 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
233 }
234
235 void 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) );
241 }
242
243 void 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);
255 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
256 }
257 }
258
259 void 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);
274 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
275 node = node->Next();
276 }
277 }
278
279 void wxPaintDC::DrawPolygon( int n, wxPoint points[], long xoffset, long yoffset, int WXUNUSED(fillStyle) )
280 {
281 if (!Ok()) return;
282
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;
302 }
303
304 void wxPaintDC::DrawPolygon( wxList *lines, long xoffset, long yoffset, int WXUNUSED(fillStyle))
305 {
306 if (!Ok()) return;
307
308 int n = lines->Number();
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;
334 }
335
336 void 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);
342 long ww = m_signX * XLOG2DEVREL(width);
343 long hh = m_signY * YLOG2DEVREL(height);
344
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
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 );
357 }
358
359 void wxPaintDC::DrawRoundedRectangle( long x, long y, long width, long height, double radius )
360 {
361 if (!Ok()) return;
362
363 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
364
365 long xx = XLOG2DEV(x);
366 long yy = YLOG2DEV(y);
367 long ww = m_signX * XLOG2DEVREL(width);
368 long hh = m_signY * YLOG2DEVREL(height);
369 long rr = XLOG2DEVREL((long)radius);
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
396 long dd = 2 * rr;
397 if (dd > ww) dd = ww;
398 if (dd > hh) dd = hh;
399 rr = dd / 2;
400
401 if (m_brush.GetStyle() != wxTRANSPARENT)
402 {
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 );
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 );
409 }
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 );
421 }
422 }
423
424 void wxPaintDC::DrawEllipse( long x, long y, long width, long height )
425 {
426 if (!Ok()) return;
427
428 long xx = XLOG2DEV(x);
429 long yy = YLOG2DEV(y);
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; }
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 );
442 }
443
444 bool wxPaintDC::CanDrawBitmap(void) const
445 {
446 return TRUE;
447 }
448
449 void 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
458 GdkBitmap *mask = (GdkBitmap *) NULL;
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 );
465 }
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 {
472 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
473 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
474 }
475 }
476
477 bool 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
482 if (m_isMemDC)
483 {
484 wxMemoryDC* srcDC = (wxMemoryDC*)source;
485 GdkBitmap* bmap = srcDC->m_selected.GetBitmap();
486 if (bmap)
487 {
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) );
495 return TRUE;
496 }
497 }
498
499 wxClientDC *csrc = (wxClientDC*)source;
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;
515 }
516
517 void wxPaintDC::DrawText( const wxString &text, long x, long y, bool WXUNUSED(use16) )
518 {
519 if (!Ok()) return;
520
521 GdkFont *font = m_font.GetInternalFont( m_scaleY );
522
523 x = XLOG2DEV(x);
524 y = YLOG2DEV(y);
525
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 }
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 }
547 }
548
549 bool wxPaintDC::CanGetTextExtent(void) const
550 {
551 return TRUE;
552 }
553
554 void wxPaintDC::GetTextExtent( const wxString &string, long *width, long *height,
555 long *descent, long *externalLeading,
556 wxFont *theFont, bool WXUNUSED(use16) )
557 {
558 if (!Ok()) return;
559
560 wxFont fontToUse = m_font;
561 if (theFont) fontToUse = *theFont;
562
563 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
564 if (width) (*width) = long(gdk_string_width( font, string ) / m_scaleX);
565 if (height) (*height) = long((font->ascent + font->descent) / m_scaleY);
566 if (descent) (*descent) = long(font->descent / m_scaleY);
567 if (externalLeading) (*externalLeading) = 0; // ??
568 }
569
570 long wxPaintDC::GetCharWidth(void)
571 {
572 if (!Ok()) return 0;
573
574 GdkFont *font = m_font.GetInternalFont( m_scaleY );
575 return long(gdk_string_width( font, "H" ) / m_scaleX);
576 }
577
578 long wxPaintDC::GetCharHeight(void)
579 {
580 if (!Ok()) return 0;
581
582 GdkFont *font = m_font.GetInternalFont( m_scaleY );
583 return long((font->ascent + font->descent) / m_scaleY);
584 }
585
586 void wxPaintDC::Clear(void)
587 {
588 if (!Ok()) return;
589
590 if (!m_isMemDC)
591 {
592 gdk_window_clear( m_window );
593 }
594 else
595 {
596 int width = 0;
597 int height = 0;
598 GetSize( &width, &height );
599 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
600 }
601 }
602
603 void wxPaintDC::SetFont( const wxFont &font )
604 {
605 if (!Ok()) return;
606
607 m_font = font;
608 }
609
610 void 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();
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 }
633
634 GdkLineStyle lineStyle = GDK_LINE_SOLID;
635 switch (m_pen.GetStyle())
636 {
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 }
643
644 GdkCapStyle capStyle = GDK_CAP_ROUND;
645 switch (m_pen.GetCap())
646 {
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 }
651
652 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
653 switch (m_pen.GetJoin())
654 {
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 }
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() );
664 }
665
666 void 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;
687 }
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() );
694 }
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] );
700 }
701 }
702
703 // CMB 21/7/98: Added SetBackground. Sets background brush
704 // for Clear() and bg colour for shapes filled with cross-hatch brush
705 void 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;
727 }
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() );
734 }
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] );
740 }
741 }
742
743 void 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;
752 }
753 m_logicalFunction = function;
754 gdk_gc_set_function( m_penGC, mode );
755 gdk_gc_set_function( m_brushGC, mode );
756 }
757
758 void 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() );
769 }
770
771 void 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() );
782 }
783
784 void wxPaintDC::SetBackgroundMode( int mode )
785 {
786 m_backgroundMode = mode;
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 }
795 }
796
797 void wxPaintDC::SetPalette( const wxPalette& WXUNUSED(palette) )
798 {
799 }
800
801 void 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);
808 rect.width = XLOG2DEVREL(width);
809 rect.height = YLOG2DEVREL(height);
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
815 }
816
817 void wxPaintDC::DestroyClippingRegion(void)
818 {
819 wxDC::DestroyClippingRegion();
820
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 );
825 }
826
827 void wxPaintDC::SetUpDC(void)
828 {
829 m_ok = TRUE;
830 m_logicalFunction = wxCOPY;
831 if (m_penGC) gdk_gc_unref( m_penGC );
832 m_penGC = gdk_gc_new( m_window );
833 if (m_brushGC) gdk_gc_unref( m_brushGC );
834 m_brushGC = gdk_gc_new( m_window );
835 if (m_textGC) gdk_gc_unref( m_textGC );
836 m_textGC = gdk_gc_new( m_window );
837 if (m_bgGC) gdk_gc_unref( m_bgGC );
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;
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 );
856 }
857 }
858
859 GdkWindow *wxPaintDC::GetWindow(void)
860 {
861 return m_window;
862 }
863
864 // ----------------------------------- spline code ----------------------------------------
865
866 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
867 double a3, double b3, double a4, double b4);
868 void wx_clear_stack(void);
869 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
870 double *y3, double *x4, double *y4);
871 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
872 double x4, double y4);
873 static bool wx_spline_add_point(double x, double y);
874 static void wx_spline_draw_point_array(wxDC *dc);
875
876 wxList wx_spline_point_list;
877
878 #define half(z1, z2) ((z1+z2)/2.0)
879 #define THRESHOLD 5
880
881 /* iterative version */
882
883 void 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
910 typedef struct wx_spline_stack_struct {
911 double x1, y1, x2, y2, x3, y3, x4, y4;
912 } Stack;
913
914 #define SPLINE_STACK_DEPTH 20
915 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
916 static Stack *wx_stack_top;
917 static int wx_stack_count;
918
919 void wx_clear_stack(void)
920 {
921 wx_stack_top = wx_spline_stack;
922 wx_stack_count = 0;
923 }
924
925 void 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
939 int 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
957 static 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
966 static 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
979 void wxPaintDC::DrawSpline( wxList *points )
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 );
1027 }