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 x1
, wxCoord y1
, wxColour
*col
) const
347 // Generic (and therefore rather inefficient) method.
348 // Could be improved.
350 wxBitmap
bitmap(1, 1);
351 memdc
.SelectObject(bitmap
);
352 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
353 memdc
.SelectObject(wxNullBitmap
);
354 wxImage
image(bitmap
);
355 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
359 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
361 wxCHECK_RET( Ok(), wxT("invalid window dc") );
363 if (m_pen
.GetStyle() != wxTRANSPARENT
)
366 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
368 CalcBoundingBox(x1
, y1
);
369 CalcBoundingBox(x2
, y2
);
373 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
375 wxCHECK_RET( Ok(), wxT("invalid window dc") );
377 if (m_pen
.GetStyle() != wxTRANSPARENT
)
382 wxCoord xx
= XLOG2DEV(x
);
383 wxCoord yy
= YLOG2DEV(y
);
386 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
387 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
392 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
393 wxCoord xc
, wxCoord yc
)
395 wxCHECK_RET( Ok(), wxT("invalid window dc") );
397 wxCoord xx1
= XLOG2DEV(x1
);
398 wxCoord yy1
= YLOG2DEV(y1
);
399 wxCoord xx2
= XLOG2DEV(x2
);
400 wxCoord yy2
= YLOG2DEV(y2
);
401 wxCoord xxc
= XLOG2DEV(xc
);
402 wxCoord yyc
= YLOG2DEV(yc
);
403 double dx
= xx1
- xxc
;
404 double dy
= yy1
- yyc
;
405 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
406 wxCoord r
= (wxCoord
)radius
;
407 double radius1
, radius2
;
409 if (xx1
== xx2
&& yy1
== yy2
)
417 radius1
= radius2
= 0.0;
421 radius1
= (xx1
- xxc
== 0) ?
422 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
423 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
424 radius2
= (xx2
- xxc
== 0) ?
425 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
426 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
428 wxCoord alpha1
= wxCoord(radius1
* 64.0);
429 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
430 while (alpha2
<= 0) alpha2
+= 360*64;
431 while (alpha1
> 360*64) alpha1
-= 360*64;
435 if (m_brush
.GetStyle() != wxTRANSPARENT
)
436 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
438 if (m_pen
.GetStyle() != wxTRANSPARENT
)
439 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
442 CalcBoundingBox (x1
, y1
);
443 CalcBoundingBox (x2
, y2
);
446 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
448 wxCHECK_RET( Ok(), wxT("invalid window dc") );
450 wxCoord xx
= XLOG2DEV(x
);
451 wxCoord yy
= YLOG2DEV(y
);
452 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
453 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
455 // CMB: handle -ve width and/or height
456 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
457 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
461 wxCoord start
= wxCoord(sa
* 64.0);
462 wxCoord end
= wxCoord(ea
* 64.0);
464 if (m_brush
.GetStyle() != wxTRANSPARENT
)
465 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
467 if (m_pen
.GetStyle() != wxTRANSPARENT
)
468 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
471 CalcBoundingBox (x
, y
);
472 CalcBoundingBox (x
+ width
, y
+ height
);
475 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
477 wxCHECK_RET( Ok(), wxT("invalid window dc") );
479 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
480 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
482 CalcBoundingBox (x
, y
);
485 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
487 wxCHECK_RET( Ok(), wxT("invalid window dc") );
489 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
492 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
494 for (int i
= 0; i
< n
-1; i
++)
496 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
497 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
498 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
499 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
502 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
504 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
508 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
510 wxCHECK_RET( Ok(), wxT("invalid window dc") );
514 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
516 for (i
= 0 ; i
< n
; i
++)
518 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
519 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
521 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
526 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
527 gdk_draw_polygon (m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
530 if ((m_brush
.GetStyle() != wxTRANSPARENT
))
531 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
537 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
539 for (i
= 0 ; i
< n
; i
++)
541 gdk_draw_line( m_window
, m_penGC
,
544 gdkpoints
[(i
+1)%n
].x
,
545 gdkpoints
[(i
+1)%n
].y
);
552 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
554 wxCHECK_RET( Ok(), wxT("invalid window dc") );
556 wxCoord xx
= XLOG2DEV(x
);
557 wxCoord yy
= YLOG2DEV(y
);
558 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
559 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
561 // CMB: draw nothing if transformed w or h is 0
562 if (ww
== 0 || hh
== 0) return;
564 // CMB: handle -ve width and/or height
565 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
566 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
570 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
572 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
573 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
577 if (m_brush
.GetStyle() != wxTRANSPARENT
)
578 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
580 if (m_pen
.GetStyle() != wxTRANSPARENT
)
581 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
585 CalcBoundingBox( x
, y
);
586 CalcBoundingBox( x
+ width
, y
+ height
);
589 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
591 wxCHECK_RET( Ok(), wxT("invalid window dc") );
593 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
595 wxCoord xx
= XLOG2DEV(x
);
596 wxCoord yy
= YLOG2DEV(y
);
597 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
598 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
599 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
601 // CMB: handle -ve width and/or height
602 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
603 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
605 // CMB: if radius is zero use DrawRectangle() instead to avoid
606 // X drawing errors with small radii
609 DrawRectangle( x
, y
, width
, height
);
613 // CMB: draw nothing if transformed w or h is 0
614 if (ww
== 0 || hh
== 0) return;
616 // CMB: adjust size if outline is drawn otherwise the result is
617 // 1 pixel too wide and high
618 if (m_pen
.GetStyle() != wxTRANSPARENT
)
626 // CMB: ensure dd is not larger than rectangle otherwise we
627 // get an hour glass shape
629 if (dd
> ww
) dd
= ww
;
630 if (dd
> hh
) dd
= hh
;
633 if (m_brush
.GetStyle() != wxTRANSPARENT
)
635 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
636 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
637 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
638 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
639 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
640 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
643 if (m_pen
.GetStyle() != wxTRANSPARENT
)
645 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
646 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
647 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
648 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
649 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
650 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
651 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
652 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
656 // this ignores the radius
657 CalcBoundingBox( x
, y
);
658 CalcBoundingBox( x
+ width
, y
+ height
);
661 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
663 wxCHECK_RET( Ok(), wxT("invalid window dc") );
665 wxCoord xx
= XLOG2DEV(x
);
666 wxCoord yy
= YLOG2DEV(y
);
667 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
668 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
670 // CMB: handle -ve width and/or height
671 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
672 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
676 if (m_brush
.GetStyle() != wxTRANSPARENT
)
677 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
679 if (m_pen
.GetStyle() != wxTRANSPARENT
)
680 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
683 CalcBoundingBox( x
- width
, y
- height
);
684 CalcBoundingBox( x
+ width
, y
+ height
);
687 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
689 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
690 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
693 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
694 wxCoord x
, wxCoord y
,
697 wxCHECK_RET( Ok(), wxT("invalid window dc") );
699 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
701 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
703 /* scale/translate size and position */
704 int xx
= XLOG2DEV(x
);
705 int yy
= YLOG2DEV(y
);
707 int w
= bitmap
.GetWidth();
708 int h
= bitmap
.GetHeight();
710 CalcBoundingBox( x
, y
);
711 CalcBoundingBox( x
+ w
, y
+ h
);
713 if (!m_window
) return;
715 int ww
= XLOG2DEVREL(w
);
716 int hh
= YLOG2DEVREL(h
);
718 /* compare to current clipping region */
719 if (!m_currentClippingRegion
.IsEmpty())
721 wxRegion
tmp( xx
,yy
,ww
,hh
);
722 tmp
.Intersect( m_currentClippingRegion
);
727 /* scale bitmap if required */
729 if ((w
!= ww
) || (h
!= hh
))
731 wxImage
image( bitmap
);
732 image
.Rescale( ww
, hh
);
734 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
736 use_bitmap
= image
.ConvertToBitmap();
743 /* apply mask if any */
744 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
745 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
749 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
750 if (!m_currentClippingRegion
.IsEmpty())
753 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
754 GdkGC
*gc
= gdk_gc_new( new_mask
);
756 gdk_gc_set_foreground( gc
, &col
);
757 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
759 gdk_gc_set_background( gc
, &col
);
761 gdk_gc_set_foreground( gc
, &col
);
762 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
763 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
764 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
765 gdk_gc_set_stipple( gc
, mask
);
766 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
768 gdk_gc_set_clip_mask( m_brushGC, NULL );
769 gdk_gc_set_clip_mask( m_textGC, NULL );
770 SetBrush( *wxRED_BRUSH );
771 DrawRectangle( 70, 0, 70, 1000 );
772 gdk_draw_bitmap( m_window, m_textGC, new_mask, 0, 0, 100, 5, ww, hh );
773 gdk_draw_bitmap( m_window, m_textGC, mask, 0, 0, 80, 5, ww, hh );
781 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
783 gdk_gc_set_clip_mask( m_textGC
, mask
);
784 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
789 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
791 gdk_gc_set_clip_mask( m_penGC
, mask
);
792 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
795 gdk_bitmap_unref( new_mask
);
798 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
799 drawing a mono-bitmap (XBitmap) we use the current text GC */
801 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
803 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
805 /* remove mask again if any */
810 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
811 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
812 if (!m_currentClippingRegion
.IsEmpty())
813 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
817 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
818 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
819 if (!m_currentClippingRegion
.IsEmpty())
820 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
825 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
826 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
827 int logical_func
, bool useMask
)
829 /* this is the nth try to get this utterly useless function to
830 work. it now completely ignores the scaling or translation
831 of the source dc, but scales correctly on the target dc and
832 knows about possible mask information in a memory dc. */
834 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
836 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
838 if (!m_window
) return FALSE
;
840 wxClientDC
*srcDC
= (wxClientDC
*)source
;
841 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
843 bool use_bitmap_method
= FALSE
;
844 bool is_mono
= FALSE
;
846 if (srcDC
->m_isMemDC
)
848 if (!memDC
->m_selected
.Ok()) return FALSE
;
850 /* we use the "XCopyArea" way to copy a memory dc into
851 y different window if the memory dc BOTH
852 a) doesn't have any mask or its mask isn't used
856 if (useMask
&& (memDC
->m_selected
.GetMask()))
858 /* we HAVE TO use the direct way for memory dcs
859 that have mask since the XCopyArea doesn't know
861 use_bitmap_method
= TRUE
;
863 else if (memDC
->m_selected
.GetDepth() == 1)
865 /* we HAVE TO use the direct way for memory dcs
866 that are bitmaps because XCopyArea doesn't cope
867 with different bit depths */
869 use_bitmap_method
= TRUE
;
871 else if ((xsrc
== 0) && (ysrc
== 0) &&
872 (width
== memDC
->m_selected
.GetWidth()) &&
873 (height
== memDC
->m_selected
.GetHeight()))
875 /* we SHOULD use the direct way if all of the bitmap
876 in the memory dc is copied in which case XCopyArea
877 wouldn't be able able to boost performace by reducing
878 the area to be scaled */
879 use_bitmap_method
= TRUE
;
883 use_bitmap_method
= FALSE
;
887 CalcBoundingBox( xdest
, ydest
);
888 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
890 /* scale/translate size and position */
891 wxCoord xx
= XLOG2DEV(xdest
);
892 wxCoord yy
= YLOG2DEV(ydest
);
894 wxCoord ww
= XLOG2DEVREL(width
);
895 wxCoord hh
= YLOG2DEVREL(height
);
897 /* compare to current clipping region */
898 if (!m_currentClippingRegion
.IsEmpty())
900 wxRegion
tmp( xx
,yy
,ww
,hh
);
901 tmp
.Intersect( m_currentClippingRegion
);
906 int old_logical_func
= m_logicalFunction
;
907 SetLogicalFunction( logical_func
);
909 if (use_bitmap_method
)
911 /* scale/translate bitmap size */
912 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
913 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
915 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
916 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
918 /* scale bitmap if required */
921 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
923 wxImage
image( memDC
->m_selected
);
924 image
= image
.Scale( bm_ww
, bm_hh
);
927 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
929 use_bitmap
= image
.ConvertToBitmap();
933 use_bitmap
= memDC
->m_selected
;
936 /* apply mask if any */
937 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
938 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
942 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
943 if (!m_currentClippingRegion
.IsEmpty())
946 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
947 GdkGC
*gc
= gdk_gc_new( new_mask
);
949 gdk_gc_set_foreground( gc
, &col
);
950 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
952 gdk_gc_set_background( gc
, &col
);
954 gdk_gc_set_foreground( gc
, &col
);
955 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
956 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
957 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
958 gdk_gc_set_stipple( gc
, mask
);
959 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
966 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
968 gdk_gc_set_clip_mask( m_textGC
, mask
);
969 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
974 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
976 gdk_gc_set_clip_mask( m_penGC
, mask
);
977 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
980 gdk_bitmap_unref( new_mask
);
983 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
984 drawing a mono-bitmap (XBitmap) we use the current text GC */
986 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
988 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
990 /* remove mask again if any */
995 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
996 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
997 if (!m_currentClippingRegion
.IsEmpty())
998 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1002 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1003 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1004 if (!m_currentClippingRegion
.IsEmpty())
1005 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1009 else /* use_bitmap_method */
1011 if ((width
!= ww
) || (height
!= hh
))
1013 /* draw source window into a bitmap as we cannot scale
1014 a window in contrast to a bitmap. this would actually
1015 work with memory dcs as well, but we'd lose the mask
1016 information and waste one step in this process since
1017 a memory already has a bitmap. all this is slightly
1018 inefficient as we could take an XImage directly from
1019 an X window, but we'd then also have to care that
1020 the window is not outside the screen (in which case
1021 we'd get a BadMatch or what not).
1022 Is a double XGetImage and combined XGetPixel and
1023 XPutPixel really faster? I'm not sure. look at wxXt
1024 for a different implementation of the same problem. */
1026 wxBitmap
bitmap( width
, height
);
1027 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1029 xsrc
, ysrc
, width
, height
);
1033 wxImage
image( bitmap
);
1034 image
= image
.Scale( ww
, hh
);
1036 /* convert to bitmap */
1038 bitmap
= image
.ConvertToBitmap();
1040 /* draw scaled bitmap */
1042 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1047 /* no scaling and not a memory dc with a mask either */
1049 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1051 xsrc
, ysrc
, width
, height
);
1055 SetLogicalFunction( old_logical_func
);
1059 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1061 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1063 if (!m_window
) return;
1065 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1067 wxCHECK_RET( font
, wxT("invalid font") );
1072 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1073 if (m_backgroundMode
== wxSOLID
)
1075 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1076 wxCoord height
= font
->ascent
+ font
->descent
;
1077 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1078 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1079 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1081 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1083 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1084 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1085 properties (see wxXt implementation) */
1086 if (m_font
.GetUnderlined())
1088 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1089 wxCoord ul_y
= y
+ font
->ascent
;
1090 if (font
->descent
> 0) ul_y
++;
1091 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1095 GetTextExtent (text
, &w
, &h
);
1096 CalcBoundingBox (x
+ w
, y
+ h
);
1097 CalcBoundingBox (x
, y
);
1100 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1104 DrawText(text
, x
, y
);
1108 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1110 if (!m_window
) return;
1112 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1114 wxCHECK_RET( font
, wxT("invalid font") );
1116 // the size of the text
1117 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1118 wxCoord h
= font
->ascent
+ font
->descent
;
1120 // draw the string normally
1123 dc
.SelectObject(src
);
1124 dc
.SetFont(GetFont());
1125 dc
.SetBackground(*wxWHITE_BRUSH
);
1126 dc
.SetBrush(*wxBLACK_BRUSH
);
1128 dc
.DrawText(text
, 0, 0);
1129 dc
.SetFont(wxNullFont
);
1130 dc
.SelectObject(wxNullBitmap
);
1132 // Calculate the size of the rotated bounding box.
1133 double rad
= DegToRad(angle
);
1134 double dx
= cos(rad
),
1137 // the rectngle vertices are counted clockwise with the first one being at
1138 // (0, 0) (or, rather, at (x, y))
1140 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1143 double x3
= x4
+ x2
,
1147 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1148 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1149 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1150 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1152 // prepare to blit-with-rotate the bitmap to the DC
1155 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1156 *colBack
= m_textBackgroundColour
.GetColor();
1158 bool textColSet
= TRUE
;
1160 unsigned char *data
= image
.GetData();
1162 // paint pixel by pixel
1163 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1165 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1167 // transform source coords to dest coords
1168 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1169 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1170 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1171 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1174 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1175 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1177 // change colour if needed
1178 if ( textPixel
!= textColSet
)
1180 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1183 textColSet
= textPixel
;
1186 // don't use DrawPoint() because it uses the current pen
1187 // colour, and we don't need it here
1188 gdk_draw_point( m_window
, m_textGC
,
1189 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1194 // it would be better to draw with non underlined font and draw the line
1195 // manually here (it would be more straight...)
1197 if ( m_font
.GetUnderlined() )
1199 gdk_draw_line( m_window
, m_textGC
,
1200 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1201 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1205 // restore the font colour
1206 gdk_gc_set_foreground( m_textGC
, colText
);
1208 // update the bounding box
1209 CalcBoundingBox(x
+ minX
, y
+ minY
);
1210 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1213 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1214 wxCoord
*width
, wxCoord
*height
,
1215 wxCoord
*descent
, wxCoord
*externalLeading
,
1216 wxFont
*theFont
) const
1218 wxFont fontToUse
= m_font
;
1219 if (theFont
) fontToUse
= *theFont
;
1221 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1222 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1223 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1224 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1225 if (externalLeading
) (*externalLeading
) = 0; // ??
1228 wxCoord
wxWindowDC::GetCharWidth() const
1230 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1231 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1233 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1236 wxCoord
wxWindowDC::GetCharHeight() const
1238 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1239 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1241 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1244 void wxWindowDC::Clear()
1246 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1248 if (!m_window
) return;
1250 /* - we either are a memory dc or have a window as the
1251 owner. anything else shouldn't happen.
1252 - we don't use gdk_window_clear() as we don't set
1253 the window's background colour anymore. it is too
1254 much pain to keep the DC's and the window's back-
1255 ground colour in synch. */
1260 m_owner
->GetSize( &width
, &height
);
1261 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1268 GetSize( &width
, &height
);
1269 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1274 void wxWindowDC::SetFont( const wxFont
&font
)
1279 void wxWindowDC::SetPen( const wxPen
&pen
)
1281 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1283 if (m_pen
== pen
) return;
1287 if (!m_pen
.Ok()) return;
1289 if (!m_window
) return;
1291 gint width
= m_pen
.GetWidth();
1294 // CMB: if width is non-zero scale it with the dc
1299 // X doesn't allow different width in x and y and so we take
1302 ( fabs((double) XLOG2DEVREL(width
)) +
1303 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1307 static const char dotted
[] = {1, 1};
1308 static const char short_dashed
[] = {2, 2};
1309 static const char wxCoord_dashed
[] = {2, 4};
1310 static const char dotted_dashed
[] = {3, 3, 1, 3};
1312 // We express dash pattern in pen width unit, so we are
1313 // independent of zoom factor and so on...
1315 const char *req_dash
;
1317 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1318 switch (m_pen
.GetStyle())
1322 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1323 req_nb_dash
= m_pen
.GetDashCount();
1324 req_dash
= m_pen
.GetDash();
1329 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1336 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1338 req_dash
= wxCoord_dashed
;
1343 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1345 req_dash
= short_dashed
;
1350 // lineStyle = GDK_LINE_DOUBLE_DASH;
1351 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1353 req_dash
= dotted_dashed
;
1358 case wxSTIPPLE_MASK_OPAQUE
:
1363 lineStyle
= GDK_LINE_SOLID
;
1364 req_dash
= (wxDash
*)NULL
;
1370 #if (GTK_MINOR_VERSION > 0)
1371 if (req_dash
&& req_nb_dash
)
1373 char *real_req_dash
= new char[req_nb_dash
];
1376 for (int i
= 0; i
< req_nb_dash
; i
++)
1377 real_req_dash
[i
] = req_dash
[i
] * width
;
1378 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1379 delete[] real_req_dash
;
1383 // No Memory. We use non-scaled dash pattern...
1384 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1389 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1390 switch (m_pen
.GetCap())
1392 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1393 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1400 capStyle
= GDK_CAP_NOT_LAST
;
1404 capStyle
= GDK_CAP_ROUND
;
1410 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1411 switch (m_pen
.GetJoin())
1413 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1414 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1416 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1419 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1421 m_pen
.GetColour().CalcPixel( m_cmap
);
1422 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1425 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1427 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1429 if (m_brush
== brush
) return;
1433 if (!m_brush
.Ok()) return;
1435 if (!m_window
) return;
1437 m_brush
.GetColour().CalcPixel( m_cmap
);
1438 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1440 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1442 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1444 if (m_brush
.GetStipple()->GetPixmap())
1446 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1447 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1451 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1452 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1456 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1458 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1459 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1462 if (IS_HATCH(m_brush
.GetStyle()))
1464 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1465 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1466 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1470 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1472 /* CMB 21/7/98: Added SetBackground. Sets background brush
1473 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1475 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1477 if (m_backgroundBrush
== brush
) return;
1479 m_backgroundBrush
= brush
;
1481 if (!m_backgroundBrush
.Ok()) return;
1483 if (!m_window
) return;
1485 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1486 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1487 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1488 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1489 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1491 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1493 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1495 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1497 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1498 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1502 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1503 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1507 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1509 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1510 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1511 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1515 void wxWindowDC::SetLogicalFunction( int function
)
1517 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1519 if (m_logicalFunction
== function
)
1522 // VZ: shouldn't this be a CHECK?
1526 GdkFunction mode
= GDK_COPY
;
1529 case wxXOR
: mode
= GDK_XOR
; break;
1530 case wxINVERT
: mode
= GDK_INVERT
; break;
1531 #if (GTK_MINOR_VERSION > 0)
1532 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1533 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1534 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1535 case wxSET
: mode
= GDK_SET
; break;
1536 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1537 case wxAND
: mode
= GDK_AND
; break;
1538 case wxOR
: mode
= GDK_OR
; break;
1539 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1540 case wxNAND
: mode
= GDK_NAND
; break;
1541 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1542 case wxCOPY
: mode
= GDK_COPY
; break;
1543 case wxNO_OP
: mode
= GDK_NOOP
; break;
1544 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1546 // unsupported by GTK
1547 case wxNOR
: mode
= GDK_COPY
; break;
1551 wxFAIL_MSG( wxT("unsupported logical function") );
1556 m_logicalFunction
= function
;
1558 gdk_gc_set_function( m_penGC
, mode
);
1559 gdk_gc_set_function( m_brushGC
, mode
);
1561 // to stay compatible with wxMSW, we don't apply ROPs to the text
1562 // operations (i.e. DrawText/DrawRotatedText).
1563 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1564 gdk_gc_set_function( m_textGC
, mode
);
1567 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1569 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1571 if (m_textForegroundColour
== col
) return;
1573 m_textForegroundColour
= col
;
1574 if (!m_textForegroundColour
.Ok()) return;
1576 if (!m_window
) return;
1578 m_textForegroundColour
.CalcPixel( m_cmap
);
1579 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1582 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1584 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1586 if (m_textBackgroundColour
== col
) return;
1588 m_textBackgroundColour
= col
;
1589 if (!m_textBackgroundColour
.Ok()) return;
1591 if (!m_window
) return;
1593 m_textBackgroundColour
.CalcPixel( m_cmap
);
1594 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1597 void wxWindowDC::SetBackgroundMode( int mode
)
1599 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1601 m_backgroundMode
= mode
;
1603 if (!m_window
) return;
1605 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1606 // transparent/solid background mode
1608 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1610 gdk_gc_set_fill( m_brushGC
,
1611 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1615 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1617 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1620 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1622 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1624 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1626 if (!m_window
) return;
1629 rect
.x
= XLOG2DEV(x
);
1630 rect
.y
= YLOG2DEV(y
);
1631 rect
.width
= XLOG2DEVREL(width
);
1632 rect
.height
= YLOG2DEVREL(height
);
1634 m_currentClippingRegion
.Clear();
1635 m_currentClippingRegion
.Union( rect
);
1636 #if USE_PAINT_REGION
1637 if (!m_paintClippingRegion
.IsEmpty())
1638 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1641 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1642 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1643 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1644 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1647 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1649 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1653 DestroyClippingRegion();
1658 region
.GetBox( x
, y
, w
, h
);
1660 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
1662 if (!m_window
) return;
1664 m_currentClippingRegion
.Clear();
1665 m_currentClippingRegion
.Union( region
);
1666 #if USE_PAINT_REGION
1667 if (!m_paintClippingRegion
.IsEmpty())
1668 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1671 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1672 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1673 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1674 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1677 void wxWindowDC::DestroyClippingRegion()
1679 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1681 wxDC::DestroyClippingRegion();
1683 m_currentClippingRegion
.Clear();
1685 if (!m_paintClippingRegion
.IsEmpty())
1686 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1688 if (!m_window
) return;
1690 if (m_currentClippingRegion
.IsEmpty())
1692 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1693 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1694 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1695 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1699 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1700 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1701 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1702 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1706 void wxWindowDC::Destroy()
1708 if (m_penGC
) wxFreePoolGC( m_penGC
);
1709 m_penGC
= (GdkGC
*) NULL
;
1710 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1711 m_brushGC
= (GdkGC
*) NULL
;
1712 if (m_textGC
) wxFreePoolGC( m_textGC
);
1713 m_textGC
= (GdkGC
*) NULL
;
1714 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1715 m_bgGC
= (GdkGC
*) NULL
;
1718 void wxWindowDC::ComputeScaleAndOrigin()
1720 /* CMB: copy scale to see if it changes */
1721 double origScaleX
= m_scaleX
;
1722 double origScaleY
= m_scaleY
;
1724 wxDC::ComputeScaleAndOrigin();
1726 /* CMB: if scale has changed call SetPen to recalulate the line width */
1727 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1730 /* this is a bit artificial, but we need to force wxDC to think
1731 the pen has changed */
1738 // Resolution in pixels per logical inch
1739 wxSize
wxWindowDC::GetPPI() const
1741 return wxSize(100, 100);
1744 int wxWindowDC::GetDepth() const
1746 wxFAIL_MSG(wxT("not implemented"));
1752 // ----------------------------------- spline code ----------------------------------------
1754 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1755 double a3
, double b3
, double a4
, double b4
);
1756 void wx_clear_stack();
1757 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1758 double *y3
, double *x4
, double *y4
);
1759 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1760 double x4
, double y4
);
1761 static bool wx_spline_add_point(double x
, double y
);
1762 static void wx_spline_draw_point_array(wxDC
*dc
);
1764 wxList wx_spline_point_list
;
1766 #define half(z1, z2) ((z1+z2)/2.0)
1769 /* iterative version */
1771 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1774 register double xmid
, ymid
;
1775 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1778 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1780 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1781 xmid
= (double)half(x2
, x3
);
1782 ymid
= (double)half(y2
, y3
);
1783 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1784 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1785 wx_spline_add_point( x1
, y1
);
1786 wx_spline_add_point( xmid
, ymid
);
1788 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1789 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1790 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1791 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1796 /* utilities used by spline drawing routines */
1798 typedef struct wx_spline_stack_struct
{
1799 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1802 #define SPLINE_STACK_DEPTH 20
1803 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1804 static Stack
*wx_stack_top
;
1805 static int wx_stack_count
;
1807 void wx_clear_stack()
1809 wx_stack_top
= wx_spline_stack
;
1813 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1815 wx_stack_top
->x1
= x1
;
1816 wx_stack_top
->y1
= y1
;
1817 wx_stack_top
->x2
= x2
;
1818 wx_stack_top
->y2
= y2
;
1819 wx_stack_top
->x3
= x3
;
1820 wx_stack_top
->y3
= y3
;
1821 wx_stack_top
->x4
= x4
;
1822 wx_stack_top
->y4
= y4
;
1827 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1828 double *x3
, double *y3
, double *x4
, double *y4
)
1830 if (wx_stack_count
== 0)
1834 *x1
= wx_stack_top
->x1
;
1835 *y1
= wx_stack_top
->y1
;
1836 *x2
= wx_stack_top
->x2
;
1837 *y2
= wx_stack_top
->y2
;
1838 *x3
= wx_stack_top
->x3
;
1839 *y3
= wx_stack_top
->y3
;
1840 *x4
= wx_stack_top
->x4
;
1841 *y4
= wx_stack_top
->y4
;
1845 static bool wx_spline_add_point(double x
, double y
)
1847 wxPoint
*point
= new wxPoint
;
1850 wx_spline_point_list
.Append((wxObject
*)point
);
1854 static void wx_spline_draw_point_array(wxDC
*dc
)
1856 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1857 wxNode
*node
= wx_spline_point_list
.First();
1860 wxPoint
*point
= (wxPoint
*)node
->Data();
1863 node
= wx_spline_point_list
.First();
1867 void wxWindowDC::DoDrawSpline( wxList
*points
)
1869 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1872 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1873 double x1
, y1
, x2
, y2
;
1875 wxNode
*node
= points
->First();
1876 p
= (wxPoint
*)node
->Data();
1881 node
= node
->Next();
1882 p
= (wxPoint
*)node
->Data();
1886 cx1
= (double)((x1
+ x2
) / 2);
1887 cy1
= (double)((y1
+ y2
) / 2);
1888 cx2
= (double)((cx1
+ x2
) / 2);
1889 cy2
= (double)((cy1
+ y2
) / 2);
1891 wx_spline_add_point(x1
, y1
);
1893 while ((node
= node
->Next()) != NULL
)
1895 p
= (wxPoint
*)node
->Data();
1900 cx4
= (double)(x1
+ x2
) / 2;
1901 cy4
= (double)(y1
+ y2
) / 2;
1902 cx3
= (double)(x1
+ cx4
) / 2;
1903 cy3
= (double)(y1
+ cy4
) / 2;
1905 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1909 cx2
= (double)(cx1
+ x2
) / 2;
1910 cy2
= (double)(cy1
+ y2
) / 2;
1913 wx_spline_add_point( cx1
, cy1
);
1914 wx_spline_add_point( x2
, y2
);
1916 wx_spline_draw_point_array( this );
1919 #endif // wxUSE_SPLINE
1921 //-----------------------------------------------------------------------------
1923 //-----------------------------------------------------------------------------
1925 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1927 wxPaintDC::wxPaintDC()
1932 wxPaintDC::wxPaintDC( wxWindow
*win
)
1935 #if USE_PAINT_REGION
1936 if (!win
->GetUpdateRegion().IsEmpty())
1938 m_paintClippingRegion
= win
->GetUpdateRegion();
1939 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1941 gdk_gc_set_clip_region( m_penGC
, m_paintClippingRegion
.GetRegion() );
1942 gdk_gc_set_clip_region( m_brushGC
, m_paintClippingRegion
.GetRegion() );
1943 gdk_gc_set_clip_region( m_textGC
, m_paintClippingRegion
.GetRegion() );
1944 gdk_gc_set_clip_region( m_bgGC
, m_paintClippingRegion
.GetRegion() );
1949 //-----------------------------------------------------------------------------
1951 //-----------------------------------------------------------------------------
1953 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1955 wxClientDC::wxClientDC()
1960 wxClientDC::wxClientDC( wxWindow
*win
)
1965 // ----------------------------------------------------------------------------
1967 // ----------------------------------------------------------------------------
1969 class wxDCModule
: public wxModule
1976 DECLARE_DYNAMIC_CLASS(wxDCModule
)
1979 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
1981 bool wxDCModule::OnInit()
1987 void wxDCModule::OnExit()