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
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
31 #define USE_PAINT_REGION 0
33 //-----------------------------------------------------------------------------
35 //-----------------------------------------------------------------------------
45 static GdkPixmap
*hatches
[num_hatches
];
46 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
48 extern GtkWidget
*wxRootWindow
;
50 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
54 const double RAD2DEG
= 180.0 / M_PI
;
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
61 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
63 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
65 //-----------------------------------------------------------------------------
66 // temporary implementation of the missing GDK function
67 //-----------------------------------------------------------------------------
69 #include "gdk/gdkprivate.h"
71 void gdk_draw_bitmap (GdkDrawable
*drawable
,
81 GdkWindowPrivate
*drawable_private
;
82 GdkWindowPrivate
*src_private
;
83 GdkGCPrivate
*gc_private
;
85 g_return_if_fail (drawable
!= NULL
);
86 g_return_if_fail (src
!= NULL
);
87 g_return_if_fail (gc
!= NULL
);
89 drawable_private
= (GdkWindowPrivate
*) drawable
;
90 src_private
= (GdkWindowPrivate
*) src
;
91 if (drawable_private
->destroyed
|| src_private
->destroyed
)
94 gc_private
= (GdkGCPrivate
*) gc
;
96 if (width
== -1) width
= src_private
->width
;
97 if (height
== -1) height
= src_private
->height
;
99 XCopyPlane( drawable_private
->xdisplay
,
100 src_private
->xwindow
,
101 drawable_private
->xwindow
,
109 //-----------------------------------------------------------------------------
110 // Implement Pool of Graphic contexts. Creating them takes too much time.
111 //-----------------------------------------------------------------------------
133 static wxGC wxGCPool
[200];
135 static void wxInitGCPool()
137 memset( wxGCPool
, 0, 200*sizeof(wxGC
) );
140 static void wxCleanUpGCPool()
142 for (int i
= 0; i
< 200; i
++)
144 if (wxGCPool
[i
].m_gc
)
145 gdk_gc_unref( wxGCPool
[i
].m_gc
);
149 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
151 for (int i
= 0; i
< 200; i
++)
153 if (!wxGCPool
[i
].m_gc
)
155 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
156 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
157 wxGCPool
[i
].m_type
= type
;
158 wxGCPool
[i
].m_used
= FALSE
;
160 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
162 wxGCPool
[i
].m_used
= TRUE
;
163 return wxGCPool
[i
].m_gc
;
167 wxFAIL_MSG( wxT("No GC available") );
169 return (GdkGC
*) NULL
;
172 static void wxFreePoolGC( GdkGC
*gc
)
174 for (int i
= 0; i
< 200; i
++)
176 if (wxGCPool
[i
].m_gc
== gc
)
178 wxGCPool
[i
].m_used
= FALSE
;
183 wxFAIL_MSG( wxT("Wrong GC") );
186 //-----------------------------------------------------------------------------
188 //-----------------------------------------------------------------------------
190 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
192 wxWindowDC::wxWindowDC()
194 m_penGC
= (GdkGC
*) NULL
;
195 m_brushGC
= (GdkGC
*) NULL
;
196 m_textGC
= (GdkGC
*) NULL
;
197 m_bgGC
= (GdkGC
*) NULL
;
198 m_cmap
= (GdkColormap
*) NULL
;
200 m_owner
= (wxWindow
*)NULL
;
203 wxWindowDC::wxWindowDC( wxWindow
*window
)
205 m_penGC
= (GdkGC
*) NULL
;
206 m_brushGC
= (GdkGC
*) NULL
;
207 m_textGC
= (GdkGC
*) NULL
;
208 m_bgGC
= (GdkGC
*) NULL
;
209 m_cmap
= (GdkColormap
*) NULL
;
210 m_owner
= (wxWindow
*)NULL
;
212 m_font
= window
->GetFont();
214 wxASSERT_MSG( window
, wxT("DC needs a window") );
216 GtkWidget
*widget
= window
->m_wxwindow
;
218 // some controls don't have m_wxwindow - like wxStaticBox, but the user
219 // code should still be able to create wxClientDCs for them, so we will
220 // use the parent window here then
223 window
= window
->GetParent();
224 widget
= window
->m_wxwindow
;
227 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
229 GtkPizza
*pizza
= GTK_PIZZA( widget
);
230 m_window
= pizza
->bin_window
;
235 /* don't report problems */
241 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
245 /* this must be done after SetUpDC, bacause SetUpDC calls the
246 repective SetBrush, SetPen, SetBackground etc functions
247 to set up the DC. SetBackground call m_owner->SetBackground
248 and this might not be desired as the standard dc background
249 is white whereas a window might assume gray to be the
250 standard (as e.g. wxStatusBar) */
255 wxWindowDC::~wxWindowDC()
260 void wxWindowDC::SetUpDC()
264 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
266 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
268 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
269 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
270 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
271 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
275 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
276 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
277 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
278 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
281 /* background colour */
282 m_backgroundBrush
= *wxWHITE_BRUSH
;
283 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
284 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
287 m_textForegroundColour
.CalcPixel( m_cmap
);
288 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
290 m_textBackgroundColour
.CalcPixel( m_cmap
);
291 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
293 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
296 m_pen
.GetColour().CalcPixel( m_cmap
);
297 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
298 gdk_gc_set_background( m_penGC
, bg_col
);
300 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
304 m_brush
.GetColour().CalcPixel( m_cmap
);
305 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
306 gdk_gc_set_background( m_brushGC
, bg_col
);
308 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
312 gdk_gc_set_background( m_bgGC
, bg_col
);
313 gdk_gc_set_foreground( m_bgGC
, bg_col
);
315 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
318 gdk_gc_set_function( m_textGC
, GDK_COPY
);
319 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
320 gdk_gc_set_function( m_penGC
, GDK_COPY
);
323 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
324 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
325 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
326 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
330 hatch_bitmap
= hatches
;
331 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
332 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
333 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
334 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
335 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
336 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
340 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
341 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
343 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
346 bool wxWindowDC::DoGetPixel( wxCoord x1
, wxCoord y1
, wxColour
*col
) const
348 // Generic (and therefore rather inefficient) method.
349 // Could be improved.
351 wxBitmap
bitmap(1, 1);
352 memdc
.SelectObject(bitmap
);
353 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
354 memdc
.SelectObject(wxNullBitmap
);
355 wxImage
image(bitmap
);
356 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
360 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
362 wxCHECK_RET( Ok(), wxT("invalid window dc") );
364 if (m_pen
.GetStyle() != wxTRANSPARENT
)
367 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
369 CalcBoundingBox(x1
, y1
);
370 CalcBoundingBox(x2
, y2
);
374 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
376 wxCHECK_RET( Ok(), wxT("invalid window dc") );
378 if (m_pen
.GetStyle() != wxTRANSPARENT
)
383 wxCoord xx
= XLOG2DEV(x
);
384 wxCoord yy
= YLOG2DEV(y
);
387 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
388 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
393 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
394 wxCoord xc
, wxCoord yc
)
396 wxCHECK_RET( Ok(), wxT("invalid window dc") );
398 wxCoord xx1
= XLOG2DEV(x1
);
399 wxCoord yy1
= YLOG2DEV(y1
);
400 wxCoord xx2
= XLOG2DEV(x2
);
401 wxCoord yy2
= YLOG2DEV(y2
);
402 wxCoord xxc
= XLOG2DEV(xc
);
403 wxCoord yyc
= YLOG2DEV(yc
);
404 double dx
= xx1
- xxc
;
405 double dy
= yy1
- yyc
;
406 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
407 wxCoord r
= (wxCoord
)radius
;
408 double radius1
, radius2
;
410 if (xx1
== xx2
&& yy1
== yy2
)
418 radius1
= radius2
= 0.0;
422 radius1
= (xx1
- xxc
== 0) ?
423 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
424 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
425 radius2
= (xx2
- xxc
== 0) ?
426 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
427 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
429 wxCoord alpha1
= wxCoord(radius1
* 64.0);
430 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
431 while (alpha2
<= 0) alpha2
+= 360*64;
432 while (alpha1
> 360*64) alpha1
-= 360*64;
436 if (m_brush
.GetStyle() != wxTRANSPARENT
)
437 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
439 if (m_pen
.GetStyle() != wxTRANSPARENT
)
440 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
443 CalcBoundingBox (x1
, y1
);
444 CalcBoundingBox (x2
, y2
);
447 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
449 wxCHECK_RET( Ok(), wxT("invalid window dc") );
451 wxCoord xx
= XLOG2DEV(x
);
452 wxCoord yy
= YLOG2DEV(y
);
453 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
454 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
456 // CMB: handle -ve width and/or height
457 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
458 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
462 wxCoord start
= wxCoord(sa
* 64.0);
463 wxCoord end
= wxCoord(ea
* 64.0);
465 if (m_brush
.GetStyle() != wxTRANSPARENT
)
466 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
468 if (m_pen
.GetStyle() != wxTRANSPARENT
)
469 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
472 CalcBoundingBox (x
, y
);
473 CalcBoundingBox (x
+ width
, y
+ height
);
476 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
478 wxCHECK_RET( Ok(), wxT("invalid window dc") );
480 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
481 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
483 CalcBoundingBox (x
, y
);
486 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
488 wxCHECK_RET( Ok(), wxT("invalid window dc") );
490 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
493 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
495 for (int i
= 0; i
< n
-1; i
++)
497 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
498 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
499 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
500 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
503 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
505 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
509 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
511 wxCHECK_RET( Ok(), wxT("invalid window dc") );
515 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
517 for (i
= 0 ; i
< n
; i
++)
519 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
520 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
522 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
527 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
528 gdk_draw_polygon (m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
531 if ((m_brush
.GetStyle() != wxTRANSPARENT
))
532 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
538 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
540 for (i
= 0 ; i
< n
; i
++)
542 gdk_draw_line( m_window
, m_penGC
,
545 gdkpoints
[(i
+1)%n
].x
,
546 gdkpoints
[(i
+1)%n
].y
);
553 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
555 wxCHECK_RET( Ok(), wxT("invalid window dc") );
557 wxCoord xx
= XLOG2DEV(x
);
558 wxCoord yy
= YLOG2DEV(y
);
559 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
560 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
562 // CMB: draw nothing if transformed w or h is 0
563 if (ww
== 0 || hh
== 0) return;
565 // CMB: handle -ve width and/or height
566 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
567 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
571 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
573 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
574 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
578 if (m_brush
.GetStyle() != wxTRANSPARENT
)
579 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
581 if (m_pen
.GetStyle() != wxTRANSPARENT
)
582 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
586 CalcBoundingBox( x
, y
);
587 CalcBoundingBox( x
+ width
, y
+ height
);
590 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
592 wxCHECK_RET( Ok(), wxT("invalid window dc") );
594 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
596 wxCoord xx
= XLOG2DEV(x
);
597 wxCoord yy
= YLOG2DEV(y
);
598 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
599 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
600 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
602 // CMB: handle -ve width and/or height
603 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
604 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
606 // CMB: if radius is zero use DrawRectangle() instead to avoid
607 // X drawing errors with small radii
610 DrawRectangle( x
, y
, width
, height
);
614 // CMB: draw nothing if transformed w or h is 0
615 if (ww
== 0 || hh
== 0) return;
617 // CMB: adjust size if outline is drawn otherwise the result is
618 // 1 pixel too wide and high
619 if (m_pen
.GetStyle() != wxTRANSPARENT
)
627 // CMB: ensure dd is not larger than rectangle otherwise we
628 // get an hour glass shape
630 if (dd
> ww
) dd
= ww
;
631 if (dd
> hh
) dd
= hh
;
634 if (m_brush
.GetStyle() != wxTRANSPARENT
)
636 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
637 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
638 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
639 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
640 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
641 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
644 if (m_pen
.GetStyle() != wxTRANSPARENT
)
646 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
647 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
648 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
649 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
650 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
651 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
652 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
653 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
657 // this ignores the radius
658 CalcBoundingBox( x
, y
);
659 CalcBoundingBox( x
+ width
, y
+ height
);
662 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
664 wxCHECK_RET( Ok(), wxT("invalid window dc") );
666 wxCoord xx
= XLOG2DEV(x
);
667 wxCoord yy
= YLOG2DEV(y
);
668 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
669 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
671 // CMB: handle -ve width and/or height
672 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
673 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
677 if (m_brush
.GetStyle() != wxTRANSPARENT
)
678 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
680 if (m_pen
.GetStyle() != wxTRANSPARENT
)
681 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
684 CalcBoundingBox( x
- width
, y
- height
);
685 CalcBoundingBox( x
+ width
, y
+ height
);
688 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
690 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
691 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
694 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
695 wxCoord x
, wxCoord y
,
698 wxCHECK_RET( Ok(), wxT("invalid window dc") );
700 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
702 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
704 /* scale/translate size and position */
705 int xx
= XLOG2DEV(x
);
706 int yy
= YLOG2DEV(y
);
708 int w
= bitmap
.GetWidth();
709 int h
= bitmap
.GetHeight();
711 CalcBoundingBox( x
, y
);
712 CalcBoundingBox( x
+ w
, y
+ h
);
714 if (!m_window
) return;
716 int ww
= XLOG2DEVREL(w
);
717 int hh
= YLOG2DEVREL(h
);
719 /* compare to current clipping region */
720 if (!m_currentClippingRegion
.IsEmpty())
722 wxRegion
tmp( xx
,yy
,ww
,hh
);
723 tmp
.Intersect( m_currentClippingRegion
);
728 /* scale bitmap if required */
730 if ((w
!= ww
) || (h
!= hh
))
732 wxImage
image( bitmap
);
733 image
.Rescale( ww
, hh
);
735 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
737 use_bitmap
= image
.ConvertToBitmap();
744 /* apply mask if any */
745 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
746 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
750 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
751 if (!m_currentClippingRegion
.IsEmpty())
754 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
755 GdkGC
*gc
= gdk_gc_new( new_mask
);
757 gdk_gc_set_foreground( gc
, &col
);
758 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
760 gdk_gc_set_background( gc
, &col
);
762 gdk_gc_set_foreground( gc
, &col
);
763 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
764 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
765 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
766 gdk_gc_set_stipple( gc
, mask
);
767 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
769 gdk_gc_set_clip_mask( m_brushGC, NULL );
770 gdk_gc_set_clip_mask( m_textGC, NULL );
771 SetBrush( *wxRED_BRUSH );
772 DrawRectangle( 70, 0, 70, 1000 );
773 gdk_draw_bitmap( m_window, m_textGC, new_mask, 0, 0, 100, 5, ww, hh );
774 gdk_draw_bitmap( m_window, m_textGC, mask, 0, 0, 80, 5, ww, hh );
782 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
784 gdk_gc_set_clip_mask( m_textGC
, mask
);
785 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
790 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
792 gdk_gc_set_clip_mask( m_penGC
, mask
);
793 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
796 gdk_bitmap_unref( new_mask
);
799 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
800 drawing a mono-bitmap (XBitmap) we use the current text GC */
802 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
804 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
806 /* remove mask again if any */
811 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
812 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
813 if (!m_currentClippingRegion
.IsEmpty())
814 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
818 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
819 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
820 if (!m_currentClippingRegion
.IsEmpty())
821 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
826 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
827 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
828 int logical_func
, bool useMask
)
830 /* this is the nth try to get this utterly useless function to
831 work. it now completely ignores the scaling or translation
832 of the source dc, but scales correctly on the target dc and
833 knows about possible mask information in a memory dc. */
835 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
837 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
839 if (!m_window
) return FALSE
;
841 wxClientDC
*srcDC
= (wxClientDC
*)source
;
842 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
844 bool use_bitmap_method
= FALSE
;
845 bool is_mono
= FALSE
;
847 if (srcDC
->m_isMemDC
)
849 if (!memDC
->m_selected
.Ok()) return FALSE
;
851 /* we use the "XCopyArea" way to copy a memory dc into
852 y different window if the memory dc BOTH
853 a) doesn't have any mask or its mask isn't used
857 if (useMask
&& (memDC
->m_selected
.GetMask()))
859 /* we HAVE TO use the direct way for memory dcs
860 that have mask since the XCopyArea doesn't know
862 use_bitmap_method
= TRUE
;
864 else if (memDC
->m_selected
.GetDepth() == 1)
866 /* we HAVE TO use the direct way for memory dcs
867 that are bitmaps because XCopyArea doesn't cope
868 with different bit depths */
870 use_bitmap_method
= TRUE
;
872 else if ((xsrc
== 0) && (ysrc
== 0) &&
873 (width
== memDC
->m_selected
.GetWidth()) &&
874 (height
== memDC
->m_selected
.GetHeight()))
876 /* we SHOULD use the direct way if all of the bitmap
877 in the memory dc is copied in which case XCopyArea
878 wouldn't be able able to boost performace by reducing
879 the area to be scaled */
880 use_bitmap_method
= TRUE
;
884 use_bitmap_method
= FALSE
;
888 CalcBoundingBox( xdest
, ydest
);
889 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
891 /* scale/translate size and position */
892 wxCoord xx
= XLOG2DEV(xdest
);
893 wxCoord yy
= YLOG2DEV(ydest
);
895 wxCoord ww
= XLOG2DEVREL(width
);
896 wxCoord hh
= YLOG2DEVREL(height
);
898 /* compare to current clipping region */
899 if (!m_currentClippingRegion
.IsEmpty())
901 wxRegion
tmp( xx
,yy
,ww
,hh
);
902 tmp
.Intersect( m_currentClippingRegion
);
907 int old_logical_func
= m_logicalFunction
;
908 SetLogicalFunction( logical_func
);
910 if (use_bitmap_method
)
912 /* scale/translate bitmap size */
913 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
914 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
916 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
917 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
919 /* scale bitmap if required */
922 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
924 wxImage
image( memDC
->m_selected
);
925 image
= image
.Scale( bm_ww
, bm_hh
);
928 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
930 use_bitmap
= image
.ConvertToBitmap();
934 use_bitmap
= memDC
->m_selected
;
937 /* apply mask if any */
938 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
939 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
943 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
944 if (!m_currentClippingRegion
.IsEmpty())
947 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
948 GdkGC
*gc
= gdk_gc_new( new_mask
);
950 gdk_gc_set_foreground( gc
, &col
);
951 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
953 gdk_gc_set_background( gc
, &col
);
955 gdk_gc_set_foreground( gc
, &col
);
956 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
957 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
958 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
959 gdk_gc_set_stipple( gc
, mask
);
960 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
967 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
969 gdk_gc_set_clip_mask( m_textGC
, mask
);
970 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
975 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
977 gdk_gc_set_clip_mask( m_penGC
, mask
);
978 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
981 gdk_bitmap_unref( new_mask
);
984 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
985 drawing a mono-bitmap (XBitmap) we use the current text GC */
988 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
990 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
992 /* remove mask again if any */
997 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
998 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
999 if (!m_currentClippingRegion
.IsEmpty())
1000 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1004 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1005 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1006 if (!m_currentClippingRegion
.IsEmpty())
1007 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1011 else /* use_bitmap_method */
1013 if ((width
!= ww
) || (height
!= hh
))
1015 /* draw source window into a bitmap as we cannot scale
1016 a window in contrast to a bitmap. this would actually
1017 work with memory dcs as well, but we'd lose the mask
1018 information and waste one step in this process since
1019 a memory already has a bitmap. all this is slightly
1020 inefficient as we could take an XImage directly from
1021 an X window, but we'd then also have to care that
1022 the window is not outside the screen (in which case
1023 we'd get a BadMatch or what not).
1024 Is a double XGetImage and combined XGetPixel and
1025 XPutPixel really faster? I'm not sure. look at wxXt
1026 for a different implementation of the same problem. */
1028 wxBitmap
bitmap( width
, height
);
1030 /* We have to use the srcDC's GC as it might be a
1031 wxScreenDC and we only have the GDK_INCLUDE_INFERIORS
1034 if (srcDC
->GetWindow() == GDK_ROOT_PARENT())
1035 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1037 gdk_window_copy_area( bitmap
.GetPixmap(), srcDC
->m_penGC
, 0, 0,
1039 xsrc
, ysrc
, width
, height
);
1041 if (srcDC
->GetWindow() == GDK_ROOT_PARENT())
1042 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1046 wxImage
image( bitmap
);
1047 image
= image
.Scale( ww
, hh
);
1049 /* convert to bitmap */
1051 bitmap
= image
.ConvertToBitmap();
1053 /* draw scaled bitmap */
1055 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1060 /* No scaling and not a memory dc with a mask either */
1062 if (srcDC
->GetWindow() == GDK_ROOT_PARENT())
1063 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1065 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1067 xsrc
, ysrc
, width
, height
);
1069 if (srcDC
->GetWindow() == GDK_ROOT_PARENT())
1070 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1074 SetLogicalFunction( old_logical_func
);
1078 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1080 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1082 if (!m_window
) return;
1084 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1086 wxCHECK_RET( font
, wxT("invalid font") );
1091 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1092 if (m_backgroundMode
== wxSOLID
)
1094 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1095 wxCoord height
= font
->ascent
+ font
->descent
;
1096 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1097 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1098 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1100 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1102 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1103 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1104 properties (see wxXt implementation) */
1105 if (m_font
.GetUnderlined())
1107 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1108 wxCoord ul_y
= y
+ font
->ascent
;
1109 if (font
->descent
> 0) ul_y
++;
1110 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1114 GetTextExtent (text
, &w
, &h
);
1115 CalcBoundingBox (x
+ w
, y
+ h
);
1116 CalcBoundingBox (x
, y
);
1119 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1123 DrawText(text
, x
, y
);
1127 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1129 if (!m_window
) return;
1131 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1133 wxCHECK_RET( font
, wxT("invalid font") );
1135 // the size of the text
1136 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1137 wxCoord h
= font
->ascent
+ font
->descent
;
1139 // draw the string normally
1142 dc
.SelectObject(src
);
1143 dc
.SetFont(GetFont());
1144 dc
.SetBackground(*wxWHITE_BRUSH
);
1145 dc
.SetBrush(*wxBLACK_BRUSH
);
1147 dc
.DrawText(text
, 0, 0);
1148 dc
.SetFont(wxNullFont
);
1149 dc
.SelectObject(wxNullBitmap
);
1151 // Calculate the size of the rotated bounding box.
1152 double rad
= DegToRad(angle
);
1153 double dx
= cos(rad
),
1156 // the rectngle vertices are counted clockwise with the first one being at
1157 // (0, 0) (or, rather, at (x, y))
1159 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1162 double x3
= x4
+ x2
,
1166 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1167 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1168 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1169 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1171 // prepare to blit-with-rotate the bitmap to the DC
1174 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1175 *colBack
= m_textBackgroundColour
.GetColor();
1177 bool textColSet
= TRUE
;
1179 unsigned char *data
= image
.GetData();
1181 // paint pixel by pixel
1182 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1184 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1186 // transform source coords to dest coords
1187 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1188 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1189 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1190 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1193 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1194 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1196 // change colour if needed
1197 if ( textPixel
!= textColSet
)
1199 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1202 textColSet
= textPixel
;
1205 // don't use DrawPoint() because it uses the current pen
1206 // colour, and we don't need it here
1207 gdk_draw_point( m_window
, m_textGC
,
1208 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1213 // it would be better to draw with non underlined font and draw the line
1214 // manually here (it would be more straight...)
1216 if ( m_font
.GetUnderlined() )
1218 gdk_draw_line( m_window
, m_textGC
,
1219 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1220 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1224 // restore the font colour
1225 gdk_gc_set_foreground( m_textGC
, colText
);
1227 // update the bounding box
1228 CalcBoundingBox(x
+ minX
, y
+ minY
);
1229 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1232 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1233 wxCoord
*width
, wxCoord
*height
,
1234 wxCoord
*descent
, wxCoord
*externalLeading
,
1235 wxFont
*theFont
) const
1237 wxFont fontToUse
= m_font
;
1238 if (theFont
) fontToUse
= *theFont
;
1240 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1241 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1242 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1243 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1244 if (externalLeading
) (*externalLeading
) = 0; // ??
1247 wxCoord
wxWindowDC::GetCharWidth() const
1249 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1250 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1252 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1255 wxCoord
wxWindowDC::GetCharHeight() const
1257 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1258 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1260 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1263 void wxWindowDC::Clear()
1265 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1267 if (!m_window
) return;
1269 /* - we either are a memory dc or have a window as the
1270 owner. anything else shouldn't happen.
1271 - we don't use gdk_window_clear() as we don't set
1272 the window's background colour anymore. it is too
1273 much pain to keep the DC's and the window's back-
1274 ground colour in synch. */
1279 m_owner
->GetSize( &width
, &height
);
1280 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1287 GetSize( &width
, &height
);
1288 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1293 void wxWindowDC::SetFont( const wxFont
&font
)
1298 void wxWindowDC::SetPen( const wxPen
&pen
)
1300 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1302 if (m_pen
== pen
) return;
1306 if (!m_pen
.Ok()) return;
1308 if (!m_window
) return;
1310 gint width
= m_pen
.GetWidth();
1313 // CMB: if width is non-zero scale it with the dc
1318 // X doesn't allow different width in x and y and so we take
1321 ( fabs((double) XLOG2DEVREL(width
)) +
1322 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1326 static const char dotted
[] = {1, 1};
1327 static const char short_dashed
[] = {2, 2};
1328 static const char wxCoord_dashed
[] = {2, 4};
1329 static const char dotted_dashed
[] = {3, 3, 1, 3};
1331 // We express dash pattern in pen width unit, so we are
1332 // independent of zoom factor and so on...
1334 const char *req_dash
;
1336 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1337 switch (m_pen
.GetStyle())
1341 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1342 req_nb_dash
= m_pen
.GetDashCount();
1343 req_dash
= m_pen
.GetDash();
1348 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1355 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1357 req_dash
= wxCoord_dashed
;
1362 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1364 req_dash
= short_dashed
;
1369 // lineStyle = GDK_LINE_DOUBLE_DASH;
1370 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1372 req_dash
= dotted_dashed
;
1377 case wxSTIPPLE_MASK_OPAQUE
:
1382 lineStyle
= GDK_LINE_SOLID
;
1383 req_dash
= (wxDash
*)NULL
;
1389 #if (GTK_MINOR_VERSION > 0)
1390 if (req_dash
&& req_nb_dash
)
1392 char *real_req_dash
= new char[req_nb_dash
];
1395 for (int i
= 0; i
< req_nb_dash
; i
++)
1396 real_req_dash
[i
] = req_dash
[i
] * width
;
1397 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1398 delete[] real_req_dash
;
1402 // No Memory. We use non-scaled dash pattern...
1403 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1408 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1409 switch (m_pen
.GetCap())
1411 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1412 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1419 capStyle
= GDK_CAP_NOT_LAST
;
1423 capStyle
= GDK_CAP_ROUND
;
1429 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1430 switch (m_pen
.GetJoin())
1432 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1433 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1435 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1438 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1440 m_pen
.GetColour().CalcPixel( m_cmap
);
1441 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1444 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1446 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1448 if (m_brush
== brush
) return;
1452 if (!m_brush
.Ok()) return;
1454 if (!m_window
) return;
1456 m_brush
.GetColour().CalcPixel( m_cmap
);
1457 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1459 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1461 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1463 if (m_brush
.GetStipple()->GetPixmap())
1465 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1466 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1470 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1471 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1475 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1477 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1478 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1481 if (IS_HATCH(m_brush
.GetStyle()))
1483 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1484 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1485 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1489 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1491 /* CMB 21/7/98: Added SetBackground. Sets background brush
1492 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1494 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1496 if (m_backgroundBrush
== brush
) return;
1498 m_backgroundBrush
= brush
;
1500 if (!m_backgroundBrush
.Ok()) return;
1502 if (!m_window
) return;
1504 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1505 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1506 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1507 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1508 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1510 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1512 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1514 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1516 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1517 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1521 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1522 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1526 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1528 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1529 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1530 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1534 void wxWindowDC::SetLogicalFunction( int function
)
1536 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1538 if (m_logicalFunction
== function
)
1541 // VZ: shouldn't this be a CHECK?
1545 GdkFunction mode
= GDK_COPY
;
1548 case wxXOR
: mode
= GDK_XOR
; break;
1549 case wxINVERT
: mode
= GDK_INVERT
; break;
1550 #if (GTK_MINOR_VERSION > 0)
1551 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1552 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1553 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1554 case wxSET
: mode
= GDK_SET
; break;
1555 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1556 case wxAND
: mode
= GDK_AND
; break;
1557 case wxOR
: mode
= GDK_OR
; break;
1558 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1559 case wxNAND
: mode
= GDK_NAND
; break;
1560 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1561 case wxCOPY
: mode
= GDK_COPY
; break;
1562 case wxNO_OP
: mode
= GDK_NOOP
; break;
1563 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1565 // unsupported by GTK
1566 case wxNOR
: mode
= GDK_COPY
; break;
1570 wxFAIL_MSG( wxT("unsupported logical function") );
1575 m_logicalFunction
= function
;
1577 gdk_gc_set_function( m_penGC
, mode
);
1578 gdk_gc_set_function( m_brushGC
, mode
);
1580 // to stay compatible with wxMSW, we don't apply ROPs to the text
1581 // operations (i.e. DrawText/DrawRotatedText).
1582 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1583 gdk_gc_set_function( m_textGC
, mode
);
1586 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1588 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1590 if (m_textForegroundColour
== col
) return;
1592 m_textForegroundColour
= col
;
1593 if (!m_textForegroundColour
.Ok()) return;
1595 if (!m_window
) return;
1597 m_textForegroundColour
.CalcPixel( m_cmap
);
1598 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1601 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1603 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1605 if (m_textBackgroundColour
== col
) return;
1607 m_textBackgroundColour
= col
;
1608 if (!m_textBackgroundColour
.Ok()) return;
1610 if (!m_window
) return;
1612 m_textBackgroundColour
.CalcPixel( m_cmap
);
1613 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1616 void wxWindowDC::SetBackgroundMode( int mode
)
1618 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1620 m_backgroundMode
= mode
;
1622 if (!m_window
) return;
1624 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1625 // transparent/solid background mode
1627 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1629 gdk_gc_set_fill( m_brushGC
,
1630 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1634 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1636 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1639 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1641 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1643 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1645 if (!m_window
) return;
1648 rect
.x
= XLOG2DEV(x
);
1649 rect
.y
= YLOG2DEV(y
);
1650 rect
.width
= XLOG2DEVREL(width
);
1651 rect
.height
= YLOG2DEVREL(height
);
1653 if (!m_currentClippingRegion
.IsEmpty())
1654 m_currentClippingRegion
.Intersect( rect
);
1656 m_currentClippingRegion
.Union( rect
);
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::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1671 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1675 DestroyClippingRegion();
1680 region
.GetBox( x
, y
, w
, h
);
1682 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
1684 if (!m_window
) return;
1686 if (!m_currentClippingRegion
.IsEmpty())
1687 m_currentClippingRegion
.Intersect( region
);
1689 m_currentClippingRegion
.Union( region
);
1691 #if USE_PAINT_REGION
1692 if (!m_paintClippingRegion
.IsEmpty())
1693 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1696 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1697 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1698 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1699 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1702 void wxWindowDC::DestroyClippingRegion()
1704 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1706 wxDC::DestroyClippingRegion();
1708 m_currentClippingRegion
.Clear();
1710 #if USE_PAINT_REGION
1711 if (!m_paintClippingRegion
.IsEmpty())
1712 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1715 if (!m_window
) return;
1717 if (m_currentClippingRegion
.IsEmpty())
1719 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1720 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1721 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1722 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1726 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1727 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1728 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1729 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1733 void wxWindowDC::Destroy()
1735 if (m_penGC
) wxFreePoolGC( m_penGC
);
1736 m_penGC
= (GdkGC
*) NULL
;
1737 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1738 m_brushGC
= (GdkGC
*) NULL
;
1739 if (m_textGC
) wxFreePoolGC( m_textGC
);
1740 m_textGC
= (GdkGC
*) NULL
;
1741 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1742 m_bgGC
= (GdkGC
*) NULL
;
1745 void wxWindowDC::ComputeScaleAndOrigin()
1747 /* CMB: copy scale to see if it changes */
1748 double origScaleX
= m_scaleX
;
1749 double origScaleY
= m_scaleY
;
1751 wxDC::ComputeScaleAndOrigin();
1753 /* CMB: if scale has changed call SetPen to recalulate the line width */
1754 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1757 /* this is a bit artificial, but we need to force wxDC to think
1758 the pen has changed */
1765 // Resolution in pixels per logical inch
1766 wxSize
wxWindowDC::GetPPI() const
1768 return wxSize(100, 100);
1771 int wxWindowDC::GetDepth() const
1773 wxFAIL_MSG(wxT("not implemented"));
1779 // ----------------------------------- spline code ----------------------------------------
1781 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1782 double a3
, double b3
, double a4
, double b4
);
1783 void wx_clear_stack();
1784 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1785 double *y3
, double *x4
, double *y4
);
1786 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1787 double x4
, double y4
);
1788 static bool wx_spline_add_point(double x
, double y
);
1789 static void wx_spline_draw_point_array(wxDC
*dc
);
1791 wxList wx_spline_point_list
;
1793 #define half(z1, z2) ((z1+z2)/2.0)
1796 /* iterative version */
1798 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1801 register double xmid
, ymid
;
1802 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1805 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1807 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1808 xmid
= (double)half(x2
, x3
);
1809 ymid
= (double)half(y2
, y3
);
1810 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1811 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1812 wx_spline_add_point( x1
, y1
);
1813 wx_spline_add_point( xmid
, ymid
);
1815 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1816 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1817 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1818 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1823 /* utilities used by spline drawing routines */
1825 typedef struct wx_spline_stack_struct
{
1826 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1829 #define SPLINE_STACK_DEPTH 20
1830 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1831 static Stack
*wx_stack_top
;
1832 static int wx_stack_count
;
1834 void wx_clear_stack()
1836 wx_stack_top
= wx_spline_stack
;
1840 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1842 wx_stack_top
->x1
= x1
;
1843 wx_stack_top
->y1
= y1
;
1844 wx_stack_top
->x2
= x2
;
1845 wx_stack_top
->y2
= y2
;
1846 wx_stack_top
->x3
= x3
;
1847 wx_stack_top
->y3
= y3
;
1848 wx_stack_top
->x4
= x4
;
1849 wx_stack_top
->y4
= y4
;
1854 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1855 double *x3
, double *y3
, double *x4
, double *y4
)
1857 if (wx_stack_count
== 0)
1861 *x1
= wx_stack_top
->x1
;
1862 *y1
= wx_stack_top
->y1
;
1863 *x2
= wx_stack_top
->x2
;
1864 *y2
= wx_stack_top
->y2
;
1865 *x3
= wx_stack_top
->x3
;
1866 *y3
= wx_stack_top
->y3
;
1867 *x4
= wx_stack_top
->x4
;
1868 *y4
= wx_stack_top
->y4
;
1872 static bool wx_spline_add_point(double x
, double y
)
1874 wxPoint
*point
= new wxPoint
;
1877 wx_spline_point_list
.Append((wxObject
*)point
);
1881 static void wx_spline_draw_point_array(wxDC
*dc
)
1883 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1884 wxNode
*node
= wx_spline_point_list
.First();
1887 wxPoint
*point
= (wxPoint
*)node
->Data();
1890 node
= wx_spline_point_list
.First();
1894 void wxWindowDC::DoDrawSpline( wxList
*points
)
1896 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1899 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1900 double x1
, y1
, x2
, y2
;
1902 wxNode
*node
= points
->First();
1903 p
= (wxPoint
*)node
->Data();
1908 node
= node
->Next();
1909 p
= (wxPoint
*)node
->Data();
1913 cx1
= (double)((x1
+ x2
) / 2);
1914 cy1
= (double)((y1
+ y2
) / 2);
1915 cx2
= (double)((cx1
+ x2
) / 2);
1916 cy2
= (double)((cy1
+ y2
) / 2);
1918 wx_spline_add_point(x1
, y1
);
1920 while ((node
= node
->Next()) != NULL
)
1922 p
= (wxPoint
*)node
->Data();
1927 cx4
= (double)(x1
+ x2
) / 2;
1928 cy4
= (double)(y1
+ y2
) / 2;
1929 cx3
= (double)(x1
+ cx4
) / 2;
1930 cy3
= (double)(y1
+ cy4
) / 2;
1932 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1936 cx2
= (double)(cx1
+ x2
) / 2;
1937 cy2
= (double)(cy1
+ y2
) / 2;
1940 wx_spline_add_point( cx1
, cy1
);
1941 wx_spline_add_point( x2
, y2
);
1943 wx_spline_draw_point_array( this );
1946 #endif // wxUSE_SPLINE
1948 //-----------------------------------------------------------------------------
1950 //-----------------------------------------------------------------------------
1952 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1954 wxPaintDC::wxPaintDC()
1959 wxPaintDC::wxPaintDC( wxWindow
*win
)
1962 #if USE_PAINT_REGION
1963 if (!win
->GetUpdateRegion().IsEmpty())
1965 m_paintClippingRegion
= win
->GetUpdateRegion();
1966 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1968 gdk_gc_set_clip_region( m_penGC
, m_paintClippingRegion
.GetRegion() );
1969 gdk_gc_set_clip_region( m_brushGC
, m_paintClippingRegion
.GetRegion() );
1970 gdk_gc_set_clip_region( m_textGC
, m_paintClippingRegion
.GetRegion() );
1971 gdk_gc_set_clip_region( m_bgGC
, m_paintClippingRegion
.GetRegion() );
1976 //-----------------------------------------------------------------------------
1978 //-----------------------------------------------------------------------------
1980 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1982 wxClientDC::wxClientDC()
1987 wxClientDC::wxClientDC( wxWindow
*win
)
1992 // ----------------------------------------------------------------------------
1994 // ----------------------------------------------------------------------------
1996 class wxDCModule
: public wxModule
2003 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2006 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2008 bool wxDCModule::OnInit()
2014 void wxDCModule::OnExit()