1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "dc.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #include "wx/dialog.h"
31 #include "wx/dcprint.h"
32 #include "wx/msw/private.h"
37 #if wxUSE_COMMON_DIALOGS
57 #if !USE_SHARED_LIBRARY
58 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
61 // Declarations local to this file
63 #define YSCALE(y) (yorigin - (y))
65 // #define wx_round(a) (int)((a)+.5)
67 // Default constructor
70 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
80 m_minX
= 0; m_minY
= 0; m_maxX
= 0; m_maxY
= 0;
85 m_logicalScaleX
= 1.0;
86 m_logicalScaleY
= 1.0;
93 m_mappingMode
= MM_TEXT
;
98 m_windowExtX
= VIEWPORT_EXTENT
;
99 m_windowExtY
= VIEWPORT_EXTENT
;
100 m_logicalFunction
= -1;
102 m_backgroundBrush
= *wxWHITE_BRUSH
;
104 m_textForegroundColour
= *wxBLACK
;
105 m_textBackgroundColour
= *wxWHITE
;
107 m_colour
= wxColourDisplay();
116 SelectOldObjects(m_hDC
);
118 if ( m_canvas
== NULL
)
119 ::DeleteDC((HDC
)m_hDC
);
121 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), (HDC
)m_hDC
);
127 // This will select current objects out of the DC,
128 // which is what you have to do before deleting the
130 void wxDC::SelectOldObjects(WXHDC dc
)
133 wxDebugMsg("wxDC::SelectOldObjects %X\n", this);
140 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HBITMAP %X\n", m_oldBitmap
);
142 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
143 if (m_selectedBitmap
.Ok())
145 m_selectedBitmap
.SetSelectedInto(NULL
);
152 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HPEN %X\n", m_oldPen
);
154 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
160 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HBRUSH %X\n", m_oldBrush
);
162 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
168 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HFONT %X\n", m_oldFont
);
170 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
176 wxDebugMsg("wxDC::SelectOldObjects: Selecting old HPALETTE %X\n", m_oldPalette
);
178 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
181 wxDebugMsg("wxDC::SelectOldObjects: Done.\n");
186 m_brush
= wxNullBrush
;
188 m_palette
= wxNullPalette
;
190 m_backgroundBrush
= wxNullBrush
;
191 m_selectedBitmap
= wxNullBitmap
;
194 void wxDC::SetClippingRegion(long cx
, long cy
, long cw
, long ch
)
199 m_clipX2
= (int)(cx
+ cw
);
200 m_clipY2
= (int)(cy
+ ch
);
202 DoClipping((WXHDC
) m_hDC
);
205 void wxDC::DoClipping(WXHDC dc
)
207 if (m_clipping
&& dc
)
209 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
210 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
214 void wxDC::DestroyClippingRegion(void)
216 if (m_clipping
&& m_hDC
)
218 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
220 wxDebugMsg("wxDC::DestroyClippingRegion: Selecting HRGN %X\n", rgn
);
222 SelectClipRgn((HDC
) m_hDC
, rgn
);
224 wxDebugMsg("wxDC::DestroyClippingRegion: Deleting HRGN %X\n", rgn
);
231 bool wxDC::CanDrawBitmap(void) const
236 bool wxDC::CanGetTextExtent(void) const
238 // What sort of display is it?
239 int technology
= ::GetDeviceCaps((HDC
) m_hDC
, TECHNOLOGY
);
243 if (technology
!= DT_RASDISPLAY
&& technology
!= DT_RASPRINTER
)
250 void wxDC::SetPalette(const wxPalette
& palette
)
252 // Set the old object temporarily, in case the assignment deletes an object
253 // that's not yet selected out.
256 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
260 m_palette
= m_palette
;
264 // Setting a NULL colourmap is a way of restoring
265 // the original colourmap
268 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_oldPalette
, TRUE
);
270 wxDebugMsg("wxDC::SetPalette: set old palette %X\n", m_oldPalette
);
278 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
280 HPALETTE oldPal
= ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
282 m_oldPalette
= (WXHPALETTE
) oldPal
;
285 wxDebugMsg("wxDC::SetPalette %X: selected palette %X\n", this, m_palette
.GetHPALETTE());
287 wxDebugMsg("wxDC::SetPalette: oldPal was palette %X\n", oldPal
);
289 wxDebugMsg("wxDC::SetPalette: m_oldPalette is palette %X\n", m_oldPalette
);
291 ::RealizePalette((HDC
) m_hDC
);
295 void wxDC::Clear(void)
299 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
300 else if (m_selectedBitmap
.Ok())
302 rect
.left
= 0; rect
.top
= 0;
303 rect
.right
= m_selectedBitmap
.GetWidth();
304 rect
.bottom
= m_selectedBitmap
.GetHeight();
306 (void) ::SetMapMode((HDC
) m_hDC
, MM_TEXT
);
308 DWORD colour
= GetBkColor((HDC
) m_hDC
);
309 HBRUSH brush
= CreateSolidBrush(colour
);
310 FillRect((HDC
) m_hDC
, &rect
, brush
);
313 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
314 ::SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
315 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
316 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
317 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
320 void wxDC::FloodFill(long x
, long y
, const wxColour
& col
, int style
)
322 (void)ExtFloodFill((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
324 style
==wxFLOOD_SURFACE
?
325 FLOODFILLSURFACE
:FLOODFILLBORDER
328 CalcBoundingBox(x
, y
);
331 bool wxDC::GetPixel(long x
, long y
, wxColour
*col
) const
333 // added by steve 29.12.94 (copied from DrawPoint)
334 // returns TRUE for pixels in the color of the current pen
335 // and FALSE for all other pixels colors
336 // if col is non-NULL return the color of the pixel
338 // get the color of the pixel
339 COLORREF pixelcolor
= ::GetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
));
340 // get the color of the pen
341 COLORREF pencolor
= 0x00ffffff;
344 pencolor
= m_pen
.GetColour().GetPixel() ;
347 // return the color of the pixel
349 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
351 // check, if color of the pixels is the same as the color
352 // of the current pen
353 return(pixelcolor
==pencolor
);
356 void wxDC::CrossHair(long x
, long y
)
358 // We suppose that our screen is 2000x2000 max.
364 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
365 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y
));
367 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
368 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y2
));
370 CalcBoundingBox(x1
, y1
);
371 CalcBoundingBox(x2
, y2
);
374 void wxDC::DrawLine(long x1
, long y1
, long x2
, long y2
)
376 (void)MoveToEx((HDC
) m_hDC
, XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
377 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
), YLOG2DEV(y2
));
379 /* MATTHEW: [6] New normalization */
380 #if WX_STANDARD_GRAPHICS
381 (void)LineTo((HDC
) m_hDC
, XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
384 CalcBoundingBox(x1
, y1
);
385 CalcBoundingBox(x2
, y2
);
388 void wxDC::DrawArc(long x1
,long y1
,long x2
,long y2
, long xc
, long yc
)
392 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
393 if (x1
==x2
&& x2
==y2
)
395 DrawEllipse(xc
,yc
,(double)(radius
*2.0),(double)(radius
*2)) ;
399 long xx1
= XLOG2DEV(x1
) ;
400 long yy1
= YLOG2DEV(y1
) ;
401 long xx2
= XLOG2DEV(x2
) ;
402 long yy2
= YLOG2DEV(y2
) ;
403 long xxc
= XLOG2DEV(xc
) ;
404 long yyc
= YLOG2DEV(yc
) ;
405 long ray
= (long) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
))) ;
407 (void)MoveToEx((HDC
) m_hDC
, (int) xx1
, (int) yy1
, NULL
);
408 long xxx1
= (long) (xxc
-ray
);
409 long yyy1
= (long) (yyc
-ray
);
410 long xxx2
= (long) (xxc
+ray
);
411 long yyy2
= (long) (yyc
+ray
);
412 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
414 // Have to add 1 to bottom-right corner of rectangle
415 // to make semi-circles look right (crooked line otherwise).
416 // Unfortunately this is not a reliable method, depends
417 // on the size of shape.
418 // TODO: figure out why this happens!
419 Pie((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
+1,yyy2
+1,
423 Arc((HDC
) m_hDC
,xxx1
,yyy1
,xxx2
,yyy2
,
426 CalcBoundingBox((xc
-radius
), (yc
-radius
));
427 CalcBoundingBox((xc
+radius
), (yc
+radius
));
430 void wxDC::DrawPoint(long x
, long y
)
432 COLORREF color
= 0x00ffffff;
435 color
= m_pen
.GetColour().GetPixel() ;
438 SetPixel((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), color
);
440 CalcBoundingBox(x
, y
);
443 void wxDC::DrawPolygon(int n
, wxPoint points
[], long xoffset
, long yoffset
,int fillStyle
)
445 // Do things less efficiently if we have offsets
446 if (xoffset
!= 0 || yoffset
!= 0)
448 POINT
*cpoints
= new POINT
[n
];
450 for (i
= 0; i
< n
; i
++)
452 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
453 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
455 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
457 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
458 (void)Polygon((HDC
) m_hDC
, cpoints
, n
);
459 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
465 for (i
= 0; i
< n
; i
++)
466 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
468 int prev
= SetPolyFillMode((HDC
) m_hDC
,fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
) ;
469 (void)Polygon((HDC
) m_hDC
, (POINT
*) points
, n
);
470 SetPolyFillMode((HDC
) m_hDC
,prev
) ;
474 void wxDC::DrawLines(int n
, wxPoint points
[], long xoffset
, long yoffset
)
476 // Do things less efficiently if we have offsets
477 if (xoffset
!= 0 || yoffset
!= 0)
479 POINT
*cpoints
= new POINT
[n
];
481 for (i
= 0; i
< n
; i
++)
483 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
484 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
486 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
488 (void)Polyline((HDC
) m_hDC
, cpoints
, n
);
494 for (i
= 0; i
< n
; i
++)
495 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
497 (void)Polyline((HDC
) m_hDC
, (POINT
*) points
, n
);
501 void wxDC::DrawRectangle(long x
, long y
, long width
, long height
)
504 long y2
= y
+ height
;
506 /* MATTHEW: [6] new normalization */
507 #if WX_STANDARD_GRAPHICS
508 bool do_brush
, do_pen
;
510 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
511 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
514 HPEN orig_pen
= NULL
;
516 if (do_pen
|| !m_pen
.Ok())
517 orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
519 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
520 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
522 if (do_pen
|| !m_pen
.Ok())
523 ::SelectObject((HDC
) m_hDC
, orig_pen
);
526 HBRUSH orig_brush
= NULL
;
528 if (do_brush
|| !m_brush
.Ok())
529 orig_brush
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
531 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
),
532 XLOG2DEV(x2
), YLOG2DEV(y2
));
534 if (do_brush
|| !m_brush
.Ok())
535 ::SelectObject((HDC
) m_hDC
, orig_brush
);
538 (void)Rectangle((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
541 CalcBoundingBox(x
, y
);
542 CalcBoundingBox(x2
, y2
);
545 void wxDC::DrawRoundedRectangle(long x
, long y
, long width
, long height
, double radius
)
547 // Now, a negative radius value is interpreted to mean
548 // 'the proportion of the smallest X or Y dimension'
552 double smallest
= 0.0;
557 radius
= (- radius
* smallest
);
561 long y2
= (y
+height
);
563 (void)RoundRect((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
564 YLOG2DEV(y2
), 2*XLOG2DEV(radius
), 2*YLOG2DEV(radius
));
566 CalcBoundingBox(x
, y
);
567 CalcBoundingBox(x2
, y2
);
570 void wxDC::DrawEllipse(long x
, long y
, long width
, long height
)
573 long y2
= (y
+height
);
575 (void)Ellipse((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
577 CalcBoundingBox(x
, y
);
578 CalcBoundingBox(x2
, y2
);
581 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
582 void wxDC::DrawEllipticArc(long x
,long y
,long w
,long h
,double sa
,double ea
)
587 const double deg2rad
= 3.14159265359 / 180.0;
588 int rx1
= XLOG2DEV(x
+w
/2);
589 int ry1
= YLOG2DEV(y
+h
/2);
592 rx1
+= (int)(100.0 * abs(w
) * cos(sa
* deg2rad
));
593 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
* deg2rad
));
594 rx2
+= (int)(100.0 * abs(w
) * cos(ea
* deg2rad
));
595 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
* deg2rad
));
597 // draw pie with NULL_PEN first and then outline otherwise a line is
598 // drawn from the start and end points to the centre
599 HPEN orig_pen
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
) ::GetStockObject(NULL_PEN
));
602 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
607 (void)Pie((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
608 rx1
, ry1
-1, rx2
, ry2
-1);
610 ::SelectObject((HDC
) m_hDC
, orig_pen
);
611 (void)Arc((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
614 CalcBoundingBox(x
, y
);
615 CalcBoundingBox(x2
, y2
);
618 void wxDC::DrawIcon(const wxIcon
& icon
, long x
, long y
)
620 ::DrawIcon((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
621 CalcBoundingBox(x
, y
);
622 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
625 void wxDC::SetFont(const wxFont
& the_font
)
627 // Set the old object temporarily, in case the assignment deletes an object
628 // that's not yet selected out.
631 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
640 ::SelectObject((HDC
) m_hDC
, (HFONT
) m_oldFont
);
644 if (m_font
.Ok() && m_font
.GetResourceHandle())
647 wxDebugMsg("wxDC::SetFont: Selecting HFONT %X\n", m_font
.GetResourceHandle());
649 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
652 wxDebugMsg("::SelectObject failed in wxDC::SetFont.");
655 m_oldFont
= (WXHFONT
) f
;
659 void wxDC::SetPen(const wxPen
& pen
)
661 // Set the old object temporarily, in case the assignment deletes an object
662 // that's not yet selected out.
665 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
674 ::SelectObject((HDC
) m_hDC
, (HPEN
) m_oldPen
);
680 if (m_pen
.GetResourceHandle())
682 HPEN p
= (HPEN
) ::SelectObject((HDC
) m_hDC
, (HPEN
)m_pen
.GetResourceHandle()) ;
684 m_oldPen
= (WXHPEN
) p
;
689 void wxDC::SetBrush(const wxBrush
& brush
)
691 // Set the old object temporarily, in case the assignment deletes an object
692 // that's not yet selected out.
695 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
704 ::SelectObject((HDC
) m_hDC
, (HBRUSH
) m_oldBrush
);
710 if (m_brush
.GetResourceHandle())
713 b
= (HBRUSH
) ::SelectObject((HDC
) m_hDC
, (HBRUSH
)m_brush
.GetResourceHandle()) ;
715 m_oldBrush
= (WXHBRUSH
) b
;
720 void wxDC::DrawText(const wxString
& text
, long x
, long y
, bool use16bit
)
722 // Should be unnecessary: SetFont should have done this already.
724 if (m_font
.Ok() && m_font
.GetResourceHandle())
727 wxDebugMsg("wxDC::DrawText: Selecting HFONT %X\n", m_font
.GetResourceHandle());
729 HFONT f
= (HFONT
) ::SelectObject((HDC
) m_hDC
, (HFONT
) m_font
.GetResourceHandle());
731 m_oldFont
= (WXHFONT
) f
;
735 if (m_textForegroundColour
.Ok())
736 SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
738 DWORD old_background
;
739 if (m_textBackgroundColour
.Ok())
741 old_background
= SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
744 if (m_backgroundMode
== wxTRANSPARENT
)
745 SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
747 SetBkMode((HDC
) m_hDC
, OPAQUE
);
749 (void)TextOut((HDC
) m_hDC
, XLOG2DEV(x
), YLOG2DEV(y
), (char *) (const char *)text
, strlen((const char *)text
));
751 if (m_textBackgroundColour
.Ok())
752 (void)SetBkColor((HDC
) m_hDC
, old_background
);
754 CalcBoundingBox(x
, y
);
757 GetTextExtent(text
, &w
, &h
);
758 CalcBoundingBox((x
+ w
), (y
+ h
));
761 void wxDC::SetBackground(const wxBrush
& brush
)
763 m_backgroundBrush
= brush
;
765 if (!m_backgroundBrush
.Ok())
770 bool customColours
= TRUE
;
771 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
772 // change background colours from the control-panel specified colours.
773 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
774 customColours
= FALSE
;
778 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
780 m_canvas
->m_backgroundTransparent
= TRUE
;
784 m_canvas
->SetBackgroundColour(m_backgroundBrush
.GetColour());
785 m_canvas
->m_backgroundTransparent
= FALSE
;
789 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel() ;
791 (void)SetBkColor((HDC
) m_hDC
, new_color
);
795 void wxDC::SetBackgroundMode(int mode
)
797 m_backgroundMode
= mode
;
799 if (m_backgroundMode
== wxTRANSPARENT
)
800 ::SetBkMode((HDC
) m_hDC
, TRANSPARENT
);
802 ::SetBkMode((HDC
) m_hDC
, OPAQUE
);
805 void wxDC::SetLogicalFunction(int function
)
807 m_logicalFunction
= function
;
809 SetRop((WXHDC
) m_hDC
);
812 void wxDC::SetRop(WXHDC dc
)
814 if (!dc
|| m_logicalFunction
< 0)
818 // These may be wrong
819 switch (m_logicalFunction
)
821 // case wxXOR: c_rop = R2_XORPEN; break;
822 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
823 case wxINVERT
: c_rop
= R2_NOT
; break;
824 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
825 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
826 case wxCLEAR
: c_rop
= R2_WHITE
; break;
827 case wxSET
: c_rop
= R2_BLACK
; break;
828 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
829 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
830 case wxAND
: c_rop
= R2_MASKPEN
; break;
831 case wxOR
: c_rop
= R2_MERGEPEN
; break;
832 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
837 c_rop
= R2_COPYPEN
; break;
839 SetROP2((HDC
) dc
, c_rop
);
842 bool wxDC::StartDoc(const wxString
& message
)
844 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
848 docinfo
.cbSize
= sizeof(DOCINFO
);
849 docinfo
.lpszDocName
= (const char *)message
;
851 if (m_filename
.IsEmpty())
852 docinfo
.lpszOutput
= NULL
;
854 docinfo
.lpszOutput
= (const char *)m_filename
;
856 #if defined(__WIN95__)
857 docinfo
.lpszDatatype
= NULL
;
866 ::StartDoc((HDC
) m_hDC
, &docinfo
);
869 ::StartDocW((HDC
) m_hDC
, &docinfo
);
871 ::StartDocA((HDC
) m_hDC
, &docinfo
);
877 DWORD lastError
= GetLastError();
878 wxDebugMsg("wxDC::StartDoc failed with error: %d\n", lastError
);
883 void wxDC::EndDoc(void)
885 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
887 if (m_hDC
) ::EndDoc((HDC
) m_hDC
);
890 void wxDC::StartPage(void)
892 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
895 ::StartPage((HDC
) m_hDC
);
898 void wxDC::EndPage(void)
900 if (!this->IsKindOf(CLASSINFO(wxPrinterDC
)))
903 ::EndPage((HDC
) m_hDC
);
906 long wxDC::GetCharHeight(void) const
908 TEXTMETRIC lpTextMetric
;
910 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
912 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
915 long wxDC::GetCharWidth(void) const
917 TEXTMETRIC lpTextMetric
;
919 GetTextMetrics((HDC
) m_hDC
, &lpTextMetric
);
921 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
924 void wxDC::GetTextExtent(const wxString
& string
, long *x
, long *y
,
925 long *descent
, long *externalLeading
, wxFont
*theFont
, bool use16bit
) const
927 wxFont
*fontToUse
= (wxFont
*) theFont
;
929 fontToUse
= (wxFont
*) &m_font
;
934 GetTextExtentPoint((HDC
) m_hDC
, (char *)(const char *) string
, strlen((char *)(const char *) string
), &sizeRect
);
935 GetTextMetrics((HDC
) m_hDC
, &tm
);
937 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
938 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
939 if (descent
) *descent
= tm
.tmDescent
;
940 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
943 void wxDC::SetMapMode(int mode
)
945 m_mappingMode
= mode
;
948 int pixel_height
= 0;
952 pixel_width
= GetDeviceCaps((HDC
) m_hDC
, HORZRES
);
953 pixel_height
= GetDeviceCaps((HDC
) m_hDC
, VERTRES
);
954 mm_width
= GetDeviceCaps((HDC
) m_hDC
, HORZSIZE
);
955 mm_height
= GetDeviceCaps((HDC
) m_hDC
, VERTSIZE
);
957 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
962 double mm2pixelsX
= pixel_width
/mm_width
;
963 double mm2pixelsY
= pixel_height
/mm_height
;
969 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
970 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
975 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
976 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
981 m_logicalScaleX
= mm2pixelsX
;
982 m_logicalScaleY
= mm2pixelsY
;
987 m_logicalScaleX
= (mm2pixelsX
/10.0);
988 m_logicalScaleY
= (mm2pixelsY
/10.0);
994 m_logicalScaleX
= 1.0;
995 m_logicalScaleY
= 1.0;
1000 if (::GetMapMode((HDC
) m_hDC
) != MM_ANISOTROPIC
)
1001 ::SetMapMode((HDC
) m_hDC
, MM_ANISOTROPIC
);
1003 SetViewportExtEx((HDC
) m_hDC
, VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1004 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1005 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1006 ::SetWindowExtEx((HDC
) m_hDC
, m_windowExtX
, m_windowExtY
, NULL
);
1007 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1008 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1011 void wxDC::SetUserScale(double x
, double y
)
1016 SetMapMode(m_mappingMode
);
1019 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1021 m_signX
= xLeftRight
? 1 : -1;
1022 m_signY
= yBottomUp
? -1 : 1;
1024 SetMapMode(m_mappingMode
);
1027 void wxDC::SetSystemScale(double x
, double y
)
1032 SetMapMode(m_mappingMode
);
1035 void wxDC::SetLogicalOrigin(long x
, long y
)
1037 m_logicalOriginX
= x
;
1038 m_logicalOriginY
= y
;
1040 ::SetWindowOrgEx((HDC
) m_hDC
, (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1043 void wxDC::SetDeviceOrigin(long x
, long y
)
1045 m_deviceOriginX
= x
;
1046 m_deviceOriginY
= y
;
1048 ::SetViewportOrgEx((HDC
) m_hDC
, (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1051 long wxDC::DeviceToLogicalX(long x
) const
1053 return (long) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) - m_logicalOriginX
) ;
1056 long wxDC::DeviceToLogicalXRel(long x
) const
1058 return (long) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
)) ;
1061 long wxDC::DeviceToLogicalY(long y
) const
1063 return (long) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) - m_logicalOriginY
) ;
1066 long wxDC::DeviceToLogicalYRel(long y
) const
1068 return (long) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
)) ;
1071 long wxDC::LogicalToDeviceX(long x
) const
1073 return (long) (floor((x
) - m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
+ m_deviceOriginX
) ;
1076 long wxDC::LogicalToDeviceXRel(long x
) const
1078 return (long) (floor(x
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_systemScaleX
) ;
1081 long wxDC::LogicalToDeviceY(long y
) const
1083 return (long) (floor((y
) - m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
+ m_deviceOriginY
);
1086 long wxDC::LogicalToDeviceYRel(long y
) const
1088 return (long) (floor(y
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_systemScaleY
) ;
1091 // This group of functions may not do any conversion
1092 // if m_scaleGDI is TRUE, since the HDC does the
1093 // conversion automatically.
1095 long wxDC::ImplDeviceToLogicalX(long x
) const
1097 // return (m_scaleGDI ? x : DeviceToLogicalX(x));
1101 long wxDC::ImplDeviceToLogicalY(long y
) const
1103 // return (m_scaleGDI ? y : DeviceToLogicalY(y));
1107 long wxDC::ImplDeviceToLogicalXRel(long x
) const
1109 // return (m_scaleGDI ? x : DeviceToLogicalXRel(x));
1113 long wxDC::ImplDeviceToLogicalYRel(long y
) const
1115 // return (m_scaleGDI ? y : DeviceToLogicalYRel(y));
1119 long wxDC::ImplLogicalToDeviceX(long x
) const
1121 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceX(x));
1125 long wxDC::ImplLogicalToDeviceY(long y
) const
1127 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceY(y));
1131 long wxDC::ImplLogicalToDeviceXRel(long x
) const
1133 // return (m_scaleGDI ? (floor(double(x))) : LogicalToDeviceXRel(x));
1137 long wxDC::ImplLogicalToDeviceYRel(long y
) const
1139 // return (m_scaleGDI ? (floor(double(y))) : LogicalToDeviceYRel(y));
1143 bool wxDC::Blit(long xdest
, long ydest
, long width
, long height
,
1144 wxDC
*source
, long xsrc
, long ysrc
, int rop
, bool useMask
)
1146 long xdest1
= xdest
;
1147 long ydest1
= ydest
;
1151 // Chris Breeze 18/5/98: use text foreground/background colours
1152 // when blitting from 1-bit bitmaps
1153 COLORREF old_textground
= ::GetTextColor((HDC
)m_hDC
);
1154 COLORREF old_background
= ::GetBkColor((HDC
)m_hDC
);
1155 if (m_textForegroundColour
.Ok())
1157 ::SetTextColor((HDC
) m_hDC
, m_textForegroundColour
.GetPixel() ) ;
1159 if (m_textBackgroundColour
.Ok())
1161 ::SetBkColor((HDC
) m_hDC
, m_textBackgroundColour
.GetPixel() ) ;
1164 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1165 rop
== wxCLEAR
? WHITENESS
:
1166 rop
== wxSET
? BLACKNESS
:
1167 rop
== wxINVERT
? DSTINVERT
:
1168 rop
== wxAND
? MERGECOPY
:
1169 rop
== wxOR
? MERGEPAINT
:
1170 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1171 rop
== wxXOR
? SRCINVERT
:
1172 rop
== wxOR_REVERSE
? MERGEPAINT
:
1173 rop
== wxAND_REVERSE
? SRCERASE
:
1174 rop
== wxSRC_OR
? SRCPAINT
:
1175 rop
== wxSRC_AND
? SRCAND
:
1179 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1183 // Not implemented under Win95 (or maybe a specific device?)
1184 if (MaskBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1185 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1195 HDC dc_mask
= CreateCompatibleDC((HDC
) source
->m_hDC
);
1196 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1197 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1198 dc_mask
, xsrc1
, ysrc1
, 0x00220326 /* NOTSRCAND */) != 0);
1199 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1200 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, SRCPAINT
) != 0);
1201 ::SelectObject(dc_mask
, 0);
1202 ::DeleteDC(dc_mask
);
1204 // New code from Chris Breeze, 15/7/98
1205 // Blit bitmap with mask
1207 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1209 // If we are printing source colours are screen colours
1210 // not printer colours and so we need copy the bitmap
1213 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1214 HDC dc_src
= (HDC
) source
->m_hDC
;
1216 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1217 for (int x
= 0; x
< width
; x
++)
1219 for (int y
= 0; y
< height
; y
++)
1221 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1224 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1225 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1226 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1227 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1228 ::DeleteObject(brush
);
1232 ::SelectObject(dc_mask
, 0);
1233 ::DeleteDC(dc_mask
);
1237 // create a temp buffer bitmap and DCs to access it and the mask
1238 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1239 HDC dc_buffer
= ::CreateCompatibleDC((HDC
) m_hDC
);
1240 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap((HDC
) m_hDC
, width
, height
);
1241 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1242 ::SelectObject(dc_buffer
, buffer_bmap
);
1244 // copy dest to buffer
1245 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1246 (HDC
) m_hDC
, xdest1
, ydest1
, SRCCOPY
);
1248 // copy src to buffer using selected raster op
1249 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1250 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1252 // set masked area in buffer to BLACK (pixel value 0)
1253 COLORREF prevBkCol
= ::SetBkColor((HDC
) m_hDC
, RGB(255, 255, 255));
1254 COLORREF prevCol
= ::SetTextColor((HDC
) m_hDC
, RGB(0, 0, 0));
1255 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1256 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1258 // set unmasked area in dest to BLACK
1259 ::SetBkColor((HDC
) m_hDC
, RGB(0, 0, 0));
1260 ::SetTextColor((HDC
) m_hDC
, RGB(255, 255, 255));
1261 ::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1262 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1263 ::SetBkColor((HDC
) m_hDC
, prevBkCol
); // restore colours to original values
1264 ::SetTextColor((HDC
) m_hDC
, prevCol
);
1266 // OR buffer to dest
1267 success
= (::BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
,
1268 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1270 // tidy up temporary DCs and bitmap
1271 ::SelectObject(dc_mask
, 0);
1272 ::DeleteDC(dc_mask
);
1273 ::SelectObject(dc_buffer
, 0);
1274 ::DeleteDC(dc_buffer
);
1275 ::DeleteObject(buffer_bmap
);
1281 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1283 // If we are printing source colours are screen colours
1284 // not printer colours and so we need copy the bitmap
1286 HDC dc_src
= (HDC
) source
->m_hDC
;
1288 for (int x
= 0; x
< width
; x
++)
1290 for (int y
= 0; y
< height
; y
++)
1292 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1293 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1294 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1295 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1296 ::DeleteObject(brush
);
1302 success
= (BitBlt((HDC
) m_hDC
, xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1303 xsrc1
, ysrc1
, dwRop
) != 0);
1306 ::SetTextColor((HDC
)m_hDC
, old_textground
);
1307 ::SetBkColor((HDC
)m_hDC
, old_background
);
1312 void wxDC::GetSize(int* width
, int* height
) const
1314 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZRES
);
1315 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTRES
);
1320 void wxDC::GetSizeMM(long *width
, long *height
) const
1322 long w
=::GetDeviceCaps((HDC
) m_hDC
,HORZSIZE
);
1323 long h
=::GetDeviceCaps((HDC
) m_hDC
,VERTSIZE
);
1328 void wxDC::DrawPolygon(wxList
*list
, long xoffset
, long yoffset
,int fillStyle
)
1330 int n
= list
->Number();
1331 wxPoint
*points
= new wxPoint
[n
];
1334 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1335 wxPoint
*point
= (wxPoint
*)node
->Data();
1336 points
[i
].x
= point
->x
;
1337 points
[i
++].y
= point
->y
;
1339 DrawPolygon(n
, points
, xoffset
, yoffset
,fillStyle
);
1343 void wxDC::DrawLines(wxList
*list
, long xoffset
, long yoffset
)
1345 int n
= list
->Number();
1346 wxPoint
*points
= new wxPoint
[n
];
1349 for(wxNode
*node
= list
->First(); node
; node
= node
->Next()) {
1350 wxPoint
*point
= (wxPoint
*)node
->Data();
1351 points
[i
].x
= point
->x
;
1352 points
[i
++].y
= point
->y
;
1354 DrawLines(n
, points
, xoffset
, yoffset
);
1358 void wxDC::SetTextForeground(const wxColour
& colour
)
1360 m_textForegroundColour
= colour
;
1363 void wxDC::SetTextBackground(const wxColour
& colour
)
1365 m_textBackgroundColour
= colour
;
1368 // For use by wxWindows only, unless custom units are required.
1369 void wxDC::SetLogicalScale(double x
, double y
)
1371 m_logicalScaleX
= x
;
1372 m_logicalScaleY
= y
;
1375 void wxDC::CalcBoundingBox(long x
, long y
)
1377 if (x
< m_minX
) m_minX
= x
;
1378 if (y
< m_minY
) m_minY
= y
;
1379 if (x
> m_maxX
) m_maxX
= x
;
1380 if (y
> m_maxY
) m_maxY
= y
;
1383 void wxDC::GetClippingBox(long *x
,long *y
,long *w
,long *h
) const
1389 *w
= (m_clipX2
- m_clipX1
) ;
1390 *h
= (m_clipY2
- m_clipY1
) ;
1393 *x
= *y
= *w
= *h
= 0 ;
1396 #if WXWIN_COMPATIBILITY
1397 void wxDC::GetTextExtent(const wxString
& string
, float *x
, float *y
,
1398 float *descent
, float *externalLeading
,
1399 wxFont
*theFont
, bool use16bit
) const
1401 long x1
, y1
, descent1
, externalLeading1
;
1402 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1405 *descent
= descent1
;
1406 if (externalLeading
)
1407 *externalLeading
= externalLeading1
;
1411 int wxDC::GetDepth(void) const
1413 return (int) ::GetDeviceCaps((HDC
) m_hDC
,BITSPIXEL
);
1418 // Make a 3-point spline
1419 void wxDC::DrawSpline(long x1
, long y1
, long x2
, long y2
, long x3
, long y3
)
1421 wxList
*point_list
= new wxList
;
1423 wxPoint
*point1
= new wxPoint
;
1424 point1
->x
= x1
; point1
->y
= y1
;
1425 point_list
->Append((wxObject
*)point1
);
1427 wxPoint
*point2
= new wxPoint
;
1428 point2
->x
= x2
; point2
->y
= y2
;
1429 point_list
->Append((wxObject
*)point2
);
1431 wxPoint
*point3
= new wxPoint
;
1432 point3
->x
= x3
; point3
->y
= y3
;
1433 point_list
->Append((wxObject
*)point3
);
1435 DrawSpline(point_list
);
1437 for(wxNode
*node
= point_list
->First(); node
; node
= node
->Next()) {
1438 wxPoint
*p
= (wxPoint
*)node
->Data();
1444 ////#define wx_round(a) (int)((a)+.5)
1445 //#define wx_round(a) (a)
1447 class wxSpline
: public wxObject
1453 wxSpline(wxList
*list
);
1454 void DeletePoints(void);
1456 // Doesn't delete points
1460 void wxDC::DrawSpline(int n
, wxPoint points
[])
1464 for (i
=0; i
< n
; i
++)
1465 list
.Append((wxObject
*)&points
[i
]);
1466 DrawSpline((wxList
*)&list
);
1469 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1471 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1472 double a3
, double b3
, double a4
, double b4
);
1473 void wx_clear_stack(void);
1474 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1475 double *y3
, double *x4
, double *y4
);
1476 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1477 double x4
, double y4
);
1478 static bool wx_spline_add_point(double x
, double y
);
1479 static void wx_spline_draw_point_array(wxDC
*dc
);
1480 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1482 void wxDC::DrawSpline(wxList
*list
)
1484 wxSpline
spline(list
);
1486 wx_draw_open_spline(this, &spline
);
1490 wxList wx_spline_point_list
;
1492 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1495 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1496 double x1
, y1
, x2
, y2
;
1498 wxNode
*node
= spline
->points
->First();
1499 p
= (wxPoint
*)node
->Data();
1504 node
= node
->Next();
1505 p
= (wxPoint
*)node
->Data();
1509 cx1
= (double)((x1
+ x2
) / 2);
1510 cy1
= (double)((y1
+ y2
) / 2);
1511 cx2
= (double)((cx1
+ x2
) / 2);
1512 cy2
= (double)((cy1
+ y2
) / 2);
1514 wx_spline_add_point(x1
, y1
);
1516 while ((node
= node
->Next()) != NULL
)
1518 p
= (wxPoint
*)node
->Data();
1523 cx4
= (double)(x1
+ x2
) / 2;
1524 cy4
= (double)(y1
+ y2
) / 2;
1525 cx3
= (double)(x1
+ cx4
) / 2;
1526 cy3
= (double)(y1
+ cy4
) / 2;
1528 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1532 cx2
= (double)(cx1
+ x2
) / 2;
1533 cy2
= (double)(cy1
+ y2
) / 2;
1536 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1537 wx_spline_add_point(x2
, y2
);
1539 wx_spline_draw_point_array(dc
);
1543 /********************* CURVES FOR SPLINES *****************************
1545 The following spline drawing routine is from
1547 "An Algorithm for High-Speed Curve Generation"
1548 by George Merrill Chaikin,
1549 Computer Graphics and Image Processing, 3, Academic Press,
1554 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1555 Computer Graphics and Image Processing, 4, Academic Press,
1558 ***********************************************************************/
1560 #define half(z1, z2) ((z1+z2)/2.0)
1563 /* iterative version */
1565 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1568 register double xmid
, ymid
;
1569 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1572 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1574 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1575 xmid
= (double)half(x2
, x3
);
1576 ymid
= (double)half(y2
, y3
);
1577 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1578 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1579 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1580 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1582 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1583 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1584 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1585 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1591 /* utilities used by spline drawing routines */
1594 typedef struct wx_spline_stack_struct
{
1595 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1599 #define SPLINE_STACK_DEPTH 20
1600 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1601 static Stack
*wx_stack_top
;
1602 static int wx_stack_count
;
1604 void wx_clear_stack(void)
1606 wx_stack_top
= wx_spline_stack
;
1610 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1612 wx_stack_top
->x1
= x1
;
1613 wx_stack_top
->y1
= y1
;
1614 wx_stack_top
->x2
= x2
;
1615 wx_stack_top
->y2
= y2
;
1616 wx_stack_top
->x3
= x3
;
1617 wx_stack_top
->y3
= y3
;
1618 wx_stack_top
->x4
= x4
;
1619 wx_stack_top
->y4
= y4
;
1624 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1625 double *x3
, double *y3
, double *x4
, double *y4
)
1627 if (wx_stack_count
== 0)
1631 *x1
= wx_stack_top
->x1
;
1632 *y1
= wx_stack_top
->y1
;
1633 *x2
= wx_stack_top
->x2
;
1634 *y2
= wx_stack_top
->y2
;
1635 *x3
= wx_stack_top
->x3
;
1636 *y3
= wx_stack_top
->y3
;
1637 *x4
= wx_stack_top
->x4
;
1638 *y4
= wx_stack_top
->y4
;
1642 static bool wx_spline_add_point(double x
, double y
)
1644 wxPoint
*point
= new wxPoint
;
1647 wx_spline_point_list
.Append((wxObject
*)point
);
1651 static void wx_spline_draw_point_array(wxDC
*dc
)
1653 dc
->DrawLines(&wx_spline_point_list
, (double)0.0, (double)0.0);
1654 wxNode
*node
= wx_spline_point_list
.First();
1657 wxPoint
*point
= (wxPoint
*)node
->Data();
1660 node
= wx_spline_point_list
.First();
1664 wxSpline::wxSpline(wxList
*list
)
1669 wxSpline::~wxSpline(void)
1673 void wxSpline::DeletePoints(void)
1675 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1677 wxPoint
*point
= (wxPoint
*)node
->Data();
1685 #endif // wxUSE_SPLINES