]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/dc.cpp
Clean-up, speed-up and bug-fix for wxListCtrl drawing,
[wxWidgets.git] / src / msw / dc.cpp
index f4657caf107ee57813cb587d57aa32f8837b3894..354c617418ff9d75cc5c0cbc288e050df19d43cb 100644 (file)
@@ -48,9 +48,6 @@
 #include "wx/msw/private.h" // needs to be before #include <commdlg.h>
 
 #if wxUSE_COMMON_DIALOGS
-#if wxUSE_NORLANDER_HEADERS
-    #include <windows.h>
-#endif
     #include <commdlg.h>
 #endif
 
@@ -74,6 +71,10 @@ static const int MM_METRIC = 10;
     static const double M_PI = 3.14159265358979323846;
 #endif // M_PI
 
+// ROPs which don't have standard names (see "Ternary Raster Operations" in the
+// MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
+#define DSTCOPY 0x00AA0029      // a.k.a. NOP operation
+
 // ---------------------------------------------------------------------------
 // private functions
 // ---------------------------------------------------------------------------
@@ -317,12 +318,15 @@ bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
     // get the color of the pixel
     COLORREF pixelcolor = ::GetPixel(GetHdc(), XLOG2DEV(x), YLOG2DEV(y));
 
+    // JACS: what was this for?
+#if 0
     // get the color of the pen
     COLORREF pencolor = 0x00ffffff;
     if (m_pen.Ok())
     {
         pencolor = m_pen.GetColour().GetPixel();
     }
+#endif
 
     // return the color of the pixel
     if( col )
@@ -334,7 +338,10 @@ bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
 
     // check, if color of the pixels is the same as the color of the current
     // pen and return TRUE if it is, FALSE otherwise
-    return pixelcolor == pencolor;
+    // JACS, 24/02/2000: can't understand the reason for this, so returning TRUE instead.
+    // return pixelcolor == pencolor;
+
+    return TRUE;
 }
 
 void wxDC::DoCrossHair(wxCoord x, wxCoord y)
@@ -359,10 +366,9 @@ 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));
 
-    /* MATTHEW: [6] New normalization */
-#if WX_STANDARD_GRAPHICS
-    (void)LineTo(GetHdc(), XLOG2DEV(x2) + 1, YLOG2DEV(y2));
-#endif
+    // 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);
@@ -410,6 +416,41 @@ void wxDC::DoDrawArc(wxCoord x1,wxCoord y1,wxCoord x2,wxCoord y2, wxCoord xc, wx
     CalcBoundingBox((wxCoord)(xc+radius), (wxCoord)(yc+radius));
 }
 
+void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
+                           wxCoord width, wxCoord height)
+{
+    wxCoord x2 = x1 + width,
+            y2 = y1 + height;
+
+#if defined(__WIN32__) && !defined(__SC__)
+    RECT rect;
+    rect.left   = x1;
+    rect.top    = y1;
+    rect.right  = x2;
+    rect.bottom = y2;
+
+    DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK);
+#else // Win16
+    // In WIN16, 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);
+    MoveTo(GetHdc(), x1, y1);
+    LineTo(GetHdc(), x2, y2);
+    MoveTo(GetHdc(), x2, y1);
+    LineTo(GetHdc(), x1, y2);
+    ::SelectObject(GetHdc(), hPenOld);
+    ::SelectObject(GetHdc(), hBrushOld);
+    ::DeleteObject(blackPen);
+#endif // Win32/16
+
+    CalcBoundingBox(x1, y1);
+    CalcBoundingBox(x2, y2);
+}
+
 void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
 {
     COLORREF color = 0x00ffffff;
@@ -541,16 +582,31 @@ void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
     wxCoord x2 = x + width;
     wxCoord y2 = y + height;
 
-    // Windows draws the filled rectangles without outline (i.e. drawn with a
-    // transparent pen) one pixel smaller in both directions and we want them
-    // to have the same size regardless of which pen is used - adjust
-    if ( m_pen.GetStyle() == wxTRANSPARENT )
+    if ((m_logicalFunction == wxCOPY) && (m_pen.GetStyle() == wxTRANSPARENT))
     {
-        x2++;
-        y2++;
+        RECT rect;
+        rect.left = XLOG2DEV(x);
+        rect.top = YLOG2DEV(y);
+        rect.right = XLOG2DEV(x2);
+        rect.bottom = YLOG2DEV(y2);
+        (void)FillRect(GetHdc(), &rect, (HBRUSH)m_brush.GetResourceHandle() );
+    }
+    else
+    {
+        // Windows draws the filled rectangles without outline (i.e. drawn with a
+        // transparent pen) one pixel smaller in both directions and we want them
+           // to have the same size regardless of which pen is used - adjust
+
+        // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR.
+        if ( m_pen.GetStyle() == wxTRANSPARENT )
+        {
+            x2++;
+            y2++;
+        }
+
+           (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
     }
 
-    (void)Rectangle(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2), YLOG2DEV(y2));
 
     CalcBoundingBox(x, y);
     CalcBoundingBox(x2, y2);
@@ -582,6 +638,15 @@ void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord h
     wxCoord x2 = (x+width);
     wxCoord y2 = (y+height);
 
+    // Windows draws the filled rectangles without outline (i.e. drawn with a
+    // transparent pen) one pixel smaller in both directions and we want them
+    // to have the same size regardless of which pen is used - adjust
+    if ( m_pen.GetStyle() == wxTRANSPARENT )
+    {
+        x2++;
+        y2++;
+    }
+
     (void)RoundRect(GetHdc(), XLOG2DEV(x), YLOG2DEV(y), XLOG2DEV(x2),
         YLOG2DEV(y2), (int) (2*XLOG2DEV(radius)), (int)( 2*YLOG2DEV(radius)));
 
@@ -657,7 +722,50 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask
     int width = bmp.GetWidth(),
         height = bmp.GetHeight();
 
-    if ( !useMask )
+    HBITMAP hbmpMask = 0;
+
+    if ( useMask )
+    {
+        wxMask *mask = bmp.GetMask();
+        if ( mask )
+            hbmpMask = (HBITMAP)mask->GetMaskBitmap();
+
+        if ( !hbmpMask )
+        {
+            // don't give assert here because this would break existing
+            // programs - just silently ignore useMask parameter
+            useMask = FALSE;
+        }
+    }
+
+    if ( useMask )
+    {
+#ifdef __WIN32__
+        HDC hdcMem = ::CreateCompatibleDC(GetHdc());
+        ::SelectObject(hdcMem, GetHbitmapOf(bmp));
+
+        // use MaskBlt() with ROP which doesn't do anything to dst in the mask
+        // points
+        bool ok = ::MaskBlt(GetHdc(), x, y, width, height,
+                            hdcMem, 0, 0,
+                            hbmpMask, 0, 0,
+                            MAKEROP4(SRCCOPY, DSTCOPY)) != 0;
+        ::DeleteDC(hdcMem);
+
+        if ( !ok )
+#endif // Win32
+        {
+            // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
+            // level
+            wxMemoryDC memDC;
+            memDC.SelectObject(bmp);
+
+            Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
+
+            memDC.SelectObject(wxNullBitmap);
+        }
+    }
+    else // no mask, just use BitBlt()
     {
         HDC cdc = GetHdc();
         HDC memdc = ::CreateCompatibleDC( cdc );
@@ -683,16 +791,6 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask
         ::SetTextColor(GetHdc(), old_textground);
         ::SetBkColor(GetHdc(), old_background);
     }
-    else
-    {
-        // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
-        wxMemoryDC memDC;
-        memDC.SelectObject(bmp);
-
-        Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
-
-        memDC.SelectObject(wxNullBitmap);
-    }
 }
 
 void wxDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y)
@@ -778,6 +876,7 @@ void wxDC::DoDrawRotatedText(const wxString& text,
             DrawAnyText(text, x, y);
 
             (void)::SelectObject(GetHdc(), hfontOld);
+            (void)::DeleteObject(hfont);
         }
 
         // call the bounding box by adding all four vertices of the rectangle
@@ -991,37 +1090,41 @@ void wxDC::SetLogicalFunction(int function)
 {
     m_logicalFunction = function;
 
-    SetRop((WXHDC) m_hDC);
+    SetRop(m_hDC);
 }
 
 void wxDC::SetRop(WXHDC dc)
 {
-    if (!dc || m_logicalFunction < 0)
+    if ( !dc || m_logicalFunction < 0 )
         return;
 
-    int c_rop;
-    // These may be wrong
+    int rop;
+
     switch (m_logicalFunction)
     {
-        //    case wxXOR: c_rop = R2_XORPEN; break;
-    case wxXOR: c_rop = R2_NOTXORPEN; break;
-    case wxINVERT: c_rop = R2_NOT; break;
-    case wxOR_REVERSE: c_rop = R2_MERGEPENNOT; break;
-    case wxAND_REVERSE: c_rop = R2_MASKPENNOT; break;
-    case wxCLEAR: c_rop = R2_WHITE; break;
-    case wxSET: c_rop = R2_BLACK; break;
-    case wxSRC_INVERT: c_rop = R2_NOTCOPYPEN; break;
-    case wxOR_INVERT: c_rop = R2_MERGENOTPEN; break;
-    case wxAND: c_rop = R2_MASKPEN; break;
-    case wxOR: c_rop = R2_MERGEPEN; break;
-    case wxAND_INVERT: c_rop = R2_MASKNOTPEN; break;
-    case wxEQUIV:
-    case wxNAND:
-    case wxCOPY:
-    default:
-        c_rop = R2_COPYPEN; break;
+        case wxCLEAR:        rop = R2_BLACK;         break;
+        case wxXOR:          rop = R2_XORPEN;        break;
+        case wxINVERT:       rop = R2_NOT;           break;
+        case wxOR_REVERSE:   rop = R2_MERGEPENNOT;   break;
+        case wxAND_REVERSE:  rop = R2_MASKPENNOT;    break;
+        case wxCOPY:         rop = R2_COPYPEN;       break;
+        case wxAND:          rop = R2_MASKPEN;       break;
+        case wxAND_INVERT:   rop = R2_MASKNOTPEN;    break;
+        case wxNO_OP:        rop = R2_NOP;           break;
+        case wxNOR:          rop = R2_NOTMERGEPEN;   break;
+        case wxEQUIV:        rop = R2_NOTXORPEN;     break;
+        case wxSRC_INVERT:   rop = R2_NOTCOPYPEN;    break;
+        case wxOR_INVERT:    rop = R2_MERGENOTPEN;   break;
+        case wxNAND:         rop = R2_NOTMASKPEN;    break;
+        case wxOR:           rop = R2_MERGEPEN;      break;
+        case wxSET:          rop = R2_WHITE;         break;
+
+        default:
+           wxFAIL_MSG( wxT("unsupported logical function") );
+           return;
     }
-    SetROP2((HDC) dc, c_rop);
+
+    SetROP2(GetHdc(), rop);
 }
 
 bool wxDC::StartDoc(const wxString& message)
@@ -1270,41 +1373,43 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest,
         ::SetBkColor(GetHdc(), m_textBackgroundColour.GetPixel() );
     }
 
-    DWORD dwRop = rop == wxCOPY ? SRCCOPY :
-                  rop == wxCLEAR ? WHITENESS :
-                  rop == wxSET ? BLACKNESS :
-                  rop == wxINVERT ? DSTINVERT :
-                  rop == wxAND ? MERGECOPY :
-                  rop == wxOR ? MERGEPAINT :
-                  rop == wxSRC_INVERT ? NOTSRCCOPY :
-                  rop == wxXOR ? SRCINVERT :
-                  rop == wxOR_REVERSE ? MERGEPAINT :
-                  rop == wxAND_REVERSE ? SRCERASE :
-                  rop == wxSRC_OR ? SRCPAINT :
-                  rop == wxSRC_AND ? SRCAND :
-                  SRCCOPY;
+    DWORD dwRop = SRCCOPY;
+    switch (rop)
+    {
+        case wxXOR:          dwRop = SRCINVERT;        break;
+        case wxINVERT:       dwRop = DSTINVERT;        break;
+        case wxOR_REVERSE:   dwRop = 0x00DD0228;       break;
+        case wxAND_REVERSE:  dwRop = SRCERASE;         break;
+        case wxCLEAR:        dwRop = BLACKNESS;        break;
+        case wxSET:          dwRop = WHITENESS;        break;
+        case wxOR_INVERT:    dwRop = MERGEPAINT;       break;
+        case wxAND:          dwRop = SRCAND;           break;
+        case wxOR:           dwRop = SRCPAINT;         break;
+        case wxEQUIV:        dwRop = 0x00990066;       break;
+        case wxNAND:         dwRop = 0x007700E6;       break;
+        case wxAND_INVERT:   dwRop = 0x00220326;       break;
+        case wxCOPY:         dwRop = SRCCOPY;          break;
+        case wxNO_OP:        dwRop = DSTCOPY;          break;
+        case wxSRC_INVERT:   dwRop = NOTSRCCOPY;       break;
+        case wxNOR:          dwRop = NOTSRCCOPY;       break;
+        default:
+           wxFAIL_MSG( wxT("unsupported logical function") );
+           return FALSE;
+    }
 
     bool success;
 
     if (useMask)
     {
 #ifdef __WIN32__
-        HBITMAP hbmpMask = wxInvertMask((HBITMAP)mask->GetMaskBitmap());
-
         // we want the part of the image corresponding to the mask to be
-        // transparent, i.e. do PATCOPY there and apply dwRop elsewhere
-        const wxColour& colBg = m_backgroundBrush.GetColour();
-        HBRUSH hbrBg = (HBRUSH)::CreateSolidBrush(wxColourToRGB(colBg));
-        HBRUSH hbrOld = (HBRUSH)::SelectObject(GetHdc(), hbrBg);
-
+        // transparent, so use "DSTCOPY" ROP for the mask points (the usual
+        // meaning of fg and bg is inverted which corresponds to wxWin notion
+        // of the mask which is also contrary to the Windows one)
         success = ::MaskBlt(GetHdc(), xdest, ydest, width, height,
                             GetHdcOf(*source), xsrc, ysrc,
-                            hbmpMask, 0, 0,
-                            MAKEROP4(PATCOPY, dwRop)) != 0;
-
-        (void)::SelectObject(GetHdc(), hbrOld);
-        ::DeleteObject(hbrOld);
-        ::DeleteObject(hbmpMask);
+                            (HBITMAP)mask->GetMaskBitmap(), 0, 0,
+                            MAKEROP4(dwRop, DSTCOPY)) != 0;
 
         if ( !success )
 #endif // Win32
@@ -1379,7 +1484,6 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest,
             wxLogLastError("BitBlt");
         }
     }
-
     ::SetTextColor(GetHdc(), old_textground);
     ::SetBkColor(GetHdc(), old_background);