X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/761598d4e5b9f59bfc773e06f843c070d920f8b9..1ae82ba9f23ee688bc4db2cd449eca5bf97cfdf0:/src/msw/dc.cpp diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index cf75d3e84e..11570c8c40 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -35,12 +35,12 @@ #include "wx/dcmemory.h" #include "wx/log.h" #include "wx/icon.h" + #include "wx/dcprint.h" #endif #include "wx/sysopt.h" -#include "wx/dcprint.h" #include "wx/module.h" -#include "wx/dynload.h" +#include "wx/dynlib.h" #ifdef wxHAVE_RAW_BITMAP #include "wx/rawbmp.h" @@ -196,6 +196,37 @@ private: DECLARE_NO_COPY_CLASS(StretchBltModeChanger) }; +// support for dynamic loading of msimg32.dll which we use for some functions +class wxMSImg32DLL +{ +public: + // return the symbol with the given name if the DLL not loaded or symbol + // not present + static void *GetSymbol(const wxChar *name) + { + wxLogNull noLog; + + if ( !ms_triedToLoad ) + { + ms_triedToLoad = true; + ms_dll.Load(_T("msimg32")); + } + + return ms_dll.IsLoaded() ? ms_dll.GetSymbol(name) : NULL; + } + +private: + static wxDynamicLibrary ms_dll; + static bool ms_triedToLoad; +}; + +wxDynamicLibrary wxMSImg32DLL::ms_dll; +bool wxMSImg32DLL::ms_triedToLoad = false; + +// helper macro for getting the symbols from msimg32.dll: it supposes that a +// type "name_t" is defined and casts the returned symbol to it automatically +#define wxMSIMG32_SYMBOL(name) (name ## _t)wxMSImg32DLL::GetSymbol(_T(#name)) + // =========================================================================== // implementation // =========================================================================== @@ -258,23 +289,6 @@ wxColourChanger::~wxColourChanger() // wxDC // --------------------------------------------------------------------------- -// Default constructor -wxDC::wxDC() -{ - m_canvas = NULL; - - m_oldBitmap = 0; - m_oldPen = 0; - m_oldBrush = 0; - m_oldFont = 0; -#if wxUSE_PALETTE - m_oldPalette = 0; -#endif // wxUSE_PALETTE - - m_bOwnsDC = false; - m_hDC = 0; -} - wxDC::~wxDC() { if ( m_hDC != 0 ) @@ -469,6 +483,14 @@ void wxDC::DestroyClippingRegion() if (m_clipping && m_hDC) { +#if 1 + // On a PocketPC device (not necessarily emulator), resetting + // the clip region as per the old method causes bad display + // problems. In fact setting a null region is probably OK + // on desktop WIN32 also, since the WIN32 docs imply that the user + // clipping region is independent from the paint clipping region. + ::SelectClipRgn(GetHdc(), 0); +#else // TODO: this should restore the previous clipping region, // so that OnPaint processing works correctly, and the update // clipping region doesn't get destroyed after the first @@ -476,6 +498,7 @@ void wxDC::DestroyClippingRegion() HRGN rgn = CreateRectRgn(0, 0, 32000, 32000); ::SelectClipRgn(GetHdc(), rgn); ::DeleteObject(rgn); +#endif } wxDCBase::DestroyClippingRegion(); @@ -701,12 +724,13 @@ void wxDC::DoDrawArc(wxCoord x1, wxCoord y1, void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height) { - WXMICROWIN_CHECK_HDC - + // cases when we don't have DrawFrameControl() +#if defined(__SYMANTEC__) || defined(__WXMICROWIN__) + return wxDCBase::DoDrawCheckMark(x1, y1, width, height); +#else // normal case wxCoord x2 = x1 + width, y2 = y1 + height; -#if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__) RECT rect; rect.left = x1; rect.top = y1; @@ -718,25 +742,10 @@ void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, #else DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK); #endif -#else // Symantec-MicroWin - // draw a cross - HPEN blackPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); - HPEN whiteBrush = (HPEN)::GetStockObject(WHITE_BRUSH); - HPEN hPenOld = (HPEN)::SelectObject(GetHdc(), blackPen); - HPEN hBrushOld = (HPEN)::SelectObject(GetHdc(), whiteBrush); - ::SetROP2(GetHdc(), R2_COPYPEN); - Rectangle(GetHdc(), x1, y1, x2, y2); - MoveToEx(GetHdc(), x1, y1, NULL); - LineTo(GetHdc(), x2, y2); - MoveToEx(GetHdc(), x2, y1, NULL); - LineTo(GetHdc(), x1, y2); - ::SelectObject(GetHdc(), hPenOld); - ::SelectObject(GetHdc(), hBrushOld); - ::DeleteObject(blackPen); -#endif // Win32/Symantec-MicroWin CalcBoundingBox(x1, y1); CalcBoundingBox(x2, y2); +#endif // Microwin/Normal } void wxDC::DoDrawPoint(wxCoord x, wxCoord y) @@ -1479,7 +1488,7 @@ void wxDC::SetFont(const wxFont& font) else // selected ok { if ( !m_oldFont ) - m_oldFont = (WXHPEN)hfont; + m_oldFont = (WXHFONT)hfont; m_font = font; } @@ -1572,7 +1581,7 @@ void wxDC::SetBrush(const wxBrush& brush) else // selected ok { if ( !m_oldBrush ) - m_oldBrush = (WXHPEN)hbrush; + m_oldBrush = (WXHBRUSH)hbrush; m_brush = brush; } @@ -1730,10 +1739,42 @@ void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y, } SIZE sizeRect; - TEXTMETRIC tm; + const size_t len = string.length(); + if ( !::GetTextExtentPoint32(GetHdc(), string, len, &sizeRect) ) + { + wxLogLastError(_T("GetTextExtentPoint32()")); + } - ::GetTextExtentPoint32(GetHdc(), string, string.length(), &sizeRect); - GetTextMetrics(GetHdc(), &tm); +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + // the result computed by GetTextExtentPoint32() may be too small as it + // accounts for under/overhang of the first/last character while we want + // just the bounding rect for this string so adjust the width as needed + // (using API not available in 2002 SDKs of WinCE) + if ( len > 0 ) + { + ABC width; + const wxChar chFirst = *string.begin(); + if ( ::GetCharABCWidths(GetHdc(), chFirst, chFirst, &width) ) + { + if ( width.abcA < 0 ) + sizeRect.cx -= width.abcA; + + if ( len > 1 ) + { + const wxChar chLast = *string.rbegin(); + ::GetCharABCWidths(GetHdc(), chLast, chLast, &width); + } + //else: we already have the width of the last character + + if ( width.abcC < 0 ) + sizeRect.cx -= width.abcC; + } + //else: GetCharABCWidths() failed, not a TrueType font? + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + + TEXTMETRIC tm; + ::GetTextMetrics(GetHdc(), &tm); if (x) *x = sizeRect.cx; @@ -2285,12 +2326,14 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, return success; } -void wxDC::DoGetSize(int *w, int *h) const +void wxDC::GetDeviceSize(int *width, int *height) const { WXMICROWIN_CHECK_HDC - if ( w ) *w = ::GetDeviceCaps(GetHdc(), HORZRES); - if ( h ) *h = ::GetDeviceCaps(GetHdc(), VERTRES); + if ( width ) + *width = ::GetDeviceCaps(GetHdc(), HORZRES); + if ( height ) + *height = ::GetDeviceCaps(GetHdc(), VERTRES); } void wxDC::DoGetSizeMM(int *w, int *h) const @@ -2498,32 +2541,7 @@ static bool AlphaBlt(HDC hdcDst, HDC,int,int,int,int, BLENDFUNCTION); - // bitmaps can be drawn only from GUI thread so there is no need to - // protect this static variable from multiple threads - static bool s_triedToLoad = false; - static AlphaBlend_t pfnAlphaBlend = NULL; - if ( !s_triedToLoad ) - { - s_triedToLoad = true; - - // don't give errors about the DLL being unavailable, we're - // prepared to handle this - wxLogNull nolog; - - wxDynamicLibrary dll(_T("msimg32.dll")); - if ( dll.IsLoaded() ) - { - pfnAlphaBlend = (AlphaBlend_t)dll.GetSymbol(_T("AlphaBlend")); - if ( pfnAlphaBlend ) - { - // we must keep the DLL loaded if we want to be able to - // call AlphaBlend() so just never unload it at all, not a - // big deal - dll.Detach(); - } - } - } - + static AlphaBlend_t pfnAlphaBlend = wxMSIMG32_SYMBOL(AlphaBlend); if ( pfnAlphaBlend ) { BLENDFUNCTION bf; @@ -2624,3 +2642,66 @@ wxAlphaBlend(HDC hdcDst, int xDst, int yDst, } #endif // #ifdef wxHAVE_RAW_BITMAP + +void wxDC::DoGradientFillLinear (const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + wxDirection nDirection) +{ + // use native function if we have compile-time support it and can load it + // during run-time (linking to it statically would make the program + // unusable on earlier Windows versions) +#if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS + typedef BOOL + (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); + static GradientFill_t pfnGradientFill = wxMSIMG32_SYMBOL(GradientFill); + + if ( pfnGradientFill ) + { + GRADIENT_RECT grect; + grect.UpperLeft = 0; + grect.LowerRight = 1; + + // invert colours direction if not filling from left-to-right or + // top-to-bottom + int firstVertex = nDirection == wxNORTH || nDirection == wxWEST ? 1 : 0; + + // one vertex for upper left and one for upper-right + TRIVERTEX vertices[2]; + + vertices[0].x = rect.GetLeft(); + vertices[0].y = rect.GetTop(); + vertices[1].x = rect.GetRight(); + vertices[1].y = rect.GetBottom(); + + vertices[firstVertex].Red = (COLOR16)(initialColour.Red() << 8); + vertices[firstVertex].Green = (COLOR16)(initialColour.Green() << 8); + vertices[firstVertex].Blue = (COLOR16)(initialColour.Blue() << 8); + vertices[firstVertex].Alpha = 0; + vertices[1 - firstVertex].Red = (COLOR16)(destColour.Red() << 8); + vertices[1 - firstVertex].Green = (COLOR16)(destColour.Green() << 8); + vertices[1 - firstVertex].Blue = (COLOR16)(destColour.Blue() << 8); + vertices[1 - firstVertex].Alpha = 0; + + if ( (*pfnGradientFill) + ( + GetHdc(), + vertices, + WXSIZEOF(vertices), + &grect, + 1, + nDirection == wxWEST || nDirection == wxEAST + ? GRADIENT_FILL_RECT_H + : GRADIENT_FILL_RECT_V + ) ) + { + // skip call of the base class version below + return; + } + + wxLogLastError(_T("GradientFill")); + } +#endif // wxUSE_DYNLIB_CLASS + + wxDCBase::DoGradientFillLinear(rect, initialColour, destColour, nDirection); +}