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_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
135 static wxGC wxGCPool
[GC_POOL_SIZE
];
137 static void wxInitGCPool()
139 memset( wxGCPool
, 0, GC_POOL_SIZE
*sizeof(wxGC
) );
142 static void wxCleanUpGCPool()
144 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
146 if (wxGCPool
[i
].m_gc
)
147 gdk_gc_unref( wxGCPool
[i
].m_gc
);
151 static GdkGC
* wxGetPoolGC( GdkWindow
*window
, wxPoolGCType type
)
153 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
155 if (!wxGCPool
[i
].m_gc
)
157 wxGCPool
[i
].m_gc
= gdk_gc_new( window
);
158 gdk_gc_set_exposures( wxGCPool
[i
].m_gc
, FALSE
);
159 wxGCPool
[i
].m_type
= type
;
160 wxGCPool
[i
].m_used
= FALSE
;
162 if ((!wxGCPool
[i
].m_used
) && (wxGCPool
[i
].m_type
== type
))
164 wxGCPool
[i
].m_used
= TRUE
;
165 return wxGCPool
[i
].m_gc
;
169 wxFAIL_MSG( wxT("No GC available") );
171 return (GdkGC
*) NULL
;
174 static void wxFreePoolGC( GdkGC
*gc
)
176 for (int i
= 0; i
< GC_POOL_SIZE
; i
++)
178 if (wxGCPool
[i
].m_gc
== gc
)
180 wxGCPool
[i
].m_used
= FALSE
;
185 wxFAIL_MSG( wxT("Wrong GC") );
188 //-----------------------------------------------------------------------------
190 //-----------------------------------------------------------------------------
192 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
194 wxWindowDC::wxWindowDC()
196 m_penGC
= (GdkGC
*) NULL
;
197 m_brushGC
= (GdkGC
*) NULL
;
198 m_textGC
= (GdkGC
*) NULL
;
199 m_bgGC
= (GdkGC
*) NULL
;
200 m_cmap
= (GdkColormap
*) NULL
;
202 m_isScreenDC
= FALSE
;
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_isScreenDC
= FALSE
;
216 m_font
= window
->GetFont();
218 wxASSERT_MSG( window
, wxT("DC needs a window") );
220 GtkWidget
*widget
= window
->m_wxwindow
;
222 // some controls don't have m_wxwindow - like wxStaticBox, but the user
223 // code should still be able to create wxClientDCs for them, so we will
224 // use the parent window here then
227 window
= window
->GetParent();
228 widget
= window
->m_wxwindow
;
231 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
233 GtkPizza
*pizza
= GTK_PIZZA( widget
);
234 m_window
= pizza
->bin_window
;
239 /* don't report problems */
245 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
249 /* this must be done after SetUpDC, bacause SetUpDC calls the
250 repective SetBrush, SetPen, SetBackground etc functions
251 to set up the DC. SetBackground call m_owner->SetBackground
252 and this might not be desired as the standard dc background
253 is white whereas a window might assume gray to be the
254 standard (as e.g. wxStatusBar) */
259 wxWindowDC::~wxWindowDC()
264 void wxWindowDC::SetUpDC()
268 wxASSERT_MSG( !m_penGC
, wxT("GCs already created") );
270 if (m_isMemDC
&& (((wxMemoryDC
*)this)->m_selected
.GetDepth() == 1))
272 m_penGC
= wxGetPoolGC( m_window
, wxPEN_MONO
);
273 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_MONO
);
274 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_MONO
);
275 m_bgGC
= wxGetPoolGC( m_window
, wxBG_MONO
);
279 m_penGC
= wxGetPoolGC( m_window
, wxPEN_COLOUR
);
280 m_brushGC
= wxGetPoolGC( m_window
, wxBRUSH_COLOUR
);
281 m_textGC
= wxGetPoolGC( m_window
, wxTEXT_COLOUR
);
282 m_bgGC
= wxGetPoolGC( m_window
, wxBG_COLOUR
);
285 /* background colour */
286 m_backgroundBrush
= *wxWHITE_BRUSH
;
287 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
288 GdkColor
*bg_col
= m_backgroundBrush
.GetColour().GetColor();
291 m_textForegroundColour
.CalcPixel( m_cmap
);
292 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
294 m_textBackgroundColour
.CalcPixel( m_cmap
);
295 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
297 gdk_gc_set_fill( m_textGC
, GDK_SOLID
);
300 m_pen
.GetColour().CalcPixel( m_cmap
);
301 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
302 gdk_gc_set_background( m_penGC
, bg_col
);
304 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
);
314 gdk_gc_set_background( m_bgGC
, bg_col
);
315 gdk_gc_set_foreground( m_bgGC
, bg_col
);
317 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
320 gdk_gc_set_function( m_textGC
, GDK_COPY
);
321 gdk_gc_set_function( m_brushGC
, GDK_COPY
);
322 gdk_gc_set_function( m_penGC
, GDK_COPY
);
325 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
326 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
327 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
328 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
332 hatch_bitmap
= hatches
;
333 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
334 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
335 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
336 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
337 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
338 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
342 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
343 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
345 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
348 bool wxWindowDC::DoGetPixel( wxCoord x1
, wxCoord y1
, wxColour
*col
) const
350 // Generic (and therefore rather inefficient) method.
351 // Could be improved.
353 wxBitmap
bitmap(1, 1);
354 memdc
.SelectObject(bitmap
);
355 memdc
.Blit(0, 0, 1, 1, (wxDC
*) this, x1
, y1
);
356 memdc
.SelectObject(wxNullBitmap
);
357 wxImage
image(bitmap
);
358 col
->Set(image
.GetRed(0, 0), image
.GetGreen(0, 0), image
.GetBlue(0, 0));
362 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
364 wxCHECK_RET( Ok(), wxT("invalid window dc") );
366 if (m_pen
.GetStyle() != wxTRANSPARENT
)
369 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
371 CalcBoundingBox(x1
, y1
);
372 CalcBoundingBox(x2
, y2
);
376 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
378 wxCHECK_RET( Ok(), wxT("invalid window dc") );
380 if (m_pen
.GetStyle() != wxTRANSPARENT
)
385 wxCoord xx
= XLOG2DEV(x
);
386 wxCoord yy
= YLOG2DEV(y
);
389 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
390 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
395 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
396 wxCoord xc
, wxCoord yc
)
398 wxCHECK_RET( Ok(), wxT("invalid window dc") );
400 wxCoord xx1
= XLOG2DEV(x1
);
401 wxCoord yy1
= YLOG2DEV(y1
);
402 wxCoord xx2
= XLOG2DEV(x2
);
403 wxCoord yy2
= YLOG2DEV(y2
);
404 wxCoord xxc
= XLOG2DEV(xc
);
405 wxCoord yyc
= YLOG2DEV(yc
);
406 double dx
= xx1
- xxc
;
407 double dy
= yy1
- yyc
;
408 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
409 wxCoord r
= (wxCoord
)radius
;
410 double radius1
, radius2
;
412 if (xx1
== xx2
&& yy1
== yy2
)
420 radius1
= radius2
= 0.0;
424 radius1
= (xx1
- xxc
== 0) ?
425 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
426 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
427 radius2
= (xx2
- xxc
== 0) ?
428 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
429 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
431 wxCoord alpha1
= wxCoord(radius1
* 64.0);
432 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
433 while (alpha2
<= 0) alpha2
+= 360*64;
434 while (alpha1
> 360*64) alpha1
-= 360*64;
438 if (m_brush
.GetStyle() != wxTRANSPARENT
)
440 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
442 gdk_gc_set_ts_origin( m_textGC
,
443 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
444 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
445 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
446 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
448 if (m_brush
.GetStyle() == wxSTIPPLE
)
450 gdk_gc_set_ts_origin( m_brushGC
,
451 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
452 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
453 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
454 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
458 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
462 if (m_pen
.GetStyle() != wxTRANSPARENT
)
463 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
466 CalcBoundingBox (x1
, y1
);
467 CalcBoundingBox (x2
, y2
);
470 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
472 wxCHECK_RET( Ok(), wxT("invalid window dc") );
474 wxCoord xx
= XLOG2DEV(x
);
475 wxCoord yy
= YLOG2DEV(y
);
476 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
477 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
479 // CMB: handle -ve width and/or height
480 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
481 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
485 wxCoord start
= wxCoord(sa
* 64.0);
486 wxCoord end
= wxCoord(ea
* 64.0);
488 if (m_brush
.GetStyle() != wxTRANSPARENT
)
490 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
492 gdk_gc_set_ts_origin( m_textGC
,
493 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
494 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
495 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
496 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
498 if (m_brush
.GetStyle() == wxSTIPPLE
)
500 gdk_gc_set_ts_origin( m_brushGC
,
501 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
502 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
503 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
504 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
508 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
512 if (m_pen
.GetStyle() != wxTRANSPARENT
)
513 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
516 CalcBoundingBox (x
, y
);
517 CalcBoundingBox (x
+ width
, y
+ height
);
520 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
522 wxCHECK_RET( Ok(), wxT("invalid window dc") );
524 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
525 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
527 CalcBoundingBox (x
, y
);
530 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
532 wxCHECK_RET( Ok(), wxT("invalid window dc") );
534 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
537 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
539 for (int i
= 0; i
< n
-1; i
++)
541 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
542 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
543 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
544 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
547 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
549 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
553 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
555 wxCHECK_RET( Ok(), wxT("invalid window dc") );
559 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
561 for (i
= 0 ; i
< n
; i
++)
563 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
564 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
566 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
571 if (m_brush
.GetStyle() != wxTRANSPARENT
)
573 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
575 gdk_gc_set_ts_origin( m_textGC
,
576 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
577 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
578 gdk_draw_polygon( m_window
, m_textGC
, TRUE
, gdkpoints
, n
);
579 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
581 if (m_brush
.GetStyle() == wxSTIPPLE
)
583 gdk_gc_set_ts_origin( m_brushGC
,
584 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
585 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
586 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
587 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
591 gdk_draw_polygon( m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
595 if (m_pen
.GetStyle() != wxTRANSPARENT
)
597 for (i
= 0 ; i
< n
; i
++)
599 gdk_draw_line( m_window
, m_penGC
,
602 gdkpoints
[(i
+1)%n
].x
,
603 gdkpoints
[(i
+1)%n
].y
);
611 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
613 wxCHECK_RET( Ok(), wxT("invalid window dc") );
615 wxCoord xx
= XLOG2DEV(x
);
616 wxCoord yy
= YLOG2DEV(y
);
617 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
618 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
620 // CMB: draw nothing if transformed w or h is 0
621 if (ww
== 0 || hh
== 0) return;
623 // CMB: handle -ve width and/or height
624 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
625 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
629 if (m_brush
.GetStyle() != wxTRANSPARENT
)
631 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
633 gdk_gc_set_ts_origin( m_textGC
,
634 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
635 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
636 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
);
637 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
639 else if (m_brush
.GetStyle() == wxSTIPPLE
)
641 gdk_gc_set_ts_origin( m_brushGC
,
642 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
643 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
644 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
645 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
649 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
653 if (m_pen
.GetStyle() != wxTRANSPARENT
)
654 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
657 CalcBoundingBox( x
, y
);
658 CalcBoundingBox( x
+ width
, y
+ height
);
661 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
663 wxCHECK_RET( Ok(), wxT("invalid window dc") );
665 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
667 wxCoord xx
= XLOG2DEV(x
);
668 wxCoord yy
= YLOG2DEV(y
);
669 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
670 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
671 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
673 // CMB: handle -ve width and/or height
674 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
675 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
677 // CMB: if radius is zero use DrawRectangle() instead to avoid
678 // X drawing errors with small radii
681 DrawRectangle( x
, y
, width
, height
);
685 // CMB: draw nothing if transformed w or h is 0
686 if (ww
== 0 || hh
== 0) return;
688 // CMB: adjust size if outline is drawn otherwise the result is
689 // 1 pixel too wide and high
690 if (m_pen
.GetStyle() != wxTRANSPARENT
)
698 // CMB: ensure dd is not larger than rectangle otherwise we
699 // get an hour glass shape
701 if (dd
> ww
) dd
= ww
;
702 if (dd
> hh
) dd
= hh
;
705 if (m_brush
.GetStyle() != wxTRANSPARENT
)
707 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
709 gdk_gc_set_ts_origin( m_textGC
,
710 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
711 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
712 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
713 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
714 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
715 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
716 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
717 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
718 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
720 else if (m_brush
.GetStyle() == wxSTIPPLE
)
722 gdk_gc_set_ts_origin( m_brushGC
,
723 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
724 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
725 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
726 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
727 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
728 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
729 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
730 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
731 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
735 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
736 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
737 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
738 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
739 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
740 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
744 if (m_pen
.GetStyle() != wxTRANSPARENT
)
746 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
747 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
748 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
749 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
750 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
751 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
752 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
753 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
757 // this ignores the radius
758 CalcBoundingBox( x
, y
);
759 CalcBoundingBox( x
+ width
, y
+ height
);
762 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
764 wxCHECK_RET( Ok(), wxT("invalid window dc") );
766 wxCoord xx
= XLOG2DEV(x
);
767 wxCoord yy
= YLOG2DEV(y
);
768 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
769 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
771 // CMB: handle -ve width and/or height
772 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
773 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
777 if (m_brush
.GetStyle() != wxTRANSPARENT
)
779 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
781 gdk_gc_set_ts_origin( m_textGC
,
782 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
783 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
784 gdk_draw_arc( m_window
, m_textGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
785 gdk_gc_set_ts_origin( m_textGC
, 0, 0 );
787 else if (m_brush
.GetStyle() == wxSTIPPLE
)
789 gdk_gc_set_ts_origin( m_brushGC
,
790 m_deviceOriginX
% m_brush
.GetStipple()->GetWidth(),
791 m_deviceOriginY
% m_brush
.GetStipple()->GetHeight() );
792 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
793 gdk_gc_set_ts_origin( m_brushGC
, 0, 0 );
797 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
801 if (m_pen
.GetStyle() != wxTRANSPARENT
)
802 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
805 CalcBoundingBox( x
- width
, y
- height
);
806 CalcBoundingBox( x
+ width
, y
+ height
);
809 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
811 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
812 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
815 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
816 wxCoord x
, wxCoord y
,
819 wxCHECK_RET( Ok(), wxT("invalid window dc") );
821 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
823 bool is_mono
= (bitmap
.GetBitmap() != NULL
);
825 /* scale/translate size and position */
826 int xx
= XLOG2DEV(x
);
827 int yy
= YLOG2DEV(y
);
829 int w
= bitmap
.GetWidth();
830 int h
= bitmap
.GetHeight();
832 CalcBoundingBox( x
, y
);
833 CalcBoundingBox( x
+ w
, y
+ h
);
835 if (!m_window
) return;
837 int ww
= XLOG2DEVREL(w
);
838 int hh
= YLOG2DEVREL(h
);
840 /* compare to current clipping region */
841 if (!m_currentClippingRegion
.IsNull())
843 wxRegion
tmp( xx
,yy
,ww
,hh
);
844 tmp
.Intersect( m_currentClippingRegion
);
849 /* scale bitmap if required */
851 if ((w
!= ww
) || (h
!= hh
))
853 wxImage
image( bitmap
);
854 image
.Rescale( ww
, hh
);
856 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
858 use_bitmap
= image
.ConvertToBitmap();
865 /* apply mask if any */
866 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
867 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
871 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
872 if (!m_currentClippingRegion
.IsNull())
875 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, ww
, hh
, 1 );
876 GdkGC
*gc
= gdk_gc_new( new_mask
);
878 gdk_gc_set_foreground( gc
, &col
);
879 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
881 gdk_gc_set_background( gc
, &col
);
883 gdk_gc_set_foreground( gc
, &col
);
884 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
885 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
886 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
887 gdk_gc_set_stipple( gc
, mask
);
888 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, ww
, hh
);
895 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
897 gdk_gc_set_clip_mask( m_textGC
, mask
);
898 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
903 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
905 gdk_gc_set_clip_mask( m_penGC
, mask
);
906 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
909 gdk_bitmap_unref( new_mask
);
912 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
913 drawing a mono-bitmap (XBitmap) we use the current text GC */
915 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), 0, 0, xx
, yy
, -1, -1 );
917 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
919 /* remove mask again if any */
924 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
925 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
926 if (!m_currentClippingRegion
.IsNull())
927 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
931 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
932 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
933 if (!m_currentClippingRegion
.IsNull())
934 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
939 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
940 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
941 int logical_func
, bool useMask
)
943 /* this is the nth try to get this utterly useless function to
944 work. it now completely ignores the scaling or translation
945 of the source dc, but scales correctly on the target dc and
946 knows about possible mask information in a memory dc. */
948 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
950 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
952 if (!m_window
) return FALSE
;
954 wxClientDC
*srcDC
= (wxClientDC
*)source
;
955 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
957 bool use_bitmap_method
= FALSE
;
958 bool is_mono
= FALSE
;
960 if (srcDC
->m_isMemDC
)
962 if (!memDC
->m_selected
.Ok()) return FALSE
;
964 /* we use the "XCopyArea" way to copy a memory dc into
965 y different window if the memory dc BOTH
966 a) doesn't have any mask or its mask isn't used
970 if (useMask
&& (memDC
->m_selected
.GetMask()))
972 /* we HAVE TO use the direct way for memory dcs
973 that have mask since the XCopyArea doesn't know
975 use_bitmap_method
= TRUE
;
977 else if (memDC
->m_selected
.GetDepth() == 1)
979 /* we HAVE TO use the direct way for memory dcs
980 that are bitmaps because XCopyArea doesn't cope
981 with different bit depths */
983 use_bitmap_method
= TRUE
;
985 else if ((xsrc
== 0) && (ysrc
== 0) &&
986 (width
== memDC
->m_selected
.GetWidth()) &&
987 (height
== memDC
->m_selected
.GetHeight()))
989 /* we SHOULD use the direct way if all of the bitmap
990 in the memory dc is copied in which case XCopyArea
991 wouldn't be able able to boost performace by reducing
992 the area to be scaled */
993 use_bitmap_method
= TRUE
;
997 use_bitmap_method
= FALSE
;
1001 CalcBoundingBox( xdest
, ydest
);
1002 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
1004 /* scale/translate size and position */
1005 wxCoord xx
= XLOG2DEV(xdest
);
1006 wxCoord yy
= YLOG2DEV(ydest
);
1008 wxCoord ww
= XLOG2DEVREL(width
);
1009 wxCoord hh
= YLOG2DEVREL(height
);
1011 /* compare to current clipping region */
1012 if (!m_currentClippingRegion
.IsNull())
1014 wxRegion
tmp( xx
,yy
,ww
,hh
);
1015 tmp
.Intersect( m_currentClippingRegion
);
1020 int old_logical_func
= m_logicalFunction
;
1021 SetLogicalFunction( logical_func
);
1023 if (use_bitmap_method
)
1025 /* scale/translate bitmap size */
1026 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
1027 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
1029 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
1030 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
1032 /* scale bitmap if required */
1033 wxBitmap use_bitmap
;
1035 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
1037 wxImage
image( memDC
->m_selected
);
1038 image
= image
.Scale( bm_ww
, bm_hh
);
1041 use_bitmap
= image
.ConvertToMonoBitmap(255,255,255);
1043 use_bitmap
= image
.ConvertToBitmap();
1047 use_bitmap
= memDC
->m_selected
;
1050 /* apply mask if any */
1051 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1052 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
1054 if (useMask
&& mask
)
1056 GdkBitmap
*new_mask
= (GdkBitmap
*) NULL
;
1057 if (!m_currentClippingRegion
.IsNull())
1060 new_mask
= gdk_pixmap_new( wxRootWindow
->window
, bm_ww
, bm_hh
, 1 );
1061 GdkGC
*gc
= gdk_gc_new( new_mask
);
1063 gdk_gc_set_foreground( gc
, &col
);
1064 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1066 gdk_gc_set_background( gc
, &col
);
1068 gdk_gc_set_foreground( gc
, &col
);
1069 gdk_gc_set_clip_region( gc
, m_currentClippingRegion
.GetRegion() );
1070 gdk_gc_set_clip_origin( gc
, -xx
, -yy
);
1071 gdk_gc_set_fill( gc
, GDK_OPAQUE_STIPPLED
);
1072 gdk_gc_set_stipple( gc
, mask
);
1073 gdk_draw_rectangle( new_mask
, gc
, TRUE
, 0, 0, bm_ww
, bm_hh
);
1080 gdk_gc_set_clip_mask( m_textGC
, new_mask
);
1082 gdk_gc_set_clip_mask( m_textGC
, mask
);
1083 gdk_gc_set_clip_origin( m_textGC
, xx
, yy
);
1088 gdk_gc_set_clip_mask( m_penGC
, new_mask
);
1090 gdk_gc_set_clip_mask( m_penGC
, mask
);
1091 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
1094 gdk_bitmap_unref( new_mask
);
1097 /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
1098 drawing a mono-bitmap (XBitmap) we use the current text GC */
1101 gdk_draw_bitmap( m_window
, m_textGC
, use_bitmap
.GetBitmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1103 gdk_draw_pixmap( m_window
, m_penGC
, use_bitmap
.GetPixmap(), xsrc
, ysrc
, xx
, yy
, ww
, hh
);
1105 /* remove mask again if any */
1106 if (useMask
&& mask
)
1110 gdk_gc_set_clip_mask( m_textGC
, (GdkBitmap
*) NULL
);
1111 gdk_gc_set_clip_origin( m_textGC
, 0, 0 );
1112 if (!m_currentClippingRegion
.IsNull())
1113 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1117 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
1118 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
1119 if (!m_currentClippingRegion
.IsNull())
1120 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1124 else /* use_bitmap_method */
1126 if ((width
!= ww
) || (height
!= hh
))
1128 /* draw source window into a bitmap as we cannot scale
1129 a window in contrast to a bitmap. this would actually
1130 work with memory dcs as well, but we'd lose the mask
1131 information and waste one step in this process since
1132 a memory already has a bitmap. all this is slightly
1133 inefficient as we could take an XImage directly from
1134 an X window, but we'd then also have to care that
1135 the window is not outside the screen (in which case
1136 we'd get a BadMatch or what not).
1137 Is a double XGetImage and combined XGetPixel and
1138 XPutPixel really faster? I'm not sure. look at wxXt
1139 for a different implementation of the same problem. */
1141 wxBitmap
bitmap( width
, height
);
1143 /* copy including child window contents */
1144 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1145 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
1147 xsrc
, ysrc
, width
, height
);
1148 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1151 wxImage
image( bitmap
);
1152 image
= image
.Scale( ww
, hh
);
1154 /* convert to bitmap */
1155 bitmap
= image
.ConvertToBitmap();
1157 /* draw scaled bitmap */
1158 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
1163 /* No scaling and not a memory dc with a mask either */
1165 /* copy including child window contents */
1166 gdk_gc_set_subwindow( m_penGC
, GDK_INCLUDE_INFERIORS
);
1167 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
1169 xsrc
, ysrc
, width
, height
);
1170 gdk_gc_set_subwindow( m_penGC
, GDK_CLIP_BY_CHILDREN
);
1174 SetLogicalFunction( old_logical_func
);
1178 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
1180 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1182 if (!m_window
) return;
1184 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1186 wxCHECK_RET( font
, wxT("invalid font") );
1191 /* CMB 21/5/98: draw text background if mode is wxSOLID */
1192 if (m_backgroundMode
== wxSOLID
)
1194 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1195 wxCoord height
= font
->ascent
+ font
->descent
;
1196 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
1197 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
1198 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1200 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
1202 /* CMB 17/7/98: simple underline: ignores scaling and underlying
1203 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
1204 properties (see wxXt implementation) */
1205 if (m_font
.GetUnderlined())
1207 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
1208 wxCoord ul_y
= y
+ font
->ascent
;
1209 if (font
->descent
> 0) ul_y
++;
1210 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
1214 GetTextExtent (text
, &w
, &h
);
1215 CalcBoundingBox (x
+ w
, y
+ h
);
1216 CalcBoundingBox (x
, y
);
1219 void wxWindowDC::DoDrawRotatedText( const wxString
&text
, wxCoord x
, wxCoord y
, double angle
)
1223 DrawText(text
, x
, y
);
1227 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1229 if (!m_window
) return;
1231 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1233 wxCHECK_RET( font
, wxT("invalid font") );
1235 // the size of the text
1236 wxCoord w
= gdk_string_width( font
, text
.mbc_str() );
1237 wxCoord h
= font
->ascent
+ font
->descent
;
1239 // draw the string normally
1242 dc
.SelectObject(src
);
1243 dc
.SetFont(GetFont());
1244 dc
.SetBackground(*wxWHITE_BRUSH
);
1245 dc
.SetBrush(*wxBLACK_BRUSH
);
1247 dc
.DrawText(text
, 0, 0);
1248 dc
.SetFont(wxNullFont
);
1249 dc
.SelectObject(wxNullBitmap
);
1251 // Calculate the size of the rotated bounding box.
1252 double rad
= DegToRad(angle
);
1253 double dx
= cos(rad
),
1256 // the rectngle vertices are counted clockwise with the first one being at
1257 // (0, 0) (or, rather, at (x, y))
1259 y2
= -w
*dy
; // y axis points to the bottom, hence minus
1262 double x3
= x4
+ x2
,
1266 wxCoord maxX
= (wxCoord
)(dmax(x2
, dmax(x3
, x4
)) + 0.5),
1267 maxY
= (wxCoord
)(dmax(y2
, dmax(y3
, y4
)) + 0.5),
1268 minX
= (wxCoord
)(dmin(x2
, dmin(x3
, x4
)) - 0.5),
1269 minY
= (wxCoord
)(dmin(y2
, dmin(y3
, y4
)) - 0.5);
1271 // prepare to blit-with-rotate the bitmap to the DC
1274 GdkColor
*colText
= m_textForegroundColour
.GetColor(),
1275 *colBack
= m_textBackgroundColour
.GetColor();
1277 bool textColSet
= TRUE
;
1279 unsigned char *data
= image
.GetData();
1281 // paint pixel by pixel
1282 for ( wxCoord srcX
= 0; srcX
< w
; srcX
++ )
1284 for ( wxCoord srcY
= 0; srcY
< h
; srcY
++ )
1286 // transform source coords to dest coords
1287 double r
= sqrt(srcX
*srcX
+ srcY
*srcY
);
1288 double angleOrig
= atan2(srcY
, srcX
) - rad
;
1289 wxCoord dstX
= (wxCoord
)(r
*cos(angleOrig
) + 0.5),
1290 dstY
= (wxCoord
)(r
*sin(angleOrig
) + 0.5);
1293 bool textPixel
= data
[(srcY
*w
+ srcX
)*3] == 0;
1294 if ( textPixel
|| (m_backgroundMode
== wxSOLID
) )
1296 // change colour if needed
1297 if ( textPixel
!= textColSet
)
1299 gdk_gc_set_foreground( m_textGC
, textPixel
? colText
1302 textColSet
= textPixel
;
1305 // don't use DrawPoint() because it uses the current pen
1306 // colour, and we don't need it here
1307 gdk_draw_point( m_window
, m_textGC
,
1308 XLOG2DEV(x
+ dstX
), YLOG2DEV(y
+ dstY
) );
1313 // it would be better to draw with non underlined font and draw the line
1314 // manually here (it would be more straight...)
1316 if ( m_font
.GetUnderlined() )
1318 gdk_draw_line( m_window
, m_textGC
,
1319 XLOG2DEV(x
+ x4
), YLOG2DEV(y
+ y4
+ font
->descent
),
1320 XLOG2DEV(x
+ x3
), YLOG2DEV(y
+ y3
+ font
->descent
));
1324 // restore the font colour
1325 gdk_gc_set_foreground( m_textGC
, colText
);
1327 // update the bounding box
1328 CalcBoundingBox(x
+ minX
, y
+ minY
);
1329 CalcBoundingBox(x
+ maxX
, y
+ maxY
);
1332 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
1333 wxCoord
*width
, wxCoord
*height
,
1334 wxCoord
*descent
, wxCoord
*externalLeading
,
1335 wxFont
*theFont
) const
1337 wxFont fontToUse
= m_font
;
1338 if (theFont
) fontToUse
= *theFont
;
1340 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
1341 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
1342 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1343 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
1344 if (externalLeading
) (*externalLeading
) = 0; // ??
1347 wxCoord
wxWindowDC::GetCharWidth() const
1349 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1350 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1352 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
1355 wxCoord
wxWindowDC::GetCharHeight() const
1357 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
1358 wxCHECK_MSG( font
, -1, wxT("invalid font") );
1360 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
1363 void wxWindowDC::Clear()
1365 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1367 if (!m_window
) return;
1369 /* - we either are a memory dc or have a window as the
1370 owner. anything else shouldn't happen.
1371 - we don't use gdk_window_clear() as we don't set
1372 the window's background colour anymore. it is too
1373 much pain to keep the DC's and the window's back-
1374 ground colour in synch. */
1379 m_owner
->GetSize( &width
, &height
);
1380 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1387 GetSize( &width
, &height
);
1388 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
1393 void wxWindowDC::SetFont( const wxFont
&font
)
1398 void wxWindowDC::SetPen( const wxPen
&pen
)
1400 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1402 if (m_pen
== pen
) return;
1406 if (!m_pen
.Ok()) return;
1408 if (!m_window
) return;
1410 gint width
= m_pen
.GetWidth();
1413 // CMB: if width is non-zero scale it with the dc
1418 // X doesn't allow different width in x and y and so we take
1421 ( fabs((double) XLOG2DEVREL(width
)) +
1422 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
1426 static const wxGTKDash dotted
[] = {1, 1};
1427 static const wxGTKDash short_dashed
[] = {2, 2};
1428 static const wxGTKDash wxCoord_dashed
[] = {2, 4};
1429 static const wxGTKDash dotted_dashed
[] = {3, 3, 1, 3};
1431 // We express dash pattern in pen width unit, so we are
1432 // independent of zoom factor and so on...
1434 const wxGTKDash
*req_dash
;
1436 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
1437 switch (m_pen
.GetStyle())
1441 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1442 req_nb_dash
= m_pen
.GetDashCount();
1443 req_dash
= (wxGTKDash
*)m_pen
.GetDash();
1448 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1455 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1457 req_dash
= wxCoord_dashed
;
1462 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1464 req_dash
= short_dashed
;
1469 // lineStyle = GDK_LINE_DOUBLE_DASH;
1470 lineStyle
= GDK_LINE_ON_OFF_DASH
;
1472 req_dash
= dotted_dashed
;
1477 case wxSTIPPLE_MASK_OPAQUE
:
1482 lineStyle
= GDK_LINE_SOLID
;
1483 req_dash
= (wxGTKDash
*)NULL
;
1489 #if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1)
1490 if (req_dash
&& req_nb_dash
)
1492 wxGTKDash
*real_req_dash
= new wxGTKDash
[req_nb_dash
];
1495 for (int i
= 0; i
< req_nb_dash
; i
++)
1496 real_req_dash
[i
] = req_dash
[i
] * width
;
1497 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
1498 delete[] real_req_dash
;
1502 // No Memory. We use non-scaled dash pattern...
1503 gdk_gc_set_dashes( m_penGC
, 0, (wxGTKDash
*)req_dash
, req_nb_dash
);
1508 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
1509 switch (m_pen
.GetCap())
1511 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
1512 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
1519 capStyle
= GDK_CAP_NOT_LAST
;
1523 capStyle
= GDK_CAP_ROUND
;
1529 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
1530 switch (m_pen
.GetJoin())
1532 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
1533 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
1535 default: { joinStyle
= GDK_JOIN_ROUND
; break; }
1538 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
1540 m_pen
.GetColour().CalcPixel( m_cmap
);
1541 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
1544 void wxWindowDC::SetBrush( const wxBrush
&brush
)
1546 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1548 if (m_brush
== brush
) return;
1552 if (!m_brush
.Ok()) return;
1554 if (!m_window
) return;
1556 m_brush
.GetColour().CalcPixel( m_cmap
);
1557 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1559 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1561 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1563 if (m_brush
.GetStipple()->GetPixmap())
1565 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1566 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1570 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1571 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1575 if ((m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
) && (m_brush
.GetStipple()->GetMask()))
1577 gdk_gc_set_fill( m_textGC
, GDK_OPAQUE_STIPPLED
);
1578 gdk_gc_set_stipple( m_textGC
, m_brush
.GetStipple()->GetMask()->GetBitmap() );
1581 if (IS_HATCH(m_brush
.GetStyle()))
1583 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1584 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1585 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1589 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1591 /* CMB 21/7/98: Added SetBackground. Sets background brush
1592 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1594 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1596 if (m_backgroundBrush
== brush
) return;
1598 m_backgroundBrush
= brush
;
1600 if (!m_backgroundBrush
.Ok()) return;
1602 if (!m_window
) return;
1604 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1605 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1606 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1607 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1608 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1610 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1612 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1614 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1616 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1617 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1621 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1622 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1626 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1628 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1629 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1630 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1634 void wxWindowDC::SetLogicalFunction( int function
)
1636 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1638 if (m_logicalFunction
== function
)
1641 // VZ: shouldn't this be a CHECK?
1645 GdkFunction mode
= GDK_COPY
;
1648 case wxXOR
: mode
= GDK_XOR
; break;
1649 case wxINVERT
: mode
= GDK_INVERT
; break;
1650 #if (GTK_MINOR_VERSION > 0)
1651 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1652 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1653 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1654 case wxSET
: mode
= GDK_SET
; break;
1655 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1656 case wxAND
: mode
= GDK_AND
; break;
1657 case wxOR
: mode
= GDK_OR
; break;
1658 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1659 case wxNAND
: mode
= GDK_NAND
; break;
1660 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1661 case wxCOPY
: mode
= GDK_COPY
; break;
1662 case wxNO_OP
: mode
= GDK_NOOP
; break;
1663 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1665 // unsupported by GTK
1666 case wxNOR
: mode
= GDK_COPY
; break;
1670 wxFAIL_MSG( wxT("unsupported logical function") );
1675 m_logicalFunction
= function
;
1677 gdk_gc_set_function( m_penGC
, mode
);
1678 gdk_gc_set_function( m_brushGC
, mode
);
1680 // to stay compatible with wxMSW, we don't apply ROPs to the text
1681 // operations (i.e. DrawText/DrawRotatedText).
1682 // True, but mono-bitmaps use the m_textGC and they use ROPs as well.
1683 gdk_gc_set_function( m_textGC
, mode
);
1686 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1688 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1690 if (m_textForegroundColour
== col
) return;
1692 m_textForegroundColour
= col
;
1693 if (!m_textForegroundColour
.Ok()) return;
1695 if (!m_window
) return;
1697 m_textForegroundColour
.CalcPixel( m_cmap
);
1698 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1701 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1703 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1705 if (m_textBackgroundColour
== col
) return;
1707 m_textBackgroundColour
= col
;
1708 if (!m_textBackgroundColour
.Ok()) return;
1710 if (!m_window
) return;
1712 m_textBackgroundColour
.CalcPixel( m_cmap
);
1713 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1716 void wxWindowDC::SetBackgroundMode( int mode
)
1718 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1720 m_backgroundMode
= mode
;
1722 if (!m_window
) return;
1724 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1725 // transparent/solid background mode
1727 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1729 gdk_gc_set_fill( m_brushGC
,
1730 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1734 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1736 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1739 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1741 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1743 if (!m_window
) return;
1746 rect
.x
= XLOG2DEV(x
);
1747 rect
.y
= YLOG2DEV(y
);
1748 rect
.width
= XLOG2DEVREL(width
);
1749 rect
.height
= YLOG2DEVREL(height
);
1751 if (!m_currentClippingRegion
.IsNull())
1752 m_currentClippingRegion
.Intersect( rect
);
1754 m_currentClippingRegion
.Union( rect
);
1756 #if USE_PAINT_REGION
1757 if (!m_paintClippingRegion
.IsNull())
1758 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1761 wxCoord xx
, yy
, ww
, hh
;
1762 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1763 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1765 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1766 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1767 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1768 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1771 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1773 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1777 DestroyClippingRegion();
1781 if (!m_window
) return;
1783 if (!m_currentClippingRegion
.IsNull())
1784 m_currentClippingRegion
.Intersect( region
);
1786 m_currentClippingRegion
.Union( region
);
1788 #if USE_PAINT_REGION
1789 if (!m_paintClippingRegion
.IsNull())
1790 m_currentClippingRegion
.Intersect( m_paintClippingRegion
);
1793 wxCoord xx
, yy
, ww
, hh
;
1794 m_currentClippingRegion
.GetBox( xx
, yy
, ww
, hh
);
1795 wxDC::DoSetClippingRegion( xx
, yy
, ww
, hh
);
1797 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1798 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1799 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1800 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1803 void wxWindowDC::DestroyClippingRegion()
1805 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1807 wxDC::DestroyClippingRegion();
1809 m_currentClippingRegion
.Clear();
1811 #if USE_PAINT_REGION
1812 if (!m_paintClippingRegion
.IsEmpty())
1813 m_currentClippingRegion
.Union( m_paintClippingRegion
);
1816 if (!m_window
) return;
1818 if (m_currentClippingRegion
.IsEmpty())
1820 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1821 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1822 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1823 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1827 gdk_gc_set_clip_region( m_penGC
, m_currentClippingRegion
.GetRegion() );
1828 gdk_gc_set_clip_region( m_brushGC
, m_currentClippingRegion
.GetRegion() );
1829 gdk_gc_set_clip_region( m_textGC
, m_currentClippingRegion
.GetRegion() );
1830 gdk_gc_set_clip_region( m_bgGC
, m_currentClippingRegion
.GetRegion() );
1834 void wxWindowDC::Destroy()
1836 if (m_penGC
) wxFreePoolGC( m_penGC
);
1837 m_penGC
= (GdkGC
*) NULL
;
1838 if (m_brushGC
) wxFreePoolGC( m_brushGC
);
1839 m_brushGC
= (GdkGC
*) NULL
;
1840 if (m_textGC
) wxFreePoolGC( m_textGC
);
1841 m_textGC
= (GdkGC
*) NULL
;
1842 if (m_bgGC
) wxFreePoolGC( m_bgGC
);
1843 m_bgGC
= (GdkGC
*) NULL
;
1846 void wxWindowDC::ComputeScaleAndOrigin()
1848 /* CMB: copy scale to see if it changes */
1849 double origScaleX
= m_scaleX
;
1850 double origScaleY
= m_scaleY
;
1852 wxDC::ComputeScaleAndOrigin();
1854 /* CMB: if scale has changed call SetPen to recalulate the line width */
1855 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1858 /* this is a bit artificial, but we need to force wxDC to think
1859 the pen has changed */
1866 // Resolution in pixels per logical inch
1867 wxSize
wxWindowDC::GetPPI() const
1869 return wxSize(100, 100);
1872 int wxWindowDC::GetDepth() const
1874 wxFAIL_MSG(wxT("not implemented"));
1880 // ----------------------------------- spline code ----------------------------------------
1882 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1883 double a3
, double b3
, double a4
, double b4
);
1884 void wx_clear_stack();
1885 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1886 double *y3
, double *x4
, double *y4
);
1887 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1888 double x4
, double y4
);
1889 static bool wx_spline_add_point(double x
, double y
);
1890 static void wx_spline_draw_point_array(wxDC
*dc
);
1892 wxList wx_spline_point_list
;
1894 #define half(z1, z2) ((z1+z2)/2.0)
1897 /* iterative version */
1899 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1902 register double xmid
, ymid
;
1903 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1906 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1908 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1909 xmid
= (double)half(x2
, x3
);
1910 ymid
= (double)half(y2
, y3
);
1911 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1912 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1913 wx_spline_add_point( x1
, y1
);
1914 wx_spline_add_point( xmid
, ymid
);
1916 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1917 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1918 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1919 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1924 /* utilities used by spline drawing routines */
1926 typedef struct wx_spline_stack_struct
{
1927 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1930 #define SPLINE_STACK_DEPTH 20
1931 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1932 static Stack
*wx_stack_top
;
1933 static int wx_stack_count
;
1935 void wx_clear_stack()
1937 wx_stack_top
= wx_spline_stack
;
1941 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1943 wx_stack_top
->x1
= x1
;
1944 wx_stack_top
->y1
= y1
;
1945 wx_stack_top
->x2
= x2
;
1946 wx_stack_top
->y2
= y2
;
1947 wx_stack_top
->x3
= x3
;
1948 wx_stack_top
->y3
= y3
;
1949 wx_stack_top
->x4
= x4
;
1950 wx_stack_top
->y4
= y4
;
1955 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1956 double *x3
, double *y3
, double *x4
, double *y4
)
1958 if (wx_stack_count
== 0)
1962 *x1
= wx_stack_top
->x1
;
1963 *y1
= wx_stack_top
->y1
;
1964 *x2
= wx_stack_top
->x2
;
1965 *y2
= wx_stack_top
->y2
;
1966 *x3
= wx_stack_top
->x3
;
1967 *y3
= wx_stack_top
->y3
;
1968 *x4
= wx_stack_top
->x4
;
1969 *y4
= wx_stack_top
->y4
;
1973 static bool wx_spline_add_point(double x
, double y
)
1975 wxPoint
*point
= new wxPoint
;
1978 wx_spline_point_list
.Append((wxObject
*)point
);
1982 static void wx_spline_draw_point_array(wxDC
*dc
)
1984 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1985 wxNode
*node
= wx_spline_point_list
.First();
1988 wxPoint
*point
= (wxPoint
*)node
->Data();
1991 node
= wx_spline_point_list
.First();
1995 void wxWindowDC::DoDrawSpline( wxList
*points
)
1997 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2000 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
2001 double x1
, y1
, x2
, y2
;
2003 wxNode
*node
= points
->First();
2004 p
= (wxPoint
*)node
->Data();
2009 node
= node
->Next();
2010 p
= (wxPoint
*)node
->Data();
2014 cx1
= (double)((x1
+ x2
) / 2);
2015 cy1
= (double)((y1
+ y2
) / 2);
2016 cx2
= (double)((cx1
+ x2
) / 2);
2017 cy2
= (double)((cy1
+ y2
) / 2);
2019 wx_spline_add_point(x1
, y1
);
2021 while ((node
= node
->Next()) != NULL
)
2023 p
= (wxPoint
*)node
->Data();
2028 cx4
= (double)(x1
+ x2
) / 2;
2029 cy4
= (double)(y1
+ y2
) / 2;
2030 cx3
= (double)(x1
+ cx4
) / 2;
2031 cy3
= (double)(y1
+ cy4
) / 2;
2033 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
2037 cx2
= (double)(cx1
+ x2
) / 2;
2038 cy2
= (double)(cy1
+ y2
) / 2;
2041 wx_spline_add_point( cx1
, cy1
);
2042 wx_spline_add_point( x2
, y2
);
2044 wx_spline_draw_point_array( this );
2047 #endif // wxUSE_SPLINE
2049 //-----------------------------------------------------------------------------
2051 //-----------------------------------------------------------------------------
2053 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
2055 wxPaintDC::wxPaintDC()
2060 wxPaintDC::wxPaintDC( wxWindow
*win
)
2063 #if USE_PAINT_REGION
2064 if (!win
->m_clipPaintRegion
)
2067 m_paintClippingRegion
= win
->GetUpdateRegion();
2068 GdkRegion
*region
= m_paintClippingRegion
.GetRegion();
2071 m_currentClippingRegion
.Union( m_paintClippingRegion
);
2073 gdk_gc_set_clip_region( m_penGC
, region
);
2074 gdk_gc_set_clip_region( m_brushGC
, region
);
2075 gdk_gc_set_clip_region( m_textGC
, region
);
2076 gdk_gc_set_clip_region( m_bgGC
, region
);
2081 //-----------------------------------------------------------------------------
2083 //-----------------------------------------------------------------------------
2085 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
2087 wxClientDC::wxClientDC()
2092 wxClientDC::wxClientDC( wxWindow
*win
)
2097 // ----------------------------------------------------------------------------
2099 // ----------------------------------------------------------------------------
2101 class wxDCModule
: public wxModule
2108 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2111 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2113 bool wxDCModule::OnInit()
2119 void wxDCModule::OnExit()