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
58 IMPLEMENT_ABSTRACT_CLASS(wxDC
, wxObject
)
60 // ---------------------------------------------------------------------------
62 // ---------------------------------------------------------------------------
64 static const int VIEWPORT_EXTENT
= 1000;
66 static const int MM_POINTS
= 9;
67 static const int MM_METRIC
= 10;
69 // usually this is defined in math.h
71 static const double M_PI
= 3.14159265358979323846;
74 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
75 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
76 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
78 // ---------------------------------------------------------------------------
80 // ---------------------------------------------------------------------------
82 // convert degrees to radians
83 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
85 // ===========================================================================
87 // ===========================================================================
89 // ---------------------------------------------------------------------------
91 // ---------------------------------------------------------------------------
93 // Default constructor
107 m_windowExtX
= VIEWPORT_EXTENT
;
108 m_windowExtY
= VIEWPORT_EXTENT
;
117 SelectOldObjects(m_hDC
);
119 if ( m_canvas
== NULL
)
120 ::DeleteDC(GetHdc());
122 ::ReleaseDC((HWND
)m_canvas
->GetHWND(), GetHdc());
128 // This will select current objects out of the DC,
129 // which is what you have to do before deleting the
131 void wxDC::SelectOldObjects(WXHDC dc
)
137 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
138 if (m_selectedBitmap
.Ok())
140 m_selectedBitmap
.SetSelectedInto(NULL
);
146 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
151 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
156 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
161 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, TRUE
);
166 m_brush
= wxNullBrush
;
168 m_palette
= wxNullPalette
;
170 m_backgroundBrush
= wxNullBrush
;
171 m_selectedBitmap
= wxNullBitmap
;
174 // ---------------------------------------------------------------------------
176 // ---------------------------------------------------------------------------
178 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
183 m_clipX2
= (int)(cx
+ cw
);
184 m_clipY2
= (int)(cy
+ ch
);
186 DoClipping((WXHDC
) m_hDC
);
189 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
191 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
193 wxRect box
= region
.GetBox();
198 m_clipX2
= box
.x
+ box
.width
;
199 m_clipY2
= box
.y
+ box
.height
;
202 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
204 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
208 void wxDC::DoClipping(WXHDC dc
)
210 if (m_clipping
&& dc
)
212 IntersectClipRect((HDC
) dc
, XLOG2DEV(m_clipX1
), YLOG2DEV(m_clipY1
),
213 XLOG2DEV(m_clipX2
), YLOG2DEV(m_clipY2
));
217 void wxDC::DestroyClippingRegion()
219 if (m_clipping
&& m_hDC
)
221 // TODO: this should restore the previous clipping region,
222 // so that OnPaint processing works correctly, and the update clipping region
223 // doesn't get destroyed after the first DestroyClippingRegion.
224 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
225 SelectClipRgn(GetHdc(), rgn
);
231 // ---------------------------------------------------------------------------
232 // query capabilities
233 // ---------------------------------------------------------------------------
235 bool wxDC::CanDrawBitmap() const
240 bool wxDC::CanGetTextExtent() const
242 // What sort of display is it?
243 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
245 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
248 int wxDC::GetDepth() const
250 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
253 // ---------------------------------------------------------------------------
255 // ---------------------------------------------------------------------------
262 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
266 // No, I think we should simply ignore this if printing on e.g.
268 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
269 if (!m_selectedBitmap
.Ok())
272 rect
.left
= 0; rect
.top
= 0;
273 rect
.right
= m_selectedBitmap
.GetWidth();
274 rect
.bottom
= m_selectedBitmap
.GetHeight();
277 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
279 DWORD colour
= GetBkColor(GetHdc());
280 HBRUSH brush
= CreateSolidBrush(colour
);
281 FillRect(GetHdc(), &rect
, brush
);
284 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
285 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
286 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
287 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
288 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
291 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
293 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
295 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
298 // quoting from the MSDN docs:
300 // Following are some of the reasons this function might fail:
302 // * The filling could not be completed.
303 // * The specified point has the boundary color specified by the
304 // crColor parameter (if FLOODFILLBORDER was requested).
305 // * The specified point does not have the color specified by
306 // crColor (if FLOODFILLSURFACE was requested)
307 // * The point is outside the clipping region that is, it is not
308 // visible on the device.
310 wxLogLastError("ExtFloodFill");
313 CalcBoundingBox(x
, y
);
316 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
318 // get the color of the pixel
319 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
321 // get the color of the pen
322 COLORREF pencolor
= 0x00ffffff;
325 pencolor
= m_pen
.GetColour().GetPixel();
328 // return the color of the pixel
331 col
->Set(GetRValue(pixelcolor
),
332 GetGValue(pixelcolor
),
333 GetBValue(pixelcolor
));
336 // check, if color of the pixels is the same as the color of the current
337 // pen and return TRUE if it is, FALSE otherwise
338 return pixelcolor
== pencolor
;
341 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
343 wxCoord x1
= x
-VIEWPORT_EXTENT
;
344 wxCoord y1
= y
-VIEWPORT_EXTENT
;
345 wxCoord x2
= x
+VIEWPORT_EXTENT
;
346 wxCoord y2
= y
+VIEWPORT_EXTENT
;
348 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
349 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
351 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
352 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
354 CalcBoundingBox(x1
, y1
);
355 CalcBoundingBox(x2
, y2
);
358 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
360 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
361 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
363 // Normalization: Windows doesn't draw the last point of the line
364 (void)LineTo(GetHdc(), XLOG2DEV(x2
) + 1, YLOG2DEV(y2
));
366 CalcBoundingBox(x1
, y1
);
367 CalcBoundingBox(x2
, y2
);
370 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
374 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
375 if (x1
==x2
&& x2
==y2
)
377 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
381 wxCoord xx1
= XLOG2DEV(x1
);
382 wxCoord yy1
= YLOG2DEV(y1
);
383 wxCoord xx2
= XLOG2DEV(x2
);
384 wxCoord yy2
= YLOG2DEV(y2
);
385 wxCoord xxc
= XLOG2DEV(xc
);
386 wxCoord yyc
= YLOG2DEV(yc
);
387 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
389 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
390 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
391 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
392 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
393 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
394 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
396 // Have to add 1 to bottom-right corner of rectangle
397 // to make semi-circles look right (crooked line otherwise).
398 // Unfortunately this is not a reliable method, depends
399 // on the size of shape.
400 // TODO: figure out why this happens!
401 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
405 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
408 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
409 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
412 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
413 wxCoord width
, wxCoord height
)
415 wxCoord x2
= x1
+ width
,
418 #if defined(__WIN32__) && !defined(__SC__)
425 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
427 // In WIN16, draw a cross
428 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
429 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
430 HPEN hPenOld
= (HPEN
)::SelectObject(hdcMem
, blackPen
);
431 HPEN hBrushOld
= (HPEN
)::SelectObject(hdcMem
, whiteBrush
);
432 ::SetROP2(GetHdc(), R2_COPYPEN
);
433 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
434 MoveTo(GetHdc(), x1
, y1
);
435 LineTo(GetHdc(), x2
, y2
);
436 MoveTo(GetHdc(), x2
, y1
);
437 LineTo(GetHdc(), x1
, y2
);
438 ::SelectObject(GetHdc(), hPenOld
);
439 ::SelectObject(GetHdc(), hBrushOld
);
440 ::DeleteObject(blackPen
);
443 CalcBoundingBox(x1
, y1
);
444 CalcBoundingBox(x2
, y2
);
447 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
449 COLORREF color
= 0x00ffffff;
452 color
= m_pen
.GetColour().GetPixel();
455 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
457 CalcBoundingBox(x
, y
);
460 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
462 COLORREF old_textground
= ::GetTextColor(GetHdc());
463 COLORREF old_background
= ::GetBkColor(GetHdc());
464 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
467 if (m_textForegroundColour
.Ok())
468 { //just the oposite from what is expected see help on pattern brush
469 // 1 in mask becomes bk color
470 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
472 if (m_textBackgroundColour
.Ok())
473 { //just the oposite from what is expected
474 // 0 in mask becomes text color
475 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
478 if (m_backgroundMode
== wxTRANSPARENT
)
479 SetBkMode(GetHdc(), TRANSPARENT
);
481 SetBkMode(GetHdc(), OPAQUE
);
484 // Do things less efficiently if we have offsets
485 if (xoffset
!= 0 || yoffset
!= 0)
487 POINT
*cpoints
= new POINT
[n
];
489 for (i
= 0; i
< n
; i
++)
491 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
492 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
494 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
496 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
497 (void)Polygon(GetHdc(), cpoints
, n
);
498 SetPolyFillMode(GetHdc(),prev
);
504 for (i
= 0; i
< n
; i
++)
505 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
507 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
508 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
509 SetPolyFillMode(GetHdc(),prev
);
512 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
514 ::SetBkMode(GetHdc(), TRANSPARENT
);
515 ::SetTextColor(GetHdc(), old_textground
);
516 ::SetBkColor(GetHdc(), old_background
);
520 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
522 // Do things less efficiently if we have offsets
523 if (xoffset
!= 0 || yoffset
!= 0)
525 POINT
*cpoints
= new POINT
[n
];
527 for (i
= 0; i
< n
; i
++)
529 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
530 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
532 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
534 (void)Polyline(GetHdc(), cpoints
, n
);
540 for (i
= 0; i
< n
; i
++)
541 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
543 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
547 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
549 COLORREF colFgOld
= 0,
552 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
554 colFgOld
= ::GetTextColor(GetHdc());
555 colBgOld
= ::GetBkColor(GetHdc());
557 if ( m_textForegroundColour
.Ok() )
559 // just the oposite from what is expected see help on pattern brush
560 // 1 in mask becomes bk color
561 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel());
564 if ( m_textBackgroundColour
.Ok() )
566 // 0 in mask becomes text color
567 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel());
570 // VZ: IMHO this does strictly nothing here
571 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
575 wxCoord x2
= x
+ width
;
576 wxCoord y2
= y
+ height
;
578 // Windows draws the filled rectangles without outline (i.e. drawn with a
579 // transparent pen) one pixel smaller in both directions and we want them
580 // to have the same size regardless of which pen is used - adjust
581 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
587 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
589 CalcBoundingBox(x
, y
);
590 CalcBoundingBox(x2
, y2
);
592 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
594 // restore the colours we changed
595 ::SetBkMode(GetHdc(), TRANSPARENT
);
596 ::SetTextColor(GetHdc(), colFgOld
);
597 ::SetBkColor(GetHdc(), colBgOld
);
601 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
603 // Now, a negative radius value is interpreted to mean
604 // 'the proportion of the smallest X or Y dimension'
608 double smallest
= 0.0;
613 radius
= (- radius
* smallest
);
616 wxCoord x2
= (x
+width
);
617 wxCoord y2
= (y
+height
);
619 // Windows draws the filled rectangles without outline (i.e. drawn with a
620 // transparent pen) one pixel smaller in both directions and we want them
621 // to have the same size regardless of which pen is used - adjust
622 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
628 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
629 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
631 CalcBoundingBox(x
, y
);
632 CalcBoundingBox(x2
, y2
);
635 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
637 wxCoord x2
= (x
+width
);
638 wxCoord y2
= (y
+height
);
640 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
642 CalcBoundingBox(x
, y
);
643 CalcBoundingBox(x2
, y2
);
646 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
647 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
652 int rx1
= XLOG2DEV(x
+w
/2);
653 int ry1
= YLOG2DEV(y
+h
/2);
660 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
661 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
662 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
663 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
665 // draw pie with NULL_PEN first and then outline otherwise a line is
666 // drawn from the start and end points to the centre
667 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
670 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
675 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
676 rx1
, ry1
-1, rx2
, ry2
-1);
678 ::SelectObject(GetHdc(), orig_pen
);
679 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
682 CalcBoundingBox(x
, y
);
683 CalcBoundingBox(x2
, y2
);
686 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
688 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
690 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
692 CalcBoundingBox(x
, y
);
693 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
696 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
698 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
700 int width
= bmp
.GetWidth(),
701 height
= bmp
.GetHeight();
703 HBITMAP hbmpMask
= 0;
707 wxMask
*mask
= bmp
.GetMask();
709 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
713 // don't give assert here because this would break existing
714 // programs - just silently ignore useMask parameter
722 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
723 ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
725 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
727 bool ok
= ::MaskBlt(GetHdc(), x
, y
, width
, height
,
730 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
736 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
739 memDC
.SelectObject(bmp
);
741 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
743 memDC
.SelectObject(wxNullBitmap
);
746 else // no mask, just use BitBlt()
749 HDC memdc
= ::CreateCompatibleDC( cdc
);
750 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
752 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
754 COLORREF old_textground
= ::GetTextColor(GetHdc());
755 COLORREF old_background
= ::GetBkColor(GetHdc());
756 if (m_textForegroundColour
.Ok())
758 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
760 if (m_textBackgroundColour
.Ok())
762 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
765 ::SelectObject( memdc
, hbitmap
);
766 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
769 ::SetTextColor(GetHdc(), old_textground
);
770 ::SetBkColor(GetHdc(), old_background
);
774 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
776 DrawAnyText(text
, x
, y
);
778 // update the bounding box
779 CalcBoundingBox(x
, y
);
782 GetTextExtent(text
, &w
, &h
);
783 CalcBoundingBox(x
+ w
, y
+ h
);
786 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
788 // prepare for drawing the text
789 if ( m_textForegroundColour
.Ok() )
790 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
792 DWORD old_background
= 0;
793 if ( m_textBackgroundColour
.Ok() )
795 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
798 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
801 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
802 text
.c_str(), text
.length()) == 0 )
804 wxLogLastError("TextOut");
807 // restore the old parameters (text foreground colour may be left because
808 // it never is set to anything else, but background should remain
809 // transparent even if we just drew an opaque string)
810 if ( m_textBackgroundColour
.Ok() )
811 (void)SetBkColor(GetHdc(), old_background
);
813 SetBkMode(GetHdc(), TRANSPARENT
);
816 void wxDC::DoDrawRotatedText(const wxString
& text
,
817 wxCoord x
, wxCoord y
,
820 // we test that we have some font because otherwise we should still use the
821 // "else" part below to avoid that DrawRotatedText(angle = 180) and
822 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
823 // font for drawing rotated fonts unfortunately)
824 if ( (angle
== 0.0) && m_font
.Ok() )
826 DoDrawText(text
, x
, y
);
830 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
831 // can't have non zero orientation/escapement
832 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
833 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
835 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
837 wxLogLastError("GetObject(hfont)");
840 // GDI wants the angle in tenth of degree
841 long angle10
= (long)(angle
* 10);
842 lf
.lfEscapement
= angle10
;
843 lf
. lfOrientation
= angle10
;
845 hfont
= ::CreateFontIndirect(&lf
);
848 wxLogLastError("CreateFont");
852 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
854 DrawAnyText(text
, x
, y
);
856 (void)::SelectObject(GetHdc(), hfontOld
);
857 (void)::DeleteObject(hfont
);
860 // call the bounding box by adding all four vertices of the rectangle
861 // containing the text to it (simpler and probably not slower than
862 // determining which of them is really topmost/leftmost/...)
864 GetTextExtent(text
, &w
, &h
);
866 double rad
= DegToRad(angle
);
868 // "upper left" and "upper right"
869 CalcBoundingBox(x
, y
);
870 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
872 // "bottom left" and "bottom right"
873 x
+= (wxCoord
)(h
*sin(rad
));
874 y
+= (wxCoord
)(h
*cos(rad
));
875 CalcBoundingBox(x
, y
);
876 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
880 // ---------------------------------------------------------------------------
882 // ---------------------------------------------------------------------------
884 void wxDC::SetPalette(const wxPalette
& palette
)
886 // Set the old object temporarily, in case the assignment deletes an object
887 // that's not yet selected out.
890 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
898 // Setting a NULL colourmap is a way of restoring
899 // the original colourmap
902 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
909 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
911 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
913 m_oldPalette
= (WXHPALETTE
) oldPal
;
915 ::RealizePalette(GetHdc());
919 void wxDC::SetFont(const wxFont
& the_font
)
921 // Set the old object temporarily, in case the assignment deletes an object
922 // that's not yet selected out.
925 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
934 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
938 if (m_font
.Ok() && m_font
.GetResourceHandle())
940 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
941 if (f
== (HFONT
) NULL
)
943 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
946 m_oldFont
= (WXHFONT
) f
;
950 void wxDC::SetPen(const wxPen
& pen
)
952 // Set the old object temporarily, in case the assignment deletes an object
953 // that's not yet selected out.
956 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
965 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
971 if (m_pen
.GetResourceHandle())
973 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
975 m_oldPen
= (WXHPEN
) p
;
980 void wxDC::SetBrush(const wxBrush
& brush
)
982 // Set the old object temporarily, in case the assignment deletes an object
983 // that's not yet selected out.
986 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
995 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1001 if (m_brush
.GetResourceHandle())
1004 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1006 m_oldBrush
= (WXHBRUSH
) b
;
1011 void wxDC::SetBackground(const wxBrush
& brush
)
1013 m_backgroundBrush
= brush
;
1015 if (!m_backgroundBrush
.Ok())
1020 bool customColours
= TRUE
;
1021 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1022 // change background colours from the control-panel specified colours.
1023 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1024 customColours
= FALSE
;
1028 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1030 m_canvas
->SetTransparent(TRUE
);
1034 // New behaviour, 10/2/99: setting the background brush of a DC
1035 // doesn't affect the window background colour. However,
1036 // I'm leaving in the transparency setting because it's needed by
1037 // various controls (e.g. wxStaticText) to determine whether to draw
1038 // transparently or not. TODO: maybe this should be a new function
1039 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1041 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1042 m_canvas
->SetTransparent(FALSE
);
1046 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1048 (void)SetBkColor(GetHdc(), new_color
);
1052 void wxDC::SetBackgroundMode(int mode
)
1054 m_backgroundMode
= mode
;
1056 // SetBackgroundColour now only refers to text background
1057 // and m_backgroundMode is used there
1060 if (m_backgroundMode == wxTRANSPARENT)
1061 ::SetBkMode(GetHdc(), TRANSPARENT);
1063 ::SetBkMode(GetHdc(), OPAQUE);
1067 void wxDC::SetLogicalFunction(int function
)
1069 m_logicalFunction
= function
;
1074 void wxDC::SetRop(WXHDC dc
)
1076 if ( !dc
|| m_logicalFunction
< 0 )
1081 switch (m_logicalFunction
)
1083 case wxCLEAR
: rop
= R2_BLACK
; break;
1084 case wxXOR
: rop
= R2_XORPEN
; break;
1085 case wxINVERT
: rop
= R2_NOT
; break;
1086 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1087 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1088 case wxCOPY
: rop
= R2_COPYPEN
; break;
1089 case wxAND
: rop
= R2_MASKPEN
; break;
1090 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1091 case wxNO_OP
: rop
= R2_NOP
; break;
1092 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1093 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1094 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1095 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1096 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1097 case wxOR
: rop
= R2_MERGEPEN
; break;
1098 case wxSET
: rop
= R2_WHITE
; break;
1101 wxFAIL_MSG( wxT("unsupported logical function") );
1105 SetROP2(GetHdc(), rop
);
1108 bool wxDC::StartDoc(const wxString
& message
)
1110 // We might be previewing, so return TRUE to let it continue.
1118 void wxDC::StartPage()
1122 void wxDC::EndPage()
1126 // ---------------------------------------------------------------------------
1128 // ---------------------------------------------------------------------------
1130 wxCoord
wxDC::GetCharHeight() const
1132 TEXTMETRIC lpTextMetric
;
1134 GetTextMetrics(GetHdc(), &lpTextMetric
);
1136 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1139 wxCoord
wxDC::GetCharWidth() const
1141 TEXTMETRIC lpTextMetric
;
1143 GetTextMetrics(GetHdc(), &lpTextMetric
);
1145 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1148 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1149 wxCoord
*descent
, wxCoord
*externalLeading
,
1150 wxFont
*theFont
) const
1152 wxFont
*fontToUse
= (wxFont
*) theFont
;
1154 fontToUse
= (wxFont
*) &m_font
;
1159 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1160 GetTextMetrics(GetHdc(), &tm
);
1162 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1163 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1164 if (descent
) *descent
= tm
.tmDescent
;
1165 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1168 void wxDC::SetMapMode(int mode
)
1170 m_mappingMode
= mode
;
1172 int pixel_width
= 0;
1173 int pixel_height
= 0;
1177 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1178 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1179 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1180 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1182 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1187 double mm2pixelsX
= pixel_width
/mm_width
;
1188 double mm2pixelsY
= pixel_height
/mm_height
;
1194 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1195 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1200 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1201 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1206 m_logicalScaleX
= mm2pixelsX
;
1207 m_logicalScaleY
= mm2pixelsY
;
1212 m_logicalScaleX
= (mm2pixelsX
/10.0);
1213 m_logicalScaleY
= (mm2pixelsY
/10.0);
1219 m_logicalScaleX
= 1.0;
1220 m_logicalScaleY
= 1.0;
1225 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1226 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1228 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1229 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1230 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1231 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1232 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1233 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1236 void wxDC::SetUserScale(double x
, double y
)
1241 SetMapMode(m_mappingMode
);
1244 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1246 m_signX
= xLeftRight
? 1 : -1;
1247 m_signY
= yBottomUp
? -1 : 1;
1249 SetMapMode(m_mappingMode
);
1252 void wxDC::SetSystemScale(double x
, double y
)
1257 SetMapMode(m_mappingMode
);
1260 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1262 m_logicalOriginX
= x
;
1263 m_logicalOriginY
= y
;
1265 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1268 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1270 m_deviceOriginX
= x
;
1271 m_deviceOriginY
= y
;
1273 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1276 // ---------------------------------------------------------------------------
1277 // coordinates transformations
1278 // ---------------------------------------------------------------------------
1280 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1282 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1285 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1287 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1290 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1292 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1295 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1297 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1300 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1302 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1305 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1307 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1310 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1312 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1315 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1317 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1320 // ---------------------------------------------------------------------------
1322 // ---------------------------------------------------------------------------
1324 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1325 wxCoord width
, wxCoord height
,
1326 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1327 int rop
, bool useMask
)
1329 wxMask
*mask
= NULL
;
1332 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1333 mask
= bmp
.GetMask();
1335 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1337 // don't give assert here because this would break existing
1338 // programs - just silently ignore useMask parameter
1343 COLORREF old_textground
= ::GetTextColor(GetHdc());
1344 COLORREF old_background
= ::GetBkColor(GetHdc());
1345 if (m_textForegroundColour
.Ok())
1347 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1349 if (m_textBackgroundColour
.Ok())
1351 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1354 DWORD dwRop
= SRCCOPY
;
1357 case wxXOR
: dwRop
= SRCINVERT
; break;
1358 case wxINVERT
: dwRop
= DSTINVERT
; break;
1359 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1360 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1361 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1362 case wxSET
: dwRop
= WHITENESS
; break;
1363 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1364 case wxAND
: dwRop
= SRCAND
; break;
1365 case wxOR
: dwRop
= SRCPAINT
; break;
1366 case wxEQUIV
: dwRop
= 0x00990066; break;
1367 case wxNAND
: dwRop
= 0x007700E6; break;
1368 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1369 case wxCOPY
: dwRop
= SRCCOPY
; break;
1370 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1371 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1372 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1374 wxFAIL_MSG( wxT("unsupported logical function") );
1383 // we want the part of the image corresponding to the mask to be
1384 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1385 // meaning of fg and bg is inverted which corresponds to wxWin notion
1386 // of the mask which is also contrary to the Windows one)
1387 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1388 GetHdcOf(*source
), xsrc
, ysrc
,
1389 (HBITMAP
)mask
->GetMaskBitmap(), 0, 0,
1390 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1395 // Blit bitmap with mask
1397 // create a temp buffer bitmap and DCs to access it and the mask
1398 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1399 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1400 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1401 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1402 ::SelectObject(dc_buffer
, buffer_bmap
);
1404 // copy dest to buffer
1405 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1406 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1408 wxLogLastError("BitBlt");
1411 // copy src to buffer using selected raster op
1412 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1413 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1415 wxLogLastError("BitBlt");
1418 // set masked area in buffer to BLACK (pixel value 0)
1419 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1420 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1421 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1422 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1424 wxLogLastError("BitBlt");
1427 // set unmasked area in dest to BLACK
1428 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1429 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1430 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1431 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1433 wxLogLastError("BitBlt");
1435 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1436 ::SetTextColor(GetHdc(), prevCol
);
1438 // OR buffer to dest
1439 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1440 (int)width
, (int)height
,
1441 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1444 wxLogLastError("BitBlt");
1447 // tidy up temporary DCs and bitmap
1448 ::SelectObject(dc_mask
, 0);
1449 ::DeleteDC(dc_mask
);
1450 ::SelectObject(dc_buffer
, 0);
1451 ::DeleteDC(dc_buffer
);
1452 ::DeleteObject(buffer_bmap
);
1455 else // no mask, just BitBlt() it
1457 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1458 (int)width
, (int)height
,
1459 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1462 wxLogLastError("BitBlt");
1465 ::SetTextColor(GetHdc(), old_textground
);
1466 ::SetBkColor(GetHdc(), old_background
);
1471 void wxDC::DoGetSize(int *w
, int *h
) const
1473 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1474 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1477 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1479 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1480 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1483 wxSize
wxDC::GetPPI() const
1485 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1486 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1488 return wxSize(x
, y
);
1491 // For use by wxWindows only, unless custom units are required.
1492 void wxDC::SetLogicalScale(double x
, double y
)
1494 m_logicalScaleX
= x
;
1495 m_logicalScaleY
= y
;
1498 #if WXWIN_COMPATIBILITY
1499 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1500 float *descent
, float *externalLeading
,
1501 wxFont
*theFont
, bool use16bit
) const
1503 wxCoord x1
, y1
, descent1
, externalLeading1
;
1504 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1507 *descent
= descent1
;
1508 if (externalLeading
)
1509 *externalLeading
= externalLeading1
;
1513 // ---------------------------------------------------------------------------
1514 // spline drawing code
1515 // ---------------------------------------------------------------------------
1519 class wxSpline
: public wxObject
1525 wxSpline(wxList
*list
);
1526 void DeletePoints();
1528 // Doesn't delete points
1532 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1534 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1535 double a3
, double b3
, double a4
, double b4
);
1536 void wx_clear_stack();
1537 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1538 double *y3
, double *x4
, double *y4
);
1539 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1540 double x4
, double y4
);
1541 static bool wx_spline_add_point(double x
, double y
);
1542 static void wx_spline_draw_point_array(wxDC
*dc
);
1543 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1545 void wxDC::DoDrawSpline(wxList
*list
)
1547 wxSpline
spline(list
);
1549 wx_draw_open_spline(this, &spline
);
1552 wxList wx_spline_point_list
;
1554 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1557 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1558 double x1
, y1
, x2
, y2
;
1560 wxNode
*node
= spline
->points
->First();
1561 p
= (wxPoint
*)node
->Data();
1566 node
= node
->Next();
1567 p
= (wxPoint
*)node
->Data();
1571 cx1
= (double)((x1
+ x2
) / 2);
1572 cy1
= (double)((y1
+ y2
) / 2);
1573 cx2
= (double)((cx1
+ x2
) / 2);
1574 cy2
= (double)((cy1
+ y2
) / 2);
1576 wx_spline_add_point(x1
, y1
);
1578 while ((node
= node
->Next()) != NULL
)
1580 p
= (wxPoint
*)node
->Data();
1585 cx4
= (double)(x1
+ x2
) / 2;
1586 cy4
= (double)(y1
+ y2
) / 2;
1587 cx3
= (double)(x1
+ cx4
) / 2;
1588 cy3
= (double)(y1
+ cy4
) / 2;
1590 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1594 cx2
= (double)(cx1
+ x2
) / 2;
1595 cy2
= (double)(cy1
+ y2
) / 2;
1598 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1599 wx_spline_add_point(x2
, y2
);
1601 wx_spline_draw_point_array(dc
);
1605 /********************* CURVES FOR SPLINES *****************************
1607 The following spline drawing routine is from
1609 "An Algorithm for High-Speed Curve Generation"
1610 by George Merrill Chaikin,
1611 Computer Graphics and Image Processing, 3, Academic Press,
1616 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1617 Computer Graphics and Image Processing, 4, Academic Press,
1620 ***********************************************************************/
1622 #define half(z1, z2) ((z1+z2)/2.0)
1625 /* iterative version */
1627 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1630 register double xmid
, ymid
;
1631 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1634 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1636 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1637 xmid
= (double)half(x2
, x3
);
1638 ymid
= (double)half(y2
, y3
);
1639 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1640 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1641 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1642 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1644 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1645 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1646 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1647 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1653 /* utilities used by spline drawing routines */
1656 typedef struct wx_spline_stack_struct
{
1657 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1661 #define SPLINE_STACK_DEPTH 20
1662 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1663 static Stack
*wx_stack_top
;
1664 static int wx_stack_count
;
1666 void wx_clear_stack()
1668 wx_stack_top
= wx_spline_stack
;
1672 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1674 wx_stack_top
->x1
= x1
;
1675 wx_stack_top
->y1
= y1
;
1676 wx_stack_top
->x2
= x2
;
1677 wx_stack_top
->y2
= y2
;
1678 wx_stack_top
->x3
= x3
;
1679 wx_stack_top
->y3
= y3
;
1680 wx_stack_top
->x4
= x4
;
1681 wx_stack_top
->y4
= y4
;
1686 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1687 double *x3
, double *y3
, double *x4
, double *y4
)
1689 if (wx_stack_count
== 0)
1693 *x1
= wx_stack_top
->x1
;
1694 *y1
= wx_stack_top
->y1
;
1695 *x2
= wx_stack_top
->x2
;
1696 *y2
= wx_stack_top
->y2
;
1697 *x3
= wx_stack_top
->x3
;
1698 *y3
= wx_stack_top
->y3
;
1699 *x4
= wx_stack_top
->x4
;
1700 *y4
= wx_stack_top
->y4
;
1704 static bool wx_spline_add_point(double x
, double y
)
1706 wxPoint
*point
= new wxPoint
;
1709 wx_spline_point_list
.Append((wxObject
*)point
);
1713 static void wx_spline_draw_point_array(wxDC
*dc
)
1715 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1716 wxNode
*node
= wx_spline_point_list
.First();
1719 wxPoint
*point
= (wxPoint
*)node
->Data();
1722 node
= wx_spline_point_list
.First();
1726 wxSpline::wxSpline(wxList
*list
)
1731 wxSpline::~wxSpline()
1735 void wxSpline::DeletePoints()
1737 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1739 wxPoint
*point
= (wxPoint
*)node
->Data();
1747 #endif // wxUSE_SPLINES