1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dc.cpp
3 // Purpose: wxDC class for MSW port
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
28 #include "wx/msw/wrapcdlg.h"
30 #include "wx/window.h"
33 #include "wx/dialog.h"
35 #include "wx/bitmap.h"
36 #include "wx/dcmemory.h"
39 #include "wx/dcprint.h"
40 #include "wx/module.h"
43 #include "wx/sysopt.h"
44 #include "wx/dynlib.h"
46 #ifdef wxHAVE_RAW_BITMAP
47 #include "wx/rawbmp.h"
57 #define AC_SRC_ALPHA 1
64 /* Quaternary raster codes */
66 #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
69 // apparently with MicroWindows it is possible that HDC is 0 so we have to
70 // check for this ourselves
72 #define WXMICROWIN_CHECK_HDC if ( !GetHDC() ) return;
73 #define WXMICROWIN_CHECK_HDC_RET(x) if ( !GetHDC() ) return x;
75 #define WXMICROWIN_CHECK_HDC
76 #define WXMICROWIN_CHECK_HDC_RET(x)
79 IMPLEMENT_ABSTRACT_CLASS(wxMSWDCImpl
, wxDCImpl
)
81 // ---------------------------------------------------------------------------
83 // ---------------------------------------------------------------------------
85 static const int VIEWPORT_EXTENT
= 1000;
87 static const int MM_POINTS
= 9;
88 static const int MM_METRIC
= 10;
90 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
91 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
92 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
94 // ----------------------------------------------------------------------------
95 // macros for logical <-> device coords conversion
96 // ----------------------------------------------------------------------------
99 We currently let Windows do all the translations itself so these macros are
100 not really needed (any more) but keep them to enhance readability of the
101 code by allowing to see where are the logical and where are the device
106 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
107 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
108 #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
109 #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
111 #define XLOG2DEV(x) (x)
112 #define YLOG2DEV(y) (y)
113 #define XDEV2LOG(x) (x)
114 #define YDEV2LOG(y) (y)
117 // ---------------------------------------------------------------------------
119 // ---------------------------------------------------------------------------
121 // convert degrees to radians
122 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
124 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
126 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
127 // to pass it to this function but as we already have it at the point
128 // of call anyhow we do
130 // return true if we could draw the bitmap in one way or the other, false
132 static bool AlphaBlt(HDC hdcDst
,
133 int x
, int y
, int dstWidth
, int dstHeight
,
135 int srcWidth
, int srcHeight
,
137 const wxBitmap
& bmp
);
139 #ifdef wxHAVE_RAW_BITMAP
141 // our (limited) AlphaBlend() replacement for Windows versions not providing it
143 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
144 int dstWidth
, int dstHeight
,
146 int srcWidth
, int srcHeight
,
147 const wxBitmap
& bmpSrc
);
149 #endif // wxHAVE_RAW_BITMAP
151 // ----------------------------------------------------------------------------
153 // ----------------------------------------------------------------------------
155 // instead of duplicating the same code which sets and then restores text
156 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
157 // encapsulate this in a small helper class
159 // wxColourChanger: changes the text colours in the ctor if required and
160 // restores them in the dtor
161 class wxColourChanger
164 wxColourChanger(wxMSWDCImpl
& dc
);
170 COLORREF m_colFgOld
, m_colBgOld
;
174 DECLARE_NO_COPY_CLASS(wxColourChanger
)
177 // this class saves the old stretch blit mode during its life time
178 class StretchBltModeChanger
181 StretchBltModeChanger(HDC hdc
,
182 int WXUNUSED_IN_WINCE(mode
))
186 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
188 wxLogLastError(_T("SetStretchBltMode"));
192 ~StretchBltModeChanger()
195 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
196 wxLogLastError(_T("SetStretchBltMode"));
205 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
208 #if wxUSE_DYNLIB_CLASS
210 // helper class to cache dynamically loaded libraries and not attempt reloading
212 class wxOnceOnlyDLLLoader
215 // ctor argument must be a literal string as we don't make a copy of it!
216 wxOnceOnlyDLLLoader(const wxChar
*dllName
)
222 // return the symbol with the given name or NULL if the DLL not loaded
223 // or symbol not present
224 void *GetSymbol(const wxChar
*name
)
226 // we're prepared to handle errors here
231 m_dll
.Load(m_dllName
);
233 // reset the name whether we succeeded or failed so that we don't
234 // try again the next time
238 return m_dll
.IsLoaded() ? m_dll
.GetSymbol(name
) : NULL
;
243 if ( m_dll
.IsLoaded() )
250 wxDynamicLibrary m_dll
;
251 const wxChar
*m_dllName
;
254 static wxOnceOnlyDLLLoader
wxMSIMG32DLL(_T("msimg32"));
256 // we must ensure that DLLs are unloaded before the static objects cleanup time
257 // because we may hit the notorious DllMain() dead lock in this case if wx is
258 // used as a DLL (attempting to unload another DLL from inside DllMain() hangs
259 // under Windows because it tries to reacquire the same lock)
260 class wxGDIDLLsCleanupModule
: public wxModule
263 virtual bool OnInit() { return true; }
264 virtual void OnExit() { wxMSIMG32DLL
.Unload(); }
267 DECLARE_DYNAMIC_CLASS(wxGDIDLLsCleanupModule
)
270 IMPLEMENT_DYNAMIC_CLASS(wxGDIDLLsCleanupModule
, wxModule
)
272 #endif // wxUSE_DYNLIB_CLASS
274 // ===========================================================================
276 // ===========================================================================
278 // ----------------------------------------------------------------------------
280 // ----------------------------------------------------------------------------
282 wxColourChanger::wxColourChanger(wxMSWDCImpl
& dc
) : m_dc(dc
)
284 const wxBrush
& brush
= dc
.GetBrush();
285 if ( brush
.Ok() && brush
.GetStyle() == wxSTIPPLE_MASK_OPAQUE
)
287 HDC hdc
= GetHdcOf(dc
);
288 m_colFgOld
= ::GetTextColor(hdc
);
289 m_colBgOld
= ::GetBkColor(hdc
);
291 // note that Windows convention is opposite to wxWidgets one, this is
292 // why text colour becomes the background one and vice versa
293 const wxColour
& colFg
= dc
.GetTextForeground();
296 ::SetBkColor(hdc
, colFg
.GetPixel());
299 const wxColour
& colBg
= dc
.GetTextBackground();
302 ::SetTextColor(hdc
, colBg
.GetPixel());
306 dc
.GetBackgroundMode() == wxTRANSPARENT
? TRANSPARENT
309 // flag which telsl us to undo changes in the dtor
314 // nothing done, nothing to undo
319 wxColourChanger::~wxColourChanger()
323 // restore the colours we changed
324 HDC hdc
= GetHdcOf(m_dc
);
326 ::SetBkMode(hdc
, TRANSPARENT
);
327 ::SetTextColor(hdc
, m_colFgOld
);
328 ::SetBkColor(hdc
, m_colBgOld
);
332 // ---------------------------------------------------------------------------
334 // ---------------------------------------------------------------------------
336 wxMSWDCImpl::wxMSWDCImpl( wxDC
*owner
, WXHDC hDC
) :
343 wxMSWDCImpl::~wxMSWDCImpl()
347 SelectOldObjects(m_hDC
);
349 // if we own the HDC, we delete it, otherwise we just release it
353 ::DeleteDC(GetHdc());
355 else // we don't own our HDC
359 ::ReleaseDC(GetHwndOf(m_window
), GetHdc());
363 // Must have been a wxScreenDC
364 ::ReleaseDC((HWND
) NULL
, GetHdc());
370 // This will select current objects out of the DC,
371 // which is what you have to do before deleting the
373 void wxMSWDCImpl::SelectOldObjects(WXHDC dc
)
379 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
381 if (m_selectedBitmap
.Ok())
383 m_selectedBitmap
.SetSelectedInto(NULL
);
390 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
395 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
400 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
407 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
410 #endif // wxUSE_PALETTE
413 m_brush
= wxNullBrush
;
416 m_palette
= wxNullPalette
;
417 #endif // wxUSE_PALETTE
419 m_backgroundBrush
= wxNullBrush
;
420 m_selectedBitmap
= wxNullBitmap
;
423 // ---------------------------------------------------------------------------
425 // ---------------------------------------------------------------------------
427 void wxMSWDCImpl::UpdateClipBox()
432 ::GetClipBox(GetHdc(), &rect
);
434 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
435 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
436 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
437 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
441 wxMSWDCImpl::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
443 // check if we should try to retrieve the clipping region possibly not set
444 // by our SetClippingRegion() but preset by Windows:this can only happen
445 // when we're associated with an existing HDC usign SetHDC(), see there
446 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
448 wxMSWDCImpl
*self
= wxConstCast(this, wxMSWDCImpl
);
449 self
->UpdateClipBox();
451 if ( !m_clipX1
&& !m_clipX2
)
452 self
->m_clipping
= false;
455 wxDCImpl::DoGetClippingBox(x
, y
, w
, h
);
458 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
459 void wxMSWDCImpl::SetClippingHrgn(WXHRGN hrgn
)
461 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
465 // note that we combine the new clipping region with the existing one: this
466 // is compatible with what the other ports do and is the documented
467 // behaviour now (starting with 2.3.3)
468 #if defined(__WXWINCE__)
470 if ( !::GetClipBox(GetHdc(), &rectClip
) )
473 // GetClipBox returns logical coordinates, so transform to device
474 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
475 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
476 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
477 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
479 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
480 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
481 rectClip
.right
, rectClip
.bottom
);
483 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
485 ::SelectClipRgn(GetHdc(), hrgnDest
);
488 ::DeleteObject(hrgnClipOld
);
489 ::DeleteObject(hrgnDest
);
491 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
493 wxLogLastError(_T("ExtSelectClipRgn"));
497 #endif // WinCE/!WinCE
504 void wxMSWDCImpl::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
506 // the region coords are always the device ones, so do the translation
509 // FIXME: possible +/-1 error here, to check!
510 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
512 LogicalToDeviceX(x
+ w
),
513 LogicalToDeviceY(y
+ h
));
516 wxLogLastError(_T("CreateRectRgn"));
520 SetClippingHrgn((WXHRGN
)hrgn
);
522 ::DeleteObject(hrgn
);
526 void wxMSWDCImpl::DoSetClippingRegionAsRegion(const wxRegion
& region
)
528 SetClippingHrgn(region
.GetHRGN());
531 void wxMSWDCImpl::DestroyClippingRegion()
535 if (m_clipping
&& m_hDC
)
538 // On a PocketPC device (not necessarily emulator), resetting
539 // the clip region as per the old method causes bad display
540 // problems. In fact setting a null region is probably OK
541 // on desktop WIN32 also, since the WIN32 docs imply that the user
542 // clipping region is independent from the paint clipping region.
543 ::SelectClipRgn(GetHdc(), 0);
545 // TODO: this should restore the previous clipping region,
546 // so that OnPaint processing works correctly, and the update
547 // clipping region doesn't get destroyed after the first
548 // DestroyClippingRegion.
549 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
550 ::SelectClipRgn(GetHdc(), rgn
);
555 wxDCImpl::DestroyClippingRegion();
558 // ---------------------------------------------------------------------------
559 // query capabilities
560 // ---------------------------------------------------------------------------
562 bool wxMSWDCImpl::CanDrawBitmap() const
567 bool wxMSWDCImpl::CanGetTextExtent() const
569 #ifdef __WXMICROWIN__
570 // TODO Extend MicroWindows' GetDeviceCaps function
573 // What sort of display is it?
574 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
576 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
580 int wxMSWDCImpl::GetDepth() const
582 WXMICROWIN_CHECK_HDC_RET(16)
584 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
587 // ---------------------------------------------------------------------------
589 // ---------------------------------------------------------------------------
591 void wxMSWDCImpl::Clear()
598 GetClientRect((HWND
) m_window
->GetHWND(), &rect
);
602 // No, I think we should simply ignore this if printing on e.g.
604 // wxCHECK_RET( m_selectedBitmap.Ok(), wxT("this DC can't be cleared") );
605 if (!m_selectedBitmap
.Ok())
608 rect
.left
= -m_deviceOriginX
; rect
.top
= -m_deviceOriginY
;
609 rect
.right
= m_selectedBitmap
.GetWidth()-m_deviceOriginX
;
610 rect
.bottom
= m_selectedBitmap
.GetHeight()-m_deviceOriginY
;
614 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
617 DWORD colour
= ::GetBkColor(GetHdc());
618 HBRUSH brush
= ::CreateSolidBrush(colour
);
619 ::FillRect(GetHdc(), &rect
, brush
);
620 ::DeleteObject(brush
);
622 RealizeScaleAndOrigin();
625 bool wxMSWDCImpl::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
626 wxCoord
WXUNUSED_IN_WINCE(y
),
627 const wxColour
& WXUNUSED_IN_WINCE(col
),
628 int WXUNUSED_IN_WINCE(style
))
633 WXMICROWIN_CHECK_HDC_RET(false)
635 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
637 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
638 : FLOODFILLBORDER
) ) ;
641 // quoting from the MSDN docs:
643 // Following are some of the reasons this function might fail:
645 // * The filling could not be completed.
646 // * The specified point has the boundary color specified by the
647 // crColor parameter (if FLOODFILLBORDER was requested).
648 // * The specified point does not have the color specified by
649 // crColor (if FLOODFILLSURFACE was requested)
650 // * The point is outside the clipping region that is, it is not
651 // visible on the device.
653 wxLogLastError(wxT("ExtFloodFill"));
656 CalcBoundingBox(x
, y
);
662 bool wxMSWDCImpl::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
664 WXMICROWIN_CHECK_HDC_RET(false)
666 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxMSWDCImpl::GetPixel") );
668 // get the color of the pixel
669 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
671 wxRGBToColour(*col
, pixelcolor
);
676 void wxMSWDCImpl::DoCrossHair(wxCoord x
, wxCoord y
)
680 wxCoord x1
= x
-VIEWPORT_EXTENT
;
681 wxCoord y1
= y
-VIEWPORT_EXTENT
;
682 wxCoord x2
= x
+VIEWPORT_EXTENT
;
683 wxCoord y2
= y
+VIEWPORT_EXTENT
;
685 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
686 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
688 CalcBoundingBox(x1
, y1
);
689 CalcBoundingBox(x2
, y2
);
692 void wxMSWDCImpl::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
696 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
698 CalcBoundingBox(x1
, y1
);
699 CalcBoundingBox(x2
, y2
);
702 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
703 // and ending at (x2, y2)
704 void wxMSWDCImpl::DoDrawArc(wxCoord x1
, wxCoord y1
,
705 wxCoord x2
, wxCoord y2
,
706 wxCoord xc
, wxCoord yc
)
709 // Slower emulation since WinCE doesn't support Pie and Arc
710 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
711 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
712 if( y1
>yc
) sa
= -sa
; // below center
713 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
714 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
719 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
723 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
724 wxCoord r
= (wxCoord
)radius
;
726 // treat the special case of full circle separately
727 if ( x1
== x2
&& y1
== y2
)
729 GetOwner()->DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
733 wxCoord xx1
= XLOG2DEV(x1
);
734 wxCoord yy1
= YLOG2DEV(y1
);
735 wxCoord xx2
= XLOG2DEV(x2
);
736 wxCoord yy2
= YLOG2DEV(y2
);
737 wxCoord xxc
= XLOG2DEV(xc
);
738 wxCoord yyc
= YLOG2DEV(yc
);
739 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
741 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
742 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
743 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
744 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
746 if ( m_brush
.Ok() && m_brush
.GetStyle() != wxTRANSPARENT
)
748 // Have to add 1 to bottom-right corner of rectangle
749 // to make semi-circles look right (crooked line otherwise).
750 // Unfortunately this is not a reliable method, depends
751 // on the size of shape.
752 // TODO: figure out why this happens!
753 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
757 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
760 CalcBoundingBox(xc
- r
, yc
- r
);
761 CalcBoundingBox(xc
+ r
, yc
+ r
);
765 void wxMSWDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
766 wxCoord width
, wxCoord height
)
768 // cases when we don't have DrawFrameControl()
769 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
770 return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
);
772 wxCoord x2
= x1
+ width
,
782 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
);
784 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
787 CalcBoundingBox(x1
, y1
);
788 CalcBoundingBox(x2
, y2
);
789 #endif // Microwin/Normal
792 void wxMSWDCImpl::DoDrawPoint(wxCoord x
, wxCoord y
)
796 COLORREF color
= 0x00ffffff;
799 color
= m_pen
.GetColour().GetPixel();
802 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
804 CalcBoundingBox(x
, y
);
807 void wxMSWDCImpl::DoDrawPolygon(int n
,
811 int WXUNUSED_IN_WINCE(fillStyle
))
815 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
817 // Do things less efficiently if we have offsets
818 if (xoffset
!= 0 || yoffset
!= 0)
820 POINT
*cpoints
= new POINT
[n
];
822 for (i
= 0; i
< n
; i
++)
824 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
825 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
827 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
830 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
832 (void)Polygon(GetHdc(), cpoints
, n
);
834 SetPolyFillMode(GetHdc(),prev
);
841 for (i
= 0; i
< n
; i
++)
842 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
845 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
847 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
849 SetPolyFillMode(GetHdc(),prev
);
855 wxMSWDCImpl::DoDrawPolyPolygon(int n
,
863 wxDCBase::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
867 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
869 for (i
= cnt
= 0; i
< n
; i
++)
872 // Do things less efficiently if we have offsets
873 if (xoffset
!= 0 || yoffset
!= 0)
875 POINT
*cpoints
= new POINT
[cnt
];
876 for (i
= 0; i
< cnt
; i
++)
878 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
879 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
881 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
884 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
886 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
888 SetPolyFillMode(GetHdc(),prev
);
894 for (i
= 0; i
< cnt
; i
++)
895 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
898 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
900 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
902 SetPolyFillMode(GetHdc(),prev
);
909 void wxMSWDCImpl::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
913 // Do things less efficiently if we have offsets
914 if (xoffset
!= 0 || yoffset
!= 0)
916 POINT
*cpoints
= new POINT
[n
];
918 for (i
= 0; i
< n
; i
++)
920 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
921 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
923 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
925 (void)Polyline(GetHdc(), cpoints
, n
);
931 for (i
= 0; i
< n
; i
++)
932 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
934 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
938 void wxMSWDCImpl::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
942 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
944 wxCoord x2
= x
+ width
;
945 wxCoord y2
= y
+ height
;
947 if ((m_logicalFunction
== wxCOPY
) && (m_pen
.GetStyle() == wxTRANSPARENT
))
950 rect
.left
= XLOG2DEV(x
);
951 rect
.top
= YLOG2DEV(y
);
952 rect
.right
= XLOG2DEV(x2
);
953 rect
.bottom
= YLOG2DEV(y2
);
954 (void)FillRect(GetHdc(), &rect
, (HBRUSH
)m_brush
.GetResourceHandle() );
958 // Windows draws the filled rectangles without outline (i.e. drawn with a
959 // transparent pen) one pixel smaller in both directions and we want them
960 // to have the same size regardless of which pen is used - adjust
962 // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR.
963 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
965 // Apparently not needed for WinCE (see e.g. Life! demo)
972 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
976 CalcBoundingBox(x
, y
);
977 CalcBoundingBox(x2
, y2
);
980 void wxMSWDCImpl::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
984 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
986 // Now, a negative radius value is interpreted to mean
987 // 'the proportion of the smallest X or Y dimension'
991 double smallest
= (width
< height
) ? width
: height
;
992 radius
= (- radius
* smallest
);
995 wxCoord x2
= (x
+width
);
996 wxCoord y2
= (y
+height
);
998 // Windows draws the filled rectangles without outline (i.e. drawn with a
999 // transparent pen) one pixel smaller in both directions and we want them
1000 // to have the same size regardless of which pen is used - adjust
1001 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
1007 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
1008 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
1010 CalcBoundingBox(x
, y
);
1011 CalcBoundingBox(x2
, y2
);
1014 void wxMSWDCImpl::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1016 WXMICROWIN_CHECK_HDC
1018 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1020 wxCoord x2
= (x
+width
);
1021 wxCoord y2
= (y
+height
);
1023 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
1025 CalcBoundingBox(x
, y
);
1026 CalcBoundingBox(x2
, y2
);
1030 void wxMSWDCImpl::DoDrawSpline(const wxPointList
*points
)
1033 // WinCE does not support ::PolyBezier so use generic version
1034 wxDCBase::DoDrawSpline(points
);
1036 // quadratic b-spline to cubic bezier spline conversion
1038 // quadratic spline with control points P0,P1,P2
1039 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1041 // bezier spline with control points B0,B1,B2,B3
1042 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1044 // control points of bezier spline calculated from b-spline
1046 // B1 = (2*P1 + P0)/3
1047 // B2 = (2*P1 + P2)/3
1050 WXMICROWIN_CHECK_HDC
1052 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1054 const size_t n_points
= points
->GetCount();
1055 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1057 const size_t n_bezier_points
= n_points
* 3 + 1;
1058 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1059 size_t bezier_pos
= 0;
1060 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1062 wxPointList::compatibility_iterator node
= points
->GetFirst();
1063 wxPoint
*p
= node
->GetData();
1064 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1065 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1067 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1070 node
= node
->GetNext();
1071 p
= node
->GetData();
1075 cx1
= ( x1
+ x2
) / 2;
1076 cy1
= ( y1
+ y2
) / 2;
1077 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1078 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1080 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1084 while ((node
= node
->GetNext()) != NULL
)
1086 while ((node
= node
->GetNext()))
1087 #endif // !wxUSE_STL
1089 p
= (wxPoint
*)node
->GetData();
1094 cx4
= (x1
+ x2
) / 2;
1095 cy4
= (y1
+ y2
) / 2;
1096 // B0 is B3 of previous segment
1098 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1099 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1102 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1103 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1106 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1107 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1113 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1115 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1116 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1118 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1121 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1128 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1129 void wxMSWDCImpl::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1132 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1135 WXMICROWIN_CHECK_HDC
1137 wxColourChanger
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1142 int rx1
= XLOG2DEV(x
+w
/2);
1143 int ry1
= YLOG2DEV(y
+h
/2);
1150 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1151 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1152 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1153 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1155 // Swap start and end positions if the end angle is less than the start angle.
1166 // draw pie with NULL_PEN first and then outline otherwise a line is
1167 // drawn from the start and end points to the centre
1168 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1171 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1172 rx1
, ry1
, rx2
, ry2
);
1176 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1177 rx1
, ry1
-1, rx2
, ry2
-1);
1180 ::SelectObject(GetHdc(), hpenOld
);
1182 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1183 rx1
, ry1
, rx2
, ry2
);
1185 CalcBoundingBox(x
, y
);
1186 CalcBoundingBox(x2
, y2
);
1190 void wxMSWDCImpl::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1192 WXMICROWIN_CHECK_HDC
1194 wxCHECK_RET( icon
.Ok(), wxT("invalid icon in DrawIcon") );
1197 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1199 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1202 CalcBoundingBox(x
, y
);
1203 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1206 void wxMSWDCImpl::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1208 WXMICROWIN_CHECK_HDC
1210 wxCHECK_RET( bmp
.Ok(), _T("invalid bitmap in wxMSWDCImpl::DrawBitmap") );
1212 int width
= bmp
.GetWidth(),
1213 height
= bmp
.GetHeight();
1215 HBITMAP hbmpMask
= 0;
1218 HPALETTE oldPal
= 0;
1219 #endif // wxUSE_PALETTE
1221 if ( bmp
.HasAlpha() )
1224 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1226 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, width
, height
, hdcMem
, bmp
) )
1232 wxMask
*mask
= bmp
.GetMask();
1234 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1238 // don't give assert here because this would break existing
1239 // programs - just silently ignore useMask parameter
1246 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1248 // On some systems, MaskBlt succeeds yet is much much slower
1249 // than the wxWidgets fall-back implementation. So we need
1250 // to be able to switch this on and off at runtime.
1252 #if wxUSE_SYSTEM_OPTIONS
1253 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1257 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1258 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1260 wxPalette
*pal
= bmp
.GetPalette();
1261 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1263 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1264 ::RealizePalette(hdcMem
);
1266 #endif // wxUSE_PALETTE
1268 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1271 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1275 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1276 #endif // wxUSE_PALETTE
1278 ::SelectObject(hdcMem
, hOldBitmap
);
1285 // Rather than reproduce wxMSWDCImpl::Blit, let's do it at the wxWin API
1289 memDC
.SelectObjectAsSource(bmp
);
1291 GetOwner()->Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1293 memDC
.SelectObject(wxNullBitmap
);
1296 else // no mask, just use BitBlt()
1299 HDC memdc
= ::CreateCompatibleDC( cdc
);
1300 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1302 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1304 COLORREF old_textground
= ::GetTextColor(GetHdc());
1305 COLORREF old_background
= ::GetBkColor(GetHdc());
1306 if (m_textForegroundColour
.Ok())
1308 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
1310 if (m_textBackgroundColour
.Ok())
1312 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1316 wxPalette
*pal
= bmp
.GetPalette();
1317 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1319 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1320 ::RealizePalette(memdc
);
1322 #endif // wxUSE_PALETTE
1324 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1325 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1329 ::SelectPalette(memdc
, oldPal
, FALSE
);
1330 #endif // wxUSE_PALETTE
1332 ::SelectObject( memdc
, hOldBitmap
);
1333 ::DeleteDC( memdc
);
1335 ::SetTextColor(GetHdc(), old_textground
);
1336 ::SetBkColor(GetHdc(), old_background
);
1340 void wxMSWDCImpl::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1342 WXMICROWIN_CHECK_HDC
1344 DrawAnyText(text
, x
, y
);
1346 // update the bounding box
1347 CalcBoundingBox(x
, y
);
1350 GetOwner()->GetTextExtent(text
, &w
, &h
);
1351 CalcBoundingBox(x
+ w
, y
+ h
);
1354 void wxMSWDCImpl::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1356 WXMICROWIN_CHECK_HDC
1358 // prepare for drawing the text
1359 if ( m_textForegroundColour
.Ok() )
1360 SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel());
1362 DWORD old_background
= 0;
1363 if ( m_textBackgroundColour
.Ok() )
1365 old_background
= SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
1368 SetBkMode(GetHdc(), m_backgroundMode
== wxTRANSPARENT
? TRANSPARENT
1372 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1373 text
.c_str(), text
.length(), NULL
) == 0 )
1375 wxLogLastError(wxT("TextOut"));
1378 if ( ::TextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
1379 text
.c_str(), text
.length()) == 0 )
1381 wxLogLastError(wxT("TextOut"));
1385 // restore the old parameters (text foreground colour may be left because
1386 // it never is set to anything else, but background should remain
1387 // transparent even if we just drew an opaque string)
1388 if ( m_textBackgroundColour
.Ok() )
1389 (void)SetBkColor(GetHdc(), old_background
);
1391 SetBkMode(GetHdc(), TRANSPARENT
);
1394 void wxMSWDCImpl::DoDrawRotatedText(const wxString
& text
,
1395 wxCoord x
, wxCoord y
,
1398 WXMICROWIN_CHECK_HDC
1400 // we test that we have some font because otherwise we should still use the
1401 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1402 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1403 // font for drawing rotated fonts unfortunately)
1404 if ( (angle
== 0.0) && m_font
.Ok() )
1406 DoDrawText(text
, x
, y
);
1408 #ifndef __WXMICROWIN__
1411 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1412 // because it's not TrueType and so can't have non zero
1413 // orientation/escapement under Win9x
1414 wxFont font
= m_font
.Ok() ? m_font
: *wxSWISS_FONT
;
1415 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1417 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1419 wxLogLastError(wxT("GetObject(hfont)"));
1422 // GDI wants the angle in tenth of degree
1423 long angle10
= (long)(angle
* 10);
1424 lf
.lfEscapement
= angle10
;
1425 lf
. lfOrientation
= angle10
;
1427 hfont
= ::CreateFontIndirect(&lf
);
1430 wxLogLastError(wxT("CreateFont"));
1434 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1436 DrawAnyText(text
, x
, y
);
1438 (void)::SelectObject(GetHdc(), hfontOld
);
1439 (void)::DeleteObject(hfont
);
1442 // call the bounding box by adding all four vertices of the rectangle
1443 // containing the text to it (simpler and probably not slower than
1444 // determining which of them is really topmost/leftmost/...)
1446 GetOwner()->GetTextExtent(text
, &w
, &h
);
1448 double rad
= DegToRad(angle
);
1450 // "upper left" and "upper right"
1451 CalcBoundingBox(x
, y
);
1452 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1454 // "bottom left" and "bottom right"
1455 x
+= (wxCoord
)(h
*sin(rad
));
1456 y
+= (wxCoord
)(h
*cos(rad
));
1457 CalcBoundingBox(x
, y
);
1458 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1463 // ---------------------------------------------------------------------------
1465 // ---------------------------------------------------------------------------
1469 void wxMSWDCImpl::DoSelectPalette(bool realize
)
1471 WXMICROWIN_CHECK_HDC
1473 // Set the old object temporarily, in case the assignment deletes an object
1474 // that's not yet selected out.
1477 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1481 if ( m_palette
.Ok() )
1483 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1484 GetHpaletteOf(m_palette
),
1487 m_oldPalette
= (WXHPALETTE
) oldPal
;
1490 ::RealizePalette(GetHdc());
1494 void wxMSWDCImpl::SetPalette(const wxPalette
& palette
)
1498 m_palette
= palette
;
1499 DoSelectPalette(true);
1503 void wxMSWDCImpl::InitializePalette()
1505 if ( wxDisplayDepth() <= 8 )
1507 // look for any window or parent that has a custom palette. If any has
1508 // one then we need to use it in drawing operations
1509 wxWindow
*win
= m_window
->GetAncestorWithCustomPalette();
1511 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1512 if ( m_hasCustomPalette
)
1514 m_palette
= win
->GetPalette();
1516 // turn on MSW translation for this palette
1522 #endif // wxUSE_PALETTE
1524 // SetFont/Pen/Brush() really ask to be implemented as a single template
1525 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1527 void wxMSWDCImpl::SetFont(const wxFont
& font
)
1529 WXMICROWIN_CHECK_HDC
1531 if ( font
== m_font
)
1536 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1537 if ( hfont
== HGDI_ERROR
)
1539 wxLogLastError(_T("SelectObject(font)"));
1544 m_oldFont
= (WXHFONT
)hfont
;
1549 else // invalid font, reset the current font
1553 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1555 wxLogLastError(_T("SelectObject(old font)"));
1561 m_font
= wxNullFont
;
1565 void wxMSWDCImpl::SetPen(const wxPen
& pen
)
1567 WXMICROWIN_CHECK_HDC
1574 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1575 if ( hpen
== HGDI_ERROR
)
1577 wxLogLastError(_T("SelectObject(pen)"));
1582 m_oldPen
= (WXHPEN
)hpen
;
1587 else // invalid pen, reset the current pen
1591 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1593 wxLogLastError(_T("SelectObject(old pen)"));
1603 void wxMSWDCImpl::SetBrush(const wxBrush
& brush
)
1605 WXMICROWIN_CHECK_HDC
1607 if ( brush
== m_brush
)
1612 // we must make sure the brush is aligned with the logical coordinates
1613 // before selecting it
1614 wxBitmap
*stipple
= brush
.GetStipple();
1615 if ( stipple
&& stipple
->Ok() )
1617 if ( !::SetBrushOrgEx
1620 m_deviceOriginX
% stipple
->GetWidth(),
1621 m_deviceOriginY
% stipple
->GetHeight(),
1622 NULL
// [out] previous brush origin
1625 wxLogLastError(_T("SetBrushOrgEx()"));
1629 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1630 if ( hbrush
== HGDI_ERROR
)
1632 wxLogLastError(_T("SelectObject(brush)"));
1637 m_oldBrush
= (WXHBRUSH
)hbrush
;
1642 else // invalid brush, reset the current brush
1646 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1648 wxLogLastError(_T("SelectObject(old brush)"));
1654 m_brush
= wxNullBrush
;
1658 void wxMSWDCImpl::SetBackground(const wxBrush
& brush
)
1660 WXMICROWIN_CHECK_HDC
1662 m_backgroundBrush
= brush
;
1664 if ( m_backgroundBrush
.Ok() )
1666 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1670 void wxMSWDCImpl::SetBackgroundMode(int mode
)
1672 WXMICROWIN_CHECK_HDC
1674 m_backgroundMode
= mode
;
1676 // SetBackgroundColour now only refers to text background
1677 // and m_backgroundMode is used there
1680 void wxMSWDCImpl::SetLogicalFunction(int function
)
1682 WXMICROWIN_CHECK_HDC
1684 m_logicalFunction
= function
;
1689 void wxMSWDCImpl::SetRop(WXHDC dc
)
1691 if ( !dc
|| m_logicalFunction
< 0 )
1696 switch (m_logicalFunction
)
1698 case wxCLEAR
: rop
= R2_BLACK
; break;
1699 case wxXOR
: rop
= R2_XORPEN
; break;
1700 case wxINVERT
: rop
= R2_NOT
; break;
1701 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1702 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1703 case wxCOPY
: rop
= R2_COPYPEN
; break;
1704 case wxAND
: rop
= R2_MASKPEN
; break;
1705 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1706 case wxNO_OP
: rop
= R2_NOP
; break;
1707 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1708 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1709 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1710 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1711 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1712 case wxOR
: rop
= R2_MERGEPEN
; break;
1713 case wxSET
: rop
= R2_WHITE
; break;
1716 wxFAIL_MSG( wxT("unsupported logical function") );
1720 SetROP2(GetHdc(), rop
);
1723 bool wxMSWDCImpl::StartDoc(const wxString
& WXUNUSED(message
))
1725 // We might be previewing, so return true to let it continue.
1729 void wxMSWDCImpl::EndDoc()
1733 void wxMSWDCImpl::StartPage()
1737 void wxMSWDCImpl::EndPage()
1741 // ---------------------------------------------------------------------------
1743 // ---------------------------------------------------------------------------
1745 wxCoord
wxMSWDCImpl::GetCharHeight() const
1747 WXMICROWIN_CHECK_HDC_RET(0)
1749 TEXTMETRIC lpTextMetric
;
1751 GetTextMetrics(GetHdc(), &lpTextMetric
);
1753 return lpTextMetric
.tmHeight
;
1756 wxCoord
wxMSWDCImpl::GetCharWidth() const
1758 WXMICROWIN_CHECK_HDC_RET(0)
1760 TEXTMETRIC lpTextMetric
;
1762 GetTextMetrics(GetHdc(), &lpTextMetric
);
1764 return lpTextMetric
.tmAveCharWidth
;
1767 void wxMSWDCImpl::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1768 wxCoord
*descent
, wxCoord
*externalLeading
,
1769 const wxFont
*font
) const
1771 #ifdef __WXMICROWIN__
1776 if (descent
) *descent
= 0;
1777 if (externalLeading
) *externalLeading
= 0;
1780 #endif // __WXMICROWIN__
1785 wxASSERT_MSG( font
->Ok(), _T("invalid font in wxMSWDCImpl::GetTextExtent") );
1787 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1789 else // don't change the font
1795 const size_t len
= string
.length();
1796 if ( !::GetTextExtentPoint32(GetHdc(), string
.wx_str(), len
, &sizeRect
) )
1798 wxLogLastError(_T("GetTextExtentPoint32()"));
1801 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1802 // the result computed by GetTextExtentPoint32() may be too small as it
1803 // accounts for under/overhang of the first/last character while we want
1804 // just the bounding rect for this string so adjust the width as needed
1805 // (using API not available in 2002 SDKs of WinCE)
1809 const wxChar chFirst
= *string
.begin();
1810 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1812 if ( width
.abcA
< 0 )
1813 sizeRect
.cx
-= width
.abcA
;
1817 const wxChar chLast
= *string
.rbegin();
1818 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1820 //else: we already have the width of the last character
1822 if ( width
.abcC
< 0 )
1823 sizeRect
.cx
-= width
.abcC
;
1825 //else: GetCharABCWidths() failed, not a TrueType font?
1827 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1830 ::GetTextMetrics(GetHdc(), &tm
);
1837 *descent
= tm
.tmDescent
;
1838 if (externalLeading
)
1839 *externalLeading
= tm
.tmExternalLeading
;
1843 ::SelectObject(GetHdc(), hfontOld
);
1848 // Each element of the array will be the width of the string up to and
1849 // including the coresoponding character in text.
1851 bool wxMSWDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1853 static int maxLenText
= -1;
1854 static int maxWidth
= -1;
1857 int stlen
= text
.length();
1859 if (maxLenText
== -1)
1861 // Win9x and WinNT+ have different limits
1862 int version
= wxGetOsVersion();
1863 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1864 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1868 widths
.Add(0, stlen
); // fill the array with zeros
1872 if (!::GetTextExtentExPoint(GetHdc(),
1873 text
.c_str(), // string to check
1874 wxMin(stlen
, maxLenText
),
1876 &fit
, // [out] count of chars
1878 &widths
[0], // array to fill
1882 wxLogLastError(wxT("GetTextExtentExPoint"));
1889 void wxMSWDCImpl::RealizeScaleAndOrigin()
1891 // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of
1892 // cases we could do with MM_TEXT and in the remaining 0.9% with
1893 // MM_ISOTROPIC (TODO!)
1895 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1897 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1898 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1900 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1901 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1903 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1904 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1909 void wxMSWDCImpl::SetMapMode(int mode
)
1911 WXMICROWIN_CHECK_HDC
1913 m_mappingMode
= mode
;
1915 if ( mode
== wxMM_TEXT
)
1918 m_logicalScaleY
= 1.0;
1920 else // need to do some calculations
1922 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1923 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1924 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1925 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1927 if ( (mm_width
== 0) || (mm_height
== 0) )
1929 // we can't calculate mm2pixels[XY] then!
1933 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1934 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1939 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1940 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1944 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1945 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1949 m_logicalScaleX
= mm2pixelsX
;
1950 m_logicalScaleY
= mm2pixelsY
;
1954 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1955 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1959 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1963 ComputeScaleAndOrigin();
1965 RealizeScaleAndOrigin();
1968 void wxMSWDCImpl::SetUserScale(double x
, double y
)
1970 WXMICROWIN_CHECK_HDC
1972 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1975 wxDCImpl::SetUserScale(x
,y
);
1977 RealizeScaleAndOrigin();
1980 void wxMSWDCImpl::SetAxisOrientation(bool xLeftRight
,
1983 WXMICROWIN_CHECK_HDC
1985 int signX
= xLeftRight
? 1 : -1,
1986 signY
= yBottomUp
? -1 : 1;
1988 if (signX
== m_signX
&& signY
== m_signY
)
1991 wxDCImpl::SetAxisOrientation( xLeftRight
, yBottomUp
);
1993 RealizeScaleAndOrigin();
1996 void wxMSWDCImpl::SetLogicalOrigin(wxCoord x
, wxCoord y
)
1998 WXMICROWIN_CHECK_HDC
2000 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
2003 wxDCImpl::SetLogicalOrigin( x
, y
);
2006 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
2010 void wxMSWDCImpl::SetDeviceOrigin(wxCoord x
, wxCoord y
)
2012 WXMICROWIN_CHECK_HDC
2014 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
2017 wxDCImpl::SetDeviceOrigin( x
, y
);
2019 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
2022 // ---------------------------------------------------------------------------
2024 // ---------------------------------------------------------------------------
2026 bool wxMSWDCImpl::DoBlit(wxCoord dstX
, wxCoord dstY
,
2027 wxCoord dstWidth
, wxCoord dstHeight
,
2029 wxCoord srcX
, wxCoord srcY
,
2030 int rop
, bool useMask
,
2031 wxCoord srcMaskX
, wxCoord srcMaskY
)
2033 return DoStretchBlit(dstX
, dstY
, dstWidth
, dstHeight
, source
, srcX
, srcY
, dstWidth
, dstHeight
, rop
, useMask
, srcMaskX
, srcMaskY
);
2036 bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
2037 wxCoord dstWidth
, wxCoord dstHeight
,
2039 wxCoord xsrc
, wxCoord ysrc
,
2040 wxCoord srcWidth
, wxCoord srcHeight
,
2041 int rop
, bool useMask
,
2042 wxCoord xsrcMask
, wxCoord ysrcMask
)
2044 wxCHECK_MSG( source
, false, _T("wxMSWDCImpl::Blit(): NULL wxDC pointer") );
2046 WXMICROWIN_CHECK_HDC_RET(false)
2048 wxDCImpl
*impl
= source
->GetImpl();
2049 wxMSWDCImpl
*msw_impl
= wxDynamicCast( impl
, wxMSWDCImpl
);
2052 // TODO: Do we want to be able to blit
2053 // from other DCs too?
2057 // if either the source or destination has alpha channel, we must use
2058 // AlphaBlt() as other function don't handle it correctly
2059 const wxBitmap
& bmpSrc
= msw_impl
->GetSelectedBitmap();
2060 if ( bmpSrc
.Ok() && (bmpSrc
.HasAlpha() ||
2061 (m_selectedBitmap
.Ok() && m_selectedBitmap
.HasAlpha())) )
2063 if ( AlphaBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2064 xsrc
, ysrc
, srcWidth
, srcHeight
, GetHdcOf(*msw_impl
), bmpSrc
) )
2068 wxMask
*mask
= NULL
;
2071 mask
= bmpSrc
.GetMask();
2073 if ( !(bmpSrc
.Ok() && mask
&& mask
->GetMaskBitmap()) )
2075 // don't give assert here because this would break existing
2076 // programs - just silently ignore useMask parameter
2081 if (xsrcMask
== -1 && ysrcMask
== -1)
2083 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2086 COLORREF old_textground
= ::GetTextColor(GetHdc());
2087 COLORREF old_background
= ::GetBkColor(GetHdc());
2088 if (m_textForegroundColour
.Ok())
2090 ::SetTextColor(GetHdc(), m_textForegroundColour
.GetPixel() );
2092 if (m_textBackgroundColour
.Ok())
2094 ::SetBkColor(GetHdc(), m_textBackgroundColour
.GetPixel() );
2100 case wxXOR
: dwRop
= SRCINVERT
; break;
2101 case wxINVERT
: dwRop
= DSTINVERT
; break;
2102 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2103 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2104 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2105 case wxSET
: dwRop
= WHITENESS
; break;
2106 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2107 case wxAND
: dwRop
= SRCAND
; break;
2108 case wxOR
: dwRop
= SRCPAINT
; break;
2109 case wxEQUIV
: dwRop
= 0x00990066; break;
2110 case wxNAND
: dwRop
= 0x007700E6; break;
2111 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2112 case wxCOPY
: dwRop
= SRCCOPY
; break;
2113 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2114 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2115 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2117 wxFAIL_MSG( wxT("unsupported logical function") );
2121 bool success
= false;
2126 // we want the part of the image corresponding to the mask to be
2127 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2128 // meaning of fg and bg is inverted which corresponds to wxWin notion
2129 // of the mask which is also contrary to the Windows one)
2131 // On some systems, MaskBlt succeeds yet is much much slower
2132 // than the wxWidgets fall-back implementation. So we need
2133 // to be able to switch this on and off at runtime.
2134 #if wxUSE_SYSTEM_OPTIONS
2135 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2138 if ( dstWidth
== srcWidth
&& dstHeight
== srcHeight
)
2143 xdest
, ydest
, dstWidth
, dstHeight
,
2144 GetHdcOf(*msw_impl
),
2146 (HBITMAP
)mask
->GetMaskBitmap(),
2148 MAKEROP4(dwRop
, DSTCOPY
)
2156 // Blit bitmap with mask
2159 HBITMAP buffer_bmap
;
2161 #if wxUSE_DC_CACHEING
2162 // create a temp buffer bitmap and DCs to access it and the mask
2163 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, msw_impl
->GetHDC());
2164 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2166 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2167 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2169 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2170 dstWidth
, dstHeight
);
2172 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2173 #else // !wxUSE_DC_CACHEING
2174 // create a temp buffer bitmap and DCs to access it and the mask
2175 dc_mask
= ::CreateCompatibleDC(GetHdcOf(*source
));
2176 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2177 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), dstWidth
, dstHeight
);
2178 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2179 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2180 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2182 // copy dest to buffer
2183 if ( !::BitBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2184 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2186 wxLogLastError(wxT("BitBlt"));
2190 StretchBltModeChanger
changeMode(dc_buffer
, COLORONCOLOR
);
2193 // copy src to buffer using selected raster op
2194 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2195 GetHdcOf(*msw_impl
), xsrc
, ysrc
, srcWidth
, srcHeight
, dwRop
) )
2197 wxLogLastError(wxT("StretchBlt"));
2200 // set masked area in buffer to BLACK (pixel value 0)
2201 COLORREF prevBkCol
= ::SetBkColor(GetHdc(), RGB(255, 255, 255));
2202 COLORREF prevCol
= ::SetTextColor(GetHdc(), RGB(0, 0, 0));
2203 if ( !::StretchBlt(dc_buffer
, 0, 0, (int)dstWidth
, (int)dstHeight
,
2204 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2206 wxLogLastError(wxT("StretchBlt"));
2209 // set unmasked area in dest to BLACK
2210 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2211 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2212 if ( !::StretchBlt(GetHdc(), xdest
, ydest
, (int)dstWidth
, (int)dstHeight
,
2213 dc_mask
, xsrcMask
, ysrcMask
, srcWidth
, srcHeight
, SRCAND
) )
2215 wxLogLastError(wxT("StretchBlt"));
2217 ::SetBkColor(GetHdc(), prevBkCol
); // restore colours to original values
2218 ::SetTextColor(GetHdc(), prevCol
);
2220 // OR buffer to dest
2221 success
= ::BitBlt(GetHdc(), xdest
, ydest
,
2222 (int)dstWidth
, (int)dstHeight
,
2223 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2226 wxLogLastError(wxT("BitBlt"));
2229 // tidy up temporary DCs and bitmap
2230 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2231 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2233 #if !wxUSE_DC_CACHEING
2235 ::DeleteDC(dc_mask
);
2236 ::DeleteDC(dc_buffer
);
2237 ::DeleteObject(buffer_bmap
);
2242 else // no mask, just BitBlt() it
2244 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2245 // use StretchBlt() if available and finally fall back to BitBlt()
2247 // FIXME: use appropriate WinCE functions
2249 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2250 if ( bmpSrc
.Ok() && (caps
& RC_STRETCHDIB
) )
2255 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2257 &ds
) == sizeof(ds
) )
2259 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2261 // Figure out what co-ordinate system we're supposed to specify
2263 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2267 ysrc
= hDIB
- (ysrc
+ dstHeight
);
2270 if ( ::StretchDIBits(GetHdc(),
2272 dstWidth
, dstHeight
,
2274 srcWidth
, srcHeight
,
2276 (LPBITMAPINFO
)&ds
.dsBmih
,
2279 ) == (int)GDI_ERROR
)
2281 // On Win9x this API fails most (all?) of the time, so
2282 // logging it becomes quite distracting. Since it falls
2283 // back to the code below this is not really serious, so
2285 //wxLogLastError(wxT("StretchDIBits"));
2294 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2299 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2305 xdest
, ydest
, dstWidth
, dstHeight
,
2306 GetHdcOf(*msw_impl
),
2307 xsrc
, ysrc
, srcWidth
, srcHeight
,
2311 wxLogLastError(_T("StretchBlt"));
2325 (int)dstWidth
, (int)dstHeight
,
2326 GetHdcOf(*msw_impl
),
2331 wxLogLastError(_T("BitBlt"));
2340 ::SetTextColor(GetHdc(), old_textground
);
2341 ::SetBkColor(GetHdc(), old_background
);
2346 void wxMSWDCImpl::GetDeviceSize(int *width
, int *height
) const
2348 WXMICROWIN_CHECK_HDC
2351 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2353 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2356 void wxMSWDCImpl::DoGetSizeMM(int *w
, int *h
) const
2358 WXMICROWIN_CHECK_HDC
2360 // if we implement it in terms of DoGetSize() instead of directly using the
2361 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2362 // will also work for wxWindowDC and wxClientDC even though their size is
2363 // not the same as the total size of the screen
2364 int wPixels
, hPixels
;
2365 DoGetSize(&wPixels
, &hPixels
);
2369 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2371 wxCHECK_RET( wTotal
, _T("0 width device?") );
2373 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2378 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2380 wxCHECK_RET( hTotal
, _T("0 height device?") );
2382 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2386 wxSize
wxMSWDCImpl::GetPPI() const
2388 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2390 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2391 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2393 return wxSize(x
, y
);
2396 // For use by wxWidgets only, unless custom units are required.
2397 void wxMSWDCImpl::SetLogicalScale(double x
, double y
)
2399 WXMICROWIN_CHECK_HDC
2401 wxDCImpl::SetLogicalScale(x
,y
);
2404 // ----------------------------------------------------------------------------
2406 // ----------------------------------------------------------------------------
2408 #if wxUSE_DC_CACHEING
2411 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2412 * improve it in due course, either using arrays, or simply storing pointers to one
2413 * entry for the bitmap, and two for the DCs. -- JACS
2416 wxObjectList
wxMSWDCImpl::sm_bitmapCache
;
2417 wxObjectList
wxMSWDCImpl::sm_dcCache
;
2419 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2428 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2437 wxDCCacheEntry::~wxDCCacheEntry()
2440 ::DeleteObject((HBITMAP
) m_bitmap
);
2442 ::DeleteDC((HDC
) m_dc
);
2445 wxDCCacheEntry
* wxMSWDCImpl::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2447 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2448 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2451 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2453 if (entry
->m_depth
== depth
)
2455 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2457 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2458 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2459 if ( !entry
->m_bitmap
)
2461 wxLogLastError(wxT("CreateCompatibleBitmap"));
2463 entry
->m_width
= w
; entry
->m_height
= h
;
2469 node
= node
->GetNext();
2471 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2474 wxLogLastError(wxT("CreateCompatibleBitmap"));
2476 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2477 AddToBitmapCache(entry
);
2481 wxDCCacheEntry
* wxMSWDCImpl::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2483 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2484 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2487 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2489 // Don't return the same one as we already have
2490 if (!notThis
|| (notThis
!= entry
))
2492 if (entry
->m_depth
== depth
)
2498 node
= node
->GetNext();
2500 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2503 wxLogLastError(wxT("CreateCompatibleDC"));
2505 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2506 AddToDCCache(entry
);
2510 void wxMSWDCImpl::AddToBitmapCache(wxDCCacheEntry
* entry
)
2512 sm_bitmapCache
.Append(entry
);
2515 void wxMSWDCImpl::AddToDCCache(wxDCCacheEntry
* entry
)
2517 sm_dcCache
.Append(entry
);
2520 void wxMSWDCImpl::ClearCache()
2522 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2523 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2526 // Clean up cache at app exit
2527 class wxDCModule
: public wxModule
2530 virtual bool OnInit() { return true; }
2531 virtual void OnExit() { wxMSWDCImpl::ClearCache(); }
2534 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2537 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2539 #endif // wxUSE_DC_CACHEING
2541 // ----------------------------------------------------------------------------
2542 // alpha channel support
2543 // ----------------------------------------------------------------------------
2545 static bool AlphaBlt(HDC hdcDst
,
2546 int x
, int y
, int dstWidth
, int dstHeight
,
2548 int srcWidth
, int srcHeight
,
2550 const wxBitmap
& bmp
)
2552 wxASSERT_MSG( bmp
.Ok() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2553 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2555 // do we have AlphaBlend() and company in the headers?
2556 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2557 // yes, now try to see if we have it during run-time
2558 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2559 HDC
,int,int,int,int,
2563 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2564 if ( pfnAlphaBlend
)
2567 bf
.BlendOp
= AC_SRC_OVER
;
2569 bf
.SourceConstantAlpha
= 0xff;
2570 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2572 if ( pfnAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
,
2573 hdcSrc
, srcX
, srcY
, srcWidth
, srcHeight
,
2576 // skip wxAlphaBlend() call below
2580 wxLogLastError(_T("AlphaBlend"));
2583 wxUnusedVar(hdcSrc
);
2584 #endif // defined(AC_SRC_OVER)
2586 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2588 #ifdef wxHAVE_RAW_BITMAP
2589 wxAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
, srcX
, srcY
, srcWidth
, srcHeight
, bmp
);
2592 #else // !wxHAVE_RAW_BITMAP
2593 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2594 // alpha but at least something will be shown like this)
2597 #endif // wxHAVE_RAW_BITMAP
2601 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2602 #ifdef wxHAVE_RAW_BITMAP
2605 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2606 int dstWidth
, int dstHeight
,
2608 int srcWidth
, int srcHeight
,
2609 const wxBitmap
& bmpSrc
)
2611 // get the destination DC pixels
2612 wxBitmap
bmpDst(dstWidth
, dstHeight
, 32 /* force creating RGBA DIB */);
2614 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2616 if ( !::BitBlt(hdcMem
, 0, 0, dstWidth
, dstHeight
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2618 wxLogLastError(_T("BitBlt"));
2621 // combine them with the source bitmap using alpha
2622 wxAlphaPixelData
dataDst(bmpDst
),
2623 dataSrc((wxBitmap
&)bmpSrc
);
2625 wxCHECK_RET( dataDst
&& dataSrc
,
2626 _T("failed to get raw data in wxAlphaBlend") );
2628 wxAlphaPixelData::Iterator
pDst(dataDst
),
2632 for ( int y
= 0; y
< dstHeight
; y
++ )
2634 wxAlphaPixelData::Iterator pDstRowStart
= pDst
;
2636 for ( int x
= 0; x
< dstWidth
; x
++ )
2638 // source is point sampled, Alpha StretchBlit is ugly on Win95
2639 // (but does not impact performance)
2640 pSrc
.MoveTo(dataSrc
, srcX
+ (srcWidth
*x
/dstWidth
), srcY
+ (srcHeight
*y
/dstHeight
));
2642 // note that source bitmap uses premultiplied alpha (as required by
2643 // the real AlphaBlend)
2644 const unsigned beta
= 255 - pSrc
.Alpha();
2646 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2647 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2648 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2653 pDst
= pDstRowStart
;
2654 pDst
.OffsetY(dataDst
, 1);
2657 // and finally blit them back to the destination DC
2658 if ( !::BitBlt(hdcDst
, xDst
, yDst
, dstWidth
, dstHeight
, hdcMem
, 0, 0, SRCCOPY
) )
2660 wxLogLastError(_T("BitBlt"));
2664 #endif // #ifdef wxHAVE_RAW_BITMAP
2666 void wxMSWDCImpl::DoGradientFillLinear (const wxRect
& rect
,
2667 const wxColour
& initialColour
,
2668 const wxColour
& destColour
,
2669 wxDirection nDirection
)
2671 // use native function if we have compile-time support it and can load it
2672 // during run-time (linking to it statically would make the program
2673 // unusable on earlier Windows versions)
2674 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2676 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2677 static GradientFill_t pfnGradientFill
=
2678 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2680 if ( pfnGradientFill
)
2682 GRADIENT_RECT grect
;
2683 grect
.UpperLeft
= 0;
2684 grect
.LowerRight
= 1;
2686 // invert colours direction if not filling from left-to-right or
2688 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2690 // one vertex for upper left and one for upper-right
2691 TRIVERTEX vertices
[2];
2693 vertices
[0].x
= rect
.GetLeft();
2694 vertices
[0].y
= rect
.GetTop();
2695 vertices
[1].x
= rect
.GetRight()+1;
2696 vertices
[1].y
= rect
.GetBottom()+1;
2698 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2699 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2700 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2701 vertices
[firstVertex
].Alpha
= 0;
2702 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2703 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2704 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2705 vertices
[1 - firstVertex
].Alpha
= 0;
2707 if ( (*pfnGradientFill
)
2714 nDirection
== wxWEST
|| nDirection
== wxEAST
2715 ? GRADIENT_FILL_RECT_H
2716 : GRADIENT_FILL_RECT_V
2719 // skip call of the base class version below
2723 wxLogLastError(_T("GradientFill"));
2725 #endif // wxUSE_DYNLIB_CLASS
2727 wxDCImpl::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2730 #if wxUSE_DYNLIB_CLASS
2732 static DWORD
wxGetDCLayout(HDC hdc
)
2734 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2736 wxDL_INIT_FUNC(s_pfn
, GetLayout
, wxDynamicLibrary(_T("gdi32.dll")));
2738 return s_pfnGetLayout
? s_pfnGetLayout(hdc
) : (DWORD
)-1;
2741 wxLayoutDirection
wxMSWDCImpl::GetLayoutDirection() const
2743 DWORD layout
= wxGetDCLayout(GetHdc());
2745 if ( layout
== (DWORD
)-1 )
2746 return wxLayout_Default
;
2748 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2751 void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir
)
2753 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2755 wxDL_INIT_FUNC(s_pfn
, SetLayout
, wxDynamicLibrary(_T("gdi32.dll")));
2756 if ( !s_pfnSetLayout
)
2759 if ( dir
== wxLayout_Default
)
2761 dir
= wxTheApp
->GetLayoutDirection();
2762 if ( dir
== wxLayout_Default
)
2766 DWORD layout
= wxGetDCLayout(GetHdc());
2767 if ( dir
== wxLayout_RightToLeft
)
2768 layout
|= LAYOUT_RTL
;
2770 layout
&= ~LAYOUT_RTL
;
2772 s_pfnSetLayout(GetHdc(), layout
);
2775 #else // !wxUSE_DYNLIB_CLASS
2777 // we can't provide RTL support without dynamic loading, so stub it out
2778 wxLayoutDirection
wxMSWDCImpl::GetLayoutDirection() const
2780 return wxLayout_Default
;
2783 void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection
WXUNUSED(dir
))
2787 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS