X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5230934a95bf9b3112ec2a7e070e8cbb4cea7f55..fa03793d3bf2b76a753483ddf12abfd35eebe7a0:/src/msw/dc.cpp diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index c222cbbf4c..09d21ad3d0 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -77,6 +77,25 @@ static const int MM_METRIC = 10; // MSDN docs for how this and other numbers in wxDC::Blit() are obtained) #define DSTCOPY 0x00AA0029 // a.k.a. NOP operation +// ---------------------------------------------------------------------------- +// macros for logical <-> device coords conversion +// ---------------------------------------------------------------------------- + +/* + We currently let Windows do all the translations itself so these macros are + not really needed (any more) but keep them to enhance readability of the + code by allowing to see where are the logical and where are the device + coordinates used. + */ + +// logical to device +#define XLOG2DEV(x) (x) +#define YLOG2DEV(y) (y) + +// device to logical +#define XDEV2LOG(x) (x) +#define YDEV2LOG(y) (y) + // --------------------------------------------------------------------------- // private functions // --------------------------------------------------------------------------- @@ -118,7 +137,8 @@ private: wxColourChanger::wxColourChanger(wxDC& dc) : m_dc(dc) { - if ( dc.GetBrush().GetStyle() == wxSTIPPLE_MASK_OPAQUE ) + const wxBrush& brush = dc.GetBrush(); + if ( brush.Ok() && brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE ) { HDC hdc = GetHdcOf(dc); m_colFgOld = ::GetTextColor(hdc); @@ -184,12 +204,8 @@ wxDC::wxDC() m_bOwnsDC = FALSE; m_hDC = 0; - - m_windowExtX = VIEWPORT_EXTENT; - m_windowExtY = VIEWPORT_EXTENT; } - wxDC::~wxDC() { if ( m_hDC != 0 ) @@ -437,14 +453,17 @@ void wxDC::Clear() (void) ::SetMapMode(GetHdc(), MM_TEXT); - DWORD colour = GetBkColor(GetHdc()); - HBRUSH brush = CreateSolidBrush(colour); - FillRect(GetHdc(), &rect, brush); - DeleteObject(brush); + DWORD colour = ::GetBkColor(GetHdc()); + HBRUSH brush = ::CreateSolidBrush(colour); + ::FillRect(GetHdc(), &rect, brush); + ::DeleteObject(brush); + + int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX, + height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY; ::SetMapMode(GetHdc(), MM_ANISOTROPIC); ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL); - ::SetWindowExtEx(GetHdc(), m_windowExtX, m_windowExtY, NULL); + ::SetWindowExtEx(GetHdc(), width, height, NULL); ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL); ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL); } @@ -524,10 +543,6 @@ void wxDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) (void)MoveToEx(GetHdc(), XLOG2DEV(x1), YLOG2DEV(y1), NULL); (void)LineTo(GetHdc(), XLOG2DEV(x2), YLOG2DEV(y2)); - // Normalization: Windows doesn't draw the last point of the line. - // But apparently neither does GTK+, so we take it out again. -// (void)LineTo(GetHdc(), XLOG2DEV(x2) + 1, YLOG2DEV(y2)); - CalcBoundingBox(x1, y1); CalcBoundingBox(x2, y2); } @@ -925,7 +940,7 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask wxPalette *pal = bmp.GetPalette(); if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 ) { - oldPal = ::SelectPalette(hdcMem, GetHpaletteOf(pal), FALSE); + oldPal = ::SelectPalette(hdcMem, GetHpaletteOf(*pal), FALSE); ::RealizePalette(hdcMem); } #endif // wxUSE_PALETTE @@ -980,7 +995,7 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask wxPalette *pal = bmp.GetPalette(); if ( pal && ::GetDeviceCaps(cdc,BITSPIXEL) <= 8 ) { - oldPal = ::SelectPalette(memdc, GetHpaletteOf(pal), FALSE); + oldPal = ::SelectPalette(memdc, GetHpaletteOf(*pal), FALSE); ::RealizePalette(memdc); } #endif // wxUSE_PALETTE @@ -1128,7 +1143,7 @@ void wxDC::DoDrawRotatedText(const wxString& text, #if wxUSE_PALETTE -void wxDC::SetPalette(const wxPalette& palette) +void wxDC::DoSelectPalette(bool realize) { #ifdef __WXMICROWIN__ if (!GetHDC()) return; @@ -1142,28 +1157,44 @@ void wxDC::SetPalette(const wxPalette& palette) m_oldPalette = 0; } - m_palette = palette; - - if (!m_palette.Ok()) + if ( m_palette.Ok() ) { - // Setting a NULL colourmap is a way of restoring - // the original colourmap - if (m_oldPalette) - { - ::SelectPalette(GetHdc(), (HPALETTE) m_oldPalette, FALSE); - m_oldPalette = 0; - } + HPALETTE oldPal = ::SelectPalette(GetHdc(), + GetHpaletteOf(m_palette), + FALSE); + if (!m_oldPalette) + m_oldPalette = (WXHPALETTE) oldPal; - return; + if (realize) + ::RealizePalette(GetHdc()); } +} - if (m_palette.Ok() && m_palette.GetHPALETTE()) +void wxDC::SetPalette(const wxPalette& palette) +{ + if ( palette.Ok() ) { - HPALETTE oldPal = ::SelectPalette(GetHdc(), (HPALETTE) m_palette.GetHPALETTE(), FALSE); - if (!m_oldPalette) - m_oldPalette = (WXHPALETTE) oldPal; + m_palette = palette; + DoSelectPalette(TRUE); + } +} + +void wxDC::InitializePalette() +{ + if ( wxDisplayDepth() <= 8 ) + { + // look for any window or parent that has a custom palette. If any has + // one then we need to use it in drawing operations + wxWindow *win = m_canvas->GetAncestorWithCustomPalette(); - ::RealizePalette(GetHdc()); + m_hasCustomPalette = win && win->HasCustomPalette(); + if ( m_hasCustomPalette ) + { + m_palette = win->GetPalette(); + + // turn on MSW translation for this palette + DoSelectPalette(); + } } } @@ -1423,7 +1454,7 @@ wxCoord wxDC::GetCharHeight() const GetTextMetrics(GetHdc(), &lpTextMetric); - return YDEV2LOGREL(lpTextMetric.tmHeight); + return lpTextMetric.tmHeight; } wxCoord wxDC::GetCharWidth() const @@ -1436,7 +1467,7 @@ wxCoord wxDC::GetCharWidth() const GetTextMetrics(GetHdc(), &lpTextMetric); - return XDEV2LOGREL(lpTextMetric.tmAveCharWidth); + return lpTextMetric.tmAveCharWidth; } void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y, @@ -1472,10 +1503,14 @@ void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y, GetTextExtentPoint(GetHdc(), string, string.length(), &sizeRect); GetTextMetrics(GetHdc(), &tm); - if (x) *x = XDEV2LOGREL(sizeRect.cx); - if (y) *y = YDEV2LOGREL(sizeRect.cy); - if (descent) *descent = tm.tmDescent; - if (externalLeading) *externalLeading = tm.tmExternalLeading; + if (x) + *x = sizeRect.cx; + if (y) + *y = sizeRect.cy; + if (descent) + *descent = tm.tmDescent; + if (externalLeading) + *externalLeading = tm.tmExternalLeading; if ( hfontOld ) { @@ -1491,68 +1526,67 @@ void wxDC::SetMapMode(int mode) m_mappingMode = mode; - int pixel_width = 0; - int pixel_height = 0; - int mm_width = 0; - int mm_height = 0; - - pixel_width = GetDeviceCaps(GetHdc(), HORZRES); - pixel_height = GetDeviceCaps(GetHdc(), VERTRES); - mm_width = GetDeviceCaps(GetHdc(), HORZSIZE); - mm_height = GetDeviceCaps(GetHdc(), VERTSIZE); - - if ((pixel_width == 0) || (pixel_height == 0) || (mm_width == 0) || (mm_height == 0)) + if ( mode == wxMM_TEXT ) { - return; + m_logicalScaleX = + m_logicalScaleY = 1.0; } - - double mm2pixelsX = pixel_width/mm_width; - double mm2pixelsY = pixel_height/mm_height; - - switch (mode) + else // need to do some calculations { - case wxMM_TWIPS: - { - m_logicalScaleX = (twips2mm * mm2pixelsX); - m_logicalScaleY = (twips2mm * mm2pixelsY); - break; - } - case wxMM_POINTS: - { - m_logicalScaleX = (pt2mm * mm2pixelsX); - m_logicalScaleY = (pt2mm * mm2pixelsY); - break; - } - case wxMM_METRIC: - { - m_logicalScaleX = mm2pixelsX; - m_logicalScaleY = mm2pixelsY; - break; - } - case wxMM_LOMETRIC: + int pixel_width = ::GetDeviceCaps(GetHdc(), HORZRES), + pixel_height = ::GetDeviceCaps(GetHdc(), VERTRES), + mm_width = ::GetDeviceCaps(GetHdc(), HORZSIZE), + mm_height = ::GetDeviceCaps(GetHdc(), VERTSIZE); + + if ( (mm_width == 0) || (mm_height == 0) ) { - m_logicalScaleX = (mm2pixelsX/10.0); - m_logicalScaleY = (mm2pixelsY/10.0); - break; + // we can't calculate mm2pixels[XY] then! + return; } - default: - case wxMM_TEXT: + + double mm2pixelsX = pixel_width / mm_width, + mm2pixelsY = pixel_height / mm_height; + + switch (mode) { - m_logicalScaleX = 1.0; - m_logicalScaleY = 1.0; - break; + case wxMM_TWIPS: + m_logicalScaleX = twips2mm * mm2pixelsX; + m_logicalScaleY = twips2mm * mm2pixelsY; + break; + + case wxMM_POINTS: + m_logicalScaleX = pt2mm * mm2pixelsX; + m_logicalScaleY = pt2mm * mm2pixelsY; + break; + + case wxMM_METRIC: + m_logicalScaleX = mm2pixelsX; + m_logicalScaleY = mm2pixelsY; + break; + + case wxMM_LOMETRIC: + m_logicalScaleX = mm2pixelsX / 10.0; + m_logicalScaleY = mm2pixelsY / 10.0; + break; + + default: + wxFAIL_MSG( _T("unknown mapping mode in SetMapMode") ); } } - if (::GetMapMode(GetHdc()) != MM_ANISOTROPIC) - ::SetMapMode(GetHdc(), MM_ANISOTROPIC); + // VZ: it seems very wasteful to always use MM_ANISOTROPIC when in 99% of + // cases we could do with MM_TEXT and in the remaining 0.9% with + // MM_ISOTROPIC (TODO!) + ::SetMapMode(GetHdc(), MM_ANISOTROPIC); - SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL); - m_windowExtX = (int)MS_XDEV2LOG(VIEWPORT_EXTENT); - m_windowExtY = (int)MS_YDEV2LOG(VIEWPORT_EXTENT); - ::SetWindowExtEx(GetHdc(), m_windowExtX, m_windowExtY, NULL); - ::SetViewportOrgEx(GetHdc(), (int)m_deviceOriginX, (int)m_deviceOriginY, NULL); - ::SetWindowOrgEx(GetHdc(), (int)m_logicalOriginX, (int)m_logicalOriginY, NULL); + int width = DeviceToLogicalXRel(VIEWPORT_EXTENT)*m_signX, + height = DeviceToLogicalYRel(VIEWPORT_EXTENT)*m_signY; + + ::SetViewportExtEx(GetHdc(), VIEWPORT_EXTENT, VIEWPORT_EXTENT, NULL); + ::SetWindowExtEx(GetHdc(), width, height, NULL); + + ::SetViewportOrgEx(GetHdc(), m_deviceOriginX, m_deviceOriginY, NULL); + ::SetWindowOrgEx(GetHdc(), m_logicalOriginX, m_logicalOriginY, NULL); } void wxDC::SetUserScale(double x, double y) @@ -1561,6 +1595,9 @@ void wxDC::SetUserScale(double x, double y) if (!GetHDC()) return; #endif + if ( x == m_userScaleX && y == m_userScaleY ) + return; + m_userScaleX = x; m_userScaleY = y; @@ -1573,10 +1610,16 @@ void wxDC::SetAxisOrientation(bool xLeftRight, bool yBottomUp) if (!GetHDC()) return; #endif - m_signX = xLeftRight ? 1 : -1; - m_signY = yBottomUp ? -1 : 1; + int signX = xLeftRight ? 1 : -1, + signY = yBottomUp ? -1 : 1; - SetMapMode(m_mappingMode); + if ( signX != m_signX || signY != m_signY ) + { + m_signX = signX; + m_signY = signY; + + SetMapMode(m_mappingMode); + } } void wxDC::SetSystemScale(double x, double y) @@ -1585,6 +1628,9 @@ void wxDC::SetSystemScale(double x, double y) if (!GetHDC()) return; #endif + if ( x == m_scaleX && y == m_scaleY ) + return; + m_scaleX = x; m_scaleY = y; @@ -1597,6 +1643,9 @@ void wxDC::SetLogicalOrigin(wxCoord x, wxCoord y) if (!GetHDC()) return; #endif + if ( x == m_logicalOriginX && y == m_logicalOriginY ) + return; + m_logicalOriginX = x; m_logicalOriginY = y; @@ -1609,6 +1658,9 @@ void wxDC::SetDeviceOrigin(wxCoord x, wxCoord y) if (!GetHDC()) return; #endif + if ( x == m_deviceOriginX && y == m_deviceOriginY ) + return; + m_deviceOriginX = x; m_deviceOriginY = y; @@ -1621,49 +1673,45 @@ void wxDC::SetDeviceOrigin(wxCoord x, wxCoord y) wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const { - double xRel = x - m_deviceOriginX; - xRel /= m_logicalScaleX*m_userScaleX*m_signX*m_scaleX; - return (wxCoord)(xRel + m_logicalOriginX); + return DeviceToLogicalXRel(x - m_deviceOriginX)*m_signX + m_logicalOriginX; } wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const { - // axis orientation is not taken into account for conversion of a distance - return (wxCoord) ((x)/(m_logicalScaleX*m_userScaleX*m_scaleX)); + // axis orientation is not taken into account for conversion of a distance + return (wxCoord)(x / (m_logicalScaleX*m_userScaleX*m_scaleX)); } wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const { - double yRel = y - m_deviceOriginY; - yRel /= m_logicalScaleY*m_userScaleY*m_signY*m_scaleY; - return (wxCoord)(yRel + m_logicalOriginY); + return DeviceToLogicalYRel(y - m_deviceOriginY)*m_signY + m_logicalOriginY; } wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const { - // axis orientation is not taken into account for conversion of a distance - return (wxCoord) ((y)/(m_logicalScaleY*m_userScaleY*m_scaleY)); + // axis orientation is not taken into account for conversion of a distance + return (wxCoord)( y / (m_logicalScaleY*m_userScaleY*m_scaleY)); } wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const { - return (wxCoord) ((x - m_logicalOriginX)*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX + m_deviceOriginX); + return LogicalToDeviceXRel(x - m_logicalOriginX)*m_signX + m_deviceOriginX; } wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const { - // axis orientation is not taken into account for conversion of a distance + // axis orientation is not taken into account for conversion of a distance return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_scaleX); } wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const { - return (wxCoord) ((y - m_logicalOriginY)*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY + m_deviceOriginY); + return LogicalToDeviceYRel(y - m_logicalOriginY)*m_signY + m_deviceOriginY; } wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const { - // axis orientation is not taken into account for conversion of a distance + // axis orientation is not taken into account for conversion of a distance return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_scaleY); } @@ -1875,8 +1923,30 @@ void wxDC::DoGetSizeMM(int *w, int *h) const if (!GetHDC()) return; #endif - if ( w ) *w = ::GetDeviceCaps(GetHdc(), HORZSIZE); - if ( h ) *h = ::GetDeviceCaps(GetHdc(), VERTSIZE); + // if we implement it in terms of DoGetSize() instead of directly using the + // results returned by GetDeviceCaps(HORZ/VERTSIZE) as was done before, it + // will also work for wxWindowDC and wxClientDC even though their size is + // not the same as the total size of the screen + int wPixels, hPixels; + DoGetSize(&wPixels, &hPixels); + + if ( w ) + { + int wTotal = ::GetDeviceCaps(GetHdc(), HORZRES); + + wxCHECK_RET( wTotal, _T("0 width device?") ); + + *w = (wPixels * ::GetDeviceCaps(GetHdc(), HORZSIZE)) / wTotal; + } + + if ( h ) + { + int hTotal = ::GetDeviceCaps(GetHdc(), VERTRES); + + wxCHECK_RET( hTotal, _T("0 height device?") ); + + *h = (hPixels * ::GetDeviceCaps(GetHdc(), VERTSIZE)) / hTotal; + } } wxSize wxDC::GetPPI() const