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 #if wxUSE_COMMON_DIALOGS
49 #if wxUSE_NORLANDER_HEADERS
59 #include "wx/msw/private.h"
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 wxCHECK_RET( m_selectedBitmap
.Ok(), wxT("this DC can't be cleared") );
267 rect
.left
= 0; rect
.top
= 0;
268 rect
.right
= m_selectedBitmap
.GetWidth();
269 rect
.bottom
= m_selectedBitmap
.GetHeight();
272 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
274 DWORD colour
= GetBkColor(GetHdc());
275 HBRUSH brush
= CreateSolidBrush(colour
);
276 FillRect(GetHdc(), &rect
, brush
);
279 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
280 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
281 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
282 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
283 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
286 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
288 (void)ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
290 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
293 CalcBoundingBox(x
, y
);
296 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
298 // added by steve 29.12.94 (copied from DrawPoint)
299 // returns TRUE for pixels in the color of the current pen
300 // and FALSE for all other pixels colors
301 // if col is non-NULL return the color of the pixel
303 // get the color of the pixel
304 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
305 // get the color of the pen
306 COLORREF pencolor
= 0x00ffffff;
309 pencolor
= m_pen
.GetColour().GetPixel();
312 // return the color of the pixel
314 col
->Set(GetRValue(pixelcolor
),GetGValue(pixelcolor
),GetBValue(pixelcolor
));
316 // check, if color of the pixels is the same as the color
317 // of the current pen
318 return(pixelcolor
==pencolor
);
321 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
323 wxCoord x1
= x
-VIEWPORT_EXTENT
;
324 wxCoord y1
= y
-VIEWPORT_EXTENT
;
325 wxCoord x2
= x
+VIEWPORT_EXTENT
;
326 wxCoord y2
= y
+VIEWPORT_EXTENT
;
328 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
329 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
331 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
332 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
334 CalcBoundingBox(x1
, y1
);
335 CalcBoundingBox(x2
, y2
);
338 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
340 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
341 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
343 /* MATTHEW: [6] New normalization */
344 #if WX_STANDARD_GRAPHICS
345 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
348 CalcBoundingBox(x1
, y1
);
349 CalcBoundingBox(x2
, y2
);
352 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
356 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
357 if (x1
==x2
&& x2
==y2
)
359 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
363 wxCoord xx1
= XLOG2DEV(x1
);
364 wxCoord yy1
= YLOG2DEV(y1
);
365 wxCoord xx2
= XLOG2DEV(x2
);
366 wxCoord yy2
= YLOG2DEV(y2
);
367 wxCoord xxc
= XLOG2DEV(xc
);
368 wxCoord yyc
= YLOG2DEV(yc
);
369 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
371 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
372 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
373 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
374 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
375 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
376 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
378 // Have to add 1 to bottom-right corner of rectangle
379 // to make semi-circles look right (crooked line otherwise).
380 // Unfortunately this is not a reliable method, depends
381 // on the size of shape.
382 // TODO: figure out why this happens!
383 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
387 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
390 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
391 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
394 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
396 COLORREF color
= 0x00ffffff;
399 color
= m_pen
.GetColour().GetPixel();
402 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
404 CalcBoundingBox(x
, y
);
407 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
409 // Do things less efficiently if we have offsets
410 if (xoffset
!= 0 || yoffset
!= 0)
412 POINT
*cpoints
= new POINT
[n
];
414 for (i
= 0; i
< n
; i
++)
416 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
417 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
419 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
421 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
422 (void)Polygon(GetHdc(), cpoints
, n
);
423 SetPolyFillMode(GetHdc(),prev
);
429 for (i
= 0; i
< n
; i
++)
430 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
432 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
433 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
434 SetPolyFillMode(GetHdc(),prev
);
438 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
440 // Do things less efficiently if we have offsets
441 if (xoffset
!= 0 || yoffset
!= 0)
443 POINT
*cpoints
= new POINT
[n
];
445 for (i
= 0; i
< n
; i
++)
447 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
448 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
450 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
452 (void)Polyline(GetHdc(), cpoints
, n
);
458 for (i
= 0; i
< n
; i
++)
459 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
461 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
465 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
467 wxCoord x2
= x
+ width
;
468 wxCoord y2
= y
+ height
;
470 /* MATTHEW: [6] new normalization */
471 #if WX_STANDARD_GRAPHICS
472 bool do_brush
, do_pen
;
474 do_brush
= m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
;
475 do_pen
= m_pen
.Ok() && m_pen
.GetStyle() != wxTRANSPARENT
;
478 HPEN orig_pen
= NULL
;
480 if (do_pen
|| !m_pen
.Ok())
481 orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
483 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
484 XLOG2DEV(x2
) + 1, YLOG2DEV(y2
) + 1);
486 if (do_pen
|| !m_pen
.Ok())
487 ::SelectObject(GetHdc() , orig_pen
);
490 HBRUSH orig_brush
= NULL
;
492 if (do_brush
|| !m_brush
.Ok())
493 orig_brush
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
) ::GetStockObject(NULL_BRUSH
));
495 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
496 XLOG2DEV(x2
), YLOG2DEV(y2
));
498 if (do_brush
|| !m_brush
.Ok())
499 ::SelectObject(GetHdc(), orig_brush
);
502 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
505 CalcBoundingBox(x
, y
);
506 CalcBoundingBox(x2
, y2
);
509 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
511 // Now, a negative radius value is interpreted to mean
512 // 'the proportion of the smallest X or Y dimension'
516 double smallest
= 0.0;
521 radius
= (- radius
* smallest
);
524 wxCoord x2
= (x
+width
);
525 wxCoord y2
= (y
+height
);
527 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
528 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
530 CalcBoundingBox(x
, y
);
531 CalcBoundingBox(x2
, y2
);
534 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
536 wxCoord x2
= (x
+width
);
537 wxCoord y2
= (y
+height
);
539 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
541 CalcBoundingBox(x
, y
);
542 CalcBoundingBox(x2
, y2
);
545 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
546 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
551 int rx1
= XLOG2DEV(x
+w
/2);
552 int ry1
= YLOG2DEV(y
+h
/2);
559 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
560 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
561 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
562 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
564 // draw pie with NULL_PEN first and then outline otherwise a line is
565 // drawn from the start and end points to the centre
566 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
569 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
574 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
575 rx1
, ry1
-1, rx2
, ry2
-1);
577 ::SelectObject(GetHdc(), orig_pen
);
578 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
581 CalcBoundingBox(x
, y
);
582 CalcBoundingBox(x2
, y2
);
585 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
587 #if defined(__WIN32__) && !defined(__SC__) && !defined(__TWIN32__)
588 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON(),
589 icon
.GetWidth(), icon
.GetHeight(), 0, 0, DI_NORMAL
);
591 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), (HICON
) icon
.GetHICON());
594 CalcBoundingBox(x
, y
);
595 CalcBoundingBox(x
+icon
.GetWidth(), y
+icon
.GetHeight());
598 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
603 bool needsPixelCopy
= FALSE
;
604 bool isPrinter
= FALSE
;
605 if (IsKindOf(CLASSINFO(wxPrinterDC
)) )
608 if ( ::GetDeviceCaps((HDC
) m_hDC
, RASTERCAPS
) & RC_STRETCHDIB
)
613 needsPixelCopy
= TRUE
;
616 // If we're not drawing transparently, and not drawing to a printer,
617 // optimize this function to use Windows functions.
618 if (!useMask
&& !needsPixelCopy
)
622 BITMAPINFO
*info
= (BITMAPINFO
*) malloc( sizeof( BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
) ) ;
623 int iBitsSize
= ((bmp
.GetWidth() + 3 ) & ~3 ) * bmp
.GetHeight() ;
625 void* bits
= malloc( iBitsSize
) ;
627 memset( info
, 0 , sizeof( BITMAPINFOHEADER
) ) ;
629 info
->bmiHeader
.biSize
= sizeof( BITMAPINFOHEADER
) ;
630 info
->bmiHeader
.biWidth
= bmp
.GetWidth() ;
631 info
->bmiHeader
.biHeight
= bmp
.GetHeight() ;
632 info
->bmiHeader
.biPlanes
= 1 ;
633 info
->bmiHeader
.biBitCount
= 8 ;
634 info
->bmiHeader
.biCompression
= BI_RGB
;
636 HDC display
= GetDC( NULL
) ;
637 if ( GetDIBits( display
, (HBITMAP
) bmp
.GetHBITMAP( ) , 0 , bmp
.GetHeight() , bits
, info
, DIB_RGB_COLORS
) )
639 StretchDIBits( (HDC
) m_hDC
,
640 x
, y
, bmp
.GetWidth(), bmp
.GetHeight() ,
641 0 , 0 ,bmp
.GetWidth(), bmp
.GetHeight() ,
642 bits
, info
, DIB_RGB_COLORS
, SRCCOPY
) ;
644 ReleaseDC( NULL
, display
) ;
651 HDC memdc
= ::CreateCompatibleDC( cdc
);
652 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
654 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
656 COLORREF old_textground
= ::GetTextColor(GetHdc());
657 COLORREF old_background
= ::GetBkColor(GetHdc());
658 if (m_textForegroundColour
.Ok())
660 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
662 if (m_textBackgroundColour
.Ok())
664 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
667 ::SelectObject( memdc
, hbitmap
);
668 ::BitBlt( cdc
, x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), memdc
, 0, 0, SRCCOPY
);
671 ::SetTextColor(GetHdc(), old_textground
);
672 ::SetBkColor(GetHdc(), old_background
);
677 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
679 memDC
.SelectObject(bmp
);
681 /* Not sure if we need this. The mask should leave the
682 * masked areas as per the original background of this DC.
685 // There might be transparent areas, so make these
686 // the same colour as this DC
687 memDC.SetBackground(* GetBackground());
691 Blit(x
, y
, bmp
.GetWidth(), bmp
.GetHeight(), & memDC
, 0, 0, wxCOPY
, useMask
);
693 memDC
.SelectObject(wxNullBitmap
);
697 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
699 DrawAnyText(text
, x
, y
);
701 // update the bounding box
702 CalcBoundingBox(x
, y
);
705 GetTextExtent(text
, &w
, &h
);
706 CalcBoundingBox(x
+ w
, y
+ h
);
709 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
711 // prepare for drawing the text
712 if ( m_textForegroundColour
.Ok() )
713 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
715 DWORD old_background
= 0;
716 if ( m_textBackgroundColour
.Ok() )
718 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
721 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
724 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
725 text
.c_str(), text
.length()) == 0 )
727 wxLogLastError("TextOut");
730 // restore the old parameters (text foreground colour may be left because
731 // it never is set to anything else, but background should remain
732 // transparent even if we just drew an opaque string)
733 if ( m_textBackgroundColour
.Ok() )
734 (void)SetBkColor(GetHdc(), old_background
);
736 SetBkMode(GetHdc(), TRANSPARENT
);
739 void wxDC::DoDrawRotatedText(const wxString
& text
,
740 wxCoord x
, wxCoord y
,
743 // we test that we have some font because otherwise we should still use the
744 // "else" part below to avoid that DrawRotatedText(angle = 180) and
745 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
746 // font for drawing rotated fonts unfortunately)
747 if ( (angle
== 0.0) && m_font
.Ok() )
749 DoDrawText(text
, x
, y
);
753 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
754 // can't have non zero orientation/escapement
755 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
756 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
758 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
760 wxLogLastError("GetObject(hfont)");
763 // GDI wants the angle in tenth of degree
764 long angle10
= (long)(angle
* 10);
765 lf
.lfEscapement
= angle10
;
766 lf
. lfOrientation
= angle10
;
768 hfont
= ::CreateFontIndirect(&lf
);
771 wxLogLastError("CreateFont");
775 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
777 DrawAnyText(text
, x
, y
);
779 (void)::SelectObject(GetHdc(), hfontOld
);
782 // call the bounding box by adding all four vertices of the rectangle
783 // containing the text to it (simpler and probably not slower than
784 // determining which of them is really topmost/leftmost/...)
786 GetTextExtent(text
, &w
, &h
);
788 double rad
= DegToRad(angle
);
790 // "upper left" and "upper right"
791 CalcBoundingBox(x
, y
);
792 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
794 // "bottom left" and "bottom right"
795 x
+= (wxCoord
)(h
*sin(rad
));
796 y
+= (wxCoord
)(h
*cos(rad
));
797 CalcBoundingBox(x
, y
);
798 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
802 // ---------------------------------------------------------------------------
804 // ---------------------------------------------------------------------------
806 void wxDC::SetPalette(const wxPalette
& palette
)
808 // Set the old object temporarily, in case the assignment deletes an object
809 // that's not yet selected out.
812 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
820 // Setting a NULL colourmap is a way of restoring
821 // the original colourmap
824 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
831 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
833 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
835 m_oldPalette
= (WXHPALETTE
) oldPal
;
837 ::RealizePalette(GetHdc());
841 void wxDC::SetFont(const wxFont
& the_font
)
843 // Set the old object temporarily, in case the assignment deletes an object
844 // that's not yet selected out.
847 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
856 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
860 if (m_font
.Ok() && m_font
.GetResourceHandle())
862 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
863 if (f
== (HFONT
) NULL
)
865 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
868 m_oldFont
= (WXHFONT
) f
;
872 void wxDC::SetPen(const wxPen
& pen
)
874 // Set the old object temporarily, in case the assignment deletes an object
875 // that's not yet selected out.
878 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
887 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
893 if (m_pen
.GetResourceHandle())
895 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
897 m_oldPen
= (WXHPEN
) p
;
902 void wxDC::SetBrush(const wxBrush
& brush
)
904 // Set the old object temporarily, in case the assignment deletes an object
905 // that's not yet selected out.
908 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
917 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
923 if (m_brush
.GetResourceHandle())
926 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
928 m_oldBrush
= (WXHBRUSH
) b
;
933 void wxDC::SetBackground(const wxBrush
& brush
)
935 m_backgroundBrush
= brush
;
937 if (!m_backgroundBrush
.Ok())
942 bool customColours
= TRUE
;
943 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
944 // change background colours from the control-panel specified colours.
945 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
946 customColours
= FALSE
;
950 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
952 m_canvas
->SetTransparent(TRUE
);
956 // New behaviour, 10/2/99: setting the background brush of a DC
957 // doesn't affect the window background colour. However,
958 // I'm leaving in the transparency setting because it's needed by
959 // various controls (e.g. wxStaticText) to determine whether to draw
960 // transparently or not. TODO: maybe this should be a new function
961 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
963 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
964 m_canvas
->SetTransparent(FALSE
);
968 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
970 (void)SetBkColor(GetHdc(), new_color
);
974 void wxDC::SetBackgroundMode(int mode
)
976 m_backgroundMode
= mode
;
978 // SetBackgroundColour now only refers to text background
979 // and m_backgroundMode is used there
982 if (m_backgroundMode == wxTRANSPARENT)
983 ::SetBkMode(GetHdc(), TRANSPARENT);
985 ::SetBkMode(GetHdc(), OPAQUE);
989 void wxDC::SetLogicalFunction(int function
)
991 m_logicalFunction
= function
;
993 SetRop((WXHDC
) m_hDC
);
996 void wxDC::SetRop(WXHDC dc
)
998 if (!dc
|| m_logicalFunction
< 0)
1002 // These may be wrong
1003 switch (m_logicalFunction
)
1005 // case wxXOR: c_rop = R2_XORPEN; break;
1006 case wxXOR
: c_rop
= R2_NOTXORPEN
; break;
1007 case wxINVERT
: c_rop
= R2_NOT
; break;
1008 case wxOR_REVERSE
: c_rop
= R2_MERGEPENNOT
; break;
1009 case wxAND_REVERSE
: c_rop
= R2_MASKPENNOT
; break;
1010 case wxCLEAR
: c_rop
= R2_WHITE
; break;
1011 case wxSET
: c_rop
= R2_BLACK
; break;
1012 case wxSRC_INVERT
: c_rop
= R2_NOTCOPYPEN
; break;
1013 case wxOR_INVERT
: c_rop
= R2_MERGENOTPEN
; break;
1014 case wxAND
: c_rop
= R2_MASKPEN
; break;
1015 case wxOR
: c_rop
= R2_MERGEPEN
; break;
1016 case wxAND_INVERT
: c_rop
= R2_MASKNOTPEN
; break;
1021 c_rop
= R2_COPYPEN
; break;
1023 SetROP2((HDC
) dc
, c_rop
);
1026 bool wxDC::StartDoc(const wxString
& message
)
1028 // We might be previewing, so return TRUE to let it continue.
1036 void wxDC::StartPage()
1040 void wxDC::EndPage()
1044 // ---------------------------------------------------------------------------
1046 // ---------------------------------------------------------------------------
1048 wxCoord
wxDC::GetCharHeight() const
1050 TEXTMETRIC lpTextMetric
;
1052 GetTextMetrics(GetHdc(), &lpTextMetric
);
1054 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1057 wxCoord
wxDC::GetCharWidth() const
1059 TEXTMETRIC lpTextMetric
;
1061 GetTextMetrics(GetHdc(), &lpTextMetric
);
1063 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1066 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1067 wxCoord
*descent
, wxCoord
*externalLeading
,
1068 wxFont
*theFont
) const
1070 wxFont
*fontToUse
= (wxFont
*) theFont
;
1072 fontToUse
= (wxFont
*) &m_font
;
1077 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1078 GetTextMetrics(GetHdc(), &tm
);
1080 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1081 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1082 if (descent
) *descent
= tm
.tmDescent
;
1083 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1086 void wxDC::SetMapMode(int mode
)
1088 m_mappingMode
= mode
;
1090 int pixel_width
= 0;
1091 int pixel_height
= 0;
1095 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1096 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1097 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1098 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1100 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1105 double mm2pixelsX
= pixel_width
/mm_width
;
1106 double mm2pixelsY
= pixel_height
/mm_height
;
1112 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1113 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1118 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1119 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1124 m_logicalScaleX
= mm2pixelsX
;
1125 m_logicalScaleY
= mm2pixelsY
;
1130 m_logicalScaleX
= (mm2pixelsX
/10.0);
1131 m_logicalScaleY
= (mm2pixelsY
/10.0);
1137 m_logicalScaleX
= 1.0;
1138 m_logicalScaleY
= 1.0;
1143 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1144 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1146 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1147 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1148 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1149 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1150 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1151 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1154 void wxDC::SetUserScale(double x
, double y
)
1159 SetMapMode(m_mappingMode
);
1162 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1164 m_signX
= xLeftRight
? 1 : -1;
1165 m_signY
= yBottomUp
? -1 : 1;
1167 SetMapMode(m_mappingMode
);
1170 void wxDC::SetSystemScale(double x
, double y
)
1175 SetMapMode(m_mappingMode
);
1178 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1180 m_logicalOriginX
= x
;
1181 m_logicalOriginY
= y
;
1183 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1186 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1188 m_deviceOriginX
= x
;
1189 m_deviceOriginY
= y
;
1191 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1194 // ---------------------------------------------------------------------------
1195 // coordinates transformations
1196 // ---------------------------------------------------------------------------
1198 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1200 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1203 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1205 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1208 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1210 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1213 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1215 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1218 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1220 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1223 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1225 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1228 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1230 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1233 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1235 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1238 // ---------------------------------------------------------------------------
1240 // ---------------------------------------------------------------------------
1241 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
1242 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
, int rop
, bool useMask
)
1244 wxCoord xdest1
= xdest
;
1245 wxCoord ydest1
= ydest
;
1246 wxCoord xsrc1
= xsrc
;
1247 wxCoord ysrc1
= ysrc
;
1249 COLORREF old_textground
= ::GetTextColor(GetHdc());
1250 COLORREF old_background
= ::GetBkColor(GetHdc());
1251 if (m_textForegroundColour
.Ok())
1253 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1255 if (m_textBackgroundColour
.Ok())
1257 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1260 DWORD dwRop
= rop
== wxCOPY
? SRCCOPY
:
1261 rop
== wxCLEAR
? WHITENESS
:
1262 rop
== wxSET
? BLACKNESS
:
1263 rop
== wxINVERT
? DSTINVERT
:
1264 rop
== wxAND
? MERGECOPY
:
1265 rop
== wxOR
? MERGEPAINT
:
1266 rop
== wxSRC_INVERT
? NOTSRCCOPY
:
1267 rop
== wxXOR
? SRCINVERT
:
1268 rop
== wxOR_REVERSE
? MERGEPAINT
:
1269 rop
== wxAND_REVERSE
? SRCERASE
:
1270 rop
== wxSRC_OR
? SRCPAINT
:
1271 rop
== wxSRC_AND
? SRCAND
:
1274 bool success
= TRUE
;
1275 if (useMask
&& source
->m_selectedBitmap
.Ok() && source
->m_selectedBitmap
.GetMask())
1279 // Not implemented under Win95 (or maybe a specific device?)
1280 if (MaskBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1281 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap(),
1289 // New code from Chris Breeze, 15/7/98
1290 // Blit bitmap with mask
1292 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1294 // If we are printing source colours are screen colours
1295 // not printer colours and so we need copy the bitmap
1298 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1299 HDC dc_src
= (HDC
) source
->m_hDC
;
1301 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1302 for (int x
= 0; x
< width
; x
++)
1304 for (int y
= 0; y
< height
; y
++)
1306 COLORREF cref
= ::GetPixel(dc_mask
, x
, y
);
1309 HBRUSH brush
= ::CreateSolidBrush(::GetPixel(dc_src
, x
, y
));
1310 rect
.left
= xdest1
+ x
; rect
.right
= rect
.left
+ 1;
1311 rect
.top
= ydest1
+ y
; rect
.bottom
= rect
.top
+ 1;
1312 ::FillRect(GetHdc(), &rect
, brush
);
1313 ::DeleteObject(brush
);
1317 ::SelectObject(dc_mask
, 0);
1318 ::DeleteDC(dc_mask
);
1322 // create a temp buffer bitmap and DCs to access it and the mask
1323 HDC dc_mask
= ::CreateCompatibleDC((HDC
) source
->m_hDC
);
1324 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1325 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1326 ::SelectObject(dc_mask
, (HBITMAP
) source
->m_selectedBitmap
.GetMask()->GetMaskBitmap());
1327 ::SelectObject(dc_buffer
, buffer_bmap
);
1329 // copy dest to buffer
1330 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1331 GetHdc(), xdest1
, ydest1
, SRCCOPY
);
1333 // copy src to buffer using selected raster op
1334 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1335 (HDC
) source
->m_hDC
, xsrc1
, ysrc1
, dwRop
);
1337 // set masked area in buffer to BLACK (pixel value 0)
1338 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1339 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1340 ::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1341 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1343 // set unmasked area in dest to BLACK
1344 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1345 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1346 ::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1347 dc_mask
, xsrc1
, ysrc1
, SRCAND
);
1348 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1349 ::SetTextColor(GetHdc(), prevCol
);
1351 // OR buffer to dest
1352 success
= (::BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
,
1353 dc_buffer
, 0, 0, SRCPAINT
) != 0);
1355 // tidy up temporary DCs and bitmap
1356 ::SelectObject(dc_mask
, 0);
1357 ::DeleteDC(dc_mask
);
1358 ::SelectObject(dc_buffer
, 0);
1359 ::DeleteDC(dc_buffer
);
1360 ::DeleteObject(buffer_bmap
);
1366 // If we are printing, source colours are screen colours
1367 // not printer colours and so we need copy the bitmap
1369 if (IsKindOf(CLASSINFO(wxPrinterDC
)))
1371 HDC dc_src
= (HDC
) source
->m_hDC
;
1373 for (int y
= 0; y
< height
; y
++)
1375 // This is Stefan Csomor's optimisation, where
1376 // identical adjacent pixels are drawn together.
1377 // We still need a faster way of drawing bitmaps,
1378 // perhaps converting to a DIB first and using SetDIBitsToDevice.
1379 for (int x
= 0; x
< width
; x
++)
1381 COLORREF col
= ::GetPixel(dc_src
, x
, y
) ;
1382 HBRUSH brush
= ::CreateSolidBrush( col
);
1384 rect
.left
= xdest1
+ x
;
1385 rect
.top
= ydest1
+ y
;
1386 while( (x
+ 1 < width
) && (::GetPixel(dc_src
, x
+ 1, y
) == col
) )
1390 rect
.right
= xdest1
+ x
+ 1;
1391 rect
.bottom
= rect
.top
+ 1;
1392 ::FillRect((HDC
) m_hDC
, &rect
, brush
);
1393 ::DeleteObject(brush
);
1397 HDC dc_src = (HDC) source->m_hDC;
1399 for (int x = 0; x < width; x++)
1401 for (int y = 0; y < height; y++)
1403 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
1404 rect.left = xdest1 + x; rect.right = rect.left + 1;
1405 rect.top = ydest1 + y; rect.bottom = rect.top + 1;
1406 ::FillRect(GetHdc(), &rect, brush);
1407 ::DeleteObject(brush);
1414 success
= (BitBlt(GetHdc(), xdest1
, ydest1
, (int)width
, (int)height
, (HDC
) source
->m_hDC
,
1415 xsrc1
, ysrc1
, dwRop
) != 0);
1418 ::SetTextColor(GetHdc(), old_textground
);
1419 ::SetBkColor(GetHdc(), old_background
);
1424 void wxDC::DoGetSize(int *w
, int *h
) const
1426 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1427 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1430 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1432 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1433 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1436 wxSize
wxDC::GetPPI() const
1438 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1439 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1441 return wxSize(x
, y
);
1444 // For use by wxWindows only, unless custom units are required.
1445 void wxDC::SetLogicalScale(double x
, double y
)
1447 m_logicalScaleX
= x
;
1448 m_logicalScaleY
= y
;
1451 #if WXWIN_COMPATIBILITY
1452 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1453 float *descent
, float *externalLeading
,
1454 wxFont
*theFont
, bool use16bit
) const
1456 wxCoord x1
, y1
, descent1
, externalLeading1
;
1457 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1460 *descent
= descent1
;
1461 if (externalLeading
)
1462 *externalLeading
= externalLeading1
;
1466 // ---------------------------------------------------------------------------
1467 // spline drawing code
1468 // ---------------------------------------------------------------------------
1472 class wxSpline
: public wxObject
1478 wxSpline(wxList
*list
);
1479 void DeletePoints();
1481 // Doesn't delete points
1485 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1487 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1488 double a3
, double b3
, double a4
, double b4
);
1489 void wx_clear_stack();
1490 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1491 double *y3
, double *x4
, double *y4
);
1492 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1493 double x4
, double y4
);
1494 static bool wx_spline_add_point(double x
, double y
);
1495 static void wx_spline_draw_point_array(wxDC
*dc
);
1496 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1498 void wxDC::DoDrawSpline(wxList
*list
)
1500 wxSpline
spline(list
);
1502 wx_draw_open_spline(this, &spline
);
1505 wxList wx_spline_point_list
;
1507 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1510 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1511 double x1
, y1
, x2
, y2
;
1513 wxNode
*node
= spline
->points
->First();
1514 p
= (wxPoint
*)node
->Data();
1519 node
= node
->Next();
1520 p
= (wxPoint
*)node
->Data();
1524 cx1
= (double)((x1
+ x2
) / 2);
1525 cy1
= (double)((y1
+ y2
) / 2);
1526 cx2
= (double)((cx1
+ x2
) / 2);
1527 cy2
= (double)((cy1
+ y2
) / 2);
1529 wx_spline_add_point(x1
, y1
);
1531 while ((node
= node
->Next()) != NULL
)
1533 p
= (wxPoint
*)node
->Data();
1538 cx4
= (double)(x1
+ x2
) / 2;
1539 cy4
= (double)(y1
+ y2
) / 2;
1540 cx3
= (double)(x1
+ cx4
) / 2;
1541 cy3
= (double)(y1
+ cy4
) / 2;
1543 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1547 cx2
= (double)(cx1
+ x2
) / 2;
1548 cy2
= (double)(cy1
+ y2
) / 2;
1551 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1552 wx_spline_add_point(x2
, y2
);
1554 wx_spline_draw_point_array(dc
);
1558 /********************* CURVES FOR SPLINES *****************************
1560 The following spline drawing routine is from
1562 "An Algorithm for High-Speed Curve Generation"
1563 by George Merrill Chaikin,
1564 Computer Graphics and Image Processing, 3, Academic Press,
1569 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1570 Computer Graphics and Image Processing, 4, Academic Press,
1573 ***********************************************************************/
1575 #define half(z1, z2) ((z1+z2)/2.0)
1578 /* iterative version */
1580 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1583 register double xmid
, ymid
;
1584 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1587 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1589 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1590 xmid
= (double)half(x2
, x3
);
1591 ymid
= (double)half(y2
, y3
);
1592 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1593 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1594 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1595 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1597 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1598 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1599 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1600 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1606 /* utilities used by spline drawing routines */
1609 typedef struct wx_spline_stack_struct
{
1610 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1614 #define SPLINE_STACK_DEPTH 20
1615 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1616 static Stack
*wx_stack_top
;
1617 static int wx_stack_count
;
1619 void wx_clear_stack()
1621 wx_stack_top
= wx_spline_stack
;
1625 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1627 wx_stack_top
->x1
= x1
;
1628 wx_stack_top
->y1
= y1
;
1629 wx_stack_top
->x2
= x2
;
1630 wx_stack_top
->y2
= y2
;
1631 wx_stack_top
->x3
= x3
;
1632 wx_stack_top
->y3
= y3
;
1633 wx_stack_top
->x4
= x4
;
1634 wx_stack_top
->y4
= y4
;
1639 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1640 double *x3
, double *y3
, double *x4
, double *y4
)
1642 if (wx_stack_count
== 0)
1646 *x1
= wx_stack_top
->x1
;
1647 *y1
= wx_stack_top
->y1
;
1648 *x2
= wx_stack_top
->x2
;
1649 *y2
= wx_stack_top
->y2
;
1650 *x3
= wx_stack_top
->x3
;
1651 *y3
= wx_stack_top
->y3
;
1652 *x4
= wx_stack_top
->x4
;
1653 *y4
= wx_stack_top
->y4
;
1657 static bool wx_spline_add_point(double x
, double y
)
1659 wxPoint
*point
= new wxPoint
;
1662 wx_spline_point_list
.Append((wxObject
*)point
);
1666 static void wx_spline_draw_point_array(wxDC
*dc
)
1668 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1669 wxNode
*node
= wx_spline_point_list
.First();
1672 wxPoint
*point
= (wxPoint
*)node
->Data();
1675 node
= wx_spline_point_list
.First();
1679 wxSpline::wxSpline(wxList
*list
)
1684 wxSpline::~wxSpline()
1688 void wxSpline::DeletePoints()
1690 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1692 wxPoint
*point
= (wxPoint
*)node
->Data();
1700 #endif // wxUSE_SPLINES