1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "dcclient.h"
14 #include "wx/dcclient.h"
15 #include "wx/dcmemory.h"
17 #include "wx/gtk/win_gtk.h"
19 #include <math.h> // for floating-point functions
23 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
35 static GdkPixmap
*hatches
[num_hatches
];
36 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
42 const double RAD2DEG
= 180.0 / M_PI
;
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
49 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
51 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
53 //-----------------------------------------------------------------------------
54 // temporary implementation of the missing GDK function
55 //-----------------------------------------------------------------------------
57 #include "gdk/gdkprivate.h"
59 void gdk_draw_bitmap (GdkDrawable
*drawable
,
69 GdkWindowPrivate
*drawable_private
;
70 GdkWindowPrivate
*src_private
;
71 GdkGCPrivate
*gc_private
;
73 g_return_if_fail (drawable
!= NULL
);
74 g_return_if_fail (src
!= NULL
);
75 g_return_if_fail (gc
!= NULL
);
77 drawable_private
= (GdkWindowPrivate
*) drawable
;
78 src_private
= (GdkWindowPrivate
*) src
;
79 if (drawable_private
->destroyed
|| src_private
->destroyed
)
82 gc_private
= (GdkGCPrivate
*) gc
;
84 if (width
== -1) width
= src_private
->width
;
85 if (height
== -1) height
= src_private
->height
;
87 XCopyPlane( drawable_private
->xdisplay
,
89 drawable_private
->xwindow
,
97 //-----------------------------------------------------------------------------
99 //-----------------------------------------------------------------------------
101 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
103 wxWindowDC::wxWindowDC()
105 m_penGC
= (GdkGC
*) NULL
;
106 m_brushGC
= (GdkGC
*) NULL
;
107 m_textGC
= (GdkGC
*) NULL
;
108 m_bgGC
= (GdkGC
*) NULL
;
109 m_cmap
= (GdkColormap
*) NULL
;
111 m_owner
= (wxWindow
*)NULL
;
114 wxWindowDC::wxWindowDC( wxWindow
*window
)
116 m_penGC
= (GdkGC
*) NULL
;
117 m_brushGC
= (GdkGC
*) NULL
;
118 m_textGC
= (GdkGC
*) NULL
;
119 m_bgGC
= (GdkGC
*) NULL
;
120 m_cmap
= (GdkColormap
*) NULL
;
121 m_owner
= (wxWindow
*)NULL
;
123 m_font
= window
->GetFont();
125 wxASSERT_MSG( window
, wxT("DC needs a window") );
127 GtkWidget
*widget
= window
->m_wxwindow
;
129 // some controls don't have m_wxwindow - like wxStaticBox, but the user
130 // code should still be able to create wxClientDCs for them, so we will
131 // use the parent window here then
134 window
= window
->GetParent();
135 widget
= window
->m_wxwindow
;
138 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
140 GtkPizza
*pizza
= GTK_PIZZA( widget
);
141 m_window
= pizza
->bin_window
;
146 /* don't report problems */
152 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
156 /* this must be done after SetUpDC, bacause SetUpDC calls the
157 repective SetBrush, SetPen, SetBackground etc functions
158 to set up the DC. SetBackground call m_owner->SetBackground
159 and this might not be desired as the standard dc background
160 is white whereas a window might assume gray to be the
161 standard (as e.g. wxStatusBar) */
166 wxWindowDC::~wxWindowDC()
171 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
172 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
174 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
177 bool wxWindowDC::DoGetPixel( wxCoord
WXUNUSED(x1
), wxCoord
WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
179 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
183 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
185 wxCHECK_RET( Ok(), wxT("invalid window dc") );
187 if (m_pen
.GetStyle() != wxTRANSPARENT
)
190 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
192 CalcBoundingBox(x1
, y1
);
193 CalcBoundingBox(x2
, y2
);
197 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
199 wxCHECK_RET( Ok(), wxT("invalid window dc") );
201 if (m_pen
.GetStyle() != wxTRANSPARENT
)
206 wxCoord xx
= XLOG2DEV(x
);
207 wxCoord yy
= YLOG2DEV(y
);
210 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
211 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
216 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
217 wxCoord xc
, wxCoord yc
)
219 wxCHECK_RET( Ok(), wxT("invalid window dc") );
221 wxCoord xx1
= XLOG2DEV(x1
);
222 wxCoord yy1
= YLOG2DEV(y1
);
223 wxCoord xx2
= XLOG2DEV(x2
);
224 wxCoord yy2
= YLOG2DEV(y2
);
225 wxCoord xxc
= XLOG2DEV(xc
);
226 wxCoord yyc
= YLOG2DEV(yc
);
227 double dx
= xx1
- xxc
;
228 double dy
= yy1
- yyc
;
229 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
230 wxCoord r
= (wxCoord
)radius
;
231 double radius1
, radius2
;
233 if (xx1
== xx2
&& yy1
== yy2
)
241 radius1
= radius2
= 0.0;
245 radius1
= (xx1
- xxc
== 0) ?
246 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
247 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
248 radius2
= (xx2
- xxc
== 0) ?
249 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
250 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
252 wxCoord alpha1
= wxCoord(radius1
* 64.0);
253 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
254 while (alpha2
<= 0) alpha2
+= 360*64;
255 while (alpha1
> 360*64) alpha1
-= 360*64;
259 if (m_brush
.GetStyle() != wxTRANSPARENT
)
260 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
262 if (m_pen
.GetStyle() != wxTRANSPARENT
)
263 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
266 CalcBoundingBox (x1
, y1
);
267 CalcBoundingBox (x2
, y2
);
270 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
272 wxCHECK_RET( Ok(), wxT("invalid window dc") );
274 wxCoord xx
= XLOG2DEV(x
);
275 wxCoord yy
= YLOG2DEV(y
);
276 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
277 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
279 // CMB: handle -ve width and/or height
280 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
281 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
285 wxCoord start
= wxCoord(sa
* 64.0);
286 wxCoord end
= wxCoord(ea
* 64.0);
288 if (m_brush
.GetStyle() != wxTRANSPARENT
)
289 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
291 if (m_pen
.GetStyle() != wxTRANSPARENT
)
292 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
295 CalcBoundingBox (x
, y
);
296 CalcBoundingBox (x
+ width
, y
+ height
);
299 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
301 wxCHECK_RET( Ok(), wxT("invalid window dc") );
303 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
304 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
306 CalcBoundingBox (x
, y
);
309 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
311 wxCHECK_RET( Ok(), wxT("invalid window dc") );
313 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
316 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
318 for (int i
= 0; i
< n
-1; i
++)
320 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
321 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
322 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
323 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
326 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
328 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
332 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
334 wxCHECK_RET( Ok(), wxT("invalid window dc") );
338 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
340 for (i
= 0 ; i
< n
; i
++)
342 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
343 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
345 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
350 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
351 gdk_draw_polygon (m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
354 if ((m_brush
.GetStyle() != wxTRANSPARENT
))
355 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
361 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
363 for (i
= 0 ; i
< n
; i
++)
365 gdk_draw_line( m_window
, m_penGC
,
368 gdkpoints
[(i
+1)%n
].x
,
369 gdkpoints
[(i
+1)%n
].y
);
376 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
378 wxCHECK_RET( Ok(), wxT("invalid window dc") );
380 wxCoord xx
= XLOG2DEV(x
);
381 wxCoord yy
= YLOG2DEV(y
);
382 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
383 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
385 // CMB: draw nothing if transformed w or h is 0
386 if (ww
== 0 || hh
== 0) return;
388 // CMB: handle -ve width and/or height
389 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
390 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
394 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
396 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
397 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
401 if (m_brush
.GetStyle() != wxTRANSPARENT
)
402 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
404 if (m_pen
.GetStyle() != wxTRANSPARENT
)
405 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
409 CalcBoundingBox( x
, y
);
410 CalcBoundingBox( x
+ width
, y
+ height
);
413 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
415 wxCHECK_RET( Ok(), wxT("invalid window dc") );
417 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
419 wxCoord xx
= XLOG2DEV(x
);
420 wxCoord yy
= YLOG2DEV(y
);
421 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
422 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
423 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
425 // CMB: handle -ve width and/or height
426 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
427 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
429 // CMB: if radius is zero use DrawRectangle() instead to avoid
430 // X drawing errors with small radii
433 DrawRectangle( x
, y
, width
, height
);
437 // CMB: draw nothing if transformed w or h is 0
438 if (ww
== 0 || hh
== 0) return;
440 // CMB: adjust size if outline is drawn otherwise the result is
441 // 1 pixel too wide and high
442 if (m_pen
.GetStyle() != wxTRANSPARENT
)
450 // CMB: ensure dd is not larger than rectangle otherwise we
451 // get an hour glass shape
453 if (dd
> ww
) dd
= ww
;
454 if (dd
> hh
) dd
= hh
;
457 if (m_brush
.GetStyle() != wxTRANSPARENT
)
459 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
460 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
461 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
462 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
463 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
464 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
467 if (m_pen
.GetStyle() != wxTRANSPARENT
)
469 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
470 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
471 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
472 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
473 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
474 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
475 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
476 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
480 // this ignores the radius
481 CalcBoundingBox( x
, y
);
482 CalcBoundingBox( x
+ width
, y
+ height
);
485 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
487 wxCHECK_RET( Ok(), wxT("invalid window dc") );
489 wxCoord xx
= XLOG2DEV(x
);
490 wxCoord yy
= YLOG2DEV(y
);
491 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
492 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
494 // CMB: handle -ve width and/or height
495 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
496 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
500 if (m_brush
.GetStyle() != wxTRANSPARENT
)
501 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
503 if (m_pen
.GetStyle() != wxTRANSPARENT
)
504 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
507 CalcBoundingBox( x
- width
, y
- height
);
508 CalcBoundingBox( x
+ width
, y
+ height
);
511 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
513 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
514 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
517 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
518 wxCoord x
, wxCoord y
,
521 wxCHECK_RET( Ok(), wxT("invalid window dc") );
523 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
525 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
527 /* scale/translate size and position */
529 int xx
= XLOG2DEV(x
);
530 int yy
= YLOG2DEV(y
);
532 int w
= bitmap
.GetWidth();
533 int h
= bitmap
.GetHeight();
535 CalcBoundingBox( x
, y
);
536 CalcBoundingBox( x
+ w
, y
+ h
);
538 if (!m_window
) return;
540 int ww
= XLOG2DEVREL(w
);
541 int hh
= YLOG2DEVREL(h
);
543 /* scale bitmap if required */
547 if ((w
!= ww
) || (h
!= hh
))
549 wxImage
image( bitmap
);
550 image
.Rescale( ww
, hh
);
552 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
554 use_bitmap
= image
.ConvertToBitmap();
561 /* apply mask if any */
563 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
564 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
570 gdk_gc_set_clip_mask( m_textGC
, mask
);
571 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
575 gdk_gc_set_clip_mask( m_penGC
, mask
);
576 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
580 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
581 drawing a mono-bitmap (XBitmap) we use the current text GC */
583 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
585 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
587 /* remove mask again if any */
593 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
594 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
598 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
599 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
604 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
605 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
606 int logical_func
, bool useMask
)
608 /* this is the nth try to get this utterly useless function to
609 work. it now completely ignores the scaling or translation
610 of the source dc, but scales correctly on the target dc and
611 knows about possible mask information in a memory dc. */
613 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
615 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
617 if (!m_window
) return FALSE
;
619 wxClientDC
*srcDC
= (wxClientDC
*)source
;
620 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
622 bool use_bitmap_method
= FALSE
;
623 bool is_mono
= FALSE
;
625 if (srcDC
->m_isMemDC
)
627 if (!memDC
->m_selected
.Ok()) return FALSE
;
629 /* we use the "XCopyArea" way to copy a memory dc into
630 y different window if the memory dc BOTH
631 a) doesn't have any mask or its mask isn't used
635 if (useMask
&& (memDC
->m_selected
.GetMask()))
637 /* we HAVE TO use the direct way for memory dcs
638 that have mask since the XCopyArea doesn't know
640 use_bitmap_method
= TRUE
;
642 else if (memDC
->m_selected
.GetDepth() == 1)
644 /* we HAVE TO use the direct way for memory dcs
645 that are bitmaps because XCopyArea doesn't cope
646 with different bit depths */
648 use_bitmap_method
= TRUE
;
650 else if ((xsrc
== 0) && (ysrc
== 0) &&
651 (width
== memDC
->m_selected
.GetWidth()) &&
652 (height
== memDC
->m_selected
.GetHeight()))
654 /* we SHOULD use the direct way if all of the bitmap
655 in the memory dc is copied in which case XCopyArea
656 wouldn't be able able to boost performace by reducing
657 the area to be scaled */
658 use_bitmap_method
= TRUE
;
662 use_bitmap_method
= FALSE
;
666 CalcBoundingBox( xdest
, ydest
);
667 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
669 int old_logical_func
= m_logicalFunction
;
670 SetLogicalFunction( logical_func
);
672 if (use_bitmap_method
)
674 /* scale/translate bitmap size */
676 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
677 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
679 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
680 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
682 /* scale bitmap if required */
686 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
688 wxImage
image( memDC
->m_selected
);
689 image
= image
.Scale( bm_ww
, bm_hh
);
692 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
694 use_bitmap
= image
.ConvertToBitmap();
698 use_bitmap
= memDC
->m_selected
;
701 /* scale/translate size and position */
703 wxCoord xx
= XLOG2DEV(xdest
);
704 wxCoord yy
= YLOG2DEV(ydest
);
706 wxCoord ww
= XLOG2DEVREL(width
);
707 wxCoord hh
= YLOG2DEVREL(height
);
709 /* apply mask if any */
711 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
712 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
718 gdk_gc_set_clip_mask( m_textGC
, mask
);
719 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
723 gdk_gc_set_clip_mask( m_penGC
, mask
);
724 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
728 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
729 drawing a mono-bitmap (XBitmap) we use the current text GC */
731 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
733 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
735 /* remove mask again if any */
741 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
742 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
746 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
747 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
751 else /* use_bitmap_method */
753 /* scale/translate size and position */
755 wxCoord xx
= XLOG2DEV(xdest
);
756 wxCoord yy
= YLOG2DEV(ydest
);
758 wxCoord ww
= XLOG2DEVREL(width
);
759 wxCoord hh
= YLOG2DEVREL(height
);
761 if ((width
!= ww
) || (height
!= hh
))
763 /* draw source window into a bitmap as we cannot scale
764 a window in contrast to a bitmap. this would actually
765 work with memory dcs as well, but we'd lose the mask
766 information and waste one step in this process since
767 a memory already has a bitmap. all this is slightly
768 inefficient as we could take an XImage directly from
769 an X window, but we'd then also have to care that
770 the window is not outside the screen (in which case
771 we'd get a BadMatch or what not).
772 Is a double XGetImage and combined XGetPixel and
773 XPutPixel really faster? I'm not sure. look at wxXt
774 for a different implementation of the same problem. */
776 wxBitmap
bitmap( width
, height
);
777 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
779 xsrc
, ysrc
, width
, height
);
783 wxImage
image( bitmap
);
784 image
= image
.Scale( ww
, hh
);
786 /* convert to bitmap */
788 bitmap
= image
.ConvertToBitmap();
790 /* draw scaled bitmap */
792 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
797 /* no scaling and not a memory dc with a mask either */
799 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
801 xsrc
, ysrc
, width
, height
);
805 SetLogicalFunction( old_logical_func
);
809 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
811 wxCHECK_RET( Ok(), wxT("invalid window dc") );
813 if (!m_window
) return;
815 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
817 wxCHECK_RET( font
, wxT("invalid font") );
822 /* CMB 21/5/98: draw text background if mode is wxSOLID */
823 if (m_backgroundMode
== wxSOLID
)
825 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
826 wxCoord height
= font
->ascent
+ font
->descent
;
827 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
828 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
829 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
831 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
833 /* CMB 17/7/98: simple underline: ignores scaling and underlying
834 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
835 properties (see wxXt implementation) */
836 if (m_font
.GetUnderlined())
838 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
839 wxCoord ul_y
= y
+ font
->ascent
;
840 if (font
->descent
> 0) ul_y
++;
841 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
845 GetTextExtent (text
, &w
, &h
);
846 CalcBoundingBox (x
+ w
, y
+ h
);
847 CalcBoundingBox (x
, y
);
850 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
854 DrawText(text
, x
, y
);
858 wxCHECK_RET( Ok(), wxT("invalid window dc") );
860 if (!m_window
) return;
862 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
864 wxCHECK_RET( font
, wxT("invalid font") );
866 // the size of the text
867 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
868 wxCoord h
= font
->ascent
+ font
->descent
;
870 // draw the string normally
873 dc
.SelectObject(src
);
874 dc
.SetFont(GetFont());
875 dc
.SetBackground(*wxWHITE_BRUSH
);
876 dc
.SetBrush(*wxBLACK_BRUSH
);
878 dc
.DrawText(text
, 0, 0);
879 dc
.SetFont(wxNullFont
);
880 dc
.SelectObject(wxNullBitmap
);
882 // Calculate the size of the rotated bounding box.
883 double rad
= DegToRad(angle
);
884 double dx
= cos(rad
),
887 // the rectngle vertices are counted clockwise with the first one being at
888 // (0, 0) (or, rather, at (x, y))
890 y2
= -w
*dy
; // y axis points to the bottom, hence minus
897 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
898 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
899 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
900 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
902 // prepare to blit-with-rotate the bitmap to the DC
905 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
906 *colBack
= m_textBackgroundColour
.GetColor();
908 bool textColSet
= TRUE
;
910 unsigned char *data
= image
.GetData();
912 // paint pixel by pixel
913 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
915 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
917 // transform source coords to dest coords
918 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
919 double angleOrig
= atan2(srcY
, srcX
) - rad
;
920 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
921 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
924 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
925 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
927 // change colour if needed
928 if ( textPixel
!= textColSet
)
930 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
933 textColSet
= textPixel
;
936 // don't use DrawPoint() because it uses the current pen
937 // colour, and we don't need it here
938 gdk_draw_point( m_window
, m_textGC
,
939 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
944 // it would be better to draw with non underlined font and draw the line
945 // manually here (it would be more straight...)
947 if ( m_font
.GetUnderlined() )
949 gdk_draw_line( m_window
, m_textGC
,
950 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
951 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
955 // restore the font colour
956 gdk_gc_set_foreground( m_textGC
, colText
);
958 // update the bounding box
959 CalcBoundingBox(x
+ minX
, y
+ minY
);
960 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
963 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
964 wxCoord
*width
, wxCoord
*height
,
965 wxCoord
*descent
, wxCoord
*externalLeading
,
966 wxFont
*theFont
) const
968 wxFont fontToUse
= m_font
;
969 if (theFont
) fontToUse
= *theFont
;
971 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
972 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
973 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
974 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
975 if (externalLeading
) (*externalLeading
) = 0; // ??
978 wxCoord
wxWindowDC::GetCharWidth() const
980 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
981 wxCHECK_MSG( font
, -1, wxT("invalid font") );
983 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
986 wxCoord
wxWindowDC::GetCharHeight() const
988 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
989 wxCHECK_MSG( font
, -1, wxT("invalid font") );
991 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
994 void wxWindowDC::Clear()
996 wxCHECK_RET( Ok(), wxT("invalid window dc") );
998 if (!m_window
) return;
1000 /* - we either are a memory dc or have a window as the
1001 owner. anything else shouldn't happen.
1002 - we don't use gdk_window_clear() as we don't set
1003 the window's background colour anymore. it is too
1004 much pain to keep the DC's and the window's back-
1005 ground colour in synch. */
1010 m_owner
->GetSize( &width
, &height
);
1011 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1018 GetSize( &width
, &height
);
1019 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1024 void wxWindowDC::SetFont( const wxFont
&font
)
1029 void wxWindowDC::SetPen( const wxPen
&pen
)
1031 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1033 if (m_pen
== pen
) return;
1037 if (!m_pen
.Ok()) return;
1039 if (!m_window
) return;
1041 gint width
= m_pen
.GetWidth();
1044 // CMB: if width is non-zero scale it with the dc
1049 // X doesn't allow different width in x and y and so we take
1052 ( fabs((double) XLOG2DEVREL(width
)) +
1053 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1057 static const char dotted
[] = {1, 1};
1058 static const char short_dashed
[] = {2, 2};
1059 static const char wxCoord_dashed
[] = {2, 4};
1060 static const char dotted_dashed
[] = {3, 3, 1, 3};
1062 // We express dash pattern in pen width unit, so we are
1063 // independent of zoom factor and so on...
1065 const char *req_dash
;
1067 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1068 switch (m_pen
.GetStyle())
1072 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1073 req_nb_dash
= m_pen
.GetDashCount();
1074 req_dash
= m_pen
.GetDash();
1079 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1086 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1088 req_dash
= wxCoord_dashed
;
1093 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1095 req_dash
= short_dashed
;
1100 // lineStyle = GDK_LINE_DOUBLE_DASH;
1101 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1103 req_dash
= dotted_dashed
;
1108 case wxSTIPPLE_MASK_OPAQUE
:
1113 lineStyle
= GDK_LINE_SOLID
;
1114 req_dash
= (wxDash
*)NULL
;
1120 #if (GTK_MINOR_VERSION > 0)
1121 if (req_dash
&& req_nb_dash
)
1123 char *real_req_dash
= new char[req_nb_dash
];
1126 for (int i
= 0; i
< req_nb_dash
; i
++)
1127 real_req_dash
[i
] = req_dash
[i
] * width
;
1128 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1129 delete[] real_req_dash
;
1133 // No Memory. We use non-scaled dash pattern...
1134 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1139 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1140 switch (m_pen
.GetCap())
1142 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1143 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1150 capStyle
= GDK_CAP_NOT_LAST
;
1154 capStyle
= GDK_CAP_ROUND
;
1160 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1161 switch (m_pen
.GetJoin())
1163 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1164 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1166 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1169 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1171 m_pen
.GetColour().CalcPixel( m_cmap
);
1172 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1175 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1177 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1179 if (m_brush
== brush
) return;
1183 if (!m_brush
.Ok()) return;
1185 if (!m_window
) return;
1187 m_brush
.GetColour().CalcPixel( m_cmap
);
1188 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1190 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1192 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1194 if (m_brush
.GetStipple()->GetPixmap())
1196 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1197 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1201 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1202 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1206 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1208 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1209 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1212 if (IS_HATCH(m_brush
.GetStyle()))
1214 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1215 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1216 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1220 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1222 /* CMB 21/7/98: Added SetBackground. Sets background brush
1223 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1225 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1227 if (m_backgroundBrush
== brush
) return;
1229 m_backgroundBrush
= brush
;
1231 if (!m_backgroundBrush
.Ok()) return;
1233 if (!m_window
) return;
1235 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1236 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1237 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1238 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1239 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1241 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1243 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1245 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1247 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1248 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1252 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1253 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1257 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1259 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1260 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1261 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1265 void wxWindowDC::SetLogicalFunction( int function
)
1267 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1269 if (m_logicalFunction
== function
)
1272 // VZ: shouldn't this be a CHECK?
1276 GdkFunction mode
= GDK_COPY
;
1279 case wxXOR
: mode
= GDK_XOR
; break;
1280 case wxINVERT
: mode
= GDK_INVERT
; break;
1281 #if (GTK_MINOR_VERSION > 0)
1282 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1283 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1284 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1285 case wxSET
: mode
= GDK_SET
; break;
1286 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1287 case wxAND
: mode
= GDK_AND
; break;
1288 case wxOR
: mode
= GDK_OR
; break;
1289 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1290 case wxNAND
: mode
= GDK_NAND
; break;
1291 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1292 case wxCOPY
: mode
= GDK_COPY
; break;
1293 case wxNO_OP
: mode
= GDK_NOOP
; break;
1294 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1296 // unsupported by GTK
1297 case wxNOR
: mode
= GDK_COPY
; break;
1301 wxFAIL_MSG( wxT("unsupported logical function") );
1306 m_logicalFunction
= function
;
1308 gdk_gc_set_function( m_penGC
, mode
);
1309 gdk_gc_set_function( m_brushGC
, mode
);
1311 // to stay compatible with wxMSW, we don't apply ROPs to the text
1312 // operations (i.e. DrawText/DrawRotatedText)
1313 // gdk_gc_set_function( m_textGC, mode );
1316 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1318 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1320 if (m_textForegroundColour
== col
) return;
1322 m_textForegroundColour
= col
;
1323 if (!m_textForegroundColour
.Ok()) return;
1325 if (!m_window
) return;
1327 m_textForegroundColour
.CalcPixel( m_cmap
);
1328 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1331 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1333 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1335 if (m_textBackgroundColour
== col
) return;
1337 m_textBackgroundColour
= col
;
1338 if (!m_textBackgroundColour
.Ok()) return;
1340 if (!m_window
) return;
1342 m_textBackgroundColour
.CalcPixel( m_cmap
);
1343 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1346 void wxWindowDC::SetBackgroundMode( int mode
)
1348 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1350 m_backgroundMode
= mode
;
1352 if (!m_window
) return;
1354 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1355 // transparent/solid background mode
1357 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1359 gdk_gc_set_fill( m_brushGC
,
1360 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1364 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1366 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1369 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1371 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1373 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1375 if (!m_window
) return;
1378 rect
.x
= XLOG2DEV(x
);
1379 rect
.y
= YLOG2DEV(y
);
1380 rect
.width
= XLOG2DEVREL(width
);
1381 rect
.height
= YLOG2DEVREL(height
);
1382 gdk_gc_set_clip_rectangle( m_penGC
, &rect
);
1383 gdk_gc_set_clip_rectangle( m_brushGC
, &rect
);
1384 gdk_gc_set_clip_rectangle( m_textGC
, &rect
);
1385 gdk_gc_set_clip_rectangle( m_bgGC
, &rect
);
1388 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1390 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1394 DestroyClippingRegion();
1399 region
.GetBox( x
, y
, w
, h
);
1401 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
1403 if (!m_window
) return;
1405 gdk_gc_set_clip_region( m_penGC
, region
.GetRegion() );
1406 gdk_gc_set_clip_region( m_brushGC
, region
.GetRegion() );
1407 gdk_gc_set_clip_region( m_textGC
, region
.GetRegion() );
1408 gdk_gc_set_clip_region( m_bgGC
, region
.GetRegion() );
1411 void wxWindowDC::DestroyClippingRegion()
1413 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1415 wxDC::DestroyClippingRegion();
1417 if (!m_window
) return;
1419 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1420 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1421 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1422 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1425 void wxWindowDC::SetUpDC()
1429 m_logicalFunction
= wxCOPY
;
1430 m_penGC
= gdk_gc_new( m_window
);
1431 m_brushGC
= gdk_gc_new( m_window
);
1432 m_textGC
= gdk_gc_new( m_window
);
1433 m_bgGC
= gdk_gc_new( m_window
);
1435 wxColour
tmp_col( m_textForegroundColour
);
1436 m_textForegroundColour
= wxNullColour
;
1437 SetTextForeground( tmp_col
);
1438 tmp_col
= m_textBackgroundColour
;
1439 m_textBackgroundColour
= wxNullColour
;
1440 SetTextBackground( tmp_col
);
1442 wxPen
tmp_pen( m_pen
);
1446 wxFont
tmp_font( m_font
);
1447 m_font
= wxNullFont
;
1448 SetFont( tmp_font
);
1450 wxBrush
tmp_brush( m_brush
);
1451 m_brush
= wxNullBrush
;
1452 SetBrush( tmp_brush
);
1455 tmp_brush = m_backgroundBrush;
1456 m_backgroundBrush = wxNullBrush;
1457 SetBackground( tmp_brush );
1459 tmp_brush
= m_backgroundBrush
;
1460 m_backgroundBrush
= wxNullBrush
;
1461 SetBackground( *wxWHITE_BRUSH
);
1462 m_backgroundBrush
= tmp_brush
;
1466 hatch_bitmap
= hatches
;
1467 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1468 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1469 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1470 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1471 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1472 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1476 void wxWindowDC::Destroy()
1478 if (m_penGC
) gdk_gc_unref( m_penGC
);
1479 m_penGC
= (GdkGC
*) NULL
;
1480 if (m_brushGC
) gdk_gc_unref( m_brushGC
);
1481 m_brushGC
= (GdkGC
*) NULL
;
1482 if (m_textGC
) gdk_gc_unref( m_textGC
);
1483 m_textGC
= (GdkGC
*) NULL
;
1484 if (m_bgGC
) gdk_gc_unref( m_bgGC
);
1485 m_bgGC
= (GdkGC
*) NULL
;
1488 void wxWindowDC::ComputeScaleAndOrigin()
1490 /* CMB: copy scale to see if it changes */
1491 double origScaleX
= m_scaleX
;
1492 double origScaleY
= m_scaleY
;
1494 wxDC::ComputeScaleAndOrigin();
1496 /* CMB: if scale has changed call SetPen to recalulate the line width */
1497 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1500 /* this is a bit artificial, but we need to force wxDC to think
1501 the pen has changed */
1508 // Resolution in pixels per logical inch
1509 wxSize
wxWindowDC::GetPPI() const
1511 return wxSize(100, 100);
1514 int wxWindowDC::GetDepth() const
1516 wxFAIL_MSG(wxT("not implemented"));
1522 // ----------------------------------- spline code ----------------------------------------
1524 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1525 double a3
, double b3
, double a4
, double b4
);
1526 void wx_clear_stack();
1527 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1528 double *y3
, double *x4
, double *y4
);
1529 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1530 double x4
, double y4
);
1531 static bool wx_spline_add_point(double x
, double y
);
1532 static void wx_spline_draw_point_array(wxDC
*dc
);
1534 wxList wx_spline_point_list
;
1536 #define half(z1, z2) ((z1+z2)/2.0)
1539 /* iterative version */
1541 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1544 register double xmid
, ymid
;
1545 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1548 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1550 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1551 xmid
= (double)half(x2
, x3
);
1552 ymid
= (double)half(y2
, y3
);
1553 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1554 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1555 wx_spline_add_point( x1
, y1
);
1556 wx_spline_add_point( xmid
, ymid
);
1558 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1559 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1560 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1561 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1566 /* utilities used by spline drawing routines */
1568 typedef struct wx_spline_stack_struct
{
1569 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1572 #define SPLINE_STACK_DEPTH 20
1573 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1574 static Stack
*wx_stack_top
;
1575 static int wx_stack_count
;
1577 void wx_clear_stack()
1579 wx_stack_top
= wx_spline_stack
;
1583 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1585 wx_stack_top
->x1
= x1
;
1586 wx_stack_top
->y1
= y1
;
1587 wx_stack_top
->x2
= x2
;
1588 wx_stack_top
->y2
= y2
;
1589 wx_stack_top
->x3
= x3
;
1590 wx_stack_top
->y3
= y3
;
1591 wx_stack_top
->x4
= x4
;
1592 wx_stack_top
->y4
= y4
;
1597 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1598 double *x3
, double *y3
, double *x4
, double *y4
)
1600 if (wx_stack_count
== 0)
1604 *x1
= wx_stack_top
->x1
;
1605 *y1
= wx_stack_top
->y1
;
1606 *x2
= wx_stack_top
->x2
;
1607 *y2
= wx_stack_top
->y2
;
1608 *x3
= wx_stack_top
->x3
;
1609 *y3
= wx_stack_top
->y3
;
1610 *x4
= wx_stack_top
->x4
;
1611 *y4
= wx_stack_top
->y4
;
1615 static bool wx_spline_add_point(double x
, double y
)
1617 wxPoint
*point
= new wxPoint
;
1620 wx_spline_point_list
.Append((wxObject
*)point
);
1624 static void wx_spline_draw_point_array(wxDC
*dc
)
1626 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1627 wxNode
*node
= wx_spline_point_list
.First();
1630 wxPoint
*point
= (wxPoint
*)node
->Data();
1633 node
= wx_spline_point_list
.First();
1637 void wxWindowDC::DoDrawSpline( wxList
*points
)
1639 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1642 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1643 double x1
, y1
, x2
, y2
;
1645 wxNode
*node
= points
->First();
1646 p
= (wxPoint
*)node
->Data();
1651 node
= node
->Next();
1652 p
= (wxPoint
*)node
->Data();
1656 cx1
= (double)((x1
+ x2
) / 2);
1657 cy1
= (double)((y1
+ y2
) / 2);
1658 cx2
= (double)((cx1
+ x2
) / 2);
1659 cy2
= (double)((cy1
+ y2
) / 2);
1661 wx_spline_add_point(x1
, y1
);
1663 while ((node
= node
->Next()) != NULL
)
1665 p
= (wxPoint
*)node
->Data();
1670 cx4
= (double)(x1
+ x2
) / 2;
1671 cy4
= (double)(y1
+ y2
) / 2;
1672 cx3
= (double)(x1
+ cx4
) / 2;
1673 cy3
= (double)(y1
+ cy4
) / 2;
1675 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1679 cx2
= (double)(cx1
+ x2
) / 2;
1680 cy2
= (double)(cy1
+ y2
) / 2;
1683 wx_spline_add_point( cx1
, cy1
);
1684 wx_spline_add_point( x2
, y2
);
1686 wx_spline_draw_point_array( this );
1689 #endif // wxUSE_SPLINE
1691 //-----------------------------------------------------------------------------
1693 //-----------------------------------------------------------------------------
1695 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1697 wxPaintDC::wxPaintDC()
1702 wxPaintDC::wxPaintDC( wxWindow
*win
)
1707 //-----------------------------------------------------------------------------
1709 //-----------------------------------------------------------------------------
1711 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1713 wxClientDC::wxClientDC()
1718 wxClientDC::wxClientDC( wxWindow
*win
)