1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/dcclient.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "dcclient.h"
14 #include "wx/dcclient.h"
15 #include "wx/dcmemory.h"
17 #include "wx/module.h"
19 #include "wx/gtk/win_gtk.h"
21 #include <math.h> // for floating-point functions
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
31 #define USE_PAINT_REGION 1
33 //-----------------------------------------------------------------------------
35 //-----------------------------------------------------------------------------
45 static GdkPixmap
*hatches
[num_hatches
];
46 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
48 extern GtkWidget
*wxRootWindow
;
50 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
54 const double RAD2DEG
= 180.0 / M_PI
;
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 static inline double dmax(double a
, double b
) { return a
> b
? a
: b
; }
61 static inline double dmin(double a
, double b
) { return a
< b
? a
: b
; }
63 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
65 //-----------------------------------------------------------------------------
66 // temporary implementation of the missing GDK function
67 //-----------------------------------------------------------------------------
69 #include "gdk/gdkprivate.h"
71 void gdk_wx_draw_bitmap (GdkDrawable
*drawable
,
81 GdkWindowPrivate
*drawable_private
;
82 GdkWindowPrivate
*src_private
;
83 GdkGCPrivate
*gc_private
;
85 g_return_if_fail (drawable
!= NULL
);
86 g_return_if_fail (src
!= NULL
);
87 g_return_if_fail (gc
!= NULL
);
89 drawable_private
= (GdkWindowPrivate
*) drawable
;
90 src_private
= (GdkWindowPrivate
*) src
;
91 if (drawable_private
->destroyed
|| src_private
->destroyed
)
94 gc_private
= (GdkGCPrivate
*) gc
;
96 if (width
== -1) width
= src_private
->width
;
97 if (height
== -1) height
= src_private
->height
;
99 XCopyPlane( drawable_private
->xdisplay
,
100 src_private
->xwindow
,
101 drawable_private
->xwindow
,
109 //-----------------------------------------------------------------------------
110 // Implement Pool of Graphic contexts. Creating them takes too much time.
111 //-----------------------------------------------------------------------------
113 #define GC_POOL_SIZE 200
139 static wxGC wxGCPool
[GC_POOL_SIZE
];
141 static void wxInitGCPool()
143 memset( wxGCPool
, 0, GC_POOL_SIZE
*sizeof(wxGC
) );
146 static void wxCleanUpGCPool()
148 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
150 if (wxGCPool
[i
].m_gc
)
151 gdk_gc_unref( wxGCPool
[i
].m_gc
);
155 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
157 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
159 if (!wxGCPool
[i
].m_gc
)
161 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
162 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
163 wxGCPool
[i
].m_type
= type
;
164 wxGCPool
[i
].m_used
= FALSE
;
166 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
168 wxGCPool
[i
].m_used
= TRUE
;
169 return wxGCPool
[i
].m_gc
;
173 wxFAIL_MSG( wxT("No GC available") );
175 return (GdkGC
*) NULL
;
178 static void wxFreePoolGC( GdkGC
*gc
)
180 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
182 if (wxGCPool
[i
].m_gc
== gc
)
184 wxGCPool
[i
].m_used
= FALSE
;
189 wxFAIL_MSG( wxT("Wrong GC") );
192 //-----------------------------------------------------------------------------
194 //-----------------------------------------------------------------------------
196 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
198 wxWindowDC::wxWindowDC()
200 m_penGC
= (GdkGC
*) NULL
;
201 m_brushGC
= (GdkGC
*) NULL
;
202 m_textGC
= (GdkGC
*) NULL
;
203 m_bgGC
= (GdkGC
*) NULL
;
204 m_cmap
= (GdkColormap
*) NULL
;
206 m_isScreenDC
= FALSE
;
207 m_owner
= (wxWindow
*)NULL
;
210 wxWindowDC::wxWindowDC( wxWindow
*window
)
212 m_penGC
= (GdkGC
*) NULL
;
213 m_brushGC
= (GdkGC
*) NULL
;
214 m_textGC
= (GdkGC
*) NULL
;
215 m_bgGC
= (GdkGC
*) NULL
;
216 m_cmap
= (GdkColormap
*) NULL
;
217 m_owner
= (wxWindow
*)NULL
;
219 m_isScreenDC
= FALSE
;
220 m_font
= window
->GetFont();
222 wxASSERT_MSG( window
, wxT("DC needs a window") );
224 GtkWidget
*widget
= window
->m_wxwindow
;
226 // some controls don't have m_wxwindow - like wxStaticBox, but the user
227 // code should still be able to create wxClientDCs for them, so we will
228 // use the parent window here then
231 window
= window
->GetParent();
232 widget
= window
->m_wxwindow
;
235 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
237 GtkPizza
*pizza
= GTK_PIZZA( widget
);
238 m_window
= pizza
->bin_window
;
243 /* don't report problems */
249 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
253 /* this must be done after SetUpDC, bacause SetUpDC calls the
254 repective SetBrush, SetPen, SetBackground etc functions
255 to set up the DC. SetBackground call m_owner->SetBackground
256 and this might not be desired as the standard dc background
257 is white whereas a window might assume gray to be the
258 standard (as e.g. wxStatusBar) */
263 wxWindowDC::~wxWindowDC()
268 void wxWindowDC::SetUpDC()
272 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
276 m_penGC
= wxGetPoolGC( m_window
, wxPEN_SCREEN
);
277 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_SCREEN
);
278 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_SCREEN
);
279 m_bgGC
= wxGetPoolGC( m_window
, wxBG_SCREEN
);
282 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
284 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
285 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
286 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
287 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
291 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
292 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
293 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
294 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
297 /* background colour */
298 m_backgroundBrush
= *wxWHITE_BRUSH
;
299 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
300 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
303 m_textForegroundColour
.CalcPixel( m_cmap
);
304 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
306 m_textBackgroundColour
.CalcPixel( m_cmap
);
307 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
309 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
312 m_pen
.GetColour().CalcPixel( m_cmap
);
313 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
314 gdk_gc_set_background( m_penGC
, bg_col
);
316 gdk_gc_set_line_attributes( m_penGC
, 0, GDK_LINE_SOLID
, GDK_CAP_NOT_LAST
, GDK_JOIN_ROUND
);
319 m_brush
.GetColour().CalcPixel( m_cmap
);
320 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
321 gdk_gc_set_background( m_brushGC
, bg_col
);
323 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
326 gdk_gc_set_background( m_bgGC
, bg_col
);
327 gdk_gc_set_foreground( m_bgGC
, bg_col
);
329 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
332 gdk_gc_set_function( m_textGC
, GDK_COPY
);
333 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
334 gdk_gc_set_function( m_penGC
, GDK_COPY
);
337 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
338 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
339 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
340 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
344 hatch_bitmap
= hatches
;
345 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
346 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
347 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
348 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
349 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
350 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
354 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
355 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
357 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
360 bool wxWindowDC::DoGetPixel( wxCoord x1
, wxCoord y1
, wxColour
*col
) const
362 // Generic (and therefore rather inefficient) method.
363 // Could be improved.
365 wxBitmap
bitmap(1, 1);
366 memdc
.SelectObject(bitmap
);
367 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
368 memdc
.SelectObject(wxNullBitmap
);
369 wxImage
image(bitmap
);
370 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
374 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
376 wxCHECK_RET( Ok(), wxT("invalid window dc") );
378 if (m_pen
.GetStyle() != wxTRANSPARENT
)
381 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
383 CalcBoundingBox(x1
, y1
);
384 CalcBoundingBox(x2
, y2
);
388 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
390 wxCHECK_RET( Ok(), wxT("invalid window dc") );
392 if (m_pen
.GetStyle() != wxTRANSPARENT
)
397 wxCoord xx
= XLOG2DEV(x
);
398 wxCoord yy
= YLOG2DEV(y
);
401 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
402 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
407 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
408 wxCoord xc
, wxCoord yc
)
410 wxCHECK_RET( Ok(), wxT("invalid window dc") );
412 wxCoord xx1
= XLOG2DEV(x1
);
413 wxCoord yy1
= YLOG2DEV(y1
);
414 wxCoord xx2
= XLOG2DEV(x2
);
415 wxCoord yy2
= YLOG2DEV(y2
);
416 wxCoord xxc
= XLOG2DEV(xc
);
417 wxCoord yyc
= YLOG2DEV(yc
);
418 double dx
= xx1
- xxc
;
419 double dy
= yy1
- yyc
;
420 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
421 wxCoord r
= (wxCoord
)radius
;
422 double radius1
, radius2
;
424 if (xx1
== xx2
&& yy1
== yy2
)
432 radius1
= radius2
= 0.0;
436 radius1
= (xx1
- xxc
== 0) ?
437 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
438 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
439 radius2
= (xx2
- xxc
== 0) ?
440 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
441 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
443 wxCoord alpha1
= wxCoord(radius1
* 64.0);
444 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
445 while (alpha2
<= 0) alpha2
+= 360*64;
446 while (alpha1
> 360*64) alpha1
-= 360*64;
450 if (m_brush
.GetStyle() != wxTRANSPARENT
)
452 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
454 gdk_gc_set_ts_origin( m_textGC
,
455 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
456 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
457 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
458 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
460 if (m_brush
.GetStyle() == wxSTIPPLE
)
462 gdk_gc_set_ts_origin( m_brushGC
,
463 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
464 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
465 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
466 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
470 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
474 if (m_pen
.GetStyle() != wxTRANSPARENT
)
475 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
478 CalcBoundingBox (x1
, y1
);
479 CalcBoundingBox (x2
, y2
);
482 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
484 wxCHECK_RET( Ok(), wxT("invalid window dc") );
486 wxCoord xx
= XLOG2DEV(x
);
487 wxCoord yy
= YLOG2DEV(y
);
488 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
489 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
491 // CMB: handle -ve width and/or height
492 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
493 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
497 wxCoord start
= wxCoord(sa
* 64.0);
498 wxCoord end
= wxCoord(ea
* 64.0);
500 if (m_brush
.GetStyle() != wxTRANSPARENT
)
502 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
504 gdk_gc_set_ts_origin( m_textGC
,
505 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
506 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
507 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
508 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
510 if (m_brush
.GetStyle() == wxSTIPPLE
)
512 gdk_gc_set_ts_origin( m_brushGC
,
513 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
514 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
515 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
516 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
520 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
524 if (m_pen
.GetStyle() != wxTRANSPARENT
)
525 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
528 CalcBoundingBox (x
, y
);
529 CalcBoundingBox (x
+ width
, y
+ height
);
532 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
534 wxCHECK_RET( Ok(), wxT("invalid window dc") );
536 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
537 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
539 CalcBoundingBox (x
, y
);
542 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
544 wxCHECK_RET( Ok(), wxT("invalid window dc") );
546 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
549 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
551 for (int i
= 0; i
< n
-1; i
++)
553 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
554 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
555 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
556 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
559 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
561 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
565 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
567 wxCHECK_RET( Ok(), wxT("invalid window dc") );
571 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
573 for (i
= 0 ; i
< n
; i
++)
575 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
576 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
578 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
583 if (m_brush
.GetStyle() != wxTRANSPARENT
)
585 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
587 gdk_gc_set_ts_origin( m_textGC
,
588 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
589 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
590 gdk_draw_polygon( m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
591 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
593 if (m_brush
.GetStyle() == wxSTIPPLE
)
595 gdk_gc_set_ts_origin( m_brushGC
,
596 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
597 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
598 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
599 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
603 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
607 if (m_pen
.GetStyle() != wxTRANSPARENT
)
609 for (i
= 0 ; i
< n
; i
++)
611 gdk_draw_line( m_window
, m_penGC
,
614 gdkpoints
[(i
+1)%n
].x
,
615 gdkpoints
[(i
+1)%n
].y
);
623 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
625 wxCHECK_RET( Ok(), wxT("invalid window dc") );
627 wxCoord xx
= XLOG2DEV(x
);
628 wxCoord yy
= YLOG2DEV(y
);
629 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
630 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
632 // CMB: draw nothing if transformed w or h is 0
633 if (ww
== 0 || hh
== 0) return;
635 // CMB: handle -ve width and/or height
636 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
637 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
641 if (m_brush
.GetStyle() != wxTRANSPARENT
)
643 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
645 gdk_gc_set_ts_origin( m_textGC
,
646 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
647 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
648 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
649 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
651 else if (m_brush
.GetStyle() == wxSTIPPLE
)
653 gdk_gc_set_ts_origin( m_brushGC
,
654 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
655 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
656 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
657 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
661 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
665 if (m_pen
.GetStyle() != wxTRANSPARENT
)
666 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
669 CalcBoundingBox( x
, y
);
670 CalcBoundingBox( x
+ width
, y
+ height
);
673 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
675 wxCHECK_RET( Ok(), wxT("invalid window dc") );
677 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
679 wxCoord xx
= XLOG2DEV(x
);
680 wxCoord yy
= YLOG2DEV(y
);
681 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
682 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
683 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
685 // CMB: handle -ve width and/or height
686 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
687 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
689 // CMB: if radius is zero use DrawRectangle() instead to avoid
690 // X drawing errors with small radii
693 DrawRectangle( x
, y
, width
, height
);
697 // CMB: draw nothing if transformed w or h is 0
698 if (ww
== 0 || hh
== 0) return;
700 // CMB: adjust size if outline is drawn otherwise the result is
701 // 1 pixel too wide and high
702 if (m_pen
.GetStyle() != wxTRANSPARENT
)
710 // CMB: ensure dd is not larger than rectangle otherwise we
711 // get an hour glass shape
713 if (dd
> ww
) dd
= ww
;
714 if (dd
> hh
) dd
= hh
;
717 if (m_brush
.GetStyle() != wxTRANSPARENT
)
719 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
721 gdk_gc_set_ts_origin( m_textGC
,
722 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
723 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
724 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
725 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
726 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
727 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
728 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
729 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
730 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
732 else if (m_brush
.GetStyle() == wxSTIPPLE
)
734 gdk_gc_set_ts_origin( m_brushGC
,
735 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
736 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
737 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
738 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
739 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
740 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
741 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
742 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
743 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
747 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
748 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
749 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
750 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
751 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
752 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
756 if (m_pen
.GetStyle() != wxTRANSPARENT
)
758 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
759 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
760 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
761 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
762 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
763 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
764 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
765 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
769 // this ignores the radius
770 CalcBoundingBox( x
, y
);
771 CalcBoundingBox( x
+ width
, y
+ height
);
774 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
776 wxCHECK_RET( Ok(), wxT("invalid window dc") );
778 wxCoord xx
= XLOG2DEV(x
);
779 wxCoord yy
= YLOG2DEV(y
);
780 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
781 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
783 // CMB: handle -ve width and/or height
784 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
785 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
789 if (m_brush
.GetStyle() != wxTRANSPARENT
)
791 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
793 gdk_gc_set_ts_origin( m_textGC
,
794 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
795 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
796 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
797 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
799 else if (m_brush
.GetStyle() == wxSTIPPLE
)
801 gdk_gc_set_ts_origin( m_brushGC
,
802 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
803 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
804 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
805 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
809 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
813 if (m_pen
.GetStyle() != wxTRANSPARENT
)
814 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
817 CalcBoundingBox( x
- width
, y
- height
);
818 CalcBoundingBox( x
+ width
, y
+ height
);
821 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
823 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
824 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
827 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
828 wxCoord x
, wxCoord y
,
831 wxCHECK_RET( Ok(), wxT("invalid window dc") );
833 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
835 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
837 /* scale/translate size and position */
838 int xx
= XLOG2DEV(x
);
839 int yy
= YLOG2DEV(y
);
841 int w
= bitmap
.GetWidth();
842 int h
= bitmap
.GetHeight();
844 CalcBoundingBox( x
, y
);
845 CalcBoundingBox( x
+ w
, y
+ h
);
847 if (!m_window
) return;
849 int ww
= XLOG2DEVREL(w
);
850 int hh
= YLOG2DEVREL(h
);
852 /* compare to current clipping region */
853 if (!m_currentClippingRegion
.IsNull())
855 wxRegion
tmp( xx
,yy
,ww
,hh
);
856 tmp
.Intersect( m_currentClippingRegion
);
861 /* scale bitmap if required */
863 if ((w
!= ww
) || (h
!= hh
))
865 wxImage
image( bitmap
);
866 image
.Rescale( ww
, hh
);
868 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
870 use_bitmap
= image
.ConvertToBitmap();
877 /* apply mask if any */
878 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
879 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
883 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
884 if (!m_currentClippingRegion
.IsNull())
887 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
888 GdkGC
*gc
= gdk_gc_new( new_mask
);
890 gdk_gc_set_foreground( gc
, &col
);
891 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
893 gdk_gc_set_background( gc
, &col
);
895 gdk_gc_set_foreground( gc
, &col
);
896 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
897 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
898 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
899 gdk_gc_set_stipple( gc
, mask
);
900 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
907 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
909 gdk_gc_set_clip_mask( m_textGC
, mask
);
910 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
915 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
917 gdk_gc_set_clip_mask( m_penGC
, mask
);
918 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
921 gdk_bitmap_unref( new_mask
);
924 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
925 drawing a mono-bitmap (XBitmap) we use the current text GC */
927 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
929 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
931 /* remove mask again if any */
936 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
937 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
938 if (!m_currentClippingRegion
.IsNull())
939 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
943 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
944 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
945 if (!m_currentClippingRegion
.IsNull())
946 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
951 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
952 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
953 int logical_func
, bool useMask
)
955 /* this is the nth try to get this utterly useless function to
956 work. it now completely ignores the scaling or translation
957 of the source dc, but scales correctly on the target dc and
958 knows about possible mask information in a memory dc. */
960 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
962 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
964 if (!m_window
) return FALSE
;
966 wxClientDC
*srcDC
= (wxClientDC
*)source
;
967 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
969 bool use_bitmap_method
= FALSE
;
970 bool is_mono
= FALSE
;
972 if (srcDC
->m_isMemDC
)
974 if (!memDC
->m_selected
.Ok()) return FALSE
;
976 /* we use the "XCopyArea" way to copy a memory dc into
977 y different window if the memory dc BOTH
978 a) doesn't have any mask or its mask isn't used
982 if (useMask
&& (memDC
->m_selected
.GetMask()))
984 /* we HAVE TO use the direct way for memory dcs
985 that have mask since the XCopyArea doesn't know
987 use_bitmap_method
= TRUE
;
989 else if (memDC
->m_selected
.GetDepth() == 1)
991 /* we HAVE TO use the direct way for memory dcs
992 that are bitmaps because XCopyArea doesn't cope
993 with different bit depths */
995 use_bitmap_method
= TRUE
;
997 else if ((xsrc
== 0) && (ysrc
== 0) &&
998 (width
== memDC
->m_selected
.GetWidth()) &&
999 (height
== memDC
->m_selected
.GetHeight()))
1001 /* we SHOULD use the direct way if all of the bitmap
1002 in the memory dc is copied in which case XCopyArea
1003 wouldn't be able able to boost performace by reducing
1004 the area to be scaled */
1005 use_bitmap_method
= TRUE
;
1009 use_bitmap_method
= FALSE
;
1013 CalcBoundingBox( xdest
, ydest
);
1014 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
1016 /* scale/translate size and position */
1017 wxCoord xx
= XLOG2DEV(xdest
);
1018 wxCoord yy
= YLOG2DEV(ydest
);
1020 wxCoord ww
= XLOG2DEVREL(width
);
1021 wxCoord hh
= YLOG2DEVREL(height
);
1023 /* compare to current clipping region */
1024 if (!m_currentClippingRegion
.IsNull())
1026 wxRegion
tmp( xx
,yy
,ww
,hh
);
1027 tmp
.Intersect( m_currentClippingRegion
);
1032 int old_logical_func
= m_logicalFunction
;
1033 SetLogicalFunction( logical_func
);
1035 if (use_bitmap_method
)
1037 /* scale/translate bitmap size */
1038 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
1039 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
1041 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
1042 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
1044 /* scale bitmap if required */
1045 wxBitmap use_bitmap
;
1047 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
1049 wxImage
image( memDC
->m_selected
);
1050 image
= image
.Scale( bm_ww
, bm_hh
);
1053 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
1055 use_bitmap
= image
.ConvertToBitmap();
1059 use_bitmap
= memDC
->m_selected
;
1062 /* apply mask if any */
1063 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1064 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1066 if (useMask
&& mask
)
1068 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1069 if (!m_currentClippingRegion
.IsNull())
1072 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
1073 GdkGC
*gc
= gdk_gc_new( new_mask
);
1075 gdk_gc_set_foreground( gc
, &col
);
1076 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1078 gdk_gc_set_background( gc
, &col
);
1080 gdk_gc_set_foreground( gc
, &col
);
1081 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1082 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1083 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1084 gdk_gc_set_stipple( gc
, mask
);
1085 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1092 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1094 gdk_gc_set_clip_mask( m_textGC
, mask
);
1095 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1100 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1102 gdk_gc_set_clip_mask( m_penGC
, mask
);
1103 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1106 gdk_bitmap_unref( new_mask
);
1109 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1110 drawing a mono-bitmap (XBitmap) we use the current text GC */
1113 gdk_wx_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1115 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1117 /* remove mask again if any */
1118 if (useMask
&& mask
)
1122 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1123 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1124 if (!m_currentClippingRegion
.IsNull())
1125 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1129 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1130 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1131 if (!m_currentClippingRegion
.IsNull())
1132 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1136 else /* use_bitmap_method */
1138 if ((width
!= ww
) || (height
!= hh
))
1140 /* draw source window into a bitmap as we cannot scale
1141 a window in contrast to a bitmap. this would actually
1142 work with memory dcs as well, but we'd lose the mask
1143 information and waste one step in this process since
1144 a memory already has a bitmap. all this is slightly
1145 inefficient as we could take an XImage directly from
1146 an X window, but we'd then also have to care that
1147 the window is not outside the screen (in which case
1148 we'd get a BadMatch or what not).
1149 Is a double XGetImage and combined XGetPixel and
1150 XPutPixel really faster? I'm not sure. look at wxXt
1151 for a different implementation of the same problem. */
1153 wxBitmap
bitmap( width
, height
);
1155 /* copy including child window contents */
1156 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1157 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1159 xsrc
, ysrc
, width
, height
);
1160 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1163 wxImage
image( bitmap
);
1164 image
= image
.Scale( ww
, hh
);
1166 /* convert to bitmap */
1167 bitmap
= image
.ConvertToBitmap();
1169 /* draw scaled bitmap */
1170 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1175 /* No scaling and not a memory dc with a mask either */
1177 /* copy including child window contents */
1178 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1179 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1181 xsrc
, ysrc
, width
, height
);
1182 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1186 SetLogicalFunction( old_logical_func
);
1190 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1192 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1194 if (!m_window
) return;
1196 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1198 wxCHECK_RET( font
, wxT("invalid font") );
1203 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1204 if (m_backgroundMode
== wxSOLID
)
1206 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1207 wxCoord height
= font
->ascent
+ font
->descent
;
1208 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1209 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1210 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1212 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1214 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1215 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1216 properties (see wxXt implementation) */
1217 if (m_font
.GetUnderlined())
1219 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1220 wxCoord ul_y
= y
+ font
->ascent
;
1221 if (font
->descent
> 0) ul_y
++;
1222 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1226 GetTextExtent (text
, &w
, &h
);
1227 CalcBoundingBox (x
+ w
, y
+ h
);
1228 CalcBoundingBox (x
, y
);
1231 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1235 DrawText(text
, x
, y
);
1239 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1241 if (!m_window
) return;
1243 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1245 wxCHECK_RET( font
, wxT("invalid font") );
1247 // the size of the text
1248 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1249 wxCoord h
= font
->ascent
+ font
->descent
;
1251 // draw the string normally
1254 dc
.SelectObject(src
);
1255 dc
.SetFont(GetFont());
1256 dc
.SetBackground(*wxWHITE_BRUSH
);
1257 dc
.SetBrush(*wxBLACK_BRUSH
);
1259 dc
.DrawText(text
, 0, 0);
1260 dc
.SetFont(wxNullFont
);
1261 dc
.SelectObject(wxNullBitmap
);
1263 // Calculate the size of the rotated bounding box.
1264 double rad
= DegToRad(angle
);
1265 double dx
= cos(rad
),
1268 // the rectngle vertices are counted clockwise with the first one being at
1269 // (0, 0) (or, rather, at (x, y))
1271 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1274 double x3
= x4
+ x2
,
1278 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1279 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1280 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1281 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1283 // prepare to blit-with-rotate the bitmap to the DC
1286 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1287 *colBack
= m_textBackgroundColour
.GetColor();
1289 bool textColSet
= TRUE
;
1291 unsigned char *data
= image
.GetData();
1293 // paint pixel by pixel
1294 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1296 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1298 // transform source coords to dest coords
1299 double r
= sqrt((double)srcX
*srcX
+ srcY
*srcY
);
1300 double angleOrig
= atan2((double)srcY
, (double)srcX
) - rad
;
1301 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1302 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1305 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1306 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1308 // change colour if needed
1309 if ( textPixel
!= textColSet
)
1311 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1314 textColSet
= textPixel
;
1317 // don't use DrawPoint() because it uses the current pen
1318 // colour, and we don't need it here
1319 gdk_draw_point( m_window
, m_textGC
,
1320 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1325 // it would be better to draw with non underlined font and draw the line
1326 // manually here (it would be more straight...)
1328 if ( m_font
.GetUnderlined() )
1330 gdk_draw_line( m_window
, m_textGC
,
1331 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1332 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1336 // restore the font colour
1337 gdk_gc_set_foreground( m_textGC
, colText
);
1339 // update the bounding box
1340 CalcBoundingBox(x
+ minX
, y
+ minY
);
1341 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1344 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1345 wxCoord
*width
, wxCoord
*height
,
1346 wxCoord
*descent
, wxCoord
*externalLeading
,
1347 wxFont
*theFont
) const
1349 wxFont fontToUse
= m_font
;
1350 if (theFont
) fontToUse
= *theFont
;
1352 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1353 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1354 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1355 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1356 if (externalLeading
) (*externalLeading
) = 0; // ??
1359 wxCoord
wxWindowDC::GetCharWidth() const
1361 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1362 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1364 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1367 wxCoord
wxWindowDC::GetCharHeight() const
1369 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1370 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1372 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1375 void wxWindowDC::Clear()
1377 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1379 if (!m_window
) return;
1381 /* - we either are a memory dc or have a window as the
1382 owner. anything else shouldn't happen.
1383 - we don't use gdk_window_clear() as we don't set
1384 the window's background colour anymore. it is too
1385 much pain to keep the DC's and the window's back-
1386 ground colour in synch. */
1391 m_owner
->GetSize( &width
, &height
);
1392 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1399 GetSize( &width
, &height
);
1400 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1405 void wxWindowDC::SetFont( const wxFont
&font
)
1410 void wxWindowDC::SetPen( const wxPen
&pen
)
1412 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1414 if (m_pen
== pen
) return;
1418 if (!m_pen
.Ok()) return;
1420 if (!m_window
) return;
1422 gint width
= m_pen
.GetWidth();
1425 // CMB: if width is non-zero scale it with the dc
1430 // X doesn't allow different width in x and y and so we take
1433 ( fabs((double) XLOG2DEVREL(width
)) +
1434 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1438 static const wxGTKDash dotted
[] = {1, 1};
1439 static const wxGTKDash short_dashed
[] = {2, 2};
1440 static const wxGTKDash wxCoord_dashed
[] = {2, 4};
1441 static const wxGTKDash dotted_dashed
[] = {3, 3, 1, 3};
1443 // We express dash pattern in pen width unit, so we are
1444 // independent of zoom factor and so on...
1446 const wxGTKDash
*req_dash
;
1448 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1449 switch (m_pen
.GetStyle())
1453 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1454 req_nb_dash
= m_pen
.GetDashCount();
1455 req_dash
= (wxGTKDash
*)m_pen
.GetDash();
1460 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1467 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1469 req_dash
= wxCoord_dashed
;
1474 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1476 req_dash
= short_dashed
;
1481 // lineStyle = GDK_LINE_DOUBLE_DASH;
1482 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1484 req_dash
= dotted_dashed
;
1489 case wxSTIPPLE_MASK_OPAQUE
:
1494 lineStyle
= GDK_LINE_SOLID
;
1495 req_dash
= (wxGTKDash
*)NULL
;
1501 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1502 if (req_dash
&& req_nb_dash
)
1504 wxGTKDash
*real_req_dash
= new wxGTKDash
[req_nb_dash
];
1507 for (int i
= 0; i
< req_nb_dash
; i
++)
1508 real_req_dash
[i
] = req_dash
[i
] * width
;
1509 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1510 delete[] real_req_dash
;
1514 // No Memory. We use non-scaled dash pattern...
1515 gdk_gc_set_dashes( m_penGC
, 0, (wxGTKDash
*)req_dash
, req_nb_dash
);
1520 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1521 switch (m_pen
.GetCap())
1523 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1524 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1531 capStyle
= GDK_CAP_NOT_LAST
;
1535 capStyle
= GDK_CAP_ROUND
;
1541 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1542 switch (m_pen
.GetJoin())
1544 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1545 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1547 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1550 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1552 m_pen
.GetColour().CalcPixel( m_cmap
);
1553 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1556 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1558 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1560 if (m_brush
== brush
) return;
1564 if (!m_brush
.Ok()) return;
1566 if (!m_window
) return;
1568 m_brush
.GetColour().CalcPixel( m_cmap
);
1569 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1571 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1573 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1575 if (m_brush
.GetStipple()->GetPixmap())
1577 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1578 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1582 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1583 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1587 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1589 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1590 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1593 if (IS_HATCH(m_brush
.GetStyle()))
1595 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1596 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1597 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1601 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1603 /* CMB 21/7/98: Added SetBackground. Sets background brush
1604 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1606 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1608 if (m_backgroundBrush
== brush
) return;
1610 m_backgroundBrush
= brush
;
1612 if (!m_backgroundBrush
.Ok()) return;
1614 if (!m_window
) return;
1616 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1617 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1618 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1619 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1620 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1622 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1624 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1626 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1628 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1629 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1633 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1634 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1638 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1640 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1641 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1642 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1646 void wxWindowDC::SetLogicalFunction( int function
)
1648 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1650 if (m_logicalFunction
== function
)
1653 // VZ: shouldn't this be a CHECK?
1657 GdkFunction mode
= GDK_COPY
;
1660 case wxXOR
: mode
= GDK_XOR
; break;
1661 case wxINVERT
: mode
= GDK_INVERT
; break;
1662 #if (GTK_MINOR_VERSION > 0)
1663 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1664 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1665 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1666 case wxSET
: mode
= GDK_SET
; break;
1667 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1668 case wxAND
: mode
= GDK_AND
; break;
1669 case wxOR
: mode
= GDK_OR
; break;
1670 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1671 case wxNAND
: mode
= GDK_NAND
; break;
1672 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1673 case wxCOPY
: mode
= GDK_COPY
; break;
1674 case wxNO_OP
: mode
= GDK_NOOP
; break;
1675 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1677 // unsupported by GTK
1678 case wxNOR
: mode
= GDK_COPY
; break;
1682 wxFAIL_MSG( wxT("unsupported logical function") );
1687 m_logicalFunction
= function
;
1689 gdk_gc_set_function( m_penGC
, mode
);
1690 gdk_gc_set_function( m_brushGC
, mode
);
1692 // to stay compatible with wxMSW, we don't apply ROPs to the text
1693 // operations (i.e. DrawText/DrawRotatedText).
1694 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1695 gdk_gc_set_function( m_textGC
, mode
);
1698 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1700 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1702 if (m_textForegroundColour
== col
) return;
1704 m_textForegroundColour
= col
;
1705 if (!m_textForegroundColour
.Ok()) return;
1707 if (!m_window
) return;
1709 m_textForegroundColour
.CalcPixel( m_cmap
);
1710 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1713 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1715 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1717 if (m_textBackgroundColour
== col
) return;
1719 m_textBackgroundColour
= col
;
1720 if (!m_textBackgroundColour
.Ok()) return;
1722 if (!m_window
) return;
1724 m_textBackgroundColour
.CalcPixel( m_cmap
);
1725 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1728 void wxWindowDC::SetBackgroundMode( int mode
)
1730 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1732 m_backgroundMode
= mode
;
1734 if (!m_window
) return;
1736 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1737 // transparent/solid background mode
1739 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1741 gdk_gc_set_fill( m_brushGC
,
1742 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1746 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1748 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1751 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1753 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1755 if (!m_window
) return;
1758 rect
.x
= XLOG2DEV(x
);
1759 rect
.y
= YLOG2DEV(y
);
1760 rect
.width
= XLOG2DEVREL(width
);
1761 rect
.height
= YLOG2DEVREL(height
);
1763 if (!m_currentClippingRegion
.IsNull())
1764 m_currentClippingRegion
.Intersect( rect
);
1766 m_currentClippingRegion
.Union( rect
);
1768 #if USE_PAINT_REGION
1769 if (!m_paintClippingRegion
.IsNull())
1770 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1773 wxCoord xx
, yy
, ww
, hh
;
1774 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1775 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1777 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1778 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1779 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1780 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1783 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1785 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1789 DestroyClippingRegion();
1793 if (!m_window
) return;
1795 if (!m_currentClippingRegion
.IsNull())
1796 m_currentClippingRegion
.Intersect( region
);
1798 m_currentClippingRegion
.Union( region
);
1800 #if USE_PAINT_REGION
1801 if (!m_paintClippingRegion
.IsNull())
1802 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1805 wxCoord xx
, yy
, ww
, hh
;
1806 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1807 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1809 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1810 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1811 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1812 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1815 void wxWindowDC::DestroyClippingRegion()
1817 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1819 wxDC::DestroyClippingRegion();
1821 m_currentClippingRegion
.Clear();
1823 #if USE_PAINT_REGION
1824 if (!m_paintClippingRegion
.IsEmpty())
1825 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1828 if (!m_window
) return;
1830 if (m_currentClippingRegion
.IsEmpty())
1832 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1833 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1834 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1835 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1839 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1840 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1841 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1842 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1846 void wxWindowDC::Destroy()
1848 if (m_penGC
) wxFreePoolGC( m_penGC
);
1849 m_penGC
= (GdkGC
*) NULL
;
1850 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1851 m_brushGC
= (GdkGC
*) NULL
;
1852 if (m_textGC
) wxFreePoolGC( m_textGC
);
1853 m_textGC
= (GdkGC
*) NULL
;
1854 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1855 m_bgGC
= (GdkGC
*) NULL
;
1858 void wxWindowDC::ComputeScaleAndOrigin()
1860 /* CMB: copy scale to see if it changes */
1861 double origScaleX
= m_scaleX
;
1862 double origScaleY
= m_scaleY
;
1864 wxDC::ComputeScaleAndOrigin();
1866 /* CMB: if scale has changed call SetPen to recalulate the line width */
1867 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1870 /* this is a bit artificial, but we need to force wxDC to think
1871 the pen has changed */
1878 // Resolution in pixels per logical inch
1879 wxSize
wxWindowDC::GetPPI() const
1881 return wxSize(100, 100);
1884 int wxWindowDC::GetDepth() const
1886 wxFAIL_MSG(wxT("not implemented"));
1892 // ----------------------------------- spline code ----------------------------------------
1894 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1895 double a3
, double b3
, double a4
, double b4
);
1896 void wx_clear_stack();
1897 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1898 double *y3
, double *x4
, double *y4
);
1899 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1900 double x4
, double y4
);
1901 static bool wx_spline_add_point(double x
, double y
);
1902 static void wx_spline_draw_point_array(wxDC
*dc
);
1904 wxList wx_spline_point_list
;
1906 #define half(z1, z2) ((z1+z2)/2.0)
1909 /* iterative version */
1911 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1914 register double xmid
, ymid
;
1915 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1918 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1920 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1921 xmid
= (double)half(x2
, x3
);
1922 ymid
= (double)half(y2
, y3
);
1923 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1924 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1925 wx_spline_add_point( x1
, y1
);
1926 wx_spline_add_point( xmid
, ymid
);
1928 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1929 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1930 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1931 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1936 /* utilities used by spline drawing routines */
1938 typedef struct wx_spline_stack_struct
{
1939 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1942 #define SPLINE_STACK_DEPTH 20
1943 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1944 static Stack
*wx_stack_top
;
1945 static int wx_stack_count
;
1947 void wx_clear_stack()
1949 wx_stack_top
= wx_spline_stack
;
1953 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1955 wx_stack_top
->x1
= x1
;
1956 wx_stack_top
->y1
= y1
;
1957 wx_stack_top
->x2
= x2
;
1958 wx_stack_top
->y2
= y2
;
1959 wx_stack_top
->x3
= x3
;
1960 wx_stack_top
->y3
= y3
;
1961 wx_stack_top
->x4
= x4
;
1962 wx_stack_top
->y4
= y4
;
1967 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1968 double *x3
, double *y3
, double *x4
, double *y4
)
1970 if (wx_stack_count
== 0)
1974 *x1
= wx_stack_top
->x1
;
1975 *y1
= wx_stack_top
->y1
;
1976 *x2
= wx_stack_top
->x2
;
1977 *y2
= wx_stack_top
->y2
;
1978 *x3
= wx_stack_top
->x3
;
1979 *y3
= wx_stack_top
->y3
;
1980 *x4
= wx_stack_top
->x4
;
1981 *y4
= wx_stack_top
->y4
;
1985 static bool wx_spline_add_point(double x
, double y
)
1987 wxPoint
*point
= new wxPoint
;
1990 wx_spline_point_list
.Append((wxObject
*)point
);
1994 static void wx_spline_draw_point_array(wxDC
*dc
)
1996 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1997 wxNode
*node
= wx_spline_point_list
.First();
2000 wxPoint
*point
= (wxPoint
*)node
->Data();
2003 node
= wx_spline_point_list
.First();
2007 void wxWindowDC::DoDrawSpline( wxList
*points
)
2009 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2012 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2013 double x1
, y1
, x2
, y2
;
2015 wxNode
*node
= points
->First();
2016 p
= (wxPoint
*)node
->Data();
2021 node
= node
->Next();
2022 p
= (wxPoint
*)node
->Data();
2026 cx1
= (double)((x1
+ x2
) / 2);
2027 cy1
= (double)((y1
+ y2
) / 2);
2028 cx2
= (double)((cx1
+ x2
) / 2);
2029 cy2
= (double)((cy1
+ y2
) / 2);
2031 wx_spline_add_point(x1
, y1
);
2033 while ((node
= node
->Next()) != NULL
)
2035 p
= (wxPoint
*)node
->Data();
2040 cx4
= (double)(x1
+ x2
) / 2;
2041 cy4
= (double)(y1
+ y2
) / 2;
2042 cx3
= (double)(x1
+ cx4
) / 2;
2043 cy3
= (double)(y1
+ cy4
) / 2;
2045 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2049 cx2
= (double)(cx1
+ x2
) / 2;
2050 cy2
= (double)(cy1
+ y2
) / 2;
2053 wx_spline_add_point( cx1
, cy1
);
2054 wx_spline_add_point( x2
, y2
);
2056 wx_spline_draw_point_array( this );
2059 #endif // wxUSE_SPLINE
2061 //-----------------------------------------------------------------------------
2063 //-----------------------------------------------------------------------------
2065 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
2067 wxPaintDC::wxPaintDC()
2072 wxPaintDC::wxPaintDC( wxWindow
*win
)
2075 #if USE_PAINT_REGION
2076 if (!win
->m_clipPaintRegion
)
2079 m_paintClippingRegion
= win
->GetUpdateRegion();
2080 GdkRegion
*region
= m_paintClippingRegion
.GetRegion();
2083 m_currentClippingRegion
.Union( m_paintClippingRegion
);
2085 gdk_gc_set_clip_region( m_penGC
, region
);
2086 gdk_gc_set_clip_region( m_brushGC
, region
);
2087 gdk_gc_set_clip_region( m_textGC
, region
);
2088 gdk_gc_set_clip_region( m_bgGC
, region
);
2093 //-----------------------------------------------------------------------------
2095 //-----------------------------------------------------------------------------
2097 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
2099 wxClientDC::wxClientDC()
2104 wxClientDC::wxClientDC( wxWindow
*win
)
2109 // ----------------------------------------------------------------------------
2111 // ----------------------------------------------------------------------------
2113 class wxDCModule
: public wxModule
2120 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2123 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2125 bool wxDCModule::OnInit()
2131 void wxDCModule::OnExit()