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 int xx
= XLOG2DEV(x
);
515 int yy
= YLOG2DEV(y
);
517 int w
= bitmap
.GetWidth();
518 int h
= bitmap
.GetHeight();
520 int ww
= XLOG2DEVREL(w
);
521 int hh
= YLOG2DEVREL(h
);
525 if ((w
!= ww
) || (h
!= hh
))
527 wxImage
image( bitmap
);
528 image
= image
.Scale( ww
, hh
);
530 use_bitmap
= image
.ConvertToBitmap();
537 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
538 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
542 gdk_gc_set_clip_mask( m_penGC
, mask
);
543 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
546 GdkPixmap
*pm
= use_bitmap
.GetPixmap();
547 gdk_draw_pixmap( m_window
, m_penGC
, pm
, 0, 0, xx
, yy
, -1, -1 );
551 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
552 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
555 CalcBoundingBox( x
, y
);
556 CalcBoundingBox( x
+ w
, y
+ h
);
559 bool wxWindowDC::Blit( long xdest
, long ydest
, long width
, long height
,
560 wxDC
*source
, long xsrc
, long ysrc
, int logical_func
, bool useMask
)
562 wxCHECK_MSG( Ok(), FALSE
, "invalid window dc" );
564 CalcBoundingBox( xdest
, ydest
);
565 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
567 int old_logical_func
= m_logicalFunction
;
568 SetLogicalFunction( logical_func
);
570 wxClientDC
*csrc
= (wxClientDC
*)source
;
574 wxMemoryDC
* srcDC
= (wxMemoryDC
*)source
;
575 GdkPixmap
* pmap
= srcDC
->m_selected
.GetPixmap();
578 long xx
= XLOG2DEV(xdest
);
579 long yy
= YLOG2DEV(ydest
);
581 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
582 if (srcDC
->m_selected
.GetMask()) mask
= srcDC
->m_selected
.GetMask()->GetBitmap();
586 gdk_gc_set_clip_mask( m_penGC
, mask
);
587 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
590 gdk_draw_pixmap( m_window
, m_penGC
, pmap
,
591 source
->DeviceToLogicalX(xsrc
),
592 source
->DeviceToLogicalY(ysrc
),
595 source
->DeviceToLogicalXRel(width
),
596 source
->DeviceToLogicalYRel(height
) );
600 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
601 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
604 SetLogicalFunction( old_logical_func
);
608 GdkBitmap
* bmap
= srcDC
->m_selected
.GetBitmap();
611 long xx
= XLOG2DEV(xdest
);
612 long yy
= YLOG2DEV(ydest
);
614 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
615 if (srcDC
->m_selected
.GetMask()) mask
= srcDC
->m_selected
.GetMask()->GetBitmap();
619 gdk_gc_set_clip_mask( m_penGC
, mask
);
620 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
623 gdk_draw_bitmap( m_window
, m_textGC
, bmap
,
624 source
->DeviceToLogicalX(xsrc
),
625 source
->DeviceToLogicalY(ysrc
),
628 source
->DeviceToLogicalXRel(width
),
629 source
->DeviceToLogicalYRel(height
) );
633 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
634 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
637 SetLogicalFunction( old_logical_func
);
642 gdk_window_copy_area ( m_window
, m_penGC
,
643 XLOG2DEV(xdest
), YLOG2DEV(ydest
),
645 source
->DeviceToLogicalX(xsrc
),
646 source
->DeviceToLogicalY(ysrc
),
647 source
->DeviceToLogicalXRel(width
),
648 source
->DeviceToLogicalYRel(height
) );
650 SetLogicalFunction( old_logical_func
);
654 void wxWindowDC::DrawText( const wxString
&text
, long x
, long y
, bool WXUNUSED(use16
) )
656 wxCHECK_RET( Ok(), "invalid window dc" );
658 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
663 // CMB 21/5/98: draw text background if mode is wxSOLID
664 if (m_backgroundMode
== wxSOLID
)
666 long width
= gdk_string_width( font
, text
);
667 long height
= font
->ascent
+ font
->descent
;
668 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
669 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
670 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
672 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
);
674 // CMB 17/7/98: simple underline: ignores scaling and underlying
675 // X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
676 // properties (see wxXt implementation)
677 if (m_font
.GetUnderlined())
679 long width
= gdk_string_width( font
, text
);
680 long ul_y
= y
+ font
->ascent
;
681 if (font
->descent
> 0) ul_y
++;
682 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
686 GetTextExtent (text
, &w
, &h
);
687 CalcBoundingBox (x
+ w
, y
+ h
);
688 CalcBoundingBox (x
, y
);
691 bool wxWindowDC::CanGetTextExtent() const
696 void wxWindowDC::GetTextExtent( const wxString
&string
, long *width
, long *height
,
697 long *descent
, long *externalLeading
,
698 wxFont
*theFont
, bool WXUNUSED(use16
) )
700 wxCHECK_RET( Ok(), "invalid window dc" );
702 wxFont fontToUse
= m_font
;
703 if (theFont
) fontToUse
= *theFont
;
705 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
706 if (width
) (*width
) = long(gdk_string_width( font
, string
) / m_scaleX
);
707 if (height
) (*height
) = long((font
->ascent
+ font
->descent
) / m_scaleY
);
708 if (descent
) (*descent
) = long(font
->descent
/ m_scaleY
);
709 if (externalLeading
) (*externalLeading
) = 0; // ??
712 long wxWindowDC::GetCharWidth()
714 wxCHECK_MSG( Ok(), 0, "invalid window dc" );
716 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
717 return long(gdk_string_width( font
, "H" ) / m_scaleX
);
720 long wxWindowDC::GetCharHeight()
722 wxCHECK_MSG( Ok(), 0, "invalid window dc" );
724 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
725 return long((font
->ascent
+ font
->descent
) / m_scaleY
);
728 void wxWindowDC::Clear()
730 wxCHECK_RET( Ok(), "invalid window dc" );
734 gdk_window_clear( m_window
);
739 GetSize( &width
, &height
);
740 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
744 void wxWindowDC::SetFont( const wxFont
&font
)
746 wxCHECK_RET( Ok(), "invalid window dc" );
751 void wxWindowDC::SetPen( const wxPen
&pen
)
753 wxCHECK_RET( Ok(), "invalid window dc" );
755 if (m_pen
== pen
) return;
759 if (!m_pen
.Ok()) return;
761 gint width
= m_pen
.GetWidth();
762 // CMB: if width is non-zero scale it with the dc
769 // X doesn't allow different width in x and y and so we take
771 double w
= 0.5 + (abs(XLOG2DEVREL(width
)) + abs(YLOG2DEVREL(width
))) / 2.0;
775 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
776 switch (m_pen
.GetStyle())
778 case wxSOLID
: { lineStyle
= GDK_LINE_SOLID
; break; }
779 case wxDOT
: { lineStyle
= GDK_LINE_ON_OFF_DASH
; break; }
780 case wxLONG_DASH
: { lineStyle
= GDK_LINE_ON_OFF_DASH
; break; }
781 case wxSHORT_DASH
: { lineStyle
= GDK_LINE_ON_OFF_DASH
; break; }
782 case wxDOT_DASH
: { lineStyle
= GDK_LINE_DOUBLE_DASH
; break; }
785 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
786 switch (m_pen
.GetCap())
788 case wxCAP_ROUND
: { capStyle
= (width
<= 1) ? GDK_CAP_NOT_LAST
: GDK_CAP_ROUND
; break; }
789 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
790 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
793 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
794 switch (m_pen
.GetJoin())
796 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
797 case wxJOIN_ROUND
: { joinStyle
= GDK_JOIN_ROUND
; break; }
798 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
801 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
803 m_pen
.GetColour().CalcPixel( m_cmap
);
804 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
807 void wxWindowDC::SetBrush( const wxBrush
&brush
)
809 wxCHECK_RET( Ok(), "invalid window dc" );
811 if (m_brush
== brush
) return;
815 if (!m_brush
.Ok()) return;
817 m_brush
.GetColour().CalcPixel( m_cmap
);
818 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
820 GdkFill fillStyle
= GDK_SOLID
;
821 switch (m_brush
.GetStyle())
827 fillStyle
= GDK_STIPPLED
;
830 gdk_gc_set_fill( m_brushGC
, fillStyle
);
832 if (m_brush
.GetStyle() == wxSTIPPLE
)
834 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
837 if (IS_HATCH(m_brush
.GetStyle()))
839 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
840 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
844 void wxWindowDC::SetBackground( const wxBrush
&brush
)
846 // CMB 21/7/98: Added SetBackground. Sets background brush
847 // for Clear() and bg colour for shapes filled with cross-hatch brush
849 wxCHECK_RET( Ok(), "invalid window dc" );
851 if (m_backgroundBrush
== brush
) return;
853 m_backgroundBrush
= brush
;
855 if (!m_backgroundBrush
.Ok()) return;
857 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
858 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
859 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
860 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
861 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
863 GdkFill fillStyle
= GDK_SOLID
;
864 switch (m_backgroundBrush
.GetStyle())
870 fillStyle
= GDK_STIPPLED
;
873 gdk_gc_set_fill( m_bgGC
, fillStyle
);
875 if (m_backgroundBrush
.GetStyle() == wxSTIPPLE
)
877 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
880 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
882 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
883 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
887 void wxWindowDC::SetLogicalFunction( int function
)
889 wxCHECK_RET( Ok(), "invalid window dc" );
891 if (m_logicalFunction
== function
) return;
893 GdkFunction mode
= GDK_COPY
;
896 case wxXOR
: mode
= GDK_INVERT
; break;
897 case wxINVERT
: mode
= GDK_INVERT
; break;
901 m_logicalFunction
= function
;
902 gdk_gc_set_function( m_penGC
, mode
);
903 gdk_gc_set_function( m_brushGC
, mode
);
904 gdk_gc_set_function( m_textGC
, mode
);
907 void wxWindowDC::SetTextForeground( const wxColour
&col
)
909 wxCHECK_RET( Ok(), "invalid window dc" );
911 if (m_textForegroundColour
== col
) return;
913 m_textForegroundColour
= col
;
914 if (!m_textForegroundColour
.Ok()) return;
916 m_textForegroundColour
.CalcPixel( m_cmap
);
917 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
920 void wxWindowDC::SetTextBackground( const wxColour
&col
)
922 wxCHECK_RET( Ok(), "invalid window dc" );
924 if (m_textBackgroundColour
== col
) return;
926 m_textBackgroundColour
= col
;
927 if (!m_textBackgroundColour
.Ok()) return;
929 m_textBackgroundColour
.CalcPixel( m_cmap
);
930 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
933 void wxWindowDC::SetBackgroundMode( int mode
)
935 wxCHECK_RET( Ok(), "invalid window dc" );
937 m_backgroundMode
= mode
;
939 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
940 // transparent/solid background mode
942 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
944 gdk_gc_set_fill( m_brushGC
,
945 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
949 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
951 wxFAIL_MSG( "wxWindowDC::SetPalette not implemented" );
954 void wxWindowDC::SetClippingRegion( long x
, long y
, long width
, long height
)
956 wxCHECK_RET( Ok(), "invalid window dc" );
958 wxDC::SetClippingRegion( x
, y
, width
, height
);
961 rect
.x
= XLOG2DEV(x
);
962 rect
.y
= YLOG2DEV(y
);
963 rect
.width
= XLOG2DEVREL(width
);
964 rect
.height
= YLOG2DEVREL(height
);
965 gdk_gc_set_clip_rectangle( m_penGC
, &rect
);
966 gdk_gc_set_clip_rectangle( m_brushGC
, &rect
);
967 gdk_gc_set_clip_rectangle( m_textGC
, &rect
);
968 gdk_gc_set_clip_rectangle( m_bgGC
, &rect
);
971 void wxWindowDC::SetClippingRegion( const wxRegion
®ion
)
973 wxCHECK_RET( Ok(), "invalid window dc" );
977 DestroyClippingRegion();
981 gdk_gc_set_clip_region( m_penGC
, region
.GetRegion() );
982 gdk_gc_set_clip_region( m_brushGC
, region
.GetRegion() );
983 gdk_gc_set_clip_region( m_textGC
, region
.GetRegion() );
984 gdk_gc_set_clip_region( m_bgGC
, region
.GetRegion() );
987 void wxWindowDC::DestroyClippingRegion()
989 wxCHECK_RET( Ok(), "invalid window dc" );
991 wxDC::DestroyClippingRegion();
993 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
994 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
995 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
996 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
999 void wxWindowDC::SetUpDC()
1003 m_logicalFunction
= wxCOPY
;
1004 m_penGC
= gdk_gc_new( m_window
);
1005 m_brushGC
= gdk_gc_new( m_window
);
1006 m_textGC
= gdk_gc_new( m_window
);
1007 m_bgGC
= gdk_gc_new( m_window
);
1009 wxColour
tmp_col( m_textForegroundColour
);
1010 m_textForegroundColour
= wxNullColour
;
1011 SetTextForeground( tmp_col
);
1012 tmp_col
= m_textBackgroundColour
;
1013 m_textBackgroundColour
= wxNullColour
;
1014 SetTextBackground( tmp_col
);
1016 wxPen
tmp_pen( m_pen
);
1020 wxFont
tmp_font( m_font
);
1021 m_font
= wxNullFont
;
1022 SetFont( tmp_font
);
1024 wxBrush
tmp_brush( m_brush
);
1025 m_brush
= wxNullBrush
;
1026 SetBrush( tmp_brush
);
1028 tmp_brush
= m_backgroundBrush
;
1029 m_backgroundBrush
= wxNullBrush
;
1030 SetBackground( tmp_brush
);
1034 hatch_bitmap
= hatches
;
1035 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1036 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1037 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1038 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1039 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1040 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1044 void wxWindowDC::Destroy()
1046 if (m_penGC
) gdk_gc_unref( m_penGC
);
1047 m_penGC
= (GdkGC
*) NULL
;
1048 if (m_brushGC
) gdk_gc_unref( m_brushGC
);
1049 m_brushGC
= (GdkGC
*) NULL
;
1050 if (m_textGC
) gdk_gc_unref( m_textGC
);
1051 m_textGC
= (GdkGC
*) NULL
;
1052 if (m_bgGC
) gdk_gc_unref( m_bgGC
);
1053 m_bgGC
= (GdkGC
*) NULL
;
1056 GdkWindow
*wxWindowDC::GetWindow()
1061 // ----------------------------------- spline code ----------------------------------------
1063 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1064 double a3
, double b3
, double a4
, double b4
);
1065 void wx_clear_stack();
1066 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1067 double *y3
, double *x4
, double *y4
);
1068 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1069 double x4
, double y4
);
1070 static bool wx_spline_add_point(double x
, double y
);
1071 static void wx_spline_draw_point_array(wxDC
*dc
);
1073 wxList wx_spline_point_list
;
1075 #define half(z1, z2) ((z1+z2)/2.0)
1078 /* iterative version */
1080 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1083 register double xmid
, ymid
;
1084 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1087 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1089 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1090 xmid
= (double)half(x2
, x3
);
1091 ymid
= (double)half(y2
, y3
);
1092 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1093 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1094 wx_spline_add_point( x1
, y1
);
1095 wx_spline_add_point( xmid
, ymid
);
1097 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1098 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1099 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1100 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1105 /* utilities used by spline drawing routines */
1107 typedef struct wx_spline_stack_struct
{
1108 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1111 #define SPLINE_STACK_DEPTH 20
1112 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1113 static Stack
*wx_stack_top
;
1114 static int wx_stack_count
;
1116 void wx_clear_stack()
1118 wx_stack_top
= wx_spline_stack
;
1122 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1124 wx_stack_top
->x1
= x1
;
1125 wx_stack_top
->y1
= y1
;
1126 wx_stack_top
->x2
= x2
;
1127 wx_stack_top
->y2
= y2
;
1128 wx_stack_top
->x3
= x3
;
1129 wx_stack_top
->y3
= y3
;
1130 wx_stack_top
->x4
= x4
;
1131 wx_stack_top
->y4
= y4
;
1136 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1137 double *x3
, double *y3
, double *x4
, double *y4
)
1139 if (wx_stack_count
== 0)
1143 *x1
= wx_stack_top
->x1
;
1144 *y1
= wx_stack_top
->y1
;
1145 *x2
= wx_stack_top
->x2
;
1146 *y2
= wx_stack_top
->y2
;
1147 *x3
= wx_stack_top
->x3
;
1148 *y3
= wx_stack_top
->y3
;
1149 *x4
= wx_stack_top
->x4
;
1150 *y4
= wx_stack_top
->y4
;
1154 static bool wx_spline_add_point(double x
, double y
)
1156 wxPoint
*point
= new wxPoint
;
1159 wx_spline_point_list
.Append((wxObject
*)point
);
1163 static void wx_spline_draw_point_array(wxDC
*dc
)
1165 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1166 wxNode
*node
= wx_spline_point_list
.First();
1169 wxPoint
*point
= (wxPoint
*)node
->Data();
1172 node
= wx_spline_point_list
.First();
1176 void wxWindowDC::DrawSpline( wxList
*points
)
1178 wxCHECK_RET( Ok(), "invalid window dc" );
1181 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1182 double x1
, y1
, x2
, y2
;
1184 wxNode
*node
= points
->First();
1185 p
= (wxPoint
*)node
->Data();
1190 node
= node
->Next();
1191 p
= (wxPoint
*)node
->Data();
1195 cx1
= (double)((x1
+ x2
) / 2);
1196 cy1
= (double)((y1
+ y2
) / 2);
1197 cx2
= (double)((cx1
+ x2
) / 2);
1198 cy2
= (double)((cy1
+ y2
) / 2);
1200 wx_spline_add_point(x1
, y1
);
1202 while ((node
= node
->Next()) != NULL
)
1204 p
= (wxPoint
*)node
->Data();
1209 cx4
= (double)(x1
+ x2
) / 2;
1210 cy4
= (double)(y1
+ y2
) / 2;
1211 cx3
= (double)(x1
+ cx4
) / 2;
1212 cy3
= (double)(y1
+ cy4
) / 2;
1214 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1218 cx2
= (double)(cx1
+ x2
) / 2;
1219 cy2
= (double)(cy1
+ y2
) / 2;
1222 wx_spline_add_point( cx1
, cy1
);
1223 wx_spline_add_point( x2
, y2
);
1225 wx_spline_draw_point_array( this );
1229 //-----------------------------------------------------------------------------
1231 //-----------------------------------------------------------------------------
1233 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1235 wxPaintDC::wxPaintDC()
1240 wxPaintDC::wxPaintDC( wxWindow
*win
)
1245 //-----------------------------------------------------------------------------
1247 //-----------------------------------------------------------------------------
1249 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1251 wxClientDC::wxClientDC()
1256 wxClientDC::wxClientDC( wxWindow
*win
)