1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "dcclient.h"
14 #include "wx/dcclient.h"
15 #include "wx/dcmemory.h"
17 #include "wx/gtk/win_gtk.h"
19 #include <math.h> // for floating-point functions
23 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
35 static GdkPixmap
*hatches
[num_hatches
];
36 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
38 extern GtkWidget
*wxRootWindow
;
40 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
44 const double RAD2DEG
= 180.0 / M_PI
;
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 static inline double dmax(double a
, double b
) { return a
> b ? a
: b
; }
51 static inline double dmin(double a
, double b
) { return a
< b ? a
: b
; }
53 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
55 //-----------------------------------------------------------------------------
56 // temporary implementation of the missing GDK function
57 //-----------------------------------------------------------------------------
59 #include "gdk/gdkprivate.h"
61 void gdk_draw_bitmap (GdkDrawable
*drawable
,
71 GdkWindowPrivate
*drawable_private
;
72 GdkWindowPrivate
*src_private
;
73 GdkGCPrivate
*gc_private
;
75 g_return_if_fail (drawable
!= NULL
);
76 g_return_if_fail (src
!= NULL
);
77 g_return_if_fail (gc
!= NULL
);
79 drawable_private
= (GdkWindowPrivate
*) drawable
;
80 src_private
= (GdkWindowPrivate
*) src
;
81 if (drawable_private
->destroyed
|| src_private
->destroyed
)
84 gc_private
= (GdkGCPrivate
*) gc
;
86 if (width
== -1) width
= src_private
->width
;
87 if (height
== -1) height
= src_private
->height
;
89 XCopyPlane( drawable_private
->xdisplay
,
91 drawable_private
->xwindow
,
99 //-----------------------------------------------------------------------------
100 // Implement Pool of Graphic contexts. Creating them takes too much time.
101 //-----------------------------------------------------------------------------
110 static wxGC wxGCPool
[200];
112 static void wxInitGCPool()
114 memset( wxGCPool
, 0, 200*sizeof(wxGC
) );
117 static void wxCleanUpGCPool()
119 for (int i
= 0; i
< 200; i
++)
121 if (wxGCPool
[i
].m_gc
)
122 gdk_gc_unref( wxGCPool
[i
].m_gc
);
126 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, bool mono
=FALSE
)
128 for (int i
= 0; i
< 200; i
++)
130 if (!wxGCPool
[i
].m_gc
)
132 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
133 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
134 wxGCPool
[i
].m_mono
= mono
;
135 wxGCPool
[i
].m_used
= FALSE
;
137 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_mono
== mono
))
139 wxGCPool
[i
].m_used
= TRUE
;
140 return wxGCPool
[i
].m_gc
;
144 wxFAIL_MSG( wxT("No GC available") );
146 return (GdkGC
*) NULL
;
149 static void wxFreePoolGC( GdkGC
*gc
)
151 for (int i
= 0; i
< 200; i
++)
153 if (wxGCPool
[i
].m_gc
== gc
)
155 wxGCPool
[i
].m_used
= FALSE
;
160 wxFAIL_MSG( wxT("Wrong GC") );
163 //-----------------------------------------------------------------------------
165 //-----------------------------------------------------------------------------
167 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
169 wxWindowDC
::wxWindowDC()
171 m_penGC
= (GdkGC
*) NULL
;
172 m_brushGC
= (GdkGC
*) NULL
;
173 m_textGC
= (GdkGC
*) NULL
;
174 m_bgGC
= (GdkGC
*) NULL
;
175 m_cmap
= (GdkColormap
*) NULL
;
177 m_owner
= (wxWindow
*)NULL
;
180 wxWindowDC
::wxWindowDC( wxWindow
*window
)
182 m_penGC
= (GdkGC
*) NULL
;
183 m_brushGC
= (GdkGC
*) NULL
;
184 m_textGC
= (GdkGC
*) NULL
;
185 m_bgGC
= (GdkGC
*) NULL
;
186 m_cmap
= (GdkColormap
*) NULL
;
187 m_owner
= (wxWindow
*)NULL
;
189 m_font
= window
->GetFont();
191 wxASSERT_MSG( window
, wxT("DC needs a window") );
193 GtkWidget
*widget
= window
->m_wxwindow
;
195 // some controls don't have m_wxwindow - like wxStaticBox, but the user
196 // code should still be able to create wxClientDCs for them, so we will
197 // use the parent window here then
200 window
= window
->GetParent();
201 widget
= window
->m_wxwindow
;
204 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
206 GtkPizza
*pizza
= GTK_PIZZA( widget
);
207 m_window
= pizza
->bin_window
;
212 /* don't report problems */
218 m_cmap
= gtk_widget_get_colormap( widget ? widget
: window
->m_widget
);
222 /* this must be done after SetUpDC, bacause SetUpDC calls the
223 repective SetBrush, SetPen, SetBackground etc functions
224 to set up the DC. SetBackground call m_owner->SetBackground
225 and this might not be desired as the standard dc background
226 is white whereas a window might assume gray to be the
227 standard (as e.g. wxStatusBar) */
232 wxWindowDC
::~wxWindowDC()
237 void wxWindowDC
::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
238 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
240 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
243 bool wxWindowDC
::DoGetPixel( wxCoord
WXUNUSED(x1
), wxCoord
WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
245 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
249 void wxWindowDC
::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
251 wxCHECK_RET( Ok(), wxT("invalid window dc") );
253 if (m_pen
.GetStyle() != wxTRANSPARENT
)
256 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
258 CalcBoundingBox(x1
, y1
);
259 CalcBoundingBox(x2
, y2
);
263 void wxWindowDC
::DoCrossHair( wxCoord x
, wxCoord y
)
265 wxCHECK_RET( Ok(), wxT("invalid window dc") );
267 if (m_pen
.GetStyle() != wxTRANSPARENT
)
272 wxCoord xx
= XLOG2DEV(x
);
273 wxCoord yy
= YLOG2DEV(y
);
276 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
277 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
282 void wxWindowDC
::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
283 wxCoord xc
, wxCoord yc
)
285 wxCHECK_RET( Ok(), wxT("invalid window dc") );
287 wxCoord xx1
= XLOG2DEV(x1
);
288 wxCoord yy1
= YLOG2DEV(y1
);
289 wxCoord xx2
= XLOG2DEV(x2
);
290 wxCoord yy2
= YLOG2DEV(y2
);
291 wxCoord xxc
= XLOG2DEV(xc
);
292 wxCoord yyc
= YLOG2DEV(yc
);
293 double dx
= xx1
- xxc
;
294 double dy
= yy1
- yyc
;
295 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
296 wxCoord r
= (wxCoord
)radius
;
297 double radius1
, radius2
;
299 if (xx1
== xx2
&& yy1
== yy2
)
307 radius1
= radius2
= 0.0;
311 radius1
= (xx1
- xxc
== 0) ?
312 (yy1
- yyc
< 0) ?
90.0 : -90.0 :
313 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
314 radius2
= (xx2
- xxc
== 0) ?
315 (yy2
- yyc
< 0) ?
90.0 : -90.0 :
316 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
318 wxCoord alpha1
= wxCoord(radius1
* 64.0);
319 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
320 while (alpha2
<= 0) alpha2
+= 360*64;
321 while (alpha1
> 360*64) alpha1
-= 360*64;
325 if (m_brush
.GetStyle() != wxTRANSPARENT
)
326 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
328 if (m_pen
.GetStyle() != wxTRANSPARENT
)
329 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
332 CalcBoundingBox (x1
, y1
);
333 CalcBoundingBox (x2
, y2
);
336 void wxWindowDC
::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
338 wxCHECK_RET( Ok(), wxT("invalid window dc") );
340 wxCoord xx
= XLOG2DEV(x
);
341 wxCoord yy
= YLOG2DEV(y
);
342 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
343 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
345 // CMB: handle -ve width and/or height
346 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
347 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
351 wxCoord start
= wxCoord(sa
* 64.0);
352 wxCoord end
= wxCoord(ea
* 64.0);
354 if (m_brush
.GetStyle() != wxTRANSPARENT
)
355 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
357 if (m_pen
.GetStyle() != wxTRANSPARENT
)
358 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
361 CalcBoundingBox (x
, y
);
362 CalcBoundingBox (x
+ width
, y
+ height
);
365 void wxWindowDC
::DoDrawPoint( wxCoord x
, wxCoord y
)
367 wxCHECK_RET( Ok(), wxT("invalid window dc") );
369 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
370 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
372 CalcBoundingBox (x
, y
);
375 void wxWindowDC
::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
377 wxCHECK_RET( Ok(), wxT("invalid window dc") );
379 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
382 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
384 for (int i
= 0; i
< n
-1; i
++)
386 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
387 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
388 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
389 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
392 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
394 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
398 void wxWindowDC
::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
400 wxCHECK_RET( Ok(), wxT("invalid window dc") );
404 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
406 for (i
= 0 ; i
< n
; i
++)
408 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
409 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
411 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
416 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
417 gdk_draw_polygon (m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
420 if ((m_brush
.GetStyle() != wxTRANSPARENT
))
421 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
427 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
429 for (i
= 0 ; i
< n
; i
++)
431 gdk_draw_line( m_window
, m_penGC
,
434 gdkpoints
[(i
+1)%n
].x
,
435 gdkpoints
[(i
+1)%n
].y
);
442 void wxWindowDC
::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
444 wxCHECK_RET( Ok(), wxT("invalid window dc") );
446 wxCoord xx
= XLOG2DEV(x
);
447 wxCoord yy
= YLOG2DEV(y
);
448 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
449 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
451 // CMB: draw nothing if transformed w or h is 0
452 if (ww
== 0 || hh
== 0) return;
454 // CMB: handle -ve width and/or height
455 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
456 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
460 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
462 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
463 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
467 if (m_brush
.GetStyle() != wxTRANSPARENT
)
468 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
470 if (m_pen
.GetStyle() != wxTRANSPARENT
)
471 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
475 CalcBoundingBox( x
, y
);
476 CalcBoundingBox( x
+ width
, y
+ height
);
479 void wxWindowDC
::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
481 wxCHECK_RET( Ok(), wxT("invalid window dc") );
483 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
485 wxCoord xx
= XLOG2DEV(x
);
486 wxCoord yy
= YLOG2DEV(y
);
487 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
488 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
489 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
491 // CMB: handle -ve width and/or height
492 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
493 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
495 // CMB: if radius is zero use DrawRectangle() instead to avoid
496 // X drawing errors with small radii
499 DrawRectangle( x
, y
, width
, height
);
503 // CMB: draw nothing if transformed w or h is 0
504 if (ww
== 0 || hh
== 0) return;
506 // CMB: adjust size if outline is drawn otherwise the result is
507 // 1 pixel too wide and high
508 if (m_pen
.GetStyle() != wxTRANSPARENT
)
516 // CMB: ensure dd is not larger than rectangle otherwise we
517 // get an hour glass shape
519 if (dd
> ww
) dd
= ww
;
520 if (dd
> hh
) dd
= hh
;
523 if (m_brush
.GetStyle() != wxTRANSPARENT
)
525 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
526 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
527 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
528 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
529 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
530 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
533 if (m_pen
.GetStyle() != wxTRANSPARENT
)
535 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
536 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
537 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
538 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
539 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
540 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
541 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
542 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
546 // this ignores the radius
547 CalcBoundingBox( x
, y
);
548 CalcBoundingBox( x
+ width
, y
+ height
);
551 void wxWindowDC
::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
553 wxCHECK_RET( Ok(), wxT("invalid window dc") );
555 wxCoord xx
= XLOG2DEV(x
);
556 wxCoord yy
= YLOG2DEV(y
);
557 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
558 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
560 // CMB: handle -ve width and/or height
561 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
562 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
566 if (m_brush
.GetStyle() != wxTRANSPARENT
)
567 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
569 if (m_pen
.GetStyle() != wxTRANSPARENT
)
570 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
573 CalcBoundingBox( x
- width
, y
- height
);
574 CalcBoundingBox( x
+ width
, y
+ height
);
577 void wxWindowDC
::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
579 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
580 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
583 void wxWindowDC
::DoDrawBitmap( const wxBitmap
&bitmap
,
584 wxCoord x
, wxCoord y
,
587 wxCHECK_RET( Ok(), wxT("invalid window dc") );
589 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
591 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
593 /* scale/translate size and position */
594 int xx
= XLOG2DEV(x
);
595 int yy
= YLOG2DEV(y
);
597 int w
= bitmap
.GetWidth();
598 int h
= bitmap
.GetHeight();
600 CalcBoundingBox( x
, y
);
601 CalcBoundingBox( x
+ w
, y
+ h
);
603 if (!m_window
) return;
605 int ww
= XLOG2DEVREL(w
);
606 int hh
= YLOG2DEVREL(h
);
608 /* compare to current clipping region */
609 if (!m_currentClippingRegion
.IsEmpty())
611 wxRegion
tmp( xx
,yy
,ww
,hh
);
612 tmp
.Intersect( m_currentClippingRegion
);
617 /* scale bitmap if required */
619 if ((w
!= ww
) || (h
!= hh
))
621 wxImage
image( bitmap
);
622 image
.Rescale( ww
, hh
);
624 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
626 use_bitmap
= image
.ConvertToBitmap();
633 /* apply mask if any */
634 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
635 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
639 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
640 if (!m_currentClippingRegion
.IsEmpty())
643 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
644 GdkGC
*gc
= gdk_gc_new( new_mask
);
646 gdk_gc_set_foreground( gc
, &col
);
647 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
649 gdk_gc_set_background( gc
, &col
);
651 gdk_gc_set_foreground( gc
, &col
);
652 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
653 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
654 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
655 gdk_gc_set_stipple( gc
, mask
);
656 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
663 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
665 gdk_gc_set_clip_mask( m_textGC
, mask
);
666 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
671 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
673 gdk_gc_set_clip_mask( m_penGC
, mask
);
674 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
677 gdk_bitmap_unref( new_mask
);
680 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
681 drawing a mono-bitmap (XBitmap) we use the current text GC */
683 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
685 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
687 /* remove mask again if any */
692 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
693 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
694 if (!m_currentClippingRegion
.IsEmpty())
695 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
699 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
700 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
701 if (!m_currentClippingRegion
.IsEmpty())
702 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
707 bool wxWindowDC
::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
708 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
709 int logical_func
, bool useMask
)
711 /* this is the nth try to get this utterly useless function to
712 work. it now completely ignores the scaling or translation
713 of the source dc, but scales correctly on the target dc and
714 knows about possible mask information in a memory dc. */
716 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
718 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
720 if (!m_window
) return FALSE
;
722 wxClientDC
*srcDC
= (wxClientDC
*)source
;
723 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
725 bool use_bitmap_method
= FALSE
;
726 bool is_mono
= FALSE
;
728 if (srcDC
->m_isMemDC
)
730 if (!memDC
->m_selected
.Ok()) return FALSE
;
732 /* we use the "XCopyArea" way to copy a memory dc into
733 y different window if the memory dc BOTH
734 a) doesn't have any mask or its mask isn't used
738 if (useMask
&& (memDC
->m_selected
.GetMask()))
740 /* we HAVE TO use the direct way for memory dcs
741 that have mask since the XCopyArea doesn't know
743 use_bitmap_method
= TRUE
;
745 else if (memDC
->m_selected
.GetDepth() == 1)
747 /* we HAVE TO use the direct way for memory dcs
748 that are bitmaps because XCopyArea doesn't cope
749 with different bit depths */
751 use_bitmap_method
= TRUE
;
753 else if ((xsrc
== 0) && (ysrc
== 0) &&
754 (width
== memDC
->m_selected
.GetWidth()) &&
755 (height
== memDC
->m_selected
.GetHeight()))
757 /* we SHOULD use the direct way if all of the bitmap
758 in the memory dc is copied in which case XCopyArea
759 wouldn't be able able to boost performace by reducing
760 the area to be scaled */
761 use_bitmap_method
= TRUE
;
765 use_bitmap_method
= FALSE
;
769 CalcBoundingBox( xdest
, ydest
);
770 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
772 /* scale/translate size and position */
773 wxCoord xx
= XLOG2DEV(xdest
);
774 wxCoord yy
= YLOG2DEV(ydest
);
776 wxCoord ww
= XLOG2DEVREL(width
);
777 wxCoord hh
= YLOG2DEVREL(height
);
779 /* compare to current clipping region */
780 if (!m_currentClippingRegion
.IsEmpty())
782 wxRegion
tmp( xx
,yy
,ww
,hh
);
783 tmp
.Intersect( m_currentClippingRegion
);
788 int old_logical_func
= m_logicalFunction
;
789 SetLogicalFunction( logical_func
);
791 if (use_bitmap_method
)
793 /* scale/translate bitmap size */
794 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
795 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
797 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
798 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
800 /* scale bitmap if required */
803 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
805 wxImage
image( memDC
->m_selected
);
806 image
= image
.Scale( bm_ww
, bm_hh
);
809 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
811 use_bitmap
= image
.ConvertToBitmap();
815 use_bitmap
= memDC
->m_selected
;
818 /* apply mask if any */
819 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
820 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
824 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
825 if (!m_currentClippingRegion
.IsEmpty())
828 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
829 GdkGC
*gc
= gdk_gc_new( new_mask
);
831 gdk_gc_set_foreground( gc
, &col
);
832 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
834 gdk_gc_set_background( gc
, &col
);
836 gdk_gc_set_foreground( gc
, &col
);
837 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
838 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
839 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
840 gdk_gc_set_stipple( gc
, mask
);
841 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
848 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
850 gdk_gc_set_clip_mask( m_textGC
, mask
);
851 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
856 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
858 gdk_gc_set_clip_mask( m_penGC
, mask
);
859 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
862 gdk_bitmap_unref( new_mask
);
865 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
866 drawing a mono-bitmap (XBitmap) we use the current text GC */
868 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
870 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
872 /* remove mask again if any */
877 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
878 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
879 if (!m_currentClippingRegion
.IsEmpty())
880 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
884 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
885 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
886 if (!m_currentClippingRegion
.IsEmpty())
887 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
891 else /* use_bitmap_method */
893 if ((width
!= ww
) || (height
!= hh
))
895 /* draw source window into a bitmap as we cannot scale
896 a window in contrast to a bitmap. this would actually
897 work with memory dcs as well, but we'd lose the mask
898 information and waste one step in this process since
899 a memory already has a bitmap. all this is slightly
900 inefficient as we could take an XImage directly from
901 an X window, but we'd then also have to care that
902 the window is not outside the screen (in which case
903 we'd get a BadMatch or what not).
904 Is a double XGetImage and combined XGetPixel and
905 XPutPixel really faster? I'm not sure. look at wxXt
906 for a different implementation of the same problem. */
908 wxBitmap
bitmap( width
, height
);
909 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
911 xsrc
, ysrc
, width
, height
);
915 wxImage
image( bitmap
);
916 image
= image
.Scale( ww
, hh
);
918 /* convert to bitmap */
920 bitmap
= image
.ConvertToBitmap();
922 /* draw scaled bitmap */
924 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
929 /* no scaling and not a memory dc with a mask either */
931 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
933 xsrc
, ysrc
, width
, height
);
937 SetLogicalFunction( old_logical_func
);
941 void wxWindowDC
::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
943 wxCHECK_RET( Ok(), wxT("invalid window dc") );
945 if (!m_window
) return;
947 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
949 wxCHECK_RET( font
, wxT("invalid font") );
954 /* CMB 21/5/98: draw text background if mode is wxSOLID */
955 if (m_backgroundMode
== wxSOLID
)
957 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
958 wxCoord height
= font
->ascent
+ font
->descent
;
959 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
960 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
961 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
963 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
965 /* CMB 17/7/98: simple underline: ignores scaling and underlying
966 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
967 properties (see wxXt implementation) */
968 if (m_font
.GetUnderlined())
970 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
971 wxCoord ul_y
= y
+ font
->ascent
;
972 if (font
->descent
> 0) ul_y
++;
973 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
977 GetTextExtent (text
, &w
, &h
);
978 CalcBoundingBox (x
+ w
, y
+ h
);
979 CalcBoundingBox (x
, y
);
982 void wxWindowDC
::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
986 DrawText(text
, x
, y
);
990 wxCHECK_RET( Ok(), wxT("invalid window dc") );
992 if (!m_window
) return;
994 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
996 wxCHECK_RET( font
, wxT("invalid font") );
998 // the size of the text
999 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1000 wxCoord h
= font
->ascent
+ font
->descent
;
1002 // draw the string normally
1005 dc
.SelectObject(src
);
1006 dc
.SetFont(GetFont());
1007 dc
.SetBackground(*wxWHITE_BRUSH
);
1008 dc
.SetBrush(*wxBLACK_BRUSH
);
1010 dc
.DrawText(text
, 0, 0);
1011 dc
.SetFont(wxNullFont
);
1012 dc
.SelectObject(wxNullBitmap
);
1014 // Calculate the size of the rotated bounding box.
1015 double rad
= DegToRad(angle
);
1016 double dx
= cos(rad
),
1019 // the rectngle vertices are counted clockwise with the first one being at
1020 // (0, 0) (or, rather, at (x, y))
1022 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1025 double x3
= x4
+ x2
,
1029 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1030 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1031 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1032 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1034 // prepare to blit-with-rotate the bitmap to the DC
1037 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1038 *colBack
= m_textBackgroundColour
.GetColor();
1040 bool textColSet
= TRUE
;
1042 unsigned char *data
= image
.GetData();
1044 // paint pixel by pixel
1045 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1047 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1049 // transform source coords to dest coords
1050 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1051 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1052 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1053 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1056 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1057 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1059 // change colour if needed
1060 if ( textPixel
!= textColSet
)
1062 gdk_gc_set_foreground( m_textGC
, textPixel ? colText
1065 textColSet
= textPixel
;
1068 // don't use DrawPoint() because it uses the current pen
1069 // colour, and we don't need it here
1070 gdk_draw_point( m_window
, m_textGC
,
1071 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1076 // it would be better to draw with non underlined font and draw the line
1077 // manually here (it would be more straight...)
1079 if ( m_font
.GetUnderlined() )
1081 gdk_draw_line( m_window
, m_textGC
,
1082 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1083 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1087 // restore the font colour
1088 gdk_gc_set_foreground( m_textGC
, colText
);
1090 // update the bounding box
1091 CalcBoundingBox(x
+ minX
, y
+ minY
);
1092 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1095 void wxWindowDC
::DoGetTextExtent(const wxString
&string
,
1096 wxCoord
*width
, wxCoord
*height
,
1097 wxCoord
*descent
, wxCoord
*externalLeading
,
1098 wxFont
*theFont
) const
1100 wxFont fontToUse
= m_font
;
1101 if (theFont
) fontToUse
= *theFont
;
1103 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1104 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1105 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1106 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1107 if (externalLeading
) (*externalLeading
) = 0; // ??
1110 wxCoord wxWindowDC
::GetCharWidth() const
1112 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1113 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1115 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1118 wxCoord wxWindowDC
::GetCharHeight() const
1120 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1121 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1123 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1126 void wxWindowDC
::Clear()
1128 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1130 if (!m_window
) return;
1132 /* - we either are a memory dc or have a window as the
1133 owner. anything else shouldn't happen.
1134 - we don't use gdk_window_clear() as we don't set
1135 the window's background colour anymore. it is too
1136 much pain to keep the DC's and the window's back-
1137 ground colour in synch. */
1142 m_owner
->GetSize( &width
, &height
);
1143 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1150 GetSize( &width
, &height
);
1151 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1156 void wxWindowDC
::SetFont( const wxFont
&font
)
1161 void wxWindowDC
::SetPen( const wxPen
&pen
)
1163 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1165 if (m_pen
== pen
) return;
1169 if (!m_pen
.Ok()) return;
1171 if (!m_window
) return;
1173 gint width
= m_pen
.GetWidth();
1176 // CMB: if width is non-zero scale it with the dc
1181 // X doesn't allow different width in x and y and so we take
1184 ( fabs((double) XLOG2DEVREL(width
)) +
1185 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1189 static const char dotted
[] = {1, 1};
1190 static const char short_dashed
[] = {2, 2};
1191 static const char wxCoord_dashed
[] = {2, 4};
1192 static const char dotted_dashed
[] = {3, 3, 1, 3};
1194 // We express dash pattern in pen width unit, so we are
1195 // independent of zoom factor and so on...
1197 const char *req_dash
;
1199 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1200 switch (m_pen
.GetStyle())
1204 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1205 req_nb_dash
= m_pen
.GetDashCount();
1206 req_dash
= m_pen
.GetDash();
1211 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1218 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1220 req_dash
= wxCoord_dashed
;
1225 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1227 req_dash
= short_dashed
;
1232 // lineStyle = GDK_LINE_DOUBLE_DASH;
1233 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1235 req_dash
= dotted_dashed
;
1240 case wxSTIPPLE_MASK_OPAQUE
:
1245 lineStyle
= GDK_LINE_SOLID
;
1246 req_dash
= (wxDash
*)NULL
;
1252 #if (GTK_MINOR_VERSION > 0)
1253 if (req_dash
&& req_nb_dash
)
1255 char *real_req_dash
= new char[req_nb_dash
];
1258 for (int i
= 0; i
< req_nb_dash
; i
++)
1259 real_req_dash
[i
] = req_dash
[i
] * width
;
1260 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1261 delete[] real_req_dash
;
1265 // No Memory. We use non-scaled dash pattern...
1266 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1271 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1272 switch (m_pen
.GetCap())
1274 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1275 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1282 capStyle
= GDK_CAP_NOT_LAST
;
1286 capStyle
= GDK_CAP_ROUND
;
1292 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1293 switch (m_pen
.GetJoin())
1295 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1296 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1298 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1301 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1303 m_pen
.GetColour().CalcPixel( m_cmap
);
1304 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1307 void wxWindowDC
::SetBrush( const wxBrush
&brush
)
1309 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1311 if (m_brush
== brush
) return;
1315 if (!m_brush
.Ok()) return;
1317 if (!m_window
) return;
1319 m_brush
.GetColour().CalcPixel( m_cmap
);
1320 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1322 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1324 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1326 if (m_brush
.GetStipple()->GetPixmap())
1328 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1329 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1333 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1334 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1338 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1340 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1341 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1344 if (IS_HATCH(m_brush
.GetStyle()))
1346 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1347 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1348 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1352 void wxWindowDC
::SetBackground( const wxBrush
&brush
)
1354 /* CMB 21/7/98: Added SetBackground. Sets background brush
1355 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1357 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1359 if (m_backgroundBrush
== brush
) return;
1361 m_backgroundBrush
= brush
;
1363 if (!m_backgroundBrush
.Ok()) return;
1365 if (!m_window
) return;
1367 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1368 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1369 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1370 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1371 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1373 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1375 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1377 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1379 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1380 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1384 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1385 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1389 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1391 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1392 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1393 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1397 void wxWindowDC
::SetLogicalFunction( int function
)
1399 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1401 if (m_logicalFunction
== function
)
1404 // VZ: shouldn't this be a CHECK?
1408 GdkFunction mode
= GDK_COPY
;
1411 case wxXOR
: mode
= GDK_XOR
; break;
1412 case wxINVERT
: mode
= GDK_INVERT
; break;
1413 #if (GTK_MINOR_VERSION > 0)
1414 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1415 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1416 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1417 case wxSET
: mode
= GDK_SET
; break;
1418 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1419 case wxAND
: mode
= GDK_AND
; break;
1420 case wxOR
: mode
= GDK_OR
; break;
1421 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1422 case wxNAND
: mode
= GDK_NAND
; break;
1423 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1424 case wxCOPY
: mode
= GDK_COPY
; break;
1425 case wxNO_OP
: mode
= GDK_NOOP
; break;
1426 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1428 // unsupported by GTK
1429 case wxNOR
: mode
= GDK_COPY
; break;
1433 wxFAIL_MSG( wxT("unsupported logical function") );
1438 m_logicalFunction
= function
;
1440 gdk_gc_set_function( m_penGC
, mode
);
1441 gdk_gc_set_function( m_brushGC
, mode
);
1443 // to stay compatible with wxMSW, we don't apply ROPs to the text
1444 // operations (i.e. DrawText/DrawRotatedText).
1445 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1446 gdk_gc_set_function( m_textGC
, mode
);
1449 void wxWindowDC
::SetTextForeground( const wxColour
&col
)
1451 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1453 if (m_textForegroundColour
== col
) return;
1455 m_textForegroundColour
= col
;
1456 if (!m_textForegroundColour
.Ok()) return;
1458 if (!m_window
) return;
1460 m_textForegroundColour
.CalcPixel( m_cmap
);
1461 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1464 void wxWindowDC
::SetTextBackground( const wxColour
&col
)
1466 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1468 if (m_textBackgroundColour
== col
) return;
1470 m_textBackgroundColour
= col
;
1471 if (!m_textBackgroundColour
.Ok()) return;
1473 if (!m_window
) return;
1475 m_textBackgroundColour
.CalcPixel( m_cmap
);
1476 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1479 void wxWindowDC
::SetBackgroundMode( int mode
)
1481 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1483 m_backgroundMode
= mode
;
1485 if (!m_window
) return;
1487 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1488 // transparent/solid background mode
1490 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1492 gdk_gc_set_fill( m_brushGC
,
1493 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1497 void wxWindowDC
::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1499 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1502 void wxWindowDC
::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1504 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1506 wxDC
::DoSetClippingRegion( x
, y
, width
, height
);
1508 if (!m_window
) return;
1511 rect
.x
= XLOG2DEV(x
);
1512 rect
.y
= YLOG2DEV(y
);
1513 rect
.width
= XLOG2DEVREL(width
);
1514 rect
.height
= YLOG2DEVREL(height
);
1516 m_currentClippingRegion
.Clear();
1517 m_currentClippingRegion
.Union( rect
);
1518 if (!m_paintClippingRegion
.IsEmpty())
1519 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1521 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1522 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1523 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1524 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1527 void wxWindowDC
::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1529 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1533 DestroyClippingRegion();
1538 region
.GetBox( x
, y
, w
, h
);
1540 wxDC
::DoSetClippingRegion( x
, y
, w
, h
);
1542 if (!m_window
) return;
1544 m_currentClippingRegion
.Clear();
1545 m_currentClippingRegion
.Union( region
);
1546 if (!m_paintClippingRegion
.IsEmpty())
1547 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1549 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1550 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1551 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1552 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1555 void wxWindowDC
::DestroyClippingRegion()
1557 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1559 wxDC
::DestroyClippingRegion();
1561 m_currentClippingRegion
.Clear();
1563 if (!m_paintClippingRegion
.IsEmpty())
1564 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1566 if (!m_window
) return;
1568 if (m_currentClippingRegion
.IsEmpty())
1570 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1571 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1572 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1573 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1577 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1578 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1579 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1580 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1584 void wxWindowDC
::SetUpDC()
1590 m_penGC
= wxGetPoolGC( m_window
);
1591 m_brushGC
= wxGetPoolGC( m_window
);
1592 m_textGC
= wxGetPoolGC( m_window
);
1593 m_bgGC
= wxGetPoolGC( m_window
);
1596 /* background colour */
1597 m_backgroundBrush
= *wxWHITE_BRUSH
;
1598 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1599 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
1602 m_textForegroundColour
.CalcPixel( m_cmap
);
1603 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1605 m_textBackgroundColour
.CalcPixel( m_cmap
);
1606 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1608 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
1609 gdk_gc_set_line_attributes( m_textGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
1612 m_pen
.GetColour().CalcPixel( m_cmap
);
1613 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1614 gdk_gc_set_background( m_penGC
, bg_col
);
1616 gdk_gc_set_fill( m_penGC
, GDK_SOLID
);
1617 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
1621 m_brush
.GetColour().CalcPixel( m_cmap
);
1622 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1623 gdk_gc_set_background( m_brushGC
, bg_col
);
1625 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1626 gdk_gc_set_line_attributes( m_brushGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
1630 gdk_gc_set_background( m_bgGC
, bg_col
);
1631 gdk_gc_set_foreground( m_bgGC
, bg_col
);
1633 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1634 gdk_gc_set_line_attributes( m_bgGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
1637 gdk_gc_set_function( m_textGC
, GDK_COPY
);
1638 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
1639 gdk_gc_set_function( m_penGC
, GDK_COPY
);
1640 gdk_gc_set_function( m_bgGC
, GDK_COPY
);
1643 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1644 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1645 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1646 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1650 hatch_bitmap
= hatches
;
1651 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1652 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1653 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1654 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1655 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1656 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1660 void wxWindowDC
::Destroy()
1662 if (m_penGC
) wxFreePoolGC( m_penGC
);
1663 m_penGC
= (GdkGC
*) NULL
;
1664 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1665 m_brushGC
= (GdkGC
*) NULL
;
1666 if (m_textGC
) wxFreePoolGC( m_textGC
);
1667 m_textGC
= (GdkGC
*) NULL
;
1668 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1669 m_bgGC
= (GdkGC
*) NULL
;
1672 void wxWindowDC
::ComputeScaleAndOrigin()
1674 /* CMB: copy scale to see if it changes */
1675 double origScaleX
= m_scaleX
;
1676 double origScaleY
= m_scaleY
;
1678 wxDC
::ComputeScaleAndOrigin();
1680 /* CMB: if scale has changed call SetPen to recalulate the line width */
1681 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1684 /* this is a bit artificial, but we need to force wxDC to think
1685 the pen has changed */
1692 // Resolution in pixels per logical inch
1693 wxSize wxWindowDC
::GetPPI() const
1695 return wxSize(100, 100);
1698 int wxWindowDC
::GetDepth() const
1700 wxFAIL_MSG(wxT("not implemented"));
1706 // ----------------------------------- spline code ----------------------------------------
1708 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1709 double a3
, double b3
, double a4
, double b4
);
1710 void wx_clear_stack();
1711 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1712 double *y3
, double *x4
, double *y4
);
1713 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1714 double x4
, double y4
);
1715 static bool wx_spline_add_point(double x
, double y
);
1716 static void wx_spline_draw_point_array(wxDC
*dc
);
1718 wxList wx_spline_point_list
;
1720 #define half(z1, z2) ((z1+z2)/2.0)
1723 /* iterative version */
1725 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1728 register double xmid
, ymid
;
1729 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1732 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1734 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1735 xmid
= (double)half(x2
, x3
);
1736 ymid
= (double)half(y2
, y3
);
1737 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1738 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1739 wx_spline_add_point( x1
, y1
);
1740 wx_spline_add_point( xmid
, ymid
);
1742 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1743 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1744 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1745 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1750 /* utilities used by spline drawing routines */
1752 typedef struct wx_spline_stack_struct
{
1753 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1756 #define SPLINE_STACK_DEPTH 20
1757 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1758 static Stack
*wx_stack_top
;
1759 static int wx_stack_count
;
1761 void wx_clear_stack()
1763 wx_stack_top
= wx_spline_stack
;
1767 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1769 wx_stack_top
->x1
= x1
;
1770 wx_stack_top
->y1
= y1
;
1771 wx_stack_top
->x2
= x2
;
1772 wx_stack_top
->y2
= y2
;
1773 wx_stack_top
->x3
= x3
;
1774 wx_stack_top
->y3
= y3
;
1775 wx_stack_top
->x4
= x4
;
1776 wx_stack_top
->y4
= y4
;
1781 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1782 double *x3
, double *y3
, double *x4
, double *y4
)
1784 if (wx_stack_count
== 0)
1788 *x1
= wx_stack_top
->x1
;
1789 *y1
= wx_stack_top
->y1
;
1790 *x2
= wx_stack_top
->x2
;
1791 *y2
= wx_stack_top
->y2
;
1792 *x3
= wx_stack_top
->x3
;
1793 *y3
= wx_stack_top
->y3
;
1794 *x4
= wx_stack_top
->x4
;
1795 *y4
= wx_stack_top
->y4
;
1799 static bool wx_spline_add_point(double x
, double y
)
1801 wxPoint
*point
= new wxPoint
;
1804 wx_spline_point_list
.Append((wxObject
*)point
);
1808 static void wx_spline_draw_point_array(wxDC
*dc
)
1810 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1811 wxNode
*node
= wx_spline_point_list
.First();
1814 wxPoint
*point
= (wxPoint
*)node
->Data();
1817 node
= wx_spline_point_list
.First();
1821 void wxWindowDC
::DoDrawSpline( wxList
*points
)
1823 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1826 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1827 double x1
, y1
, x2
, y2
;
1829 wxNode
*node
= points
->First();
1830 p
= (wxPoint
*)node
->Data();
1835 node
= node
->Next();
1836 p
= (wxPoint
*)node
->Data();
1840 cx1
= (double)((x1
+ x2
) / 2);
1841 cy1
= (double)((y1
+ y2
) / 2);
1842 cx2
= (double)((cx1
+ x2
) / 2);
1843 cy2
= (double)((cy1
+ y2
) / 2);
1845 wx_spline_add_point(x1
, y1
);
1847 while ((node
= node
->Next()) != NULL
)
1849 p
= (wxPoint
*)node
->Data();
1854 cx4
= (double)(x1
+ x2
) / 2;
1855 cy4
= (double)(y1
+ y2
) / 2;
1856 cx3
= (double)(x1
+ cx4
) / 2;
1857 cy3
= (double)(y1
+ cy4
) / 2;
1859 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1863 cx2
= (double)(cx1
+ x2
) / 2;
1864 cy2
= (double)(cy1
+ y2
) / 2;
1867 wx_spline_add_point( cx1
, cy1
);
1868 wx_spline_add_point( x2
, y2
);
1870 wx_spline_draw_point_array( this );
1873 #endif // wxUSE_SPLINE
1875 //-----------------------------------------------------------------------------
1877 //-----------------------------------------------------------------------------
1879 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1881 wxPaintDC
::wxPaintDC()
1886 wxPaintDC
::wxPaintDC( wxWindow
*win
)
1890 if (!win->GetUpdateRegion().IsEmpty())
1892 m_paintClippingRegion = win->GetUpdateRegion();
1893 m_currentClippingRegion.Union( m_paintClippingRegion );
1895 gdk_gc_set_clip_region( m_penGC, m_paintClippingRegion.GetRegion() );
1896 gdk_gc_set_clip_region( m_brushGC, m_paintClippingRegion.GetRegion() );
1897 gdk_gc_set_clip_region( m_textGC, m_paintClippingRegion.GetRegion() );
1898 gdk_gc_set_clip_region( m_bgGC, m_paintClippingRegion.GetRegion() );
1903 //-----------------------------------------------------------------------------
1905 //-----------------------------------------------------------------------------
1907 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1909 wxClientDC
::wxClientDC()
1914 wxClientDC
::wxClientDC( wxWindow
*win
)
1919 // ----------------------------------------------------------------------------
1921 // ----------------------------------------------------------------------------
1923 class wxDCModule
: public wxModule
1930 DECLARE_DYNAMIC_CLASS(wxDCModule
)
1933 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
1935 bool wxDCModule
::OnInit()
1941 void wxDCModule
::OnExit()