1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/dcclient.cpp
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/module.h"
19 #include "wx/gtk/win_gtk.h"
21 #include <math.h> // for floating-point functions
26 //-----------------------------------------------------------------------------
28 //-----------------------------------------------------------------------------
30 #define USE_PAINT_REGION 0
32 //-----------------------------------------------------------------------------
34 //-----------------------------------------------------------------------------
44 static GdkPixmap
*hatches
[num_hatches
];
45 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
47 extern GtkWidget
*wxRootWindow
;
49 //-----------------------------------------------------------------------------
51 //-----------------------------------------------------------------------------
53 const double RAD2DEG
= 180.0 / M_PI
;
55 // ----------------------------------------------------------------------------
57 // ----------------------------------------------------------------------------
59 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
60 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
62 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
64 //-----------------------------------------------------------------------------
65 // temporary implementation of the missing GDK function
66 //-----------------------------------------------------------------------------
68 #include "gdk/gdkprivate.h"
70 void gdk_draw_bitmap (GdkDrawable
*drawable
,
80 GdkWindowPrivate
*drawable_private
;
81 GdkWindowPrivate
*src_private
;
82 GdkGCPrivate
*gc_private
;
84 g_return_if_fail (drawable
!= NULL
);
85 g_return_if_fail (src
!= NULL
);
86 g_return_if_fail (gc
!= NULL
);
88 drawable_private
= (GdkWindowPrivate
*) drawable
;
89 src_private
= (GdkWindowPrivate
*) src
;
90 if (drawable_private
->destroyed
|| src_private
->destroyed
)
93 gc_private
= (GdkGCPrivate
*) gc
;
95 if (width
== -1) width
= src_private
->width
;
96 if (height
== -1) height
= src_private
->height
;
98 XCopyPlane( drawable_private
->xdisplay
,
100 drawable_private
->xwindow
,
108 //-----------------------------------------------------------------------------
109 // Implement Pool of Graphic contexts. Creating them takes too much time.
110 //-----------------------------------------------------------------------------
132 static wxGC wxGCPool
[200];
134 static void wxInitGCPool()
136 memset( wxGCPool
, 0, 200*sizeof(wxGC
) );
139 static void wxCleanUpGCPool()
141 for (int i
= 0; i
< 200; i
++)
143 if (wxGCPool
[i
].m_gc
)
144 gdk_gc_unref( wxGCPool
[i
].m_gc
);
148 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
150 for (int i
= 0; i
< 200; i
++)
152 if (!wxGCPool
[i
].m_gc
)
154 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
155 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
156 wxGCPool
[i
].m_type
= type
;
157 wxGCPool
[i
].m_used
= FALSE
;
159 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
161 wxGCPool
[i
].m_used
= TRUE
;
162 return wxGCPool
[i
].m_gc
;
166 wxFAIL_MSG( wxT("No GC available") );
168 return (GdkGC
*) NULL
;
171 static void wxFreePoolGC( GdkGC
*gc
)
173 for (int i
= 0; i
< 200; i
++)
175 if (wxGCPool
[i
].m_gc
== gc
)
177 wxGCPool
[i
].m_used
= FALSE
;
182 wxFAIL_MSG( wxT("Wrong GC") );
185 //-----------------------------------------------------------------------------
187 //-----------------------------------------------------------------------------
189 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
191 wxWindowDC::wxWindowDC()
193 m_penGC
= (GdkGC
*) NULL
;
194 m_brushGC
= (GdkGC
*) NULL
;
195 m_textGC
= (GdkGC
*) NULL
;
196 m_bgGC
= (GdkGC
*) NULL
;
197 m_cmap
= (GdkColormap
*) NULL
;
199 m_owner
= (wxWindow
*)NULL
;
202 wxWindowDC::wxWindowDC( wxWindow
*window
)
204 m_penGC
= (GdkGC
*) NULL
;
205 m_brushGC
= (GdkGC
*) NULL
;
206 m_textGC
= (GdkGC
*) NULL
;
207 m_bgGC
= (GdkGC
*) NULL
;
208 m_cmap
= (GdkColormap
*) NULL
;
209 m_owner
= (wxWindow
*)NULL
;
211 m_font
= window
->GetFont();
213 wxASSERT_MSG( window
, wxT("DC needs a window") );
215 GtkWidget
*widget
= window
->m_wxwindow
;
217 // some controls don't have m_wxwindow - like wxStaticBox, but the user
218 // code should still be able to create wxClientDCs for them, so we will
219 // use the parent window here then
222 window
= window
->GetParent();
223 widget
= window
->m_wxwindow
;
226 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
228 GtkPizza
*pizza
= GTK_PIZZA( widget
);
229 m_window
= pizza
->bin_window
;
234 /* don't report problems */
240 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
244 /* this must be done after SetUpDC, bacause SetUpDC calls the
245 repective SetBrush, SetPen, SetBackground etc functions
246 to set up the DC. SetBackground call m_owner->SetBackground
247 and this might not be desired as the standard dc background
248 is white whereas a window might assume gray to be the
249 standard (as e.g. wxStatusBar) */
254 wxWindowDC::~wxWindowDC()
259 void wxWindowDC::SetUpDC()
263 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
265 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
267 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
268 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
269 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
270 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
274 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
275 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
276 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
277 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
280 /* background colour */
281 m_backgroundBrush
= *wxWHITE_BRUSH
;
282 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
283 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
286 m_textForegroundColour
.CalcPixel( m_cmap
);
287 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
289 m_textBackgroundColour
.CalcPixel( m_cmap
);
290 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
292 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
295 m_pen
.GetColour().CalcPixel( m_cmap
);
296 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
297 gdk_gc_set_background( m_penGC
, bg_col
);
299 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
303 m_brush
.GetColour().CalcPixel( m_cmap
);
304 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
305 gdk_gc_set_background( m_brushGC
, bg_col
);
307 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
311 gdk_gc_set_background( m_bgGC
, bg_col
);
312 gdk_gc_set_foreground( m_bgGC
, bg_col
);
314 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
317 gdk_gc_set_function( m_textGC
, GDK_COPY
);
318 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
319 gdk_gc_set_function( m_penGC
, GDK_COPY
);
322 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
323 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
324 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
325 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
329 hatch_bitmap
= hatches
;
330 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
331 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
332 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
333 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
334 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
335 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
339 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
340 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
342 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
345 bool wxWindowDC::DoGetPixel( wxCoord
WXUNUSED(x1
), wxCoord
WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
347 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
351 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
353 wxCHECK_RET( Ok(), wxT("invalid window dc") );
355 if (m_pen
.GetStyle() != wxTRANSPARENT
)
358 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
360 CalcBoundingBox(x1
, y1
);
361 CalcBoundingBox(x2
, y2
);
365 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
367 wxCHECK_RET( Ok(), wxT("invalid window dc") );
369 if (m_pen
.GetStyle() != wxTRANSPARENT
)
374 wxCoord xx
= XLOG2DEV(x
);
375 wxCoord yy
= YLOG2DEV(y
);
378 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
379 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
384 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
385 wxCoord xc
, wxCoord yc
)
387 wxCHECK_RET( Ok(), wxT("invalid window dc") );
389 wxCoord xx1
= XLOG2DEV(x1
);
390 wxCoord yy1
= YLOG2DEV(y1
);
391 wxCoord xx2
= XLOG2DEV(x2
);
392 wxCoord yy2
= YLOG2DEV(y2
);
393 wxCoord xxc
= XLOG2DEV(xc
);
394 wxCoord yyc
= YLOG2DEV(yc
);
395 double dx
= xx1
- xxc
;
396 double dy
= yy1
- yyc
;
397 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
398 wxCoord r
= (wxCoord
)radius
;
399 double radius1
, radius2
;
401 if (xx1
== xx2
&& yy1
== yy2
)
409 radius1
= radius2
= 0.0;
413 radius1
= (xx1
- xxc
== 0) ?
414 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
415 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
416 radius2
= (xx2
- xxc
== 0) ?
417 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
418 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
420 wxCoord alpha1
= wxCoord(radius1
* 64.0);
421 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
422 while (alpha2
<= 0) alpha2
+= 360*64;
423 while (alpha1
> 360*64) alpha1
-= 360*64;
427 if (m_brush
.GetStyle() != wxTRANSPARENT
)
428 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
430 if (m_pen
.GetStyle() != wxTRANSPARENT
)
431 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
434 CalcBoundingBox (x1
, y1
);
435 CalcBoundingBox (x2
, y2
);
438 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
440 wxCHECK_RET( Ok(), wxT("invalid window dc") );
442 wxCoord xx
= XLOG2DEV(x
);
443 wxCoord yy
= YLOG2DEV(y
);
444 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
445 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
447 // CMB: handle -ve width and/or height
448 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
449 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
453 wxCoord start
= wxCoord(sa
* 64.0);
454 wxCoord end
= wxCoord(ea
* 64.0);
456 if (m_brush
.GetStyle() != wxTRANSPARENT
)
457 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
459 if (m_pen
.GetStyle() != wxTRANSPARENT
)
460 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
463 CalcBoundingBox (x
, y
);
464 CalcBoundingBox (x
+ width
, y
+ height
);
467 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
469 wxCHECK_RET( Ok(), wxT("invalid window dc") );
471 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
472 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
474 CalcBoundingBox (x
, y
);
477 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
479 wxCHECK_RET( Ok(), wxT("invalid window dc") );
481 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
484 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
486 for (int i
= 0; i
< n
-1; i
++)
488 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
489 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
490 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
491 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
494 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
496 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
500 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
502 wxCHECK_RET( Ok(), wxT("invalid window dc") );
506 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
508 for (i
= 0 ; i
< n
; i
++)
510 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
511 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
513 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
518 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
519 gdk_draw_polygon (m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
522 if ((m_brush
.GetStyle() != wxTRANSPARENT
))
523 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
529 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
531 for (i
= 0 ; i
< n
; i
++)
533 gdk_draw_line( m_window
, m_penGC
,
536 gdkpoints
[(i
+1)%n
].x
,
537 gdkpoints
[(i
+1)%n
].y
);
544 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
546 wxCHECK_RET( Ok(), wxT("invalid window dc") );
548 wxCoord xx
= XLOG2DEV(x
);
549 wxCoord yy
= YLOG2DEV(y
);
550 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
551 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
553 // CMB: draw nothing if transformed w or h is 0
554 if (ww
== 0 || hh
== 0) return;
556 // CMB: handle -ve width and/or height
557 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
558 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
562 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
564 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
565 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
569 if (m_brush
.GetStyle() != wxTRANSPARENT
)
570 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
572 if (m_pen
.GetStyle() != wxTRANSPARENT
)
573 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
577 CalcBoundingBox( x
, y
);
578 CalcBoundingBox( x
+ width
, y
+ height
);
581 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
583 wxCHECK_RET( Ok(), wxT("invalid window dc") );
585 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
587 wxCoord xx
= XLOG2DEV(x
);
588 wxCoord yy
= YLOG2DEV(y
);
589 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
590 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
591 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
593 // CMB: handle -ve width and/or height
594 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
595 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
597 // CMB: if radius is zero use DrawRectangle() instead to avoid
598 // X drawing errors with small radii
601 DrawRectangle( x
, y
, width
, height
);
605 // CMB: draw nothing if transformed w or h is 0
606 if (ww
== 0 || hh
== 0) return;
608 // CMB: adjust size if outline is drawn otherwise the result is
609 // 1 pixel too wide and high
610 if (m_pen
.GetStyle() != wxTRANSPARENT
)
618 // CMB: ensure dd is not larger than rectangle otherwise we
619 // get an hour glass shape
621 if (dd
> ww
) dd
= ww
;
622 if (dd
> hh
) dd
= hh
;
625 if (m_brush
.GetStyle() != wxTRANSPARENT
)
627 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
628 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
629 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
630 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
631 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
632 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
635 if (m_pen
.GetStyle() != wxTRANSPARENT
)
637 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
638 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
639 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
640 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
641 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
642 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
643 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
644 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
648 // this ignores the radius
649 CalcBoundingBox( x
, y
);
650 CalcBoundingBox( x
+ width
, y
+ height
);
653 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
655 wxCHECK_RET( Ok(), wxT("invalid window dc") );
657 wxCoord xx
= XLOG2DEV(x
);
658 wxCoord yy
= YLOG2DEV(y
);
659 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
660 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
662 // CMB: handle -ve width and/or height
663 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
664 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
668 if (m_brush
.GetStyle() != wxTRANSPARENT
)
669 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
671 if (m_pen
.GetStyle() != wxTRANSPARENT
)
672 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
675 CalcBoundingBox( x
- width
, y
- height
);
676 CalcBoundingBox( x
+ width
, y
+ height
);
679 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
681 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
682 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
685 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
686 wxCoord x
, wxCoord y
,
689 wxCHECK_RET( Ok(), wxT("invalid window dc") );
691 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
693 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
695 /* scale/translate size and position */
696 int xx
= XLOG2DEV(x
);
697 int yy
= YLOG2DEV(y
);
699 int w
= bitmap
.GetWidth();
700 int h
= bitmap
.GetHeight();
702 CalcBoundingBox( x
, y
);
703 CalcBoundingBox( x
+ w
, y
+ h
);
705 if (!m_window
) return;
707 int ww
= XLOG2DEVREL(w
);
708 int hh
= YLOG2DEVREL(h
);
710 /* compare to current clipping region */
711 if (!m_currentClippingRegion
.IsEmpty())
713 wxRegion
tmp( xx
,yy
,ww
,hh
);
714 tmp
.Intersect( m_currentClippingRegion
);
719 /* scale bitmap if required */
721 if ((w
!= ww
) || (h
!= hh
))
723 wxImage
image( bitmap
);
724 image
.Rescale( ww
, hh
);
726 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
728 use_bitmap
= image
.ConvertToBitmap();
735 /* apply mask if any */
736 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
737 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
741 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
742 if (!m_currentClippingRegion
.IsEmpty())
745 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
746 GdkGC
*gc
= gdk_gc_new( new_mask
);
748 gdk_gc_set_foreground( gc
, &col
);
749 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
751 gdk_gc_set_background( gc
, &col
);
753 gdk_gc_set_foreground( gc
, &col
);
754 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
755 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
756 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
757 gdk_gc_set_stipple( gc
, mask
);
758 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
760 gdk_gc_set_clip_mask( m_brushGC, NULL );
761 gdk_gc_set_clip_mask( m_textGC, NULL );
762 SetBrush( *wxRED_BRUSH );
763 DrawRectangle( 70, 0, 70, 1000 );
764 gdk_draw_bitmap( m_window, m_textGC, new_mask, 0, 0, 100, 5, ww, hh );
765 gdk_draw_bitmap( m_window, m_textGC, mask, 0, 0, 80, 5, ww, hh );
773 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
775 gdk_gc_set_clip_mask( m_textGC
, mask
);
776 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
781 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
783 gdk_gc_set_clip_mask( m_penGC
, mask
);
784 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
787 gdk_bitmap_unref( new_mask
);
790 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
791 drawing a mono-bitmap (XBitmap) we use the current text GC */
793 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
795 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
797 /* remove mask again if any */
802 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
803 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
804 if (!m_currentClippingRegion
.IsEmpty())
805 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
809 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
810 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
811 if (!m_currentClippingRegion
.IsEmpty())
812 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
817 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
818 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
819 int logical_func
, bool useMask
)
821 /* this is the nth try to get this utterly useless function to
822 work. it now completely ignores the scaling or translation
823 of the source dc, but scales correctly on the target dc and
824 knows about possible mask information in a memory dc. */
826 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
828 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
830 if (!m_window
) return FALSE
;
832 wxClientDC
*srcDC
= (wxClientDC
*)source
;
833 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
835 bool use_bitmap_method
= FALSE
;
836 bool is_mono
= FALSE
;
838 if (srcDC
->m_isMemDC
)
840 if (!memDC
->m_selected
.Ok()) return FALSE
;
842 /* we use the "XCopyArea" way to copy a memory dc into
843 y different window if the memory dc BOTH
844 a) doesn't have any mask or its mask isn't used
848 if (useMask
&& (memDC
->m_selected
.GetMask()))
850 /* we HAVE TO use the direct way for memory dcs
851 that have mask since the XCopyArea doesn't know
853 use_bitmap_method
= TRUE
;
855 else if (memDC
->m_selected
.GetDepth() == 1)
857 /* we HAVE TO use the direct way for memory dcs
858 that are bitmaps because XCopyArea doesn't cope
859 with different bit depths */
861 use_bitmap_method
= TRUE
;
863 else if ((xsrc
== 0) && (ysrc
== 0) &&
864 (width
== memDC
->m_selected
.GetWidth()) &&
865 (height
== memDC
->m_selected
.GetHeight()))
867 /* we SHOULD use the direct way if all of the bitmap
868 in the memory dc is copied in which case XCopyArea
869 wouldn't be able able to boost performace by reducing
870 the area to be scaled */
871 use_bitmap_method
= TRUE
;
875 use_bitmap_method
= FALSE
;
879 CalcBoundingBox( xdest
, ydest
);
880 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
882 /* scale/translate size and position */
883 wxCoord xx
= XLOG2DEV(xdest
);
884 wxCoord yy
= YLOG2DEV(ydest
);
886 wxCoord ww
= XLOG2DEVREL(width
);
887 wxCoord hh
= YLOG2DEVREL(height
);
889 /* compare to current clipping region */
890 if (!m_currentClippingRegion
.IsEmpty())
892 wxRegion
tmp( xx
,yy
,ww
,hh
);
893 tmp
.Intersect( m_currentClippingRegion
);
898 int old_logical_func
= m_logicalFunction
;
899 SetLogicalFunction( logical_func
);
901 if (use_bitmap_method
)
903 /* scale/translate bitmap size */
904 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
905 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
907 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
908 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
910 /* scale bitmap if required */
913 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
915 wxImage
image( memDC
->m_selected
);
916 image
= image
.Scale( bm_ww
, bm_hh
);
919 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
921 use_bitmap
= image
.ConvertToBitmap();
925 use_bitmap
= memDC
->m_selected
;
928 /* apply mask if any */
929 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
930 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
934 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
935 if (!m_currentClippingRegion
.IsEmpty())
938 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
939 GdkGC
*gc
= gdk_gc_new( new_mask
);
941 gdk_gc_set_foreground( gc
, &col
);
942 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
944 gdk_gc_set_background( gc
, &col
);
946 gdk_gc_set_foreground( gc
, &col
);
947 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
948 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
949 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
950 gdk_gc_set_stipple( gc
, mask
);
951 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
958 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
960 gdk_gc_set_clip_mask( m_textGC
, mask
);
961 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
966 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
968 gdk_gc_set_clip_mask( m_penGC
, mask
);
969 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
972 gdk_bitmap_unref( new_mask
);
975 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
976 drawing a mono-bitmap (XBitmap) we use the current text GC */
978 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
980 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
982 /* remove mask again if any */
987 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
988 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
989 if (!m_currentClippingRegion
.IsEmpty())
990 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
994 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
995 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
996 if (!m_currentClippingRegion
.IsEmpty())
997 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1001 else /* use_bitmap_method */
1003 if ((width
!= ww
) || (height
!= hh
))
1005 /* draw source window into a bitmap as we cannot scale
1006 a window in contrast to a bitmap. this would actually
1007 work with memory dcs as well, but we'd lose the mask
1008 information and waste one step in this process since
1009 a memory already has a bitmap. all this is slightly
1010 inefficient as we could take an XImage directly from
1011 an X window, but we'd then also have to care that
1012 the window is not outside the screen (in which case
1013 we'd get a BadMatch or what not).
1014 Is a double XGetImage and combined XGetPixel and
1015 XPutPixel really faster? I'm not sure. look at wxXt
1016 for a different implementation of the same problem. */
1018 wxBitmap
bitmap( width
, height
);
1019 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1021 xsrc
, ysrc
, width
, height
);
1025 wxImage
image( bitmap
);
1026 image
= image
.Scale( ww
, hh
);
1028 /* convert to bitmap */
1030 bitmap
= image
.ConvertToBitmap();
1032 /* draw scaled bitmap */
1034 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1039 /* no scaling and not a memory dc with a mask either */
1041 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1043 xsrc
, ysrc
, width
, height
);
1047 SetLogicalFunction( old_logical_func
);
1051 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1053 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1055 if (!m_window
) return;
1057 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1059 wxCHECK_RET( font
, wxT("invalid font") );
1064 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1065 if (m_backgroundMode
== wxSOLID
)
1067 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1068 wxCoord height
= font
->ascent
+ font
->descent
;
1069 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1070 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1071 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1073 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1075 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1076 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1077 properties (see wxXt implementation) */
1078 if (m_font
.GetUnderlined())
1080 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1081 wxCoord ul_y
= y
+ font
->ascent
;
1082 if (font
->descent
> 0) ul_y
++;
1083 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1087 GetTextExtent (text
, &w
, &h
);
1088 CalcBoundingBox (x
+ w
, y
+ h
);
1089 CalcBoundingBox (x
, y
);
1092 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1096 DrawText(text
, x
, y
);
1100 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1102 if (!m_window
) return;
1104 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1106 wxCHECK_RET( font
, wxT("invalid font") );
1108 // the size of the text
1109 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1110 wxCoord h
= font
->ascent
+ font
->descent
;
1112 // draw the string normally
1115 dc
.SelectObject(src
);
1116 dc
.SetFont(GetFont());
1117 dc
.SetBackground(*wxWHITE_BRUSH
);
1118 dc
.SetBrush(*wxBLACK_BRUSH
);
1120 dc
.DrawText(text
, 0, 0);
1121 dc
.SetFont(wxNullFont
);
1122 dc
.SelectObject(wxNullBitmap
);
1124 // Calculate the size of the rotated bounding box.
1125 double rad
= DegToRad(angle
);
1126 double dx
= cos(rad
),
1129 // the rectngle vertices are counted clockwise with the first one being at
1130 // (0, 0) (or, rather, at (x, y))
1132 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1135 double x3
= x4
+ x2
,
1139 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1140 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1141 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1142 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1144 // prepare to blit-with-rotate the bitmap to the DC
1147 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1148 *colBack
= m_textBackgroundColour
.GetColor();
1150 bool textColSet
= TRUE
;
1152 unsigned char *data
= image
.GetData();
1154 // paint pixel by pixel
1155 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1157 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1159 // transform source coords to dest coords
1160 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1161 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1162 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1163 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1166 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1167 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1169 // change colour if needed
1170 if ( textPixel
!= textColSet
)
1172 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1175 textColSet
= textPixel
;
1178 // don't use DrawPoint() because it uses the current pen
1179 // colour, and we don't need it here
1180 gdk_draw_point( m_window
, m_textGC
,
1181 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1186 // it would be better to draw with non underlined font and draw the line
1187 // manually here (it would be more straight...)
1189 if ( m_font
.GetUnderlined() )
1191 gdk_draw_line( m_window
, m_textGC
,
1192 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1193 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1197 // restore the font colour
1198 gdk_gc_set_foreground( m_textGC
, colText
);
1200 // update the bounding box
1201 CalcBoundingBox(x
+ minX
, y
+ minY
);
1202 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1205 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1206 wxCoord
*width
, wxCoord
*height
,
1207 wxCoord
*descent
, wxCoord
*externalLeading
,
1208 wxFont
*theFont
) const
1210 wxFont fontToUse
= m_font
;
1211 if (theFont
) fontToUse
= *theFont
;
1213 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1214 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1215 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1216 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1217 if (externalLeading
) (*externalLeading
) = 0; // ??
1220 wxCoord
wxWindowDC::GetCharWidth() const
1222 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1223 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1225 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1228 wxCoord
wxWindowDC::GetCharHeight() const
1230 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1231 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1233 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1236 void wxWindowDC::Clear()
1238 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1240 if (!m_window
) return;
1242 /* - we either are a memory dc or have a window as the
1243 owner. anything else shouldn't happen.
1244 - we don't use gdk_window_clear() as we don't set
1245 the window's background colour anymore. it is too
1246 much pain to keep the DC's and the window's back-
1247 ground colour in synch. */
1252 m_owner
->GetSize( &width
, &height
);
1253 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1260 GetSize( &width
, &height
);
1261 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1266 void wxWindowDC::SetFont( const wxFont
&font
)
1271 void wxWindowDC::SetPen( const wxPen
&pen
)
1273 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1275 if (m_pen
== pen
) return;
1279 if (!m_pen
.Ok()) return;
1281 if (!m_window
) return;
1283 gint width
= m_pen
.GetWidth();
1286 // CMB: if width is non-zero scale it with the dc
1291 // X doesn't allow different width in x and y and so we take
1294 ( fabs((double) XLOG2DEVREL(width
)) +
1295 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1299 static const char dotted
[] = {1, 1};
1300 static const char short_dashed
[] = {2, 2};
1301 static const char wxCoord_dashed
[] = {2, 4};
1302 static const char dotted_dashed
[] = {3, 3, 1, 3};
1304 // We express dash pattern in pen width unit, so we are
1305 // independent of zoom factor and so on...
1307 const char *req_dash
;
1309 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1310 switch (m_pen
.GetStyle())
1314 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1315 req_nb_dash
= m_pen
.GetDashCount();
1316 req_dash
= m_pen
.GetDash();
1321 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1328 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1330 req_dash
= wxCoord_dashed
;
1335 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1337 req_dash
= short_dashed
;
1342 // lineStyle = GDK_LINE_DOUBLE_DASH;
1343 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1345 req_dash
= dotted_dashed
;
1350 case wxSTIPPLE_MASK_OPAQUE
:
1355 lineStyle
= GDK_LINE_SOLID
;
1356 req_dash
= (wxDash
*)NULL
;
1362 #if (GTK_MINOR_VERSION > 0)
1363 if (req_dash
&& req_nb_dash
)
1365 char *real_req_dash
= new char[req_nb_dash
];
1368 for (int i
= 0; i
< req_nb_dash
; i
++)
1369 real_req_dash
[i
] = req_dash
[i
] * width
;
1370 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1371 delete[] real_req_dash
;
1375 // No Memory. We use non-scaled dash pattern...
1376 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1381 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1382 switch (m_pen
.GetCap())
1384 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1385 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1392 capStyle
= GDK_CAP_NOT_LAST
;
1396 capStyle
= GDK_CAP_ROUND
;
1402 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1403 switch (m_pen
.GetJoin())
1405 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1406 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1408 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1411 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1413 m_pen
.GetColour().CalcPixel( m_cmap
);
1414 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1417 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1419 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1421 if (m_brush
== brush
) return;
1425 if (!m_brush
.Ok()) return;
1427 if (!m_window
) return;
1429 m_brush
.GetColour().CalcPixel( m_cmap
);
1430 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1432 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1434 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1436 if (m_brush
.GetStipple()->GetPixmap())
1438 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1439 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1443 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1444 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1448 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1450 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1451 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1454 if (IS_HATCH(m_brush
.GetStyle()))
1456 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1457 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1458 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1462 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1464 /* CMB 21/7/98: Added SetBackground. Sets background brush
1465 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1467 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1469 if (m_backgroundBrush
== brush
) return;
1471 m_backgroundBrush
= brush
;
1473 if (!m_backgroundBrush
.Ok()) return;
1475 if (!m_window
) return;
1477 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1478 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1479 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1480 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1481 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1483 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1485 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1487 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1489 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1490 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1494 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1495 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1499 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1501 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1502 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1503 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1507 void wxWindowDC::SetLogicalFunction( int function
)
1509 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1511 if (m_logicalFunction
== function
)
1514 // VZ: shouldn't this be a CHECK?
1518 GdkFunction mode
= GDK_COPY
;
1521 case wxXOR
: mode
= GDK_XOR
; break;
1522 case wxINVERT
: mode
= GDK_INVERT
; break;
1523 #if (GTK_MINOR_VERSION > 0)
1524 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1525 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1526 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1527 case wxSET
: mode
= GDK_SET
; break;
1528 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1529 case wxAND
: mode
= GDK_AND
; break;
1530 case wxOR
: mode
= GDK_OR
; break;
1531 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1532 case wxNAND
: mode
= GDK_NAND
; break;
1533 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1534 case wxCOPY
: mode
= GDK_COPY
; break;
1535 case wxNO_OP
: mode
= GDK_NOOP
; break;
1536 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1538 // unsupported by GTK
1539 case wxNOR
: mode
= GDK_COPY
; break;
1543 wxFAIL_MSG( wxT("unsupported logical function") );
1548 m_logicalFunction
= function
;
1550 gdk_gc_set_function( m_penGC
, mode
);
1551 gdk_gc_set_function( m_brushGC
, mode
);
1553 // to stay compatible with wxMSW, we don't apply ROPs to the text
1554 // operations (i.e. DrawText/DrawRotatedText).
1555 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1556 gdk_gc_set_function( m_textGC
, mode
);
1559 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1561 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1563 if (m_textForegroundColour
== col
) return;
1565 m_textForegroundColour
= col
;
1566 if (!m_textForegroundColour
.Ok()) return;
1568 if (!m_window
) return;
1570 m_textForegroundColour
.CalcPixel( m_cmap
);
1571 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1574 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1576 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1578 if (m_textBackgroundColour
== col
) return;
1580 m_textBackgroundColour
= col
;
1581 if (!m_textBackgroundColour
.Ok()) return;
1583 if (!m_window
) return;
1585 m_textBackgroundColour
.CalcPixel( m_cmap
);
1586 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1589 void wxWindowDC::SetBackgroundMode( int mode
)
1591 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1593 m_backgroundMode
= mode
;
1595 if (!m_window
) return;
1597 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1598 // transparent/solid background mode
1600 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1602 gdk_gc_set_fill( m_brushGC
,
1603 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1607 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1609 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1612 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1614 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1616 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1618 if (!m_window
) return;
1621 rect
.x
= XLOG2DEV(x
);
1622 rect
.y
= YLOG2DEV(y
);
1623 rect
.width
= XLOG2DEVREL(width
);
1624 rect
.height
= YLOG2DEVREL(height
);
1626 m_currentClippingRegion
.Clear();
1627 m_currentClippingRegion
.Union( rect
);
1628 #if USE_PAINT_REGION
1629 if (!m_paintClippingRegion
.IsEmpty())
1630 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1633 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1634 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1635 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1636 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1639 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1641 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1645 DestroyClippingRegion();
1650 region
.GetBox( x
, y
, w
, h
);
1652 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
1654 if (!m_window
) return;
1656 m_currentClippingRegion
.Clear();
1657 m_currentClippingRegion
.Union( region
);
1658 #if USE_PAINT_REGION
1659 if (!m_paintClippingRegion
.IsEmpty())
1660 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1663 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1664 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1665 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1666 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1669 void wxWindowDC::DestroyClippingRegion()
1671 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1673 wxDC::DestroyClippingRegion();
1675 m_currentClippingRegion
.Clear();
1677 if (!m_paintClippingRegion
.IsEmpty())
1678 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1680 if (!m_window
) return;
1682 if (m_currentClippingRegion
.IsEmpty())
1684 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1685 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1686 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1687 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1691 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1692 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1693 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1694 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1698 void wxWindowDC::Destroy()
1700 if (m_penGC
) wxFreePoolGC( m_penGC
);
1701 m_penGC
= (GdkGC
*) NULL
;
1702 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1703 m_brushGC
= (GdkGC
*) NULL
;
1704 if (m_textGC
) wxFreePoolGC( m_textGC
);
1705 m_textGC
= (GdkGC
*) NULL
;
1706 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1707 m_bgGC
= (GdkGC
*) NULL
;
1710 void wxWindowDC::ComputeScaleAndOrigin()
1712 /* CMB: copy scale to see if it changes */
1713 double origScaleX
= m_scaleX
;
1714 double origScaleY
= m_scaleY
;
1716 wxDC::ComputeScaleAndOrigin();
1718 /* CMB: if scale has changed call SetPen to recalulate the line width */
1719 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1722 /* this is a bit artificial, but we need to force wxDC to think
1723 the pen has changed */
1730 // Resolution in pixels per logical inch
1731 wxSize
wxWindowDC::GetPPI() const
1733 return wxSize(100, 100);
1736 int wxWindowDC::GetDepth() const
1738 wxFAIL_MSG(wxT("not implemented"));
1744 // ----------------------------------- spline code ----------------------------------------
1746 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1747 double a3
, double b3
, double a4
, double b4
);
1748 void wx_clear_stack();
1749 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1750 double *y3
, double *x4
, double *y4
);
1751 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1752 double x4
, double y4
);
1753 static bool wx_spline_add_point(double x
, double y
);
1754 static void wx_spline_draw_point_array(wxDC
*dc
);
1756 wxList wx_spline_point_list
;
1758 #define half(z1, z2) ((z1+z2)/2.0)
1761 /* iterative version */
1763 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1766 register double xmid
, ymid
;
1767 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1770 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1772 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1773 xmid
= (double)half(x2
, x3
);
1774 ymid
= (double)half(y2
, y3
);
1775 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1776 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1777 wx_spline_add_point( x1
, y1
);
1778 wx_spline_add_point( xmid
, ymid
);
1780 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1781 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1782 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1783 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1788 /* utilities used by spline drawing routines */
1790 typedef struct wx_spline_stack_struct
{
1791 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1794 #define SPLINE_STACK_DEPTH 20
1795 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1796 static Stack
*wx_stack_top
;
1797 static int wx_stack_count
;
1799 void wx_clear_stack()
1801 wx_stack_top
= wx_spline_stack
;
1805 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1807 wx_stack_top
->x1
= x1
;
1808 wx_stack_top
->y1
= y1
;
1809 wx_stack_top
->x2
= x2
;
1810 wx_stack_top
->y2
= y2
;
1811 wx_stack_top
->x3
= x3
;
1812 wx_stack_top
->y3
= y3
;
1813 wx_stack_top
->x4
= x4
;
1814 wx_stack_top
->y4
= y4
;
1819 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1820 double *x3
, double *y3
, double *x4
, double *y4
)
1822 if (wx_stack_count
== 0)
1826 *x1
= wx_stack_top
->x1
;
1827 *y1
= wx_stack_top
->y1
;
1828 *x2
= wx_stack_top
->x2
;
1829 *y2
= wx_stack_top
->y2
;
1830 *x3
= wx_stack_top
->x3
;
1831 *y3
= wx_stack_top
->y3
;
1832 *x4
= wx_stack_top
->x4
;
1833 *y4
= wx_stack_top
->y4
;
1837 static bool wx_spline_add_point(double x
, double y
)
1839 wxPoint
*point
= new wxPoint
;
1842 wx_spline_point_list
.Append((wxObject
*)point
);
1846 static void wx_spline_draw_point_array(wxDC
*dc
)
1848 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1849 wxNode
*node
= wx_spline_point_list
.First();
1852 wxPoint
*point
= (wxPoint
*)node
->Data();
1855 node
= wx_spline_point_list
.First();
1859 void wxWindowDC::DoDrawSpline( wxList
*points
)
1861 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1864 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1865 double x1
, y1
, x2
, y2
;
1867 wxNode
*node
= points
->First();
1868 p
= (wxPoint
*)node
->Data();
1873 node
= node
->Next();
1874 p
= (wxPoint
*)node
->Data();
1878 cx1
= (double)((x1
+ x2
) / 2);
1879 cy1
= (double)((y1
+ y2
) / 2);
1880 cx2
= (double)((cx1
+ x2
) / 2);
1881 cy2
= (double)((cy1
+ y2
) / 2);
1883 wx_spline_add_point(x1
, y1
);
1885 while ((node
= node
->Next()) != NULL
)
1887 p
= (wxPoint
*)node
->Data();
1892 cx4
= (double)(x1
+ x2
) / 2;
1893 cy4
= (double)(y1
+ y2
) / 2;
1894 cx3
= (double)(x1
+ cx4
) / 2;
1895 cy3
= (double)(y1
+ cy4
) / 2;
1897 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1901 cx2
= (double)(cx1
+ x2
) / 2;
1902 cy2
= (double)(cy1
+ y2
) / 2;
1905 wx_spline_add_point( cx1
, cy1
);
1906 wx_spline_add_point( x2
, y2
);
1908 wx_spline_draw_point_array( this );
1911 #endif // wxUSE_SPLINE
1913 //-----------------------------------------------------------------------------
1915 //-----------------------------------------------------------------------------
1917 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1919 wxPaintDC::wxPaintDC()
1924 wxPaintDC::wxPaintDC( wxWindow
*win
)
1927 #if USE_PAINT_REGION
1928 if (!win
->GetUpdateRegion().IsEmpty())
1930 m_paintClippingRegion
= win
->GetUpdateRegion();
1931 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1933 gdk_gc_set_clip_region( m_penGC
, m_paintClippingRegion
.GetRegion() );
1934 gdk_gc_set_clip_region( m_brushGC
, m_paintClippingRegion
.GetRegion() );
1935 gdk_gc_set_clip_region( m_textGC
, m_paintClippingRegion
.GetRegion() );
1936 gdk_gc_set_clip_region( m_bgGC
, m_paintClippingRegion
.GetRegion() );
1941 //-----------------------------------------------------------------------------
1943 //-----------------------------------------------------------------------------
1945 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1947 wxClientDC::wxClientDC()
1952 wxClientDC::wxClientDC( wxWindow
*win
)
1957 // ----------------------------------------------------------------------------
1959 // ----------------------------------------------------------------------------
1961 class wxDCModule
: public wxModule
1968 DECLARE_DYNAMIC_CLASS(wxDCModule
)
1971 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
1973 bool wxDCModule::OnInit()
1979 void wxDCModule::OnExit()