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( long WXUNUSED(x
), long WXUNUSED(y
),
157 const wxColour
&WXUNUSED(col
), int WXUNUSED(style
) )
159 wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") );
162 bool wxWindowDC::DoGetPixel( long WXUNUSED(x1
), long WXUNUSED(y1
), wxColour
*WXUNUSED(col
) ) const
164 wxFAIL_MSG( wxT("wxWindowDC::DoGetPixel not implemented") );
168 void wxWindowDC::DoDrawLine( long x1
, long y1
, long x2
, long 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( long x
, long y
)
184 wxCHECK_RET( Ok(), wxT("invalid window dc") );
186 if (m_pen
.GetStyle() != wxTRANSPARENT
)
191 long xx
= XLOG2DEV(x
);
192 long 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( long x1
, long y1
, long x2
, long y2
,
204 wxCHECK_RET( Ok(), wxT("invalid window dc") );
206 long xx1
= XLOG2DEV(x1
);
207 long yy1
= YLOG2DEV(y1
);
208 long xx2
= XLOG2DEV(x2
);
209 long yy2
= YLOG2DEV(y2
);
210 long xxc
= XLOG2DEV(xc
);
211 long yyc
= YLOG2DEV(yc
);
212 double dx
= xx1
- xxc
;
213 double dy
= yy1
- yyc
;
214 double radius
= sqrt((double)(dx
*dx
+dy
*dy
));
215 long r
= (long)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 long alpha1
= long(radius1
* 64.0);
238 long alpha2
= long((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( long x
, long y
, long width
, long height
, double sa
, double ea
)
257 wxCHECK_RET( Ok(), wxT("invalid window dc") );
259 long xx
= XLOG2DEV(x
);
260 long yy
= YLOG2DEV(y
);
261 long ww
= m_signX
* XLOG2DEVREL(width
);
262 long 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 long start
= long(sa
* 64.0);
271 long end
= long(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( long x
, long 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
[], long xoffset
, long 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 long x1
= XLOG2DEV(points
[i
].x
+ xoffset
);
306 long x2
= XLOG2DEV(points
[i
+1].x
+ xoffset
);
307 long y1
= YLOG2DEV(points
[i
].y
+ yoffset
); // oh, what a waste
308 long 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
[], long xoffset
, long 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( long x
, long y
, long width
, long height
)
355 wxCHECK_RET( Ok(), wxT("invalid window dc") );
357 long xx
= XLOG2DEV(x
);
358 long yy
= YLOG2DEV(y
);
359 long ww
= m_signX
* XLOG2DEVREL(width
);
360 long 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( long x
, long y
, long width
, long height
, double radius
)
384 wxCHECK_RET( Ok(), wxT("invalid window dc") );
386 if (radius
< 0.0) radius
= - radius
* ((width
< height
) ? width
: height
);
388 long xx
= XLOG2DEV(x
);
389 long yy
= YLOG2DEV(y
);
390 long ww
= m_signX
* XLOG2DEVREL(width
);
391 long hh
= m_signY
* YLOG2DEVREL(height
);
392 long rr
= XLOG2DEVREL((long)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( long x
, long y
, long width
, long height
)
456 wxCHECK_RET( Ok(), wxT("invalid window dc") );
458 long xx
= XLOG2DEV(x
);
459 long yy
= YLOG2DEV(y
);
460 long ww
= m_signX
* XLOG2DEVREL(width
);
461 long 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
, long x
, long 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
,
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( long xdest
, long ydest
, long width
, long height
,
563 wxDC
*source
, long xsrc
, long 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 long bm_width
= memDC
->m_selected
.GetWidth();
633 long bm_height
= memDC
->m_selected
.GetHeight();
635 long bm_ww
= XLOG2DEVREL( bm_width
);
636 long 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 long xx
= XLOG2DEV(xdest
);
657 long yy
= YLOG2DEV(ydest
);
659 long ww
= XLOG2DEVREL(width
);
660 long 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 long xx
= XLOG2DEV(xdest
);
704 long yy
= YLOG2DEV(ydest
);
706 long ww
= XLOG2DEVREL(width
);
707 long 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
, long x
, long y
)
759 wxCHECK_RET( Ok(), wxT("invalid window dc") );
761 if (!m_window
) return;
763 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
768 /* CMB 21/5/98: draw text background if mode is wxSOLID */
769 if (m_backgroundMode
== wxSOLID
)
771 long width
= gdk_string_width( font
, text
.mbc_str() );
772 long height
= font
->ascent
+ font
->descent
;
773 gdk_gc_set_foreground( m_textGC
, m_textBackgroundColour
.GetColor() );
774 gdk_draw_rectangle( m_window
, m_textGC
, TRUE
, x
, y
, width
, height
);
775 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
777 gdk_draw_string( m_window
, font
, m_textGC
, x
, y
+ font
->ascent
, text
.mbc_str() );
779 /* CMB 17/7/98: simple underline: ignores scaling and underlying
780 X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS
781 properties (see wxXt implementation) */
782 if (m_font
.GetUnderlined())
784 long width
= gdk_string_width( font
, text
.mbc_str() );
785 long ul_y
= y
+ font
->ascent
;
786 if (font
->descent
> 0) ul_y
++;
787 gdk_draw_line( m_window
, m_textGC
, x
, ul_y
, x
+ width
, ul_y
);
791 GetTextExtent (text
, &w
, &h
);
792 CalcBoundingBox (x
+ w
, y
+ h
);
793 CalcBoundingBox (x
, y
);
796 void wxWindowDC::GetTextExtent( const wxString
&string
, long *width
, long *height
,
797 long *descent
, long *externalLeading
,
798 wxFont
*theFont
) const
800 wxFont fontToUse
= m_font
;
801 if (theFont
) fontToUse
= *theFont
;
803 GdkFont
*font
= fontToUse
.GetInternalFont( m_scaleY
);
804 if (width
) (*width
) = long(gdk_string_width( font
, string
.mbc_str() ) / m_scaleX
);
805 if (height
) (*height
) = long((font
->ascent
+ font
->descent
) / m_scaleY
);
806 if (descent
) (*descent
) = long(font
->descent
/ m_scaleY
);
807 if (externalLeading
) (*externalLeading
) = 0; // ??
810 long wxWindowDC::GetCharWidth() const
812 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
813 return long(gdk_string_width( font
, "H" ) / m_scaleX
);
816 long wxWindowDC::GetCharHeight() const
818 GdkFont
*font
= m_font
.GetInternalFont( m_scaleY
);
819 return long((font
->ascent
+ font
->descent
) / m_scaleY
);
822 void wxWindowDC::Clear()
824 wxCHECK_RET( Ok(), wxT("invalid window dc") );
826 if (!m_window
) return;
828 /* - we either are a memory dc or have a window as the
829 owner. anything else shouldn't happen.
830 - we don't use gdk_window_clear() as we don't set
831 the window's background colour anymore. it is too
832 much pain to keep the DC's and the window's back-
833 ground colour in synch. */
838 m_owner
->GetSize( &width
, &height
);
839 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
846 GetSize( &width
, &height
);
847 gdk_draw_rectangle( m_window
, m_bgGC
, TRUE
, 0, 0, width
, height
);
852 void wxWindowDC::SetFont( const wxFont
&font
)
857 void wxWindowDC::SetPen( const wxPen
&pen
)
859 wxCHECK_RET( Ok(), wxT("invalid window dc") );
861 if (m_pen
== pen
) return;
865 if (!m_pen
.Ok()) return;
867 if (!m_window
) return;
869 gint width
= m_pen
.GetWidth();
872 // CMB: if width is non-zero scale it with the dc
877 // X doesn't allow different width in x and y and so we take
880 ( fabs((double) XLOG2DEVREL(width
)) +
881 fabs((double) YLOG2DEVREL(width
)) ) / 2.0;
885 static const char dotted
[] = {1, 1};
886 static const char short_dashed
[] = {2, 2};
887 static const char long_dashed
[] = {2, 4};
888 static const char dotted_dashed
[] = {3, 3, 1, 3};
890 // We express dash pattern in pen width unit, so we are
891 // independent of zoom factor and so on...
893 const char *req_dash
;
895 GdkLineStyle lineStyle
= GDK_LINE_SOLID
;
896 switch (m_pen
.GetStyle())
900 lineStyle
= GDK_LINE_ON_OFF_DASH
;
901 req_nb_dash
= m_pen
.GetDashCount();
902 req_dash
= m_pen
.GetDash();
907 lineStyle
= GDK_LINE_ON_OFF_DASH
;
914 lineStyle
= GDK_LINE_ON_OFF_DASH
;
916 req_dash
= long_dashed
;
921 lineStyle
= GDK_LINE_ON_OFF_DASH
;
923 req_dash
= short_dashed
;
928 // lineStyle = GDK_LINE_DOUBLE_DASH;
929 lineStyle
= GDK_LINE_ON_OFF_DASH
;
931 req_dash
= dotted_dashed
;
940 lineStyle
= GDK_LINE_SOLID
;
941 req_dash
= (wxDash
*)NULL
;
947 #if (GTK_MINOR_VERSION > 0)
948 if (req_dash
&& req_nb_dash
)
950 char *real_req_dash
= new char[req_nb_dash
];
953 for (int i
= 0; i
< req_nb_dash
; i
++)
954 real_req_dash
[i
] = req_dash
[i
] * width
;
955 gdk_gc_set_dashes( m_penGC
, 0, real_req_dash
, req_nb_dash
);
956 delete[] real_req_dash
;
960 // No Memory. We use non-scaled dash pattern...
961 gdk_gc_set_dashes( m_penGC
, 0, (char*)req_dash
, req_nb_dash
);
966 GdkCapStyle capStyle
= GDK_CAP_ROUND
;
967 switch (m_pen
.GetCap())
969 case wxCAP_ROUND
: { capStyle
= (width
<= 1) ? GDK_CAP_NOT_LAST
: GDK_CAP_ROUND
; break; }
970 case wxCAP_PROJECTING
: { capStyle
= GDK_CAP_PROJECTING
; break; }
971 case wxCAP_BUTT
: { capStyle
= GDK_CAP_BUTT
; break; }
974 GdkJoinStyle joinStyle
= GDK_JOIN_ROUND
;
975 switch (m_pen
.GetJoin())
977 case wxJOIN_BEVEL
: { joinStyle
= GDK_JOIN_BEVEL
; break; }
978 case wxJOIN_ROUND
: { joinStyle
= GDK_JOIN_ROUND
; break; }
979 case wxJOIN_MITER
: { joinStyle
= GDK_JOIN_MITER
; break; }
982 gdk_gc_set_line_attributes( m_penGC
, width
, lineStyle
, capStyle
, joinStyle
);
984 m_pen
.GetColour().CalcPixel( m_cmap
);
985 gdk_gc_set_foreground( m_penGC
, m_pen
.GetColour().GetColor() );
988 void wxWindowDC::SetBrush( const wxBrush
&brush
)
990 wxCHECK_RET( Ok(), wxT("invalid window dc") );
992 if (m_brush
== brush
) return;
996 if (!m_brush
.Ok()) return;
998 if (!m_window
) return;
1000 m_brush
.GetColour().CalcPixel( m_cmap
);
1001 gdk_gc_set_foreground( m_brushGC
, m_brush
.GetColour().GetColor() );
1003 gdk_gc_set_fill( m_brushGC
, GDK_SOLID
);
1005 if ((m_brush
.GetStyle() == wxSTIPPLE
) && (m_brush
.GetStipple()->Ok()))
1007 if (m_brush
.GetStipple()->GetPixmap())
1009 gdk_gc_set_fill( m_brushGC
, GDK_TILED
);
1010 gdk_gc_set_tile( m_brushGC
, m_brush
.GetStipple()->GetPixmap() );
1014 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1015 gdk_gc_set_stipple( m_brushGC
, m_brush
.GetStipple()->GetBitmap() );
1019 if (IS_HATCH(m_brush
.GetStyle()))
1021 gdk_gc_set_fill( m_brushGC
, GDK_STIPPLED
);
1022 int num
= m_brush
.GetStyle() - wxBDIAGONAL_HATCH
;
1023 gdk_gc_set_stipple( m_brushGC
, hatches
[num
] );
1027 void wxWindowDC::SetBackground( const wxBrush
&brush
)
1029 /* CMB 21/7/98: Added SetBackground. Sets background brush
1030 * for Clear() and bg colour for shapes filled with cross-hatch brush */
1032 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1034 if (m_backgroundBrush
== brush
) return;
1036 m_backgroundBrush
= brush
;
1038 if (!m_backgroundBrush
.Ok()) return;
1040 if (!m_window
) return;
1042 m_backgroundBrush
.GetColour().CalcPixel( m_cmap
);
1043 gdk_gc_set_background( m_brushGC
, m_backgroundBrush
.GetColour().GetColor() );
1044 gdk_gc_set_background( m_penGC
, m_backgroundBrush
.GetColour().GetColor() );
1045 gdk_gc_set_background( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1046 gdk_gc_set_foreground( m_bgGC
, m_backgroundBrush
.GetColour().GetColor() );
1048 gdk_gc_set_fill( m_bgGC
, GDK_SOLID
);
1050 if ((m_backgroundBrush
.GetStyle() == wxSTIPPLE
) && (m_backgroundBrush
.GetStipple()->Ok()))
1052 if (m_backgroundBrush
.GetStipple()->GetPixmap())
1054 gdk_gc_set_fill( m_bgGC
, GDK_TILED
);
1055 gdk_gc_set_tile( m_bgGC
, m_backgroundBrush
.GetStipple()->GetPixmap() );
1059 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1060 gdk_gc_set_stipple( m_bgGC
, m_backgroundBrush
.GetStipple()->GetBitmap() );
1064 if (IS_HATCH(m_backgroundBrush
.GetStyle()))
1066 gdk_gc_set_fill( m_bgGC
, GDK_STIPPLED
);
1067 int num
= m_backgroundBrush
.GetStyle() - wxBDIAGONAL_HATCH
;
1068 gdk_gc_set_stipple( m_bgGC
, hatches
[num
] );
1072 void wxWindowDC::SetLogicalFunction( int function
)
1074 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1076 if (m_logicalFunction
== function
) return;
1078 GdkFunction mode
= GDK_COPY
;
1081 case wxXOR
: mode
= GDK_XOR
; break;
1082 case wxINVERT
: mode
= GDK_INVERT
; break;
1083 #if (GTK_MINOR_VERSION > 0)
1084 case wxOR_REVERSE
: mode
= GDK_OR_REVERSE
; break;
1085 case wxAND_REVERSE
: mode
= GDK_AND_REVERSE
; break;
1086 case wxCLEAR
: mode
= GDK_CLEAR
; break;
1087 case wxSET
: mode
= GDK_SET
; break;
1088 case wxOR_INVERT
: mode
= GDK_OR_INVERT
; break;
1090 case wxAND
: mode
= GDK_AND
; break;
1092 case wxOR
: mode
= GDK_OR
; break;
1093 case wxEQUIV
: mode
= GDK_EQUIV
; break;
1094 case wxNAND
: mode
= GDK_NAND
; break;
1095 case wxAND_INVERT
: mode
= GDK_AND_INVERT
; break;
1096 case wxCOPY
: mode
= GDK_COPY
; break;
1097 case wxNO_OP
: mode
= GDK_NOOP
; break;
1098 case wxSRC_INVERT
: mode
= GDK_COPY_INVERT
; break;
1102 wxFAIL_MSG( wxT("unsupported logical function") );
1107 m_logicalFunction
= function
;
1109 if (!m_window
) return;
1111 gdk_gc_set_function( m_penGC
, mode
);
1112 gdk_gc_set_function( m_brushGC
, mode
);
1113 gdk_gc_set_function( m_textGC
, mode
);
1116 void wxWindowDC::SetTextForeground( const wxColour
&col
)
1118 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1120 if (m_textForegroundColour
== col
) return;
1122 m_textForegroundColour
= col
;
1123 if (!m_textForegroundColour
.Ok()) return;
1125 if (!m_window
) return;
1127 m_textForegroundColour
.CalcPixel( m_cmap
);
1128 gdk_gc_set_foreground( m_textGC
, m_textForegroundColour
.GetColor() );
1131 void wxWindowDC::SetTextBackground( const wxColour
&col
)
1133 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1135 if (m_textBackgroundColour
== col
) return;
1137 m_textBackgroundColour
= col
;
1138 if (!m_textBackgroundColour
.Ok()) return;
1140 if (!m_window
) return;
1142 m_textBackgroundColour
.CalcPixel( m_cmap
);
1143 gdk_gc_set_background( m_textGC
, m_textBackgroundColour
.GetColor() );
1146 void wxWindowDC::SetBackgroundMode( int mode
)
1148 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1150 m_backgroundMode
= mode
;
1152 if (!m_window
) return;
1154 // CMB 21/7/98: fill style of cross-hatch brushes is affected by
1155 // transparent/solid background mode
1157 if (m_brush
.GetStyle() != wxSOLID
&& m_brush
.GetStyle() != wxTRANSPARENT
)
1159 gdk_gc_set_fill( m_brushGC
,
1160 (m_backgroundMode
== wxTRANSPARENT
) ? GDK_STIPPLED
: GDK_OPAQUE_STIPPLED
);
1164 void wxWindowDC::SetPalette( const wxPalette
& WXUNUSED(palette
) )
1166 wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") );
1169 void wxWindowDC::DoSetClippingRegion( long x
, long y
, long width
, long height
)
1171 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1173 wxDC::DoSetClippingRegion( x
, y
, width
, height
);
1175 if (!m_window
) return;
1178 rect
.x
= XLOG2DEV(x
);
1179 rect
.y
= YLOG2DEV(y
);
1180 rect
.width
= XLOG2DEVREL(width
);
1181 rect
.height
= YLOG2DEVREL(height
);
1182 gdk_gc_set_clip_rectangle( m_penGC
, &rect
);
1183 gdk_gc_set_clip_rectangle( m_brushGC
, &rect
);
1184 gdk_gc_set_clip_rectangle( m_textGC
, &rect
);
1185 gdk_gc_set_clip_rectangle( m_bgGC
, &rect
);
1188 void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion
®ion
)
1190 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1194 DestroyClippingRegion();
1198 if (!m_window
) return;
1200 gdk_gc_set_clip_region( m_penGC
, region
.GetRegion() );
1201 gdk_gc_set_clip_region( m_brushGC
, region
.GetRegion() );
1202 gdk_gc_set_clip_region( m_textGC
, region
.GetRegion() );
1203 gdk_gc_set_clip_region( m_bgGC
, region
.GetRegion() );
1206 void wxWindowDC::DestroyClippingRegion()
1208 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1210 wxDC::DestroyClippingRegion();
1212 if (!m_window
) return;
1214 gdk_gc_set_clip_rectangle( m_penGC
, (GdkRectangle
*) NULL
);
1215 gdk_gc_set_clip_rectangle( m_brushGC
, (GdkRectangle
*) NULL
);
1216 gdk_gc_set_clip_rectangle( m_textGC
, (GdkRectangle
*) NULL
);
1217 gdk_gc_set_clip_rectangle( m_bgGC
, (GdkRectangle
*) NULL
);
1220 void wxWindowDC::SetUpDC()
1224 m_logicalFunction
= wxCOPY
;
1225 m_penGC
= gdk_gc_new( m_window
);
1226 m_brushGC
= gdk_gc_new( m_window
);
1227 m_textGC
= gdk_gc_new( m_window
);
1228 m_bgGC
= gdk_gc_new( m_window
);
1230 wxColour
tmp_col( m_textForegroundColour
);
1231 m_textForegroundColour
= wxNullColour
;
1232 SetTextForeground( tmp_col
);
1233 tmp_col
= m_textBackgroundColour
;
1234 m_textBackgroundColour
= wxNullColour
;
1235 SetTextBackground( tmp_col
);
1237 wxPen
tmp_pen( m_pen
);
1241 wxFont
tmp_font( m_font
);
1242 m_font
= wxNullFont
;
1243 SetFont( tmp_font
);
1245 wxBrush
tmp_brush( m_brush
);
1246 m_brush
= wxNullBrush
;
1247 SetBrush( tmp_brush
);
1250 tmp_brush = m_backgroundBrush;
1251 m_backgroundBrush = wxNullBrush;
1252 SetBackground( tmp_brush );
1254 tmp_brush
= m_backgroundBrush
;
1255 m_backgroundBrush
= wxNullBrush
;
1256 SetBackground( *wxWHITE_BRUSH
);
1257 m_backgroundBrush
= tmp_brush
;
1261 hatch_bitmap
= hatches
;
1262 hatch_bitmap
[0] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, bdiag_bits
, bdiag_width
, bdiag_height
);
1263 hatch_bitmap
[1] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cdiag_bits
, cdiag_width
, cdiag_height
);
1264 hatch_bitmap
[2] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, fdiag_bits
, fdiag_width
, fdiag_height
);
1265 hatch_bitmap
[3] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, cross_bits
, cross_width
, cross_height
);
1266 hatch_bitmap
[4] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, horiz_bits
, horiz_width
, horiz_height
);
1267 hatch_bitmap
[5] = gdk_bitmap_create_from_data( (GdkWindow
*) NULL
, verti_bits
, verti_width
, verti_height
);
1271 void wxWindowDC::Destroy()
1273 if (m_penGC
) gdk_gc_unref( m_penGC
);
1274 m_penGC
= (GdkGC
*) NULL
;
1275 if (m_brushGC
) gdk_gc_unref( m_brushGC
);
1276 m_brushGC
= (GdkGC
*) NULL
;
1277 if (m_textGC
) gdk_gc_unref( m_textGC
);
1278 m_textGC
= (GdkGC
*) NULL
;
1279 if (m_bgGC
) gdk_gc_unref( m_bgGC
);
1280 m_bgGC
= (GdkGC
*) NULL
;
1283 void wxWindowDC::ComputeScaleAndOrigin()
1285 /* CMB: copy scale to see if it changes */
1286 double origScaleX
= m_scaleX
;
1287 double origScaleY
= m_scaleY
;
1289 wxDC::ComputeScaleAndOrigin();
1291 /* CMB: if scale has changed call SetPen to recalulate the line width */
1292 if ((m_scaleX
!= origScaleX
|| m_scaleY
!= origScaleY
) &&
1295 /* this is a bit artificial, but we need to force wxDC to think
1296 the pen has changed */
1303 // Resolution in pixels per logical inch
1304 wxSize
wxWindowDC::GetPPI() const
1306 return wxSize(100, 100);
1309 int wxWindowDC::GetDepth() const
1311 wxFAIL_MSG(wxT("not implemented"));
1317 // ----------------------------------- spline code ----------------------------------------
1319 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1320 double a3
, double b3
, double a4
, double b4
);
1321 void wx_clear_stack();
1322 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1323 double *y3
, double *x4
, double *y4
);
1324 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1325 double x4
, double y4
);
1326 static bool wx_spline_add_point(double x
, double y
);
1327 static void wx_spline_draw_point_array(wxDC
*dc
);
1329 wxList wx_spline_point_list
;
1331 #define half(z1, z2) ((z1+z2)/2.0)
1334 /* iterative version */
1336 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1339 register double xmid
, ymid
;
1340 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1343 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1345 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1346 xmid
= (double)half(x2
, x3
);
1347 ymid
= (double)half(y2
, y3
);
1348 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1349 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1350 wx_spline_add_point( x1
, y1
);
1351 wx_spline_add_point( xmid
, ymid
);
1353 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1354 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1355 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1356 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1361 /* utilities used by spline drawing routines */
1363 typedef struct wx_spline_stack_struct
{
1364 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1367 #define SPLINE_STACK_DEPTH 20
1368 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1369 static Stack
*wx_stack_top
;
1370 static int wx_stack_count
;
1372 void wx_clear_stack()
1374 wx_stack_top
= wx_spline_stack
;
1378 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1380 wx_stack_top
->x1
= x1
;
1381 wx_stack_top
->y1
= y1
;
1382 wx_stack_top
->x2
= x2
;
1383 wx_stack_top
->y2
= y2
;
1384 wx_stack_top
->x3
= x3
;
1385 wx_stack_top
->y3
= y3
;
1386 wx_stack_top
->x4
= x4
;
1387 wx_stack_top
->y4
= y4
;
1392 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1393 double *x3
, double *y3
, double *x4
, double *y4
)
1395 if (wx_stack_count
== 0)
1399 *x1
= wx_stack_top
->x1
;
1400 *y1
= wx_stack_top
->y1
;
1401 *x2
= wx_stack_top
->x2
;
1402 *y2
= wx_stack_top
->y2
;
1403 *x3
= wx_stack_top
->x3
;
1404 *y3
= wx_stack_top
->y3
;
1405 *x4
= wx_stack_top
->x4
;
1406 *y4
= wx_stack_top
->y4
;
1410 static bool wx_spline_add_point(double x
, double y
)
1412 wxPoint
*point
= new wxPoint
;
1415 wx_spline_point_list
.Append((wxObject
*)point
);
1419 static void wx_spline_draw_point_array(wxDC
*dc
)
1421 dc
->DrawLines(&wx_spline_point_list
, 0, 0 );
1422 wxNode
*node
= wx_spline_point_list
.First();
1425 wxPoint
*point
= (wxPoint
*)node
->Data();
1428 node
= wx_spline_point_list
.First();
1432 void wxWindowDC::DoDrawSpline( wxList
*points
)
1434 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1437 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1438 double x1
, y1
, x2
, y2
;
1440 wxNode
*node
= points
->First();
1441 p
= (wxPoint
*)node
->Data();
1446 node
= node
->Next();
1447 p
= (wxPoint
*)node
->Data();
1451 cx1
= (double)((x1
+ x2
) / 2);
1452 cy1
= (double)((y1
+ y2
) / 2);
1453 cx2
= (double)((cx1
+ x2
) / 2);
1454 cy2
= (double)((cy1
+ y2
) / 2);
1456 wx_spline_add_point(x1
, y1
);
1458 while ((node
= node
->Next()) != NULL
)
1460 p
= (wxPoint
*)node
->Data();
1465 cx4
= (double)(x1
+ x2
) / 2;
1466 cy4
= (double)(y1
+ y2
) / 2;
1467 cx3
= (double)(x1
+ cx4
) / 2;
1468 cy3
= (double)(y1
+ cy4
) / 2;
1470 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1474 cx2
= (double)(cx1
+ x2
) / 2;
1475 cy2
= (double)(cy1
+ y2
) / 2;
1478 wx_spline_add_point( cx1
, cy1
);
1479 wx_spline_add_point( x2
, y2
);
1481 wx_spline_draw_point_array( this );
1484 #endif // wxUSE_SPLINE
1486 //-----------------------------------------------------------------------------
1488 //-----------------------------------------------------------------------------
1490 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
,wxWindowDC
)
1492 wxPaintDC::wxPaintDC()
1497 wxPaintDC::wxPaintDC( wxWindow
*win
)
1502 //-----------------------------------------------------------------------------
1504 //-----------------------------------------------------------------------------
1506 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
,wxWindowDC
)
1508 wxClientDC::wxClientDC()
1513 wxClientDC::wxClientDC( wxWindow
*win
)