1 /////////////////////////////////////////////////////////////////////////////
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/gtk/win_gtk.h"
18 #include <math.h> // for floating-point functions
23 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
35 static GdkPixmap
*hatches
[num_hatches
];
36 static GdkPixmap
**hatch_bitmap
= (GdkPixmap
**) NULL
;
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
42 #define RAD2DEG 57.2957795131
44 //-----------------------------------------------------------------------------
45 // temporary implementation of the missing GDK function
46 //-----------------------------------------------------------------------------
48 #include "gdk/gdkprivate.h"
50 void gdk_draw_bitmap (GdkDrawable
*drawable
,
60 GdkWindowPrivate
*drawable_private
;
61 GdkWindowPrivate
*src_private
;
62 GdkGCPrivate
*gc_private
;
64 g_return_if_fail (drawable
!= NULL
);
65 g_return_if_fail (src
!= NULL
);
66 g_return_if_fail (gc
!= NULL
);
68 drawable_private
= (GdkWindowPrivate
*) drawable
;
69 src_private
= (GdkWindowPrivate
*) src
;
70 if (drawable_private
->destroyed
|| src_private
->destroyed
)
73 gc_private
= (GdkGCPrivate
*) gc
;
75 if (width
== -1) width
= src_private
->width
;
76 if (height
== -1) height
= src_private
->height
;
78 XCopyPlane( drawable_private
->xdisplay
,
80 drawable_private
->xwindow
,
88 //-----------------------------------------------------------------------------
90 //-----------------------------------------------------------------------------
92 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
94 wxWindowDC::wxWindowDC()
96 m_penGC
= (GdkGC
*) NULL
;
97 m_brushGC
= (GdkGC
*) NULL
;
98 m_textGC
= (GdkGC
*) NULL
;
99 m_bgGC
= (GdkGC
*) NULL
;
100 m_cmap
= (GdkColormap
*) NULL
;
102 m_owner
= (wxWindow
*)NULL
;
105 wxWindowDC::wxWindowDC( wxWindow
*window
)
107 m_penGC
= (GdkGC
*) NULL
;
108 m_brushGC
= (GdkGC
*) NULL
;
109 m_textGC
= (GdkGC
*) NULL
;
110 m_bgGC
= (GdkGC
*) NULL
;
111 m_cmap
= (GdkColormap
*) NULL
;
112 m_owner
= (wxWindow
*)NULL
;
114 m_font
= window
->GetFont();
116 wxASSERT_MSG( window
, wxT("DC needs a window") );
118 GtkWidget
*widget
= window
->m_wxwindow
;
120 wxASSERT_MSG( widget
, wxT("DC needs a widget") );
122 GtkMyFixed
*myfixed
= GTK_MYFIXED( widget
);
123 m_window
= myfixed
->bin_window
;
128 /* don't report problems */
134 if (window
->m_wxwindow
)
135 m_cmap
= gtk_widget_get_colormap( window
->m_wxwindow
);
137 m_cmap
= gtk_widget_get_colormap( window
->m_widget
);
141 /* this must be done after SetUpDC, bacause SetUpDC calls the
142 repective SetBrush, SetPen, SetBackground etc functions
143 to set up the DC. SetBackground call m_owner->SetBackground
144 and this might not be desired as the standard dc background
145 is white whereas a window might assume gray to be the
146 standard (as e.g. wxStatusBar) */
151 wxWindowDC::~wxWindowDC()
156 void wxWindowDC::DoFloodFill( wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
157 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
159 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
162 bool wxWindowDC::DoGetPixel( wxCoord
WXUNUSED(x1
), wxCoord
WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
164 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
168 void wxWindowDC::DoDrawLine( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
170 wxCHECK_RET( Ok(), wxT("invalid window dc") );
172 if (m_pen
.GetStyle() != wxTRANSPARENT
)
175 gdk_draw_line( m_window
, m_penGC
, XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
) );
177 CalcBoundingBox(x1
, y1
);
178 CalcBoundingBox(x2
, y2
);
182 void wxWindowDC::DoCrossHair( wxCoord x
, wxCoord y
)
184 wxCHECK_RET( Ok(), wxT("invalid window dc") );
186 if (m_pen
.GetStyle() != wxTRANSPARENT
)
191 wxCoord xx
= XLOG2DEV(x
);
192 wxCoord yy
= YLOG2DEV(y
);
195 gdk_draw_line( m_window
, m_penGC
, 0, yy
, XLOG2DEVREL(w
), yy
);
196 gdk_draw_line( m_window
, m_penGC
, xx
, 0, xx
, YLOG2DEVREL(h
) );
201 void wxWindowDC::DoDrawArc( wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
,
202 wxCoord xc
, wxCoord yc
)
204 wxCHECK_RET( Ok(), wxT("invalid window dc") );
206 wxCoord xx1
= XLOG2DEV(x1
);
207 wxCoord yy1
= YLOG2DEV(y1
);
208 wxCoord xx2
= XLOG2DEV(x2
);
209 wxCoord yy2
= YLOG2DEV(y2
);
210 wxCoord xxc
= XLOG2DEV(xc
);
211 wxCoord yyc
= YLOG2DEV(yc
);
212 double dx
= xx1
- xxc
;
213 double dy
= yy1
- yyc
;
214 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
215 wxCoord r
= (wxCoord
)radius
;
216 double radius1
, radius2
;
218 if (xx1
== xx2
&& yy1
== yy2
)
226 radius1
= radius2
= 0.0;
230 radius1
= (xx1
- xxc
== 0) ?
231 (yy1
- yyc
< 0) ? 90.0 : -90.0 :
232 -atan2(double(yy1
-yyc
), double(xx1
-xxc
)) * RAD2DEG
;
233 radius2
= (xx2
- xxc
== 0) ?
234 (yy2
- yyc
< 0) ? 90.0 : -90.0 :
235 -atan2(double(yy2
-yyc
), double(xx2
-xxc
)) * RAD2DEG
;
237 wxCoord alpha1
= wxCoord(radius1
* 64.0);
238 wxCoord alpha2
= wxCoord((radius2
- radius1
) * 64.0);
239 while (alpha2
<= 0) alpha2
+= 360*64;
240 while (alpha1
> 360*64) alpha1
-= 360*64;
244 if (m_brush
.GetStyle() != wxTRANSPARENT
)
245 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
247 if (m_pen
.GetStyle() != wxTRANSPARENT
)
248 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xxc
-r
, yyc
-r
, 2*r
,2*r
, alpha1
, alpha2
);
251 CalcBoundingBox (x1
, y1
);
252 CalcBoundingBox (x2
, y2
);
255 void wxWindowDC::DoDrawEllipticArc( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double sa
, double ea
)
257 wxCHECK_RET( Ok(), wxT("invalid window dc") );
259 wxCoord xx
= XLOG2DEV(x
);
260 wxCoord yy
= YLOG2DEV(y
);
261 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
262 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
264 // CMB: handle -ve width and/or height
265 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
266 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
270 wxCoord start
= wxCoord(sa
* 64.0);
271 wxCoord end
= wxCoord(ea
* 64.0);
273 if (m_brush
.GetStyle() != wxTRANSPARENT
)
274 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, start
, end
);
276 if (m_pen
.GetStyle() != wxTRANSPARENT
)
277 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, start
, end
);
280 CalcBoundingBox (x
, y
);
281 CalcBoundingBox (x
+ width
, y
+ height
);
284 void wxWindowDC::DoDrawPoint( wxCoord x
, wxCoord y
)
286 wxCHECK_RET( Ok(), wxT("invalid window dc") );
288 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
289 gdk_draw_point( m_window
, m_penGC
, XLOG2DEV(x
), YLOG2DEV(y
) );
291 CalcBoundingBox (x
, y
);
294 void wxWindowDC::DoDrawLines( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
296 wxCHECK_RET( Ok(), wxT("invalid window dc") );
298 if (m_pen
.GetStyle() == wxTRANSPARENT
) return;
301 CalcBoundingBox( points
[0].x
+ xoffset
, points
[0].y
+ yoffset
);
303 for (int i
= 0; i
< n
-1; i
++)
305 wxCoord x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
306 wxCoord x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
307 wxCoord y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
308 wxCoord y2
= YLOG2DEV(points
[i
+1].y
+ yoffset
);
311 gdk_draw_line( m_window
, m_penGC
, x1
, y1
, x2
, y2
);
313 CalcBoundingBox( points
[i
+1].x
+ xoffset
, points
[i
+1].y
+ yoffset
);
317 void wxWindowDC::DoDrawPolygon( int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
, int WXUNUSED(fillStyle
) )
319 wxCHECK_RET( Ok(), wxT("invalid window dc") );
323 GdkPoint
*gdkpoints
= new GdkPoint
[n
+1];
325 for (i
= 0 ; i
< n
; i
++)
327 gdkpoints
[i
].x
= XLOG2DEV(points
[i
].x
+ xoffset
);
328 gdkpoints
[i
].y
= YLOG2DEV(points
[i
].y
+ yoffset
);
330 CalcBoundingBox( points
[i
].x
+ xoffset
, points
[i
].y
+ yoffset
);
333 if ((m_brush
.GetStyle() != wxTRANSPARENT
) && m_window
)
334 gdk_draw_polygon (m_window
, m_brushGC
, TRUE
, gdkpoints
, n
);
338 if ((m_pen
.GetStyle() != wxTRANSPARENT
) && m_window
)
340 for (i
= 0 ; i
< n
; i
++)
342 gdk_draw_line( m_window
, m_penGC
,
345 gdkpoints
[(i
+1)%n
].x
,
346 gdkpoints
[(i
+1)%n
].y
);
353 void wxWindowDC::DoDrawRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
355 wxCHECK_RET( Ok(), wxT("invalid window dc") );
357 wxCoord xx
= XLOG2DEV(x
);
358 wxCoord yy
= YLOG2DEV(y
);
359 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
360 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
362 // CMB: draw nothing if transformed w or h is 0
363 if (ww
== 0 || hh
== 0) return;
365 // CMB: handle -ve width and/or height
366 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
367 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
371 if (m_brush
.GetStyle() != wxTRANSPARENT
)
372 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
);
374 if (m_pen
.GetStyle() != wxTRANSPARENT
)
375 gdk_draw_rectangle( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
-1, hh
-1 );
378 CalcBoundingBox( x
, y
);
379 CalcBoundingBox( x
+ width
, y
+ height
);
382 void wxWindowDC::DoDrawRoundedRectangle( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
384 wxCHECK_RET( Ok(), wxT("invalid window dc") );
386 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
388 wxCoord xx
= XLOG2DEV(x
);
389 wxCoord yy
= YLOG2DEV(y
);
390 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
391 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
392 wxCoord rr
= XLOG2DEVREL((wxCoord
)radius
);
394 // CMB: handle -ve width and/or height
395 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
396 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
398 // CMB: if radius is zero use DrawRectangle() instead to avoid
399 // X drawing errors with small radii
402 DrawRectangle( x
, y
, width
, height
);
406 // CMB: draw nothing if transformed w or h is 0
407 if (ww
== 0 || hh
== 0) return;
409 // CMB: adjust size if outline is drawn otherwise the result is
410 // 1 pixel too wide and high
411 if (m_pen
.GetStyle() != wxTRANSPARENT
)
419 // CMB: ensure dd is not larger than rectangle otherwise we
420 // get an hour glass shape
422 if (dd
> ww
) dd
= ww
;
423 if (dd
> hh
) dd
= hh
;
426 if (m_brush
.GetStyle() != wxTRANSPARENT
)
428 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
+rr
, yy
, ww
-dd
+1, hh
);
429 gdk_draw_rectangle( m_window
, m_brushGC
, TRUE
, xx
, yy
+rr
, ww
, hh
-dd
+1 );
430 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
431 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
432 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
433 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
436 if (m_pen
.GetStyle() != wxTRANSPARENT
)
438 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
, xx
+ww
-rr
, yy
);
439 gdk_draw_line( m_window
, m_penGC
, xx
+rr
, yy
+hh
, xx
+ww
-rr
, yy
+hh
);
440 gdk_draw_line( m_window
, m_penGC
, xx
, yy
+rr
, xx
, yy
+hh
-rr
);
441 gdk_draw_line( m_window
, m_penGC
, xx
+ww
, yy
+rr
, xx
+ww
, yy
+hh
-rr
);
442 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, dd
, dd
, 90*64, 90*64 );
443 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
, dd
, dd
, 0, 90*64 );
444 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
+ww
-dd
, yy
+hh
-dd
, dd
, dd
, 270*64, 90*64 );
445 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
+hh
-dd
, dd
, dd
, 180*64, 90*64 );
449 // this ignores the radius
450 CalcBoundingBox( x
, y
);
451 CalcBoundingBox( x
+ width
, y
+ height
);
454 void wxWindowDC::DoDrawEllipse( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
456 wxCHECK_RET( Ok(), wxT("invalid window dc") );
458 wxCoord xx
= XLOG2DEV(x
);
459 wxCoord yy
= YLOG2DEV(y
);
460 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
461 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
463 // CMB: handle -ve width and/or height
464 if (ww
< 0) { ww
= -ww
; xx
= xx
- ww
; }
465 if (hh
< 0) { hh
= -hh
; yy
= yy
- hh
; }
469 if (m_brush
.GetStyle() != wxTRANSPARENT
)
470 gdk_draw_arc( m_window
, m_brushGC
, TRUE
, xx
, yy
, ww
, hh
, 0, 360*64 );
472 if (m_pen
.GetStyle() != wxTRANSPARENT
)
473 gdk_draw_arc( m_window
, m_penGC
, FALSE
, xx
, yy
, ww
, hh
, 0, 360*64 );
476 CalcBoundingBox( x
- width
, y
- height
);
477 CalcBoundingBox( x
+ width
, y
+ height
);
480 void wxWindowDC::DoDrawIcon( const wxIcon
&icon
, wxCoord x
, wxCoord y
)
482 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
483 DoDrawBitmap( (const wxBitmap
&)icon
, x
, y
, (bool)TRUE
);
486 void wxWindowDC::DoDrawBitmap( const wxBitmap
&bitmap
,
487 wxCoord x
, wxCoord y
,
490 wxCHECK_RET( Ok(), wxT("invalid window dc") );
492 wxCHECK_RET( bitmap
.Ok(), wxT("invalid bitmap") );
494 /* scale/translate size and position */
496 int xx
= XLOG2DEV(x
);
497 int yy
= YLOG2DEV(y
);
499 int w
= bitmap
.GetWidth();
500 int h
= bitmap
.GetHeight();
502 CalcBoundingBox( x
, y
);
503 CalcBoundingBox( x
+ w
, y
+ h
);
505 if (!m_window
) return;
507 int ww
= XLOG2DEVREL(w
);
508 int hh
= YLOG2DEVREL(h
);
510 /* scale bitmap if required */
514 if ((w
!= ww
) || (h
!= hh
))
516 wxImage
image( bitmap
);
517 image
= image
.Scale( ww
, hh
);
519 use_bitmap
= image
.ConvertToBitmap();
526 /* apply mask if any */
528 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
529 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
533 gdk_gc_set_clip_mask( m_penGC
, mask
);
534 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
537 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
539 GdkPixmap
*pm
= use_bitmap
.GetPixmap();
542 gdk_draw_pixmap( m_window
, m_penGC
, pm
, 0, 0, xx
, yy
, -1, -1 );
546 GdkBitmap
*bm
= use_bitmap
.GetBitmap();
549 gdk_draw_bitmap( m_window
, m_penGC
, bm
, 0, 0, xx
, yy
, -1, -1 );
553 /* remove mask again if any */
557 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
558 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
562 bool wxWindowDC::DoBlit( wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
563 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
564 int logical_func
, bool useMask
)
566 /* this is the nth try to get this utterly useless function to
567 work. it now completely ignores the scaling or translation
568 of the source dc, but scales correctly on the target dc and
569 knows about possible mask information in a memory dc. */
571 wxCHECK_MSG( Ok(), FALSE
, wxT("invalid window dc") );
573 wxCHECK_MSG( source
, FALSE
, wxT("invalid source dc") );
575 if (!m_window
) return FALSE
;
577 wxClientDC
*srcDC
= (wxClientDC
*)source
;
578 wxMemoryDC
*memDC
= (wxMemoryDC
*)source
;
580 bool use_bitmap_method
= FALSE
;
582 if (srcDC
->m_isMemDC
)
584 if (!memDC
->m_selected
.Ok()) return FALSE
;
586 /* we use the "XCopyArea" way to copy a memory dc into
587 y different window if the memory dc BOTH
588 a) doesn't have any mask or its mask isn't used
592 if (useMask
&& (memDC
->m_selected
.GetMask()))
594 /* we HAVE TO use the direct way for memory dcs
595 that have mask since the XCopyArea doesn't know
597 use_bitmap_method
= TRUE
;
599 else if (memDC
->m_selected
.GetDepth() == 1)
601 /* we HAVE TO use the direct way for memory dcs
602 that are bitmaps because XCopyArea doesn't cope
603 with different bit depths */
604 use_bitmap_method
= TRUE
;
606 else if ((xsrc
== 0) && (ysrc
== 0) &&
607 (width
== memDC
->m_selected
.GetWidth()) &&
608 (height
== memDC
->m_selected
.GetHeight()))
610 /* we SHOULD use the direct way if all of the bitmap
611 in the memory dc is copied in which case XCopyArea
612 wouldn't be able able to boost performace by reducing
613 the area to be scaled */
614 use_bitmap_method
= TRUE
;
618 use_bitmap_method
= FALSE
;
622 CalcBoundingBox( xdest
, ydest
);
623 CalcBoundingBox( xdest
+ width
, ydest
+ height
);
625 int old_logical_func
= m_logicalFunction
;
626 SetLogicalFunction( logical_func
);
628 if (use_bitmap_method
)
630 /* scale/translate bitmap size */
632 wxCoord bm_width
= memDC
->m_selected
.GetWidth();
633 wxCoord bm_height
= memDC
->m_selected
.GetHeight();
635 wxCoord bm_ww
= XLOG2DEVREL( bm_width
);
636 wxCoord bm_hh
= YLOG2DEVREL( bm_height
);
638 /* scale bitmap if required */
642 if ((bm_width
!= bm_ww
) || (bm_height
!= bm_hh
))
644 wxImage
image( memDC
->m_selected
);
645 image
= image
.Scale( bm_ww
, bm_hh
);
647 use_bitmap
= image
.ConvertToBitmap();
651 use_bitmap
= memDC
->m_selected
;
654 /* scale/translate size and position */
656 wxCoord xx
= XLOG2DEV(xdest
);
657 wxCoord yy
= YLOG2DEV(ydest
);
659 wxCoord ww
= XLOG2DEVREL(width
);
660 wxCoord hh
= YLOG2DEVREL(height
);
662 /* apply mask if any */
664 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
665 if (use_bitmap
.GetMask()) mask
= use_bitmap
.GetMask()->GetBitmap();
669 gdk_gc_set_clip_mask( m_penGC
, mask
);
670 gdk_gc_set_clip_origin( m_penGC
, xx
, yy
);
673 /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */
675 GdkPixmap
*pm
= use_bitmap
.GetPixmap();
678 gdk_draw_pixmap( m_window
, m_penGC
, pm
, xsrc
, ysrc
, xx
, yy
, ww
, hh
);
682 GdkBitmap
*bm
= use_bitmap
.GetBitmap();
685 /* we use the textGC here because blitting a bitmap is done
686 using the current text colour */
687 gdk_draw_bitmap( m_window
, m_textGC
, bm
, xsrc
, ysrc
, xx
, yy
, ww
, hh
);
691 /* remove mask again if any */
695 gdk_gc_set_clip_mask( m_penGC
, (GdkBitmap
*) NULL
);
696 gdk_gc_set_clip_origin( m_penGC
, 0, 0 );
699 else /* use_bitmap_method */
701 /* scale/translate size and position */
703 wxCoord xx
= XLOG2DEV(xdest
);
704 wxCoord yy
= YLOG2DEV(ydest
);
706 wxCoord ww
= XLOG2DEVREL(width
);
707 wxCoord hh
= YLOG2DEVREL(height
);
709 if ((width
!= ww
) || (height
!= hh
))
711 /* draw source window into a bitmap as we cannot scale
712 a window in contrast to a bitmap. this would actually
713 work with memory dcs as well, but we'd lose the mask
714 information and waste one step in this process since
715 a memory already has a bitmap. all this is slightly
716 inefficient as we could take an XImage directly from
717 an X window, but we'd then also have to care that
718 the window is not outside the screen (in which case
719 we'd get a BadMatch or what not).
720 Is a double XGetImage and combined XGetPixel and
721 XPutPixel really faster? I'm not sure. look at wxXt
722 for a different implementation of the same problem. */
724 wxBitmap
bitmap( width
, height
);
725 gdk_window_copy_area( bitmap
.GetPixmap(), m_penGC
, 0, 0,
727 xsrc
, ysrc
, width
, height
);
731 wxImage
image( bitmap
);
732 image
= image
.Scale( ww
, hh
);
734 /* convert to bitmap */
736 bitmap
= image
.ConvertToBitmap();
738 /* draw scaled bitmap */
740 gdk_draw_pixmap( m_window
, m_penGC
, bitmap
.GetPixmap(), 0, 0, xx
, yy
, -1, -1 );
745 /* no scaling and not a memory dc with a mask either */
747 gdk_window_copy_area( m_window
, m_penGC
, xx
, yy
,
749 xsrc
, ysrc
, width
, height
);
753 SetLogicalFunction( old_logical_func
);
757 void wxWindowDC::DoDrawText( const wxString
&text
, wxCoord x
, wxCoord y
)
759 wxCHECK_RET( Ok(), wxT("invalid window dc") );
761 if (!m_window
) return;
763 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
765 wxCHECK_RET( font
, wxT("invalid font") );
770 /* CMB 21/5/98: draw text background if mode is wxSOLID */
771 if (m_backgroundMode
== wxSOLID
)
773 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
774 wxCoord height
= font
->ascent
+ font
->descent
;
775 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
776 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
777 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
779 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
781 /* CMB 17/7/98: simple underline: ignores scaling and underlying
782 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
783 properties (see wxXt implementation) */
784 if (m_font
.GetUnderlined())
786 wxCoord width
= gdk_string_width( font
, text
.mbc_str() );
787 wxCoord ul_y
= y
+ font
->ascent
;
788 if (font
->descent
> 0) ul_y
++;
789 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
793 GetTextExtent (text
, &w
, &h
);
794 CalcBoundingBox (x
+ w
, y
+ h
);
795 CalcBoundingBox (x
, y
);
798 void wxWindowDC::DoGetTextExtent(const wxString
&string
,
799 wxCoord
*width
, wxCoord
*height
,
800 wxCoord
*descent
, wxCoord
*externalLeading
,
801 wxFont
*theFont
) const
803 wxFont fontToUse
= m_font
;
804 if (theFont
) fontToUse
= *theFont
;
806 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
807 if (width
) (*width
) = wxCoord(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
808 if (height
) (*height
) = wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
809 if (descent
) (*descent
) = wxCoord(font
->descent
/ m_scaleY
);
810 if (externalLeading
) (*externalLeading
) = 0; // ??
813 wxCoord
wxWindowDC::GetCharWidth() const
815 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
816 return wxCoord(gdk_string_width( font
, "H" ) / m_scaleX
);
819 wxCoord
wxWindowDC::GetCharHeight() const
821 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
822 return wxCoord((font
->ascent
+ font
->descent
) / m_scaleY
);
825 void wxWindowDC::Clear()
827 wxCHECK_RET( Ok(), wxT("invalid window dc") );
829 if (!m_window
) return;
831 /* - we either are a memory dc or have a window as the
832 owner. anything else shouldn't happen.
833 - we don't use gdk_window_clear() as we don't set
834 the window's background colour anymore. it is too
835 much pain to keep the DC's and the window's back-
836 ground colour in synch. */
841 m_owner
->GetSize( &width
, &height
);
842 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
849 GetSize( &width
, &height
);
850 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
855 void wxWindowDC::SetFont( const wxFont
&font
)
860 void wxWindowDC::SetPen( const wxPen
&pen
)
862 wxCHECK_RET( Ok(), wxT("invalid window dc") );
864 if (m_pen
== pen
) return;
868 if (!m_pen
.Ok()) return;
870 if (!m_window
) return;
872 gint width
= m_pen
.GetWidth();
875 // CMB: if width is non-zero scale it with the dc
880 // X doesn't allow different width in x and y and so we take
883 ( fabs((double) XLOG2DEVREL(width
)) +
884 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
888 static const char dotted
[] = {1, 1};
889 static const char short_dashed
[] = {2, 2};
890 static const char wxCoord_dashed
[] = {2, 4};
891 static const char dotted_dashed
[] = {3, 3, 1, 3};
893 // We express dash pattern in pen width unit, so we are
894 // independent of zoom factor and so on...
896 const char *req_dash
;
898 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
899 switch (m_pen
.GetStyle())
903 lineStyle
= GDK_LINE_ON_OFF_DASH
;
904 req_nb_dash
= m_pen
.GetDashCount();
905 req_dash
= m_pen
.GetDash();
910 lineStyle
= GDK_LINE_ON_OFF_DASH
;
917 lineStyle
= GDK_LINE_ON_OFF_DASH
;
919 req_dash
= wxCoord_dashed
;
924 lineStyle
= GDK_LINE_ON_OFF_DASH
;
926 req_dash
= short_dashed
;
931 // lineStyle = GDK_LINE_DOUBLE_DASH;
932 lineStyle
= GDK_LINE_ON_OFF_DASH
;
934 req_dash
= dotted_dashed
;
943 lineStyle
= GDK_LINE_SOLID
;
944 req_dash
= (wxDash
*)NULL
;
950 #if (GTK_MINOR_VERSION > 0)
951 if (req_dash
&& req_nb_dash
)
953 char *real_req_dash
= new char[req_nb_dash
];
956 for (int i
= 0; i
< req_nb_dash
; i
++)
957 real_req_dash
[i
] = req_dash
[i
] * width
;
958 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
959 delete[] real_req_dash
;
963 // No Memory. We use non-scaled dash pattern...
964 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
969 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
970 switch (m_pen
.GetCap())
972 case wxCAP_ROUND
: { capStyle
= (width
<= 1) ? GDK_CAP_NOT_LAST
: GDK_CAP_ROUND
; break; }
973 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
974 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
977 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
978 switch (m_pen
.GetJoin())
980 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
981 case wxJOIN_ROUND
: { joinStyle
= GDK_JOIN_ROUND
; break; }
982 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
985 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
987 m_pen
.GetColour().CalcPixel( m_cmap
);
988 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
991 void wxWindowDC::SetBrush( const wxBrush
&brush
)
993 wxCHECK_RET( Ok(), wxT("invalid window dc") );
995 if (m_brush
== brush
) return;
999 if (!m_brush
.Ok()) return;
1001 if (!m_window
) return;
1003 m_brush
.GetColour().CalcPixel( m_cmap
);
1004 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1006 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1008 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1010 if (m_brush
.GetStipple()->GetPixmap())
1012 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1013 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1017 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1018 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1022 if (IS_HATCH(m_brush
.GetStyle()))
1024 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1025 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1026 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1030 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1032 /* CMB 21/7/98: Added SetBackground. Sets background brush
1033 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1035 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1037 if (m_backgroundBrush
== brush
) return;
1039 m_backgroundBrush
= brush
;
1041 if (!m_backgroundBrush
.Ok()) return;
1043 if (!m_window
) return;
1045 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1046 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1047 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1048 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1049 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1051 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1053 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1055 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1057 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1058 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1062 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1063 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1067 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1069 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1070 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1071 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1075 void wxWindowDC::SetLogicalFunction( int function
)
1077 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1079 if (m_logicalFunction
== function
) return;
1081 GdkFunction mode
= GDK_COPY
;
1084 case wxXOR
: mode
= GDK_XOR
; break;
1085 case wxINVERT
: mode
= GDK_INVERT
; break;
1086 #if (GTK_MINOR_VERSION > 0)
1087 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1088 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1089 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1090 case wxSET
: mode
= GDK_SET
; break;
1091 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1093 case wxAND
: mode
= GDK_AND
; break;
1095 case wxOR
: mode
= GDK_OR
; break;
1096 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1097 case wxNAND
: mode
= GDK_NAND
; break;
1098 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1099 case wxCOPY
: mode
= GDK_COPY
; break;
1100 case wxNO_OP
: mode
= GDK_NOOP
; break;
1101 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1105 wxFAIL_MSG( wxT("unsupported logical function") );
1110 m_logicalFunction
= function
;
1112 if (!m_window
) return;
1114 gdk_gc_set_function( m_penGC
, mode
);
1115 gdk_gc_set_function( m_brushGC
, mode
);
1116 gdk_gc_set_function( m_textGC
, mode
);
1119 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1121 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1123 if (m_textForegroundColour
== col
) return;
1125 m_textForegroundColour
= col
;
1126 if (!m_textForegroundColour
.Ok()) return;
1128 if (!m_window
) return;
1130 m_textForegroundColour
.CalcPixel( m_cmap
);
1131 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1134 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1136 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1138 if (m_textBackgroundColour
== col
) return;
1140 m_textBackgroundColour
= col
;
1141 if (!m_textBackgroundColour
.Ok()) return;
1143 if (!m_window
) return;
1145 m_textBackgroundColour
.CalcPixel( m_cmap
);
1146 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1149 void wxWindowDC::SetBackgroundMode( int mode
)
1151 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1153 m_backgroundMode
= mode
;
1155 if (!m_window
) return;
1157 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1158 // transparent/solid background mode
1160 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1162 gdk_gc_set_fill( m_brushGC
,
1163 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1167 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1169 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1172 void wxWindowDC::DoSetClippingRegion( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1174 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1176 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1178 if (!m_window
) return;
1181 rect
.x
= XLOG2DEV(x
);
1182 rect
.y
= YLOG2DEV(y
);
1183 rect
.width
= XLOG2DEVREL(width
);
1184 rect
.height
= YLOG2DEVREL(height
);
1185 gdk_gc_set_clip_rectangle( m_penGC
, &rect
);
1186 gdk_gc_set_clip_rectangle( m_brushGC
, &rect
);
1187 gdk_gc_set_clip_rectangle( m_textGC
, &rect
);
1188 gdk_gc_set_clip_rectangle( m_bgGC
, &rect
);
1191 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1193 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1197 DestroyClippingRegion();
1201 if (!m_window
) return;
1203 gdk_gc_set_clip_region( m_penGC
, region
.GetRegion() );
1204 gdk_gc_set_clip_region( m_brushGC
, region
.GetRegion() );
1205 gdk_gc_set_clip_region( m_textGC
, region
.GetRegion() );
1206 gdk_gc_set_clip_region( m_bgGC
, region
.GetRegion() );
1209 void wxWindowDC::DestroyClippingRegion()
1211 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1213 wxDC::DestroyClippingRegion();
1215 if (!m_window
) return;
1217 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1218 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1219 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1220 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1223 void wxWindowDC::SetUpDC()
1227 m_logicalFunction
= wxCOPY
;
1228 m_penGC
= gdk_gc_new( m_window
);
1229 m_brushGC
= gdk_gc_new( m_window
);
1230 m_textGC
= gdk_gc_new( m_window
);
1231 m_bgGC
= gdk_gc_new( m_window
);
1233 wxColour
tmp_col( m_textForegroundColour
);
1234 m_textForegroundColour
= wxNullColour
;
1235 SetTextForeground( tmp_col
);
1236 tmp_col
= m_textBackgroundColour
;
1237 m_textBackgroundColour
= wxNullColour
;
1238 SetTextBackground( tmp_col
);
1240 wxPen
tmp_pen( m_pen
);
1244 wxFont
tmp_font( m_font
);
1245 m_font
= wxNullFont
;
1246 SetFont( tmp_font
);
1248 wxBrush
tmp_brush( m_brush
);
1249 m_brush
= wxNullBrush
;
1250 SetBrush( tmp_brush
);
1253 tmp_brush = m_backgroundBrush;
1254 m_backgroundBrush = wxNullBrush;
1255 SetBackground( tmp_brush );
1257 tmp_brush
= m_backgroundBrush
;
1258 m_backgroundBrush
= wxNullBrush
;
1259 SetBackground( *wxWHITE_BRUSH
);
1260 m_backgroundBrush
= tmp_brush
;
1264 hatch_bitmap
= hatches
;
1265 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1266 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1267 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1268 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1269 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1270 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1274 void wxWindowDC::Destroy()
1276 if (m_penGC
) gdk_gc_unref( m_penGC
);
1277 m_penGC
= (GdkGC
*) NULL
;
1278 if (m_brushGC
) gdk_gc_unref( m_brushGC
);
1279 m_brushGC
= (GdkGC
*) NULL
;
1280 if (m_textGC
) gdk_gc_unref( m_textGC
);
1281 m_textGC
= (GdkGC
*) NULL
;
1282 if (m_bgGC
) gdk_gc_unref( m_bgGC
);
1283 m_bgGC
= (GdkGC
*) NULL
;
1286 void wxWindowDC::ComputeScaleAndOrigin()
1288 /* CMB: copy scale to see if it changes */
1289 double origScaleX
= m_scaleX
;
1290 double origScaleY
= m_scaleY
;
1292 wxDC::ComputeScaleAndOrigin();
1294 /* CMB: if scale has changed call SetPen to recalulate the line width */
1295 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1298 /* this is a bit artificial, but we need to force wxDC to think
1299 the pen has changed */
1306 // Resolution in pixels per logical inch
1307 wxSize
wxWindowDC::GetPPI() const
1309 return wxSize(100, 100);
1312 int wxWindowDC::GetDepth() const
1314 wxFAIL_MSG(wxT("not implemented"));
1320 // ----------------------------------- spline code ----------------------------------------
1322 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1323 double a3
, double b3
, double a4
, double b4
);
1324 void wx_clear_stack();
1325 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1326 double *y3
, double *x4
, double *y4
);
1327 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1328 double x4
, double y4
);
1329 static bool wx_spline_add_point(double x
, double y
);
1330 static void wx_spline_draw_point_array(wxDC
*dc
);
1332 wxList wx_spline_point_list
;
1334 #define half(z1, z2) ((z1+z2)/2.0)
1337 /* iterative version */
1339 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1342 register double xmid
, ymid
;
1343 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1346 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1348 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1349 xmid
= (double)half(x2
, x3
);
1350 ymid
= (double)half(y2
, y3
);
1351 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1352 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1353 wx_spline_add_point( x1
, y1
);
1354 wx_spline_add_point( xmid
, ymid
);
1356 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1357 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1358 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1359 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1364 /* utilities used by spline drawing routines */
1366 typedef struct wx_spline_stack_struct
{
1367 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1370 #define SPLINE_STACK_DEPTH 20
1371 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1372 static Stack
*wx_stack_top
;
1373 static int wx_stack_count
;
1375 void wx_clear_stack()
1377 wx_stack_top
= wx_spline_stack
;
1381 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1383 wx_stack_top
->x1
= x1
;
1384 wx_stack_top
->y1
= y1
;
1385 wx_stack_top
->x2
= x2
;
1386 wx_stack_top
->y2
= y2
;
1387 wx_stack_top
->x3
= x3
;
1388 wx_stack_top
->y3
= y3
;
1389 wx_stack_top
->x4
= x4
;
1390 wx_stack_top
->y4
= y4
;
1395 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1396 double *x3
, double *y3
, double *x4
, double *y4
)
1398 if (wx_stack_count
== 0)
1402 *x1
= wx_stack_top
->x1
;
1403 *y1
= wx_stack_top
->y1
;
1404 *x2
= wx_stack_top
->x2
;
1405 *y2
= wx_stack_top
->y2
;
1406 *x3
= wx_stack_top
->x3
;
1407 *y3
= wx_stack_top
->y3
;
1408 *x4
= wx_stack_top
->x4
;
1409 *y4
= wx_stack_top
->y4
;
1413 static bool wx_spline_add_point(double x
, double y
)
1415 wxPoint
*point
= new wxPoint
;
1418 wx_spline_point_list
.Append((wxObject
*)point
);
1422 static void wx_spline_draw_point_array(wxDC
*dc
)
1424 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1425 wxNode
*node
= wx_spline_point_list
.First();
1428 wxPoint
*point
= (wxPoint
*)node
->Data();
1431 node
= wx_spline_point_list
.First();
1435 void wxWindowDC::DoDrawSpline( wxList
*points
)
1437 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1440 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1441 double x1
, y1
, x2
, y2
;
1443 wxNode
*node
= points
->First();
1444 p
= (wxPoint
*)node
->Data();
1449 node
= node
->Next();
1450 p
= (wxPoint
*)node
->Data();
1454 cx1
= (double)((x1
+ x2
) / 2);
1455 cy1
= (double)((y1
+ y2
) / 2);
1456 cx2
= (double)((cx1
+ x2
) / 2);
1457 cy2
= (double)((cy1
+ y2
) / 2);
1459 wx_spline_add_point(x1
, y1
);
1461 while ((node
= node
->Next()) != NULL
)
1463 p
= (wxPoint
*)node
->Data();
1468 cx4
= (double)(x1
+ x2
) / 2;
1469 cy4
= (double)(y1
+ y2
) / 2;
1470 cx3
= (double)(x1
+ cx4
) / 2;
1471 cy3
= (double)(y1
+ cy4
) / 2;
1473 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1477 cx2
= (double)(cx1
+ x2
) / 2;
1478 cy2
= (double)(cy1
+ y2
) / 2;
1481 wx_spline_add_point( cx1
, cy1
);
1482 wx_spline_add_point( x2
, y2
);
1484 wx_spline_draw_point_array( this );
1487 #endif // wxUSE_SPLINE
1489 //-----------------------------------------------------------------------------
1491 //-----------------------------------------------------------------------------
1493 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1495 wxPaintDC::wxPaintDC()
1500 wxPaintDC::wxPaintDC( wxWindow
*win
)
1505 //-----------------------------------------------------------------------------
1507 //-----------------------------------------------------------------------------
1509 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1511 wxClientDC::wxClientDC()
1516 wxClientDC::wxClientDC( wxWindow
*win
)