]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/dc.cpp
got rid of wxWindow::m_lDlgCode - now wxWANTS_CHARS style should work for all windows...
[wxWidgets.git] / src / msw / dc.cpp
index 406f0f2a1edb84542af5d775f16f598e5df1e214..bfc738c185ff28c84610f0071570cd2474cb6792 100644 (file)
@@ -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 )
@@ -279,7 +295,7 @@ void wxDC::UpdateClipBox()
 #endif
 
     RECT rect;
-    GetClipBox(GetHdc(), &rect);
+    ::GetClipBox(GetHdc(), &rect);
 
     m_clipX1 = (wxCoord) XDEV2LOG(rect.left);
     m_clipY1 = (wxCoord) YDEV2LOG(rect.top);
@@ -287,14 +303,50 @@ void wxDC::UpdateClipBox()
     m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom);
 }
 
-void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
+// common part of DoSetClippingRegion() and DoSetClippingRegionAsRegion()
+void wxDC::SetClippingHrgn(WXHRGN hrgn)
 {
+    wxCHECK_RET( hrgn, wxT("invalid clipping region") );
+
 #ifdef __WXMICROWIN__
-    if (!GetHDC()) return;
-#endif
+    if (!GetHdc()) return;
+#endif // __WXMICROWIN__
+
+    // note that we combine the new clipping region with the existing one: this
+    // is compatible with what the other ports do and is the documented
+    // behaviour now (starting with 2.3.3)
+#ifdef __WIN16__
+    RECT rectClip;
+    if ( !::GetClipBox(GetHdc(), &rectClip) )
+        return;
+
+    HRGN hrgnDest = ::CreateRectRgn(0, 0, 0, 0);
+    HRGN hrgnClipOld = ::CreateRectRgn(rectClip.left, rectClip.top,
+                                       rectClip.right, rectClip.bottom);
+
+    if ( ::CombineRgn(hrgnDest, hrgnClipOld, (HRGN)hrgn, RGN_AND) != ERROR )
+    {
+        ::SelectClipRgn(GetHdc(), hrgnDest);
+    }
+
+    ::DeleteObject(hrgnClipOld);
+    ::DeleteObject(hrgnDest);
+#else // Win32
+    if ( ::ExtSelectClipRgn(GetHdc(), (HRGN)hrgn, RGN_AND) == ERROR )
+    {
+        wxLogLastError(_T("ExtSelectClipRgn"));
+
+        return;
+    }
+#endif // Win16/32
 
     m_clipping = TRUE;
 
+    UpdateClipBox();
+}
+
+void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
+{
     // the region coords are always the device ones, so do the translation
     // manually
     //
@@ -309,33 +361,15 @@ void wxDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
     }
     else
     {
-        if ( ::SelectClipRgn(GetHdc(), hrgn) == ERROR )
-        {
-            wxLogLastError(_T("SelectClipRgn"));
-        }
-        DeleteObject(hrgn);
+        SetClippingHrgn((WXHRGN)hrgn);
 
-        UpdateClipBox();
+        ::DeleteObject(hrgn);
     }
 }
 
 void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
 {
-#ifdef __WXMICROWIN__
-    if (!GetHDC()) return;
-#endif
-
-    wxCHECK_RET( GetHrgnOf(region), wxT("invalid clipping region") );
-
-    m_clipping = TRUE;
-
-#ifdef __WIN16__
-    SelectClipRgn(GetHdc(), GetHrgnOf(region));
-#else // Win32
-    ExtSelectClipRgn(GetHdc(), GetHrgnOf(region), RGN_AND);
-#endif // Win16/32
-
-    UpdateClipBox();
+    SetClippingHrgn(region.GetHRGN());
 }
 
 void wxDC::DestroyClippingRegion()
@@ -347,11 +381,12 @@ void wxDC::DestroyClippingRegion()
     if (m_clipping && m_hDC)
     {
         // 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 DestroyClippingRegion.
+        //       so that OnPaint processing works correctly, and the update
+        //       clipping region doesn't get destroyed after the first
+        //       DestroyClippingRegion.
         HRGN rgn = CreateRectRgn(0, 0, 32000, 32000);
-        SelectClipRgn(GetHdc(), rgn);
-        DeleteObject(rgn);
+        ::SelectClipRgn(GetHdc(), rgn);
+        ::DeleteObject(rgn);
     }
 
     m_clipping = FALSE;
@@ -418,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);
 }
@@ -505,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);
 }
@@ -1404,7 +1438,7 @@ wxCoord wxDC::GetCharHeight() const
 
     GetTextMetrics(GetHdc(), &lpTextMetric);
 
-    return YDEV2LOGREL(lpTextMetric.tmHeight);
+    return lpTextMetric.tmHeight;
 }
 
 wxCoord wxDC::GetCharWidth() const
@@ -1417,7 +1451,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,
@@ -1453,10 +1487,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 )
     {
@@ -1472,68 +1510,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)
@@ -1542,6 +1579,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;
 
@@ -1554,10 +1594,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)
@@ -1566,6 +1612,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;
 
@@ -1578,6 +1627,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;
 
@@ -1590,6 +1642,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;
 
@@ -1602,49 +1657,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);
 }