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"
32 #include "wx/dialog.h"
34 #include "wx/bitmap.h"
35 #include "wx/dcmemory.h"
38 #include "wx/dcprint.h"
39 #include "wx/module.h"
42 #include "wx/msw/dc.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 // ROPs which don't have standard names (see "Ternary Raster Operations" in the
88 // MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
89 #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation
91 // ----------------------------------------------------------------------------
92 // macros for logical <-> device coords conversion
93 // ----------------------------------------------------------------------------
96 We currently let Windows do all the translations itself so these macros are
97 not really needed (any more) but keep them to enhance readability of the
98 code by allowing to see where are the logical and where are the device
103 #define XLOG2DEV(x) ((x-m_logicalOriginX)*m_signX)
104 #define YLOG2DEV(y) ((y-m_logicalOriginY)*m_signY)
105 #define XDEV2LOG(x) ((x)*m_signX+m_logicalOriginX)
106 #define YDEV2LOG(y) ((y)*m_signY+m_logicalOriginY)
108 #define XLOG2DEV(x) (x)
109 #define YLOG2DEV(y) (y)
110 #define XDEV2LOG(x) (x)
111 #define YDEV2LOG(y) (y)
114 // ---------------------------------------------------------------------------
116 // ---------------------------------------------------------------------------
118 // convert degrees to radians
119 static inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
121 // call AlphaBlend() to blit contents of hdcSrc to hdcDst using alpha
123 // NB: bmpSrc is the bitmap selected in hdcSrc, it is not really needed
124 // to pass it to this function but as we already have it at the point
125 // of call anyhow we do
127 // return true if we could draw the bitmap in one way or the other, false
129 static bool AlphaBlt(HDC hdcDst
,
130 int x
, int y
, int dstWidth
, int dstHeight
,
132 int srcWidth
, int srcHeight
,
134 const wxBitmap
& bmp
);
136 #ifdef wxHAVE_RAW_BITMAP
138 // our (limited) AlphaBlend() replacement for Windows versions not providing it
140 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
141 int dstWidth
, int dstHeight
,
143 int srcWidth
, int srcHeight
,
144 const wxBitmap
& bmpSrc
);
146 #endif // wxHAVE_RAW_BITMAP
148 // ----------------------------------------------------------------------------
150 // ----------------------------------------------------------------------------
152 // various classes to change some DC property temporarily
154 // text background and foreground colours
155 class wxTextColoursChanger
158 wxTextColoursChanger(HDC hdc
, const wxMSWDCImpl
& dc
)
161 Change(dc
.GetTextForeground(), dc
.GetTextBackground());
164 wxTextColoursChanger(HDC hdc
, const wxColour
& colFg
, const wxColour
& colBg
)
167 Change(colFg
, colBg
);
170 ~wxTextColoursChanger()
172 if ( m_oldColFg
!= CLR_INVALID
)
173 ::SetTextColor(m_hdc
, m_oldColFg
);
174 if ( m_oldColBg
!= CLR_INVALID
)
175 ::SetBkColor(m_hdc
, m_oldColBg
);
179 // this ctor doesn't change mode immediately, call Change() later to do it
181 wxTextColoursChanger(HDC hdc
)
185 m_oldColBg
= CLR_INVALID
;
188 void Change(const wxColour
& colFg
, const wxColour
& colBg
)
192 m_oldColFg
= ::SetTextColor(m_hdc
, colFg
.GetPixel());
193 if ( m_oldColFg
== CLR_INVALID
)
195 wxLogLastError(_T("SetTextColor"));
200 m_oldColFg
= CLR_INVALID
;
205 m_oldColBg
= ::SetBkColor(m_hdc
, colBg
.GetPixel());
206 if ( m_oldColBg
== CLR_INVALID
)
208 wxLogLastError(_T("SetBkColor"));
213 m_oldColBg
= CLR_INVALID
;
222 DECLARE_NO_COPY_CLASS(wxTextColoursChanger
)
226 class wxBkModeChanger
229 // set background mode to opaque if mode != wxBRUSHSTYLE_TRANSPARENT
230 wxBkModeChanger(HDC hdc
, int mode
)
239 ::SetBkMode(m_hdc
, m_oldMode
);
243 // this ctor doesn't change mode immediately, call Change() later to do it
245 wxBkModeChanger(HDC hdc
) : m_hdc(hdc
) { m_oldMode
= 0; }
247 void Change(int mode
)
249 m_oldMode
= ::SetBkMode(m_hdc
, mode
== wxBRUSHSTYLE_TRANSPARENT
254 wxLogLastError(_T("SetBkMode"));
262 DECLARE_NO_COPY_CLASS(wxBkModeChanger
)
265 // instead of duplicating the same code which sets and then restores text
266 // colours in each wxDC method working with wxSTIPPLE_MASK_OPAQUE brushes,
267 // encapsulate this in a small helper class
269 // wxBrushAttrsSetter: changes the text colours in the ctor if required and
270 // restores them in the dtor
271 class wxBrushAttrsSetter
: private wxBkModeChanger
,
272 private wxTextColoursChanger
275 wxBrushAttrsSetter(wxMSWDCImpl
& dc
);
278 DECLARE_NO_COPY_CLASS(wxBrushAttrsSetter
)
281 // this class saves the old stretch blit mode during its life time
282 class StretchBltModeChanger
285 StretchBltModeChanger(HDC hdc
,
286 int WXUNUSED_IN_WINCE(mode
))
290 m_modeOld
= ::SetStretchBltMode(m_hdc
, mode
);
292 wxLogLastError(_T("SetStretchBltMode"));
296 ~StretchBltModeChanger()
299 if ( !::SetStretchBltMode(m_hdc
, m_modeOld
) )
300 wxLogLastError(_T("SetStretchBltMode"));
309 DECLARE_NO_COPY_CLASS(StretchBltModeChanger
)
312 #if wxUSE_DYNLIB_CLASS
314 // helper class to cache dynamically loaded libraries and not attempt reloading
316 class wxOnceOnlyDLLLoader
319 // ctor argument must be a literal string as we don't make a copy of it!
320 wxOnceOnlyDLLLoader(const wxChar
*dllName
)
326 // return the symbol with the given name or NULL if the DLL not loaded
327 // or symbol not present
328 void *GetSymbol(const wxChar
*name
)
330 // we're prepared to handle errors here
335 m_dll
.Load(m_dllName
);
337 // reset the name whether we succeeded or failed so that we don't
338 // try again the next time
342 return m_dll
.IsLoaded() ? m_dll
.GetSymbol(name
) : NULL
;
347 if ( m_dll
.IsLoaded() )
354 wxDynamicLibrary m_dll
;
355 const wxChar
*m_dllName
;
358 static wxOnceOnlyDLLLoader
wxMSIMG32DLL(_T("msimg32"));
360 // we must ensure that DLLs are unloaded before the static objects cleanup time
361 // because we may hit the notorious DllMain() dead lock in this case if wx is
362 // used as a DLL (attempting to unload another DLL from inside DllMain() hangs
363 // under Windows because it tries to reacquire the same lock)
364 class wxGDIDLLsCleanupModule
: public wxModule
367 virtual bool OnInit() { return true; }
368 virtual void OnExit() { wxMSIMG32DLL
.Unload(); }
371 DECLARE_DYNAMIC_CLASS(wxGDIDLLsCleanupModule
)
374 IMPLEMENT_DYNAMIC_CLASS(wxGDIDLLsCleanupModule
, wxModule
)
376 #endif // wxUSE_DYNLIB_CLASS
378 // ===========================================================================
380 // ===========================================================================
382 // ----------------------------------------------------------------------------
383 // wxBrushAttrsSetter
384 // ----------------------------------------------------------------------------
386 wxBrushAttrsSetter::wxBrushAttrsSetter(wxMSWDCImpl
& dc
)
387 : wxBkModeChanger(GetHdcOf(dc
)),
388 wxTextColoursChanger(GetHdcOf(dc
))
390 const wxBrush
& brush
= dc
.GetBrush();
391 if ( brush
.IsOk() && brush
.GetStyle() == wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE
)
393 // note that Windows convention is opposite to wxWidgets one, this is
394 // why text colour becomes the background one and vice versa
395 wxTextColoursChanger::Change(dc
.GetTextBackground(),
396 dc
.GetTextForeground());
398 wxBkModeChanger::Change(dc
.GetBackgroundMode());
402 // ---------------------------------------------------------------------------
404 // ---------------------------------------------------------------------------
406 wxMSWDCImpl::wxMSWDCImpl( wxDC
*owner
, WXHDC hDC
) :
413 wxMSWDCImpl::~wxMSWDCImpl()
417 SelectOldObjects(m_hDC
);
419 // if we own the HDC, we delete it, otherwise we just release it
423 ::DeleteDC(GetHdc());
425 else // we don't own our HDC
429 ::ReleaseDC(GetHwndOf(m_window
), GetHdc());
433 // Must have been a wxScreenDC
434 ::ReleaseDC((HWND
) NULL
, GetHdc());
440 // This will select current objects out of the DC,
441 // which is what you have to do before deleting the
443 void wxMSWDCImpl::SelectOldObjects(WXHDC dc
)
449 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
451 if (m_selectedBitmap
.IsOk())
453 m_selectedBitmap
.SetSelectedInto(NULL
);
460 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
465 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
470 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
477 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
480 #endif // wxUSE_PALETTE
483 m_brush
= wxNullBrush
;
486 m_palette
= wxNullPalette
;
487 #endif // wxUSE_PALETTE
489 m_backgroundBrush
= wxNullBrush
;
490 m_selectedBitmap
= wxNullBitmap
;
493 // ---------------------------------------------------------------------------
495 // ---------------------------------------------------------------------------
497 void wxMSWDCImpl::UpdateClipBox()
502 ::GetClipBox(GetHdc(), &rect
);
504 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
505 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
506 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
507 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
511 wxMSWDCImpl::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
513 // check if we should try to retrieve the clipping region possibly not set
514 // by our SetClippingRegion() but preset by Windows:this can only happen
515 // when we're associated with an existing HDC usign SetHDC(), see there
516 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
518 wxMSWDCImpl
*self
= wxConstCast(this, wxMSWDCImpl
);
519 self
->UpdateClipBox();
521 if ( !m_clipX1
&& !m_clipX2
)
522 self
->m_clipping
= false;
525 wxDCImpl::DoGetClippingBox(x
, y
, w
, h
);
528 // common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
529 void wxMSWDCImpl::SetClippingHrgn(WXHRGN hrgn
)
531 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
535 // note that we combine the new clipping region with the existing one: this
536 // is compatible with what the other ports do and is the documented
537 // behaviour now (starting with 2.3.3)
538 #if defined(__WXWINCE__)
540 if ( !::GetClipBox(GetHdc(), &rectClip
) )
543 // GetClipBox returns logical coordinates, so transform to device
544 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
545 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
546 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
547 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
549 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
550 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
551 rectClip
.right
, rectClip
.bottom
);
553 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
555 ::SelectClipRgn(GetHdc(), hrgnDest
);
558 ::DeleteObject(hrgnClipOld
);
559 ::DeleteObject(hrgnDest
);
561 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
563 wxLogLastError(_T("ExtSelectClipRgn"));
567 #endif // WinCE/!WinCE
574 void wxMSWDCImpl::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
576 // the region coords are always the device ones, so do the translation
579 // FIXME: possible +/-1 error here, to check!
580 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
582 LogicalToDeviceX(x
+ w
),
583 LogicalToDeviceY(y
+ h
));
586 wxLogLastError(_T("CreateRectRgn"));
590 SetClippingHrgn((WXHRGN
)hrgn
);
592 ::DeleteObject(hrgn
);
596 void wxMSWDCImpl::DoSetClippingRegionAsRegion(const wxRegion
& region
)
598 SetClippingHrgn(region
.GetHRGN());
601 void wxMSWDCImpl::DestroyClippingRegion()
605 if (m_clipping
&& m_hDC
)
608 // On a PocketPC device (not necessarily emulator), resetting
609 // the clip region as per the old method causes bad display
610 // problems. In fact setting a null region is probably OK
611 // on desktop WIN32 also, since the WIN32 docs imply that the user
612 // clipping region is independent from the paint clipping region.
613 ::SelectClipRgn(GetHdc(), 0);
615 // TODO: this should restore the previous clipping region,
616 // so that OnPaint processing works correctly, and the update
617 // clipping region doesn't get destroyed after the first
618 // DestroyClippingRegion.
619 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
620 ::SelectClipRgn(GetHdc(), rgn
);
625 wxDCImpl::DestroyClippingRegion();
628 // ---------------------------------------------------------------------------
629 // query capabilities
630 // ---------------------------------------------------------------------------
632 bool wxMSWDCImpl::CanDrawBitmap() const
637 bool wxMSWDCImpl::CanGetTextExtent() const
639 #ifdef __WXMICROWIN__
640 // TODO Extend MicroWindows' GetDeviceCaps function
643 // What sort of display is it?
644 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
646 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
650 int wxMSWDCImpl::GetDepth() const
652 WXMICROWIN_CHECK_HDC_RET(16)
654 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
657 // ---------------------------------------------------------------------------
659 // ---------------------------------------------------------------------------
661 void wxMSWDCImpl::Clear()
668 GetClientRect((HWND
) m_window
->GetHWND(), &rect
);
672 // No, I think we should simply ignore this if printing on e.g.
674 // wxCHECK_RET( m_selectedBitmap.IsOk(), wxT("this DC can't be cleared") );
675 if (!m_selectedBitmap
.IsOk())
678 rect
.left
= -m_deviceOriginX
; rect
.top
= -m_deviceOriginY
;
679 rect
.right
= m_selectedBitmap
.GetWidth()-m_deviceOriginX
;
680 rect
.bottom
= m_selectedBitmap
.GetHeight()-m_deviceOriginY
;
684 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
687 DWORD colour
= ::GetBkColor(GetHdc());
688 HBRUSH brush
= ::CreateSolidBrush(colour
);
689 ::FillRect(GetHdc(), &rect
, brush
);
690 ::DeleteObject(brush
);
692 RealizeScaleAndOrigin();
695 bool wxMSWDCImpl::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
696 wxCoord
WXUNUSED_IN_WINCE(y
),
697 const wxColour
& WXUNUSED_IN_WINCE(col
),
698 int WXUNUSED_IN_WINCE(style
))
703 WXMICROWIN_CHECK_HDC_RET(false)
705 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
707 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
708 : FLOODFILLBORDER
) ) ;
711 // quoting from the MSDN docs:
713 // Following are some of the reasons this function might fail:
715 // * The filling could not be completed.
716 // * The specified point has the boundary color specified by the
717 // crColor parameter (if FLOODFILLBORDER was requested).
718 // * The specified point does not have the color specified by
719 // crColor (if FLOODFILLSURFACE was requested)
720 // * The point is outside the clipping region that is, it is not
721 // visible on the device.
723 wxLogLastError(wxT("ExtFloodFill"));
726 CalcBoundingBox(x
, y
);
732 bool wxMSWDCImpl::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
734 WXMICROWIN_CHECK_HDC_RET(false)
736 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxMSWDCImpl::GetPixel") );
738 // get the color of the pixel
739 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
741 wxRGBToColour(*col
, pixelcolor
);
746 void wxMSWDCImpl::DoCrossHair(wxCoord x
, wxCoord y
)
750 wxCoord x1
= x
-VIEWPORT_EXTENT
;
751 wxCoord y1
= y
-VIEWPORT_EXTENT
;
752 wxCoord x2
= x
+VIEWPORT_EXTENT
;
753 wxCoord y2
= y
+VIEWPORT_EXTENT
;
755 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
756 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
758 CalcBoundingBox(x1
, y1
);
759 CalcBoundingBox(x2
, y2
);
762 void wxMSWDCImpl::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
766 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
768 CalcBoundingBox(x1
, y1
);
769 CalcBoundingBox(x2
, y2
);
772 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
773 // and ending at (x2, y2)
774 void wxMSWDCImpl::DoDrawArc(wxCoord x1
, wxCoord y1
,
775 wxCoord x2
, wxCoord y2
,
776 wxCoord xc
, wxCoord yc
)
779 // Slower emulation since WinCE doesn't support Pie and Arc
780 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
781 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
782 if( y1
>yc
) sa
= -sa
; // below center
783 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
784 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
789 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
793 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
794 wxCoord r
= (wxCoord
)radius
;
796 // treat the special case of full circle separately
797 if ( x1
== x2
&& y1
== y2
)
799 GetOwner()->DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
803 wxCoord xx1
= XLOG2DEV(x1
);
804 wxCoord yy1
= YLOG2DEV(y1
);
805 wxCoord xx2
= XLOG2DEV(x2
);
806 wxCoord yy2
= YLOG2DEV(y2
);
807 wxCoord xxc
= XLOG2DEV(xc
);
808 wxCoord yyc
= YLOG2DEV(yc
);
809 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
811 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
812 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
813 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
814 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
816 if ( m_brush
.IsOk() && m_brush
.GetStyle() != wxBRUSHSTYLE_TRANSPARENT
)
818 // Have to add 1 to bottom-right corner of rectangle
819 // to make semi-circles look right (crooked line otherwise).
820 // Unfortunately this is not a reliable method, depends
821 // on the size of shape.
822 // TODO: figure out why this happens!
823 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
827 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
830 CalcBoundingBox(xc
- r
, yc
- r
);
831 CalcBoundingBox(xc
+ r
, yc
+ r
);
835 void wxMSWDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
836 wxCoord width
, wxCoord height
)
838 // cases when we don't have DrawFrameControl()
839 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
840 return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
);
842 wxCoord x2
= x1
+ width
,
852 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
| DFCS_CHECKED
);
854 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
857 CalcBoundingBox(x1
, y1
);
858 CalcBoundingBox(x2
, y2
);
859 #endif // Microwin/Normal
862 void wxMSWDCImpl::DoDrawPoint(wxCoord x
, wxCoord y
)
866 COLORREF color
= 0x00ffffff;
869 color
= m_pen
.GetColour().GetPixel();
872 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
874 CalcBoundingBox(x
, y
);
877 void wxMSWDCImpl::DoDrawPolygon(int n
,
881 int WXUNUSED_IN_WINCE(fillStyle
))
885 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
887 // Do things less efficiently if we have offsets
888 if (xoffset
!= 0 || yoffset
!= 0)
890 POINT
*cpoints
= new POINT
[n
];
892 for (i
= 0; i
< n
; i
++)
894 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
895 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
897 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
900 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
902 (void)Polygon(GetHdc(), cpoints
, n
);
904 SetPolyFillMode(GetHdc(),prev
);
911 for (i
= 0; i
< n
; i
++)
912 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
915 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
917 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
919 SetPolyFillMode(GetHdc(),prev
);
925 wxMSWDCImpl::DoDrawPolyPolygon(int n
,
933 wxDCImpl::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
937 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
939 for (i
= cnt
= 0; i
< n
; i
++)
942 // Do things less efficiently if we have offsets
943 if (xoffset
!= 0 || yoffset
!= 0)
945 POINT
*cpoints
= new POINT
[cnt
];
946 for (i
= 0; i
< cnt
; i
++)
948 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
949 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
951 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
954 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
956 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
958 SetPolyFillMode(GetHdc(),prev
);
964 for (i
= 0; i
< cnt
; i
++)
965 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
968 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
970 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
972 SetPolyFillMode(GetHdc(),prev
);
979 void wxMSWDCImpl::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
983 // Do things less efficiently if we have offsets
984 if (xoffset
!= 0 || yoffset
!= 0)
986 POINT
*cpoints
= new POINT
[n
];
988 for (i
= 0; i
< n
; i
++)
990 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
991 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
993 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
995 (void)Polyline(GetHdc(), cpoints
, n
);
1001 for (i
= 0; i
< n
; i
++)
1002 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
1004 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
1008 void wxMSWDCImpl::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1010 WXMICROWIN_CHECK_HDC
1012 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1014 wxCoord x2
= x
+ width
;
1015 wxCoord y2
= y
+ height
;
1017 wxCoord x2dev
= XLOG2DEV(x2
),
1018 y2dev
= YLOG2DEV(y2
);
1020 // Windows (but not Windows CE) draws the filled rectangles without outline
1021 // (i.e. drawn with a transparent pen) one pixel smaller in both directions
1022 // and we want them to have the same size regardless of which pen is used
1024 if ( m_pen
.IsOk() && m_pen
.GetStyle() == wxPENSTYLE_TRANSPARENT
)
1029 #endif // !__WXWINCE__
1031 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), x2dev
, y2dev
);
1033 CalcBoundingBox(x
, y
);
1034 CalcBoundingBox(x2
, y2
);
1037 void wxMSWDCImpl::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
1039 WXMICROWIN_CHECK_HDC
1041 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1043 // Now, a negative radius value is interpreted to mean
1044 // 'the proportion of the smallest X or Y dimension'
1048 double smallest
= (width
< height
) ? width
: height
;
1049 radius
= (- radius
* smallest
);
1052 wxCoord x2
= (x
+width
);
1053 wxCoord y2
= (y
+height
);
1055 // Windows draws the filled rectangles without outline (i.e. drawn with a
1056 // transparent pen) one pixel smaller in both directions and we want them
1057 // to have the same size regardless of which pen is used - adjust
1058 if ( m_pen
.GetStyle() == wxPENSTYLE_TRANSPARENT
)
1064 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
1065 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
1067 CalcBoundingBox(x
, y
);
1068 CalcBoundingBox(x2
, y2
);
1071 void wxMSWDCImpl::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1073 WXMICROWIN_CHECK_HDC
1075 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1077 wxCoord x2
= (x
+width
);
1078 wxCoord y2
= (y
+height
);
1080 (void)Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
1082 CalcBoundingBox(x
, y
);
1083 CalcBoundingBox(x2
, y2
);
1087 void wxMSWDCImpl::DoDrawSpline(const wxPointList
*points
)
1090 // WinCE does not support ::PolyBezier so use generic version
1091 wxDCImpl::DoDrawSpline(points
);
1093 // quadratic b-spline to cubic bezier spline conversion
1095 // quadratic spline with control points P0,P1,P2
1096 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1098 // bezier spline with control points B0,B1,B2,B3
1099 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1101 // control points of bezier spline calculated from b-spline
1103 // B1 = (2*P1 + P0)/3
1104 // B2 = (2*P1 + P2)/3
1107 WXMICROWIN_CHECK_HDC
1109 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1111 const size_t n_points
= points
->GetCount();
1112 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1114 const size_t n_bezier_points
= n_points
* 3 + 1;
1115 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1116 size_t bezier_pos
= 0;
1117 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1119 wxPointList::compatibility_iterator node
= points
->GetFirst();
1120 wxPoint
*p
= node
->GetData();
1121 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1122 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1124 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1127 node
= node
->GetNext();
1128 p
= node
->GetData();
1132 cx1
= ( x1
+ x2
) / 2;
1133 cy1
= ( y1
+ y2
) / 2;
1134 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1135 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1137 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1141 while ((node
= node
->GetNext()) != NULL
)
1143 while ((node
= node
->GetNext()))
1144 #endif // !wxUSE_STL
1146 p
= (wxPoint
*)node
->GetData();
1151 cx4
= (x1
+ x2
) / 2;
1152 cy4
= (y1
+ y2
) / 2;
1153 // B0 is B3 of previous segment
1155 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1156 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1159 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1160 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1163 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1164 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1170 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1172 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1173 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1175 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1178 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1185 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1186 void wxMSWDCImpl::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1189 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1192 WXMICROWIN_CHECK_HDC
1194 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1199 int rx1
= XLOG2DEV(x
+w
/2);
1200 int ry1
= YLOG2DEV(y
+h
/2);
1207 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1208 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1209 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1210 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1212 // Swap start and end positions if the end angle is less than the start angle.
1223 // draw pie with NULL_PEN first and then outline otherwise a line is
1224 // drawn from the start and end points to the centre
1225 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1228 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1229 rx1
, ry1
, rx2
, ry2
);
1233 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1234 rx1
, ry1
-1, rx2
, ry2
-1);
1237 ::SelectObject(GetHdc(), hpenOld
);
1239 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1240 rx1
, ry1
, rx2
, ry2
);
1242 CalcBoundingBox(x
, y
);
1243 CalcBoundingBox(x2
, y2
);
1247 void wxMSWDCImpl::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1249 WXMICROWIN_CHECK_HDC
1251 wxCHECK_RET( icon
.IsOk(), wxT("invalid icon in DrawIcon") );
1254 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1256 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1259 CalcBoundingBox(x
, y
);
1260 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1263 void wxMSWDCImpl::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1265 WXMICROWIN_CHECK_HDC
1267 wxCHECK_RET( bmp
.IsOk(), _T("invalid bitmap in wxMSWDCImpl::DrawBitmap") );
1269 int width
= bmp
.GetWidth(),
1270 height
= bmp
.GetHeight();
1272 HBITMAP hbmpMask
= 0;
1275 HPALETTE oldPal
= 0;
1276 #endif // wxUSE_PALETTE
1278 if ( bmp
.HasAlpha() )
1281 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1283 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, width
, height
, hdcMem
, bmp
) )
1289 wxMask
*mask
= bmp
.GetMask();
1291 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1295 // don't give assert here because this would break existing
1296 // programs - just silently ignore useMask parameter
1303 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1305 // On some systems, MaskBlt succeeds yet is much much slower
1306 // than the wxWidgets fall-back implementation. So we need
1307 // to be able to switch this on and off at runtime.
1309 #if wxUSE_SYSTEM_OPTIONS
1310 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1314 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1315 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1317 wxPalette
*pal
= bmp
.GetPalette();
1318 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1320 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1321 ::RealizePalette(hdcMem
);
1323 #endif // wxUSE_PALETTE
1325 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1328 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1332 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1333 #endif // wxUSE_PALETTE
1335 ::SelectObject(hdcMem
, hOldBitmap
);
1342 // Rather than reproduce wxMSWDCImpl::Blit, let's do it at the wxWin API
1346 memDC
.SelectObjectAsSource(bmp
);
1348 GetOwner()->Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1350 memDC
.SelectObject(wxNullBitmap
);
1353 else // no mask, just use BitBlt()
1356 HDC memdc
= ::CreateCompatibleDC( cdc
);
1357 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1359 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1361 wxTextColoursChanger
textCol(GetHdc(), *this);
1364 wxPalette
*pal
= bmp
.GetPalette();
1365 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1367 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1368 ::RealizePalette(memdc
);
1370 #endif // wxUSE_PALETTE
1372 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1373 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1377 ::SelectPalette(memdc
, oldPal
, FALSE
);
1378 #endif // wxUSE_PALETTE
1380 ::SelectObject( memdc
, hOldBitmap
);
1381 ::DeleteDC( memdc
);
1385 void wxMSWDCImpl::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1387 WXMICROWIN_CHECK_HDC
1389 DrawAnyText(text
, x
, y
);
1391 // update the bounding box
1392 CalcBoundingBox(x
, y
);
1395 GetOwner()->GetTextExtent(text
, &w
, &h
);
1396 CalcBoundingBox(x
+ w
, y
+ h
);
1399 void wxMSWDCImpl::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1401 WXMICROWIN_CHECK_HDC
1403 // prepare for drawing the text
1404 wxTextColoursChanger
textCol(GetHdc(), *this);
1406 wxBkModeChanger
bkMode(GetHdc(), m_backgroundMode
);
1408 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1409 text
.c_str(), text
.length(), NULL
) == 0 )
1411 wxLogLastError(wxT("TextOut"));
1415 void wxMSWDCImpl::DoDrawRotatedText(const wxString
& text
,
1416 wxCoord x
, wxCoord y
,
1419 WXMICROWIN_CHECK_HDC
1421 // we test that we have some font because otherwise we should still use the
1422 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1423 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1424 // font for drawing rotated fonts unfortunately)
1425 if ( (angle
== 0.0) && m_font
.IsOk() )
1427 DoDrawText(text
, x
, y
);
1429 #ifndef __WXMICROWIN__
1432 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1433 // because it's not TrueType and so can't have non zero
1434 // orientation/escapement under Win9x
1435 wxFont font
= m_font
.IsOk() ? m_font
: *wxSWISS_FONT
;
1436 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1438 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1440 wxLogLastError(wxT("GetObject(hfont)"));
1443 // GDI wants the angle in tenth of degree
1444 long angle10
= (long)(angle
* 10);
1445 lf
.lfEscapement
= angle10
;
1446 lf
. lfOrientation
= angle10
;
1448 hfont
= ::CreateFontIndirect(&lf
);
1451 wxLogLastError(wxT("CreateFont"));
1455 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1457 DrawAnyText(text
, x
, y
);
1459 (void)::SelectObject(GetHdc(), hfontOld
);
1460 (void)::DeleteObject(hfont
);
1463 // call the bounding box by adding all four vertices of the rectangle
1464 // containing the text to it (simpler and probably not slower than
1465 // determining which of them is really topmost/leftmost/...)
1467 GetOwner()->GetTextExtent(text
, &w
, &h
);
1469 double rad
= DegToRad(angle
);
1471 // "upper left" and "upper right"
1472 CalcBoundingBox(x
, y
);
1473 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1475 // "bottom left" and "bottom right"
1476 x
+= (wxCoord
)(h
*sin(rad
));
1477 y
+= (wxCoord
)(h
*cos(rad
));
1478 CalcBoundingBox(x
, y
);
1479 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1484 // ---------------------------------------------------------------------------
1486 // ---------------------------------------------------------------------------
1490 void wxMSWDCImpl::DoSelectPalette(bool realize
)
1492 WXMICROWIN_CHECK_HDC
1494 // Set the old object temporarily, in case the assignment deletes an object
1495 // that's not yet selected out.
1498 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1502 if ( m_palette
.IsOk() )
1504 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1505 GetHpaletteOf(m_palette
),
1508 m_oldPalette
= (WXHPALETTE
) oldPal
;
1511 ::RealizePalette(GetHdc());
1515 void wxMSWDCImpl::SetPalette(const wxPalette
& palette
)
1517 if ( palette
.IsOk() )
1519 m_palette
= palette
;
1520 DoSelectPalette(true);
1524 void wxMSWDCImpl::InitializePalette()
1526 if ( wxDisplayDepth() <= 8 )
1528 // look for any window or parent that has a custom palette. If any has
1529 // one then we need to use it in drawing operations
1530 wxWindow
*win
= m_window
->GetAncestorWithCustomPalette();
1532 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1533 if ( m_hasCustomPalette
)
1535 m_palette
= win
->GetPalette();
1537 // turn on MSW translation for this palette
1543 #endif // wxUSE_PALETTE
1545 // SetFont/Pen/Brush() really ask to be implemented as a single template
1546 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1548 void wxMSWDCImpl::SetFont(const wxFont
& font
)
1550 WXMICROWIN_CHECK_HDC
1552 if ( font
== m_font
)
1557 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1558 if ( hfont
== HGDI_ERROR
)
1560 wxLogLastError(_T("SelectObject(font)"));
1565 m_oldFont
= (WXHFONT
)hfont
;
1570 else // invalid font, reset the current font
1574 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1576 wxLogLastError(_T("SelectObject(old font)"));
1582 m_font
= wxNullFont
;
1586 void wxMSWDCImpl::SetPen(const wxPen
& pen
)
1588 WXMICROWIN_CHECK_HDC
1595 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1596 if ( hpen
== HGDI_ERROR
)
1598 wxLogLastError(_T("SelectObject(pen)"));
1603 m_oldPen
= (WXHPEN
)hpen
;
1608 else // invalid pen, reset the current pen
1612 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1614 wxLogLastError(_T("SelectObject(old pen)"));
1624 void wxMSWDCImpl::SetBrush(const wxBrush
& brush
)
1626 WXMICROWIN_CHECK_HDC
1628 if ( brush
== m_brush
)
1633 // we must make sure the brush is aligned with the logical coordinates
1634 // before selecting it
1635 wxBitmap
*stipple
= brush
.GetStipple();
1636 if ( stipple
&& stipple
->IsOk() )
1638 if ( !::SetBrushOrgEx
1641 m_deviceOriginX
% stipple
->GetWidth(),
1642 m_deviceOriginY
% stipple
->GetHeight(),
1643 NULL
// [out] previous brush origin
1646 wxLogLastError(_T("SetBrushOrgEx()"));
1650 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1651 if ( hbrush
== HGDI_ERROR
)
1653 wxLogLastError(_T("SelectObject(brush)"));
1658 m_oldBrush
= (WXHBRUSH
)hbrush
;
1663 else // invalid brush, reset the current brush
1667 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1669 wxLogLastError(_T("SelectObject(old brush)"));
1675 m_brush
= wxNullBrush
;
1679 void wxMSWDCImpl::SetBackground(const wxBrush
& brush
)
1681 WXMICROWIN_CHECK_HDC
1683 m_backgroundBrush
= brush
;
1685 if ( m_backgroundBrush
.IsOk() )
1687 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1691 void wxMSWDCImpl::SetBackgroundMode(int mode
)
1693 WXMICROWIN_CHECK_HDC
1695 m_backgroundMode
= mode
;
1697 // SetBackgroundColour now only refers to text background
1698 // and m_backgroundMode is used there
1701 void wxMSWDCImpl::SetLogicalFunction(int function
)
1703 WXMICROWIN_CHECK_HDC
1705 m_logicalFunction
= function
;
1710 void wxMSWDCImpl::SetRop(WXHDC dc
)
1712 if ( !dc
|| m_logicalFunction
< 0 )
1717 switch (m_logicalFunction
)
1719 case wxCLEAR
: rop
= R2_BLACK
; break;
1720 case wxXOR
: rop
= R2_XORPEN
; break;
1721 case wxINVERT
: rop
= R2_NOT
; break;
1722 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1723 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1724 case wxCOPY
: rop
= R2_COPYPEN
; break;
1725 case wxAND
: rop
= R2_MASKPEN
; break;
1726 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1727 case wxNO_OP
: rop
= R2_NOP
; break;
1728 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1729 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1730 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1731 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1732 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1733 case wxOR
: rop
= R2_MERGEPEN
; break;
1734 case wxSET
: rop
= R2_WHITE
; break;
1737 wxFAIL_MSG( wxT("unsupported logical function") );
1741 SetROP2(GetHdc(), rop
);
1744 bool wxMSWDCImpl::StartDoc(const wxString
& WXUNUSED(message
))
1746 // We might be previewing, so return true to let it continue.
1750 void wxMSWDCImpl::EndDoc()
1754 void wxMSWDCImpl::StartPage()
1758 void wxMSWDCImpl::EndPage()
1762 // ---------------------------------------------------------------------------
1764 // ---------------------------------------------------------------------------
1766 wxCoord
wxMSWDCImpl::GetCharHeight() const
1768 WXMICROWIN_CHECK_HDC_RET(0)
1770 TEXTMETRIC lpTextMetric
;
1772 GetTextMetrics(GetHdc(), &lpTextMetric
);
1774 return lpTextMetric
.tmHeight
;
1777 wxCoord
wxMSWDCImpl::GetCharWidth() const
1779 WXMICROWIN_CHECK_HDC_RET(0)
1781 TEXTMETRIC lpTextMetric
;
1783 GetTextMetrics(GetHdc(), &lpTextMetric
);
1785 return lpTextMetric
.tmAveCharWidth
;
1788 void wxMSWDCImpl::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1789 wxCoord
*descent
, wxCoord
*externalLeading
,
1790 const wxFont
*font
) const
1792 #ifdef __WXMICROWIN__
1797 if (descent
) *descent
= 0;
1798 if (externalLeading
) *externalLeading
= 0;
1801 #endif // __WXMICROWIN__
1806 wxASSERT_MSG( font
->IsOk(), _T("invalid font in wxMSWDCImpl::GetTextExtent") );
1808 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1810 else // don't change the font
1816 const size_t len
= string
.length();
1817 if ( !::GetTextExtentPoint32(GetHdc(), string
.wx_str(), len
, &sizeRect
) )
1819 wxLogLastError(_T("GetTextExtentPoint32()"));
1822 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1823 // the result computed by GetTextExtentPoint32() may be too small as it
1824 // accounts for under/overhang of the first/last character while we want
1825 // just the bounding rect for this string so adjust the width as needed
1826 // (using API not available in 2002 SDKs of WinCE)
1830 const wxChar chFirst
= *string
.begin();
1831 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1833 if ( width
.abcA
< 0 )
1834 sizeRect
.cx
-= width
.abcA
;
1838 const wxChar chLast
= *string
.rbegin();
1839 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1841 //else: we already have the width of the last character
1843 if ( width
.abcC
< 0 )
1844 sizeRect
.cx
-= width
.abcC
;
1846 //else: GetCharABCWidths() failed, not a TrueType font?
1848 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1851 ::GetTextMetrics(GetHdc(), &tm
);
1858 *descent
= tm
.tmDescent
;
1859 if (externalLeading
)
1860 *externalLeading
= tm
.tmExternalLeading
;
1864 ::SelectObject(GetHdc(), hfontOld
);
1869 // Each element of the array will be the width of the string up to and
1870 // including the coresoponding character in text.
1872 bool wxMSWDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1874 static int maxLenText
= -1;
1875 static int maxWidth
= -1;
1878 int stlen
= text
.length();
1880 if (maxLenText
== -1)
1882 // Win9x and WinNT+ have different limits
1883 int version
= wxGetOsVersion();
1884 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1885 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1889 widths
.Add(0, stlen
); // fill the array with zeros
1893 if (!::GetTextExtentExPoint(GetHdc(),
1894 text
.c_str(), // string to check
1895 wxMin(stlen
, maxLenText
),
1897 &fit
, // [out] count of chars
1899 &widths
[0], // array to fill
1903 wxLogLastError(wxT("GetTextExtentExPoint"));
1910 void wxMSWDCImpl::RealizeScaleAndOrigin()
1912 // although it may seem wasteful to always use MM_ANISOTROPIC here instead
1913 // of using MM_TEXT if there is no scaling, benchmarking doesn't detect any
1914 // noticeable difference between these mapping modes
1916 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1918 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1919 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1921 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1922 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1924 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1925 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1929 void wxMSWDCImpl::SetMapMode(int mode
)
1931 WXMICROWIN_CHECK_HDC
1933 m_mappingMode
= mode
;
1935 if ( mode
== wxMM_TEXT
)
1938 m_logicalScaleY
= 1.0;
1940 else // need to do some calculations
1942 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1943 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1944 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1945 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1947 if ( (mm_width
== 0) || (mm_height
== 0) )
1949 // we can't calculate mm2pixels[XY] then!
1953 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1954 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1959 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1960 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1964 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1965 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1969 m_logicalScaleX
= mm2pixelsX
;
1970 m_logicalScaleY
= mm2pixelsY
;
1974 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1975 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1979 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1983 ComputeScaleAndOrigin();
1985 RealizeScaleAndOrigin();
1988 void wxMSWDCImpl::SetUserScale(double x
, double y
)
1990 WXMICROWIN_CHECK_HDC
1992 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
1995 wxDCImpl::SetUserScale(x
,y
);
1997 RealizeScaleAndOrigin();
2000 void wxMSWDCImpl::SetAxisOrientation(bool xLeftRight
,
2003 WXMICROWIN_CHECK_HDC
2005 int signX
= xLeftRight
? 1 : -1,
2006 signY
= yBottomUp
? -1 : 1;
2008 if (signX
== m_signX
&& signY
== m_signY
)
2011 wxDCImpl::SetAxisOrientation( xLeftRight
, yBottomUp
);
2013 RealizeScaleAndOrigin();
2016 void wxMSWDCImpl::SetLogicalOrigin(wxCoord x
, wxCoord y
)
2018 WXMICROWIN_CHECK_HDC
2020 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
2023 wxDCImpl::SetLogicalOrigin( x
, y
);
2026 ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX
, (int)m_logicalOriginY
, NULL
);
2030 void wxMSWDCImpl::SetDeviceOrigin(wxCoord x
, wxCoord y
)
2032 WXMICROWIN_CHECK_HDC
2034 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
2037 wxDCImpl::SetDeviceOrigin( x
, y
);
2039 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
2042 // ---------------------------------------------------------------------------
2044 // ---------------------------------------------------------------------------
2046 bool wxMSWDCImpl::DoBlit(wxCoord dstX
, wxCoord dstY
,
2047 wxCoord dstWidth
, wxCoord dstHeight
,
2049 wxCoord srcX
, wxCoord srcY
,
2050 int rop
, bool useMask
,
2051 wxCoord srcMaskX
, wxCoord srcMaskY
)
2053 return DoStretchBlit(dstX
, dstY
, dstWidth
, dstHeight
, source
, srcX
, srcY
, dstWidth
, dstHeight
, rop
, useMask
, srcMaskX
, srcMaskY
);
2056 bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
2057 wxCoord dstWidth
, wxCoord dstHeight
,
2059 wxCoord xsrc
, wxCoord ysrc
,
2060 wxCoord srcWidth
, wxCoord srcHeight
,
2061 int rop
, bool useMask
,
2062 wxCoord xsrcMask
, wxCoord ysrcMask
)
2064 wxCHECK_MSG( source
, false, _T("wxMSWDCImpl::Blit(): NULL wxDC pointer") );
2066 WXMICROWIN_CHECK_HDC_RET(false)
2068 wxMSWDCImpl
*implSrc
= wxDynamicCast( source
->GetImpl(), wxMSWDCImpl
);
2071 // TODO: Do we want to be able to blit from other DCs too?
2075 const HDC hdcSrc
= GetHdcOf(*implSrc
);
2077 // if either the source or destination has alpha channel, we must use
2078 // AlphaBlt() as other function don't handle it correctly
2079 const wxBitmap
& bmpSrc
= implSrc
->GetSelectedBitmap();
2080 if ( bmpSrc
.IsOk() && (bmpSrc
.HasAlpha() ||
2081 (m_selectedBitmap
.IsOk() && m_selectedBitmap
.HasAlpha())) )
2083 if ( AlphaBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2084 xsrc
, ysrc
, srcWidth
, srcHeight
, hdcSrc
, bmpSrc
) )
2088 wxMask
*mask
= NULL
;
2091 mask
= bmpSrc
.GetMask();
2093 if ( !(bmpSrc
.IsOk() && mask
&& mask
->GetMaskBitmap()) )
2095 // don't give assert here because this would break existing
2096 // programs - just silently ignore useMask parameter
2101 if (xsrcMask
== -1 && ysrcMask
== -1)
2103 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2106 wxTextColoursChanger
textCol(GetHdc(), *this);
2111 case wxXOR
: dwRop
= SRCINVERT
; break;
2112 case wxINVERT
: dwRop
= DSTINVERT
; break;
2113 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2114 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2115 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2116 case wxSET
: dwRop
= WHITENESS
; break;
2117 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2118 case wxAND
: dwRop
= SRCAND
; break;
2119 case wxOR
: dwRop
= SRCPAINT
; break;
2120 case wxEQUIV
: dwRop
= 0x00990066; break;
2121 case wxNAND
: dwRop
= 0x007700E6; break;
2122 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2123 case wxCOPY
: dwRop
= SRCCOPY
; break;
2124 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2125 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2126 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2128 wxFAIL_MSG( wxT("unsupported logical function") );
2132 bool success
= false;
2137 // we want the part of the image corresponding to the mask to be
2138 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2139 // meaning of fg and bg is inverted which corresponds to wxWin notion
2140 // of the mask which is also contrary to the Windows one)
2142 // On some systems, MaskBlt succeeds yet is much much slower
2143 // than the wxWidgets fall-back implementation. So we need
2144 // to be able to switch this on and off at runtime.
2145 #if wxUSE_SYSTEM_OPTIONS
2146 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2149 if ( dstWidth
== srcWidth
&& dstHeight
== srcHeight
)
2154 xdest
, ydest
, dstWidth
, dstHeight
,
2157 (HBITMAP
)mask
->GetMaskBitmap(),
2159 MAKEROP4(dwRop
, DSTCOPY
)
2167 // Blit bitmap with mask
2170 HBITMAP buffer_bmap
;
2172 #if wxUSE_DC_CACHEING
2173 // create a temp buffer bitmap and DCs to access it and the mask
2174 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, hdcSrc
);
2175 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2177 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2178 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2180 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2181 dstWidth
, dstHeight
);
2183 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2184 #else // !wxUSE_DC_CACHEING
2185 // create a temp buffer bitmap and DCs to access it and the mask
2186 dc_mask
= ::CreateCompatibleDC(hdcSrc
);
2187 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2188 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), dstWidth
, dstHeight
);
2189 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2190 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2191 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2193 // copy dest to buffer
2194 if ( !::BitBlt(dc_buffer
, 0, 0, dstWidth
, dstHeight
,
2195 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2197 wxLogLastError(wxT("BitBlt"));
2201 StretchBltModeChanger
changeMode(dc_buffer
, COLORONCOLOR
);
2204 // copy src to buffer using selected raster op
2205 if ( !::StretchBlt(dc_buffer
, 0, 0, dstWidth
, dstHeight
,
2206 hdcSrc
, xsrc
, ysrc
, srcWidth
, srcHeight
, dwRop
) )
2208 wxLogLastError(wxT("StretchBlt"));
2211 // set masked area in buffer to BLACK
2213 wxTextColoursChanger
textCol2(GetHdc(), *wxBLACK
, *wxWHITE
);
2214 if ( !::StretchBlt(dc_buffer
, 0, 0, dstWidth
, dstHeight
,
2215 dc_mask
, xsrcMask
, ysrcMask
,
2216 srcWidth
, srcHeight
, SRCAND
) )
2218 wxLogLastError(wxT("StretchBlt"));
2221 // set unmasked area in dest to BLACK
2222 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2223 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2224 if ( !::StretchBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2225 dc_mask
, xsrcMask
, ysrcMask
,
2226 srcWidth
, srcHeight
, SRCAND
) )
2228 wxLogLastError(wxT("StretchBlt"));
2230 } // restore the original text and background colours
2232 // OR buffer to dest
2233 success
= ::BitBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2234 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2237 wxLogLastError(wxT("BitBlt"));
2240 // tidy up temporary DCs and bitmap
2241 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2242 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2244 #if !wxUSE_DC_CACHEING
2246 ::DeleteDC(dc_mask
);
2247 ::DeleteDC(dc_buffer
);
2248 ::DeleteObject(buffer_bmap
);
2253 else // no mask, just BitBlt() it
2255 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2256 // use StretchBlt() if available and finally fall back to BitBlt()
2258 // FIXME: use appropriate WinCE functions
2260 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2261 if ( bmpSrc
.IsOk() && (caps
& RC_STRETCHDIB
) )
2266 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2268 &ds
) == sizeof(ds
) )
2270 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2272 // Figure out what co-ordinate system we're supposed to specify
2274 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2278 ysrc
= hDIB
- (ysrc
+ dstHeight
);
2281 if ( ::StretchDIBits(GetHdc(),
2283 dstWidth
, dstHeight
,
2285 srcWidth
, srcHeight
,
2287 (LPBITMAPINFO
)&ds
.dsBmih
,
2290 ) == (int)GDI_ERROR
)
2292 // On Win9x this API fails most (all?) of the time, so
2293 // logging it becomes quite distracting. Since it falls
2294 // back to the code below this is not really serious, so
2296 //wxLogLastError(wxT("StretchDIBits"));
2305 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2310 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2316 xdest
, ydest
, dstWidth
, dstHeight
,
2318 xsrc
, ysrc
, srcWidth
, srcHeight
,
2322 wxLogLastError(_T("StretchBlt"));
2332 if ( !::BitBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2333 hdcSrc
, xsrc
, ysrc
, dwRop
) )
2335 wxLogLastError(_T("BitBlt"));
2347 void wxMSWDCImpl::GetDeviceSize(int *width
, int *height
) const
2349 WXMICROWIN_CHECK_HDC
2352 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2354 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2357 void wxMSWDCImpl::DoGetSizeMM(int *w
, int *h
) const
2359 WXMICROWIN_CHECK_HDC
2361 // if we implement it in terms of DoGetSize() instead of directly using the
2362 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2363 // will also work for wxWindowDC and wxClientDC even though their size is
2364 // not the same as the total size of the screen
2365 int wPixels
, hPixels
;
2366 DoGetSize(&wPixels
, &hPixels
);
2370 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2372 wxCHECK_RET( wTotal
, _T("0 width device?") );
2374 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2379 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2381 wxCHECK_RET( hTotal
, _T("0 height device?") );
2383 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2387 wxSize
wxMSWDCImpl::GetPPI() const
2389 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2391 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2392 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2394 return wxSize(x
, y
);
2397 // For use by wxWidgets only, unless custom units are required.
2398 void wxMSWDCImpl::SetLogicalScale(double x
, double y
)
2400 WXMICROWIN_CHECK_HDC
2402 wxDCImpl::SetLogicalScale(x
,y
);
2405 // ----------------------------------------------------------------------------
2407 // ----------------------------------------------------------------------------
2409 #if wxUSE_DC_CACHEING
2412 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2413 * improve it in due course, either using arrays, or simply storing pointers to one
2414 * entry for the bitmap, and two for the DCs. -- JACS
2417 wxObjectList
wxMSWDCImpl::sm_bitmapCache
;
2418 wxObjectList
wxMSWDCImpl::sm_dcCache
;
2420 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2429 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2438 wxDCCacheEntry::~wxDCCacheEntry()
2441 ::DeleteObject((HBITMAP
) m_bitmap
);
2443 ::DeleteDC((HDC
) m_dc
);
2446 wxDCCacheEntry
* wxMSWDCImpl::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2448 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2449 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2452 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2454 if (entry
->m_depth
== depth
)
2456 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2458 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2459 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2460 if ( !entry
->m_bitmap
)
2462 wxLogLastError(wxT("CreateCompatibleBitmap"));
2464 entry
->m_width
= w
; entry
->m_height
= h
;
2470 node
= node
->GetNext();
2472 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2475 wxLogLastError(wxT("CreateCompatibleBitmap"));
2477 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2478 AddToBitmapCache(entry
);
2482 wxDCCacheEntry
* wxMSWDCImpl::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2484 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2485 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2488 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2490 // Don't return the same one as we already have
2491 if (!notThis
|| (notThis
!= entry
))
2493 if (entry
->m_depth
== depth
)
2499 node
= node
->GetNext();
2501 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2504 wxLogLastError(wxT("CreateCompatibleDC"));
2506 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2507 AddToDCCache(entry
);
2511 void wxMSWDCImpl::AddToBitmapCache(wxDCCacheEntry
* entry
)
2513 sm_bitmapCache
.Append(entry
);
2516 void wxMSWDCImpl::AddToDCCache(wxDCCacheEntry
* entry
)
2518 sm_dcCache
.Append(entry
);
2521 void wxMSWDCImpl::ClearCache()
2523 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2524 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2527 // Clean up cache at app exit
2528 class wxDCModule
: public wxModule
2531 virtual bool OnInit() { return true; }
2532 virtual void OnExit() { wxMSWDCImpl::ClearCache(); }
2535 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2538 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2540 #endif // wxUSE_DC_CACHEING
2542 // ----------------------------------------------------------------------------
2543 // alpha channel support
2544 // ----------------------------------------------------------------------------
2546 static bool AlphaBlt(HDC hdcDst
,
2547 int x
, int y
, int dstWidth
, int dstHeight
,
2549 int srcWidth
, int srcHeight
,
2551 const wxBitmap
& bmp
)
2553 wxASSERT_MSG( bmp
.IsOk() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2554 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2556 // do we have AlphaBlend() and company in the headers?
2557 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2558 // yes, now try to see if we have it during run-time
2559 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2560 HDC
,int,int,int,int,
2564 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2565 if ( pfnAlphaBlend
)
2568 bf
.BlendOp
= AC_SRC_OVER
;
2570 bf
.SourceConstantAlpha
= 0xff;
2571 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2573 if ( pfnAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
,
2574 hdcSrc
, srcX
, srcY
, srcWidth
, srcHeight
,
2577 // skip wxAlphaBlend() call below
2581 wxLogLastError(_T("AlphaBlend"));
2584 wxUnusedVar(hdcSrc
);
2585 #endif // defined(AC_SRC_OVER)
2587 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2589 #ifdef wxHAVE_RAW_BITMAP
2590 wxAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
, srcX
, srcY
, srcWidth
, srcHeight
, bmp
);
2593 #else // !wxHAVE_RAW_BITMAP
2594 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2595 // alpha but at least something will be shown like this)
2598 #endif // wxHAVE_RAW_BITMAP
2602 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2603 #ifdef wxHAVE_RAW_BITMAP
2606 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2607 int dstWidth
, int dstHeight
,
2609 int srcWidth
, int srcHeight
,
2610 const wxBitmap
& bmpSrc
)
2612 // get the destination DC pixels
2613 wxBitmap
bmpDst(dstWidth
, dstHeight
, 32 /* force creating RGBA DIB */);
2615 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2617 if ( !::BitBlt(hdcMem
, 0, 0, dstWidth
, dstHeight
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2619 wxLogLastError(_T("BitBlt"));
2622 // combine them with the source bitmap using alpha
2623 wxAlphaPixelData
dataDst(bmpDst
),
2624 dataSrc((wxBitmap
&)bmpSrc
);
2626 wxCHECK_RET( dataDst
&& dataSrc
,
2627 _T("failed to get raw data in wxAlphaBlend") );
2629 wxAlphaPixelData::Iterator
pDst(dataDst
),
2633 for ( int y
= 0; y
< dstHeight
; y
++ )
2635 wxAlphaPixelData::Iterator pDstRowStart
= pDst
;
2637 for ( int x
= 0; x
< dstWidth
; x
++ )
2639 // source is point sampled, Alpha StretchBlit is ugly on Win95
2640 // (but does not impact performance)
2641 pSrc
.MoveTo(dataSrc
, srcX
+ (srcWidth
*x
/dstWidth
), srcY
+ (srcHeight
*y
/dstHeight
));
2643 // note that source bitmap uses premultiplied alpha (as required by
2644 // the real AlphaBlend)
2645 const unsigned beta
= 255 - pSrc
.Alpha();
2647 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2648 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2649 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2654 pDst
= pDstRowStart
;
2655 pDst
.OffsetY(dataDst
, 1);
2658 // and finally blit them back to the destination DC
2659 if ( !::BitBlt(hdcDst
, xDst
, yDst
, dstWidth
, dstHeight
, hdcMem
, 0, 0, SRCCOPY
) )
2661 wxLogLastError(_T("BitBlt"));
2665 #endif // #ifdef wxHAVE_RAW_BITMAP
2667 void wxMSWDCImpl::DoGradientFillLinear (const wxRect
& rect
,
2668 const wxColour
& initialColour
,
2669 const wxColour
& destColour
,
2670 wxDirection nDirection
)
2672 // use native function if we have compile-time support it and can load it
2673 // during run-time (linking to it statically would make the program
2674 // unusable on earlier Windows versions)
2675 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2677 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2678 static GradientFill_t pfnGradientFill
=
2679 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2681 if ( pfnGradientFill
)
2683 GRADIENT_RECT grect
;
2684 grect
.UpperLeft
= 0;
2685 grect
.LowerRight
= 1;
2687 // invert colours direction if not filling from left-to-right or
2689 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2691 // one vertex for upper left and one for upper-right
2692 TRIVERTEX vertices
[2];
2694 vertices
[0].x
= rect
.GetLeft();
2695 vertices
[0].y
= rect
.GetTop();
2696 vertices
[1].x
= rect
.GetRight()+1;
2697 vertices
[1].y
= rect
.GetBottom()+1;
2699 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2700 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2701 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2702 vertices
[firstVertex
].Alpha
= 0;
2703 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2704 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2705 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2706 vertices
[1 - firstVertex
].Alpha
= 0;
2708 if ( (*pfnGradientFill
)
2715 nDirection
== wxWEST
|| nDirection
== wxEAST
2716 ? GRADIENT_FILL_RECT_H
2717 : GRADIENT_FILL_RECT_V
2720 // skip call of the base class version below
2724 wxLogLastError(_T("GradientFill"));
2726 #endif // wxUSE_DYNLIB_CLASS
2728 wxDCImpl::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2731 #if wxUSE_DYNLIB_CLASS
2733 static DWORD
wxGetDCLayout(HDC hdc
)
2735 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2737 wxDL_INIT_FUNC(s_pfn
, GetLayout
, wxDynamicLibrary(_T("gdi32.dll")));
2739 return s_pfnGetLayout
? s_pfnGetLayout(hdc
) : (DWORD
)-1;
2742 wxLayoutDirection
wxMSWDCImpl::GetLayoutDirection() const
2744 DWORD layout
= wxGetDCLayout(GetHdc());
2746 if ( layout
== (DWORD
)-1 )
2747 return wxLayout_Default
;
2749 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2752 void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir
)
2754 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2756 wxDL_INIT_FUNC(s_pfn
, SetLayout
, wxDynamicLibrary(_T("gdi32.dll")));
2757 if ( !s_pfnSetLayout
)
2760 if ( dir
== wxLayout_Default
)
2762 dir
= wxTheApp
->GetLayoutDirection();
2763 if ( dir
== wxLayout_Default
)
2767 DWORD layout
= wxGetDCLayout(GetHdc());
2768 if ( dir
== wxLayout_RightToLeft
)
2769 layout
|= LAYOUT_RTL
;
2771 layout
&= ~LAYOUT_RTL
;
2773 s_pfnSetLayout(GetHdc(), layout
);
2776 #else // !wxUSE_DYNLIB_CLASS
2778 // we can't provide RTL support without dynamic loading, so stub it out
2779 wxLayoutDirection
wxMSWDCImpl::GetLayoutDirection() const
2781 return wxLayout_Default
;
2784 void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection
WXUNUSED(dir
))
2788 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS