Rotated text patch from Hans-Joachim Baader (with some corrections)
[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 #include "wx/image.h"
17 #include "wx/gtk/win_gtk.h"
18
19 #include <math.h> // for floating-point functions
20 #include <gdk/gdk.h>
21 #include <gtk/gtk.h>
22
23 //-----------------------------------------------------------------------------
24 // local data
25 //-----------------------------------------------------------------------------
26
27 #include "bdiag.xbm"
28 #include "fdiag.xbm"
29 #include "cdiag.xbm"
30 #include "horiz.xbm"
31 #include "verti.xbm"
32 #include "cross.xbm"
33 #define num_hatches 6
34
35 static GdkPixmap *hatches[num_hatches];
36 static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL;
37
38 //-----------------------------------------------------------------------------
39 // constants
40 //-----------------------------------------------------------------------------
41
42 const double RAD2DEG = 180.0 / M_PI;
43
44 //-----------------------------------------------------------------------------
45 // temporary implementation of the missing GDK function
46 //-----------------------------------------------------------------------------
47
48 #include "gdk/gdkprivate.h"
49
50 void gdk_draw_bitmap (GdkDrawable *drawable,
51 GdkGC *gc,
52 GdkDrawable *src,
53 gint xsrc,
54 gint ysrc,
55 gint xdest,
56 gint ydest,
57 gint width,
58 gint height)
59 {
60 GdkWindowPrivate *drawable_private;
61 GdkWindowPrivate *src_private;
62 GdkGCPrivate *gc_private;
63
64 g_return_if_fail (drawable != NULL);
65 g_return_if_fail (src != NULL);
66 g_return_if_fail (gc != NULL);
67
68 drawable_private = (GdkWindowPrivate*) drawable;
69 src_private = (GdkWindowPrivate*) src;
70 if (drawable_private->destroyed || src_private->destroyed)
71 return;
72
73 gc_private = (GdkGCPrivate*) gc;
74
75 if (width == -1) width = src_private->width;
76 if (height == -1) height = src_private->height;
77
78 XCopyPlane( drawable_private->xdisplay,
79 src_private->xwindow,
80 drawable_private->xwindow,
81 gc_private->xgc,
82 xsrc, ysrc,
83 width, height,
84 xdest, ydest,
85 1 );
86 }
87
88 /*
89 * compare two doubles and return the larger rounded
90 * to the nearest int
91 */
92 static int roundmax(double a, double b)
93 {
94 return (int)((a > b ? a : b) + 0.5);
95 }
96
97 /*
98 * compare two doubles and return the smaller rounded
99 * to the nearest int
100 */
101 static int roundmin(double a, double b)
102 {
103 return (int)((a < b ? a : b) - 0.5);
104 }
105
106
107 //-----------------------------------------------------------------------------
108 // wxWindowDC
109 //-----------------------------------------------------------------------------
110
111 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
112
113 wxWindowDC::wxWindowDC()
114 {
115 m_penGC = (GdkGC *) NULL;
116 m_brushGC = (GdkGC *) NULL;
117 m_textGC = (GdkGC *) NULL;
118 m_bgGC = (GdkGC *) NULL;
119 m_cmap = (GdkColormap *) NULL;
120 m_isMemDC = FALSE;
121 m_owner = (wxWindow *)NULL;
122 }
123
124 wxWindowDC::wxWindowDC( wxWindow *window )
125 {
126 m_penGC = (GdkGC *) NULL;
127 m_brushGC = (GdkGC *) NULL;
128 m_textGC = (GdkGC *) NULL;
129 m_bgGC = (GdkGC *) NULL;
130 m_cmap = (GdkColormap *) NULL;
131 m_owner = (wxWindow *)NULL;
132 m_isMemDC = FALSE;
133 m_font = window->GetFont();
134
135 wxASSERT_MSG( window, wxT("DC needs a window") );
136
137 GtkWidget *widget = window->m_wxwindow;
138
139 wxASSERT_MSG( widget, wxT("DC needs a widget") );
140
141 GtkPizza *pizza = GTK_PIZZA( widget );
142 m_window = pizza->bin_window;
143
144 /* not realized ? */
145 if (!m_window)
146 {
147 /* don't report problems */
148 m_ok = TRUE;
149
150 return;
151 }
152
153 if (window->m_wxwindow)
154 m_cmap = gtk_widget_get_colormap( window->m_wxwindow );
155 else
156 m_cmap = gtk_widget_get_colormap( window->m_widget );
157
158 SetUpDC();
159
160 /* this must be done after SetUpDC, bacause SetUpDC calls the
161 repective SetBrush, SetPen, SetBackground etc functions
162 to set up the DC. SetBackground call m_owner->SetBackground
163 and this might not be desired as the standard dc background
164 is white whereas a window might assume gray to be the
165 standard (as e.g. wxStatusBar) */
166
167 m_owner = window;
168 }
169
170 wxWindowDC::~wxWindowDC()
171 {
172 Destroy();
173 }
174
175 void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
176 const wxColour &WXUNUSED(col), int WXUNUSED(style) )
177 {
178 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
179 }
180
181 bool wxWindowDC::DoGetPixel( wxCoord WXUNUSED(x1), wxCoord WXUNUSED(y1), wxColour *WXUNUSED(col) ) const
182 {
183 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
184 return FALSE;
185 }
186
187 void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
188 {
189 wxCHECK_RET( Ok(), wxT("invalid window dc") );
190
191 if (m_pen.GetStyle() != wxTRANSPARENT)
192 {
193 if (m_window)
194 gdk_draw_line( m_window, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
195
196 CalcBoundingBox(x1, y1);
197 CalcBoundingBox(x2, y2);
198 }
199 }
200
201 void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y )
202 {
203 wxCHECK_RET( Ok(), wxT("invalid window dc") );
204
205 if (m_pen.GetStyle() != wxTRANSPARENT)
206 {
207 int w = 0;
208 int h = 0;
209 GetSize( &w, &h );
210 wxCoord xx = XLOG2DEV(x);
211 wxCoord yy = YLOG2DEV(y);
212 if (m_window)
213 {
214 gdk_draw_line( m_window, m_penGC, 0, yy, XLOG2DEVREL(w), yy );
215 gdk_draw_line( m_window, m_penGC, xx, 0, xx, YLOG2DEVREL(h) );
216 }
217 }
218 }
219
220 void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
221 wxCoord xc, wxCoord yc )
222 {
223 wxCHECK_RET( Ok(), wxT("invalid window dc") );
224
225 wxCoord xx1 = XLOG2DEV(x1);
226 wxCoord yy1 = YLOG2DEV(y1);
227 wxCoord xx2 = XLOG2DEV(x2);
228 wxCoord yy2 = YLOG2DEV(y2);
229 wxCoord xxc = XLOG2DEV(xc);
230 wxCoord yyc = YLOG2DEV(yc);
231 double dx = xx1 - xxc;
232 double dy = yy1 - yyc;
233 double radius = sqrt((double)(dx*dx+dy*dy));
234 wxCoord r = (wxCoord)radius;
235 double radius1, radius2;
236
237 if (xx1 == xx2 && yy1 == yy2)
238 {
239 radius1 = 0.0;
240 radius2 = 360.0;
241 }
242 else
243 if (radius == 0.0)
244 {
245 radius1 = radius2 = 0.0;
246 }
247 else
248 {
249 radius1 = (xx1 - xxc == 0) ?
250 (yy1 - yyc < 0) ? 90.0 : -90.0 :
251 -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG;
252 radius2 = (xx2 - xxc == 0) ?
253 (yy2 - yyc < 0) ? 90.0 : -90.0 :
254 -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG;
255 }
256 wxCoord alpha1 = wxCoord(radius1 * 64.0);
257 wxCoord alpha2 = wxCoord((radius2 - radius1) * 64.0);
258 while (alpha2 <= 0) alpha2 += 360*64;
259 while (alpha1 > 360*64) alpha1 -= 360*64;
260
261 if (m_window)
262 {
263 if (m_brush.GetStyle() != wxTRANSPARENT)
264 gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
265
266 if (m_pen.GetStyle() != wxTRANSPARENT)
267 gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
268 }
269
270 CalcBoundingBox (x1, y1);
271 CalcBoundingBox (x2, y2);
272 }
273
274 void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea )
275 {
276 wxCHECK_RET( Ok(), wxT("invalid window dc") );
277
278 wxCoord xx = XLOG2DEV(x);
279 wxCoord yy = YLOG2DEV(y);
280 wxCoord ww = m_signX * XLOG2DEVREL(width);
281 wxCoord hh = m_signY * YLOG2DEVREL(height);
282
283 // CMB: handle -ve width and/or height
284 if (ww < 0) { ww = -ww; xx = xx - ww; }
285 if (hh < 0) { hh = -hh; yy = yy - hh; }
286
287 if (m_window)
288 {
289 wxCoord start = wxCoord(sa * 64.0);
290 wxCoord end = wxCoord(ea * 64.0);
291
292 if (m_brush.GetStyle() != wxTRANSPARENT)
293 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end );
294
295 if (m_pen.GetStyle() != wxTRANSPARENT)
296 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end );
297 }
298
299 CalcBoundingBox (x, y);
300 CalcBoundingBox (x + width, y + height);
301 }
302
303 void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y )
304 {
305 wxCHECK_RET( Ok(), wxT("invalid window dc") );
306
307 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
308 gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
309
310 CalcBoundingBox (x, y);
311 }
312
313 void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
314 {
315 wxCHECK_RET( Ok(), wxT("invalid window dc") );
316
317 if (m_pen.GetStyle() == wxTRANSPARENT) return;
318 if (n <= 0) return;
319
320 CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
321
322 for (int i = 0; i < n-1; i++)
323 {
324 wxCoord x1 = XLOG2DEV(points[i].x + xoffset);
325 wxCoord x2 = XLOG2DEV(points[i+1].x + xoffset);
326 wxCoord y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste
327 wxCoord y2 = YLOG2DEV(points[i+1].y + yoffset);
328
329 if (m_window)
330 gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 );
331
332 CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset );
333 }
334 }
335
336 void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
337 {
338 wxCHECK_RET( Ok(), wxT("invalid window dc") );
339
340 if (n <= 0) return;
341
342 GdkPoint *gdkpoints = new GdkPoint[n+1];
343 int i;
344 for (i = 0 ; i < n ; i++)
345 {
346 gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
347 gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
348
349 CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset );
350 }
351
352 if ((m_brush.GetStyle() != wxTRANSPARENT) && m_window)
353 gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n);
354
355 // To do: Fillstyle
356
357 if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window)
358 {
359 for (i = 0 ; i < n ; i++)
360 {
361 gdk_draw_line( m_window, m_penGC,
362 gdkpoints[i%n].x,
363 gdkpoints[i%n].y,
364 gdkpoints[(i+1)%n].x,
365 gdkpoints[(i+1)%n].y);
366 }
367 }
368
369 delete[] gdkpoints;
370 }
371
372 void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
373 {
374 wxCHECK_RET( Ok(), wxT("invalid window dc") );
375
376 wxCoord xx = XLOG2DEV(x);
377 wxCoord yy = YLOG2DEV(y);
378 wxCoord ww = m_signX * XLOG2DEVREL(width);
379 wxCoord hh = m_signY * YLOG2DEVREL(height);
380
381 // CMB: draw nothing if transformed w or h is 0
382 if (ww == 0 || hh == 0) return;
383
384 // CMB: handle -ve width and/or height
385 if (ww < 0) { ww = -ww; xx = xx - ww; }
386 if (hh < 0) { hh = -hh; yy = yy - hh; }
387
388 if (m_window)
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
397 CalcBoundingBox( x, y );
398 CalcBoundingBox( x + width, y + height );
399 }
400
401 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
402 {
403 wxCHECK_RET( Ok(), wxT("invalid window dc") );
404
405 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
406
407 wxCoord xx = XLOG2DEV(x);
408 wxCoord yy = YLOG2DEV(y);
409 wxCoord ww = m_signX * XLOG2DEVREL(width);
410 wxCoord hh = m_signY * YLOG2DEVREL(height);
411 wxCoord rr = XLOG2DEVREL((wxCoord)radius);
412
413 // CMB: handle -ve width and/or height
414 if (ww < 0) { ww = -ww; xx = xx - ww; }
415 if (hh < 0) { hh = -hh; yy = yy - hh; }
416
417 // CMB: if radius is zero use DrawRectangle() instead to avoid
418 // X drawing errors with small radii
419 if (rr == 0)
420 {
421 DrawRectangle( x, y, width, height );
422 return;
423 }
424
425 // CMB: draw nothing if transformed w or h is 0
426 if (ww == 0 || hh == 0) return;
427
428 // CMB: adjust size if outline is drawn otherwise the result is
429 // 1 pixel too wide and high
430 if (m_pen.GetStyle() != wxTRANSPARENT)
431 {
432 ww--;
433 hh--;
434 }
435
436 if (m_window)
437 {
438 // CMB: ensure dd is not larger than rectangle otherwise we
439 // get an hour glass shape
440 wxCoord dd = 2 * rr;
441 if (dd > ww) dd = ww;
442 if (dd > hh) dd = hh;
443 rr = dd / 2;
444
445 if (m_brush.GetStyle() != wxTRANSPARENT)
446 {
447 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh );
448 gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 );
449 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 );
450 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
451 gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
452 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
453 }
454
455 if (m_pen.GetStyle() != wxTRANSPARENT)
456 {
457 gdk_draw_line( m_window, m_penGC, xx+rr, yy, xx+ww-rr, yy );
458 gdk_draw_line( m_window, m_penGC, xx+rr, yy+hh, xx+ww-rr, yy+hh );
459 gdk_draw_line( m_window, m_penGC, xx, yy+rr, xx, yy+hh-rr );
460 gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr, xx+ww, yy+hh-rr );
461 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 );
462 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 );
463 gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 );
464 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 );
465 }
466 }
467
468 // this ignores the radius
469 CalcBoundingBox( x, y );
470 CalcBoundingBox( x + width, y + height );
471 }
472
473 void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
474 {
475 wxCHECK_RET( Ok(), wxT("invalid window dc") );
476
477 wxCoord xx = XLOG2DEV(x);
478 wxCoord yy = YLOG2DEV(y);
479 wxCoord ww = m_signX * XLOG2DEVREL(width);
480 wxCoord hh = m_signY * YLOG2DEVREL(height);
481
482 // CMB: handle -ve width and/or height
483 if (ww < 0) { ww = -ww; xx = xx - ww; }
484 if (hh < 0) { hh = -hh; yy = yy - hh; }
485
486 if (m_window)
487 {
488 if (m_brush.GetStyle() != wxTRANSPARENT)
489 gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 );
490
491 if (m_pen.GetStyle() != wxTRANSPARENT)
492 gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
493 }
494
495 CalcBoundingBox( x - width, y - height );
496 CalcBoundingBox( x + width, y + height );
497 }
498
499 void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
500 {
501 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
502 DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE );
503 }
504
505 void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
506 wxCoord x, wxCoord y,
507 bool useMask )
508 {
509 wxCHECK_RET( Ok(), wxT("invalid window dc") );
510
511 wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
512
513 /* scale/translate size and position */
514
515 int xx = XLOG2DEV(x);
516 int yy = YLOG2DEV(y);
517
518 int w = bitmap.GetWidth();
519 int h = bitmap.GetHeight();
520
521 CalcBoundingBox( x, y );
522 CalcBoundingBox( x + w, y + h );
523
524 if (!m_window) return;
525
526 int ww = XLOG2DEVREL(w);
527 int hh = YLOG2DEVREL(h);
528
529 /* scale bitmap if required */
530
531 wxBitmap use_bitmap;
532
533 if ((w != ww) || (h != hh))
534 {
535 wxImage image( bitmap );
536 image = image.Scale( ww, hh );
537
538 use_bitmap = image.ConvertToBitmap();
539 }
540 else
541 {
542 use_bitmap = bitmap;
543 }
544
545 /* apply mask if any */
546
547 GdkBitmap *mask = (GdkBitmap *) NULL;
548 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
549
550 if (useMask && mask)
551 {
552 gdk_gc_set_clip_mask( m_penGC, mask );
553 gdk_gc_set_clip_origin( m_penGC, xx, yy );
554 }
555
556 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
557
558 GdkPixmap *pm = use_bitmap.GetPixmap();
559 if (pm)
560 {
561 gdk_draw_pixmap( m_window, m_penGC, pm, 0, 0, xx, yy, -1, -1 );
562 }
563 else
564 {
565 GdkBitmap *bm = use_bitmap.GetBitmap();
566 if (bm)
567 {
568 gdk_draw_bitmap( m_window, m_penGC, bm, 0, 0, xx, yy, -1, -1 );
569 }
570 }
571
572 /* remove mask again if any */
573
574 if (useMask && mask)
575 {
576 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
577 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
578 }
579 }
580
581 bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
582 wxDC *source, wxCoord xsrc, wxCoord ysrc,
583 int logical_func, bool useMask )
584 {
585 /* this is the nth try to get this utterly useless function to
586 work. it now completely ignores the scaling or translation
587 of the source dc, but scales correctly on the target dc and
588 knows about possible mask information in a memory dc. */
589
590 wxCHECK_MSG( Ok(), FALSE, wxT("invalid window dc") );
591
592 wxCHECK_MSG( source, FALSE, wxT("invalid source dc") );
593
594 if (!m_window) return FALSE;
595
596 wxClientDC *srcDC = (wxClientDC*)source;
597 wxMemoryDC *memDC = (wxMemoryDC*)source;
598
599 bool use_bitmap_method = FALSE;
600
601 if (srcDC->m_isMemDC)
602 {
603 if (!memDC->m_selected.Ok()) return FALSE;
604
605 /* we use the "XCopyArea" way to copy a memory dc into
606 y different window if the memory dc BOTH
607 a) doesn't have any mask or its mask isn't used
608 b) it is clipped
609 c) is not 1-bit */
610
611 if (useMask && (memDC->m_selected.GetMask()))
612 {
613 /* we HAVE TO use the direct way for memory dcs
614 that have mask since the XCopyArea doesn't know
615 about masks */
616 use_bitmap_method = TRUE;
617 }
618 else if (memDC->m_selected.GetDepth() == 1)
619 {
620 /* we HAVE TO use the direct way for memory dcs
621 that are bitmaps because XCopyArea doesn't cope
622 with different bit depths */
623 use_bitmap_method = TRUE;
624 }
625 else if ((xsrc == 0) && (ysrc == 0) &&
626 (width == memDC->m_selected.GetWidth()) &&
627 (height == memDC->m_selected.GetHeight()))
628 {
629 /* we SHOULD use the direct way if all of the bitmap
630 in the memory dc is copied in which case XCopyArea
631 wouldn't be able able to boost performace by reducing
632 the area to be scaled */
633 use_bitmap_method = TRUE;
634 }
635 else
636 {
637 use_bitmap_method = FALSE;
638 }
639 }
640
641 CalcBoundingBox( xdest, ydest );
642 CalcBoundingBox( xdest + width, ydest + height );
643
644 int old_logical_func = m_logicalFunction;
645 SetLogicalFunction( logical_func );
646
647 if (use_bitmap_method)
648 {
649 /* scale/translate bitmap size */
650
651 wxCoord bm_width = memDC->m_selected.GetWidth();
652 wxCoord bm_height = memDC->m_selected.GetHeight();
653
654 wxCoord bm_ww = XLOG2DEVREL( bm_width );
655 wxCoord bm_hh = YLOG2DEVREL( bm_height );
656
657 /* scale bitmap if required */
658
659 wxBitmap use_bitmap;
660
661 if ((bm_width != bm_ww) || (bm_height != bm_hh))
662 {
663 wxImage image( memDC->m_selected );
664 image = image.Scale( bm_ww, bm_hh );
665
666 use_bitmap = image.ConvertToBitmap();
667 }
668 else
669 {
670 use_bitmap = memDC->m_selected;
671 }
672
673 /* scale/translate size and position */
674
675 wxCoord xx = XLOG2DEV(xdest);
676 wxCoord yy = YLOG2DEV(ydest);
677
678 wxCoord ww = XLOG2DEVREL(width);
679 wxCoord hh = YLOG2DEVREL(height);
680
681 /* apply mask if any */
682
683 GdkBitmap *mask = (GdkBitmap *) NULL;
684 if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap();
685
686 if (useMask && mask)
687 {
688 gdk_gc_set_clip_mask( m_penGC, mask );
689 gdk_gc_set_clip_origin( m_penGC, xx, yy );
690 }
691
692 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
693
694 GdkPixmap *pm = use_bitmap.GetPixmap();
695 if (pm)
696 {
697 gdk_draw_pixmap( m_window, m_penGC, pm, xsrc, ysrc, xx, yy, ww, hh );
698 }
699 else
700 {
701 GdkBitmap *bm = use_bitmap.GetBitmap();
702 if (bm)
703 {
704 /* we use the textGC here because blitting a bitmap is done
705 using the current text colour */
706 gdk_draw_bitmap( m_window, m_textGC, bm, xsrc, ysrc, xx, yy, ww, hh );
707 }
708 }
709
710 /* remove mask again if any */
711
712 if (useMask && mask)
713 {
714 gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL );
715 gdk_gc_set_clip_origin( m_penGC, 0, 0 );
716 }
717 }
718 else /* use_bitmap_method */
719 {
720 /* scale/translate size and position */
721
722 wxCoord xx = XLOG2DEV(xdest);
723 wxCoord yy = YLOG2DEV(ydest);
724
725 wxCoord ww = XLOG2DEVREL(width);
726 wxCoord hh = YLOG2DEVREL(height);
727
728 if ((width != ww) || (height != hh))
729 {
730 /* draw source window into a bitmap as we cannot scale
731 a window in contrast to a bitmap. this would actually
732 work with memory dcs as well, but we'd lose the mask
733 information and waste one step in this process since
734 a memory already has a bitmap. all this is slightly
735 inefficient as we could take an XImage directly from
736 an X window, but we'd then also have to care that
737 the window is not outside the screen (in which case
738 we'd get a BadMatch or what not).
739 Is a double XGetImage and combined XGetPixel and
740 XPutPixel really faster? I'm not sure. look at wxXt
741 for a different implementation of the same problem. */
742
743 wxBitmap bitmap( width, height );
744 gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0,
745 srcDC->GetWindow(),
746 xsrc, ysrc, width, height );
747
748 /* scale image */
749
750 wxImage image( bitmap );
751 image = image.Scale( ww, hh );
752
753 /* convert to bitmap */
754
755 bitmap = image.ConvertToBitmap();
756
757 /* draw scaled bitmap */
758
759 gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
760
761 }
762 else
763 {
764 /* no scaling and not a memory dc with a mask either */
765
766 gdk_window_copy_area( m_window, m_penGC, xx, yy,
767 srcDC->GetWindow(),
768 xsrc, ysrc, width, height );
769 }
770 }
771
772 SetLogicalFunction( old_logical_func );
773 return TRUE;
774 }
775
776 void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
777 {
778 wxCHECK_RET( Ok(), wxT("invalid window dc") );
779
780 if (!m_window) return;
781
782 GdkFont *font = m_font.GetInternalFont( m_scaleY );
783
784 wxCHECK_RET( font, wxT("invalid font") );
785
786 x = XLOG2DEV(x);
787 y = YLOG2DEV(y);
788
789 /* CMB 21/5/98: draw text background if mode is wxSOLID */
790 if (m_backgroundMode == wxSOLID)
791 {
792 wxCoord width = gdk_string_width( font, text.mbc_str() );
793 wxCoord height = font->ascent + font->descent;
794 gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() );
795 gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height );
796 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
797 }
798 gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() );
799
800 /* CMB 17/7/98: simple underline: ignores scaling and underlying
801 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
802 properties (see wxXt implementation) */
803 if (m_font.GetUnderlined())
804 {
805 long width = gdk_string_width( font, text.mbc_str() );
806 long ul_y = y + font->ascent;
807 if (font->descent > 0) ul_y++;
808 gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y);
809 }
810
811 long w, h;
812 GetTextExtent (text, &w, &h);
813 CalcBoundingBox (x + w, y + h);
814 CalcBoundingBox (x, y);
815 }
816
817 void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
818 {
819 if (angle == 0.0)
820 {
821 DrawText(text, x, y);
822 return;
823 }
824
825 wxCHECK_RET( Ok(), wxT("invalid window dc") );
826
827 if (!m_window) return;
828
829 GdkFont *font = m_font.GetInternalFont( m_scaleY );
830
831 wxCHECK_RET( font, wxT("invalid font") );
832
833 x = XLOG2DEV(x);
834 y = YLOG2DEV(y);
835
836 int cx = gdk_string_width( font, text.mbc_str() );
837 int cy = font->ascent + font->descent;
838
839 wxBitmap src(cx, cy);
840 wxMemoryDC dc;
841 dc.SelectObject(src);
842 dc.SetFont(GetFont());
843 dc.SetBackground(*wxWHITE_BRUSH);
844 dc.SetBrush(*wxBLACK_BRUSH);
845 dc.Clear();
846 dc.DrawText(text, 0, 0);
847 dc.SetFont(wxNullFont);
848
849 // Calculate the size of the rotated bounding box.
850 double dx = cos(angle / 180.0 * M_PI);
851 double dy = sin(angle / 180.0 * M_PI);
852 double x4 = -cy * dy;
853 double y4 = cy * dx;
854 double x3 = cx * dx;
855 double y3 = cx * dy;
856 double x2 = x3 + x4;
857 double y2 = y3 + y4;
858 double x1 = x;
859 double y1 = y;
860
861 // Create image from the source bitmap after writing the text into it.
862 wxImage image(src);
863
864 int minx = roundmin(0, roundmin(x4, roundmin(x2, x3)));
865 int miny = roundmin(0, roundmin(y4, roundmin(y2, y3)));
866 int maxx = roundmax(0, roundmax(x4, roundmax(x2, x3)));
867 int maxy = roundmax(0, roundmax(y4, roundmax(y2, y3)));
868
869 // This rotates counterclockwise around the top left corner.
870 for (int rx = minx; rx < maxx; rx++)
871 {
872 for (int ry = miny; ry < maxy; ry++)
873 {
874 // transform dest coords to source coords
875 int sx = (int) (rx * dx + ry * dy + 0.5);
876 int sy = (int) (ry * dx - rx * dy + 0.5);
877 if (sx >= 0 && sx < cx && sy >= 0 && sy < cy)
878 {
879 // draw black pixels, ignore white ones (i.e. transparent b/g)
880 if (image.GetRed(sx, sy) == 0)
881 {
882 DrawPoint(x1 + maxx - rx, cy + y1 - ry);
883 }
884 else
885 {
886 // Background
887 //DrawPoint(x1 + maxx - rx, cy + y1 + maxy - ry);
888 }
889 }
890 }
891 }
892
893 // TODO call CalcBoundingBox()
894 }
895
896 void wxWindowDC::DoGetTextExtent(const wxString &string,
897 wxCoord *width, wxCoord *height,
898 wxCoord *descent, wxCoord *externalLeading,
899 wxFont *theFont) const
900 {
901 wxFont fontToUse = m_font;
902 if (theFont) fontToUse = *theFont;
903
904 GdkFont *font = fontToUse.GetInternalFont( m_scaleY );
905 if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX);
906 if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY);
907 if (descent) (*descent) = wxCoord(font->descent / m_scaleY);
908 if (externalLeading) (*externalLeading) = 0; // ??
909 }
910
911 wxCoord wxWindowDC::GetCharWidth() const
912 {
913 GdkFont *font = m_font.GetInternalFont( m_scaleY );
914 wxCHECK_MSG( font, -1, wxT("invalid font") );
915
916 return wxCoord(gdk_string_width( font, "H" ) / m_scaleX);
917 }
918
919 wxCoord wxWindowDC::GetCharHeight() const
920 {
921 GdkFont *font = m_font.GetInternalFont( m_scaleY );
922 wxCHECK_MSG( font, -1, wxT("invalid font") );
923
924 return wxCoord((font->ascent + font->descent) / m_scaleY);
925 }
926
927 void wxWindowDC::Clear()
928 {
929 wxCHECK_RET( Ok(), wxT("invalid window dc") );
930
931 if (!m_window) return;
932
933 /* - we either are a memory dc or have a window as the
934 owner. anything else shouldn't happen.
935 - we don't use gdk_window_clear() as we don't set
936 the window's background colour anymore. it is too
937 much pain to keep the DC's and the window's back-
938 ground colour in synch. */
939
940 if (m_owner)
941 {
942 int width,height;
943 m_owner->GetSize( &width, &height );
944 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
945 return;
946 }
947
948 if (m_isMemDC)
949 {
950 int width,height;
951 GetSize( &width, &height );
952 gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height );
953 return;
954 }
955 }
956
957 void wxWindowDC::SetFont( const wxFont &font )
958 {
959 m_font = font;
960 }
961
962 void wxWindowDC::SetPen( const wxPen &pen )
963 {
964 wxCHECK_RET( Ok(), wxT("invalid window dc") );
965
966 if (m_pen == pen) return;
967
968 m_pen = pen;
969
970 if (!m_pen.Ok()) return;
971
972 if (!m_window) return;
973
974 gint width = m_pen.GetWidth();
975 if (width <= 0)
976 {
977 // CMB: if width is non-zero scale it with the dc
978 width = 1;
979 }
980 else
981 {
982 // X doesn't allow different width in x and y and so we take
983 // the average
984 double w = 0.5 +
985 ( fabs((double) XLOG2DEVREL(width)) +
986 fabs((double) YLOG2DEVREL(width)) ) / 2.0;
987 width = (int)w;
988 }
989
990 static const char dotted[] = {1, 1};
991 static const char short_dashed[] = {2, 2};
992 static const char wxCoord_dashed[] = {2, 4};
993 static const char dotted_dashed[] = {3, 3, 1, 3};
994
995 // We express dash pattern in pen width unit, so we are
996 // independent of zoom factor and so on...
997 int req_nb_dash;
998 const char *req_dash;
999
1000 GdkLineStyle lineStyle = GDK_LINE_SOLID;
1001 switch (m_pen.GetStyle())
1002 {
1003 case wxUSER_DASH:
1004 {
1005 lineStyle = GDK_LINE_ON_OFF_DASH;
1006 req_nb_dash = m_pen.GetDashCount();
1007 req_dash = m_pen.GetDash();
1008 break;
1009 }
1010 case wxDOT:
1011 {
1012 lineStyle = GDK_LINE_ON_OFF_DASH;
1013 req_nb_dash = 2;
1014 req_dash = dotted;
1015 break;
1016 }
1017 case wxLONG_DASH:
1018 {
1019 lineStyle = GDK_LINE_ON_OFF_DASH;
1020 req_nb_dash = 2;
1021 req_dash = wxCoord_dashed;
1022 break;
1023 }
1024 case wxSHORT_DASH:
1025 {
1026 lineStyle = GDK_LINE_ON_OFF_DASH;
1027 req_nb_dash = 2;
1028 req_dash = short_dashed;
1029 break;
1030 }
1031 case wxDOT_DASH:
1032 {
1033 // lineStyle = GDK_LINE_DOUBLE_DASH;
1034 lineStyle = GDK_LINE_ON_OFF_DASH;
1035 req_nb_dash = 4;
1036 req_dash = dotted_dashed;
1037 break;
1038 }
1039
1040 case wxTRANSPARENT:
1041 case wxSTIPPLE:
1042 case wxSOLID:
1043 default:
1044 {
1045 lineStyle = GDK_LINE_SOLID;
1046 req_dash = (wxDash*)NULL;
1047 req_nb_dash = 0;
1048 break;
1049 }
1050 }
1051
1052 #if (GTK_MINOR_VERSION > 0)
1053 if (req_dash && req_nb_dash)
1054 {
1055 char *real_req_dash = new char[req_nb_dash];
1056 if (real_req_dash)
1057 {
1058 for (int i = 0; i < req_nb_dash; i++)
1059 real_req_dash[i] = req_dash[i] * width;
1060 gdk_gc_set_dashes( m_penGC, 0, real_req_dash, req_nb_dash );
1061 delete[] real_req_dash;
1062 }
1063 else
1064 {
1065 // No Memory. We use non-scaled dash pattern...
1066 gdk_gc_set_dashes( m_penGC, 0, (char*)req_dash, req_nb_dash );
1067 }
1068 }
1069 #endif
1070
1071 GdkCapStyle capStyle = GDK_CAP_ROUND;
1072 switch (m_pen.GetCap())
1073 {
1074 case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; }
1075 case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; }
1076 case wxCAP_BUTT: { capStyle = GDK_CAP_BUTT; break; }
1077 }
1078
1079 GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
1080 switch (m_pen.GetJoin())
1081 {
1082 case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; }
1083 case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; }
1084 case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; }
1085 }
1086
1087 gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle );
1088
1089 m_pen.GetColour().CalcPixel( m_cmap );
1090 gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() );
1091 }
1092
1093 void wxWindowDC::SetBrush( const wxBrush &brush )
1094 {
1095 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1096
1097 if (m_brush == brush) return;
1098
1099 m_brush = brush;
1100
1101 if (!m_brush.Ok()) return;
1102
1103 if (!m_window) return;
1104
1105 m_brush.GetColour().CalcPixel( m_cmap );
1106 gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() );
1107
1108 gdk_gc_set_fill( m_brushGC, GDK_SOLID );
1109
1110 if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok()))
1111 {
1112 if (m_brush.GetStipple()->GetPixmap())
1113 {
1114 gdk_gc_set_fill( m_brushGC, GDK_TILED );
1115 gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() );
1116 }
1117 else
1118 {
1119 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1120 gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() );
1121 }
1122 }
1123
1124 if (IS_HATCH(m_brush.GetStyle()))
1125 {
1126 gdk_gc_set_fill( m_brushGC, GDK_STIPPLED );
1127 int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH;
1128 gdk_gc_set_stipple( m_brushGC, hatches[num] );
1129 }
1130 }
1131
1132 void wxWindowDC::SetBackground( const wxBrush &brush )
1133 {
1134 /* CMB 21/7/98: Added SetBackground. Sets background brush
1135 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1136
1137 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1138
1139 if (m_backgroundBrush == brush) return;
1140
1141 m_backgroundBrush = brush;
1142
1143 if (!m_backgroundBrush.Ok()) return;
1144
1145 if (!m_window) return;
1146
1147 m_backgroundBrush.GetColour().CalcPixel( m_cmap );
1148 gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
1149 gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
1150 gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1151 gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
1152
1153 gdk_gc_set_fill( m_bgGC, GDK_SOLID );
1154
1155 if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok()))
1156 {
1157 if (m_backgroundBrush.GetStipple()->GetPixmap())
1158 {
1159 gdk_gc_set_fill( m_bgGC, GDK_TILED );
1160 gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
1161 }
1162 else
1163 {
1164 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1165 gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() );
1166 }
1167 }
1168
1169 if (IS_HATCH(m_backgroundBrush.GetStyle()))
1170 {
1171 gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
1172 int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH;
1173 gdk_gc_set_stipple( m_bgGC, hatches[num] );
1174 }
1175 }
1176
1177 void wxWindowDC::SetLogicalFunction( int function )
1178 {
1179 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1180
1181 if (m_logicalFunction == function) return;
1182
1183 GdkFunction mode = GDK_COPY;
1184 switch (function)
1185 {
1186 case wxXOR: mode = GDK_XOR; break;
1187 case wxINVERT: mode = GDK_INVERT; break;
1188 #if (GTK_MINOR_VERSION > 0)
1189 case wxOR_REVERSE: mode = GDK_OR_REVERSE; break;
1190 case wxAND_REVERSE: mode = GDK_AND_REVERSE; break;
1191 case wxCLEAR: mode = GDK_CLEAR; break;
1192 case wxSET: mode = GDK_SET; break;
1193 case wxOR_INVERT: mode = GDK_OR_INVERT; break;
1194 case wxSRC_AND:
1195 case wxAND: mode = GDK_AND; break;
1196 case wxSRC_OR:
1197 case wxOR: mode = GDK_OR; break;
1198 case wxEQUIV: mode = GDK_EQUIV; break;
1199 case wxNAND: mode = GDK_NAND; break;
1200 case wxAND_INVERT: mode = GDK_AND_INVERT; break;
1201 case wxCOPY: mode = GDK_COPY; break;
1202 case wxNO_OP: mode = GDK_NOOP; break;
1203 case wxSRC_INVERT: mode = GDK_COPY_INVERT; break;
1204 #endif
1205 default:
1206 {
1207 wxFAIL_MSG( wxT("unsupported logical function") );
1208 break;
1209 }
1210 }
1211
1212 m_logicalFunction = function;
1213
1214 if (!m_window) return;
1215
1216 gdk_gc_set_function( m_penGC, mode );
1217 gdk_gc_set_function( m_brushGC, mode );
1218 gdk_gc_set_function( m_textGC, mode );
1219 }
1220
1221 void wxWindowDC::SetTextForeground( const wxColour &col )
1222 {
1223 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1224
1225 if (m_textForegroundColour == col) return;
1226
1227 m_textForegroundColour = col;
1228 if (!m_textForegroundColour.Ok()) return;
1229
1230 if (!m_window) return;
1231
1232 m_textForegroundColour.CalcPixel( m_cmap );
1233 gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() );
1234 }
1235
1236 void wxWindowDC::SetTextBackground( const wxColour &col )
1237 {
1238 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1239
1240 if (m_textBackgroundColour == col) return;
1241
1242 m_textBackgroundColour = col;
1243 if (!m_textBackgroundColour.Ok()) return;
1244
1245 if (!m_window) return;
1246
1247 m_textBackgroundColour.CalcPixel( m_cmap );
1248 gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() );
1249 }
1250
1251 void wxWindowDC::SetBackgroundMode( int mode )
1252 {
1253 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1254
1255 m_backgroundMode = mode;
1256
1257 if (!m_window) return;
1258
1259 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1260 // transparent/solid background mode
1261
1262 if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
1263 {
1264 gdk_gc_set_fill( m_brushGC,
1265 (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
1266 }
1267 }
1268
1269 void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) )
1270 {
1271 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1272 }
1273
1274 void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
1275 {
1276 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1277
1278 wxDC::DoSetClippingRegion( x, y, width, height );
1279
1280 if (!m_window) return;
1281
1282 GdkRectangle rect;
1283 rect.x = XLOG2DEV(x);
1284 rect.y = YLOG2DEV(y);
1285 rect.width = XLOG2DEVREL(width);
1286 rect.height = YLOG2DEVREL(height);
1287 gdk_gc_set_clip_rectangle( m_penGC, &rect );
1288 gdk_gc_set_clip_rectangle( m_brushGC, &rect );
1289 gdk_gc_set_clip_rectangle( m_textGC, &rect );
1290 gdk_gc_set_clip_rectangle( m_bgGC, &rect );
1291 }
1292
1293 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion &region )
1294 {
1295 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1296
1297 if (region.Empty())
1298 {
1299 DestroyClippingRegion();
1300 return;
1301 }
1302
1303 if (!m_window) return;
1304
1305 gdk_gc_set_clip_region( m_penGC, region.GetRegion() );
1306 gdk_gc_set_clip_region( m_brushGC, region.GetRegion() );
1307 gdk_gc_set_clip_region( m_textGC, region.GetRegion() );
1308 gdk_gc_set_clip_region( m_bgGC, region.GetRegion() );
1309 }
1310
1311 void wxWindowDC::DestroyClippingRegion()
1312 {
1313 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1314
1315 wxDC::DestroyClippingRegion();
1316
1317 if (!m_window) return;
1318
1319 gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
1320 gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
1321 gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
1322 gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
1323 }
1324
1325 void wxWindowDC::SetUpDC()
1326 {
1327 Destroy();
1328 m_ok = TRUE;
1329 m_logicalFunction = wxCOPY;
1330 m_penGC = gdk_gc_new( m_window );
1331 m_brushGC = gdk_gc_new( m_window );
1332 m_textGC = gdk_gc_new( m_window );
1333 m_bgGC = gdk_gc_new( m_window );
1334
1335 wxColour tmp_col( m_textForegroundColour );
1336 m_textForegroundColour = wxNullColour;
1337 SetTextForeground( tmp_col );
1338 tmp_col = m_textBackgroundColour;
1339 m_textBackgroundColour = wxNullColour;
1340 SetTextBackground( tmp_col );
1341
1342 wxPen tmp_pen( m_pen );
1343 m_pen = wxNullPen;
1344 SetPen( tmp_pen );
1345
1346 wxFont tmp_font( m_font );
1347 m_font = wxNullFont;
1348 SetFont( tmp_font );
1349
1350 wxBrush tmp_brush( m_brush );
1351 m_brush = wxNullBrush;
1352 SetBrush( tmp_brush );
1353
1354 /*
1355 tmp_brush = m_backgroundBrush;
1356 m_backgroundBrush = wxNullBrush;
1357 SetBackground( tmp_brush );
1358 */
1359 tmp_brush = m_backgroundBrush;
1360 m_backgroundBrush = wxNullBrush;
1361 SetBackground( *wxWHITE_BRUSH );
1362 m_backgroundBrush = tmp_brush;
1363
1364 if (!hatch_bitmap)
1365 {
1366 hatch_bitmap = hatches;
1367 hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height );
1368 hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height );
1369 hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height );
1370 hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height );
1371 hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height );
1372 hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height );
1373 }
1374 }
1375
1376 void wxWindowDC::Destroy()
1377 {
1378 if (m_penGC) gdk_gc_unref( m_penGC );
1379 m_penGC = (GdkGC*) NULL;
1380 if (m_brushGC) gdk_gc_unref( m_brushGC );
1381 m_brushGC = (GdkGC*) NULL;
1382 if (m_textGC) gdk_gc_unref( m_textGC );
1383 m_textGC = (GdkGC*) NULL;
1384 if (m_bgGC) gdk_gc_unref( m_bgGC );
1385 m_bgGC = (GdkGC*) NULL;
1386 }
1387
1388 void wxWindowDC::ComputeScaleAndOrigin()
1389 {
1390 /* CMB: copy scale to see if it changes */
1391 double origScaleX = m_scaleX;
1392 double origScaleY = m_scaleY;
1393
1394 wxDC::ComputeScaleAndOrigin();
1395
1396 /* CMB: if scale has changed call SetPen to recalulate the line width */
1397 if ((m_scaleX != origScaleX || m_scaleY != origScaleY) &&
1398 (m_pen.Ok()))
1399 {
1400 /* this is a bit artificial, but we need to force wxDC to think
1401 the pen has changed */
1402 wxPen pen = m_pen;
1403 m_pen = wxNullPen;
1404 SetPen( pen );
1405 }
1406 }
1407
1408 // Resolution in pixels per logical inch
1409 wxSize wxWindowDC::GetPPI() const
1410 {
1411 return wxSize(100, 100);
1412 }
1413
1414 int wxWindowDC::GetDepth() const
1415 {
1416 wxFAIL_MSG(wxT("not implemented"));
1417
1418 return -1;
1419 }
1420
1421 #if wxUSE_SPLINES
1422 // ----------------------------------- spline code ----------------------------------------
1423
1424 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1425 double a3, double b3, double a4, double b4);
1426 void wx_clear_stack();
1427 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1428 double *y3, double *x4, double *y4);
1429 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1430 double x4, double y4);
1431 static bool wx_spline_add_point(double x, double y);
1432 static void wx_spline_draw_point_array(wxDC *dc);
1433
1434 wxList wx_spline_point_list;
1435
1436 #define half(z1, z2) ((z1+z2)/2.0)
1437 #define THRESHOLD 5
1438
1439 /* iterative version */
1440
1441 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1442 double b4)
1443 {
1444 register double xmid, ymid;
1445 double x1, y1, x2, y2, x3, y3, x4, y4;
1446
1447 wx_clear_stack();
1448 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1449
1450 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1451 xmid = (double)half(x2, x3);
1452 ymid = (double)half(y2, y3);
1453 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1454 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1455 wx_spline_add_point( x1, y1 );
1456 wx_spline_add_point( xmid, ymid );
1457 } else {
1458 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1459 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1460 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1461 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1462 }
1463 }
1464 }
1465
1466 /* utilities used by spline drawing routines */
1467
1468 typedef struct wx_spline_stack_struct {
1469 double x1, y1, x2, y2, x3, y3, x4, y4;
1470 } Stack;
1471
1472 #define SPLINE_STACK_DEPTH 20
1473 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1474 static Stack *wx_stack_top;
1475 static int wx_stack_count;
1476
1477 void wx_clear_stack()
1478 {
1479 wx_stack_top = wx_spline_stack;
1480 wx_stack_count = 0;
1481 }
1482
1483 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1484 {
1485 wx_stack_top->x1 = x1;
1486 wx_stack_top->y1 = y1;
1487 wx_stack_top->x2 = x2;
1488 wx_stack_top->y2 = y2;
1489 wx_stack_top->x3 = x3;
1490 wx_stack_top->y3 = y3;
1491 wx_stack_top->x4 = x4;
1492 wx_stack_top->y4 = y4;
1493 wx_stack_top++;
1494 wx_stack_count++;
1495 }
1496
1497 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1498 double *x3, double *y3, double *x4, double *y4)
1499 {
1500 if (wx_stack_count == 0)
1501 return (0);
1502 wx_stack_top--;
1503 wx_stack_count--;
1504 *x1 = wx_stack_top->x1;
1505 *y1 = wx_stack_top->y1;
1506 *x2 = wx_stack_top->x2;
1507 *y2 = wx_stack_top->y2;
1508 *x3 = wx_stack_top->x3;
1509 *y3 = wx_stack_top->y3;
1510 *x4 = wx_stack_top->x4;
1511 *y4 = wx_stack_top->y4;
1512 return (1);
1513 }
1514
1515 static bool wx_spline_add_point(double x, double y)
1516 {
1517 wxPoint *point = new wxPoint ;
1518 point->x = (int) x;
1519 point->y = (int) y;
1520 wx_spline_point_list.Append((wxObject*)point);
1521 return TRUE;
1522 }
1523
1524 static void wx_spline_draw_point_array(wxDC *dc)
1525 {
1526 dc->DrawLines(&wx_spline_point_list, 0, 0 );
1527 wxNode *node = wx_spline_point_list.First();
1528 while (node)
1529 {
1530 wxPoint *point = (wxPoint *)node->Data();
1531 delete point;
1532 delete node;
1533 node = wx_spline_point_list.First();
1534 }
1535 }
1536
1537 void wxWindowDC::DoDrawSpline( wxList *points )
1538 {
1539 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1540
1541 wxPoint *p;
1542 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1543 double x1, y1, x2, y2;
1544
1545 wxNode *node = points->First();
1546 p = (wxPoint *)node->Data();
1547
1548 x1 = p->x;
1549 y1 = p->y;
1550
1551 node = node->Next();
1552 p = (wxPoint *)node->Data();
1553
1554 x2 = p->x;
1555 y2 = p->y;
1556 cx1 = (double)((x1 + x2) / 2);
1557 cy1 = (double)((y1 + y2) / 2);
1558 cx2 = (double)((cx1 + x2) / 2);
1559 cy2 = (double)((cy1 + y2) / 2);
1560
1561 wx_spline_add_point(x1, y1);
1562
1563 while ((node = node->Next()) != NULL)
1564 {
1565 p = (wxPoint *)node->Data();
1566 x1 = x2;
1567 y1 = y2;
1568 x2 = p->x;
1569 y2 = p->y;
1570 cx4 = (double)(x1 + x2) / 2;
1571 cy4 = (double)(y1 + y2) / 2;
1572 cx3 = (double)(x1 + cx4) / 2;
1573 cy3 = (double)(y1 + cy4) / 2;
1574
1575 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1576
1577 cx1 = cx4;
1578 cy1 = cy4;
1579 cx2 = (double)(cx1 + x2) / 2;
1580 cy2 = (double)(cy1 + y2) / 2;
1581 }
1582
1583 wx_spline_add_point( cx1, cy1 );
1584 wx_spline_add_point( x2, y2 );
1585
1586 wx_spline_draw_point_array( this );
1587 }
1588
1589 #endif // wxUSE_SPLINE
1590
1591 //-----------------------------------------------------------------------------
1592 // wxPaintDC
1593 //-----------------------------------------------------------------------------
1594
1595 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC)
1596
1597 wxPaintDC::wxPaintDC()
1598 : wxWindowDC()
1599 {
1600 }
1601
1602 wxPaintDC::wxPaintDC( wxWindow *win )
1603 : wxWindowDC( win )
1604 {
1605 }
1606
1607 //-----------------------------------------------------------------------------
1608 // wxClientDC
1609 //-----------------------------------------------------------------------------
1610
1611 IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC)
1612
1613 wxClientDC::wxClientDC()
1614 : wxWindowDC()
1615 {
1616 }
1617
1618 wxClientDC::wxClientDC( wxWindow *win )
1619 : wxWindowDC( win )
1620 {
1621 }
1622