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 #define DO_SET_CLIPPING_BOX() \
182 GetClipBox(GetHdc(), &rect); \
184 m_clipX1 = (wxCoord) XDEV2LOG(rect.left); \
185 m_clipY1 = (wxCoord) YDEV2LOG(rect.top); \
186 m_clipX2 = (wxCoord) XDEV2LOG(rect.right); \
187 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom); \
190 void wxDC::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
193 IntersectClipRect(GetHdc(), XLOG2DEV(cx
), YLOG2DEV(cy
),
194 XLOG2DEV(cx
+ cw
), YLOG2DEV(cy
+ ch
));
195 DO_SET_CLIPPING_BOX()
198 void wxDC::DoSetClippingRegionAsRegion(const wxRegion
& region
)
200 wxCHECK_RET( region
.GetHRGN(), wxT("invalid clipping region") );
205 SelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN());
207 ExtSelectClipRgn(GetHdc(), (HRGN
) region
.GetHRGN(), RGN_AND
);
210 DO_SET_CLIPPING_BOX()
213 void wxDC::DestroyClippingRegion()
215 if (m_clipping
&& m_hDC
)
217 // TODO: this should restore the previous clipping region,
218 // so that OnPaint processing works correctly, and the update clipping region
219 // doesn't get destroyed after the first DestroyClippingRegion.
220 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
221 SelectClipRgn(GetHdc(), rgn
);
227 // ---------------------------------------------------------------------------
228 // query capabilities
229 // ---------------------------------------------------------------------------
231 bool wxDC::CanDrawBitmap() const
236 bool wxDC::CanGetTextExtent() const
238 // What sort of display is it?
239 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
241 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
244 int wxDC::GetDepth() const
246 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
249 // ---------------------------------------------------------------------------
251 // ---------------------------------------------------------------------------
258 GetClientRect((HWND
) m_canvas
->GetHWND(), &rect
);
262 // No, I think we should simply ignore this if printing on e.g.
264 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
265 if (!m_selectedBitmap
.Ok())
268 rect
.left
= 0; rect
.top
= 0;
269 rect
.right
= m_selectedBitmap
.GetWidth();
270 rect
.bottom
= m_selectedBitmap
.GetHeight();
273 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
275 DWORD colour
= GetBkColor(GetHdc());
276 HBRUSH brush
= CreateSolidBrush(colour
);
277 FillRect(GetHdc(), &rect
, brush
);
280 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
281 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
282 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
283 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
284 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
287 void wxDC::DoFloodFill(wxCoord x
, wxCoord y
, const wxColour
& col
, int style
)
289 if ( !::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
291 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
294 // quoting from the MSDN docs:
296 // Following are some of the reasons this function might fail:
298 // * The filling could not be completed.
299 // * The specified point has the boundary color specified by the
300 // crColor parameter (if FLOODFILLBORDER was requested).
301 // * The specified point does not have the color specified by
302 // crColor (if FLOODFILLSURFACE was requested)
303 // * The point is outside the clipping region that is, it is not
304 // visible on the device.
306 wxLogLastError("ExtFloodFill");
309 CalcBoundingBox(x
, y
);
312 bool wxDC::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
314 // get the color of the pixel
315 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
317 // JACS: what was this for?
319 // get the color of the pen
320 COLORREF pencolor
= 0x00ffffff;
323 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 // JACS, 24/02/2000: can't understand the reason for this, so returning TRUE instead.
338 // return pixelcolor == pencolor;
343 void wxDC::DoCrossHair(wxCoord x
, wxCoord y
)
345 wxCoord x1
= x
-VIEWPORT_EXTENT
;
346 wxCoord y1
= y
-VIEWPORT_EXTENT
;
347 wxCoord x2
= x
+VIEWPORT_EXTENT
;
348 wxCoord y2
= y
+VIEWPORT_EXTENT
;
350 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), NULL
);
351 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y
));
353 (void)MoveToEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), NULL
);
354 (void)LineTo(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y2
));
356 CalcBoundingBox(x1
, y1
);
357 CalcBoundingBox(x2
, y2
);
360 void wxDC::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
362 (void)MoveToEx(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), NULL
);
363 (void)LineTo(GetHdc(), XLOG2DEV(x2
), YLOG2DEV(y2
));
365 // Normalization: Windows doesn't draw the last point of the line.
366 // But apparently neither does GTK+, so we take it out again.
367 // (void)LineTo(GetHdc(), XLOG2DEV(x2) + 1, YLOG2DEV(y2));
369 CalcBoundingBox(x1
, y1
);
370 CalcBoundingBox(x2
, y2
);
373 void wxDC::DoDrawArc(wxCoord x1
,wxCoord y1
,wxCoord x2
,wxCoord y2
, wxCoord xc
, wxCoord yc
)
377 double radius
= (double)sqrt(dx
*dx
+dy
*dy
) ;;
378 if (x1
==x2
&& x2
==y2
)
380 DrawEllipse(xc
,yc
,(wxCoord
)(radius
*2.0),(wxCoord
)(radius
*2.0));
384 wxCoord xx1
= XLOG2DEV(x1
);
385 wxCoord yy1
= YLOG2DEV(y1
);
386 wxCoord xx2
= XLOG2DEV(x2
);
387 wxCoord yy2
= YLOG2DEV(y2
);
388 wxCoord xxc
= XLOG2DEV(xc
);
389 wxCoord yyc
= YLOG2DEV(yc
);
390 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
392 (void)MoveToEx(GetHdc(), (int) xx1
, (int) yy1
, NULL
);
393 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
394 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
395 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
396 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
397 if (m_brush
.Ok() && m_brush
.GetStyle() !=wxTRANSPARENT
)
399 // Have to add 1 to bottom-right corner of rectangle
400 // to make semi-circles look right (crooked line otherwise).
401 // Unfortunately this is not a reliable method, depends
402 // on the size of shape.
403 // TODO: figure out why this happens!
404 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1,
408 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
,
411 CalcBoundingBox((wxCoord
)(xc
-radius
), (wxCoord
)(yc
-radius
));
412 CalcBoundingBox((wxCoord
)(xc
+radius
), (wxCoord
)(yc
+radius
));
415 void wxDC::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
416 wxCoord width
, wxCoord height
)
418 wxCoord x2
= x1
+ width
,
421 #if defined(__WIN32__) && !defined(__SC__)
428 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
430 // In WIN16, draw a cross
431 HPEN blackPen
= ::CreatePen(PS_SOLID
, 1, RGB(0, 0, 0));
432 HPEN whiteBrush
= (HPEN
)::GetStockObject(WHITE_BRUSH
);
433 HPEN hPenOld
= (HPEN
)::SelectObject(GetHdc(), blackPen
);
434 HPEN hBrushOld
= (HPEN
)::SelectObject(GetHdc(), whiteBrush
);
435 ::SetROP2(GetHdc(), R2_COPYPEN
);
436 Rectangle(GetHdc(), x1
, y1
, x2
, y2
);
437 MoveTo(GetHdc(), x1
, y1
);
438 LineTo(GetHdc(), x2
, y2
);
439 MoveTo(GetHdc(), x2
, y1
);
440 LineTo(GetHdc(), x1
, y2
);
441 ::SelectObject(GetHdc(), hPenOld
);
442 ::SelectObject(GetHdc(), hBrushOld
);
443 ::DeleteObject(blackPen
);
446 CalcBoundingBox(x1
, y1
);
447 CalcBoundingBox(x2
, y2
);
450 void wxDC::DoDrawPoint(wxCoord x
, wxCoord y
)
452 COLORREF color
= 0x00ffffff;
455 color
= m_pen
.GetColour().GetPixel();
458 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
460 CalcBoundingBox(x
, y
);
463 void wxDC::DoDrawPolygon(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
,int fillStyle
)
465 COLORREF old_textground
= ::GetTextColor(GetHdc());
466 COLORREF old_background
= ::GetBkColor(GetHdc());
467 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
470 if (m_textForegroundColour
.Ok())
471 { //just the oposite from what is expected see help on pattern brush
472 // 1 in mask becomes bk color
473 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel() );
475 if (m_textBackgroundColour
.Ok())
476 { //just the oposite from what is expected
477 // 0 in mask becomes text color
478 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
481 if (m_backgroundMode
== wxTRANSPARENT
)
482 SetBkMode(GetHdc(), TRANSPARENT
);
484 SetBkMode(GetHdc(), OPAQUE
);
487 // Do things less efficiently if we have offsets
488 if (xoffset
!= 0 || yoffset
!= 0)
490 POINT
*cpoints
= new POINT
[n
];
492 for (i
= 0; i
< n
; i
++)
494 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
495 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
497 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
499 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
500 (void)Polygon(GetHdc(), cpoints
, n
);
501 SetPolyFillMode(GetHdc(),prev
);
507 for (i
= 0; i
< n
; i
++)
508 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
510 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
511 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
512 SetPolyFillMode(GetHdc(),prev
);
515 if (m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
517 ::SetBkMode(GetHdc(), TRANSPARENT
);
518 ::SetTextColor(GetHdc(), old_textground
);
519 ::SetBkColor(GetHdc(), old_background
);
523 void wxDC::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
525 // Do things less efficiently if we have offsets
526 if (xoffset
!= 0 || yoffset
!= 0)
528 POINT
*cpoints
= new POINT
[n
];
530 for (i
= 0; i
< n
; i
++)
532 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
533 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
535 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
537 (void)Polyline(GetHdc(), cpoints
, n
);
543 for (i
= 0; i
< n
; i
++)
544 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
546 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
550 void wxDC::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
552 COLORREF colFgOld
= 0,
555 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
557 colFgOld
= ::GetTextColor(GetHdc());
558 colBgOld
= ::GetBkColor(GetHdc());
560 if ( m_textForegroundColour
.Ok() )
562 // just the oposite from what is expected see help on pattern brush
563 // 1 in mask becomes bk color
564 ::SetBkColor(GetHdc(), m_textForegroundColour
.GetPixel());
567 if ( m_textBackgroundColour
.Ok() )
569 // 0 in mask becomes text color
570 ::SetTextColor(GetHdc(), m_textBackgroundColour
.GetPixel());
573 // VZ: IMHO this does strictly nothing here
574 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
578 wxCoord x2
= x
+ width
;
579 wxCoord y2
= y
+ height
;
581 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
584 rect
.left
= XLOG2DEV(x
);
585 rect
.top
= YLOG2DEV(y
);
586 rect
.right
= XLOG2DEV(x2
);
587 rect
.bottom
= YLOG2DEV(y2
);
588 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
592 // Windows draws the filled rectangles without outline (i.e. drawn with a
593 // transparent pen) one pixel smaller in both directions and we want them
594 // to have the same size regardless of which pen is used - adjust
596 // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
597 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
603 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
607 CalcBoundingBox(x
, y
);
608 CalcBoundingBox(x2
, y2
);
610 if ( m_brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
612 // restore the colours we changed
613 ::SetBkMode(GetHdc(), TRANSPARENT
);
614 ::SetTextColor(GetHdc(), colFgOld
);
615 ::SetBkColor(GetHdc(), colBgOld
);
619 void wxDC::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
621 // Now, a negative radius value is interpreted to mean
622 // 'the proportion of the smallest X or Y dimension'
626 double smallest
= 0.0;
631 radius
= (- radius
* smallest
);
634 wxCoord x2
= (x
+width
);
635 wxCoord y2
= (y
+height
);
637 // Windows draws the filled rectangles without outline (i.e. drawn with a
638 // transparent pen) one pixel smaller in both directions and we want them
639 // to have the same size regardless of which pen is used - adjust
640 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
646 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
647 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
649 CalcBoundingBox(x
, y
);
650 CalcBoundingBox(x2
, y2
);
653 void wxDC::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
655 wxCoord x2
= (x
+width
);
656 wxCoord y2
= (y
+height
);
658 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
660 CalcBoundingBox(x
, y
);
661 CalcBoundingBox(x2
, y2
);
664 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
665 void wxDC::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
670 int rx1
= XLOG2DEV(x
+w
/2);
671 int ry1
= YLOG2DEV(y
+h
/2);
678 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
679 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
680 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
681 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
683 // draw pie with NULL_PEN first and then outline otherwise a line is
684 // drawn from the start and end points to the centre
685 HPEN orig_pen
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
688 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
693 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
694 rx1
, ry1
-1, rx2
, ry2
-1);
696 ::SelectObject(GetHdc(), orig_pen
);
697 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
700 CalcBoundingBox(x
, y
);
701 CalcBoundingBox(x2
, y2
);
704 void wxDC::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
706 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
708 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
710 CalcBoundingBox(x
, y
);
711 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
714 void wxDC::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
716 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxDC::DrawBitmap") );
718 int width
= bmp
.GetWidth(),
719 height
= bmp
.GetHeight();
721 HBITMAP hbmpMask
= 0;
725 wxMask
*mask
= bmp
.GetMask();
727 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
731 // don't give assert here because this would break existing
732 // programs - just silently ignore useMask parameter
740 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
741 ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
743 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
745 bool ok
= ::MaskBlt(GetHdc(), x
, y
, width
, height
,
748 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
754 // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
757 memDC
.SelectObject(bmp
);
759 Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
761 memDC
.SelectObject(wxNullBitmap
);
764 else // no mask, just use BitBlt()
767 HDC memdc
= ::CreateCompatibleDC( cdc
);
768 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
770 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
772 COLORREF old_textground
= ::GetTextColor(GetHdc());
773 COLORREF old_background
= ::GetBkColor(GetHdc());
774 if (m_textForegroundColour
.Ok())
776 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
778 if (m_textBackgroundColour
.Ok())
780 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
783 ::SelectObject( memdc
, hbitmap
);
784 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
787 ::SetTextColor(GetHdc(), old_textground
);
788 ::SetBkColor(GetHdc(), old_background
);
792 void wxDC::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
794 DrawAnyText(text
, x
, y
);
796 // update the bounding box
797 CalcBoundingBox(x
, y
);
800 GetTextExtent(text
, &w
, &h
);
801 CalcBoundingBox(x
+ w
, y
+ h
);
804 void wxDC::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
806 // prepare for drawing the text
807 if ( m_textForegroundColour
.Ok() )
808 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
810 DWORD old_background
= 0;
811 if ( m_textBackgroundColour
.Ok() )
813 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
816 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
819 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
820 text
.c_str(), text
.length()) == 0 )
822 wxLogLastError("TextOut");
825 // restore the old parameters (text foreground colour may be left because
826 // it never is set to anything else, but background should remain
827 // transparent even if we just drew an opaque string)
828 if ( m_textBackgroundColour
.Ok() )
829 (void)SetBkColor(GetHdc(), old_background
);
831 SetBkMode(GetHdc(), TRANSPARENT
);
834 void wxDC::DoDrawRotatedText(const wxString
& text
,
835 wxCoord x
, wxCoord y
,
838 // we test that we have some font because otherwise we should still use the
839 // "else" part below to avoid that DrawRotatedText(angle = 180) and
840 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
841 // font for drawing rotated fonts unfortunately)
842 if ( (angle
== 0.0) && m_font
.Ok() )
844 DoDrawText(text
, x
, y
);
848 // NB: don't take DEFAULT_GUI_FONT because it's not TrueType and so
849 // can't have non zero orientation/escapement
850 wxFont font
= m_font
.Ok() ? m_font
: *wxNORMAL_FONT
;
851 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
853 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
855 wxLogLastError("GetObject(hfont)");
858 // GDI wants the angle in tenth of degree
859 long angle10
= (long)(angle
* 10);
860 lf
.lfEscapement
= angle10
;
861 lf
. lfOrientation
= angle10
;
863 hfont
= ::CreateFontIndirect(&lf
);
866 wxLogLastError("CreateFont");
870 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
872 DrawAnyText(text
, x
, y
);
874 (void)::SelectObject(GetHdc(), hfontOld
);
875 (void)::DeleteObject(hfont
);
878 // call the bounding box by adding all four vertices of the rectangle
879 // containing the text to it (simpler and probably not slower than
880 // determining which of them is really topmost/leftmost/...)
882 GetTextExtent(text
, &w
, &h
);
884 double rad
= DegToRad(angle
);
886 // "upper left" and "upper right"
887 CalcBoundingBox(x
, y
);
888 CalcBoundingBox(x
+ w
*cos(rad
), y
- h
*sin(rad
));
890 // "bottom left" and "bottom right"
891 x
+= (wxCoord
)(h
*sin(rad
));
892 y
+= (wxCoord
)(h
*cos(rad
));
893 CalcBoundingBox(x
, y
);
894 CalcBoundingBox(x
+ h
*sin(rad
), y
+ h
*cos(rad
));
898 // ---------------------------------------------------------------------------
900 // ---------------------------------------------------------------------------
902 void wxDC::SetPalette(const wxPalette
& palette
)
904 // Set the old object temporarily, in case the assignment deletes an object
905 // that's not yet selected out.
908 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
916 // Setting a NULL colourmap is a way of restoring
917 // the original colourmap
920 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, TRUE
);
927 if (m_palette
.Ok() && m_palette
.GetHPALETTE())
929 HPALETTE oldPal
= ::SelectPalette(GetHdc(), (HPALETTE
) m_palette
.GetHPALETTE(), TRUE
);
931 m_oldPalette
= (WXHPALETTE
) oldPal
;
933 ::RealizePalette(GetHdc());
937 void wxDC::SetFont(const wxFont
& the_font
)
939 // Set the old object temporarily, in case the assignment deletes an object
940 // that's not yet selected out.
943 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
952 ::SelectObject(GetHdc(), (HFONT
) m_oldFont
);
956 if (m_font
.Ok() && m_font
.GetResourceHandle())
958 HFONT f
= (HFONT
) ::SelectObject(GetHdc(), (HFONT
) m_font
.GetResourceHandle());
959 if (f
== (HFONT
) NULL
)
961 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
964 m_oldFont
= (WXHFONT
) f
;
968 void wxDC::SetPen(const wxPen
& pen
)
970 // Set the old object temporarily, in case the assignment deletes an object
971 // that's not yet selected out.
974 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
983 ::SelectObject(GetHdc(), (HPEN
) m_oldPen
);
989 if (m_pen
.GetResourceHandle())
991 HPEN p
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
)m_pen
.GetResourceHandle());
993 m_oldPen
= (WXHPEN
) p
;
998 void wxDC::SetBrush(const wxBrush
& brush
)
1000 // Set the old object temporarily, in case the assignment deletes an object
1001 // that's not yet selected out.
1004 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1013 ::SelectObject(GetHdc(), (HBRUSH
) m_oldBrush
);
1019 if (m_brush
.GetResourceHandle())
1022 b
= (HBRUSH
) ::SelectObject(GetHdc(), (HBRUSH
)m_brush
.GetResourceHandle());
1024 m_oldBrush
= (WXHBRUSH
) b
;
1029 void wxDC::SetBackground(const wxBrush
& brush
)
1031 m_backgroundBrush
= brush
;
1033 if (!m_backgroundBrush
.Ok())
1038 bool customColours
= TRUE
;
1039 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1040 // change background colours from the control-panel specified colours.
1041 if (m_canvas
->IsKindOf(CLASSINFO(wxWindow
)) && ((m_canvas
->GetWindowStyleFlag() & wxUSER_COLOURS
) != wxUSER_COLOURS
))
1042 customColours
= FALSE
;
1046 if (m_backgroundBrush
.GetStyle()==wxTRANSPARENT
)
1048 m_canvas
->SetTransparent(TRUE
);
1052 // New behaviour, 10/2/99: setting the background brush of a DC
1053 // doesn't affect the window background colour. However,
1054 // I'm leaving in the transparency setting because it's needed by
1055 // various controls (e.g. wxStaticText) to determine whether to draw
1056 // transparently or not. TODO: maybe this should be a new function
1057 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1059 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1060 m_canvas
->SetTransparent(FALSE
);
1064 COLORREF new_color
= m_backgroundBrush
.GetColour().GetPixel();
1066 (void)SetBkColor(GetHdc(), new_color
);
1070 void wxDC::SetBackgroundMode(int mode
)
1072 m_backgroundMode
= mode
;
1074 // SetBackgroundColour now only refers to text background
1075 // and m_backgroundMode is used there
1078 if (m_backgroundMode == wxTRANSPARENT)
1079 ::SetBkMode(GetHdc(), TRANSPARENT);
1081 ::SetBkMode(GetHdc(), OPAQUE);
1085 void wxDC::SetLogicalFunction(int function
)
1087 m_logicalFunction
= function
;
1092 void wxDC::SetRop(WXHDC dc
)
1094 if ( !dc
|| m_logicalFunction
< 0 )
1099 switch (m_logicalFunction
)
1101 case wxCLEAR
: rop
= R2_BLACK
; break;
1102 case wxXOR
: rop
= R2_XORPEN
; break;
1103 case wxINVERT
: rop
= R2_NOT
; break;
1104 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1105 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1106 case wxCOPY
: rop
= R2_COPYPEN
; break;
1107 case wxAND
: rop
= R2_MASKPEN
; break;
1108 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1109 case wxNO_OP
: rop
= R2_NOP
; break;
1110 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1111 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1112 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1113 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1114 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1115 case wxOR
: rop
= R2_MERGEPEN
; break;
1116 case wxSET
: rop
= R2_WHITE
; break;
1119 wxFAIL_MSG( wxT("unsupported logical function") );
1123 SetROP2(GetHdc(), rop
);
1126 bool wxDC::StartDoc(const wxString
& message
)
1128 // We might be previewing, so return TRUE to let it continue.
1136 void wxDC::StartPage()
1140 void wxDC::EndPage()
1144 // ---------------------------------------------------------------------------
1146 // ---------------------------------------------------------------------------
1148 wxCoord
wxDC::GetCharHeight() const
1150 TEXTMETRIC lpTextMetric
;
1152 GetTextMetrics(GetHdc(), &lpTextMetric
);
1154 return YDEV2LOGREL(lpTextMetric
.tmHeight
);
1157 wxCoord
wxDC::GetCharWidth() const
1159 TEXTMETRIC lpTextMetric
;
1161 GetTextMetrics(GetHdc(), &lpTextMetric
);
1163 return XDEV2LOGREL(lpTextMetric
.tmAveCharWidth
);
1166 void wxDC::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1167 wxCoord
*descent
, wxCoord
*externalLeading
,
1168 wxFont
*theFont
) const
1170 wxFont
*fontToUse
= (wxFont
*) theFont
;
1172 fontToUse
= (wxFont
*) &m_font
;
1177 GetTextExtentPoint(GetHdc(), WXSTRINGCAST string
, wxStrlen(WXSTRINGCAST string
), &sizeRect
);
1178 GetTextMetrics(GetHdc(), &tm
);
1180 if (x
) *x
= XDEV2LOGREL(sizeRect
.cx
);
1181 if (y
) *y
= YDEV2LOGREL(sizeRect
.cy
);
1182 if (descent
) *descent
= tm
.tmDescent
;
1183 if (externalLeading
) *externalLeading
= tm
.tmExternalLeading
;
1186 void wxDC::SetMapMode(int mode
)
1188 m_mappingMode
= mode
;
1190 int pixel_width
= 0;
1191 int pixel_height
= 0;
1195 pixel_width
= GetDeviceCaps(GetHdc(), HORZRES
);
1196 pixel_height
= GetDeviceCaps(GetHdc(), VERTRES
);
1197 mm_width
= GetDeviceCaps(GetHdc(), HORZSIZE
);
1198 mm_height
= GetDeviceCaps(GetHdc(), VERTSIZE
);
1200 if ((pixel_width
== 0) || (pixel_height
== 0) || (mm_width
== 0) || (mm_height
== 0))
1205 double mm2pixelsX
= pixel_width
/mm_width
;
1206 double mm2pixelsY
= pixel_height
/mm_height
;
1212 m_logicalScaleX
= (twips2mm
* mm2pixelsX
);
1213 m_logicalScaleY
= (twips2mm
* mm2pixelsY
);
1218 m_logicalScaleX
= (pt2mm
* mm2pixelsX
);
1219 m_logicalScaleY
= (pt2mm
* mm2pixelsY
);
1224 m_logicalScaleX
= mm2pixelsX
;
1225 m_logicalScaleY
= mm2pixelsY
;
1230 m_logicalScaleX
= (mm2pixelsX
/10.0);
1231 m_logicalScaleY
= (mm2pixelsY
/10.0);
1237 m_logicalScaleX
= 1.0;
1238 m_logicalScaleY
= 1.0;
1243 if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC
)
1244 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1246 SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1247 m_windowExtX
= (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT
);
1248 m_windowExtY
= (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT
);
1249 ::SetWindowExtEx(GetHdc(), m_windowExtX
, m_windowExtY
, NULL
);
1250 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1251 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1254 void wxDC::SetUserScale(double x
, double y
)
1259 SetMapMode(m_mappingMode
);
1262 void wxDC::SetAxisOrientation(bool xLeftRight
, bool yBottomUp
)
1264 m_signX
= xLeftRight
? 1 : -1;
1265 m_signY
= yBottomUp
? -1 : 1;
1267 SetMapMode(m_mappingMode
);
1270 void wxDC::SetSystemScale(double x
, double y
)
1275 SetMapMode(m_mappingMode
);
1278 void wxDC::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1280 m_logicalOriginX
= x
;
1281 m_logicalOriginY
= y
;
1283 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
1286 void wxDC::SetDeviceOrigin(wxCoord x
, wxCoord y
)
1288 m_deviceOriginX
= x
;
1289 m_deviceOriginY
= y
;
1291 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
1294 // ---------------------------------------------------------------------------
1295 // coordinates transformations
1296 // ---------------------------------------------------------------------------
1298 wxCoord
wxDCBase::DeviceToLogicalX(wxCoord x
) const
1300 return (wxCoord
) (((x
) - m_deviceOriginX
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
) - m_logicalOriginX
);
1303 wxCoord
wxDCBase::DeviceToLogicalXRel(wxCoord x
) const
1305 return (wxCoord
) ((x
)/(m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
));
1308 wxCoord
wxDCBase::DeviceToLogicalY(wxCoord y
) const
1310 return (wxCoord
) (((y
) - m_deviceOriginY
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
) - m_logicalOriginY
);
1313 wxCoord
wxDCBase::DeviceToLogicalYRel(wxCoord y
) const
1315 return (wxCoord
) ((y
)/(m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
));
1318 wxCoord
wxDCBase::LogicalToDeviceX(wxCoord x
) const
1320 return (wxCoord
) ((x
- m_logicalOriginX
)*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
+ m_deviceOriginX
);
1323 wxCoord
wxDCBase::LogicalToDeviceXRel(wxCoord x
) const
1325 return (wxCoord
) (x
*m_logicalScaleX
*m_userScaleX
*m_signX
*m_scaleX
);
1328 wxCoord
wxDCBase::LogicalToDeviceY(wxCoord y
) const
1330 return (wxCoord
) ((y
- m_logicalOriginY
)*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
+ m_deviceOriginY
);
1333 wxCoord
wxDCBase::LogicalToDeviceYRel(wxCoord y
) const
1335 return (wxCoord
) (y
*m_logicalScaleY
*m_userScaleY
*m_signY
*m_scaleY
);
1338 // ---------------------------------------------------------------------------
1340 // ---------------------------------------------------------------------------
1342 bool wxDC::DoBlit(wxCoord xdest
, wxCoord ydest
,
1343 wxCoord width
, wxCoord height
,
1344 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
1345 int rop
, bool useMask
)
1347 wxMask
*mask
= NULL
;
1350 const wxBitmap
& bmp
= source
->m_selectedBitmap
;
1351 mask
= bmp
.GetMask();
1353 if ( !(bmp
.Ok() && mask
&& mask
->GetMaskBitmap()) )
1355 // don't give assert here because this would break existing
1356 // programs - just silently ignore useMask parameter
1361 COLORREF old_textground
= ::GetTextColor(GetHdc());
1362 COLORREF old_background
= ::GetBkColor(GetHdc());
1363 if (m_textForegroundColour
.Ok())
1365 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1367 if (m_textBackgroundColour
.Ok())
1369 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1372 DWORD dwRop
= SRCCOPY
;
1375 case wxXOR
: dwRop
= SRCINVERT
; break;
1376 case wxINVERT
: dwRop
= DSTINVERT
; break;
1377 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
1378 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
1379 case wxCLEAR
: dwRop
= BLACKNESS
; break;
1380 case wxSET
: dwRop
= WHITENESS
; break;
1381 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
1382 case wxAND
: dwRop
= SRCAND
; break;
1383 case wxOR
: dwRop
= SRCPAINT
; break;
1384 case wxEQUIV
: dwRop
= 0x00990066; break;
1385 case wxNAND
: dwRop
= 0x007700E6; break;
1386 case wxAND_INVERT
: dwRop
= 0x00220326; break;
1387 case wxCOPY
: dwRop
= SRCCOPY
; break;
1388 case wxNO_OP
: dwRop
= DSTCOPY
; break;
1389 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
1390 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
1392 wxFAIL_MSG( wxT("unsupported logical function") );
1401 // we want the part of the image corresponding to the mask to be
1402 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
1403 // meaning of fg and bg is inverted which corresponds to wxWin notion
1404 // of the mask which is also contrary to the Windows one)
1405 success
= ::MaskBlt(GetHdc(), xdest
, ydest
, width
, height
,
1406 GetHdcOf(*source
), xsrc
, ysrc
,
1407 (HBITMAP
)mask
->GetMaskBitmap(), 0, 0,
1408 MAKEROP4(dwRop
, DSTCOPY
)) != 0;
1413 // Blit bitmap with mask
1415 // create a temp buffer bitmap and DCs to access it and the mask
1416 HDC dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
1417 HDC dc_buffer
= ::CreateCompatibleDC(GetHdc());
1418 HBITMAP buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), width
, height
);
1419 ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
1420 ::SelectObject(dc_buffer
, buffer_bmap
);
1422 // copy dest to buffer
1423 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1424 GetHdc(), xdest
, ydest
, SRCCOPY
) )
1426 wxLogLastError("BitBlt");
1429 // copy src to buffer using selected raster op
1430 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1431 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) )
1433 wxLogLastError("BitBlt");
1436 // set masked area in buffer to BLACK (pixel value 0)
1437 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
1438 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
1439 if ( !::BitBlt(dc_buffer
, 0, 0, (int)width
, (int)height
,
1440 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1442 wxLogLastError("BitBlt");
1445 // set unmasked area in dest to BLACK
1446 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
1447 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
1448 if ( !::BitBlt(GetHdc(), xdest
, ydest
, (int)width
, (int)height
,
1449 dc_mask
, xsrc
, ysrc
, SRCAND
) )
1451 wxLogLastError("BitBlt");
1453 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
1454 ::SetTextColor(GetHdc(), prevCol
);
1456 // OR buffer to dest
1457 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1458 (int)width
, (int)height
,
1459 dc_buffer
, 0, 0, SRCPAINT
) != 0;
1462 wxLogLastError("BitBlt");
1465 // tidy up temporary DCs and bitmap
1466 ::SelectObject(dc_mask
, 0);
1467 ::DeleteDC(dc_mask
);
1468 ::SelectObject(dc_buffer
, 0);
1469 ::DeleteDC(dc_buffer
);
1470 ::DeleteObject(buffer_bmap
);
1473 else // no mask, just BitBlt() it
1475 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
1476 (int)width
, (int)height
,
1477 GetHdcOf(*source
), xsrc
, ysrc
, dwRop
) != 0;
1480 wxLogLastError("BitBlt");
1483 ::SetTextColor(GetHdc(), old_textground
);
1484 ::SetBkColor(GetHdc(), old_background
);
1489 void wxDC::DoGetSize(int *w
, int *h
) const
1491 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZRES
);
1492 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTRES
);
1495 void wxDC::DoGetSizeMM(int *w
, int *h
) const
1497 if ( w
) *w
= ::GetDeviceCaps(GetHdc(), HORZSIZE
);
1498 if ( h
) *h
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1501 wxSize
wxDC::GetPPI() const
1503 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
1504 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
1506 return wxSize(x
, y
);
1509 // For use by wxWindows only, unless custom units are required.
1510 void wxDC::SetLogicalScale(double x
, double y
)
1512 m_logicalScaleX
= x
;
1513 m_logicalScaleY
= y
;
1516 #if WXWIN_COMPATIBILITY
1517 void wxDC::DoGetTextExtent(const wxString
& string
, float *x
, float *y
,
1518 float *descent
, float *externalLeading
,
1519 wxFont
*theFont
, bool use16bit
) const
1521 wxCoord x1
, y1
, descent1
, externalLeading1
;
1522 GetTextExtent(string
, & x1
, & y1
, & descent1
, & externalLeading1
, theFont
, use16bit
);
1525 *descent
= descent1
;
1526 if (externalLeading
)
1527 *externalLeading
= externalLeading1
;
1531 // ---------------------------------------------------------------------------
1532 // spline drawing code
1533 // ---------------------------------------------------------------------------
1537 class wxSpline
: public wxObject
1543 wxSpline(wxList
*list
);
1544 void DeletePoints();
1546 // Doesn't delete points
1550 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
);
1552 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
,
1553 double a3
, double b3
, double a4
, double b4
);
1554 void wx_clear_stack();
1555 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
, double *x3
,
1556 double *y3
, double *x4
, double *y4
);
1557 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
,
1558 double x4
, double y4
);
1559 static bool wx_spline_add_point(double x
, double y
);
1560 static void wx_spline_draw_point_array(wxDC
*dc
);
1561 wxSpline
*wx_make_spline(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
);
1563 void wxDC::DoDrawSpline(wxList
*list
)
1565 wxSpline
spline(list
);
1567 wx_draw_open_spline(this, &spline
);
1570 wxList wx_spline_point_list
;
1572 void wx_draw_open_spline(wxDC
*dc
, wxSpline
*spline
)
1575 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
1576 double x1
, y1
, x2
, y2
;
1578 wxNode
*node
= spline
->points
->First();
1579 p
= (wxPoint
*)node
->Data();
1584 node
= node
->Next();
1585 p
= (wxPoint
*)node
->Data();
1589 cx1
= (double)((x1
+ x2
) / 2);
1590 cy1
= (double)((y1
+ y2
) / 2);
1591 cx2
= (double)((cx1
+ x2
) / 2);
1592 cy2
= (double)((cy1
+ y2
) / 2);
1594 wx_spline_add_point(x1
, y1
);
1596 while ((node
= node
->Next()) != NULL
)
1598 p
= (wxPoint
*)node
->Data();
1603 cx4
= (double)(x1
+ x2
) / 2;
1604 cy4
= (double)(y1
+ y2
) / 2;
1605 cx3
= (double)(x1
+ cx4
) / 2;
1606 cy3
= (double)(y1
+ cy4
) / 2;
1608 wx_quadratic_spline(cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
);
1612 cx2
= (double)(cx1
+ x2
) / 2;
1613 cy2
= (double)(cy1
+ y2
) / 2;
1616 wx_spline_add_point((double)wx_round(cx1
), (double)wx_round(cy1
));
1617 wx_spline_add_point(x2
, y2
);
1619 wx_spline_draw_point_array(dc
);
1623 /********************* CURVES FOR SPLINES *****************************
1625 The following spline drawing routine is from
1627 "An Algorithm for High-Speed Curve Generation"
1628 by George Merrill Chaikin,
1629 Computer Graphics and Image Processing, 3, Academic Press,
1634 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1635 Computer Graphics and Image Processing, 4, Academic Press,
1638 ***********************************************************************/
1640 #define half(z1, z2) ((z1+z2)/2.0)
1643 /* iterative version */
1645 void wx_quadratic_spline(double a1
, double b1
, double a2
, double b2
, double a3
, double b3
, double a4
,
1648 register double xmid
, ymid
;
1649 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1652 wx_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1654 while (wx_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
)) {
1655 xmid
= (double)half(x2
, x3
);
1656 ymid
= (double)half(y2
, y3
);
1657 if (fabs(x1
- xmid
) < THRESHOLD
&& fabs(y1
- ymid
) < THRESHOLD
&&
1658 fabs(xmid
- x4
) < THRESHOLD
&& fabs(ymid
- y4
) < THRESHOLD
) {
1659 wx_spline_add_point((double)wx_round(x1
), (double)wx_round(y1
));
1660 wx_spline_add_point((double)wx_round(xmid
), (double)wx_round(ymid
));
1662 wx_spline_push(xmid
, ymid
, (double)half(xmid
, x3
), (double)half(ymid
, y3
),
1663 (double)half(x3
, x4
), (double)half(y3
, y4
), x4
, y4
);
1664 wx_spline_push(x1
, y1
, (double)half(x1
, x2
), (double)half(y1
, y2
),
1665 (double)half(x2
, xmid
), (double)half(y2
, ymid
), xmid
, ymid
);
1671 /* utilities used by spline drawing routines */
1674 typedef struct wx_spline_stack_struct
{
1675 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1679 #define SPLINE_STACK_DEPTH 20
1680 static Stack wx_spline_stack
[SPLINE_STACK_DEPTH
];
1681 static Stack
*wx_stack_top
;
1682 static int wx_stack_count
;
1684 void wx_clear_stack()
1686 wx_stack_top
= wx_spline_stack
;
1690 void wx_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
1692 wx_stack_top
->x1
= x1
;
1693 wx_stack_top
->y1
= y1
;
1694 wx_stack_top
->x2
= x2
;
1695 wx_stack_top
->y2
= y2
;
1696 wx_stack_top
->x3
= x3
;
1697 wx_stack_top
->y3
= y3
;
1698 wx_stack_top
->x4
= x4
;
1699 wx_stack_top
->y4
= y4
;
1704 int wx_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1705 double *x3
, double *y3
, double *x4
, double *y4
)
1707 if (wx_stack_count
== 0)
1711 *x1
= wx_stack_top
->x1
;
1712 *y1
= wx_stack_top
->y1
;
1713 *x2
= wx_stack_top
->x2
;
1714 *y2
= wx_stack_top
->y2
;
1715 *x3
= wx_stack_top
->x3
;
1716 *y3
= wx_stack_top
->y3
;
1717 *x4
= wx_stack_top
->x4
;
1718 *y4
= wx_stack_top
->y4
;
1722 static bool wx_spline_add_point(double x
, double y
)
1724 wxPoint
*point
= new wxPoint
;
1727 wx_spline_point_list
.Append((wxObject
*)point
);
1731 static void wx_spline_draw_point_array(wxDC
*dc
)
1733 dc
->DrawLines(&wx_spline_point_list
, 0, 0);
1734 wxNode
*node
= wx_spline_point_list
.First();
1737 wxPoint
*point
= (wxPoint
*)node
->Data();
1740 node
= wx_spline_point_list
.First();
1744 wxSpline::wxSpline(wxList
*list
)
1749 wxSpline::~wxSpline()
1753 void wxSpline::DeletePoints()
1755 for(wxNode
*node
= points
->First(); node
; node
= points
->First())
1757 wxPoint
*point
= (wxPoint
*)node
->Data();
1765 #endif // wxUSE_SPLINES