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 // This allows you to e.g. copy from the screen
157 // without clipping the windows on it.
158 gdk_gc_set_subwindow( wxGCPool
[i
].m_gc
,
159 GDK_INCLUDE_INFERIORS
);
160 wxGCPool
[i
].m_type
= type
;
161 wxGCPool
[i
].m_used
= FALSE
;
163 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
165 wxGCPool
[i
].m_used
= TRUE
;
166 return wxGCPool
[i
].m_gc
;
170 wxFAIL_MSG( wxT("No GC available") );
172 return (GdkGC
*) NULL
;
175 static void wxFreePoolGC( GdkGC
*gc
)
177 for (int i
= 0; i
< 200; i
++)
179 if (wxGCPool
[i
].m_gc
== gc
)
181 wxGCPool
[i
].m_used
= FALSE
;
186 wxFAIL_MSG( wxT("Wrong GC") );
189 //-----------------------------------------------------------------------------
191 //-----------------------------------------------------------------------------
193 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
195 wxWindowDC::wxWindowDC()
197 m_penGC
= (GdkGC
*) NULL
;
198 m_brushGC
= (GdkGC
*) NULL
;
199 m_textGC
= (GdkGC
*) NULL
;
200 m_bgGC
= (GdkGC
*) NULL
;
201 m_cmap
= (GdkColormap
*) NULL
;
203 m_owner
= (wxWindow
*)NULL
;
206 wxWindowDC::wxWindowDC( wxWindow
*window
)
208 m_penGC
= (GdkGC
*) NULL
;
209 m_brushGC
= (GdkGC
*) NULL
;
210 m_textGC
= (GdkGC
*) NULL
;
211 m_bgGC
= (GdkGC
*) NULL
;
212 m_cmap
= (GdkColormap
*) NULL
;
213 m_owner
= (wxWindow
*)NULL
;
215 m_font
= window
->GetFont();
217 wxASSERT_MSG( window
, wxT("DC needs a window") );
219 GtkWidget
*widget
= window
->m_wxwindow
;
221 // some controls don't have m_wxwindow - like wxStaticBox, but the user
222 // code should still be able to create wxClientDCs for them, so we will
223 // use the parent window here then
226 window
= window
->GetParent();
227 widget
= window
->m_wxwindow
;
230 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
232 GtkPizza
*pizza
= GTK_PIZZA( widget
);
233 m_window
= pizza
->bin_window
;
238 /* don't report problems */
244 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
248 /* this must be done after SetUpDC, bacause SetUpDC calls the
249 repective SetBrush, SetPen, SetBackground etc functions
250 to set up the DC. SetBackground call m_owner->SetBackground
251 and this might not be desired as the standard dc background
252 is white whereas a window might assume gray to be the
253 standard (as e.g. wxStatusBar) */
258 wxWindowDC::~wxWindowDC()
263 void wxWindowDC::SetUpDC()
267 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
269 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
271 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
272 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
273 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
274 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
278 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
279 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
280 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
281 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
284 /* background colour */
285 m_backgroundBrush
= *wxWHITE_BRUSH
;
286 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
287 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
290 m_textForegroundColour
.CalcPixel( m_cmap
);
291 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
293 m_textBackgroundColour
.CalcPixel( m_cmap
);
294 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
296 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
299 m_pen
.GetColour().CalcPixel( m_cmap
);
300 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
301 gdk_gc_set_background( m_penGC
, bg_col
);
303 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
307 m_brush
.GetColour().CalcPixel( m_cmap
);
308 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
309 gdk_gc_set_background( m_brushGC
, bg_col
);
311 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
315 gdk_gc_set_background( m_bgGC
, bg_col
);
316 gdk_gc_set_foreground( m_bgGC
, bg_col
);
318 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
321 gdk_gc_set_function( m_textGC
, GDK_COPY
);
322 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
323 gdk_gc_set_function( m_penGC
, GDK_COPY
);
326 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
327 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
328 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
329 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
333 hatch_bitmap
= hatches
;
334 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
335 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
336 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
337 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
338 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
339 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
343 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
344 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
346 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
349 bool wxWindowDC::DoGetPixel( wxCoord x1
, wxCoord y1
, wxColour
*col
) const
351 // Generic (and therefore rather inefficient) method.
352 // Could be improved.
354 wxBitmap
bitmap(1, 1);
355 memdc
.SelectObject(bitmap
);
356 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
357 memdc
.SelectObject(wxNullBitmap
);
358 wxImage
image(bitmap
);
359 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
363 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
365 wxCHECK_RET( Ok(), wxT("invalid window dc") );
367 if (m_pen
.GetStyle() != wxTRANSPARENT
)
370 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
372 CalcBoundingBox(x1
, y1
);
373 CalcBoundingBox(x2
, y2
);
377 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
379 wxCHECK_RET( Ok(), wxT("invalid window dc") );
381 if (m_pen
.GetStyle() != wxTRANSPARENT
)
386 wxCoord xx
= XLOG2DEV(x
);
387 wxCoord yy
= YLOG2DEV(y
);
390 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
391 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
396 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
397 wxCoord xc
, wxCoord yc
)
399 wxCHECK_RET( Ok(), wxT("invalid window dc") );
401 wxCoord xx1
= XLOG2DEV(x1
);
402 wxCoord yy1
= YLOG2DEV(y1
);
403 wxCoord xx2
= XLOG2DEV(x2
);
404 wxCoord yy2
= YLOG2DEV(y2
);
405 wxCoord xxc
= XLOG2DEV(xc
);
406 wxCoord yyc
= YLOG2DEV(yc
);
407 double dx
= xx1
- xxc
;
408 double dy
= yy1
- yyc
;
409 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
410 wxCoord r
= (wxCoord
)radius
;
411 double radius1
, radius2
;
413 if (xx1
== xx2
&& yy1
== yy2
)
421 radius1
= radius2
= 0.0;
425 radius1
= (xx1
- xxc
== 0) ?
426 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
427 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
428 radius2
= (xx2
- xxc
== 0) ?
429 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
430 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
432 wxCoord alpha1
= wxCoord(radius1
* 64.0);
433 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
434 while (alpha2
<= 0) alpha2
+= 360*64;
435 while (alpha1
> 360*64) alpha1
-= 360*64;
439 if (m_brush
.GetStyle() != wxTRANSPARENT
)
440 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
442 if (m_pen
.GetStyle() != wxTRANSPARENT
)
443 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
446 CalcBoundingBox (x1
, y1
);
447 CalcBoundingBox (x2
, y2
);
450 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
452 wxCHECK_RET( Ok(), wxT("invalid window dc") );
454 wxCoord xx
= XLOG2DEV(x
);
455 wxCoord yy
= YLOG2DEV(y
);
456 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
457 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
459 // CMB: handle -ve width and/or height
460 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
461 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
465 wxCoord start
= wxCoord(sa
* 64.0);
466 wxCoord end
= wxCoord(ea
* 64.0);
468 if (m_brush
.GetStyle() != wxTRANSPARENT
)
469 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
471 if (m_pen
.GetStyle() != wxTRANSPARENT
)
472 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
475 CalcBoundingBox (x
, y
);
476 CalcBoundingBox (x
+ width
, y
+ height
);
479 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
481 wxCHECK_RET( Ok(), wxT("invalid window dc") );
483 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
484 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
486 CalcBoundingBox (x
, y
);
489 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
491 wxCHECK_RET( Ok(), wxT("invalid window dc") );
493 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
496 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
498 for (int i
= 0; i
< n
-1; i
++)
500 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
501 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
502 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
503 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
506 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
508 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
512 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
514 wxCHECK_RET( Ok(), wxT("invalid window dc") );
518 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
520 for (i
= 0 ; i
< n
; i
++)
522 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
523 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
525 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
530 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
531 gdk_draw_polygon (m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
534 if ((m_brush
.GetStyle() != wxTRANSPARENT
))
535 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
541 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
543 for (i
= 0 ; i
< n
; i
++)
545 gdk_draw_line( m_window
, m_penGC
,
548 gdkpoints
[(i
+1)%n
].x
,
549 gdkpoints
[(i
+1)%n
].y
);
556 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
558 wxCHECK_RET( Ok(), wxT("invalid window dc") );
560 wxCoord xx
= XLOG2DEV(x
);
561 wxCoord yy
= YLOG2DEV(y
);
562 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
563 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
565 // CMB: draw nothing if transformed w or h is 0
566 if (ww
== 0 || hh
== 0) return;
568 // CMB: handle -ve width and/or height
569 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
570 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
574 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
576 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
577 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
581 if (m_brush
.GetStyle() != wxTRANSPARENT
)
582 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
584 if (m_pen
.GetStyle() != wxTRANSPARENT
)
585 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
589 CalcBoundingBox( x
, y
);
590 CalcBoundingBox( x
+ width
, y
+ height
);
593 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
595 wxCHECK_RET( Ok(), wxT("invalid window dc") );
597 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
599 wxCoord xx
= XLOG2DEV(x
);
600 wxCoord yy
= YLOG2DEV(y
);
601 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
602 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
603 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
605 // CMB: handle -ve width and/or height
606 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
607 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
609 // CMB: if radius is zero use DrawRectangle() instead to avoid
610 // X drawing errors with small radii
613 DrawRectangle( x
, y
, width
, height
);
617 // CMB: draw nothing if transformed w or h is 0
618 if (ww
== 0 || hh
== 0) return;
620 // CMB: adjust size if outline is drawn otherwise the result is
621 // 1 pixel too wide and high
622 if (m_pen
.GetStyle() != wxTRANSPARENT
)
630 // CMB: ensure dd is not larger than rectangle otherwise we
631 // get an hour glass shape
633 if (dd
> ww
) dd
= ww
;
634 if (dd
> hh
) dd
= hh
;
637 if (m_brush
.GetStyle() != wxTRANSPARENT
)
639 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
640 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
641 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
642 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
643 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
644 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
647 if (m_pen
.GetStyle() != wxTRANSPARENT
)
649 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
650 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
651 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
652 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
653 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
654 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
655 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
656 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
660 // this ignores the radius
661 CalcBoundingBox( x
, y
);
662 CalcBoundingBox( x
+ width
, y
+ height
);
665 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
667 wxCHECK_RET( Ok(), wxT("invalid window dc") );
669 wxCoord xx
= XLOG2DEV(x
);
670 wxCoord yy
= YLOG2DEV(y
);
671 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
672 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
674 // CMB: handle -ve width and/or height
675 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
676 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
680 if (m_brush
.GetStyle() != wxTRANSPARENT
)
681 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
683 if (m_pen
.GetStyle() != wxTRANSPARENT
)
684 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
687 CalcBoundingBox( x
- width
, y
- height
);
688 CalcBoundingBox( x
+ width
, y
+ height
);
691 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
693 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
694 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
697 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
698 wxCoord x
, wxCoord y
,
701 wxCHECK_RET( Ok(), wxT("invalid window dc") );
703 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
705 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
707 /* scale/translate size and position */
708 int xx
= XLOG2DEV(x
);
709 int yy
= YLOG2DEV(y
);
711 int w
= bitmap
.GetWidth();
712 int h
= bitmap
.GetHeight();
714 CalcBoundingBox( x
, y
);
715 CalcBoundingBox( x
+ w
, y
+ h
);
717 if (!m_window
) return;
719 int ww
= XLOG2DEVREL(w
);
720 int hh
= YLOG2DEVREL(h
);
722 /* compare to current clipping region */
723 if (!m_currentClippingRegion
.IsEmpty())
725 wxRegion
tmp( xx
,yy
,ww
,hh
);
726 tmp
.Intersect( m_currentClippingRegion
);
731 /* scale bitmap if required */
733 if ((w
!= ww
) || (h
!= hh
))
735 wxImage
image( bitmap
);
736 image
.Rescale( ww
, hh
);
738 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
740 use_bitmap
= image
.ConvertToBitmap();
747 /* apply mask if any */
748 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
749 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
753 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
754 if (!m_currentClippingRegion
.IsEmpty())
757 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
758 GdkGC
*gc
= gdk_gc_new( new_mask
);
760 gdk_gc_set_foreground( gc
, &col
);
761 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
763 gdk_gc_set_background( gc
, &col
);
765 gdk_gc_set_foreground( gc
, &col
);
766 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
767 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
768 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
769 gdk_gc_set_stipple( gc
, mask
);
770 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
772 gdk_gc_set_clip_mask( m_brushGC, NULL );
773 gdk_gc_set_clip_mask( m_textGC, NULL );
774 SetBrush( *wxRED_BRUSH );
775 DrawRectangle( 70, 0, 70, 1000 );
776 gdk_draw_bitmap( m_window, m_textGC, new_mask, 0, 0, 100, 5, ww, hh );
777 gdk_draw_bitmap( m_window, m_textGC, mask, 0, 0, 80, 5, ww, hh );
785 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
787 gdk_gc_set_clip_mask( m_textGC
, mask
);
788 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
793 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
795 gdk_gc_set_clip_mask( m_penGC
, mask
);
796 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
799 gdk_bitmap_unref( new_mask
);
802 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
803 drawing a mono-bitmap (XBitmap) we use the current text GC */
805 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
807 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
809 /* remove mask again if any */
814 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
815 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
816 if (!m_currentClippingRegion
.IsEmpty())
817 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
821 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
822 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
823 if (!m_currentClippingRegion
.IsEmpty())
824 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
829 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
830 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
831 int logical_func
, bool useMask
)
833 /* this is the nth try to get this utterly useless function to
834 work. it now completely ignores the scaling or translation
835 of the source dc, but scales correctly on the target dc and
836 knows about possible mask information in a memory dc. */
838 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
840 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
842 if (!m_window
) return FALSE
;
844 wxClientDC
*srcDC
= (wxClientDC
*)source
;
845 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
847 bool use_bitmap_method
= FALSE
;
848 bool is_mono
= FALSE
;
850 if (srcDC
->m_isMemDC
)
852 if (!memDC
->m_selected
.Ok()) return FALSE
;
854 /* we use the "XCopyArea" way to copy a memory dc into
855 y different window if the memory dc BOTH
856 a) doesn't have any mask or its mask isn't used
860 if (useMask
&& (memDC
->m_selected
.GetMask()))
862 /* we HAVE TO use the direct way for memory dcs
863 that have mask since the XCopyArea doesn't know
865 use_bitmap_method
= TRUE
;
867 else if (memDC
->m_selected
.GetDepth() == 1)
869 /* we HAVE TO use the direct way for memory dcs
870 that are bitmaps because XCopyArea doesn't cope
871 with different bit depths */
873 use_bitmap_method
= TRUE
;
875 else if ((xsrc
== 0) && (ysrc
== 0) &&
876 (width
== memDC
->m_selected
.GetWidth()) &&
877 (height
== memDC
->m_selected
.GetHeight()))
879 /* we SHOULD use the direct way if all of the bitmap
880 in the memory dc is copied in which case XCopyArea
881 wouldn't be able able to boost performace by reducing
882 the area to be scaled */
883 use_bitmap_method
= TRUE
;
887 use_bitmap_method
= FALSE
;
891 CalcBoundingBox( xdest
, ydest
);
892 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
894 /* scale/translate size and position */
895 wxCoord xx
= XLOG2DEV(xdest
);
896 wxCoord yy
= YLOG2DEV(ydest
);
898 wxCoord ww
= XLOG2DEVREL(width
);
899 wxCoord hh
= YLOG2DEVREL(height
);
901 /* compare to current clipping region */
902 if (!m_currentClippingRegion
.IsEmpty())
904 wxRegion
tmp( xx
,yy
,ww
,hh
);
905 tmp
.Intersect( m_currentClippingRegion
);
910 int old_logical_func
= m_logicalFunction
;
911 SetLogicalFunction( logical_func
);
913 if (use_bitmap_method
)
915 /* scale/translate bitmap size */
916 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
917 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
919 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
920 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
922 /* scale bitmap if required */
925 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
927 wxImage
image( memDC
->m_selected
);
928 image
= image
.Scale( bm_ww
, bm_hh
);
931 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
933 use_bitmap
= image
.ConvertToBitmap();
937 use_bitmap
= memDC
->m_selected
;
940 /* apply mask if any */
941 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
942 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
946 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
947 if (!m_currentClippingRegion
.IsEmpty())
950 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
951 GdkGC
*gc
= gdk_gc_new( new_mask
);
953 gdk_gc_set_foreground( gc
, &col
);
954 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
956 gdk_gc_set_background( gc
, &col
);
958 gdk_gc_set_foreground( gc
, &col
);
959 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
960 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
961 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
962 gdk_gc_set_stipple( gc
, mask
);
963 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
970 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
972 gdk_gc_set_clip_mask( m_textGC
, mask
);
973 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
978 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
980 gdk_gc_set_clip_mask( m_penGC
, mask
);
981 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
984 gdk_bitmap_unref( new_mask
);
987 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
988 drawing a mono-bitmap (XBitmap) we use the current text GC */
990 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
992 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
994 /* remove mask again if any */
999 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1000 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1001 if (!m_currentClippingRegion
.IsEmpty())
1002 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1006 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1007 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1008 if (!m_currentClippingRegion
.IsEmpty())
1009 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1013 else /* use_bitmap_method */
1015 if ((width
!= ww
) || (height
!= hh
))
1017 /* draw source window into a bitmap as we cannot scale
1018 a window in contrast to a bitmap. this would actually
1019 work with memory dcs as well, but we'd lose the mask
1020 information and waste one step in this process since
1021 a memory already has a bitmap. all this is slightly
1022 inefficient as we could take an XImage directly from
1023 an X window, but we'd then also have to care that
1024 the window is not outside the screen (in which case
1025 we'd get a BadMatch or what not).
1026 Is a double XGetImage and combined XGetPixel and
1027 XPutPixel really faster? I'm not sure. look at wxXt
1028 for a different implementation of the same problem. */
1030 wxBitmap
bitmap( width
, height
);
1031 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1033 xsrc
, ysrc
, width
, height
);
1037 wxImage
image( bitmap
);
1038 image
= image
.Scale( ww
, hh
);
1040 /* convert to bitmap */
1042 bitmap
= image
.ConvertToBitmap();
1044 /* draw scaled bitmap */
1046 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1051 /* no scaling and not a memory dc with a mask either */
1053 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1055 xsrc
, ysrc
, width
, height
);
1059 SetLogicalFunction( old_logical_func
);
1063 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1065 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1067 if (!m_window
) return;
1069 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1071 wxCHECK_RET( font
, wxT("invalid font") );
1076 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1077 if (m_backgroundMode
== wxSOLID
)
1079 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1080 wxCoord height
= font
->ascent
+ font
->descent
;
1081 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1082 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1083 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1085 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1087 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1088 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1089 properties (see wxXt implementation) */
1090 if (m_font
.GetUnderlined())
1092 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1093 wxCoord ul_y
= y
+ font
->ascent
;
1094 if (font
->descent
> 0) ul_y
++;
1095 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1099 GetTextExtent (text
, &w
, &h
);
1100 CalcBoundingBox (x
+ w
, y
+ h
);
1101 CalcBoundingBox (x
, y
);
1104 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1108 DrawText(text
, x
, y
);
1112 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1114 if (!m_window
) return;
1116 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1118 wxCHECK_RET( font
, wxT("invalid font") );
1120 // the size of the text
1121 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1122 wxCoord h
= font
->ascent
+ font
->descent
;
1124 // draw the string normally
1127 dc
.SelectObject(src
);
1128 dc
.SetFont(GetFont());
1129 dc
.SetBackground(*wxWHITE_BRUSH
);
1130 dc
.SetBrush(*wxBLACK_BRUSH
);
1132 dc
.DrawText(text
, 0, 0);
1133 dc
.SetFont(wxNullFont
);
1134 dc
.SelectObject(wxNullBitmap
);
1136 // Calculate the size of the rotated bounding box.
1137 double rad
= DegToRad(angle
);
1138 double dx
= cos(rad
),
1141 // the rectngle vertices are counted clockwise with the first one being at
1142 // (0, 0) (or, rather, at (x, y))
1144 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1147 double x3
= x4
+ x2
,
1151 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1152 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1153 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1154 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1156 // prepare to blit-with-rotate the bitmap to the DC
1159 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1160 *colBack
= m_textBackgroundColour
.GetColor();
1162 bool textColSet
= TRUE
;
1164 unsigned char *data
= image
.GetData();
1166 // paint pixel by pixel
1167 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1169 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1171 // transform source coords to dest coords
1172 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1173 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1174 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1175 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1178 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1179 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1181 // change colour if needed
1182 if ( textPixel
!= textColSet
)
1184 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1187 textColSet
= textPixel
;
1190 // don't use DrawPoint() because it uses the current pen
1191 // colour, and we don't need it here
1192 gdk_draw_point( m_window
, m_textGC
,
1193 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1198 // it would be better to draw with non underlined font and draw the line
1199 // manually here (it would be more straight...)
1201 if ( m_font
.GetUnderlined() )
1203 gdk_draw_line( m_window
, m_textGC
,
1204 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1205 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1209 // restore the font colour
1210 gdk_gc_set_foreground( m_textGC
, colText
);
1212 // update the bounding box
1213 CalcBoundingBox(x
+ minX
, y
+ minY
);
1214 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1217 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1218 wxCoord
*width
, wxCoord
*height
,
1219 wxCoord
*descent
, wxCoord
*externalLeading
,
1220 wxFont
*theFont
) const
1222 wxFont fontToUse
= m_font
;
1223 if (theFont
) fontToUse
= *theFont
;
1225 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1226 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1227 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1228 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1229 if (externalLeading
) (*externalLeading
) = 0; // ??
1232 wxCoord
wxWindowDC::GetCharWidth() const
1234 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1235 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1237 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1240 wxCoord
wxWindowDC::GetCharHeight() const
1242 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1243 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1245 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1248 void wxWindowDC::Clear()
1250 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1252 if (!m_window
) return;
1254 /* - we either are a memory dc or have a window as the
1255 owner. anything else shouldn't happen.
1256 - we don't use gdk_window_clear() as we don't set
1257 the window's background colour anymore. it is too
1258 much pain to keep the DC's and the window's back-
1259 ground colour in synch. */
1264 m_owner
->GetSize( &width
, &height
);
1265 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1272 GetSize( &width
, &height
);
1273 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1278 void wxWindowDC::SetFont( const wxFont
&font
)
1283 void wxWindowDC::SetPen( const wxPen
&pen
)
1285 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1287 if (m_pen
== pen
) return;
1291 if (!m_pen
.Ok()) return;
1293 if (!m_window
) return;
1295 gint width
= m_pen
.GetWidth();
1298 // CMB: if width is non-zero scale it with the dc
1303 // X doesn't allow different width in x and y and so we take
1306 ( fabs((double) XLOG2DEVREL(width
)) +
1307 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1311 static const char dotted
[] = {1, 1};
1312 static const char short_dashed
[] = {2, 2};
1313 static const char wxCoord_dashed
[] = {2, 4};
1314 static const char dotted_dashed
[] = {3, 3, 1, 3};
1316 // We express dash pattern in pen width unit, so we are
1317 // independent of zoom factor and so on...
1319 const char *req_dash
;
1321 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1322 switch (m_pen
.GetStyle())
1326 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1327 req_nb_dash
= m_pen
.GetDashCount();
1328 req_dash
= m_pen
.GetDash();
1333 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1340 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1342 req_dash
= wxCoord_dashed
;
1347 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1349 req_dash
= short_dashed
;
1354 // lineStyle = GDK_LINE_DOUBLE_DASH;
1355 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1357 req_dash
= dotted_dashed
;
1362 case wxSTIPPLE_MASK_OPAQUE
:
1367 lineStyle
= GDK_LINE_SOLID
;
1368 req_dash
= (wxDash
*)NULL
;
1374 #if (GTK_MINOR_VERSION > 0)
1375 if (req_dash
&& req_nb_dash
)
1377 char *real_req_dash
= new char[req_nb_dash
];
1380 for (int i
= 0; i
< req_nb_dash
; i
++)
1381 real_req_dash
[i
] = req_dash
[i
] * width
;
1382 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1383 delete[] real_req_dash
;
1387 // No Memory. We use non-scaled dash pattern...
1388 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
1393 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1394 switch (m_pen
.GetCap())
1396 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1397 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1404 capStyle
= GDK_CAP_NOT_LAST
;
1408 capStyle
= GDK_CAP_ROUND
;
1414 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1415 switch (m_pen
.GetJoin())
1417 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1418 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1420 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1423 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1425 m_pen
.GetColour().CalcPixel( m_cmap
);
1426 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1429 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1431 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1433 if (m_brush
== brush
) return;
1437 if (!m_brush
.Ok()) return;
1439 if (!m_window
) return;
1441 m_brush
.GetColour().CalcPixel( m_cmap
);
1442 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1444 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1446 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1448 if (m_brush
.GetStipple()->GetPixmap())
1450 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1451 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1455 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1456 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1460 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1462 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1463 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1466 if (IS_HATCH(m_brush
.GetStyle()))
1468 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1469 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1470 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1474 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1476 /* CMB 21/7/98: Added SetBackground. Sets background brush
1477 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1479 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1481 if (m_backgroundBrush
== brush
) return;
1483 m_backgroundBrush
= brush
;
1485 if (!m_backgroundBrush
.Ok()) return;
1487 if (!m_window
) return;
1489 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1490 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1491 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1492 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1493 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1495 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1497 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1499 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1501 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1502 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1506 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1507 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1511 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1513 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1514 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1515 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1519 void wxWindowDC::SetLogicalFunction( int function
)
1521 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1523 if (m_logicalFunction
== function
)
1526 // VZ: shouldn't this be a CHECK?
1530 GdkFunction mode
= GDK_COPY
;
1533 case wxXOR
: mode
= GDK_XOR
; break;
1534 case wxINVERT
: mode
= GDK_INVERT
; break;
1535 #if (GTK_MINOR_VERSION > 0)
1536 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1537 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1538 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1539 case wxSET
: mode
= GDK_SET
; break;
1540 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1541 case wxAND
: mode
= GDK_AND
; break;
1542 case wxOR
: mode
= GDK_OR
; break;
1543 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1544 case wxNAND
: mode
= GDK_NAND
; break;
1545 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1546 case wxCOPY
: mode
= GDK_COPY
; break;
1547 case wxNO_OP
: mode
= GDK_NOOP
; break;
1548 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1550 // unsupported by GTK
1551 case wxNOR
: mode
= GDK_COPY
; break;
1555 wxFAIL_MSG( wxT("unsupported logical function") );
1560 m_logicalFunction
= function
;
1562 gdk_gc_set_function( m_penGC
, mode
);
1563 gdk_gc_set_function( m_brushGC
, mode
);
1565 // to stay compatible with wxMSW, we don't apply ROPs to the text
1566 // operations (i.e. DrawText/DrawRotatedText).
1567 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1568 gdk_gc_set_function( m_textGC
, mode
);
1571 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1573 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1575 if (m_textForegroundColour
== col
) return;
1577 m_textForegroundColour
= col
;
1578 if (!m_textForegroundColour
.Ok()) return;
1580 if (!m_window
) return;
1582 m_textForegroundColour
.CalcPixel( m_cmap
);
1583 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1586 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1588 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1590 if (m_textBackgroundColour
== col
) return;
1592 m_textBackgroundColour
= col
;
1593 if (!m_textBackgroundColour
.Ok()) return;
1595 if (!m_window
) return;
1597 m_textBackgroundColour
.CalcPixel( m_cmap
);
1598 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1601 void wxWindowDC::SetBackgroundMode( int mode
)
1603 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1605 m_backgroundMode
= mode
;
1607 if (!m_window
) return;
1609 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1610 // transparent/solid background mode
1612 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1614 gdk_gc_set_fill( m_brushGC
,
1615 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1619 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1621 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1624 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1626 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1628 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1630 if (!m_window
) return;
1633 rect
.x
= XLOG2DEV(x
);
1634 rect
.y
= YLOG2DEV(y
);
1635 rect
.width
= XLOG2DEVREL(width
);
1636 rect
.height
= YLOG2DEVREL(height
);
1638 m_currentClippingRegion
.Clear();
1639 m_currentClippingRegion
.Union( rect
);
1640 #if USE_PAINT_REGION
1641 if (!m_paintClippingRegion
.IsEmpty())
1642 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1645 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1646 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1647 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1648 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1651 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1653 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1657 DestroyClippingRegion();
1662 region
.GetBox( x
, y
, w
, h
);
1664 wxDC::DoSetClippingRegion( x
, y
, w
, h
);
1666 if (!m_window
) return;
1668 m_currentClippingRegion
.Clear();
1669 m_currentClippingRegion
.Union( region
);
1670 #if USE_PAINT_REGION
1671 if (!m_paintClippingRegion
.IsEmpty())
1672 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1675 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1676 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1677 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1678 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1681 void wxWindowDC::DestroyClippingRegion()
1683 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1685 wxDC::DestroyClippingRegion();
1687 m_currentClippingRegion
.Clear();
1689 if (!m_paintClippingRegion
.IsEmpty())
1690 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1692 if (!m_window
) return;
1694 if (m_currentClippingRegion
.IsEmpty())
1696 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1697 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1698 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1699 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1703 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1704 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1705 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1706 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1710 void wxWindowDC::Destroy()
1712 if (m_penGC
) wxFreePoolGC( m_penGC
);
1713 m_penGC
= (GdkGC
*) NULL
;
1714 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1715 m_brushGC
= (GdkGC
*) NULL
;
1716 if (m_textGC
) wxFreePoolGC( m_textGC
);
1717 m_textGC
= (GdkGC
*) NULL
;
1718 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1719 m_bgGC
= (GdkGC
*) NULL
;
1722 void wxWindowDC::ComputeScaleAndOrigin()
1724 /* CMB: copy scale to see if it changes */
1725 double origScaleX
= m_scaleX
;
1726 double origScaleY
= m_scaleY
;
1728 wxDC::ComputeScaleAndOrigin();
1730 /* CMB: if scale has changed call SetPen to recalulate the line width */
1731 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1734 /* this is a bit artificial, but we need to force wxDC to think
1735 the pen has changed */
1742 // Resolution in pixels per logical inch
1743 wxSize
wxWindowDC::GetPPI() const
1745 return wxSize(100, 100);
1748 int wxWindowDC::GetDepth() const
1750 wxFAIL_MSG(wxT("not implemented"));
1756 // ----------------------------------- spline code ----------------------------------------
1758 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1759 double a3
, double b3
, double a4
, double b4
);
1760 void wx_clear_stack();
1761 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1762 double *y3
, double *x4
, double *y4
);
1763 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1764 double x4
, double y4
);
1765 static bool wx_spline_add_point(double x
, double y
);
1766 static void wx_spline_draw_point_array(wxDC
*dc
);
1768 wxList wx_spline_point_list
;
1770 #define half(z1, z2) ((z1+z2)/2.0)
1773 /* iterative version */
1775 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1778 register double xmid
, ymid
;
1779 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1782 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1784 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1785 xmid
= (double)half(x2
, x3
);
1786 ymid
= (double)half(y2
, y3
);
1787 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1788 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1789 wx_spline_add_point( x1
, y1
);
1790 wx_spline_add_point( xmid
, ymid
);
1792 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1793 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1794 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1795 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1800 /* utilities used by spline drawing routines */
1802 typedef struct wx_spline_stack_struct
{
1803 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1806 #define SPLINE_STACK_DEPTH 20
1807 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1808 static Stack
*wx_stack_top
;
1809 static int wx_stack_count
;
1811 void wx_clear_stack()
1813 wx_stack_top
= wx_spline_stack
;
1817 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1819 wx_stack_top
->x1
= x1
;
1820 wx_stack_top
->y1
= y1
;
1821 wx_stack_top
->x2
= x2
;
1822 wx_stack_top
->y2
= y2
;
1823 wx_stack_top
->x3
= x3
;
1824 wx_stack_top
->y3
= y3
;
1825 wx_stack_top
->x4
= x4
;
1826 wx_stack_top
->y4
= y4
;
1831 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1832 double *x3
, double *y3
, double *x4
, double *y4
)
1834 if (wx_stack_count
== 0)
1838 *x1
= wx_stack_top
->x1
;
1839 *y1
= wx_stack_top
->y1
;
1840 *x2
= wx_stack_top
->x2
;
1841 *y2
= wx_stack_top
->y2
;
1842 *x3
= wx_stack_top
->x3
;
1843 *y3
= wx_stack_top
->y3
;
1844 *x4
= wx_stack_top
->x4
;
1845 *y4
= wx_stack_top
->y4
;
1849 static bool wx_spline_add_point(double x
, double y
)
1851 wxPoint
*point
= new wxPoint
;
1854 wx_spline_point_list
.Append((wxObject
*)point
);
1858 static void wx_spline_draw_point_array(wxDC
*dc
)
1860 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1861 wxNode
*node
= wx_spline_point_list
.First();
1864 wxPoint
*point
= (wxPoint
*)node
->Data();
1867 node
= wx_spline_point_list
.First();
1871 void wxWindowDC::DoDrawSpline( wxList
*points
)
1873 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1876 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1877 double x1
, y1
, x2
, y2
;
1879 wxNode
*node
= points
->First();
1880 p
= (wxPoint
*)node
->Data();
1885 node
= node
->Next();
1886 p
= (wxPoint
*)node
->Data();
1890 cx1
= (double)((x1
+ x2
) / 2);
1891 cy1
= (double)((y1
+ y2
) / 2);
1892 cx2
= (double)((cx1
+ x2
) / 2);
1893 cy2
= (double)((cy1
+ y2
) / 2);
1895 wx_spline_add_point(x1
, y1
);
1897 while ((node
= node
->Next()) != NULL
)
1899 p
= (wxPoint
*)node
->Data();
1904 cx4
= (double)(x1
+ x2
) / 2;
1905 cy4
= (double)(y1
+ y2
) / 2;
1906 cx3
= (double)(x1
+ cx4
) / 2;
1907 cy3
= (double)(y1
+ cy4
) / 2;
1909 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1913 cx2
= (double)(cx1
+ x2
) / 2;
1914 cy2
= (double)(cy1
+ y2
) / 2;
1917 wx_spline_add_point( cx1
, cy1
);
1918 wx_spline_add_point( x2
, y2
);
1920 wx_spline_draw_point_array( this );
1923 #endif // wxUSE_SPLINE
1925 //-----------------------------------------------------------------------------
1927 //-----------------------------------------------------------------------------
1929 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1931 wxPaintDC::wxPaintDC()
1936 wxPaintDC::wxPaintDC( wxWindow
*win
)
1939 #if USE_PAINT_REGION
1940 if (!win
->GetUpdateRegion().IsEmpty())
1942 m_paintClippingRegion
= win
->GetUpdateRegion();
1943 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1945 gdk_gc_set_clip_region( m_penGC
, m_paintClippingRegion
.GetRegion() );
1946 gdk_gc_set_clip_region( m_brushGC
, m_paintClippingRegion
.GetRegion() );
1947 gdk_gc_set_clip_region( m_textGC
, m_paintClippingRegion
.GetRegion() );
1948 gdk_gc_set_clip_region( m_bgGC
, m_paintClippingRegion
.GetRegion() );
1953 //-----------------------------------------------------------------------------
1955 //-----------------------------------------------------------------------------
1957 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1959 wxClientDC::wxClientDC()
1964 wxClientDC::wxClientDC( wxWindow
*win
)
1969 // ----------------------------------------------------------------------------
1971 // ----------------------------------------------------------------------------
1973 class wxDCModule
: public wxModule
1980 DECLARE_DYNAMIC_CLASS(wxDCModule
)
1983 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
1985 bool wxDCModule::OnInit()
1991 void wxDCModule::OnExit()