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"
22 //-----------------------------------------------------------------------------
24 //-----------------------------------------------------------------------------
34 static GdkPixmap
*hatches
[num_hatches
];
35 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
41 #define RAD2DEG 57.2957795131
43 //-----------------------------------------------------------------------------
44 // temporary implementation of the missing GDK function
45 //-----------------------------------------------------------------------------
47 #include "gdk/gdkprivate.h"
49 void gdk_draw_bitmap (GdkDrawable
*drawable
,
59 GdkWindowPrivate
*drawable_private
;
60 GdkWindowPrivate
*src_private
;
61 GdkGCPrivate
*gc_private
;
63 g_return_if_fail (drawable
!= NULL
);
64 g_return_if_fail (src
!= NULL
);
65 g_return_if_fail (gc
!= NULL
);
67 drawable_private
= (GdkWindowPrivate
*) drawable
;
68 src_private
= (GdkWindowPrivate
*) src
;
69 if (drawable_private
->destroyed
|| src_private
->destroyed
)
72 gc_private
= (GdkGCPrivate
*) gc
;
74 if (width
== -1) width
= src_private
->width
;
75 if (height
== -1) height
= src_private
->height
;
77 XCopyPlane( drawable_private
->xdisplay
,
79 drawable_private
->xwindow
,
87 //-----------------------------------------------------------------------------
89 //-----------------------------------------------------------------------------
91 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
93 wxWindowDC::wxWindowDC()
95 m_penGC
= (GdkGC
*) NULL
;
96 m_brushGC
= (GdkGC
*) NULL
;
97 m_textGC
= (GdkGC
*) NULL
;
98 m_bgGC
= (GdkGC
*) NULL
;
99 m_cmap
= (GdkColormap
*) NULL
;
101 m_owner
= (wxWindow
*)NULL
;
104 wxWindowDC::wxWindowDC( wxWindow
*window
)
106 m_penGC
= (GdkGC
*) NULL
;
107 m_brushGC
= (GdkGC
*) NULL
;
108 m_textGC
= (GdkGC
*) NULL
;
109 m_bgGC
= (GdkGC
*) NULL
;
110 m_cmap
= (GdkColormap
*) NULL
;
111 m_owner
= (wxWindow
*)NULL
;
116 GtkWidget
*widget
= window
->m_wxwindow
;
120 m_window
= widget
->window
;
125 /* force realization */
126 gtk_widget_realize( widget
);
127 m_window
= widget
->window
;
130 /* still not realized ? */
134 if (window
->m_wxwindow
)
135 m_cmap
= gtk_widget_get_colormap( window
->m_wxwindow
);
137 m_cmap
= gtk_widget_get_colormap( window
->m_widget
);
143 /* this must be done after SetUpDC, bacause SetUpDC calls the
144 repective SetBrush, SetPen, SetBackground etc functions
145 to set up the DC. SetBackground call m_owner->SetBackground
146 and this might not be desired as the standard dc background
147 is white whereas a window might assume gray to be the
148 standard (as e.g. wxStatusBar) */
153 wxWindowDC::~wxWindowDC()
158 void wxWindowDC::DoFloodFill( long WXUNUSED(x
), long WXUNUSED(y
),
159 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
161 wxFAIL_MSG( _T("wxWindowDC::DoFloodFill not implemented") );
164 bool wxWindowDC::DoGetPixel( long WXUNUSED(x1
), long WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
166 wxFAIL_MSG( _T("wxWindowDC::DoGetPixel not implemented") );
170 void wxWindowDC::DoDrawLine( long x1
, long y1
, long x2
, long y2
)
172 wxCHECK_RET( Ok(), _T("invalid window dc") );
174 if (m_pen
.GetStyle() != wxTRANSPARENT
)
176 gdk_draw_line( m_window
, m_penGC
,
177 XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
179 CalcBoundingBox(x1
, y1
);
180 CalcBoundingBox(x2
, y2
);
184 void wxWindowDC::DoCrossHair( long x
, long y
)
186 wxCHECK_RET( Ok(), _T("invalid window dc") );
188 if (m_pen
.GetStyle() != wxTRANSPARENT
)
193 long xx
= XLOG2DEV(x
);
194 long yy
= YLOG2DEV(y
);
195 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
196 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
200 void wxWindowDC::DoDrawArc( long x1
, long y1
, long x2
, long y2
,
203 wxCHECK_RET( Ok(), _T("invalid window dc") );
205 long xx1
= XLOG2DEV(x1
);
206 long yy1
= YLOG2DEV(y1
);
207 long xx2
= XLOG2DEV(x2
);
208 long yy2
= YLOG2DEV(y2
);
209 long xxc
= XLOG2DEV(xc
);
210 long yyc
= YLOG2DEV(yc
);
211 double dx
= xx1
- xxc
;
212 double dy
= yy1
- yyc
;
213 double radius
= sqrt(dx
*dx
+dy
*dy
);
214 long r
= (long)radius
;
215 double radius1
, radius2
;
217 if (xx1
== xx2
&& yy1
== yy2
)
225 radius1
= radius2
= 0.0;
229 radius1
= (xx1
- xxc
== 0) ?
230 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
231 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
232 radius2
= (xx2
- xxc
== 0) ?
233 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
234 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
236 long alpha1
= long(radius1
* 64.0);
237 long alpha2
= long((radius2
- radius1
) * 64.0);
238 while (alpha2
<= 0) alpha2
+= 360*64;
239 while (alpha1
> 360*64) alpha1
-= 360*64;
241 if (m_brush
.GetStyle() != wxTRANSPARENT
)
242 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
244 if (m_pen
.GetStyle() != wxTRANSPARENT
)
245 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
247 CalcBoundingBox (x1
, y1
);
248 CalcBoundingBox (x2
, y2
);
251 void wxWindowDC::DoDrawEllipticArc( long x
, long y
, long width
, long height
, double sa
, double ea
)
253 wxCHECK_RET( Ok(), _T("invalid window dc") );
255 long xx
= XLOG2DEV(x
);
256 long yy
= YLOG2DEV(y
);
257 long ww
= m_signX
* XLOG2DEVREL(width
);
258 long hh
= m_signY
* YLOG2DEVREL(height
);
260 // CMB: handle -ve width and/or height
261 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
262 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
264 long start
= long(sa
* 64.0);
265 long end
= long(ea
* 64.0);
266 if (m_brush
.GetStyle() != wxTRANSPARENT
)
267 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
269 if (m_pen
.GetStyle() != wxTRANSPARENT
)
270 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
272 CalcBoundingBox (x
, y
);
273 CalcBoundingBox (x
+ width
, y
+ height
);
276 void wxWindowDC::DoDrawPoint( long x
, long y
)
278 wxCHECK_RET( Ok(), _T("invalid window dc") );
280 if (m_pen
.GetStyle() != wxTRANSPARENT
)
281 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
283 CalcBoundingBox (x
, y
);
286 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], long xoffset
, long yoffset
)
288 wxCHECK_RET( Ok(), _T("invalid window dc") );
290 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
293 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
295 for (int i
= 0; i
< n
-1; i
++)
297 long x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
298 long x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
299 long y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
300 long y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
301 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
303 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
307 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], long xoffset
, long yoffset
, int WXUNUSED(fillStyle
) )
309 wxCHECK_RET( Ok(), _T("invalid window dc") );
313 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
315 for (i
= 0 ; i
< n
; i
++)
317 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
318 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
320 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
323 if (m_brush
.GetStyle() != wxTRANSPARENT
)
324 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
328 if (m_pen
.GetStyle() != wxTRANSPARENT
)
329 for (i
= 0 ; i
< n
; i
++)
331 gdk_draw_line( m_window
, m_penGC
,
334 gdkpoints
[(i
+1)%n
].x
,
335 gdkpoints
[(i
+1)%n
].y
);
341 void wxWindowDC::DoDrawRectangle( long x
, long y
, long width
, long height
)
343 wxCHECK_RET( Ok(), _T("invalid window dc") );
345 long xx
= XLOG2DEV(x
);
346 long yy
= YLOG2DEV(y
);
347 long ww
= m_signX
* XLOG2DEVREL(width
);
348 long hh
= m_signY
* YLOG2DEVREL(height
);
350 // CMB: draw nothing if transformed w or h is 0
351 if (ww
== 0 || hh
== 0) return;
353 // CMB: handle -ve width and/or height
354 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
355 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
357 if (m_brush
.GetStyle() != wxTRANSPARENT
)
358 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
360 if (m_pen
.GetStyle() != wxTRANSPARENT
)
361 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
363 CalcBoundingBox( x
, y
);
364 CalcBoundingBox( x
+ width
, y
+ height
);
367 void wxWindowDC::DoDrawRoundedRectangle( long x
, long y
, long width
, long height
, double radius
)
369 wxCHECK_RET( Ok(), _T("invalid window dc") );
371 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
373 long xx
= XLOG2DEV(x
);
374 long yy
= YLOG2DEV(y
);
375 long ww
= m_signX
* XLOG2DEVREL(width
);
376 long hh
= m_signY
* YLOG2DEVREL(height
);
377 long rr
= XLOG2DEVREL((long)radius
);
379 // CMB: handle -ve width and/or height
380 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
381 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
383 // CMB: if radius is zero use DrawRectangle() instead to avoid
384 // X drawing errors with small radii
387 DrawRectangle( x
, y
, width
, height
);
391 // CMB: draw nothing if transformed w or h is 0
392 if (ww
== 0 || hh
== 0) return;
394 // CMB: adjust size if outline is drawn otherwise the result is
395 // 1 pixel too wide and high
396 if (m_pen
.GetStyle() != wxTRANSPARENT
)
402 // CMB: ensure dd is not larger than rectangle otherwise we
403 // get an hour glass shape
405 if (dd
> ww
) dd
= ww
;
406 if (dd
> hh
) dd
= hh
;
409 if (m_brush
.GetStyle() != wxTRANSPARENT
)
411 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
412 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
413 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
414 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
415 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
416 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
419 if (m_pen
.GetStyle() != wxTRANSPARENT
)
421 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
422 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
423 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
424 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
425 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
426 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
427 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
428 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
431 // this ignores the radius
432 CalcBoundingBox( x
, y
);
433 CalcBoundingBox( x
+ width
, y
+ height
);
436 void wxWindowDC::DoDrawEllipse( long x
, long y
, long width
, long height
)
438 wxCHECK_RET( Ok(), _T("invalid window dc") );
440 long xx
= XLOG2DEV(x
);
441 long yy
= YLOG2DEV(y
);
442 long ww
= m_signX
* XLOG2DEVREL(width
);
443 long hh
= m_signY
* YLOG2DEVREL(height
);
445 // CMB: handle -ve width and/or height
446 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
447 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
449 if (m_brush
.GetStyle() != wxTRANSPARENT
)
450 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
452 if (m_pen
.GetStyle() != wxTRANSPARENT
)
453 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
455 CalcBoundingBox( x
- width
, y
- height
);
456 CalcBoundingBox( x
+ width
, y
+ height
);
459 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, long x
, long y
)
461 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
462 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
465 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
469 wxCHECK_RET( Ok(), _T("invalid window dc") );
471 wxCHECK_RET( bitmap
.Ok(), _T("invalid bitmap") );
473 /* scale/translate size and position */
475 int xx
= XLOG2DEV(x
);
476 int yy
= YLOG2DEV(y
);
478 int w
= bitmap
.GetWidth();
479 int h
= bitmap
.GetHeight();
481 int ww
= XLOG2DEVREL(w
);
482 int hh
= YLOG2DEVREL(h
);
484 /* scale bitmap if required */
488 if ((w
!= ww
) || (h
!= hh
))
490 wxImage
image( bitmap
);
491 image
= image
.Scale( ww
, hh
);
493 use_bitmap
= image
.ConvertToBitmap();
500 /* apply mask if any */
502 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
503 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
507 gdk_gc_set_clip_mask( m_penGC
, mask
);
508 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
511 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
513 GdkPixmap
*pm
= use_bitmap
.GetPixmap();
516 gdk_draw_pixmap( m_window
, m_penGC
, pm
, 0, 0, xx
, yy
, -1, -1 );
520 GdkBitmap
*bm
= use_bitmap
.GetBitmap();
523 gdk_draw_bitmap( m_window
, m_penGC
, bm
, 0, 0, xx
, yy
, -1, -1 );
527 /* remove mask again if any */
531 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
532 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
535 CalcBoundingBox( x
, y
);
536 CalcBoundingBox( x
+ w
, y
+ h
);
539 bool wxWindowDC::DoBlit( long xdest
, long ydest
, long width
, long height
,
540 wxDC
*source
, long xsrc
, long ysrc
,
541 int logical_func
, bool useMask
)
543 /* this is the nth try to get this utterly useless function to
544 work. it now completely ignores the scaling or translation
545 of the source dc, but scales correctly on the target dc and
546 knows about possible mask information in a memory dc. */
548 wxCHECK_MSG( Ok(), FALSE
, _T("invalid window dc") );
550 wxCHECK_MSG( source
, FALSE
, _T("invalid source dc") );
552 wxClientDC
*srcDC
= (wxClientDC
*)source
;
553 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
555 bool use_bitmap_method
= FALSE
;
557 if (srcDC
->m_isMemDC
)
559 if (!memDC
->m_selected
.Ok()) return FALSE
;
561 /* we use the "XCopyArea" way to copy a memory dc into
562 y different window if the memory dc BOTH
563 a) doesn't have any mask or its mask isn't used
567 if (useMask
&& (memDC
->m_selected
.GetMask()))
569 /* we HAVE TO use the direct way for memory dcs
570 that have mask since the XCopyArea doesn't know
572 use_bitmap_method
= TRUE
;
574 else if (memDC
->m_selected
.GetDepth() == 1)
576 /* we HAVE TO use the direct way for memory dcs
577 that are bitmaps because XCopyArea doesn't cope
578 with different bit depths */
579 use_bitmap_method
= TRUE
;
581 else if ((xsrc
== 0) && (ysrc
== 0) &&
582 (width
== memDC
->m_selected
.GetWidth()) &&
583 (height
== memDC
->m_selected
.GetHeight()))
585 /* we SHOULD use the direct way if all of the bitmap
586 in the memory dc is copied in which case XCopyArea
587 wouldn't be able able to boost performace by reducing
588 the area to be scaled */
589 use_bitmap_method
= TRUE
;
593 use_bitmap_method
= FALSE
;
597 CalcBoundingBox( xdest
, ydest
);
598 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
600 int old_logical_func
= m_logicalFunction
;
601 SetLogicalFunction( logical_func
);
603 if (use_bitmap_method
)
605 /* scale/translate bitmap size */
607 long bm_width
= memDC
->m_selected
.GetWidth();
608 long bm_height
= memDC
->m_selected
.GetHeight();
610 long bm_ww
= XLOG2DEVREL( bm_width
);
611 long bm_hh
= YLOG2DEVREL( bm_height
);
613 /* scale bitmap if required */
617 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
619 wxImage
image( memDC
->m_selected
);
620 image
= image
.Scale( bm_ww
, bm_hh
);
622 use_bitmap
= image
.ConvertToBitmap();
626 use_bitmap
= memDC
->m_selected
;
629 /* scale/translate size and position */
631 long xx
= XLOG2DEV(xdest
);
632 long yy
= YLOG2DEV(ydest
);
634 long ww
= XLOG2DEVREL(width
);
635 long hh
= YLOG2DEVREL(height
);
637 /* apply mask if any */
639 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
640 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
644 gdk_gc_set_clip_mask( m_penGC
, mask
);
645 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
648 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
650 GdkPixmap
*pm
= use_bitmap
.GetPixmap();
653 gdk_draw_pixmap( m_window
, m_penGC
, pm
, xsrc
, ysrc
, xx
, yy
, ww
, hh
);
657 GdkBitmap
*bm
= use_bitmap
.GetBitmap();
660 /* we use the textGC here because blitting a bitmap is done
661 using the current text colour */
662 gdk_draw_bitmap( m_window
, m_textGC
, bm
, xsrc
, ysrc
, xx
, yy
, ww
, hh
);
666 /* remove mask again if any */
670 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
671 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
674 else /* use_bitmap_method */
676 /* scale/translate size and position */
678 long xx
= XLOG2DEV(xdest
);
679 long yy
= YLOG2DEV(ydest
);
681 long ww
= XLOG2DEVREL(width
);
682 long hh
= YLOG2DEVREL(height
);
684 if ((width
!= ww
) || (height
!= hh
))
686 /* draw source window into a bitmap as we cannot scale
687 a window in contrast to a bitmap. this would actually
688 work with memory dcs as well, but we'd lose the mask
689 information and waste one step in this process since
690 a memory already has a bitmap. all this is slightly
691 inefficient as we could take an XImage directly from
692 an X window, but we'd then also have to care that
693 the window is not outside the screen (in which case
694 we'd get a BadMatch or what not).
695 Is a double XGetImage and combined XGetPixel and
696 XPutPixel really faster? I'm not sure. look at wxXt
697 for a different implementation of the same problem. */
699 wxBitmap
bitmap( width
, height
);
700 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
702 xsrc
, ysrc
, width
, height
);
706 wxImage
image( bitmap
);
707 image
= image
.Scale( ww
, hh
);
709 /* convert to bitmap */
711 bitmap
= image
.ConvertToBitmap();
713 /* draw scaled bitmap */
715 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
720 /* no scaling and not a memory dc with a mask either */
722 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
724 xsrc
, ysrc
, width
, height
);
728 SetLogicalFunction( old_logical_func
);
732 void wxWindowDC::DoDrawText( const wxString
&text
, long x
, long y
)
734 wxCHECK_RET( Ok(), _T("invalid window dc") );
736 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
741 /* CMB 21/5/98: draw text background if mode is wxSOLID */
742 if (m_backgroundMode
== wxSOLID
)
744 long width
= gdk_string_width( font
, text
.mbc_str() );
745 long height
= font
->ascent
+ font
->descent
;
746 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
747 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
748 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
750 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
752 /* CMB 17/7/98: simple underline: ignores scaling and underlying
753 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
754 properties (see wxXt implementation) */
755 if (m_font
.GetUnderlined())
757 long width
= gdk_string_width( font
, text
.mbc_str() );
758 long ul_y
= y
+ font
->ascent
;
759 if (font
->descent
> 0) ul_y
++;
760 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
764 GetTextExtent (text
, &w
, &h
);
765 CalcBoundingBox (x
+ w
, y
+ h
);
766 CalcBoundingBox (x
, y
);
769 void wxWindowDC::GetTextExtent( const wxString
&string
, long *width
, long *height
,
770 long *descent
, long *externalLeading
,
771 wxFont
*theFont
) const
773 wxFont fontToUse
= m_font
;
774 if (theFont
) fontToUse
= *theFont
;
776 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
777 if (width
) (*width
) = long(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
778 if (height
) (*height
) = long((font
->ascent
+ font
->descent
) / m_scaleY
);
779 if (descent
) (*descent
) = long(font
->descent
/ m_scaleY
);
780 if (externalLeading
) (*externalLeading
) = 0; // ??
783 long wxWindowDC::GetCharWidth() const
785 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
786 return long(gdk_string_width( font
, "H" ) / m_scaleX
);
789 long wxWindowDC::GetCharHeight() const
791 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
792 return long((font
->ascent
+ font
->descent
) / m_scaleY
);
795 void wxWindowDC::Clear()
797 wxCHECK_RET( Ok(), _T("invalid window dc") );
799 /* - we either are a memory dc or have a window as the
800 owner. anything else shouldn't happen.
801 - we don't use gdk_window_clear() as we don't set
802 the window's background colour anymore. it is too
803 much pain to keep the DC's and the window's back-
804 ground colour in synch. */
809 m_owner
->GetSize( &width
, &height
);
810 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
817 GetSize( &width
, &height
);
818 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
823 void wxWindowDC::SetFont( const wxFont
&font
)
828 void wxWindowDC::SetPen( const wxPen
&pen
)
830 wxCHECK_RET( Ok(), _T("invalid window dc") );
832 if (m_pen
== pen
) return;
836 if (!m_pen
.Ok()) return;
838 gint width
= m_pen
.GetWidth();
839 // CMB: if width is non-zero scale it with the dc
846 // X doesn't allow different width in x and y and so we take
848 double w
= 0.5 + (abs(XLOG2DEVREL(width
)) + abs(YLOG2DEVREL(width
))) / 2.0;
852 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
853 switch (m_pen
.GetStyle())
855 case wxSOLID
: { lineStyle
= GDK_LINE_SOLID
; break; }
856 case wxDOT
: { lineStyle
= GDK_LINE_ON_OFF_DASH
; break; }
857 case wxLONG_DASH
: { lineStyle
= GDK_LINE_ON_OFF_DASH
; break; }
858 case wxSHORT_DASH
: { lineStyle
= GDK_LINE_ON_OFF_DASH
; break; }
859 case wxDOT_DASH
: { lineStyle
= GDK_LINE_DOUBLE_DASH
; break; }
862 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
863 switch (m_pen
.GetCap())
865 case wxCAP_ROUND
: { capStyle
= (width
<= 1) ? GDK_CAP_NOT_LAST
: GDK_CAP_ROUND
; break; }
866 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
867 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
870 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
871 switch (m_pen
.GetJoin())
873 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
874 case wxJOIN_ROUND
: { joinStyle
= GDK_JOIN_ROUND
; break; }
875 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
878 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
880 m_pen
.GetColour().CalcPixel( m_cmap
);
881 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
884 void wxWindowDC::SetBrush( const wxBrush
&brush
)
886 wxCHECK_RET( Ok(), _T("invalid window dc") );
888 if (m_brush
== brush
) return;
892 if (!m_brush
.Ok()) return;
894 m_brush
.GetColour().CalcPixel( m_cmap
);
895 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
897 GdkFill fillStyle
= GDK_SOLID
;
898 switch (m_brush
.GetStyle())
904 fillStyle
= GDK_STIPPLED
;
907 gdk_gc_set_fill( m_brushGC
, fillStyle
);
909 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
911 if (m_brush
.GetStipple()->GetPixmap())
912 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
914 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
917 if (IS_HATCH(m_brush
.GetStyle()))
919 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
920 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
924 void wxWindowDC::SetBackground( const wxBrush
&brush
)
926 /* CMB 21/7/98: Added SetBackground. Sets background brush
927 * for Clear() and bg colour for shapes filled with cross-hatch brush */
929 wxCHECK_RET( Ok(), _T("invalid window dc") );
931 if (m_backgroundBrush
== brush
) return;
933 m_backgroundBrush
= brush
;
935 if (!m_backgroundBrush
.Ok()) return;
937 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
938 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
939 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
940 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
941 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
943 GdkFill fillStyle
= GDK_SOLID
;
944 switch (m_backgroundBrush
.GetStyle())
950 fillStyle
= GDK_STIPPLED
;
953 gdk_gc_set_fill( m_bgGC
, fillStyle
);
955 if (m_backgroundBrush
.GetStyle() == wxSTIPPLE
)
957 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
960 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
962 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
963 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
967 void wxWindowDC::SetLogicalFunction( int function
)
969 wxCHECK_RET( Ok(), _T("invalid window dc") );
971 if (m_logicalFunction
== function
) return;
973 GdkFunction mode
= GDK_COPY
;
976 case wxXOR
: mode
= GDK_INVERT
; break;
977 case wxINVERT
: mode
= GDK_INVERT
; break;
978 #if (GDK_MINOR_VERSION > 0)
979 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
980 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
981 case wxCLEAR
: mode
= GDK_CLEAR
; break;
982 case wxSET
: mode
= GDK_SET
; break;
983 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
984 case wxAND
: mode
= GDK_AND
; break;
985 case wxOR
: mode
= GDK_OR
; break;
986 case wxEQUIV
: mode
= GDK_EQUIV
; break;
987 case wxNAND
: mode
= GDK_NAND
; break;
988 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
989 /* ? wxSRC_INVERT GDK_AND_REVERSE, GDK_OR_REVERSE, GDK_OR_INVERT */
994 m_logicalFunction
= function
;
995 gdk_gc_set_function( m_penGC
, mode
);
996 gdk_gc_set_function( m_brushGC
, mode
);
997 gdk_gc_set_function( m_textGC
, mode
);
1000 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1002 wxCHECK_RET( Ok(), _T("invalid window dc") );
1004 if (m_textForegroundColour
== col
) return;
1006 m_textForegroundColour
= col
;
1007 if (!m_textForegroundColour
.Ok()) return;
1009 m_textForegroundColour
.CalcPixel( m_cmap
);
1010 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1013 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1015 wxCHECK_RET( Ok(), _T("invalid window dc") );
1017 if (m_textBackgroundColour
== col
) return;
1019 m_textBackgroundColour
= col
;
1020 if (!m_textBackgroundColour
.Ok()) return;
1022 m_textBackgroundColour
.CalcPixel( m_cmap
);
1023 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1026 void wxWindowDC::SetBackgroundMode( int mode
)
1028 wxCHECK_RET( Ok(), _T("invalid window dc") );
1030 m_backgroundMode
= mode
;
1032 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1033 // transparent/solid background mode
1035 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1037 gdk_gc_set_fill( m_brushGC
,
1038 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1042 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1044 wxFAIL_MSG( _T("wxWindowDC::SetPalette not implemented") );
1047 void wxWindowDC::DoSetClippingRegion( long x
, long y
, long width
, long height
)
1049 wxCHECK_RET( Ok(), _T("invalid window dc") );
1051 wxDC::SetClippingRegion( x
, y
, width
, height
);
1054 rect
.x
= XLOG2DEV(x
);
1055 rect
.y
= YLOG2DEV(y
);
1056 rect
.width
= XLOG2DEVREL(width
);
1057 rect
.height
= YLOG2DEVREL(height
);
1058 gdk_gc_set_clip_rectangle( m_penGC
, &rect
);
1059 gdk_gc_set_clip_rectangle( m_brushGC
, &rect
);
1060 gdk_gc_set_clip_rectangle( m_textGC
, &rect
);
1061 gdk_gc_set_clip_rectangle( m_bgGC
, &rect
);
1064 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1066 wxCHECK_RET( Ok(), _T("invalid window dc") );
1070 DestroyClippingRegion();
1074 gdk_gc_set_clip_region( m_penGC
, region
.GetRegion() );
1075 gdk_gc_set_clip_region( m_brushGC
, region
.GetRegion() );
1076 gdk_gc_set_clip_region( m_textGC
, region
.GetRegion() );
1077 gdk_gc_set_clip_region( m_bgGC
, region
.GetRegion() );
1080 void wxWindowDC::DestroyClippingRegion()
1082 wxCHECK_RET( Ok(), _T("invalid window dc") );
1084 wxDC::DestroyClippingRegion();
1086 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1087 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1088 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1089 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1092 void wxWindowDC::SetUpDC()
1096 m_logicalFunction
= wxCOPY
;
1097 m_penGC
= gdk_gc_new( m_window
);
1098 m_brushGC
= gdk_gc_new( m_window
);
1099 m_textGC
= gdk_gc_new( m_window
);
1100 m_bgGC
= gdk_gc_new( m_window
);
1102 wxColour
tmp_col( m_textForegroundColour
);
1103 m_textForegroundColour
= wxNullColour
;
1104 SetTextForeground( tmp_col
);
1105 tmp_col
= m_textBackgroundColour
;
1106 m_textBackgroundColour
= wxNullColour
;
1107 SetTextBackground( tmp_col
);
1109 wxPen
tmp_pen( m_pen
);
1113 wxFont
tmp_font( m_font
);
1114 m_font
= wxNullFont
;
1115 SetFont( tmp_font
);
1117 wxBrush
tmp_brush( m_brush
);
1118 m_brush
= wxNullBrush
;
1119 SetBrush( tmp_brush
);
1121 tmp_brush
= m_backgroundBrush
;
1122 m_backgroundBrush
= wxNullBrush
;
1123 SetBackground( tmp_brush
);
1127 hatch_bitmap
= hatches
;
1128 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1129 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1130 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1131 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1132 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1133 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1137 void wxWindowDC::Destroy()
1139 if (m_penGC
) gdk_gc_unref( m_penGC
);
1140 m_penGC
= (GdkGC
*) NULL
;
1141 if (m_brushGC
) gdk_gc_unref( m_brushGC
);
1142 m_brushGC
= (GdkGC
*) NULL
;
1143 if (m_textGC
) gdk_gc_unref( m_textGC
);
1144 m_textGC
= (GdkGC
*) NULL
;
1145 if (m_bgGC
) gdk_gc_unref( m_bgGC
);
1146 m_bgGC
= (GdkGC
*) NULL
;
1149 // Resolution in pixels per logical inch
1150 wxSize
wxWindowDC::GetPPI() const
1152 return wxSize(100, 100);
1155 int wxWindowDC::GetDepth() const
1157 wxFAIL_MSG(_T("not implemented"));
1163 // ----------------------------------- spline code ----------------------------------------
1165 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1166 double a3
, double b3
, double a4
, double b4
);
1167 void wx_clear_stack();
1168 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1169 double *y3
, double *x4
, double *y4
);
1170 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1171 double x4
, double y4
);
1172 static bool wx_spline_add_point(double x
, double y
);
1173 static void wx_spline_draw_point_array(wxDC
*dc
);
1175 wxList wx_spline_point_list
;
1177 #define half(z1, z2) ((z1+z2)/2.0)
1180 /* iterative version */
1182 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1185 register double xmid
, ymid
;
1186 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1189 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1191 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1192 xmid
= (double)half(x2
, x3
);
1193 ymid
= (double)half(y2
, y3
);
1194 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1195 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1196 wx_spline_add_point( x1
, y1
);
1197 wx_spline_add_point( xmid
, ymid
);
1199 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1200 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1201 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1202 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1207 /* utilities used by spline drawing routines */
1209 typedef struct wx_spline_stack_struct
{
1210 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1213 #define SPLINE_STACK_DEPTH 20
1214 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1215 static Stack
*wx_stack_top
;
1216 static int wx_stack_count
;
1218 void wx_clear_stack()
1220 wx_stack_top
= wx_spline_stack
;
1224 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1226 wx_stack_top
->x1
= x1
;
1227 wx_stack_top
->y1
= y1
;
1228 wx_stack_top
->x2
= x2
;
1229 wx_stack_top
->y2
= y2
;
1230 wx_stack_top
->x3
= x3
;
1231 wx_stack_top
->y3
= y3
;
1232 wx_stack_top
->x4
= x4
;
1233 wx_stack_top
->y4
= y4
;
1238 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1239 double *x3
, double *y3
, double *x4
, double *y4
)
1241 if (wx_stack_count
== 0)
1245 *x1
= wx_stack_top
->x1
;
1246 *y1
= wx_stack_top
->y1
;
1247 *x2
= wx_stack_top
->x2
;
1248 *y2
= wx_stack_top
->y2
;
1249 *x3
= wx_stack_top
->x3
;
1250 *y3
= wx_stack_top
->y3
;
1251 *x4
= wx_stack_top
->x4
;
1252 *y4
= wx_stack_top
->y4
;
1256 static bool wx_spline_add_point(double x
, double y
)
1258 wxPoint
*point
= new wxPoint
;
1261 wx_spline_point_list
.Append((wxObject
*)point
);
1265 static void wx_spline_draw_point_array(wxDC
*dc
)
1267 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1268 wxNode
*node
= wx_spline_point_list
.First();
1271 wxPoint
*point
= (wxPoint
*)node
->Data();
1274 node
= wx_spline_point_list
.First();
1278 void wxWindowDC::DoDrawSpline( wxList
*points
)
1280 wxCHECK_RET( Ok(), _T("invalid window dc") );
1283 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1284 double x1
, y1
, x2
, y2
;
1286 wxNode
*node
= points
->First();
1287 p
= (wxPoint
*)node
->Data();
1292 node
= node
->Next();
1293 p
= (wxPoint
*)node
->Data();
1297 cx1
= (double)((x1
+ x2
) / 2);
1298 cy1
= (double)((y1
+ y2
) / 2);
1299 cx2
= (double)((cx1
+ x2
) / 2);
1300 cy2
= (double)((cy1
+ y2
) / 2);
1302 wx_spline_add_point(x1
, y1
);
1304 while ((node
= node
->Next()) != NULL
)
1306 p
= (wxPoint
*)node
->Data();
1311 cx4
= (double)(x1
+ x2
) / 2;
1312 cy4
= (double)(y1
+ y2
) / 2;
1313 cx3
= (double)(x1
+ cx4
) / 2;
1314 cy3
= (double)(y1
+ cy4
) / 2;
1316 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1320 cx2
= (double)(cx1
+ x2
) / 2;
1321 cy2
= (double)(cy1
+ y2
) / 2;
1324 wx_spline_add_point( cx1
, cy1
);
1325 wx_spline_add_point( x2
, y2
);
1327 wx_spline_draw_point_array( this );
1330 #endif // wxUSE_SPLINE
1332 //-----------------------------------------------------------------------------
1334 //-----------------------------------------------------------------------------
1336 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1338 wxPaintDC::wxPaintDC()
1343 wxPaintDC::wxPaintDC( wxWindow
*win
)
1348 //-----------------------------------------------------------------------------
1350 //-----------------------------------------------------------------------------
1352 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1354 wxClientDC::wxClientDC()
1359 wxClientDC::wxClientDC( wxWindow
*win
)