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 //-----------------------------------------------------------------------------
46 #include "gdk/gdkprivate.h"
47 void gdk_draw_bitmap (GdkDrawable
*drawable
,
57 GdkWindowPrivate
*drawable_private
;
58 GdkWindowPrivate
*src_private
;
59 GdkGCPrivate
*gc_private
;
61 g_return_if_fail (drawable
!= NULL
);
62 g_return_if_fail (src
!= NULL
);
63 g_return_if_fail (gc
!= NULL
);
65 drawable_private
= (GdkWindowPrivate
*) drawable
;
66 src_private
= (GdkWindowPrivate
*) src
;
67 if (drawable_private
->destroyed
|| src_private
->destroyed
)
70 gc_private
= (GdkGCPrivate
*) gc
;
72 if (width
== -1) width
= src_private
->width
;
73 if (height
== -1) height
= src_private
->height
;
75 XCopyPlane( drawable_private
->xdisplay
,
77 drawable_private
->xwindow
,
85 //-----------------------------------------------------------------------------
87 //-----------------------------------------------------------------------------
89 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
,wxDC
)
91 wxWindowDC::wxWindowDC()
93 m_penGC
= (GdkGC
*) NULL
;
94 m_brushGC
= (GdkGC
*) NULL
;
95 m_textGC
= (GdkGC
*) NULL
;
96 m_bgGC
= (GdkGC
*) NULL
;
97 m_cmap
= (GdkColormap
*) NULL
;
101 wxWindowDC::wxWindowDC( wxWindow
*window
)
103 m_penGC
= (GdkGC
*) NULL
;
104 m_brushGC
= (GdkGC
*) NULL
;
105 m_textGC
= (GdkGC
*) NULL
;
106 m_bgGC
= (GdkGC
*) NULL
;
107 m_cmap
= (GdkColormap
*) NULL
;
110 GtkWidget
*widget
= window
->m_wxwindow
;
112 m_window
= widget
->window
;
113 if (!m_window
) return;
114 if (window
->m_wxwindow
)
115 m_cmap
= gtk_widget_get_colormap( window
->m_wxwindow
);
117 m_cmap
= gtk_widget_get_colormap( window
->m_widget
);
125 wxWindowDC::~wxWindowDC()
130 void wxWindowDC::FloodFill( long WXUNUSED(x
), long WXUNUSED(y
),
131 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
133 wxFAIL_MSG( "wxWindowDC::FloodFill not implemented" );
136 bool wxWindowDC::GetPixel( long WXUNUSED(x1
), long WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
138 wxFAIL_MSG( "wxWindowDC::GetPixel not implemented" );
142 void wxWindowDC::DrawLine( long x1
, long y1
, long x2
, long y2
)
144 wxCHECK_RET( Ok(), "invalid window dc" );
146 if (m_pen
.GetStyle() != wxTRANSPARENT
)
148 gdk_draw_line( m_window
, m_penGC
,
149 XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
151 CalcBoundingBox(x1
, y1
);
152 CalcBoundingBox(x2
, y2
);
156 void wxWindowDC::CrossHair( long x
, long y
)
158 wxCHECK_RET( Ok(), "invalid window dc" );
160 if (m_pen
.GetStyle() != wxTRANSPARENT
)
165 long xx
= XLOG2DEV(x
);
166 long yy
= YLOG2DEV(y
);
167 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
168 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
172 void wxWindowDC::DrawArc( long x1
, long y1
, long x2
, long y2
, double xc
, double yc
)
174 wxCHECK_RET( Ok(), "invalid window dc" );
176 long xx1
= XLOG2DEV(x1
);
177 long yy1
= YLOG2DEV(y1
);
178 long xx2
= XLOG2DEV(x2
);
179 long yy2
= YLOG2DEV(y2
);
180 long xxc
= XLOG2DEV((long)xc
);
181 long yyc
= YLOG2DEV((long)yc
);
182 double dx
= xx1
- xxc
;
183 double dy
= yy1
- yyc
;
184 double radius
= sqrt(dx
*dx
+dy
*dy
);
185 long r
= (long)radius
;
186 double radius1
, radius2
;
188 if (xx1
== xx2
&& yy1
== yy2
)
196 radius1
= radius2
= 0.0;
200 radius1
= (xx1
- xxc
== 0) ?
201 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
202 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
203 radius2
= (xx2
- xxc
== 0) ?
204 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
205 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
207 long alpha1
= long(radius1
* 64.0);
208 long alpha2
= long((radius2
- radius1
) * 64.0);
209 while (alpha2
<= 0) alpha2
+= 360*64;
210 while (alpha1
> 360*64) alpha1
-= 360*64;
212 if (m_brush
.GetStyle() != wxTRANSPARENT
)
213 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
215 if (m_pen
.GetStyle() != wxTRANSPARENT
)
216 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
218 CalcBoundingBox (x1
, y1
);
219 CalcBoundingBox (x2
, y2
);
222 void wxWindowDC::DrawEllipticArc( long x
, long y
, long width
, long height
, double sa
, double ea
)
224 wxCHECK_RET( Ok(), "invalid window dc" );
226 long xx
= XLOG2DEV(x
);
227 long yy
= YLOG2DEV(y
);
228 long ww
= m_signX
* XLOG2DEVREL(width
);
229 long hh
= m_signY
* YLOG2DEVREL(height
);
231 // CMB: handle -ve width and/or height
232 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
233 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
235 long start
= long(sa
* 64.0);
236 long end
= long(ea
* 64.0);
237 if (m_brush
.GetStyle() != wxTRANSPARENT
)
238 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
240 if (m_pen
.GetStyle() != wxTRANSPARENT
)
241 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
243 CalcBoundingBox (x
, y
);
244 CalcBoundingBox (x
+ width
, y
+ height
);
247 void wxWindowDC::DrawPoint( long x
, long y
)
249 wxCHECK_RET( Ok(), "invalid window dc" );
251 if (m_pen
.GetStyle() != wxTRANSPARENT
)
252 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
254 CalcBoundingBox (x
, y
);
257 void wxWindowDC::DrawLines( int n
, wxPoint points
[], long xoffset
, long yoffset
)
259 wxCHECK_RET( Ok(), "invalid window dc" );
261 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
264 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
266 for (int i
= 0; i
< n
-1; i
++)
268 long x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
269 long x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
270 long y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
271 long y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
272 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
274 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
278 void wxWindowDC::DrawLines( wxList
*points
, long xoffset
, long yoffset
)
280 wxCHECK_RET( Ok(), "invalid window dc" );
282 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
284 wxNode
*node
= points
->First();
287 wxPoint
*pt
= (wxPoint
*)node
->Data();
288 CalcBoundingBox( pt
->x
+ xoffset
, pt
->y
+ yoffset
);
292 wxPoint
*point
= (wxPoint
*)node
->Data();
293 wxPoint
*npoint
= (wxPoint
*)node
->Next()->Data();
294 long x1
= XLOG2DEV(point
->x
+ xoffset
);
295 long x2
= XLOG2DEV(npoint
->x
+ xoffset
);
296 long y1
= YLOG2DEV(point
->y
+ yoffset
); // and a waste again...
297 long y2
= YLOG2DEV(npoint
->y
+ yoffset
);
298 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
301 CalcBoundingBox( npoint
->x
+ xoffset
, npoint
->y
+ yoffset
);
305 void wxWindowDC::DrawPolygon( int n
, wxPoint points
[], long xoffset
, long yoffset
, int WXUNUSED(fillStyle
) )
307 wxCHECK_RET( Ok(), "invalid window dc" );
311 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
313 for (i
= 0 ; i
< n
; i
++)
315 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
316 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
318 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
321 if (m_brush
.GetStyle() != wxTRANSPARENT
)
322 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
326 if (m_pen
.GetStyle() != wxTRANSPARENT
)
327 for (i
= 0 ; i
< n
; i
++)
329 gdk_draw_line( m_window
, m_penGC
,
332 gdkpoints
[(i
+1)%n
].x
,
333 gdkpoints
[(i
+1)%n
].y
);
339 void wxWindowDC::DrawPolygon( wxList
*lines
, long xoffset
, long yoffset
, int WXUNUSED(fillStyle
))
341 wxCHECK_RET( Ok(), "invalid window dc" );
343 int n
= lines
->Number();
346 GdkPoint
*gdkpoints
= new GdkPoint
[n
];
347 wxNode
*node
= lines
->First();
351 wxPoint
*p
= (wxPoint
*) node
->Data();
352 gdkpoints
[cnt
].x
= XLOG2DEV(p
->x
+ xoffset
);
353 gdkpoints
[cnt
].y
= YLOG2DEV(p
->y
+ yoffset
);
357 CalcBoundingBox( p
->x
+ xoffset
, p
->y
+ yoffset
);
360 if (m_brush
.GetStyle() != wxTRANSPARENT
)
361 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
365 if (m_pen
.GetStyle() != wxTRANSPARENT
)
368 for (i
= 0 ; i
< n
; i
++)
370 gdk_draw_line( m_window
, m_penGC
,
373 gdkpoints
[(i
+1)%n
].x
,
374 gdkpoints
[(i
+1)%n
].y
);
380 void wxWindowDC::DrawRectangle( long x
, long y
, long width
, long height
)
382 wxCHECK_RET( Ok(), "invalid window dc" );
384 long xx
= XLOG2DEV(x
);
385 long yy
= YLOG2DEV(y
);
386 long ww
= m_signX
* XLOG2DEVREL(width
);
387 long hh
= m_signY
* YLOG2DEVREL(height
);
389 // CMB: draw nothing if transformed w or h is 0
390 if (ww
== 0 || hh
== 0) return;
392 // CMB: handle -ve width and/or height
393 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
394 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
396 if (m_brush
.GetStyle() != wxTRANSPARENT
)
397 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
399 if (m_pen
.GetStyle() != wxTRANSPARENT
)
400 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
402 CalcBoundingBox( x
, y
);
403 CalcBoundingBox( x
+ width
, y
+ height
);
406 void wxWindowDC::DrawRoundedRectangle( long x
, long y
, long width
, long height
, double radius
)
408 wxCHECK_RET( Ok(), "invalid window dc" );
410 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
412 long xx
= XLOG2DEV(x
);
413 long yy
= YLOG2DEV(y
);
414 long ww
= m_signX
* XLOG2DEVREL(width
);
415 long hh
= m_signY
* YLOG2DEVREL(height
);
416 long rr
= XLOG2DEVREL((long)radius
);
418 // CMB: handle -ve width and/or height
419 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
420 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
422 // CMB: if radius is zero use DrawRectangle() instead to avoid
423 // X drawing errors with small radii
426 DrawRectangle( x
, y
, width
, height
);
430 // CMB: draw nothing if transformed w or h is 0
431 if (ww
== 0 || hh
== 0) return;
433 // CMB: adjust size if outline is drawn otherwise the result is
434 // 1 pixel too wide and high
435 if (m_pen
.GetStyle() != wxTRANSPARENT
)
441 // CMB: ensure dd is not larger than rectangle otherwise we
442 // get an hour glass shape
444 if (dd
> ww
) dd
= ww
;
445 if (dd
> hh
) dd
= hh
;
448 if (m_brush
.GetStyle() != wxTRANSPARENT
)
450 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
451 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
452 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
453 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
454 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
455 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
458 if (m_pen
.GetStyle() != wxTRANSPARENT
)
460 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
461 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
462 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
463 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
464 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
465 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
466 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
467 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
470 // this ignores the radius
471 CalcBoundingBox( x
, y
);
472 CalcBoundingBox( x
+ width
, y
+ height
);
475 void wxWindowDC::DrawEllipse( long x
, long y
, long width
, long height
)
477 wxCHECK_RET( Ok(), "invalid window dc" );
479 long xx
= XLOG2DEV(x
);
480 long yy
= YLOG2DEV(y
);
481 long ww
= m_signX
* XLOG2DEVREL(width
);
482 long hh
= m_signY
* YLOG2DEVREL(height
);
484 // CMB: handle -ve width and/or height
485 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
486 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
488 if (m_brush
.GetStyle() != wxTRANSPARENT
)
489 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
491 if (m_pen
.GetStyle() != wxTRANSPARENT
)
492 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
494 CalcBoundingBox( x
- width
, y
- height
);
495 CalcBoundingBox( x
+ width
, y
+ height
);
498 bool wxWindowDC::CanDrawBitmap() const
503 void wxWindowDC::DrawIcon( const wxIcon
&icon
, long x
, long y
)
505 DrawBitmap( icon
, x
, y
, TRUE
);
508 void wxWindowDC::DrawBitmap( const wxBitmap
&bitmap
, long x
, long y
, bool useMask
)
510 wxCHECK_RET( Ok(), "invalid window dc" );
512 if (!bitmap
.Ok()) return;
514 /* scale/translate size and position */
516 int xx
= XLOG2DEV(x
);
517 int yy
= YLOG2DEV(y
);
519 int w
= bitmap
.GetWidth();
520 int h
= bitmap
.GetHeight();
522 int ww
= XLOG2DEVREL(w
);
523 int hh
= YLOG2DEVREL(h
);
525 /* scale bitmap if required */
529 if ((w
!= ww
) || (h
!= hh
))
531 wxImage
image( bitmap
);
532 image
= image
.Scale( ww
, hh
);
534 use_bitmap
= image
.ConvertToBitmap();
541 /* apply mask if any */
543 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
544 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
548 gdk_gc_set_clip_mask( m_penGC
, mask
);
549 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
552 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
554 GdkPixmap
*pm
= use_bitmap
.GetPixmap();
557 gdk_draw_pixmap( m_window
, m_penGC
, pm
, 0, 0, xx
, yy
, -1, -1 );
561 GdkBitmap
*bm
= use_bitmap
.GetBitmap();
564 gdk_draw_bitmap( m_window
, m_penGC
, bm
, 0, 0, xx
, yy
, -1, -1 );
568 /* remove mask again if any */
572 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
573 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
576 CalcBoundingBox( x
, y
);
577 CalcBoundingBox( x
+ w
, y
+ h
);
580 bool wxWindowDC::Blit( long xdest
, long ydest
, long width
, long height
,
581 wxDC
*source
, long xsrc
, long ysrc
, int logical_func
, bool useMask
)
583 /* this is the nth try to get this utterly useless function to
584 work. it now completely ignores the scaling or translation
585 of the source dc, but scales correctly on the target dc and
586 knows about possible mask information in a memory dc. */
588 wxCHECK_MSG( Ok(), FALSE
, "invalid window dc" );
590 wxCHECK_MSG( source
, FALSE
, "invalid source dc" );
592 wxClientDC
*srcDC
= (wxClientDC
*)source
;
593 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
595 bool use_bitmap_method
= FALSE
;
597 if (srcDC
->m_isMemDC
)
599 if (!memDC
->m_selected
.Ok()) return FALSE
;
601 /* we use the "XCopyArea" way to copy a memory dc into
602 y different window if the memory dc BOTH
603 a) doesn't have any mask or its mask isn't used
605 we HAVE TO use the direct way for memory dcs
606 that have mask since the XCopyArea doesn't know
607 about masks and we SHOULD use the direct way if
608 all of the bitmap in the memory dc is copied in
609 which case XCopyArea wouldn't be able able to
610 boost performace by reducing the area to be scaled */
612 use_bitmap_method
= ( (useMask
&& (memDC
->m_selected
.GetMask())) ||
613 ((xsrc
== 0) && (ysrc
== 0) &&
614 (width
== memDC
->m_selected
.GetWidth()) &&
615 (height
== memDC
->m_selected
.GetHeight()) )
619 CalcBoundingBox( xdest
, ydest
);
620 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
622 int old_logical_func
= m_logicalFunction
;
623 SetLogicalFunction( logical_func
);
625 if (use_bitmap_method
)
627 /* scale/translate bitmap size */
629 long bm_width
= memDC
->m_selected
.GetWidth();
630 long bm_height
= memDC
->m_selected
.GetHeight();
632 long bm_ww
= XLOG2DEVREL( bm_width
);
633 long bm_hh
= YLOG2DEVREL( bm_height
);
635 /* scale bitmap if required */
639 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
641 wxImage
image( memDC
->m_selected
);
642 image
= image
.Scale( bm_ww
, bm_hh
);
644 use_bitmap
= image
.ConvertToBitmap();
648 use_bitmap
= memDC
->m_selected
;
651 /* scale/translate size and position */
653 long xx
= XLOG2DEV(xdest
);
654 long yy
= YLOG2DEV(ydest
);
656 long ww
= XLOG2DEVREL(width
);
657 long hh
= YLOG2DEVREL(height
);
659 /* apply mask if any */
661 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
662 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
666 gdk_gc_set_clip_mask( m_penGC
, mask
);
667 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
670 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
672 GdkPixmap
*pm
= use_bitmap
.GetPixmap();
675 gdk_draw_pixmap( m_window
, m_penGC
, pm
, 0, 0, xx
, yy
, ww
, hh
);
679 GdkBitmap
*bm
= use_bitmap
.GetBitmap();
682 gdk_draw_bitmap( m_window
, m_penGC
, bm
, 0, 0, xx
, yy
, ww
, hh
);
686 /* remove mask again if any */
690 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
691 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
694 else /* use_bitmap_method */
696 /* scale/translate size and position */
698 long xx
= XLOG2DEV(xdest
);
699 long yy
= YLOG2DEV(ydest
);
701 long ww
= XLOG2DEVREL(width
);
702 long hh
= YLOG2DEVREL(height
);
704 if ((width
!= ww
) || (height
!= hh
))
706 /* draw source window into a bitmap as we cannot scale
707 a window in contrast to a bitmap. this would actually
708 work with memory dcs as well, but we'd lose the mask
709 information and waste one step in this process since
710 a memory already has a bitmap. all this is slightly
711 inefficient as we could take an XImage directly from
712 an X window, but we'd then also have to care that
713 the window is not outside the screen (in which case
714 we'd get a BadMatch or what not).
715 Is a double XGetImage and combined XGetPixel and
716 XPutPixel really faster? I'm not sure. look at wxXt
717 for a different implementation of the same problem. */
719 wxBitmap
bitmap( width
, height
);
720 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
722 xsrc
, ysrc
, width
, height
);
726 wxImage
image( bitmap
);
727 image
= image
.Scale( ww
, hh
);
729 /* convert to bitmap */
731 bitmap
= image
.ConvertToBitmap();
733 /* draw scaled bitmap */
735 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
740 /* no scaling and not a memory dc with a mask either */
742 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
744 xsrc
, ysrc
, width
, height
);
748 SetLogicalFunction( old_logical_func
);
752 void wxWindowDC::DrawText( const wxString
&text
, long x
, long y
, bool WXUNUSED(use16
) )
754 wxCHECK_RET( Ok(), "invalid window dc" );
756 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
761 // CMB 21/5/98: draw text background if mode is wxSOLID
762 if (m_backgroundMode
== wxSOLID
)
764 long width
= gdk_string_width( font
, text
);
765 long height
= font
->ascent
+ font
->descent
;
766 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
767 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
768 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
770 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
);
772 // CMB 17/7/98: simple underline: ignores scaling and underlying
773 // X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
774 // properties (see wxXt implementation)
775 if (m_font
.GetUnderlined())
777 long width
= gdk_string_width( font
, text
);
778 long ul_y
= y
+ font
->ascent
;
779 if (font
->descent
> 0) ul_y
++;
780 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
784 GetTextExtent (text
, &w
, &h
);
785 CalcBoundingBox (x
+ w
, y
+ h
);
786 CalcBoundingBox (x
, y
);
789 bool wxWindowDC::CanGetTextExtent() const
794 void wxWindowDC::GetTextExtent( const wxString
&string
, long *width
, long *height
,
795 long *descent
, long *externalLeading
,
796 wxFont
*theFont
, bool WXUNUSED(use16
) )
798 wxCHECK_RET( Ok(), "invalid window dc" );
800 wxFont fontToUse
= m_font
;
801 if (theFont
) fontToUse
= *theFont
;
803 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
804 if (width
) (*width
) = long(gdk_string_width( font
, string
) / m_scaleX
);
805 if (height
) (*height
) = long((font
->ascent
+ font
->descent
) / m_scaleY
);
806 if (descent
) (*descent
) = long(font
->descent
/ m_scaleY
);
807 if (externalLeading
) (*externalLeading
) = 0; // ??
810 long wxWindowDC::GetCharWidth()
812 wxCHECK_MSG( Ok(), 0, "invalid window dc" );
814 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
815 return long(gdk_string_width( font
, "H" ) / m_scaleX
);
818 long wxWindowDC::GetCharHeight()
820 wxCHECK_MSG( Ok(), 0, "invalid window dc" );
822 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
823 return long((font
->ascent
+ font
->descent
) / m_scaleY
);
826 void wxWindowDC::Clear()
828 wxCHECK_RET( Ok(), "invalid window dc" );
832 gdk_window_clear( m_window
);
837 GetSize( &width
, &height
);
838 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
842 void wxWindowDC::SetFont( const wxFont
&font
)
844 wxCHECK_RET( Ok(), "invalid window dc" );
849 void wxWindowDC::SetPen( const wxPen
&pen
)
851 wxCHECK_RET( Ok(), "invalid window dc" );
853 if (m_pen
== pen
) return;
857 if (!m_pen
.Ok()) return;
859 gint width
= m_pen
.GetWidth();
860 // CMB: if width is non-zero scale it with the dc
867 // X doesn't allow different width in x and y and so we take
869 double w
= 0.5 + (abs(XLOG2DEVREL(width
)) + abs(YLOG2DEVREL(width
))) / 2.0;
873 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
874 switch (m_pen
.GetStyle())
876 case wxSOLID
: { lineStyle
= GDK_LINE_SOLID
; break; }
877 case wxDOT
: { lineStyle
= GDK_LINE_ON_OFF_DASH
; break; }
878 case wxLONG_DASH
: { lineStyle
= GDK_LINE_ON_OFF_DASH
; break; }
879 case wxSHORT_DASH
: { lineStyle
= GDK_LINE_ON_OFF_DASH
; break; }
880 case wxDOT_DASH
: { lineStyle
= GDK_LINE_DOUBLE_DASH
; break; }
883 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
884 switch (m_pen
.GetCap())
886 case wxCAP_ROUND
: { capStyle
= (width
<= 1) ? GDK_CAP_NOT_LAST
: GDK_CAP_ROUND
; break; }
887 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
888 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
891 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
892 switch (m_pen
.GetJoin())
894 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
895 case wxJOIN_ROUND
: { joinStyle
= GDK_JOIN_ROUND
; break; }
896 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
899 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
901 m_pen
.GetColour().CalcPixel( m_cmap
);
902 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
905 void wxWindowDC::SetBrush( const wxBrush
&brush
)
907 wxCHECK_RET( Ok(), "invalid window dc" );
909 if (m_brush
== brush
) return;
913 if (!m_brush
.Ok()) return;
915 m_brush
.GetColour().CalcPixel( m_cmap
);
916 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
918 GdkFill fillStyle
= GDK_SOLID
;
919 switch (m_brush
.GetStyle())
925 fillStyle
= GDK_STIPPLED
;
928 gdk_gc_set_fill( m_brushGC
, fillStyle
);
930 if (m_brush
.GetStyle() == wxSTIPPLE
)
932 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
935 if (IS_HATCH(m_brush
.GetStyle()))
937 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
938 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
942 void wxWindowDC::SetBackground( const wxBrush
&brush
)
944 // CMB 21/7/98: Added SetBackground. Sets background brush
945 // for Clear() and bg colour for shapes filled with cross-hatch brush
947 wxCHECK_RET( Ok(), "invalid window dc" );
949 if (m_backgroundBrush
== brush
) return;
951 m_backgroundBrush
= brush
;
953 if (!m_backgroundBrush
.Ok()) return;
955 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
956 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
957 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
958 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
959 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
961 GdkFill fillStyle
= GDK_SOLID
;
962 switch (m_backgroundBrush
.GetStyle())
968 fillStyle
= GDK_STIPPLED
;
971 gdk_gc_set_fill( m_bgGC
, fillStyle
);
973 if (m_backgroundBrush
.GetStyle() == wxSTIPPLE
)
975 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
978 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
980 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
981 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
985 void wxWindowDC::SetLogicalFunction( int function
)
987 wxCHECK_RET( Ok(), "invalid window dc" );
989 if (m_logicalFunction
== function
) return;
991 GdkFunction mode
= GDK_COPY
;
994 case wxXOR
: mode
= GDK_INVERT
; break;
995 case wxINVERT
: mode
= GDK_INVERT
; break;
999 m_logicalFunction
= function
;
1000 gdk_gc_set_function( m_penGC
, mode
);
1001 gdk_gc_set_function( m_brushGC
, mode
);
1002 gdk_gc_set_function( m_textGC
, mode
);
1005 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1007 wxCHECK_RET( Ok(), "invalid window dc" );
1009 if (m_textForegroundColour
== col
) return;
1011 m_textForegroundColour
= col
;
1012 if (!m_textForegroundColour
.Ok()) return;
1014 m_textForegroundColour
.CalcPixel( m_cmap
);
1015 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1018 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1020 wxCHECK_RET( Ok(), "invalid window dc" );
1022 if (m_textBackgroundColour
== col
) return;
1024 m_textBackgroundColour
= col
;
1025 if (!m_textBackgroundColour
.Ok()) return;
1027 m_textBackgroundColour
.CalcPixel( m_cmap
);
1028 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1031 void wxWindowDC::SetBackgroundMode( int mode
)
1033 wxCHECK_RET( Ok(), "invalid window dc" );
1035 m_backgroundMode
= mode
;
1037 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1038 // transparent/solid background mode
1040 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1042 gdk_gc_set_fill( m_brushGC
,
1043 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1047 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1049 wxFAIL_MSG( "wxWindowDC::SetPalette not implemented" );
1052 void wxWindowDC::SetClippingRegion( long x
, long y
, long width
, long height
)
1054 wxCHECK_RET( Ok(), "invalid window dc" );
1056 wxDC::SetClippingRegion( x
, y
, width
, height
);
1059 rect
.x
= XLOG2DEV(x
);
1060 rect
.y
= YLOG2DEV(y
);
1061 rect
.width
= XLOG2DEVREL(width
);
1062 rect
.height
= YLOG2DEVREL(height
);
1063 gdk_gc_set_clip_rectangle( m_penGC
, &rect
);
1064 gdk_gc_set_clip_rectangle( m_brushGC
, &rect
);
1065 gdk_gc_set_clip_rectangle( m_textGC
, &rect
);
1066 gdk_gc_set_clip_rectangle( m_bgGC
, &rect
);
1069 void wxWindowDC::SetClippingRegion( const wxRegion
®ion
)
1071 wxCHECK_RET( Ok(), "invalid window dc" );
1075 DestroyClippingRegion();
1079 gdk_gc_set_clip_region( m_penGC
, region
.GetRegion() );
1080 gdk_gc_set_clip_region( m_brushGC
, region
.GetRegion() );
1081 gdk_gc_set_clip_region( m_textGC
, region
.GetRegion() );
1082 gdk_gc_set_clip_region( m_bgGC
, region
.GetRegion() );
1085 void wxWindowDC::DestroyClippingRegion()
1087 wxCHECK_RET( Ok(), "invalid window dc" );
1089 wxDC::DestroyClippingRegion();
1091 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1092 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1093 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1094 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1097 void wxWindowDC::SetUpDC()
1101 m_logicalFunction
= wxCOPY
;
1102 m_penGC
= gdk_gc_new( m_window
);
1103 m_brushGC
= gdk_gc_new( m_window
);
1104 m_textGC
= gdk_gc_new( m_window
);
1105 m_bgGC
= gdk_gc_new( m_window
);
1107 wxColour
tmp_col( m_textForegroundColour
);
1108 m_textForegroundColour
= wxNullColour
;
1109 SetTextForeground( tmp_col
);
1110 tmp_col
= m_textBackgroundColour
;
1111 m_textBackgroundColour
= wxNullColour
;
1112 SetTextBackground( tmp_col
);
1114 wxPen
tmp_pen( m_pen
);
1118 wxFont
tmp_font( m_font
);
1119 m_font
= wxNullFont
;
1120 SetFont( tmp_font
);
1122 wxBrush
tmp_brush( m_brush
);
1123 m_brush
= wxNullBrush
;
1124 SetBrush( tmp_brush
);
1126 tmp_brush
= m_backgroundBrush
;
1127 m_backgroundBrush
= wxNullBrush
;
1128 SetBackground( tmp_brush
);
1132 hatch_bitmap
= hatches
;
1133 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1134 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1135 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1136 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1137 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1138 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1142 void wxWindowDC::Destroy()
1144 if (m_penGC
) gdk_gc_unref( m_penGC
);
1145 m_penGC
= (GdkGC
*) NULL
;
1146 if (m_brushGC
) gdk_gc_unref( m_brushGC
);
1147 m_brushGC
= (GdkGC
*) NULL
;
1148 if (m_textGC
) gdk_gc_unref( m_textGC
);
1149 m_textGC
= (GdkGC
*) NULL
;
1150 if (m_bgGC
) gdk_gc_unref( m_bgGC
);
1151 m_bgGC
= (GdkGC
*) NULL
;
1154 GdkWindow
*wxWindowDC::GetWindow()
1159 // ----------------------------------- spline code ----------------------------------------
1161 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1162 double a3
, double b3
, double a4
, double b4
);
1163 void wx_clear_stack();
1164 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1165 double *y3
, double *x4
, double *y4
);
1166 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1167 double x4
, double y4
);
1168 static bool wx_spline_add_point(double x
, double y
);
1169 static void wx_spline_draw_point_array(wxDC
*dc
);
1171 wxList wx_spline_point_list
;
1173 #define half(z1, z2) ((z1+z2)/2.0)
1176 /* iterative version */
1178 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1181 register double xmid
, ymid
;
1182 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1185 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1187 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1188 xmid
= (double)half(x2
, x3
);
1189 ymid
= (double)half(y2
, y3
);
1190 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1191 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1192 wx_spline_add_point( x1
, y1
);
1193 wx_spline_add_point( xmid
, ymid
);
1195 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1196 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1197 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1198 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1203 /* utilities used by spline drawing routines */
1205 typedef struct wx_spline_stack_struct
{
1206 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1209 #define SPLINE_STACK_DEPTH 20
1210 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1211 static Stack
*wx_stack_top
;
1212 static int wx_stack_count
;
1214 void wx_clear_stack()
1216 wx_stack_top
= wx_spline_stack
;
1220 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1222 wx_stack_top
->x1
= x1
;
1223 wx_stack_top
->y1
= y1
;
1224 wx_stack_top
->x2
= x2
;
1225 wx_stack_top
->y2
= y2
;
1226 wx_stack_top
->x3
= x3
;
1227 wx_stack_top
->y3
= y3
;
1228 wx_stack_top
->x4
= x4
;
1229 wx_stack_top
->y4
= y4
;
1234 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1235 double *x3
, double *y3
, double *x4
, double *y4
)
1237 if (wx_stack_count
== 0)
1241 *x1
= wx_stack_top
->x1
;
1242 *y1
= wx_stack_top
->y1
;
1243 *x2
= wx_stack_top
->x2
;
1244 *y2
= wx_stack_top
->y2
;
1245 *x3
= wx_stack_top
->x3
;
1246 *y3
= wx_stack_top
->y3
;
1247 *x4
= wx_stack_top
->x4
;
1248 *y4
= wx_stack_top
->y4
;
1252 static bool wx_spline_add_point(double x
, double y
)
1254 wxPoint
*point
= new wxPoint
;
1257 wx_spline_point_list
.Append((wxObject
*)point
);
1261 static void wx_spline_draw_point_array(wxDC
*dc
)
1263 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1264 wxNode
*node
= wx_spline_point_list
.First();
1267 wxPoint
*point
= (wxPoint
*)node
->Data();
1270 node
= wx_spline_point_list
.First();
1274 void wxWindowDC::DrawSpline( wxList
*points
)
1276 wxCHECK_RET( Ok(), "invalid window dc" );
1279 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1280 double x1
, y1
, x2
, y2
;
1282 wxNode
*node
= points
->First();
1283 p
= (wxPoint
*)node
->Data();
1288 node
= node
->Next();
1289 p
= (wxPoint
*)node
->Data();
1293 cx1
= (double)((x1
+ x2
) / 2);
1294 cy1
= (double)((y1
+ y2
) / 2);
1295 cx2
= (double)((cx1
+ x2
) / 2);
1296 cy2
= (double)((cy1
+ y2
) / 2);
1298 wx_spline_add_point(x1
, y1
);
1300 while ((node
= node
->Next()) != NULL
)
1302 p
= (wxPoint
*)node
->Data();
1307 cx4
= (double)(x1
+ x2
) / 2;
1308 cy4
= (double)(y1
+ y2
) / 2;
1309 cx3
= (double)(x1
+ cx4
) / 2;
1310 cy3
= (double)(y1
+ cy4
) / 2;
1312 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1316 cx2
= (double)(cx1
+ x2
) / 2;
1317 cy2
= (double)(cy1
+ y2
) / 2;
1320 wx_spline_add_point( cx1
, cy1
);
1321 wx_spline_add_point( x2
, y2
);
1323 wx_spline_draw_point_array( this );
1327 //-----------------------------------------------------------------------------
1329 //-----------------------------------------------------------------------------
1331 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1333 wxPaintDC::wxPaintDC()
1338 wxPaintDC::wxPaintDC( wxWindow
*win
)
1343 //-----------------------------------------------------------------------------
1345 //-----------------------------------------------------------------------------
1347 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1349 wxClientDC::wxClientDC()
1354 wxClientDC::wxClientDC( wxWindow
*win
)