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 wxHAS_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 wxHAS_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 // wxHAS_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 // ----------------------------------------------------------------------------
403 // wxDC MSW-specific methods
404 // ----------------------------------------------------------------------------
406 WXHDC
wxDC::GetHDC() const
408 wxMSWDCImpl
* const impl
= wxDynamicCast(GetImpl(), wxMSWDCImpl
);
409 return impl
? impl
->GetHDC() : 0;
412 // ---------------------------------------------------------------------------
414 // ---------------------------------------------------------------------------
416 wxMSWDCImpl::wxMSWDCImpl( wxDC
*owner
, WXHDC hDC
) :
423 wxMSWDCImpl::~wxMSWDCImpl()
427 SelectOldObjects(m_hDC
);
429 // if we own the HDC, we delete it, otherwise we just release it
433 ::DeleteDC(GetHdc());
435 else // we don't own our HDC
439 ::ReleaseDC(GetHwndOf(m_window
), GetHdc());
443 // Must have been a wxScreenDC
444 ::ReleaseDC((HWND
) NULL
, GetHdc());
450 // This will select current objects out of the DC,
451 // which is what you have to do before deleting the
453 void wxMSWDCImpl::SelectOldObjects(WXHDC dc
)
459 ::SelectObject((HDC
) dc
, (HBITMAP
) m_oldBitmap
);
461 if (m_selectedBitmap
.IsOk())
463 m_selectedBitmap
.SetSelectedInto(NULL
);
470 ::SelectObject((HDC
) dc
, (HPEN
) m_oldPen
);
475 ::SelectObject((HDC
) dc
, (HBRUSH
) m_oldBrush
);
480 ::SelectObject((HDC
) dc
, (HFONT
) m_oldFont
);
487 ::SelectPalette((HDC
) dc
, (HPALETTE
) m_oldPalette
, FALSE
);
490 #endif // wxUSE_PALETTE
493 m_brush
= wxNullBrush
;
496 m_palette
= wxNullPalette
;
497 #endif // wxUSE_PALETTE
499 m_backgroundBrush
= wxNullBrush
;
500 m_selectedBitmap
= wxNullBitmap
;
503 // ---------------------------------------------------------------------------
505 // ---------------------------------------------------------------------------
507 void wxMSWDCImpl::UpdateClipBox()
512 ::GetClipBox(GetHdc(), &rect
);
514 m_clipX1
= (wxCoord
) XDEV2LOG(rect
.left
);
515 m_clipY1
= (wxCoord
) YDEV2LOG(rect
.top
);
516 m_clipX2
= (wxCoord
) XDEV2LOG(rect
.right
);
517 m_clipY2
= (wxCoord
) YDEV2LOG(rect
.bottom
);
521 wxMSWDCImpl::DoGetClippingBox(wxCoord
*x
, wxCoord
*y
, wxCoord
*w
, wxCoord
*h
) const
523 // check if we should try to retrieve the clipping region possibly not set
524 // by our SetClippingRegion() but preset by Windows:this can only happen
525 // when we're associated with an existing HDC usign SetHDC(), see there
526 if ( m_clipping
&& !m_clipX1
&& !m_clipX2
)
528 wxMSWDCImpl
*self
= wxConstCast(this, wxMSWDCImpl
);
529 self
->UpdateClipBox();
531 if ( !m_clipX1
&& !m_clipX2
)
532 self
->m_clipping
= false;
535 wxDCImpl::DoGetClippingBox(x
, y
, w
, h
);
538 // common part of DoSetClippingRegion() and DoSetDeviceClippingRegion()
539 void wxMSWDCImpl::SetClippingHrgn(WXHRGN hrgn
)
541 wxCHECK_RET( hrgn
, wxT("invalid clipping region") );
545 // note that we combine the new clipping region with the existing one: this
546 // is compatible with what the other ports do and is the documented
547 // behaviour now (starting with 2.3.3)
548 #if defined(__WXWINCE__)
550 if ( !::GetClipBox(GetHdc(), &rectClip
) )
553 // GetClipBox returns logical coordinates, so transform to device
554 rectClip
.left
= LogicalToDeviceX(rectClip
.left
);
555 rectClip
.top
= LogicalToDeviceY(rectClip
.top
);
556 rectClip
.right
= LogicalToDeviceX(rectClip
.right
);
557 rectClip
.bottom
= LogicalToDeviceY(rectClip
.bottom
);
559 HRGN hrgnDest
= ::CreateRectRgn(0, 0, 0, 0);
560 HRGN hrgnClipOld
= ::CreateRectRgn(rectClip
.left
, rectClip
.top
,
561 rectClip
.right
, rectClip
.bottom
);
563 if ( ::CombineRgn(hrgnDest
, hrgnClipOld
, (HRGN
)hrgn
, RGN_AND
) != ERROR
)
565 ::SelectClipRgn(GetHdc(), hrgnDest
);
568 ::DeleteObject(hrgnClipOld
);
569 ::DeleteObject(hrgnDest
);
571 if ( ::ExtSelectClipRgn(GetHdc(), (HRGN
)hrgn
, RGN_AND
) == ERROR
)
573 wxLogLastError(_T("ExtSelectClipRgn"));
577 #endif // WinCE/!WinCE
584 void wxMSWDCImpl::DoSetClippingRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
586 // the region coords are always the device ones, so do the translation
589 // FIXME: possible +/-1 error here, to check!
590 HRGN hrgn
= ::CreateRectRgn(LogicalToDeviceX(x
),
592 LogicalToDeviceX(x
+ w
),
593 LogicalToDeviceY(y
+ h
));
596 wxLogLastError(_T("CreateRectRgn"));
600 SetClippingHrgn((WXHRGN
)hrgn
);
602 ::DeleteObject(hrgn
);
606 void wxMSWDCImpl::DoSetDeviceClippingRegion(const wxRegion
& region
)
608 SetClippingHrgn(region
.GetHRGN());
611 void wxMSWDCImpl::DestroyClippingRegion()
615 if (m_clipping
&& m_hDC
)
618 // On a PocketPC device (not necessarily emulator), resetting
619 // the clip region as per the old method causes bad display
620 // problems. In fact setting a null region is probably OK
621 // on desktop WIN32 also, since the WIN32 docs imply that the user
622 // clipping region is independent from the paint clipping region.
623 ::SelectClipRgn(GetHdc(), 0);
625 // TODO: this should restore the previous clipping region,
626 // so that OnPaint processing works correctly, and the update
627 // clipping region doesn't get destroyed after the first
628 // DestroyClippingRegion.
629 HRGN rgn
= CreateRectRgn(0, 0, 32000, 32000);
630 ::SelectClipRgn(GetHdc(), rgn
);
635 wxDCImpl::DestroyClippingRegion();
638 // ---------------------------------------------------------------------------
639 // query capabilities
640 // ---------------------------------------------------------------------------
642 bool wxMSWDCImpl::CanDrawBitmap() const
647 bool wxMSWDCImpl::CanGetTextExtent() const
649 #ifdef __WXMICROWIN__
650 // TODO Extend MicroWindows' GetDeviceCaps function
653 // What sort of display is it?
654 int technology
= ::GetDeviceCaps(GetHdc(), TECHNOLOGY
);
656 return (technology
== DT_RASDISPLAY
) || (technology
== DT_RASPRINTER
);
660 int wxMSWDCImpl::GetDepth() const
662 WXMICROWIN_CHECK_HDC_RET(16)
664 return (int)::GetDeviceCaps(GetHdc(), BITSPIXEL
);
667 // ---------------------------------------------------------------------------
669 // ---------------------------------------------------------------------------
671 void wxMSWDCImpl::Clear()
678 GetClientRect((HWND
) m_window
->GetHWND(), &rect
);
682 // No, I think we should simply ignore this if printing on e.g.
684 // wxCHECK_RET( m_selectedBitmap.IsOk(), wxT("this DC can't be cleared") );
685 if (!m_selectedBitmap
.IsOk())
688 rect
.left
= -m_deviceOriginX
; rect
.top
= -m_deviceOriginY
;
689 rect
.right
= m_selectedBitmap
.GetWidth()-m_deviceOriginX
;
690 rect
.bottom
= m_selectedBitmap
.GetHeight()-m_deviceOriginY
;
694 (void) ::SetMapMode(GetHdc(), MM_TEXT
);
697 DWORD colour
= ::GetBkColor(GetHdc());
698 HBRUSH brush
= ::CreateSolidBrush(colour
);
699 ::FillRect(GetHdc(), &rect
, brush
);
700 ::DeleteObject(brush
);
702 RealizeScaleAndOrigin();
705 bool wxMSWDCImpl::DoFloodFill(wxCoord
WXUNUSED_IN_WINCE(x
),
706 wxCoord
WXUNUSED_IN_WINCE(y
),
707 const wxColour
& WXUNUSED_IN_WINCE(col
),
708 wxFloodFillStyle
WXUNUSED_IN_WINCE(style
))
713 WXMICROWIN_CHECK_HDC_RET(false)
715 bool success
= (0 != ::ExtFloodFill(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
),
717 style
== wxFLOOD_SURFACE
? FLOODFILLSURFACE
718 : FLOODFILLBORDER
) ) ;
721 // quoting from the MSDN docs:
723 // Following are some of the reasons this function might fail:
725 // * The filling could not be completed.
726 // * The specified point has the boundary color specified by the
727 // crColor parameter (if FLOODFILLBORDER was requested).
728 // * The specified point does not have the color specified by
729 // crColor (if FLOODFILLSURFACE was requested)
730 // * The point is outside the clipping region that is, it is not
731 // visible on the device.
733 wxLogLastError(wxT("ExtFloodFill"));
736 CalcBoundingBox(x
, y
);
742 bool wxMSWDCImpl::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
744 WXMICROWIN_CHECK_HDC_RET(false)
746 wxCHECK_MSG( col
, false, _T("NULL colour parameter in wxMSWDCImpl::GetPixel") );
748 // get the color of the pixel
749 COLORREF pixelcolor
= ::GetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
));
751 wxRGBToColour(*col
, pixelcolor
);
756 void wxMSWDCImpl::DoCrossHair(wxCoord x
, wxCoord y
)
760 wxCoord x1
= x
-VIEWPORT_EXTENT
;
761 wxCoord y1
= y
-VIEWPORT_EXTENT
;
762 wxCoord x2
= x
+VIEWPORT_EXTENT
;
763 wxCoord y2
= y
+VIEWPORT_EXTENT
;
765 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y
));
766 wxDrawLine(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y1
), XLOG2DEV(x
), YLOG2DEV(y2
));
768 CalcBoundingBox(x1
, y1
);
769 CalcBoundingBox(x2
, y2
);
772 void wxMSWDCImpl::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
776 wxDrawLine(GetHdc(), XLOG2DEV(x1
), YLOG2DEV(y1
), XLOG2DEV(x2
), YLOG2DEV(y2
));
778 CalcBoundingBox(x1
, y1
);
779 CalcBoundingBox(x2
, y2
);
782 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
783 // and ending at (x2, y2)
784 void wxMSWDCImpl::DoDrawArc(wxCoord x1
, wxCoord y1
,
785 wxCoord x2
, wxCoord y2
,
786 wxCoord xc
, wxCoord yc
)
789 // Slower emulation since WinCE doesn't support Pie and Arc
790 double r
= sqrt( (x1
-xc
)*(x1
-xc
) + (y1
-yc
)*(y1
-yc
) );
791 double sa
= acos((x1
-xc
)/r
)/M_PI
*180; // between 0 and 180
792 if( y1
>yc
) sa
= -sa
; // below center
793 double ea
= atan2(yc
-y2
, x2
-xc
)/M_PI
*180;
794 DoDrawEllipticArcRot( xc
-r
, yc
-r
, 2*r
, 2*r
, sa
, ea
);
799 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
803 double radius
= (double)sqrt(dx
*dx
+dy
*dy
);
804 wxCoord r
= (wxCoord
)radius
;
806 // treat the special case of full circle separately
807 if ( x1
== x2
&& y1
== y2
)
809 GetOwner()->DrawEllipse(xc
- r
, yc
- r
, 2*r
, 2*r
);
813 wxCoord xx1
= XLOG2DEV(x1
);
814 wxCoord yy1
= YLOG2DEV(y1
);
815 wxCoord xx2
= XLOG2DEV(x2
);
816 wxCoord yy2
= YLOG2DEV(y2
);
817 wxCoord xxc
= XLOG2DEV(xc
);
818 wxCoord yyc
= YLOG2DEV(yc
);
819 wxCoord ray
= (wxCoord
) sqrt(double((xxc
-xx1
)*(xxc
-xx1
)+(yyc
-yy1
)*(yyc
-yy1
)));
821 wxCoord xxx1
= (wxCoord
) (xxc
-ray
);
822 wxCoord yyy1
= (wxCoord
) (yyc
-ray
);
823 wxCoord xxx2
= (wxCoord
) (xxc
+ray
);
824 wxCoord yyy2
= (wxCoord
) (yyc
+ray
);
826 if ( m_brush
.IsOk() && m_brush
.GetStyle() != wxBRUSHSTYLE_TRANSPARENT
)
828 // Have to add 1 to bottom-right corner of rectangle
829 // to make semi-circles look right (crooked line otherwise).
830 // Unfortunately this is not a reliable method, depends
831 // on the size of shape.
832 // TODO: figure out why this happens!
833 Pie(GetHdc(),xxx1
,yyy1
,xxx2
+1,yyy2
+1, xx1
,yy1
,xx2
,yy2
);
837 Arc(GetHdc(),xxx1
,yyy1
,xxx2
,yyy2
, xx1
,yy1
,xx2
,yy2
);
840 CalcBoundingBox(xc
- r
, yc
- r
);
841 CalcBoundingBox(xc
+ r
, yc
+ r
);
845 void wxMSWDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
,
846 wxCoord width
, wxCoord height
)
848 // cases when we don't have DrawFrameControl()
849 #if defined(__SYMANTEC__) || defined(__WXMICROWIN__)
850 return wxDCBase::DoDrawCheckMark(x1
, y1
, width
, height
);
852 wxCoord x2
= x1
+ width
,
862 DrawFrameControl(GetHdc(), &rect
, DFC_BUTTON
, DFCS_BUTTONCHECK
| DFCS_CHECKED
);
864 DrawFrameControl(GetHdc(), &rect
, DFC_MENU
, DFCS_MENUCHECK
);
867 CalcBoundingBox(x1
, y1
);
868 CalcBoundingBox(x2
, y2
);
869 #endif // Microwin/Normal
872 void wxMSWDCImpl::DoDrawPoint(wxCoord x
, wxCoord y
)
876 COLORREF color
= 0x00ffffff;
879 color
= m_pen
.GetColour().GetPixel();
882 SetPixel(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), color
);
884 CalcBoundingBox(x
, y
);
887 void wxMSWDCImpl::DoDrawPolygon(int n
,
891 wxPolygonFillMode
WXUNUSED_IN_WINCE(fillStyle
))
895 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
897 // Do things less efficiently if we have offsets
898 if (xoffset
!= 0 || yoffset
!= 0)
900 POINT
*cpoints
= new POINT
[n
];
902 for (i
= 0; i
< n
; i
++)
904 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
905 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
907 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
910 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
912 (void)Polygon(GetHdc(), cpoints
, n
);
914 SetPolyFillMode(GetHdc(),prev
);
921 for (i
= 0; i
< n
; i
++)
922 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
925 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
927 (void)Polygon(GetHdc(), (POINT
*) points
, n
);
929 SetPolyFillMode(GetHdc(),prev
);
935 wxMSWDCImpl::DoDrawPolyPolygon(int n
,
940 wxPolygonFillMode fillStyle
)
943 wxDCImpl::DoDrawPolyPolygon(n
, count
, points
, xoffset
, yoffset
, fillStyle
);
947 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
949 for (i
= cnt
= 0; i
< n
; i
++)
952 // Do things less efficiently if we have offsets
953 if (xoffset
!= 0 || yoffset
!= 0)
955 POINT
*cpoints
= new POINT
[cnt
];
956 for (i
= 0; i
< cnt
; i
++)
958 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
959 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
961 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
964 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
966 (void)PolyPolygon(GetHdc(), cpoints
, count
, n
);
968 SetPolyFillMode(GetHdc(),prev
);
974 for (i
= 0; i
< cnt
; i
++)
975 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
978 int prev
= SetPolyFillMode(GetHdc(),fillStyle
==wxODDEVEN_RULE
?ALTERNATE
:WINDING
);
980 (void)PolyPolygon(GetHdc(), (POINT
*) points
, count
, n
);
982 SetPolyFillMode(GetHdc(),prev
);
989 void wxMSWDCImpl::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
993 // Do things less efficiently if we have offsets
994 if (xoffset
!= 0 || yoffset
!= 0)
996 POINT
*cpoints
= new POINT
[n
];
998 for (i
= 0; i
< n
; i
++)
1000 cpoints
[i
].x
= (int)(points
[i
].x
+ xoffset
);
1001 cpoints
[i
].y
= (int)(points
[i
].y
+ yoffset
);
1003 CalcBoundingBox(cpoints
[i
].x
, cpoints
[i
].y
);
1005 (void)Polyline(GetHdc(), cpoints
, n
);
1011 for (i
= 0; i
< n
; i
++)
1012 CalcBoundingBox(points
[i
].x
, points
[i
].y
);
1014 (void)Polyline(GetHdc(), (POINT
*) points
, n
);
1018 void wxMSWDCImpl::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1020 WXMICROWIN_CHECK_HDC
1022 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1024 wxCoord x2
= x
+ width
;
1025 wxCoord y2
= y
+ height
;
1027 wxCoord x2dev
= XLOG2DEV(x2
),
1028 y2dev
= YLOG2DEV(y2
);
1030 // Windows (but not Windows CE) draws the filled rectangles without outline
1031 // (i.e. drawn with a transparent pen) one pixel smaller in both directions
1032 // and we want them to have the same size regardless of which pen is used
1034 if ( m_pen
.IsOk() && m_pen
.GetStyle() == wxPENSTYLE_TRANSPARENT
)
1039 #endif // !__WXWINCE__
1041 (void)Rectangle(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), x2dev
, y2dev
);
1043 CalcBoundingBox(x
, y
);
1044 CalcBoundingBox(x2
, y2
);
1047 void wxMSWDCImpl::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
1049 WXMICROWIN_CHECK_HDC
1051 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1053 // Now, a negative radius value is interpreted to mean
1054 // 'the proportion of the smallest X or Y dimension'
1058 double smallest
= (width
< height
) ? width
: height
;
1059 radius
= (- radius
* smallest
);
1062 wxCoord x2
= (x
+width
);
1063 wxCoord y2
= (y
+height
);
1065 // Windows draws the filled rectangles without outline (i.e. drawn with a
1066 // transparent pen) one pixel smaller in both directions and we want them
1067 // to have the same size regardless of which pen is used - adjust
1068 if ( m_pen
.GetStyle() == wxPENSTYLE_TRANSPARENT
)
1074 (void)RoundRect(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
),
1075 YLOG2DEV(y2
), (int) (2*XLOG2DEV(radius
)), (int)( 2*YLOG2DEV(radius
)));
1077 CalcBoundingBox(x
, y
);
1078 CalcBoundingBox(x2
, y2
);
1081 void wxMSWDCImpl::DoDrawEllipse(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
1083 WXMICROWIN_CHECK_HDC
1085 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1087 // +1 below makes the ellipse more similar to other platforms.
1088 // In particular, DoDrawEllipse(x,y,1,1) should draw one point.
1089 wxCoord x2
= x
+ width
+ 1;
1090 wxCoord y2
= y
+ height
+ 1;
1092 // Problem: Windows GDI Ellipse() with x2-x == y2-y == 3 and transparent
1093 // pen doesn't draw anything. Should we provide a workaround?
1095 ::Ellipse(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
));
1097 CalcBoundingBox(x
, y
);
1098 CalcBoundingBox(x2
, y2
);
1101 #if wxUSE_SPLINES && !defined(__WXWINCE__)
1102 void wxMSWDCImpl::DoDrawSpline(const wxPointList
*points
)
1104 // quadratic b-spline to cubic bezier spline conversion
1106 // quadratic spline with control points P0,P1,P2
1107 // P(s) = P0*(1-s)^2 + P1*2*(1-s)*s + P2*s^2
1109 // bezier spline with control points B0,B1,B2,B3
1110 // B(s) = B0*(1-s)^3 + B1*3*(1-s)^2*s + B2*3*(1-s)*s^2 + B3*s^3
1112 // control points of bezier spline calculated from b-spline
1114 // B1 = (2*P1 + P0)/3
1115 // B2 = (2*P1 + P2)/3
1118 WXMICROWIN_CHECK_HDC
1120 wxASSERT_MSG( points
, wxT("NULL pointer to spline points?") );
1122 const size_t n_points
= points
->GetCount();
1123 wxASSERT_MSG( n_points
> 2 , wxT("incomplete list of spline points?") );
1125 const size_t n_bezier_points
= n_points
* 3 + 1;
1126 POINT
*lppt
= (POINT
*)malloc(n_bezier_points
*sizeof(POINT
));
1127 size_t bezier_pos
= 0;
1128 wxCoord x1
, y1
, x2
, y2
, cx1
, cy1
, cx4
, cy4
;
1130 wxPointList::compatibility_iterator node
= points
->GetFirst();
1131 wxPoint
*p
= node
->GetData();
1132 lppt
[ bezier_pos
].x
= x1
= p
->x
;
1133 lppt
[ bezier_pos
].y
= y1
= p
->y
;
1135 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1138 node
= node
->GetNext();
1139 p
= node
->GetData();
1143 cx1
= ( x1
+ x2
) / 2;
1144 cy1
= ( y1
+ y2
) / 2;
1145 lppt
[ bezier_pos
].x
= XLOG2DEV(cx1
);
1146 lppt
[ bezier_pos
].y
= YLOG2DEV(cy1
);
1148 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1152 while ((node
= node
->GetNext()) != NULL
)
1154 while ((node
= node
->GetNext()))
1155 #endif // !wxUSE_STL
1157 p
= (wxPoint
*)node
->GetData();
1162 cx4
= (x1
+ x2
) / 2;
1163 cy4
= (y1
+ y2
) / 2;
1164 // B0 is B3 of previous segment
1166 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx1
)/3);
1167 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy1
)/3);
1170 lppt
[ bezier_pos
].x
= XLOG2DEV((x1
*2+cx4
)/3);
1171 lppt
[ bezier_pos
].y
= YLOG2DEV((y1
*2+cy4
)/3);
1174 lppt
[ bezier_pos
].x
= XLOG2DEV(cx4
);
1175 lppt
[ bezier_pos
].y
= YLOG2DEV(cy4
);
1181 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1183 lppt
[ bezier_pos
].x
= XLOG2DEV(x2
);
1184 lppt
[ bezier_pos
].y
= YLOG2DEV(y2
);
1186 lppt
[ bezier_pos
] = lppt
[ bezier_pos
-1 ];
1189 ::PolyBezier( GetHdc(), lppt
, bezier_pos
);
1193 #endif // wxUSE_SPLINES
1195 // Chris Breeze 20/5/98: first implementation of DrawEllipticArc on Windows
1196 void wxMSWDCImpl::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
1199 DoDrawEllipticArcRot( x
, y
, w
, h
, sa
, ea
);
1202 WXMICROWIN_CHECK_HDC
1204 wxBrushAttrsSetter
cc(*this); // needed for wxSTIPPLE_MASK_OPAQUE handling
1209 int rx1
= XLOG2DEV(x
+w
/2);
1210 int ry1
= YLOG2DEV(y
+h
/2);
1217 rx1
+= (int)(100.0 * abs(w
) * cos(sa
));
1218 ry1
-= (int)(100.0 * abs(h
) * m_signY
* sin(sa
));
1219 rx2
+= (int)(100.0 * abs(w
) * cos(ea
));
1220 ry2
-= (int)(100.0 * abs(h
) * m_signY
* sin(ea
));
1222 // Swap start and end positions if the end angle is less than the start angle.
1233 // draw pie with NULL_PEN first and then outline otherwise a line is
1234 // drawn from the start and end points to the centre
1235 HPEN hpenOld
= (HPEN
) ::SelectObject(GetHdc(), (HPEN
) ::GetStockObject(NULL_PEN
));
1238 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
)+1, YLOG2DEV(y2
)+1,
1239 rx1
, ry1
, rx2
, ry2
);
1243 (void)Pie(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
)-1, XLOG2DEV(x2
)+1, YLOG2DEV(y2
),
1244 rx1
, ry1
-1, rx2
, ry2
-1);
1247 ::SelectObject(GetHdc(), hpenOld
);
1249 (void)Arc(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), XLOG2DEV(x2
), YLOG2DEV(y2
),
1250 rx1
, ry1
, rx2
, ry2
);
1252 CalcBoundingBox(x
, y
);
1253 CalcBoundingBox(x2
, y2
);
1257 void wxMSWDCImpl::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
1259 WXMICROWIN_CHECK_HDC
1261 wxCHECK_RET( icon
.IsOk(), wxT("invalid icon in DrawIcon") );
1264 ::DrawIconEx(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
), icon
.GetWidth(), icon
.GetHeight(), 0, NULL
, DI_NORMAL
);
1266 ::DrawIcon(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), GetHiconOf(icon
));
1269 CalcBoundingBox(x
, y
);
1270 CalcBoundingBox(x
+ icon
.GetWidth(), y
+ icon
.GetHeight());
1273 void wxMSWDCImpl::DoDrawBitmap( const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
1275 WXMICROWIN_CHECK_HDC
1277 wxCHECK_RET( bmp
.IsOk(), _T("invalid bitmap in wxMSWDCImpl::DrawBitmap") );
1279 int width
= bmp
.GetWidth(),
1280 height
= bmp
.GetHeight();
1282 HBITMAP hbmpMask
= 0;
1285 HPALETTE oldPal
= 0;
1286 #endif // wxUSE_PALETTE
1288 if ( bmp
.HasAlpha() )
1291 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmp
));
1293 if ( AlphaBlt(GetHdc(), x
, y
, width
, height
, 0, 0, width
, height
, hdcMem
, bmp
) )
1299 wxMask
*mask
= bmp
.GetMask();
1301 hbmpMask
= (HBITMAP
)mask
->GetMaskBitmap();
1305 // don't give assert here because this would break existing
1306 // programs - just silently ignore useMask parameter
1313 // use MaskBlt() with ROP which doesn't do anything to dst in the mask
1315 // On some systems, MaskBlt succeeds yet is much much slower
1316 // than the wxWidgets fall-back implementation. So we need
1317 // to be able to switch this on and off at runtime.
1319 #if wxUSE_SYSTEM_OPTIONS
1320 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
1324 HDC hdcMem
= ::CreateCompatibleDC(GetHdc());
1325 HGDIOBJ hOldBitmap
= ::SelectObject(hdcMem
, GetHbitmapOf(bmp
));
1327 wxPalette
*pal
= bmp
.GetPalette();
1328 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1330 oldPal
= ::SelectPalette(hdcMem
, GetHpaletteOf(*pal
), FALSE
);
1331 ::RealizePalette(hdcMem
);
1333 #endif // wxUSE_PALETTE
1335 ok
= ::MaskBlt(cdc
, x
, y
, width
, height
,
1338 MAKEROP4(SRCCOPY
, DSTCOPY
)) != 0;
1342 ::SelectPalette(hdcMem
, oldPal
, FALSE
);
1343 #endif // wxUSE_PALETTE
1345 ::SelectObject(hdcMem
, hOldBitmap
);
1352 // Rather than reproduce wxMSWDCImpl::Blit, let's do it at the wxWin API
1356 memDC
.SelectObjectAsSource(bmp
);
1358 GetOwner()->Blit(x
, y
, width
, height
, &memDC
, 0, 0, wxCOPY
, useMask
);
1360 memDC
.SelectObject(wxNullBitmap
);
1363 else // no mask, just use BitBlt()
1366 HDC memdc
= ::CreateCompatibleDC( cdc
);
1367 HBITMAP hbitmap
= (HBITMAP
) bmp
.GetHBITMAP( );
1369 wxASSERT_MSG( hbitmap
, wxT("bitmap is ok but HBITMAP is NULL?") );
1371 wxTextColoursChanger
textCol(GetHdc(), *this);
1374 wxPalette
*pal
= bmp
.GetPalette();
1375 if ( pal
&& ::GetDeviceCaps(cdc
,BITSPIXEL
) <= 8 )
1377 oldPal
= ::SelectPalette(memdc
, GetHpaletteOf(*pal
), FALSE
);
1378 ::RealizePalette(memdc
);
1380 #endif // wxUSE_PALETTE
1382 HGDIOBJ hOldBitmap
= ::SelectObject( memdc
, hbitmap
);
1383 ::BitBlt( cdc
, x
, y
, width
, height
, memdc
, 0, 0, SRCCOPY
);
1387 ::SelectPalette(memdc
, oldPal
, FALSE
);
1388 #endif // wxUSE_PALETTE
1390 ::SelectObject( memdc
, hOldBitmap
);
1391 ::DeleteDC( memdc
);
1395 void wxMSWDCImpl::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
1397 WXMICROWIN_CHECK_HDC
1399 DrawAnyText(text
, x
, y
);
1401 // update the bounding box
1402 CalcBoundingBox(x
, y
);
1405 GetOwner()->GetTextExtent(text
, &w
, &h
);
1406 CalcBoundingBox(x
+ w
, y
+ h
);
1409 void wxMSWDCImpl::DrawAnyText(const wxString
& text
, wxCoord x
, wxCoord y
)
1411 WXMICROWIN_CHECK_HDC
1413 // prepare for drawing the text
1414 wxTextColoursChanger
textCol(GetHdc(), *this);
1416 wxBkModeChanger
bkMode(GetHdc(), m_backgroundMode
);
1418 if ( ::ExtTextOut(GetHdc(), XLOG2DEV(x
), YLOG2DEV(y
), 0, NULL
,
1419 text
.c_str(), text
.length(), NULL
) == 0 )
1421 wxLogLastError(wxT("TextOut"));
1425 void wxMSWDCImpl::DoDrawRotatedText(const wxString
& text
,
1426 wxCoord x
, wxCoord y
,
1429 WXMICROWIN_CHECK_HDC
1431 // we test that we have some font because otherwise we should still use the
1432 // "else" part below to avoid that DrawRotatedText(angle = 180) and
1433 // DrawRotatedText(angle = 0) use different fonts (we can't use the default
1434 // font for drawing rotated fonts unfortunately)
1435 if ( (angle
== 0.0) && m_font
.IsOk() )
1437 DoDrawText(text
, x
, y
);
1439 #ifndef __WXMICROWIN__
1442 // NB: don't take DEFAULT_GUI_FONT (a.k.a. wxSYS_DEFAULT_GUI_FONT)
1443 // because it's not TrueType and so can't have non zero
1444 // orientation/escapement under Win9x
1445 wxFont font
= m_font
.IsOk() ? m_font
: *wxSWISS_FONT
;
1446 HFONT hfont
= (HFONT
)font
.GetResourceHandle();
1448 if ( ::GetObject(hfont
, sizeof(lf
), &lf
) == 0 )
1450 wxLogLastError(wxT("GetObject(hfont)"));
1453 // GDI wants the angle in tenth of degree
1454 long angle10
= (long)(angle
* 10);
1455 lf
.lfEscapement
= angle10
;
1456 lf
. lfOrientation
= angle10
;
1458 hfont
= ::CreateFontIndirect(&lf
);
1461 wxLogLastError(wxT("CreateFont"));
1465 HFONT hfontOld
= (HFONT
)::SelectObject(GetHdc(), hfont
);
1467 DrawAnyText(text
, x
, y
);
1469 (void)::SelectObject(GetHdc(), hfontOld
);
1470 (void)::DeleteObject(hfont
);
1473 // call the bounding box by adding all four vertices of the rectangle
1474 // containing the text to it (simpler and probably not slower than
1475 // determining which of them is really topmost/leftmost/...)
1477 GetOwner()->GetTextExtent(text
, &w
, &h
);
1479 double rad
= DegToRad(angle
);
1481 // "upper left" and "upper right"
1482 CalcBoundingBox(x
, y
);
1483 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1485 // "bottom left" and "bottom right"
1486 x
+= (wxCoord
)(h
*sin(rad
));
1487 y
+= (wxCoord
)(h
*cos(rad
));
1488 CalcBoundingBox(x
, y
);
1489 CalcBoundingBox(x
+ wxCoord(w
*cos(rad
)), y
- wxCoord(w
*sin(rad
)));
1494 // ---------------------------------------------------------------------------
1496 // ---------------------------------------------------------------------------
1500 void wxMSWDCImpl::DoSelectPalette(bool realize
)
1502 WXMICROWIN_CHECK_HDC
1504 // Set the old object temporarily, in case the assignment deletes an object
1505 // that's not yet selected out.
1508 ::SelectPalette(GetHdc(), (HPALETTE
) m_oldPalette
, FALSE
);
1512 if ( m_palette
.IsOk() )
1514 HPALETTE oldPal
= ::SelectPalette(GetHdc(),
1515 GetHpaletteOf(m_palette
),
1518 m_oldPalette
= (WXHPALETTE
) oldPal
;
1521 ::RealizePalette(GetHdc());
1525 void wxMSWDCImpl::SetPalette(const wxPalette
& palette
)
1527 if ( palette
.IsOk() )
1529 m_palette
= palette
;
1530 DoSelectPalette(true);
1534 void wxMSWDCImpl::InitializePalette()
1536 if ( wxDisplayDepth() <= 8 )
1538 // look for any window or parent that has a custom palette. If any has
1539 // one then we need to use it in drawing operations
1540 wxWindow
*win
= m_window
->GetAncestorWithCustomPalette();
1542 m_hasCustomPalette
= win
&& win
->HasCustomPalette();
1543 if ( m_hasCustomPalette
)
1545 m_palette
= win
->GetPalette();
1547 // turn on MSW translation for this palette
1553 #endif // wxUSE_PALETTE
1555 // SetFont/Pen/Brush() really ask to be implemented as a single template
1556 // function... but doing it is not worth breaking OpenWatcom build <sigh>
1558 void wxMSWDCImpl::SetFont(const wxFont
& font
)
1560 WXMICROWIN_CHECK_HDC
1562 if ( font
== m_font
)
1567 HGDIOBJ hfont
= ::SelectObject(GetHdc(), GetHfontOf(font
));
1568 if ( hfont
== HGDI_ERROR
)
1570 wxLogLastError(_T("SelectObject(font)"));
1575 m_oldFont
= (WXHFONT
)hfont
;
1580 else // invalid font, reset the current font
1584 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldFont
) == HGDI_ERROR
)
1586 wxLogLastError(_T("SelectObject(old font)"));
1592 m_font
= wxNullFont
;
1596 void wxMSWDCImpl::SetPen(const wxPen
& pen
)
1598 WXMICROWIN_CHECK_HDC
1605 HGDIOBJ hpen
= ::SelectObject(GetHdc(), GetHpenOf(pen
));
1606 if ( hpen
== HGDI_ERROR
)
1608 wxLogLastError(_T("SelectObject(pen)"));
1613 m_oldPen
= (WXHPEN
)hpen
;
1618 else // invalid pen, reset the current pen
1622 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldPen
) == HGDI_ERROR
)
1624 wxLogLastError(_T("SelectObject(old pen)"));
1634 void wxMSWDCImpl::SetBrush(const wxBrush
& brush
)
1636 WXMICROWIN_CHECK_HDC
1638 if ( brush
== m_brush
)
1643 // we must make sure the brush is aligned with the logical coordinates
1644 // before selecting it
1645 wxBitmap
*stipple
= brush
.GetStipple();
1646 if ( stipple
&& stipple
->IsOk() )
1648 if ( !::SetBrushOrgEx
1651 m_deviceOriginX
% stipple
->GetWidth(),
1652 m_deviceOriginY
% stipple
->GetHeight(),
1653 NULL
// [out] previous brush origin
1656 wxLogLastError(_T("SetBrushOrgEx()"));
1660 HGDIOBJ hbrush
= ::SelectObject(GetHdc(), GetHbrushOf(brush
));
1661 if ( hbrush
== HGDI_ERROR
)
1663 wxLogLastError(_T("SelectObject(brush)"));
1668 m_oldBrush
= (WXHBRUSH
)hbrush
;
1673 else // invalid brush, reset the current brush
1677 if ( ::SelectObject(GetHdc(), (HPEN
) m_oldBrush
) == HGDI_ERROR
)
1679 wxLogLastError(_T("SelectObject(old brush)"));
1685 m_brush
= wxNullBrush
;
1689 void wxMSWDCImpl::SetBackground(const wxBrush
& brush
)
1691 WXMICROWIN_CHECK_HDC
1693 m_backgroundBrush
= brush
;
1695 if ( m_backgroundBrush
.IsOk() )
1697 (void)SetBkColor(GetHdc(), m_backgroundBrush
.GetColour().GetPixel());
1701 void wxMSWDCImpl::SetBackgroundMode(int mode
)
1703 WXMICROWIN_CHECK_HDC
1705 m_backgroundMode
= mode
;
1707 // SetBackgroundColour now only refers to text background
1708 // and m_backgroundMode is used there
1711 void wxMSWDCImpl::SetLogicalFunction(wxRasterOperationMode function
)
1713 WXMICROWIN_CHECK_HDC
1715 m_logicalFunction
= function
;
1720 void wxMSWDCImpl::SetRop(WXHDC dc
)
1722 if ( !dc
|| m_logicalFunction
< 0 )
1725 int rop
wxDUMMY_INITIALIZE(0);
1727 switch (m_logicalFunction
)
1729 case wxCLEAR
: rop
= R2_BLACK
; break;
1730 case wxXOR
: rop
= R2_XORPEN
; break;
1731 case wxINVERT
: rop
= R2_NOT
; break;
1732 case wxOR_REVERSE
: rop
= R2_MERGEPENNOT
; break;
1733 case wxAND_REVERSE
: rop
= R2_MASKPENNOT
; break;
1734 case wxCOPY
: rop
= R2_COPYPEN
; break;
1735 case wxAND
: rop
= R2_MASKPEN
; break;
1736 case wxAND_INVERT
: rop
= R2_MASKNOTPEN
; break;
1737 case wxNO_OP
: rop
= R2_NOP
; break;
1738 case wxNOR
: rop
= R2_NOTMERGEPEN
; break;
1739 case wxEQUIV
: rop
= R2_NOTXORPEN
; break;
1740 case wxSRC_INVERT
: rop
= R2_NOTCOPYPEN
; break;
1741 case wxOR_INVERT
: rop
= R2_MERGENOTPEN
; break;
1742 case wxNAND
: rop
= R2_NOTMASKPEN
; break;
1743 case wxOR
: rop
= R2_MERGEPEN
; break;
1744 case wxSET
: rop
= R2_WHITE
; break;
1747 SetROP2(GetHdc(), rop
);
1750 bool wxMSWDCImpl::StartDoc(const wxString
& WXUNUSED(message
))
1752 // We might be previewing, so return true to let it continue.
1756 void wxMSWDCImpl::EndDoc()
1760 void wxMSWDCImpl::StartPage()
1764 void wxMSWDCImpl::EndPage()
1768 // ---------------------------------------------------------------------------
1770 // ---------------------------------------------------------------------------
1772 wxCoord
wxMSWDCImpl::GetCharHeight() const
1774 WXMICROWIN_CHECK_HDC_RET(0)
1776 TEXTMETRIC lpTextMetric
;
1778 GetTextMetrics(GetHdc(), &lpTextMetric
);
1780 return lpTextMetric
.tmHeight
;
1783 wxCoord
wxMSWDCImpl::GetCharWidth() const
1785 WXMICROWIN_CHECK_HDC_RET(0)
1787 TEXTMETRIC lpTextMetric
;
1789 GetTextMetrics(GetHdc(), &lpTextMetric
);
1791 return lpTextMetric
.tmAveCharWidth
;
1794 void wxMSWDCImpl::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
1795 wxCoord
*descent
, wxCoord
*externalLeading
,
1796 const wxFont
*font
) const
1798 #ifdef __WXMICROWIN__
1803 if (descent
) *descent
= 0;
1804 if (externalLeading
) *externalLeading
= 0;
1807 #endif // __WXMICROWIN__
1812 wxASSERT_MSG( font
->IsOk(), _T("invalid font in wxMSWDCImpl::GetTextExtent") );
1814 hfontOld
= (HFONT
)::SelectObject(GetHdc(), GetHfontOf(*font
));
1816 else // don't change the font
1822 const size_t len
= string
.length();
1823 if ( !::GetTextExtentPoint32(GetHdc(), string
.wx_str(), len
, &sizeRect
) )
1825 wxLogLastError(_T("GetTextExtentPoint32()"));
1828 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1829 // the result computed by GetTextExtentPoint32() may be too small as it
1830 // accounts for under/overhang of the first/last character while we want
1831 // just the bounding rect for this string so adjust the width as needed
1832 // (using API not available in 2002 SDKs of WinCE)
1836 const wxChar chFirst
= *string
.begin();
1837 if ( ::GetCharABCWidths(GetHdc(), chFirst
, chFirst
, &width
) )
1839 if ( width
.abcA
< 0 )
1840 sizeRect
.cx
-= width
.abcA
;
1844 const wxChar chLast
= *string
.rbegin();
1845 ::GetCharABCWidths(GetHdc(), chLast
, chLast
, &width
);
1847 //else: we already have the width of the last character
1849 if ( width
.abcC
< 0 )
1850 sizeRect
.cx
-= width
.abcC
;
1852 //else: GetCharABCWidths() failed, not a TrueType font?
1854 #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
1857 ::GetTextMetrics(GetHdc(), &tm
);
1864 *descent
= tm
.tmDescent
;
1865 if (externalLeading
)
1866 *externalLeading
= tm
.tmExternalLeading
;
1870 ::SelectObject(GetHdc(), hfontOld
);
1875 // Each element of the array will be the width of the string up to and
1876 // including the coresoponding character in text.
1878 bool wxMSWDCImpl::DoGetPartialTextExtents(const wxString
& text
, wxArrayInt
& widths
) const
1880 static int maxLenText
= -1;
1881 static int maxWidth
= -1;
1884 int stlen
= text
.length();
1886 if (maxLenText
== -1)
1888 // Win9x and WinNT+ have different limits
1889 int version
= wxGetOsVersion();
1890 maxLenText
= version
== wxOS_WINDOWS_NT
? 65535 : 8192;
1891 maxWidth
= version
== wxOS_WINDOWS_NT
? INT_MAX
: 32767;
1895 widths
.Add(0, stlen
); // fill the array with zeros
1899 if (!::GetTextExtentExPoint(GetHdc(),
1900 text
.c_str(), // string to check
1901 wxMin(stlen
, maxLenText
),
1903 &fit
, // [out] count of chars
1905 &widths
[0], // array to fill
1909 wxLogLastError(wxT("GetTextExtentExPoint"));
1916 void wxMSWDCImpl::RealizeScaleAndOrigin()
1918 // although it may seem wasteful to always use MM_ANISOTROPIC here instead
1919 // of using MM_TEXT if there is no scaling, benchmarking doesn't detect any
1920 // noticeable difference between these mapping modes
1922 ::SetMapMode(GetHdc(), MM_ANISOTROPIC
);
1924 int width
= DeviceToLogicalXRel(VIEWPORT_EXTENT
)*m_signX
,
1925 height
= DeviceToLogicalYRel(VIEWPORT_EXTENT
)*m_signY
;
1927 ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT
, VIEWPORT_EXTENT
, NULL
);
1928 ::SetWindowExtEx(GetHdc(), width
, height
, NULL
);
1930 ::SetViewportOrgEx(GetHdc(), m_deviceOriginX
, m_deviceOriginY
, NULL
);
1931 ::SetWindowOrgEx(GetHdc(), m_logicalOriginX
, m_logicalOriginY
, NULL
);
1935 void wxMSWDCImpl::SetMapMode(wxMappingMode mode
)
1937 WXMICROWIN_CHECK_HDC
1939 m_mappingMode
= mode
;
1941 if ( mode
== wxMM_TEXT
)
1944 m_logicalScaleY
= 1.0;
1946 else // need to do some calculations
1948 int pixel_width
= ::GetDeviceCaps(GetHdc(), HORZRES
),
1949 pixel_height
= ::GetDeviceCaps(GetHdc(), VERTRES
),
1950 mm_width
= ::GetDeviceCaps(GetHdc(), HORZSIZE
),
1951 mm_height
= ::GetDeviceCaps(GetHdc(), VERTSIZE
);
1953 if ( (mm_width
== 0) || (mm_height
== 0) )
1955 // we can't calculate mm2pixels[XY] then!
1959 double mm2pixelsX
= (double)pixel_width
/ mm_width
,
1960 mm2pixelsY
= (double)pixel_height
/ mm_height
;
1965 m_logicalScaleX
= twips2mm
* mm2pixelsX
;
1966 m_logicalScaleY
= twips2mm
* mm2pixelsY
;
1970 m_logicalScaleX
= pt2mm
* mm2pixelsX
;
1971 m_logicalScaleY
= pt2mm
* mm2pixelsY
;
1975 m_logicalScaleX
= mm2pixelsX
;
1976 m_logicalScaleY
= mm2pixelsY
;
1980 m_logicalScaleX
= mm2pixelsX
/ 10.0;
1981 m_logicalScaleY
= mm2pixelsY
/ 10.0;
1985 wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") );
1989 ComputeScaleAndOrigin();
1991 RealizeScaleAndOrigin();
1994 void wxMSWDCImpl::SetUserScale(double x
, double y
)
1996 WXMICROWIN_CHECK_HDC
1998 if ( x
== m_userScaleX
&& y
== m_userScaleY
)
2001 wxDCImpl::SetUserScale(x
,y
);
2003 RealizeScaleAndOrigin();
2006 void wxMSWDCImpl::SetAxisOrientation(bool xLeftRight
,
2009 WXMICROWIN_CHECK_HDC
2011 int signX
= xLeftRight
? 1 : -1,
2012 signY
= yBottomUp
? -1 : 1;
2014 if (signX
== m_signX
&& signY
== m_signY
)
2017 wxDCImpl::SetAxisOrientation( xLeftRight
, yBottomUp
);
2019 RealizeScaleAndOrigin();
2022 void wxMSWDCImpl::SetLogicalOrigin(wxCoord x
, wxCoord y
)
2024 WXMICROWIN_CHECK_HDC
2026 if ( x
== m_logicalOriginX
&& y
== m_logicalOriginY
)
2029 wxDCImpl::SetLogicalOrigin( x
, y
);
2031 RealizeScaleAndOrigin();
2034 // For use by wxWidgets only, unless custom units are required.
2035 void wxMSWDCImpl::SetLogicalScale(double x
, double y
)
2037 WXMICROWIN_CHECK_HDC
2039 wxDCImpl::SetLogicalScale(x
,y
);
2042 void wxMSWDCImpl::SetDeviceOrigin(wxCoord x
, wxCoord y
)
2044 WXMICROWIN_CHECK_HDC
2046 if ( x
== m_deviceOriginX
&& y
== m_deviceOriginY
)
2049 wxDCImpl::SetDeviceOrigin( x
, y
);
2051 ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX
, (int)m_deviceOriginY
, NULL
);
2054 // ---------------------------------------------------------------------------
2056 // ---------------------------------------------------------------------------
2058 bool wxMSWDCImpl::DoBlit(wxCoord dstX
, wxCoord dstY
,
2059 wxCoord dstWidth
, wxCoord dstHeight
,
2061 wxCoord srcX
, wxCoord srcY
,
2062 wxRasterOperationMode rop
, bool useMask
,
2063 wxCoord srcMaskX
, wxCoord srcMaskY
)
2065 return DoStretchBlit(dstX
, dstY
, dstWidth
, dstHeight
, source
, srcX
, srcY
, dstWidth
, dstHeight
, rop
, useMask
, srcMaskX
, srcMaskY
);
2068 bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest
, wxCoord ydest
,
2069 wxCoord dstWidth
, wxCoord dstHeight
,
2071 wxCoord xsrc
, wxCoord ysrc
,
2072 wxCoord srcWidth
, wxCoord srcHeight
,
2073 wxRasterOperationMode rop
, bool useMask
,
2074 wxCoord xsrcMask
, wxCoord ysrcMask
)
2076 wxCHECK_MSG( source
, false, _T("wxMSWDCImpl::Blit(): NULL wxDC pointer") );
2078 WXMICROWIN_CHECK_HDC_RET(false)
2080 wxMSWDCImpl
*implSrc
= wxDynamicCast( source
->GetImpl(), wxMSWDCImpl
);
2083 // TODO: Do we want to be able to blit from other DCs too?
2087 const HDC hdcSrc
= GetHdcOf(*implSrc
);
2089 // if either the source or destination has alpha channel, we must use
2090 // AlphaBlt() as other function don't handle it correctly
2091 const wxBitmap
& bmpSrc
= implSrc
->GetSelectedBitmap();
2092 if ( bmpSrc
.IsOk() && (bmpSrc
.HasAlpha() ||
2093 (m_selectedBitmap
.IsOk() && m_selectedBitmap
.HasAlpha())) )
2095 if ( AlphaBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2096 xsrc
, ysrc
, srcWidth
, srcHeight
, hdcSrc
, bmpSrc
) )
2100 wxMask
*mask
= NULL
;
2103 mask
= bmpSrc
.GetMask();
2105 if ( !(bmpSrc
.IsOk() && mask
&& mask
->GetMaskBitmap()) )
2107 // don't give assert here because this would break existing
2108 // programs - just silently ignore useMask parameter
2113 if (xsrcMask
== -1 && ysrcMask
== -1)
2115 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
2118 wxTextColoursChanger
textCol(GetHdc(), *this);
2123 case wxXOR
: dwRop
= SRCINVERT
; break;
2124 case wxINVERT
: dwRop
= DSTINVERT
; break;
2125 case wxOR_REVERSE
: dwRop
= 0x00DD0228; break;
2126 case wxAND_REVERSE
: dwRop
= SRCERASE
; break;
2127 case wxCLEAR
: dwRop
= BLACKNESS
; break;
2128 case wxSET
: dwRop
= WHITENESS
; break;
2129 case wxOR_INVERT
: dwRop
= MERGEPAINT
; break;
2130 case wxAND
: dwRop
= SRCAND
; break;
2131 case wxOR
: dwRop
= SRCPAINT
; break;
2132 case wxEQUIV
: dwRop
= 0x00990066; break;
2133 case wxNAND
: dwRop
= 0x007700E6; break;
2134 case wxAND_INVERT
: dwRop
= 0x00220326; break;
2135 case wxCOPY
: dwRop
= SRCCOPY
; break;
2136 case wxNO_OP
: dwRop
= DSTCOPY
; break;
2137 case wxSRC_INVERT
: dwRop
= NOTSRCCOPY
; break;
2138 case wxNOR
: dwRop
= NOTSRCCOPY
; break;
2140 wxFAIL_MSG( wxT("unsupported logical function") );
2144 bool success
= false;
2149 // we want the part of the image corresponding to the mask to be
2150 // transparent, so use "DSTCOPY" ROP for the mask points (the usual
2151 // meaning of fg and bg is inverted which corresponds to wxWin notion
2152 // of the mask which is also contrary to the Windows one)
2154 // On some systems, MaskBlt succeeds yet is much much slower
2155 // than the wxWidgets fall-back implementation. So we need
2156 // to be able to switch this on and off at runtime.
2157 #if wxUSE_SYSTEM_OPTIONS
2158 if (wxSystemOptions::GetOptionInt(wxT("no-maskblt")) == 0)
2161 if ( dstWidth
== srcWidth
&& dstHeight
== srcHeight
)
2166 xdest
, ydest
, dstWidth
, dstHeight
,
2169 (HBITMAP
)mask
->GetMaskBitmap(),
2171 MAKEROP4(dwRop
, DSTCOPY
)
2179 // Blit bitmap with mask
2182 HBITMAP buffer_bmap
;
2184 #if wxUSE_DC_CACHEING
2185 // create a temp buffer bitmap and DCs to access it and the mask
2186 wxDCCacheEntry
* dcCacheEntry1
= FindDCInCache(NULL
, hdcSrc
);
2187 dc_mask
= (HDC
) dcCacheEntry1
->m_dc
;
2189 wxDCCacheEntry
* dcCacheEntry2
= FindDCInCache(dcCacheEntry1
, GetHDC());
2190 dc_buffer
= (HDC
) dcCacheEntry2
->m_dc
;
2192 wxDCCacheEntry
* bitmapCacheEntry
= FindBitmapInCache(GetHDC(),
2193 dstWidth
, dstHeight
);
2195 buffer_bmap
= (HBITMAP
) bitmapCacheEntry
->m_bitmap
;
2196 #else // !wxUSE_DC_CACHEING
2197 // create a temp buffer bitmap and DCs to access it and the mask
2198 dc_mask
= ::CreateCompatibleDC(hdcSrc
);
2199 dc_buffer
= ::CreateCompatibleDC(GetHdc());
2200 buffer_bmap
= ::CreateCompatibleBitmap(GetHdc(), dstWidth
, dstHeight
);
2201 #endif // wxUSE_DC_CACHEING/!wxUSE_DC_CACHEING
2202 HGDIOBJ hOldMaskBitmap
= ::SelectObject(dc_mask
, (HBITMAP
) mask
->GetMaskBitmap());
2203 HGDIOBJ hOldBufferBitmap
= ::SelectObject(dc_buffer
, buffer_bmap
);
2205 // copy dest to buffer
2206 if ( !::BitBlt(dc_buffer
, 0, 0, dstWidth
, dstHeight
,
2207 GetHdc(), xdest
, ydest
, SRCCOPY
) )
2209 wxLogLastError(wxT("BitBlt"));
2213 StretchBltModeChanger
changeMode(dc_buffer
, COLORONCOLOR
);
2216 // copy src to buffer using selected raster op
2217 if ( !::StretchBlt(dc_buffer
, 0, 0, dstWidth
, dstHeight
,
2218 hdcSrc
, xsrc
, ysrc
, srcWidth
, srcHeight
, dwRop
) )
2220 wxLogLastError(wxT("StretchBlt"));
2223 // set masked area in buffer to BLACK
2225 wxTextColoursChanger
textCol2(GetHdc(), *wxBLACK
, *wxWHITE
);
2226 if ( !::StretchBlt(dc_buffer
, 0, 0, dstWidth
, dstHeight
,
2227 dc_mask
, xsrcMask
, ysrcMask
,
2228 srcWidth
, srcHeight
, SRCAND
) )
2230 wxLogLastError(wxT("StretchBlt"));
2233 // set unmasked area in dest to BLACK
2234 ::SetBkColor(GetHdc(), RGB(0, 0, 0));
2235 ::SetTextColor(GetHdc(), RGB(255, 255, 255));
2236 if ( !::StretchBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2237 dc_mask
, xsrcMask
, ysrcMask
,
2238 srcWidth
, srcHeight
, SRCAND
) )
2240 wxLogLastError(wxT("StretchBlt"));
2242 } // restore the original text and background colours
2244 // OR buffer to dest
2245 success
= ::BitBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2246 dc_buffer
, 0, 0, SRCPAINT
) != 0;
2249 wxLogLastError(wxT("BitBlt"));
2252 // tidy up temporary DCs and bitmap
2253 ::SelectObject(dc_mask
, hOldMaskBitmap
);
2254 ::SelectObject(dc_buffer
, hOldBufferBitmap
);
2256 #if !wxUSE_DC_CACHEING
2258 ::DeleteDC(dc_mask
);
2259 ::DeleteDC(dc_buffer
);
2260 ::DeleteObject(buffer_bmap
);
2265 else // no mask, just BitBlt() it
2267 // if we already have a DIB, draw it using StretchDIBits(), otherwise
2268 // use StretchBlt() if available and finally fall back to BitBlt()
2270 // FIXME: use appropriate WinCE functions
2272 const int caps
= ::GetDeviceCaps(GetHdc(), RASTERCAPS
);
2273 if ( bmpSrc
.IsOk() && (caps
& RC_STRETCHDIB
) )
2278 if ( ::GetObject(GetHbitmapOf(bmpSrc
),
2280 &ds
) == sizeof(ds
) )
2282 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2284 // Figure out what co-ordinate system we're supposed to specify
2286 const LONG hDIB
= ds
.dsBmih
.biHeight
;
2290 ysrc
= hDIB
- (ysrc
+ dstHeight
);
2293 if ( ::StretchDIBits(GetHdc(),
2295 dstWidth
, dstHeight
,
2297 srcWidth
, srcHeight
,
2299 (LPBITMAPINFO
)&ds
.dsBmih
,
2302 ) == (int)GDI_ERROR
)
2304 // On Win9x this API fails most (all?) of the time, so
2305 // logging it becomes quite distracting. Since it falls
2306 // back to the code below this is not really serious, so
2308 //wxLogLastError(wxT("StretchDIBits"));
2317 if ( !success
&& (caps
& RC_STRETCHBLT
) )
2322 StretchBltModeChanger
changeMode(GetHdc(), COLORONCOLOR
);
2328 xdest
, ydest
, dstWidth
, dstHeight
,
2330 xsrc
, ysrc
, srcWidth
, srcHeight
,
2334 wxLogLastError(_T("StretchBlt"));
2344 if ( !::BitBlt(GetHdc(), xdest
, ydest
, dstWidth
, dstHeight
,
2345 hdcSrc
, xsrc
, ysrc
, dwRop
) )
2347 wxLogLastError(_T("BitBlt"));
2359 void wxMSWDCImpl::GetDeviceSize(int *width
, int *height
) const
2361 WXMICROWIN_CHECK_HDC
2364 *width
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2366 *height
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2369 void wxMSWDCImpl::DoGetSizeMM(int *w
, int *h
) const
2371 WXMICROWIN_CHECK_HDC
2373 // if we implement it in terms of DoGetSize() instead of directly using the
2374 // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it
2375 // will also work for wxWindowDC and wxClientDC even though their size is
2376 // not the same as the total size of the screen
2377 int wPixels
, hPixels
;
2378 DoGetSize(&wPixels
, &hPixels
);
2382 int wTotal
= ::GetDeviceCaps(GetHdc(), HORZRES
);
2384 wxCHECK_RET( wTotal
, _T("0 width device?") );
2386 *w
= (wPixels
* ::GetDeviceCaps(GetHdc(), HORZSIZE
)) / wTotal
;
2391 int hTotal
= ::GetDeviceCaps(GetHdc(), VERTRES
);
2393 wxCHECK_RET( hTotal
, _T("0 height device?") );
2395 *h
= (hPixels
* ::GetDeviceCaps(GetHdc(), VERTSIZE
)) / hTotal
;
2399 wxSize
wxMSWDCImpl::GetPPI() const
2401 WXMICROWIN_CHECK_HDC_RET(wxSize(0,0))
2403 int x
= ::GetDeviceCaps(GetHdc(), LOGPIXELSX
);
2404 int y
= ::GetDeviceCaps(GetHdc(), LOGPIXELSY
);
2406 return wxSize(x
, y
);
2409 // ----------------------------------------------------------------------------
2411 // ----------------------------------------------------------------------------
2413 #if wxUSE_DC_CACHEING
2416 * This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
2417 * improve it in due course, either using arrays, or simply storing pointers to one
2418 * entry for the bitmap, and two for the DCs. -- JACS
2421 wxObjectList
wxMSWDCImpl::sm_bitmapCache
;
2422 wxObjectList
wxMSWDCImpl::sm_dcCache
;
2424 wxDCCacheEntry::wxDCCacheEntry(WXHBITMAP hBitmap
, int w
, int h
, int depth
)
2433 wxDCCacheEntry::wxDCCacheEntry(WXHDC hDC
, int depth
)
2442 wxDCCacheEntry::~wxDCCacheEntry()
2445 ::DeleteObject((HBITMAP
) m_bitmap
);
2447 ::DeleteDC((HDC
) m_dc
);
2450 wxDCCacheEntry
* wxMSWDCImpl::FindBitmapInCache(WXHDC dc
, int w
, int h
)
2452 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2453 wxList::compatibility_iterator node
= sm_bitmapCache
.GetFirst();
2456 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2458 if (entry
->m_depth
== depth
)
2460 if (entry
->m_width
< w
|| entry
->m_height
< h
)
2462 ::DeleteObject((HBITMAP
) entry
->m_bitmap
);
2463 entry
->m_bitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2464 if ( !entry
->m_bitmap
)
2466 wxLogLastError(wxT("CreateCompatibleBitmap"));
2468 entry
->m_width
= w
; entry
->m_height
= h
;
2474 node
= node
->GetNext();
2476 WXHBITMAP hBitmap
= (WXHBITMAP
) ::CreateCompatibleBitmap((HDC
) dc
, w
, h
);
2479 wxLogLastError(wxT("CreateCompatibleBitmap"));
2481 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hBitmap
, w
, h
, depth
);
2482 AddToBitmapCache(entry
);
2486 wxDCCacheEntry
* wxMSWDCImpl::FindDCInCache(wxDCCacheEntry
* notThis
, WXHDC dc
)
2488 int depth
= ::GetDeviceCaps((HDC
) dc
, PLANES
) * ::GetDeviceCaps((HDC
) dc
, BITSPIXEL
);
2489 wxList::compatibility_iterator node
= sm_dcCache
.GetFirst();
2492 wxDCCacheEntry
* entry
= (wxDCCacheEntry
*) node
->GetData();
2494 // Don't return the same one as we already have
2495 if (!notThis
|| (notThis
!= entry
))
2497 if (entry
->m_depth
== depth
)
2503 node
= node
->GetNext();
2505 WXHDC hDC
= (WXHDC
) ::CreateCompatibleDC((HDC
) dc
);
2508 wxLogLastError(wxT("CreateCompatibleDC"));
2510 wxDCCacheEntry
* entry
= new wxDCCacheEntry(hDC
, depth
);
2511 AddToDCCache(entry
);
2515 void wxMSWDCImpl::AddToBitmapCache(wxDCCacheEntry
* entry
)
2517 sm_bitmapCache
.Append(entry
);
2520 void wxMSWDCImpl::AddToDCCache(wxDCCacheEntry
* entry
)
2522 sm_dcCache
.Append(entry
);
2525 void wxMSWDCImpl::ClearCache()
2527 WX_CLEAR_LIST(wxList
, sm_dcCache
);
2528 WX_CLEAR_LIST(wxList
, sm_bitmapCache
);
2531 // Clean up cache at app exit
2532 class wxDCModule
: public wxModule
2535 virtual bool OnInit() { return true; }
2536 virtual void OnExit() { wxMSWDCImpl::ClearCache(); }
2539 DECLARE_DYNAMIC_CLASS(wxDCModule
)
2542 IMPLEMENT_DYNAMIC_CLASS(wxDCModule
, wxModule
)
2544 #endif // wxUSE_DC_CACHEING
2546 // ----------------------------------------------------------------------------
2547 // alpha channel support
2548 // ----------------------------------------------------------------------------
2550 static bool AlphaBlt(HDC hdcDst
,
2551 int x
, int y
, int dstWidth
, int dstHeight
,
2553 int srcWidth
, int srcHeight
,
2555 const wxBitmap
& bmp
)
2557 wxASSERT_MSG( bmp
.IsOk() && bmp
.HasAlpha(), _T("AlphaBlt(): invalid bitmap") );
2558 wxASSERT_MSG( hdcDst
&& hdcSrc
, _T("AlphaBlt(): invalid HDC") );
2560 // do we have AlphaBlend() and company in the headers?
2561 #if defined(AC_SRC_OVER) && wxUSE_DYNLIB_CLASS
2562 // yes, now try to see if we have it during run-time
2563 typedef BOOL (WINAPI
*AlphaBlend_t
)(HDC
,int,int,int,int,
2564 HDC
,int,int,int,int,
2568 pfnAlphaBlend
= (AlphaBlend_t
)wxMSIMG32DLL
.GetSymbol(_T("AlphaBlend"));
2569 if ( pfnAlphaBlend
)
2572 bf
.BlendOp
= AC_SRC_OVER
;
2574 bf
.SourceConstantAlpha
= 0xff;
2575 bf
.AlphaFormat
= AC_SRC_ALPHA
;
2577 if ( pfnAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
,
2578 hdcSrc
, srcX
, srcY
, srcWidth
, srcHeight
,
2581 // skip wxAlphaBlend() call below
2585 wxLogLastError(_T("AlphaBlend"));
2588 wxUnusedVar(hdcSrc
);
2589 #endif // defined(AC_SRC_OVER)
2591 // AlphaBlend() unavailable of failed: use our own (probably much slower)
2593 #ifdef wxHAS_RAW_BITMAP
2594 wxAlphaBlend(hdcDst
, x
, y
, dstWidth
, dstHeight
, srcX
, srcY
, srcWidth
, srcHeight
, bmp
);
2597 #else // !wxHAS_RAW_BITMAP
2598 // no wxAlphaBlend() neither, fall back to using simple BitBlt() (we lose
2599 // alpha but at least something will be shown like this)
2602 #endif // wxHAS_RAW_BITMAP/!wxHAS_RAW_BITMAP
2606 // wxAlphaBlend: our fallback if ::AlphaBlend() is unavailable
2607 #ifdef wxHAS_RAW_BITMAP
2610 wxAlphaBlend(HDC hdcDst
, int xDst
, int yDst
,
2611 int dstWidth
, int dstHeight
,
2613 int srcWidth
, int srcHeight
,
2614 const wxBitmap
& bmpSrc
)
2616 // get the destination DC pixels
2617 wxBitmap
bmpDst(dstWidth
, dstHeight
, 32 /* force creating RGBA DIB */);
2619 SelectInHDC
select(hdcMem
, GetHbitmapOf(bmpDst
));
2621 if ( !::BitBlt(hdcMem
, 0, 0, dstWidth
, dstHeight
, hdcDst
, xDst
, yDst
, SRCCOPY
) )
2623 wxLogLastError(_T("BitBlt"));
2626 // combine them with the source bitmap using alpha
2627 wxAlphaPixelData
dataDst(bmpDst
),
2628 dataSrc((wxBitmap
&)bmpSrc
);
2630 wxCHECK_RET( dataDst
&& dataSrc
,
2631 _T("failed to get raw data in wxAlphaBlend") );
2633 wxAlphaPixelData::Iterator
pDst(dataDst
),
2637 for ( int y
= 0; y
< dstHeight
; y
++ )
2639 wxAlphaPixelData::Iterator pDstRowStart
= pDst
;
2641 for ( int x
= 0; x
< dstWidth
; x
++ )
2643 // source is point sampled, Alpha StretchBlit is ugly on Win95
2644 // (but does not impact performance)
2645 pSrc
.MoveTo(dataSrc
, srcX
+ (srcWidth
*x
/dstWidth
), srcY
+ (srcHeight
*y
/dstHeight
));
2647 // note that source bitmap uses premultiplied alpha (as required by
2648 // the real AlphaBlend)
2649 const unsigned beta
= 255 - pSrc
.Alpha();
2651 pDst
.Red() = pSrc
.Red() + (beta
* pDst
.Red() + 127) / 255;
2652 pDst
.Blue() = pSrc
.Blue() + (beta
* pDst
.Blue() + 127) / 255;
2653 pDst
.Green() = pSrc
.Green() + (beta
* pDst
.Green() + 127) / 255;
2658 pDst
= pDstRowStart
;
2659 pDst
.OffsetY(dataDst
, 1);
2662 // and finally blit them back to the destination DC
2663 if ( !::BitBlt(hdcDst
, xDst
, yDst
, dstWidth
, dstHeight
, hdcMem
, 0, 0, SRCCOPY
) )
2665 wxLogLastError(_T("BitBlt"));
2669 #endif // wxHAS_RAW_BITMAP
2671 void wxMSWDCImpl::DoGradientFillLinear (const wxRect
& rect
,
2672 const wxColour
& initialColour
,
2673 const wxColour
& destColour
,
2674 wxDirection nDirection
)
2676 // use native function if we have compile-time support it and can load it
2677 // during run-time (linking to it statically would make the program
2678 // unusable on earlier Windows versions)
2679 #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS
2681 (WINAPI
*GradientFill_t
)(HDC
, PTRIVERTEX
, ULONG
, PVOID
, ULONG
, ULONG
);
2682 static GradientFill_t pfnGradientFill
=
2683 (GradientFill_t
)wxMSIMG32DLL
.GetSymbol(_T("GradientFill"));
2685 if ( pfnGradientFill
)
2687 GRADIENT_RECT grect
;
2688 grect
.UpperLeft
= 0;
2689 grect
.LowerRight
= 1;
2691 // invert colours direction if not filling from left-to-right or
2693 int firstVertex
= nDirection
== wxNORTH
|| nDirection
== wxWEST
? 1 : 0;
2695 // one vertex for upper left and one for upper-right
2696 TRIVERTEX vertices
[2];
2698 vertices
[0].x
= rect
.GetLeft();
2699 vertices
[0].y
= rect
.GetTop();
2700 vertices
[1].x
= rect
.GetRight()+1;
2701 vertices
[1].y
= rect
.GetBottom()+1;
2703 vertices
[firstVertex
].Red
= (COLOR16
)(initialColour
.Red() << 8);
2704 vertices
[firstVertex
].Green
= (COLOR16
)(initialColour
.Green() << 8);
2705 vertices
[firstVertex
].Blue
= (COLOR16
)(initialColour
.Blue() << 8);
2706 vertices
[firstVertex
].Alpha
= 0;
2707 vertices
[1 - firstVertex
].Red
= (COLOR16
)(destColour
.Red() << 8);
2708 vertices
[1 - firstVertex
].Green
= (COLOR16
)(destColour
.Green() << 8);
2709 vertices
[1 - firstVertex
].Blue
= (COLOR16
)(destColour
.Blue() << 8);
2710 vertices
[1 - firstVertex
].Alpha
= 0;
2712 if ( (*pfnGradientFill
)
2719 nDirection
== wxWEST
|| nDirection
== wxEAST
2720 ? GRADIENT_FILL_RECT_H
2721 : GRADIENT_FILL_RECT_V
2724 // skip call of the base class version below
2728 wxLogLastError(_T("GradientFill"));
2730 #endif // wxUSE_DYNLIB_CLASS
2732 wxDCImpl::DoGradientFillLinear(rect
, initialColour
, destColour
, nDirection
);
2735 #if wxUSE_DYNLIB_CLASS
2737 static DWORD
wxGetDCLayout(HDC hdc
)
2739 typedef DWORD (WINAPI
*GetLayout_t
)(HDC
);
2741 wxDL_INIT_FUNC(s_pfn
, GetLayout
, wxDynamicLibrary(_T("gdi32.dll")));
2743 return s_pfnGetLayout
? s_pfnGetLayout(hdc
) : (DWORD
)-1;
2746 wxLayoutDirection
wxMSWDCImpl::GetLayoutDirection() const
2748 DWORD layout
= wxGetDCLayout(GetHdc());
2750 if ( layout
== (DWORD
)-1 )
2751 return wxLayout_Default
;
2753 return layout
& LAYOUT_RTL
? wxLayout_RightToLeft
: wxLayout_LeftToRight
;
2756 void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection dir
)
2758 typedef DWORD (WINAPI
*SetLayout_t
)(HDC
, DWORD
);
2760 wxDL_INIT_FUNC(s_pfn
, SetLayout
, wxDynamicLibrary(_T("gdi32.dll")));
2761 if ( !s_pfnSetLayout
)
2764 if ( dir
== wxLayout_Default
)
2766 dir
= wxTheApp
->GetLayoutDirection();
2767 if ( dir
== wxLayout_Default
)
2771 DWORD layout
= wxGetDCLayout(GetHdc());
2772 if ( dir
== wxLayout_RightToLeft
)
2773 layout
|= LAYOUT_RTL
;
2775 layout
&= ~LAYOUT_RTL
;
2777 s_pfnSetLayout(GetHdc(), layout
);
2780 #else // !wxUSE_DYNLIB_CLASS
2782 // we can't provide RTL support without dynamic loading, so stub it out
2783 wxLayoutDirection
wxMSWDCImpl::GetLayoutDirection() const
2785 return wxLayout_Default
;
2788 void wxMSWDCImpl::SetLayoutDirection(wxLayoutDirection
WXUNUSED(dir
))
2792 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS