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_XOR
; break;
977 case wxINVERT
: mode
= GDK_INVERT
; break;
978 #if (GTK_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;
985 case wxAND
: mode
= GDK_AND
; break;
987 case wxOR
: mode
= GDK_OR
; break;
988 case wxEQUIV
: mode
= GDK_EQUIV
; break;
989 case wxNAND
: mode
= GDK_NAND
; break;
990 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
991 case wxCOPY
: mode
= GDK_COPY
; break;
992 case wxNO_OP
: mode
= GDK_NOOP
; break;
993 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
997 wxFAIL_MSG( "unsupported logical function" );
1002 m_logicalFunction
= function
;
1003 gdk_gc_set_function( m_penGC
, mode
);
1004 gdk_gc_set_function( m_brushGC
, mode
);
1005 gdk_gc_set_function( m_textGC
, mode
);
1008 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1010 wxCHECK_RET( Ok(), _T("invalid window dc") );
1012 if (m_textForegroundColour
== col
) return;
1014 m_textForegroundColour
= col
;
1015 if (!m_textForegroundColour
.Ok()) return;
1017 m_textForegroundColour
.CalcPixel( m_cmap
);
1018 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1021 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1023 wxCHECK_RET( Ok(), _T("invalid window dc") );
1025 if (m_textBackgroundColour
== col
) return;
1027 m_textBackgroundColour
= col
;
1028 if (!m_textBackgroundColour
.Ok()) return;
1030 m_textBackgroundColour
.CalcPixel( m_cmap
);
1031 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1034 void wxWindowDC::SetBackgroundMode( int mode
)
1036 wxCHECK_RET( Ok(), _T("invalid window dc") );
1038 m_backgroundMode
= mode
;
1040 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1041 // transparent/solid background mode
1043 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1045 gdk_gc_set_fill( m_brushGC
,
1046 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1050 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1052 wxFAIL_MSG( _T("wxWindowDC::SetPalette not implemented") );
1055 void wxWindowDC::DoSetClippingRegion( long x
, long y
, long width
, long height
)
1057 wxCHECK_RET( Ok(), _T("invalid window dc") );
1059 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1062 rect
.x
= XLOG2DEV(x
);
1063 rect
.y
= YLOG2DEV(y
);
1064 rect
.width
= XLOG2DEVREL(width
);
1065 rect
.height
= YLOG2DEVREL(height
);
1066 gdk_gc_set_clip_rectangle( m_penGC
, &rect
);
1067 gdk_gc_set_clip_rectangle( m_brushGC
, &rect
);
1068 gdk_gc_set_clip_rectangle( m_textGC
, &rect
);
1069 gdk_gc_set_clip_rectangle( m_bgGC
, &rect
);
1072 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1074 wxCHECK_RET( Ok(), _T("invalid window dc") );
1078 DestroyClippingRegion();
1082 gdk_gc_set_clip_region( m_penGC
, region
.GetRegion() );
1083 gdk_gc_set_clip_region( m_brushGC
, region
.GetRegion() );
1084 gdk_gc_set_clip_region( m_textGC
, region
.GetRegion() );
1085 gdk_gc_set_clip_region( m_bgGC
, region
.GetRegion() );
1088 void wxWindowDC::DestroyClippingRegion()
1090 wxCHECK_RET( Ok(), _T("invalid window dc") );
1092 wxDC::DestroyClippingRegion();
1094 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1095 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1096 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1097 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1100 void wxWindowDC::SetUpDC()
1104 m_logicalFunction
= wxCOPY
;
1105 m_penGC
= gdk_gc_new( m_window
);
1106 m_brushGC
= gdk_gc_new( m_window
);
1107 m_textGC
= gdk_gc_new( m_window
);
1108 m_bgGC
= gdk_gc_new( m_window
);
1110 wxColour
tmp_col( m_textForegroundColour
);
1111 m_textForegroundColour
= wxNullColour
;
1112 SetTextForeground( tmp_col
);
1113 tmp_col
= m_textBackgroundColour
;
1114 m_textBackgroundColour
= wxNullColour
;
1115 SetTextBackground( tmp_col
);
1117 wxPen
tmp_pen( m_pen
);
1121 wxFont
tmp_font( m_font
);
1122 m_font
= wxNullFont
;
1123 SetFont( tmp_font
);
1125 wxBrush
tmp_brush( m_brush
);
1126 m_brush
= wxNullBrush
;
1127 SetBrush( tmp_brush
);
1129 tmp_brush
= m_backgroundBrush
;
1130 m_backgroundBrush
= wxNullBrush
;
1131 SetBackground( tmp_brush
);
1135 hatch_bitmap
= hatches
;
1136 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1137 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1138 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1139 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1140 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1141 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1145 void wxWindowDC::Destroy()
1147 if (m_penGC
) gdk_gc_unref( m_penGC
);
1148 m_penGC
= (GdkGC
*) NULL
;
1149 if (m_brushGC
) gdk_gc_unref( m_brushGC
);
1150 m_brushGC
= (GdkGC
*) NULL
;
1151 if (m_textGC
) gdk_gc_unref( m_textGC
);
1152 m_textGC
= (GdkGC
*) NULL
;
1153 if (m_bgGC
) gdk_gc_unref( m_bgGC
);
1154 m_bgGC
= (GdkGC
*) NULL
;
1157 // Resolution in pixels per logical inch
1158 wxSize
wxWindowDC::GetPPI() const
1160 return wxSize(100, 100);
1163 int wxWindowDC::GetDepth() const
1165 wxFAIL_MSG(_T("not implemented"));
1171 // ----------------------------------- spline code ----------------------------------------
1173 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1174 double a3
, double b3
, double a4
, double b4
);
1175 void wx_clear_stack();
1176 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1177 double *y3
, double *x4
, double *y4
);
1178 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1179 double x4
, double y4
);
1180 static bool wx_spline_add_point(double x
, double y
);
1181 static void wx_spline_draw_point_array(wxDC
*dc
);
1183 wxList wx_spline_point_list
;
1185 #define half(z1, z2) ((z1+z2)/2.0)
1188 /* iterative version */
1190 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1193 register double xmid
, ymid
;
1194 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1197 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1199 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1200 xmid
= (double)half(x2
, x3
);
1201 ymid
= (double)half(y2
, y3
);
1202 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1203 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1204 wx_spline_add_point( x1
, y1
);
1205 wx_spline_add_point( xmid
, ymid
);
1207 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1208 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1209 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1210 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1215 /* utilities used by spline drawing routines */
1217 typedef struct wx_spline_stack_struct
{
1218 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1221 #define SPLINE_STACK_DEPTH 20
1222 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1223 static Stack
*wx_stack_top
;
1224 static int wx_stack_count
;
1226 void wx_clear_stack()
1228 wx_stack_top
= wx_spline_stack
;
1232 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1234 wx_stack_top
->x1
= x1
;
1235 wx_stack_top
->y1
= y1
;
1236 wx_stack_top
->x2
= x2
;
1237 wx_stack_top
->y2
= y2
;
1238 wx_stack_top
->x3
= x3
;
1239 wx_stack_top
->y3
= y3
;
1240 wx_stack_top
->x4
= x4
;
1241 wx_stack_top
->y4
= y4
;
1246 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1247 double *x3
, double *y3
, double *x4
, double *y4
)
1249 if (wx_stack_count
== 0)
1253 *x1
= wx_stack_top
->x1
;
1254 *y1
= wx_stack_top
->y1
;
1255 *x2
= wx_stack_top
->x2
;
1256 *y2
= wx_stack_top
->y2
;
1257 *x3
= wx_stack_top
->x3
;
1258 *y3
= wx_stack_top
->y3
;
1259 *x4
= wx_stack_top
->x4
;
1260 *y4
= wx_stack_top
->y4
;
1264 static bool wx_spline_add_point(double x
, double y
)
1266 wxPoint
*point
= new wxPoint
;
1269 wx_spline_point_list
.Append((wxObject
*)point
);
1273 static void wx_spline_draw_point_array(wxDC
*dc
)
1275 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1276 wxNode
*node
= wx_spline_point_list
.First();
1279 wxPoint
*point
= (wxPoint
*)node
->Data();
1282 node
= wx_spline_point_list
.First();
1286 void wxWindowDC::DoDrawSpline( wxList
*points
)
1288 wxCHECK_RET( Ok(), _T("invalid window dc") );
1291 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1292 double x1
, y1
, x2
, y2
;
1294 wxNode
*node
= points
->First();
1295 p
= (wxPoint
*)node
->Data();
1300 node
= node
->Next();
1301 p
= (wxPoint
*)node
->Data();
1305 cx1
= (double)((x1
+ x2
) / 2);
1306 cy1
= (double)((y1
+ y2
) / 2);
1307 cx2
= (double)((cx1
+ x2
) / 2);
1308 cy2
= (double)((cy1
+ y2
) / 2);
1310 wx_spline_add_point(x1
, y1
);
1312 while ((node
= node
->Next()) != NULL
)
1314 p
= (wxPoint
*)node
->Data();
1319 cx4
= (double)(x1
+ x2
) / 2;
1320 cy4
= (double)(y1
+ y2
) / 2;
1321 cx3
= (double)(x1
+ cx4
) / 2;
1322 cy3
= (double)(y1
+ cy4
) / 2;
1324 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1328 cx2
= (double)(cx1
+ x2
) / 2;
1329 cy2
= (double)(cy1
+ y2
) / 2;
1332 wx_spline_add_point( cx1
, cy1
);
1333 wx_spline_add_point( x2
, y2
);
1335 wx_spline_draw_point_array( this );
1338 #endif // wxUSE_SPLINE
1340 //-----------------------------------------------------------------------------
1342 //-----------------------------------------------------------------------------
1344 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1346 wxPaintDC::wxPaintDC()
1351 wxPaintDC::wxPaintDC( wxWindow
*win
)
1356 //-----------------------------------------------------------------------------
1358 //-----------------------------------------------------------------------------
1360 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1362 wxClientDC::wxClientDC()
1367 wxClientDC::wxClientDC( wxWindow
*win
)