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 //-----------------------------------------------------------------------------
123 static wxGC wxGCPool
[200];
125 static void wxInitGCPool()
127 memset( wxGCPool
, 0, 200*sizeof(wxGC
) );
130 static void wxCleanUpGCPool()
132 for (int i
= 0; i
< 200; i
++)
134 if (wxGCPool
[i
].m_gc
)
135 gdk_gc_unref( wxGCPool
[i
].m_gc
);
139 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
141 for (int i
= 0; i
< 200; i
++)
143 if (!wxGCPool
[i
].m_gc
)
145 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
146 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
147 wxGCPool
[i
].m_type
= type
;
148 wxGCPool
[i
].m_used
= FALSE
;
150 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
152 wxGCPool
[i
].m_used
= TRUE
;
153 return wxGCPool
[i
].m_gc
;
157 wxFAIL_MSG( wxT("No GC available") );
159 return (GdkGC
*) NULL
;
162 static void wxFreePoolGC( GdkGC
*gc
)
164 for (int i
= 0; i
< 200; i
++)
166 if (wxGCPool
[i
].m_gc
== gc
)
168 wxGCPool
[i
].m_used
= FALSE
;
173 wxFAIL_MSG( wxT("Wrong GC") );
176 //-----------------------------------------------------------------------------
178 //-----------------------------------------------------------------------------
180 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
182 wxWindowDC::wxWindowDC()
184 m_penGC
= (GdkGC
*) NULL
;
185 m_brushGC
= (GdkGC
*) NULL
;
186 m_textGC
= (GdkGC
*) NULL
;
187 m_bgGC
= (GdkGC
*) NULL
;
188 m_cmap
= (GdkColormap
*) NULL
;
190 m_owner
= (wxWindow
*)NULL
;
193 wxWindowDC::wxWindowDC( wxWindow
*window
)
195 m_penGC
= (GdkGC
*) NULL
;
196 m_brushGC
= (GdkGC
*) NULL
;
197 m_textGC
= (GdkGC
*) NULL
;
198 m_bgGC
= (GdkGC
*) NULL
;
199 m_cmap
= (GdkColormap
*) NULL
;
200 m_owner
= (wxWindow
*)NULL
;
202 m_font
= window
->GetFont();
204 wxASSERT_MSG( window
, wxT("DC needs a window") );
206 GtkWidget
*widget
= window
->m_wxwindow
;
208 // some controls don't have m_wxwindow - like wxStaticBox, but the user
209 // code should still be able to create wxClientDCs for them, so we will
210 // use the parent window here then
213 window
= window
->GetParent();
214 widget
= window
->m_wxwindow
;
217 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
219 GtkPizza
*pizza
= GTK_PIZZA( widget
);
220 m_window
= pizza
->bin_window
;
225 /* don't report problems */
231 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
235 /* this must be done after SetUpDC, bacause SetUpDC calls the
236 repective SetBrush, SetPen, SetBackground etc functions
237 to set up the DC. SetBackground call m_owner->SetBackground
238 and this might not be desired as the standard dc background
239 is white whereas a window might assume gray to be the
240 standard (as e.g. wxStatusBar) */
245 wxWindowDC::~wxWindowDC()
250 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
251 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
253 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
256 bool wxWindowDC::DoGetPixel( wxCoord
WXUNUSED(x1
), wxCoord
WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
258 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
262 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
264 wxCHECK_RET( Ok(), wxT("invalid window dc") );
266 if (m_pen
.GetStyle() != wxTRANSPARENT
)
269 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
271 CalcBoundingBox(x1
, y1
);
272 CalcBoundingBox(x2
, y2
);
276 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
278 wxCHECK_RET( Ok(), wxT("invalid window dc") );
280 if (m_pen
.GetStyle() != wxTRANSPARENT
)
285 wxCoord xx
= XLOG2DEV(x
);
286 wxCoord yy
= YLOG2DEV(y
);
289 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
290 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
295 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
296 wxCoord xc
, wxCoord yc
)
298 wxCHECK_RET( Ok(), wxT("invalid window dc") );
300 wxCoord xx1
= XLOG2DEV(x1
);
301 wxCoord yy1
= YLOG2DEV(y1
);
302 wxCoord xx2
= XLOG2DEV(x2
);
303 wxCoord yy2
= YLOG2DEV(y2
);
304 wxCoord xxc
= XLOG2DEV(xc
);
305 wxCoord yyc
= YLOG2DEV(yc
);
306 double dx
= xx1
- xxc
;
307 double dy
= yy1
- yyc
;
308 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
309 wxCoord r
= (wxCoord
)radius
;
310 double radius1
, radius2
;
312 if (xx1
== xx2
&& yy1
== yy2
)
320 radius1
= radius2
= 0.0;
324 radius1
= (xx1
- xxc
== 0) ?
325 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
326 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
327 radius2
= (xx2
- xxc
== 0) ?
328 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
329 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
331 wxCoord alpha1
= wxCoord(radius1
* 64.0);
332 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
333 while (alpha2
<= 0) alpha2
+= 360*64;
334 while (alpha1
> 360*64) alpha1
-= 360*64;
338 if (m_brush
.GetStyle() != wxTRANSPARENT
)
339 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
341 if (m_pen
.GetStyle() != wxTRANSPARENT
)
342 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
345 CalcBoundingBox (x1
, y1
);
346 CalcBoundingBox (x2
, y2
);
349 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
351 wxCHECK_RET( Ok(), wxT("invalid window dc") );
353 wxCoord xx
= XLOG2DEV(x
);
354 wxCoord yy
= YLOG2DEV(y
);
355 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
356 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
358 // CMB: handle -ve width and/or height
359 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
360 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
364 wxCoord start
= wxCoord(sa
* 64.0);
365 wxCoord end
= wxCoord(ea
* 64.0);
367 if (m_brush
.GetStyle() != wxTRANSPARENT
)
368 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
370 if (m_pen
.GetStyle() != wxTRANSPARENT
)
371 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
374 CalcBoundingBox (x
, y
);
375 CalcBoundingBox (x
+ width
, y
+ height
);
378 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
380 wxCHECK_RET( Ok(), wxT("invalid window dc") );
382 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
383 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
385 CalcBoundingBox (x
, y
);
388 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
390 wxCHECK_RET( Ok(), wxT("invalid window dc") );
392 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
395 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
397 for (int i
= 0; i
< n
-1; i
++)
399 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
400 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
401 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
402 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
405 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
407 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
411 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
413 wxCHECK_RET( Ok(), wxT("invalid window dc") );
417 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
419 for (i
= 0 ; i
< n
; i
++)
421 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
422 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
424 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
429 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
430 gdk_draw_polygon (m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
433 if ((m_brush
.GetStyle() != wxTRANSPARENT
))
434 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
440 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
442 for (i
= 0 ; i
< n
; i
++)
444 gdk_draw_line( m_window
, m_penGC
,
447 gdkpoints
[(i
+1)%n
].x
,
448 gdkpoints
[(i
+1)%n
].y
);
455 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
457 wxCHECK_RET( Ok(), wxT("invalid window dc") );
459 wxCoord xx
= XLOG2DEV(x
);
460 wxCoord yy
= YLOG2DEV(y
);
461 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
462 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
464 // CMB: draw nothing if transformed w or h is 0
465 if (ww
== 0 || hh
== 0) return;
467 // CMB: handle -ve width and/or height
468 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
469 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
473 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
475 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
476 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
480 if (m_brush
.GetStyle() != wxTRANSPARENT
)
481 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
483 if (m_pen
.GetStyle() != wxTRANSPARENT
)
484 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
488 CalcBoundingBox( x
, y
);
489 CalcBoundingBox( x
+ width
, y
+ height
);
492 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
494 wxCHECK_RET( Ok(), wxT("invalid window dc") );
496 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
498 wxCoord xx
= XLOG2DEV(x
);
499 wxCoord yy
= YLOG2DEV(y
);
500 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
501 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
502 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
504 // CMB: handle -ve width and/or height
505 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
506 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
508 // CMB: if radius is zero use DrawRectangle() instead to avoid
509 // X drawing errors with small radii
512 DrawRectangle( x
, y
, width
, height
);
516 // CMB: draw nothing if transformed w or h is 0
517 if (ww
== 0 || hh
== 0) return;
519 // CMB: adjust size if outline is drawn otherwise the result is
520 // 1 pixel too wide and high
521 if (m_pen
.GetStyle() != wxTRANSPARENT
)
529 // CMB: ensure dd is not larger than rectangle otherwise we
530 // get an hour glass shape
532 if (dd
> ww
) dd
= ww
;
533 if (dd
> hh
) dd
= hh
;
536 if (m_brush
.GetStyle() != wxTRANSPARENT
)
538 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
539 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
540 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
541 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
542 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
543 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
546 if (m_pen
.GetStyle() != wxTRANSPARENT
)
548 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
549 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
550 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
551 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
552 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
553 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
554 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
555 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
559 // this ignores the radius
560 CalcBoundingBox( x
, y
);
561 CalcBoundingBox( x
+ width
, y
+ height
);
564 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
566 wxCHECK_RET( Ok(), wxT("invalid window dc") );
568 wxCoord xx
= XLOG2DEV(x
);
569 wxCoord yy
= YLOG2DEV(y
);
570 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
571 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
573 // CMB: handle -ve width and/or height
574 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
575 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
579 if (m_brush
.GetStyle() != wxTRANSPARENT
)
580 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
582 if (m_pen
.GetStyle() != wxTRANSPARENT
)
583 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
586 CalcBoundingBox( x
- width
, y
- height
);
587 CalcBoundingBox( x
+ width
, y
+ height
);
590 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
592 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
593 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
596 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
597 wxCoord x
, wxCoord y
,
600 wxCHECK_RET( Ok(), wxT("invalid window dc") );
602 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
604 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
606 /* scale/translate size and position */
607 int xx
= XLOG2DEV(x
);
608 int yy
= YLOG2DEV(y
);
610 int w
= bitmap
.GetWidth();
611 int h
= bitmap
.GetHeight();
613 CalcBoundingBox( x
, y
);
614 CalcBoundingBox( x
+ w
, y
+ h
);
616 if (!m_window
) return;
618 int ww
= XLOG2DEVREL(w
);
619 int hh
= YLOG2DEVREL(h
);
621 /* compare to current clipping region */
622 if (!m_currentClippingRegion
.IsEmpty())
624 wxRegion
tmp( xx
,yy
,ww
,hh
);
625 tmp
.Intersect( m_currentClippingRegion
);
630 /* scale bitmap if required */
632 if ((w
!= ww
) || (h
!= hh
))
634 wxImage
image( bitmap
);
635 image
.Rescale( ww
, hh
);
637 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
639 use_bitmap
= image
.ConvertToBitmap();
646 /* apply mask if any */
647 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
648 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
652 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
653 if (!m_currentClippingRegion
.IsEmpty())
656 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
657 GdkGC
*gc
= gdk_gc_new( new_mask
);
659 gdk_gc_set_foreground( gc
, &col
);
660 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
662 gdk_gc_set_background( gc
, &col
);
664 gdk_gc_set_foreground( gc
, &col
);
665 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
666 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
667 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
668 gdk_gc_set_stipple( gc
, mask
);
669 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
676 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
678 gdk_gc_set_clip_mask( m_textGC
, mask
);
679 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
684 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
686 gdk_gc_set_clip_mask( m_penGC
, mask
);
687 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
690 gdk_bitmap_unref( new_mask
);
693 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
694 drawing a mono-bitmap (XBitmap) we use the current text GC */
696 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
698 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
700 /* remove mask again if any */
705 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
706 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
707 if (!m_currentClippingRegion
.IsEmpty())
708 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
712 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
713 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
714 if (!m_currentClippingRegion
.IsEmpty())
715 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
720 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
721 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
722 int logical_func
, bool useMask
)
724 /* this is the nth try to get this utterly useless function to
725 work. it now completely ignores the scaling or translation
726 of the source dc, but scales correctly on the target dc and
727 knows about possible mask information in a memory dc. */
729 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
731 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
733 if (!m_window
) return FALSE
;
735 wxClientDC
*srcDC
= (wxClientDC
*)source
;
736 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
738 bool use_bitmap_method
= FALSE
;
739 bool is_mono
= FALSE
;
741 if (srcDC
->m_isMemDC
)
743 if (!memDC
->m_selected
.Ok()) return FALSE
;
745 /* we use the "XCopyArea" way to copy a memory dc into
746 y different window if the memory dc BOTH
747 a) doesn't have any mask or its mask isn't used
751 if (useMask
&& (memDC
->m_selected
.GetMask()))
753 /* we HAVE TO use the direct way for memory dcs
754 that have mask since the XCopyArea doesn't know
756 use_bitmap_method
= TRUE
;
758 else if (memDC
->m_selected
.GetDepth() == 1)
760 /* we HAVE TO use the direct way for memory dcs
761 that are bitmaps because XCopyArea doesn't cope
762 with different bit depths */
764 use_bitmap_method
= TRUE
;
766 else if ((xsrc
== 0) && (ysrc
== 0) &&
767 (width
== memDC
->m_selected
.GetWidth()) &&
768 (height
== memDC
->m_selected
.GetHeight()))
770 /* we SHOULD use the direct way if all of the bitmap
771 in the memory dc is copied in which case XCopyArea
772 wouldn't be able able to boost performace by reducing
773 the area to be scaled */
774 use_bitmap_method
= TRUE
;
778 use_bitmap_method
= FALSE
;
782 CalcBoundingBox( xdest
, ydest
);
783 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
785 /* scale/translate size and position */
786 wxCoord xx
= XLOG2DEV(xdest
);
787 wxCoord yy
= YLOG2DEV(ydest
);
789 wxCoord ww
= XLOG2DEVREL(width
);
790 wxCoord hh
= YLOG2DEVREL(height
);
792 /* compare to current clipping region */
793 if (!m_currentClippingRegion
.IsEmpty())
795 wxRegion
tmp( xx
,yy
,ww
,hh
);
796 tmp
.Intersect( m_currentClippingRegion
);
801 int old_logical_func
= m_logicalFunction
;
802 SetLogicalFunction( logical_func
);
804 if (use_bitmap_method
)
806 /* scale/translate bitmap size */
807 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
808 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
810 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
811 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
813 /* scale bitmap if required */
816 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
818 wxImage
image( memDC
->m_selected
);
819 image
= image
.Scale( bm_ww
, bm_hh
);
822 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
824 use_bitmap
= image
.ConvertToBitmap();
828 use_bitmap
= memDC
->m_selected
;
831 /* apply mask if any */
832 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
833 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
837 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
838 if (!m_currentClippingRegion
.IsEmpty())
841 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
842 GdkGC
*gc
= gdk_gc_new( new_mask
);
844 gdk_gc_set_foreground( gc
, &col
);
845 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
847 gdk_gc_set_background( gc
, &col
);
849 gdk_gc_set_foreground( gc
, &col
);
850 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
851 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
852 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
853 gdk_gc_set_stipple( gc
, mask
);
854 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
861 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
863 gdk_gc_set_clip_mask( m_textGC
, mask
);
864 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
869 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
871 gdk_gc_set_clip_mask( m_penGC
, mask
);
872 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
875 gdk_bitmap_unref( new_mask
);
878 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
879 drawing a mono-bitmap (XBitmap) we use the current text GC */
881 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
883 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
885 /* remove mask again if any */
890 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
891 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
892 if (!m_currentClippingRegion
.IsEmpty())
893 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
897 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
898 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
899 if (!m_currentClippingRegion
.IsEmpty())
900 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
904 else /* use_bitmap_method */
906 if ((width
!= ww
) || (height
!= hh
))
908 /* draw source window into a bitmap as we cannot scale
909 a window in contrast to a bitmap. this would actually
910 work with memory dcs as well, but we'd lose the mask
911 information and waste one step in this process since
912 a memory already has a bitmap. all this is slightly
913 inefficient as we could take an XImage directly from
914 an X window, but we'd then also have to care that
915 the window is not outside the screen (in which case
916 we'd get a BadMatch or what not).
917 Is a double XGetImage and combined XGetPixel and
918 XPutPixel really faster? I'm not sure. look at wxXt
919 for a different implementation of the same problem. */
921 wxBitmap
bitmap( width
, height
);
922 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
924 xsrc
, ysrc
, width
, height
);
928 wxImage
image( bitmap
);
929 image
= image
.Scale( ww
, hh
);
931 /* convert to bitmap */
933 bitmap
= image
.ConvertToBitmap();
935 /* draw scaled bitmap */
937 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
942 /* no scaling and not a memory dc with a mask either */
944 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
946 xsrc
, ysrc
, width
, height
);
950 SetLogicalFunction( old_logical_func
);
954 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
956 wxCHECK_RET( Ok(), wxT("invalid window dc") );
958 if (!m_window
) return;
960 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
962 wxCHECK_RET( font
, wxT("invalid font") );
967 /* CMB 21/5/98: draw text background if mode is wxSOLID */
968 if (m_backgroundMode
== wxSOLID
)
970 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
971 wxCoord height
= font
->ascent
+ font
->descent
;
972 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
973 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
974 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
976 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
978 /* CMB 17/7/98: simple underline: ignores scaling and underlying
979 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
980 properties (see wxXt implementation) */
981 if (m_font
.GetUnderlined())
983 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
984 wxCoord ul_y
= y
+ font
->ascent
;
985 if (font
->descent
> 0) ul_y
++;
986 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
990 GetTextExtent (text
, &w
, &h
);
991 CalcBoundingBox (x
+ w
, y
+ h
);
992 CalcBoundingBox (x
, y
);
995 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
999 DrawText(text
, x
, y
);
1003 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1005 if (!m_window
) return;
1007 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1009 wxCHECK_RET( font
, wxT("invalid font") );
1011 // the size of the text
1012 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1013 wxCoord h
= font
->ascent
+ font
->descent
;
1015 // draw the string normally
1018 dc
.SelectObject(src
);
1019 dc
.SetFont(GetFont());
1020 dc
.SetBackground(*wxWHITE_BRUSH
);
1021 dc
.SetBrush(*wxBLACK_BRUSH
);
1023 dc
.DrawText(text
, 0, 0);
1024 dc
.SetFont(wxNullFont
);
1025 dc
.SelectObject(wxNullBitmap
);
1027 // Calculate the size of the rotated bounding box.
1028 double rad
= DegToRad(angle
);
1029 double dx
= cos(rad
),
1032 // the rectngle vertices are counted clockwise with the first one being at
1033 // (0, 0) (or, rather, at (x, y))
1035 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1038 double x3
= x4
+ x2
,
1042 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1043 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1044 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1045 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1047 // prepare to blit-with-rotate the bitmap to the DC
1050 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1051 *colBack
= m_textBackgroundColour
.GetColor();
1053 bool textColSet
= TRUE
;
1055 unsigned char *data
= image
.GetData();
1057 // paint pixel by pixel
1058 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1060 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1062 // transform source coords to dest coords
1063 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1064 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1065 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1066 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1069 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1070 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1072 // change colour if needed
1073 if ( textPixel
!= textColSet
)
1075 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1078 textColSet
= textPixel
;
1081 // don't use DrawPoint() because it uses the current pen
1082 // colour, and we don't need it here
1083 gdk_draw_point( m_window
, m_textGC
,
1084 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1089 // it would be better to draw with non underlined font and draw the line
1090 // manually here (it would be more straight...)
1092 if ( m_font
.GetUnderlined() )
1094 gdk_draw_line( m_window
, m_textGC
,
1095 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1096 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1100 // restore the font colour
1101 gdk_gc_set_foreground( m_textGC
, colText
);
1103 // update the bounding box
1104 CalcBoundingBox(x
+ minX
, y
+ minY
);
1105 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1108 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1109 wxCoord
*width
, wxCoord
*height
,
1110 wxCoord
*descent
, wxCoord
*externalLeading
,
1111 wxFont
*theFont
) const
1113 wxFont fontToUse
= m_font
;
1114 if (theFont
) fontToUse
= *theFont
;
1116 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1117 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1118 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1119 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1120 if (externalLeading
) (*externalLeading
) = 0; // ??
1123 wxCoord
wxWindowDC::GetCharWidth() const
1125 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1126 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1128 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1131 wxCoord
wxWindowDC::GetCharHeight() const
1133 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1134 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1136 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1139 void wxWindowDC::Clear()
1141 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1143 if (!m_window
) return;
1145 /* - we either are a memory dc or have a window as the
1146 owner. anything else shouldn't happen.
1147 - we don't use gdk_window_clear() as we don't set
1148 the window's background colour anymore. it is too
1149 much pain to keep the DC's and the window's back-
1150 ground colour in synch. */
1155 m_owner
->GetSize( &width
, &height
);
1156 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1163 GetSize( &width
, &height
);
1164 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1169 void wxWindowDC::SetFont( const wxFont
&font
)
1174 void wxWindowDC::SetPen( const wxPen
&pen
)
1176 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1178 if (m_pen
== pen
) return;
1182 if (!m_pen
.Ok()) return;
1184 if (!m_window
) return;
1186 gint width
= m_pen
.GetWidth();
1189 // CMB: if width is non-zero scale it with the dc
1194 // X doesn't allow different width in x and y and so we take
1197 ( fabs((double) XLOG2DEVREL(width
)) +
1198 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1202 static const char dotted
[] = {1, 1};
1203 static const char short_dashed
[] = {2, 2};
1204 static const char wxCoord_dashed
[] = {2, 4};
1205 static const char dotted_dashed
[] = {3, 3, 1, 3};
1207 // We express dash pattern in pen width unit, so we are
1208 // independent of zoom factor and so on...
1210 const char *req_dash
;
1212 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1213 switch (m_pen
.GetStyle())
1217 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1218 req_nb_dash
= m_pen
.GetDashCount();
1219 req_dash
= m_pen
.GetDash();
1224 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1231 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1233 req_dash
= wxCoord_dashed
;
1238 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1240 req_dash
= short_dashed
;
1245 // lineStyle = GDK_LINE_DOUBLE_DASH;
1246 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1248 req_dash
= dotted_dashed
;
1253 case wxSTIPPLE_MASK_OPAQUE
:
1258 lineStyle
= GDK_LINE_SOLID
;
1259 req_dash
= (wxDash
*)NULL
;
1265 #if (GTK_MINOR_VERSION > 0)
1266 if (req_dash
&& req_nb_dash
)
1268 char *real_req_dash
= new char[req_nb_dash
];
1271 for (int i
= 0; i
< req_nb_dash
; i
++)
1272 real_req_dash
[i
] = req_dash
[i
] * width
;
1273 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1274 delete[] real_req_dash
;
1278 // No Memory. We use non-scaled dash pattern...
1279 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1284 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1285 switch (m_pen
.GetCap())
1287 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1288 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1295 capStyle
= GDK_CAP_NOT_LAST
;
1299 capStyle
= GDK_CAP_ROUND
;
1305 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1306 switch (m_pen
.GetJoin())
1308 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1309 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1311 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1314 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1316 m_pen
.GetColour().CalcPixel( m_cmap
);
1317 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1320 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1322 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1324 if (m_brush
== brush
) return;
1328 if (!m_brush
.Ok()) return;
1330 if (!m_window
) return;
1332 m_brush
.GetColour().CalcPixel( m_cmap
);
1333 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1335 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1337 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1339 if (m_brush
.GetStipple()->GetPixmap())
1341 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1342 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1346 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1347 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1351 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1353 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1354 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1357 if (IS_HATCH(m_brush
.GetStyle()))
1359 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1360 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1361 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1365 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1367 /* CMB 21/7/98: Added SetBackground. Sets background brush
1368 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1370 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1372 if (m_backgroundBrush
== brush
) return;
1374 m_backgroundBrush
= brush
;
1376 if (!m_backgroundBrush
.Ok()) return;
1378 if (!m_window
) return;
1380 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1381 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1382 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1383 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1384 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1386 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1388 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1390 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1392 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1393 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1397 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1398 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1402 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1404 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1405 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1406 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1410 void wxWindowDC::SetLogicalFunction( int function
)
1412 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1414 if (m_logicalFunction
== function
)
1417 // VZ: shouldn't this be a CHECK?
1421 GdkFunction mode
= GDK_COPY
;
1424 case wxXOR
: mode
= GDK_XOR
; break;
1425 case wxINVERT
: mode
= GDK_INVERT
; break;
1426 #if (GTK_MINOR_VERSION > 0)
1427 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1428 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1429 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1430 case wxSET
: mode
= GDK_SET
; break;
1431 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1432 case wxAND
: mode
= GDK_AND
; break;
1433 case wxOR
: mode
= GDK_OR
; break;
1434 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1435 case wxNAND
: mode
= GDK_NAND
; break;
1436 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1437 case wxCOPY
: mode
= GDK_COPY
; break;
1438 case wxNO_OP
: mode
= GDK_NOOP
; break;
1439 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1441 // unsupported by GTK
1442 case wxNOR
: mode
= GDK_COPY
; break;
1446 wxFAIL_MSG( wxT("unsupported logical function") );
1451 m_logicalFunction
= function
;
1453 gdk_gc_set_function( m_penGC
, mode
);
1454 gdk_gc_set_function( m_brushGC
, mode
);
1456 // to stay compatible with wxMSW, we don't apply ROPs to the text
1457 // operations (i.e. DrawText/DrawRotatedText).
1458 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1459 gdk_gc_set_function( m_textGC
, mode
);
1462 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1464 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1466 if (m_textForegroundColour
== col
) return;
1468 m_textForegroundColour
= col
;
1469 if (!m_textForegroundColour
.Ok()) return;
1471 if (!m_window
) return;
1473 m_textForegroundColour
.CalcPixel( m_cmap
);
1474 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1477 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1479 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1481 if (m_textBackgroundColour
== col
) return;
1483 m_textBackgroundColour
= col
;
1484 if (!m_textBackgroundColour
.Ok()) return;
1486 if (!m_window
) return;
1488 m_textBackgroundColour
.CalcPixel( m_cmap
);
1489 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1492 void wxWindowDC::SetBackgroundMode( int mode
)
1494 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1496 m_backgroundMode
= mode
;
1498 if (!m_window
) return;
1500 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1501 // transparent/solid background mode
1503 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1505 gdk_gc_set_fill( m_brushGC
,
1506 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1510 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1512 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1515 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1517 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1519 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1521 if (!m_window
) return;
1524 rect
.x
= XLOG2DEV(x
);
1525 rect
.y
= YLOG2DEV(y
);
1526 rect
.width
= XLOG2DEVREL(width
);
1527 rect
.height
= YLOG2DEVREL(height
);
1529 m_currentClippingRegion
.Clear();
1530 m_currentClippingRegion
.Union( rect
);
1531 if (!m_paintClippingRegion
.IsEmpty())
1532 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1534 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1535 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1536 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1537 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1540 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1542 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1546 DestroyClippingRegion();
1551 region
.GetBox( x
, y
, w
, h
);
1553 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
1555 if (!m_window
) return;
1557 m_currentClippingRegion
.Clear();
1558 m_currentClippingRegion
.Union( region
);
1559 if (!m_paintClippingRegion
.IsEmpty())
1560 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1562 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1563 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1564 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1565 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1568 void wxWindowDC::DestroyClippingRegion()
1570 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1572 wxDC::DestroyClippingRegion();
1574 m_currentClippingRegion
.Clear();
1576 if (!m_paintClippingRegion
.IsEmpty())
1577 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1579 if (!m_window
) return;
1581 if (m_currentClippingRegion
.IsEmpty())
1583 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1584 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1585 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1586 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1590 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1591 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1592 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1593 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1597 void wxWindowDC::SetUpDC()
1603 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
1604 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
1605 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
1606 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
1609 /* background colour */
1610 m_backgroundBrush
= *wxWHITE_BRUSH
;
1611 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1612 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
1615 m_textForegroundColour
.CalcPixel( m_cmap
);
1616 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1618 m_textBackgroundColour
.CalcPixel( m_cmap
);
1619 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1621 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
1624 m_pen
.GetColour().CalcPixel( m_cmap
);
1625 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1626 gdk_gc_set_background( m_penGC
, bg_col
);
1628 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
1632 m_brush
.GetColour().CalcPixel( m_cmap
);
1633 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1634 gdk_gc_set_background( m_brushGC
, bg_col
);
1636 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1640 gdk_gc_set_background( m_bgGC
, bg_col
);
1641 gdk_gc_set_foreground( m_bgGC
, bg_col
);
1643 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1646 gdk_gc_set_function( m_textGC
, GDK_COPY
);
1647 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
1648 gdk_gc_set_function( m_penGC
, GDK_COPY
);
1651 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1652 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1653 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1654 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1658 hatch_bitmap
= hatches
;
1659 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1660 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1661 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1662 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1663 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1664 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1668 void wxWindowDC::Destroy()
1670 if (m_penGC
) wxFreePoolGC( m_penGC
);
1671 m_penGC
= (GdkGC
*) NULL
;
1672 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1673 m_brushGC
= (GdkGC
*) NULL
;
1674 if (m_textGC
) wxFreePoolGC( m_textGC
);
1675 m_textGC
= (GdkGC
*) NULL
;
1676 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1677 m_bgGC
= (GdkGC
*) NULL
;
1680 void wxWindowDC::ComputeScaleAndOrigin()
1682 /* CMB: copy scale to see if it changes */
1683 double origScaleX
= m_scaleX
;
1684 double origScaleY
= m_scaleY
;
1686 wxDC::ComputeScaleAndOrigin();
1688 /* CMB: if scale has changed call SetPen to recalulate the line width */
1689 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1692 /* this is a bit artificial, but we need to force wxDC to think
1693 the pen has changed */
1700 // Resolution in pixels per logical inch
1701 wxSize
wxWindowDC::GetPPI() const
1703 return wxSize(100, 100);
1706 int wxWindowDC::GetDepth() const
1708 wxFAIL_MSG(wxT("not implemented"));
1714 // ----------------------------------- spline code ----------------------------------------
1716 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1717 double a3
, double b3
, double a4
, double b4
);
1718 void wx_clear_stack();
1719 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1720 double *y3
, double *x4
, double *y4
);
1721 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1722 double x4
, double y4
);
1723 static bool wx_spline_add_point(double x
, double y
);
1724 static void wx_spline_draw_point_array(wxDC
*dc
);
1726 wxList wx_spline_point_list
;
1728 #define half(z1, z2) ((z1+z2)/2.0)
1731 /* iterative version */
1733 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1736 register double xmid
, ymid
;
1737 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1740 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1742 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1743 xmid
= (double)half(x2
, x3
);
1744 ymid
= (double)half(y2
, y3
);
1745 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1746 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1747 wx_spline_add_point( x1
, y1
);
1748 wx_spline_add_point( xmid
, ymid
);
1750 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1751 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1752 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1753 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1758 /* utilities used by spline drawing routines */
1760 typedef struct wx_spline_stack_struct
{
1761 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1764 #define SPLINE_STACK_DEPTH 20
1765 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1766 static Stack
*wx_stack_top
;
1767 static int wx_stack_count
;
1769 void wx_clear_stack()
1771 wx_stack_top
= wx_spline_stack
;
1775 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1777 wx_stack_top
->x1
= x1
;
1778 wx_stack_top
->y1
= y1
;
1779 wx_stack_top
->x2
= x2
;
1780 wx_stack_top
->y2
= y2
;
1781 wx_stack_top
->x3
= x3
;
1782 wx_stack_top
->y3
= y3
;
1783 wx_stack_top
->x4
= x4
;
1784 wx_stack_top
->y4
= y4
;
1789 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1790 double *x3
, double *y3
, double *x4
, double *y4
)
1792 if (wx_stack_count
== 0)
1796 *x1
= wx_stack_top
->x1
;
1797 *y1
= wx_stack_top
->y1
;
1798 *x2
= wx_stack_top
->x2
;
1799 *y2
= wx_stack_top
->y2
;
1800 *x3
= wx_stack_top
->x3
;
1801 *y3
= wx_stack_top
->y3
;
1802 *x4
= wx_stack_top
->x4
;
1803 *y4
= wx_stack_top
->y4
;
1807 static bool wx_spline_add_point(double x
, double y
)
1809 wxPoint
*point
= new wxPoint
;
1812 wx_spline_point_list
.Append((wxObject
*)point
);
1816 static void wx_spline_draw_point_array(wxDC
*dc
)
1818 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1819 wxNode
*node
= wx_spline_point_list
.First();
1822 wxPoint
*point
= (wxPoint
*)node
->Data();
1825 node
= wx_spline_point_list
.First();
1829 void wxWindowDC::DoDrawSpline( wxList
*points
)
1831 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1834 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1835 double x1
, y1
, x2
, y2
;
1837 wxNode
*node
= points
->First();
1838 p
= (wxPoint
*)node
->Data();
1843 node
= node
->Next();
1844 p
= (wxPoint
*)node
->Data();
1848 cx1
= (double)((x1
+ x2
) / 2);
1849 cy1
= (double)((y1
+ y2
) / 2);
1850 cx2
= (double)((cx1
+ x2
) / 2);
1851 cy2
= (double)((cy1
+ y2
) / 2);
1853 wx_spline_add_point(x1
, y1
);
1855 while ((node
= node
->Next()) != NULL
)
1857 p
= (wxPoint
*)node
->Data();
1862 cx4
= (double)(x1
+ x2
) / 2;
1863 cy4
= (double)(y1
+ y2
) / 2;
1864 cx3
= (double)(x1
+ cx4
) / 2;
1865 cy3
= (double)(y1
+ cy4
) / 2;
1867 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1871 cx2
= (double)(cx1
+ x2
) / 2;
1872 cy2
= (double)(cy1
+ y2
) / 2;
1875 wx_spline_add_point( cx1
, cy1
);
1876 wx_spline_add_point( x2
, y2
);
1878 wx_spline_draw_point_array( this );
1881 #endif // wxUSE_SPLINE
1883 //-----------------------------------------------------------------------------
1885 //-----------------------------------------------------------------------------
1887 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1889 wxPaintDC::wxPaintDC()
1894 wxPaintDC::wxPaintDC( wxWindow
*win
)
1897 if (!win
->GetUpdateRegion().IsEmpty())
1899 m_paintClippingRegion
= win
->GetUpdateRegion();
1900 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1902 gdk_gc_set_clip_region( m_penGC
, m_paintClippingRegion
.GetRegion() );
1903 gdk_gc_set_clip_region( m_brushGC
, m_paintClippingRegion
.GetRegion() );
1904 gdk_gc_set_clip_region( m_textGC
, m_paintClippingRegion
.GetRegion() );
1905 gdk_gc_set_clip_region( m_bgGC
, m_paintClippingRegion
.GetRegion() );
1909 //-----------------------------------------------------------------------------
1911 //-----------------------------------------------------------------------------
1913 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1915 wxClientDC::wxClientDC()
1920 wxClientDC::wxClientDC( wxWindow
*win
)
1925 // ----------------------------------------------------------------------------
1927 // ----------------------------------------------------------------------------
1929 class wxDCModule
: public wxModule
1936 DECLARE_DYNAMIC_CLASS(wxDCModule
)
1939 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
1941 bool wxDCModule::OnInit()
1947 void wxDCModule::OnExit()