]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/bitmap.cpp
merged Ctrl-Space fix from 2.2 branch
[wxWidgets.git] / src / msw / bitmap.cpp
index 8eba1311e536c396c4b1e7069cd6767056e976ec..d5b37d2cfd284b9467ec8c5f75f74fbf082b9dcf 100644 (file)
 #include "wx/msw/dib.h"
 #include "wx/image.h"
 
+// missing from mingw32 header
+#ifndef CLR_INVALID
+    #define CLR_INVALID ((COLORREF)-1)
+#endif // no CLR_INVALID
+
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
 
-    IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
-    IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
+IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
+IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
 
-    IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
+IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
 
 // ============================================================================
 // implementation
@@ -81,7 +86,7 @@ void wxBitmapRefData::Free()
     {
         if ( !::DeleteObject((HBITMAP)m_hBitmap) )
         {
-            wxLogLastError("DeleteObject(hbitmap)");
+            wxLogLastError(wxT("DeleteObject(hbitmap)"));
         }
     }
 
@@ -112,7 +117,7 @@ bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon)
     ICONINFO iconInfo;
     if ( !::GetIconInfo(hicon, &iconInfo) )
     {
-        wxLogLastError("GetIconInfo");
+        wxLogLastError(wxT("GetIconInfo"));
 
         return FALSE;
     }
@@ -131,26 +136,8 @@ bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon)
 
     // the mask returned by GetIconInfo() is inversed compared to the usual
     // wxWin convention
-    HBITMAP hbmpMask = ::CreateBitmap(w, h, 1, 1, 0);
-
-    // the icons mask is opposite to the usual wxWin convention
-    HDC dcSrc = ::CreateCompatibleDC(NULL);
-    HDC dcDst = ::CreateCompatibleDC(NULL);
-    (void)SelectObject(dcSrc, iconInfo.hbmMask);
-    (void)SelectObject(dcDst, hbmpMask);
-
-    HBRUSH brush = ::CreateSolidBrush(RGB(255, 255, 255));
-    RECT rect = { 0, 0, w, h };
-    FillRect(dcDst, &rect, brush);
-
-    BitBlt(dcDst, 0, 0, w, h, dcSrc, 0, 0, SRCINVERT);
-
-    SelectObject(dcDst, NULL);
-    SelectObject(dcSrc, NULL);
-    DeleteDC(dcDst);
-    DeleteDC(dcSrc);
-
-    refData->m_bitmapMask = new wxMask((WXHBITMAP)hbmpMask);
+    refData->m_bitmapMask = new wxMask((WXHBITMAP)
+                                        wxInvertMask(iconInfo.hbmMask, w, h));
 
 #if WXWIN_COMPATIBILITY_2
     refData->m_ok = TRUE;
@@ -255,16 +242,22 @@ wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
 
         for ( int rows = 0; rows < height; rows++ )
         {
-            // note that offset cannot be size_t due to >= 0 test!
-            for ( int offset = bytesPerLine - 1; offset >= 0; offset-- )
+            for ( size_t cols = 0; cols < bytesPerLine; cols++ )
             {
-                *dst++ = *(src + offset);
+                unsigned char val = *src++;
+                unsigned char reversed = 0;
+
+                for ( int bits = 0; bits < 8; bits++)
+                {
+                    reversed <<= 1;
+                    reversed |= (val & 0x01);
+                    val >>= 1;
+                }
+                *dst++ = reversed;
             }
 
             if ( padding )
                 *dst++ = 0;
-
-            src += bytesPerLine;
         }
     }
     else
@@ -276,7 +269,7 @@ wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
     HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data);
     if ( !hbmp )
     {
-        wxLogLastError("CreateBitmap");
+        wxLogLastError(wxT("CreateBitmap"));
     }
 
     if ( data != bits )
@@ -287,52 +280,12 @@ wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
     SetHBITMAP((WXHBITMAP)hbmp);
 }
 
-// GRG, Dic/99
-wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
-{
-    wxCHECK_MSG( Ok() &&
-                 (rect.x >= 0) && (rect.y >= 0) &&
-                 (rect.x+rect.width <= GetWidth()) &&
-                 (rect.y+rect.height <= GetHeight()),
-                 wxNullBitmap, wxT("Invalid bitmap or bitmap region") );
-
-    wxBitmap ret( rect.width, rect.height, GetDepth() );
-    wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
-
-    // copy bitmap data
-    HDC dcSrc = ::CreateCompatibleDC(NULL);
-    HDC dcDst = ::CreateCompatibleDC(NULL);
-    SelectObject(dcSrc, (HBITMAP) GetHBITMAP());
-    SelectObject(dcDst, (HBITMAP) ret.GetHBITMAP());
-    BitBlt(dcDst, 0, 0, rect.width, rect.height, dcSrc, rect.x, rect.y, SRCCOPY);
-
-    // copy mask if there is one
-    if (GetMask())
-    {
-        HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0);
-
-        SelectObject(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap());
-        SelectObject(dcDst, (HBITMAP) hbmpMask);
-        BitBlt(dcDst, 0, 0, rect.width, rect.height, dcSrc, rect.x, rect.y, SRCCOPY);
-
-        wxMask *mask = new wxMask((WXHBITMAP) hbmpMask);
-        ret.SetMask(mask);
-    }
-
-    SelectObject(dcDst, NULL);
-    SelectObject(dcSrc, NULL);
-    DeleteDC(dcDst);
-    DeleteDC(dcSrc);
-
-    return ret;
-}
-
 // Create from XPM data
-wxBitmap::wxBitmap(char **data, wxControl *WXUNUSED(anItem))
+bool wxBitmap::CreateFromXpm(const char **data)
 {
     Init();
 
-    (void)Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0);
+    return Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0);
 }
 
 wxBitmap::wxBitmap(int w, int h, int d)
@@ -373,7 +326,7 @@ bool wxBitmap::Create(int w, int h, int d)
         hbmp = ::CreateBitmap(w, h, 1, d, NULL);
         if ( !hbmp )
         {
-            wxLogLastError("CreateBitmap");
+            wxLogLastError(wxT("CreateBitmap"));
         }
     }
     else
@@ -382,7 +335,7 @@ bool wxBitmap::Create(int w, int h, int d)
         hbmp = ::CreateCompatibleBitmap(dc, w, h);
         if ( !hbmp )
         {
-            wxLogLastError("CreateCompatibleBitmap");
+            wxLogLastError(wxT("CreateCompatibleBitmap"));
         }
 
         GetBitmapData()->m_depth = wxDisplayDepth();
@@ -429,8 +382,7 @@ bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
 
     if ( !handler )
     {
-        wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for "
-                       "type %d defined."), type);
+        wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %d defined."), type);
 
         return FALSE;
     }
@@ -459,6 +411,49 @@ bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *pal
     }
 }
 
+// ----------------------------------------------------------------------------
+// sub bitmap extraction
+// ----------------------------------------------------------------------------
+
+wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
+{
+    wxCHECK_MSG( Ok() &&
+                 (rect.x >= 0) && (rect.y >= 0) &&
+                 (rect.x+rect.width <= GetWidth()) &&
+                 (rect.y+rect.height <= GetHeight()),
+                 wxNullBitmap, wxT("Invalid bitmap or bitmap region") );
+
+    wxBitmap ret( rect.width, rect.height, GetDepth() );
+    wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
+
+    // copy bitmap data
+    HDC dcSrc = ::CreateCompatibleDC(NULL);
+    HDC dcDst = ::CreateCompatibleDC(NULL);
+    SelectObject(dcSrc, (HBITMAP) GetHBITMAP());
+    SelectObject(dcDst, (HBITMAP) ret.GetHBITMAP());
+    BitBlt(dcDst, 0, 0, rect.width, rect.height, dcSrc, rect.x, rect.y, SRCCOPY);
+
+    // copy mask if there is one
+    if (GetMask())
+    {
+        HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0);
+
+        SelectObject(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap());
+        SelectObject(dcDst, (HBITMAP) hbmpMask);
+        BitBlt(dcDst, 0, 0, rect.width, rect.height, dcSrc, rect.x, rect.y, SRCCOPY);
+
+        wxMask *mask = new wxMask((WXHBITMAP) hbmpMask);
+        ret.SetMask(mask);
+    }
+
+    SelectObject(dcDst, NULL);
+    SelectObject(dcSrc, NULL);
+    DeleteDC(dcDst);
+    DeleteDC(dcSrc);
+
+    return ret;
+}
+
 // ----------------------------------------------------------------------------
 // wxBitmap accessors
 // ----------------------------------------------------------------------------
@@ -500,7 +495,7 @@ void wxBitmap::SetMask(wxMask *mask)
 wxBitmap wxBitmap::GetBitmapForDC(wxDC& dc) const
 {
     wxMemoryDC      memDC;
-    wxBitmap        tmpBitmap(this->GetWidth(), this->GetHeight(), dc.GetDepth());
+    wxBitmap        tmpBitmap(GetWidth(), GetHeight(), dc.GetDepth());
     HPALETTE        hPal = (HPALETTE) NULL;
     LPBITMAPINFO    lpDib;
     void            *lpBits = (void*) NULL;
@@ -586,15 +581,15 @@ wxMask::~wxMask()
 // Create a mask from a mono bitmap (copies the bitmap).
 bool wxMask::Create(const wxBitmap& bitmap)
 {
+    wxCHECK_MSG( bitmap.Ok() && bitmap.GetDepth() == 1, FALSE,
+                 _T("can't create mask from invalid or not monochrome bitmap") );
+
     if ( m_maskBitmap )
     {
         ::DeleteObject((HBITMAP) m_maskBitmap);
         m_maskBitmap = 0;
     }
-    if (!bitmap.Ok() || bitmap.GetDepth() != 1)
-    {
-        return FALSE;
-    }
+
     m_maskBitmap = (WXHBITMAP) CreateBitmap(
                                             bitmap.GetWidth(),
                                             bitmap.GetHeight(),
@@ -637,38 +632,65 @@ bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex)
 // the transparent area
 bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
 {
+    wxCHECK_MSG( bitmap.Ok(), FALSE, _T("invalid bitmap in wxMask::Create") );
+
     if ( m_maskBitmap )
     {
         ::DeleteObject((HBITMAP) m_maskBitmap);
         m_maskBitmap = 0;
     }
-    if (!bitmap.Ok())
+
+    int width = bitmap.GetWidth(),
+        height = bitmap.GetHeight();
+
+    // scan the bitmap for the transparent colour and set the corresponding
+    // pixels in the mask to BLACK and the rest to WHITE
+    COLORREF maskColour = wxColourToRGB(colour);
+    m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0);
+
+    HDC srcDC = ::CreateCompatibleDC(NULL);
+    HDC destDC = ::CreateCompatibleDC(NULL);
+    if ( !srcDC || !destDC )
     {
-        return FALSE;
+        wxLogLastError(wxT("CreateCompatibleDC"));
     }
 
-    // scan the bitmap for the transparent colour and set
-    // the corresponding pixels in the mask to BLACK and
-    // the rest to WHITE
-    COLORREF maskColour = RGB(colour.Red(), colour.Green(), colour.Blue());
-    m_maskBitmap = (WXHBITMAP) ::CreateBitmap(
-            bitmap.GetWidth(),
-            bitmap.GetHeight(),
-            1, 1, 0
-                                             );
-    HDC srcDC = ::CreateCompatibleDC(0);
-    ::SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP());
-    HDC destDC = ::CreateCompatibleDC(0);
-    ::SelectObject(destDC, (HBITMAP) m_maskBitmap);
-
-    // this is not very efficient, but I can't think
-    // of a better way of doing it
-    for (int w = 0; w < bitmap.GetWidth(); w++)
+    bool ok = TRUE;
+
+    HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap));
+    if ( !hbmpSrcOld )
     {
-        for (int h = 0; h < bitmap.GetHeight(); h++)
+        wxLogLastError(wxT("SelectObject"));
+
+        ok = FALSE;
+    }
+
+    HGDIOBJ hbmpDstOld = ::SelectObject(destDC, (HBITMAP)m_maskBitmap);
+    if ( !hbmpDstOld )
+    {
+        wxLogLastError(wxT("SelectObject"));
+
+        ok = FALSE;
+    }
+
+    // this is not very efficient, but I can't think of a better way of doing
+    // it
+    for ( int w = 0; ok && (w < width); w++ )
+    {
+        for ( int h = 0; ok && (h < height); h++ )
         {
             COLORREF col = GetPixel(srcDC, w, h);
-            if (col == maskColour)
+            if ( col == CLR_INVALID )
+            {
+                wxLogLastError(wxT("GetPixel"));
+
+                // doesn't make sense to continue
+                ok = FALSE;
+
+                break;
+            }
+
+            if ( col == maskColour )
             {
                 ::SetPixel(destDC, w, h, RGB(0, 0, 0));
             }
@@ -678,11 +700,13 @@ bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour)
             }
         }
     }
-    ::SelectObject(srcDC, 0);
+
+    ::SelectObject(srcDC, hbmpSrcOld);
     ::DeleteDC(srcDC);
-    ::SelectObject(destDC, 0);
+    ::SelectObject(destDC, hbmpDstOld);
     ::DeleteDC(destDC);
-    return TRUE;
+
+    return ok;
 }
 
 // ----------------------------------------------------------------------------
@@ -696,7 +720,7 @@ bool wxBitmapHandler::Create(wxGDIImage *image,
 {
     wxBitmap *bitmap = wxDynamicCast(image, wxBitmap);
 
-    return bitmap ? Create(bitmap, data, width, height, depth) : FALSE;
+    return bitmap ? Create(bitmap, data, flags, width, height, depth) : FALSE;
 }
 
 bool wxBitmapHandler::Load(wxGDIImage *image,
@@ -797,4 +821,47 @@ void wxFreeDIB(LPBITMAPINFO lpDIBHeader)
     free(lpDIBHeader);
 }
 
+// ----------------------------------------------------------------------------
+// other helper functions
+// ----------------------------------------------------------------------------
+
+extern HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h)
+{
+    wxCHECK_MSG( hbmpMask, 0, _T("invalid bitmap in wxInvertMask") );
+
+    // get width/height from the bitmap if not given
+    if ( !w || !h )
+    {
+        BITMAP bm;
+        ::GetObject(hbmpMask, sizeof(BITMAP), (LPVOID)&bm);
+        w = bm.bmWidth;
+        h = bm.bmHeight;
+    }
+
+    HDC hdcSrc = ::CreateCompatibleDC(NULL);
+    HDC hdcDst = ::CreateCompatibleDC(NULL);
+    if ( !hdcSrc || !hdcDst )
+    {
+        wxLogLastError(wxT("CreateCompatibleDC"));
+    }
 
+    HBITMAP hbmpInvMask = ::CreateBitmap(w, h, 1, 1, 0);
+    if ( !hbmpInvMask )
+    {
+        wxLogLastError(wxT("CreateBitmap"));
+    }
+
+    ::SelectObject(hdcSrc, hbmpMask);
+    ::SelectObject(hdcDst, hbmpInvMask);
+    if ( !::BitBlt(hdcDst, 0, 0, w, h,
+                   hdcSrc, 0, 0,
+                   NOTSRCCOPY) )
+    {
+        wxLogLastError(wxT("BitBlt"));
+    }
+
+    ::DeleteDC(hdcSrc);
+    ::DeleteDC(hdcDst);
+
+    return hbmpInvMask;
+}