1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
21 #pragma implementation "dc.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
32 #include "wx/window.h"
35 #include "wx/dialog.h"
37 #include "wx/bitmap.h"
38 #include "wx/dcmemory.h"
43 #include "wx/dcprint.h"
48 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
50 #if wxUSE_COMMON_DIALOGS
51 #if wxUSE_NORLANDER_HEADERS
61 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
63 // ---------------------------------------------------------------------------
65 // ---------------------------------------------------------------------------
67 static const int VIEWPORT_EXTENT
= 1000;
69 static const int MM_POINTS
= 9;
70 static const int MM_METRIC
= 10;
72 // usually this is defined in math.h
74 static const double M_PI
= 3.14159265358979323846;
77 // ---------------------------------------------------------------------------
79 // ---------------------------------------------------------------------------
81 // convert degrees to radians
82 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
84 // ===========================================================================
86 // ===========================================================================
88 // ---------------------------------------------------------------------------
90 // ---------------------------------------------------------------------------
92 // Default constructor
106 m_windowExtX
= VIEWPORT_EXTENT
;
107 m_windowExtY
= VIEWPORT_EXTENT
;
116 SelectOldObjects(m_hDC
);
118 if ( m_canvas
== NULL
)
119 ::DeleteDC(GetHdc());
121 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
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
)
136 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
137 if (m_selectedBitmap
.Ok())
139 m_selectedBitmap
.SetSelectedInto(NULL
);
145 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
150 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
155 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
160 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
165 m_brush
= wxNullBrush
;
167 m_palette
= wxNullPalette
;
169 m_backgroundBrush
= wxNullBrush
;
170 m_selectedBitmap
= wxNullBitmap
;
173 // ---------------------------------------------------------------------------
175 // ---------------------------------------------------------------------------
177 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
182 m_clipX2
= (int)(cx
+ cw
);
183 m_clipY2
= (int)(cy
+ ch
);
185 DoClipping((WXHDC
) m_hDC
);
188 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
190 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
192 wxRect box
= region
.GetBox();
197 m_clipX2
= box
.x
+ box
.width
;
198 m_clipY2
= box
.y
+ box
.height
;
201 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
203 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
207 void wxDC::DoClipping(WXHDC dc
)
209 if (m_clipping
&& dc
)
211 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
212 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
216 void wxDC::DestroyClippingRegion()
218 if (m_clipping
&& m_hDC
)
220 // TODO: this should restore the previous clipping region,
221 // so that OnPaint processing works correctly, and the update clipping region
222 // doesn't get destroyed after the first DestroyClippingRegion.
223 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
224 SelectClipRgn(GetHdc(), rgn
);
230 // ---------------------------------------------------------------------------
231 // query capabilities
232 // ---------------------------------------------------------------------------
234 bool wxDC::CanDrawBitmap() const
239 bool wxDC::CanGetTextExtent() const
241 // What sort of display is it?
242 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
244 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
247 int wxDC::GetDepth() const
249 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
252 // ---------------------------------------------------------------------------
254 // ---------------------------------------------------------------------------
261 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
265 // No, I think we should simply ignore this if printing on e.g.
267 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
268 if (!m_selectedBitmap
.Ok())
271 rect
.left
= 0; rect
.top
= 0;
272 rect
.right
= m_selectedBitmap
.GetWidth();
273 rect
.bottom
= m_selectedBitmap
.GetHeight();
276 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
278 DWORD colour
= GetBkColor(GetHdc());
279 HBRUSH brush
= CreateSolidBrush(colour
);
280 FillRect(GetHdc(), &rect
, brush
);
283 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
284 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
285 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
286 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
287 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
290 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
292 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
294 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
297 // quoting from the MSDN docs:
299 // Following are some of the reasons this function might fail:
301 // * The filling could not be completed.
302 // * The specified point has the boundary color specified by the
303 // crColor parameter (if FLOODFILLBORDER was requested).
304 // * The specified point does not have the color specified by
305 // crColor (if FLOODFILLSURFACE was requested)
306 // * The point is outside the clipping region that is, it is not
307 // visible on the device.
309 wxLogLastError("ExtFloodFill");
312 CalcBoundingBox(x
, y
);
315 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
317 // get the color of the pixel
318 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
320 // get the color of the pen
321 COLORREF pencolor
= 0x00ffffff;
324 pencolor
= m_pen
.GetColour().GetPixel();
327 // return the color of the pixel
330 col
->Set(GetRValue(pixelcolor
),
331 GetGValue(pixelcolor
),
332 GetBValue(pixelcolor
));
335 // check, if color of the pixels is the same as the color of the current
336 // pen and return TRUE if it is, FALSE otherwise
337 return pixelcolor
== pencolor
;
340 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
342 wxCoord x1
= x
-VIEWPORT_EXTENT
;
343 wxCoord y1
= y
-VIEWPORT_EXTENT
;
344 wxCoord x2
= x
+VIEWPORT_EXTENT
;
345 wxCoord y2
= y
+VIEWPORT_EXTENT
;
347 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
348 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
350 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
351 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
353 CalcBoundingBox(x1
, y1
);
354 CalcBoundingBox(x2
, y2
);
357 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
359 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
360 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
362 /* MATTHEW: [6] New normalization */
363 #if WX_STANDARD_GRAPHICS
364 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
367 CalcBoundingBox(x1
, y1
);
368 CalcBoundingBox(x2
, y2
);
371 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
375 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
376 if (x1
==x2
&& x2
==y2
)
378 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
382 wxCoord xx1
= XLOG2DEV(x1
);
383 wxCoord yy1
= YLOG2DEV(y1
);
384 wxCoord xx2
= XLOG2DEV(x2
);
385 wxCoord yy2
= YLOG2DEV(y2
);
386 wxCoord xxc
= XLOG2DEV(xc
);
387 wxCoord yyc
= YLOG2DEV(yc
);
388 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
390 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
391 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
392 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
393 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
394 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
395 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
397 // Have to add 1 to bottom-right corner of rectangle
398 // to make semi-circles look right (crooked line otherwise).
399 // Unfortunately this is not a reliable method, depends
400 // on the size of shape.
401 // TODO: figure out why this happens!
402 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
406 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
409 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
410 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
413 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
415 COLORREF color
= 0x00ffffff;
418 color
= m_pen
.GetColour().GetPixel();
421 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
423 CalcBoundingBox(x
, y
);
426 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
428 COLORREF old_textground
= ::GetTextColor(GetHdc());
429 COLORREF old_background
= ::GetBkColor(GetHdc());
430 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
433 if (m_textForegroundColour
.Ok())
434 { //just the oposite from what is expected see help on pattern brush
435 // 1 in mask becomes bk color
436 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
438 if (m_textBackgroundColour
.Ok())
439 { //just the oposite from what is expected
440 // 0 in mask becomes text color
441 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
444 if (m_backgroundMode
== wxTRANSPARENT
)
445 SetBkMode(GetHdc(), TRANSPARENT
);
447 SetBkMode(GetHdc(), OPAQUE
);
450 // Do things less efficiently if we have offsets
451 if (xoffset
!= 0 || yoffset
!= 0)
453 POINT
*cpoints
= new POINT
[n
];
455 for (i
= 0; i
< n
; i
++)
457 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
458 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
460 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
462 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
463 (void)Polygon(GetHdc(), cpoints
, n
);
464 SetPolyFillMode(GetHdc(),prev
);
470 for (i
= 0; i
< n
; i
++)
471 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
473 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
474 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
475 SetPolyFillMode(GetHdc(),prev
);
478 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
480 ::SetBkMode(GetHdc(), TRANSPARENT
);
481 ::SetTextColor(GetHdc(), old_textground
);
482 ::SetBkColor(GetHdc(), old_background
);
486 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
488 // Do things less efficiently if we have offsets
489 if (xoffset
!= 0 || yoffset
!= 0)
491 POINT
*cpoints
= new POINT
[n
];
493 for (i
= 0; i
< n
; i
++)
495 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
496 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
498 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
500 (void)Polyline(GetHdc(), cpoints
, n
);
506 for (i
= 0; i
< n
; i
++)
507 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
509 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
513 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
515 COLORREF colFgOld
= 0,
518 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
520 colFgOld
= ::GetTextColor(GetHdc());
521 colBgOld
= ::GetBkColor(GetHdc());
523 if ( m_textForegroundColour
.Ok() )
525 // just the oposite from what is expected see help on pattern brush
526 // 1 in mask becomes bk color
527 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel());
530 if ( m_textBackgroundColour
.Ok() )
532 // 0 in mask becomes text color
533 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel());
536 // VZ: IMHO this does strictly nothing here
537 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
541 wxCoord x2
= x
+ width
;
542 wxCoord y2
= y
+ height
;
544 // Windows draws the filled rectangles without outline (i.e. drawn with a
545 // transparent pen) one pixel smaller in both directions and we want them
546 // to have the same size regardless of which pen is used - adjust
547 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
553 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
555 CalcBoundingBox(x
, y
);
556 CalcBoundingBox(x2
, y2
);
558 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
560 // restore the colours we changed
561 ::SetBkMode(GetHdc(), TRANSPARENT
);
562 ::SetTextColor(GetHdc(), colFgOld
);
563 ::SetBkColor(GetHdc(), colBgOld
);
567 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
569 // Now, a negative radius value is interpreted to mean
570 // 'the proportion of the smallest X or Y dimension'
574 double smallest
= 0.0;
579 radius
= (- radius
* smallest
);
582 wxCoord x2
= (x
+width
);
583 wxCoord y2
= (y
+height
);
585 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
586 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
588 CalcBoundingBox(x
, y
);
589 CalcBoundingBox(x2
, y2
);
592 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
594 wxCoord x2
= (x
+width
);
595 wxCoord y2
= (y
+height
);
597 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
599 CalcBoundingBox(x
, y
);
600 CalcBoundingBox(x2
, y2
);
603 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
604 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
609 int rx1
= XLOG2DEV(x
+w
/2);
610 int ry1
= YLOG2DEV(y
+h
/2);
617 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
618 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
619 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
620 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
622 // draw pie with NULL_PEN first and then outline otherwise a line is
623 // drawn from the start and end points to the centre
624 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
627 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
632 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
633 rx1
, ry1
-1, rx2
, ry2
-1);
635 ::SelectObject(GetHdc(), orig_pen
);
636 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
639 CalcBoundingBox(x
, y
);
640 CalcBoundingBox(x2
, y2
);
643 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
645 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
647 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
649 CalcBoundingBox(x
, y
);
650 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
653 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
655 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
657 int width
= bmp
.GetWidth(),
658 height
= bmp
.GetHeight();
660 HBITMAP hbmpMask
= 0;
664 wxMask
*mask
= bmp
.GetMask();
666 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
670 // don't give assert here because this would break existing
671 // programs - just silently ignore useMask parameter
679 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
680 ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
682 // this will only work if the transparent part of our bitmap is black
683 // because it is combined with the destination rectangle using OR, so
684 // it won't be really transparent otherwise - I don't know what to do
685 // about it, may be use MAKEROP4(SRCCOPY, DSTINVERT) twice? Or create a
686 // copy of the bitmap with the transparent part replaced with black
688 bool ok
= ::MaskBlt(GetHdc(), x
, y
, width
, height
,
691 MAKEROP4(SRCCOPY
, 0x00AA0029)) != 0;
697 // VZ: this is incorrect, Blit() doesn't (and can't) draw
698 // transparently, but it's still better than nothing at all
700 // GRG: Blit() *should* draw transparently when there is a mask.
702 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
704 memDC
.SelectObject(bmp
);
706 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
708 memDC
.SelectObject(wxNullBitmap
);
711 else // no mask, just use BitBlt()
714 HDC memdc
= ::CreateCompatibleDC( cdc
);
715 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
717 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
719 COLORREF old_textground
= ::GetTextColor(GetHdc());
720 COLORREF old_background
= ::GetBkColor(GetHdc());
721 if (m_textForegroundColour
.Ok())
723 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
725 if (m_textBackgroundColour
.Ok())
727 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
730 ::SelectObject( memdc
, hbitmap
);
731 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
734 ::SetTextColor(GetHdc(), old_textground
);
735 ::SetBkColor(GetHdc(), old_background
);
739 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
741 DrawAnyText(text
, x
, y
);
743 // update the bounding box
744 CalcBoundingBox(x
, y
);
747 GetTextExtent(text
, &w
, &h
);
748 CalcBoundingBox(x
+ w
, y
+ h
);
751 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
753 // prepare for drawing the text
754 if ( m_textForegroundColour
.Ok() )
755 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
757 DWORD old_background
= 0;
758 if ( m_textBackgroundColour
.Ok() )
760 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
763 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
766 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
767 text
.c_str(), text
.length()) == 0 )
769 wxLogLastError("TextOut");
772 // restore the old parameters (text foreground colour may be left because
773 // it never is set to anything else, but background should remain
774 // transparent even if we just drew an opaque string)
775 if ( m_textBackgroundColour
.Ok() )
776 (void)SetBkColor(GetHdc(), old_background
);
778 SetBkMode(GetHdc(), TRANSPARENT
);
781 void wxDC::DoDrawRotatedText(const wxString
& text
,
782 wxCoord x
, wxCoord y
,
785 // we test that we have some font because otherwise we should still use the
786 // "else" part below to avoid that DrawRotatedText(angle = 180) and
787 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
788 // font for drawing rotated fonts unfortunately)
789 if ( (angle
== 0.0) && m_font
.Ok() )
791 DoDrawText(text
, x
, y
);
795 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
796 // can't have non zero orientation/escapement
797 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
798 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
800 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
802 wxLogLastError("GetObject(hfont)");
805 // GDI wants the angle in tenth of degree
806 long angle10
= (long)(angle
* 10);
807 lf
.lfEscapement
= angle10
;
808 lf
. lfOrientation
= angle10
;
810 hfont
= ::CreateFontIndirect(&lf
);
813 wxLogLastError("CreateFont");
817 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
819 DrawAnyText(text
, x
, y
);
821 (void)::SelectObject(GetHdc(), hfontOld
);
822 (void)::DeleteObject(hfont
);
825 // call the bounding box by adding all four vertices of the rectangle
826 // containing the text to it (simpler and probably not slower than
827 // determining which of them is really topmost/leftmost/...)
829 GetTextExtent(text
, &w
, &h
);
831 double rad
= DegToRad(angle
);
833 // "upper left" and "upper right"
834 CalcBoundingBox(x
, y
);
835 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
837 // "bottom left" and "bottom right"
838 x
+= (wxCoord
)(h
*sin(rad
));
839 y
+= (wxCoord
)(h
*cos(rad
));
840 CalcBoundingBox(x
, y
);
841 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
845 // ---------------------------------------------------------------------------
847 // ---------------------------------------------------------------------------
849 void wxDC::SetPalette(const wxPalette
& palette
)
851 // Set the old object temporarily, in case the assignment deletes an object
852 // that's not yet selected out.
855 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
863 // Setting a NULL colourmap is a way of restoring
864 // the original colourmap
867 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
874 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
876 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
878 m_oldPalette
= (WXHPALETTE
) oldPal
;
880 ::RealizePalette(GetHdc());
884 void wxDC::SetFont(const wxFont
& the_font
)
886 // Set the old object temporarily, in case the assignment deletes an object
887 // that's not yet selected out.
890 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
899 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
903 if (m_font
.Ok() && m_font
.GetResourceHandle())
905 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
906 if (f
== (HFONT
) NULL
)
908 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
911 m_oldFont
= (WXHFONT
) f
;
915 void wxDC::SetPen(const wxPen
& pen
)
917 // Set the old object temporarily, in case the assignment deletes an object
918 // that's not yet selected out.
921 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
930 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
936 if (m_pen
.GetResourceHandle())
938 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
940 m_oldPen
= (WXHPEN
) p
;
945 void wxDC::SetBrush(const wxBrush
& brush
)
947 // Set the old object temporarily, in case the assignment deletes an object
948 // that's not yet selected out.
951 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
960 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
966 if (m_brush
.GetResourceHandle())
969 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
971 m_oldBrush
= (WXHBRUSH
) b
;
976 void wxDC::SetBackground(const wxBrush
& brush
)
978 m_backgroundBrush
= brush
;
980 if (!m_backgroundBrush
.Ok())
985 bool customColours
= TRUE
;
986 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
987 // change background colours from the control-panel specified colours.
988 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
989 customColours
= FALSE
;
993 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
995 m_canvas
->SetTransparent(TRUE
);
999 // New behaviour, 10/2/99: setting the background brush of a DC
1000 // doesn't affect the window background colour. However,
1001 // I'm leaving in the transparency setting because it's needed by
1002 // various controls (e.g. wxStaticText) to determine whether to draw
1003 // transparently or not. TODO: maybe this should be a new function
1004 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1006 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1007 m_canvas
->SetTransparent(FALSE
);
1011 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1013 (void)SetBkColor(GetHdc(), new_color
);
1017 void wxDC::SetBackgroundMode(int mode
)
1019 m_backgroundMode
= mode
;
1021 // SetBackgroundColour now only refers to text background
1022 // and m_backgroundMode is used there
1025 if (m_backgroundMode == wxTRANSPARENT)
1026 ::SetBkMode(GetHdc(), TRANSPARENT);
1028 ::SetBkMode(GetHdc(), OPAQUE);
1032 void wxDC::SetLogicalFunction(int function
)
1034 m_logicalFunction
= function
;
1039 void wxDC::SetRop(WXHDC dc
)
1041 if ( !dc
|| m_logicalFunction
< 0 )
1046 switch (m_logicalFunction
)
1048 case wxXOR
: rop
= R2_XORPEN
; break;
1049 case wxINVERT
: rop
= R2_NOT
; break;
1050 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1051 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1052 case wxCLEAR
: rop
= R2_WHITE
; break;
1053 case wxSET
: rop
= R2_BLACK
; break;
1054 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1055 case wxAND
: rop
= R2_MASKPEN
; break;
1056 case wxOR
: rop
= R2_MERGEPEN
; break;
1057 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1058 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1059 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1060 case wxCOPY
: rop
= R2_COPYPEN
; break;
1061 case wxNO_OP
: rop
= R2_NOP
; break;
1062 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1063 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1065 wxFAIL_MSG( wxT("unsupported logical function") );
1069 SetROP2(GetHdc(), rop
);
1072 bool wxDC::StartDoc(const wxString
& message
)
1074 // We might be previewing, so return TRUE to let it continue.
1082 void wxDC::StartPage()
1086 void wxDC::EndPage()
1090 // ---------------------------------------------------------------------------
1092 // ---------------------------------------------------------------------------
1094 wxCoord
wxDC::GetCharHeight() const
1096 TEXTMETRIC lpTextMetric
;
1098 GetTextMetrics(GetHdc(), &lpTextMetric
);
1100 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1103 wxCoord
wxDC::GetCharWidth() const
1105 TEXTMETRIC lpTextMetric
;
1107 GetTextMetrics(GetHdc(), &lpTextMetric
);
1109 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1112 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1113 wxCoord
*descent
, wxCoord
*externalLeading
,
1114 wxFont
*theFont
) const
1116 wxFont
*fontToUse
= (wxFont
*) theFont
;
1118 fontToUse
= (wxFont
*) &m_font
;
1123 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1124 GetTextMetrics(GetHdc(), &tm
);
1126 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1127 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1128 if (descent
) *descent
= tm
.tmDescent
;
1129 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1132 void wxDC::SetMapMode(int mode
)
1134 m_mappingMode
= mode
;
1136 int pixel_width
= 0;
1137 int pixel_height
= 0;
1141 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1142 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1143 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1144 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1146 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1151 double mm2pixelsX
= pixel_width
/mm_width
;
1152 double mm2pixelsY
= pixel_height
/mm_height
;
1158 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1159 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1164 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1165 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1170 m_logicalScaleX
= mm2pixelsX
;
1171 m_logicalScaleY
= mm2pixelsY
;
1176 m_logicalScaleX
= (mm2pixelsX
/10.0);
1177 m_logicalScaleY
= (mm2pixelsY
/10.0);
1183 m_logicalScaleX
= 1.0;
1184 m_logicalScaleY
= 1.0;
1189 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1190 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1192 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1193 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1194 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1195 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1196 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1197 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1200 void wxDC::SetUserScale(double x
, double y
)
1205 SetMapMode(m_mappingMode
);
1208 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1210 m_signX
= xLeftRight
? 1 : -1;
1211 m_signY
= yBottomUp
? -1 : 1;
1213 SetMapMode(m_mappingMode
);
1216 void wxDC::SetSystemScale(double x
, double y
)
1221 SetMapMode(m_mappingMode
);
1224 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1226 m_logicalOriginX
= x
;
1227 m_logicalOriginY
= y
;
1229 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1232 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1234 m_deviceOriginX
= x
;
1235 m_deviceOriginY
= y
;
1237 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1240 // ---------------------------------------------------------------------------
1241 // coordinates transformations
1242 // ---------------------------------------------------------------------------
1244 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1246 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1249 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1251 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1254 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1256 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1259 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1261 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1264 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1266 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1269 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1271 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1274 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1276 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1279 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1281 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1284 // ---------------------------------------------------------------------------
1286 // ---------------------------------------------------------------------------
1288 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1289 wxCoord width
, wxCoord height
,
1290 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1291 int rop
, bool useMask
)
1293 wxMask
*mask
= NULL
;
1296 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1297 mask
= bmp
.GetMask();
1299 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1301 // don't give assert here because this would break existing
1302 // programs - just silently ignore useMask parameter
1307 COLORREF old_textground
= ::GetTextColor(GetHdc());
1308 COLORREF old_background
= ::GetBkColor(GetHdc());
1309 if (m_textForegroundColour
.Ok())
1311 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1313 if (m_textBackgroundColour
.Ok())
1315 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1318 DWORD dwRop
= SRCCOPY
;
1321 case wxXOR
: dwRop
= SRCINVERT
; break;
1322 case wxINVERT
: dwRop
= DSTINVERT
; break;
1323 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1324 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1325 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1326 case wxSET
: dwRop
= WHITENESS
; break;
1327 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1328 case wxAND
: dwRop
= SRCAND
; break;
1329 case wxOR
: dwRop
= SRCPAINT
; break;
1330 case wxEQUIV
: dwRop
= 0x00990066; break;
1331 case wxNAND
: dwRop
= 0x007700E6; break;
1332 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1333 case wxCOPY
: dwRop
= SRCCOPY
; break;
1334 case wxNO_OP
: dwRop
= 0x00AA0029; break;
1335 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1336 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1338 wxFAIL_MSG( wxT("unsupported logical function") );
1348 // prepare the mask bitmap
1349 HBITMAP hbmpMask
= wxInvertMask((HBITMAP
)mask
->GetMaskBitmap());
1351 // select the correct brush: the current one by default, background one
1356 hbrNew
= (HBRUSH
)m_brush
.GetResourceHandle();
1358 else if ( m_backgroundBrush
.Ok() )
1360 hbrNew
= (HBRUSH
)m_backgroundBrush
.GetResourceHandle();
1367 HGDIOBJ hbrOld
= hbrNew
? ::SelectObject(GetHdc(), hbrNew
) : 0;
1369 // we want the part of the image corresponding to the mask to be
1370 // transparent, i.e. do PATCOPY there and apply dwRop elsewhere
1372 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1373 GetHdcOf(*source
), xsrc
, ysrc
,
1375 MAKEROP4(0x00AA0029, dwRop
)) != 0;
1379 (void)::SelectObject(GetHdc(), hbrOld
);
1382 ::DeleteObject(hbmpMask
);
1387 // Blit bitmap with mask
1389 // create a temp buffer bitmap and DCs to access it and the mask
1390 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1391 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1392 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1393 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1394 ::SelectObject(dc_buffer
, buffer_bmap
);
1396 // copy dest to buffer
1397 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1398 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1400 wxLogLastError("BitBlt");
1403 // copy src to buffer using selected raster op
1404 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1405 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1407 wxLogLastError("BitBlt");
1410 // set masked area in buffer to BLACK (pixel value 0)
1411 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1412 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1413 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1414 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1416 wxLogLastError("BitBlt");
1419 // set unmasked area in dest to BLACK
1420 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1421 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1422 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1423 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1425 wxLogLastError("BitBlt");
1427 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1428 ::SetTextColor(GetHdc(), prevCol
);
1430 // OR buffer to dest
1431 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1432 (int)width
, (int)height
,
1433 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1436 wxLogLastError("BitBlt");
1439 // tidy up temporary DCs and bitmap
1440 ::SelectObject(dc_mask
, 0);
1441 ::DeleteDC(dc_mask
);
1442 ::SelectObject(dc_buffer
, 0);
1443 ::DeleteDC(dc_buffer
);
1444 ::DeleteObject(buffer_bmap
);
1447 else // no mask, just BitBlt() it
1449 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1450 (int)width
, (int)height
,
1451 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1454 wxLogLastError("BitBlt");
1457 ::SetTextColor(GetHdc(), old_textground
);
1458 ::SetBkColor(GetHdc(), old_background
);
1463 void wxDC::DoGetSize(int *w
, int *h
) const
1465 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1466 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1469 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1471 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1472 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1475 wxSize
wxDC::GetPPI() const
1477 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1478 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1480 return wxSize(x
, y
);
1483 // For use by wxWindows only, unless custom units are required.
1484 void wxDC::SetLogicalScale(double x
, double y
)
1486 m_logicalScaleX
= x
;
1487 m_logicalScaleY
= y
;
1490 #if WXWIN_COMPATIBILITY
1491 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1492 float *descent
, float *externalLeading
,
1493 wxFont
*theFont
, bool use16bit
) const
1495 wxCoord x1
, y1
, descent1
, externalLeading1
;
1496 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1499 *descent
= descent1
;
1500 if (externalLeading
)
1501 *externalLeading
= externalLeading1
;
1505 // ---------------------------------------------------------------------------
1506 // spline drawing code
1507 // ---------------------------------------------------------------------------
1511 class wxSpline
: public wxObject
1517 wxSpline(wxList
*list
);
1518 void DeletePoints();
1520 // Doesn't delete points
1524 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1526 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1527 double a3
, double b3
, double a4
, double b4
);
1528 void wx_clear_stack();
1529 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1530 double *y3
, double *x4
, double *y4
);
1531 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1532 double x4
, double y4
);
1533 static bool wx_spline_add_point(double x
, double y
);
1534 static void wx_spline_draw_point_array(wxDC
*dc
);
1535 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1537 void wxDC::DoDrawSpline(wxList
*list
)
1539 wxSpline
spline(list
);
1541 wx_draw_open_spline(this, &spline
);
1544 wxList wx_spline_point_list
;
1546 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1549 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1550 double x1
, y1
, x2
, y2
;
1552 wxNode
*node
= spline
->points
->First();
1553 p
= (wxPoint
*)node
->Data();
1558 node
= node
->Next();
1559 p
= (wxPoint
*)node
->Data();
1563 cx1
= (double)((x1
+ x2
) / 2);
1564 cy1
= (double)((y1
+ y2
) / 2);
1565 cx2
= (double)((cx1
+ x2
) / 2);
1566 cy2
= (double)((cy1
+ y2
) / 2);
1568 wx_spline_add_point(x1
, y1
);
1570 while ((node
= node
->Next()) != NULL
)
1572 p
= (wxPoint
*)node
->Data();
1577 cx4
= (double)(x1
+ x2
) / 2;
1578 cy4
= (double)(y1
+ y2
) / 2;
1579 cx3
= (double)(x1
+ cx4
) / 2;
1580 cy3
= (double)(y1
+ cy4
) / 2;
1582 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1586 cx2
= (double)(cx1
+ x2
) / 2;
1587 cy2
= (double)(cy1
+ y2
) / 2;
1590 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1591 wx_spline_add_point(x2
, y2
);
1593 wx_spline_draw_point_array(dc
);
1597 /********************* CURVES FOR SPLINES *****************************
1599 The following spline drawing routine is from
1601 "An Algorithm for High-Speed Curve Generation"
1602 by George Merrill Chaikin,
1603 Computer Graphics and Image Processing, 3, Academic Press,
1608 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1609 Computer Graphics and Image Processing, 4, Academic Press,
1612 ***********************************************************************/
1614 #define half(z1, z2) ((z1+z2)/2.0)
1617 /* iterative version */
1619 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1622 register double xmid
, ymid
;
1623 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1626 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1628 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1629 xmid
= (double)half(x2
, x3
);
1630 ymid
= (double)half(y2
, y3
);
1631 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1632 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1633 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1634 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1636 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1637 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1638 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1639 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1645 /* utilities used by spline drawing routines */
1648 typedef struct wx_spline_stack_struct
{
1649 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1653 #define SPLINE_STACK_DEPTH 20
1654 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1655 static Stack
*wx_stack_top
;
1656 static int wx_stack_count
;
1658 void wx_clear_stack()
1660 wx_stack_top
= wx_spline_stack
;
1664 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1666 wx_stack_top
->x1
= x1
;
1667 wx_stack_top
->y1
= y1
;
1668 wx_stack_top
->x2
= x2
;
1669 wx_stack_top
->y2
= y2
;
1670 wx_stack_top
->x3
= x3
;
1671 wx_stack_top
->y3
= y3
;
1672 wx_stack_top
->x4
= x4
;
1673 wx_stack_top
->y4
= y4
;
1678 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1679 double *x3
, double *y3
, double *x4
, double *y4
)
1681 if (wx_stack_count
== 0)
1685 *x1
= wx_stack_top
->x1
;
1686 *y1
= wx_stack_top
->y1
;
1687 *x2
= wx_stack_top
->x2
;
1688 *y2
= wx_stack_top
->y2
;
1689 *x3
= wx_stack_top
->x3
;
1690 *y3
= wx_stack_top
->y3
;
1691 *x4
= wx_stack_top
->x4
;
1692 *y4
= wx_stack_top
->y4
;
1696 static bool wx_spline_add_point(double x
, double y
)
1698 wxPoint
*point
= new wxPoint
;
1701 wx_spline_point_list
.Append((wxObject
*)point
);
1705 static void wx_spline_draw_point_array(wxDC
*dc
)
1707 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1708 wxNode
*node
= wx_spline_point_list
.First();
1711 wxPoint
*point
= (wxPoint
*)node
->Data();
1714 node
= wx_spline_point_list
.First();
1718 wxSpline::wxSpline(wxList
*list
)
1723 wxSpline::~wxSpline()
1727 void wxSpline::DeletePoints()
1729 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1731 wxPoint
*point
= (wxPoint
*)node
->Data();
1739 #endif // wxUSE_SPLINES