[COMCTL32] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / dll / win32 / comctl32 / imagelist.c
index dbbb494..ff35fd4 100644 (file)
@@ -33,7 +33,7 @@
  *
  *  TODO:
  *    - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
- *    - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE
+ *    - Add support for ILS_GLOW, ILS_SHADOW
  *    - Thread-safe locking
  */
 
@@ -586,6 +586,7 @@ ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
                     INT dxHotspot, INT dyHotspot)
 {
     INT cx, cy;
+    POINT src, dst;
 
     TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
          dxHotspot, dyHotspot);
@@ -593,8 +594,11 @@ ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
     if (!is_valid(himlTrack))
        return FALSE;
 
+    if (iTrack >= himlTrack->cCurImage)
+        return FALSE;
+
     if (InternalDrag.himl)
-        ImageList_EndDrag ();
+        return FALSE;
 
     cx = himlTrack->cx;
     cy = himlTrack->cy;
@@ -609,10 +613,12 @@ ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
     InternalDrag.dyHotspot = dyHotspot;
 
     /* copy image */
-    BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
-
-    /* copy mask */
-    BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
+    imagelist_point_from_index(InternalDrag.himl, 0, &dst);
+    imagelist_point_from_index(himlTrack, iTrack, &src);
+    BitBlt(InternalDrag.himl->hdcImage, dst.x, dst.y, cx, cy, himlTrack->hdcImage, src.x, src.y,
+            SRCCOPY);
+    BitBlt(InternalDrag.himl->hdcMask, dst.x, dst.y, cx, cy, himlTrack->hdcMask, src.x, src.y,
+            SRCCOPY);
 
     InternalDrag.himl->cCurImage = 1;
 
@@ -1227,7 +1233,7 @@ ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
 }
 
 
-static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
+static BOOL alpha_blend_image( HIMAGELIST himl, HDC srce_dc, HDC dest_dc, int dest_x, int dest_y,
                                int src_x, int src_y, int cx, int cy, BLENDFUNCTION func,
                                UINT style, COLORREF blend_col )
 {
@@ -1252,9 +1258,9 @@ static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int des
     info->bmiHeader.biYPelsPerMeter = 0;
     info->bmiHeader.biClrUsed = 0;
     info->bmiHeader.biClrImportant = 0;
-    if (!(bmp = CreateDIBSection( himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
+    if (!(bmp = CreateDIBSection( srce_dc, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
     SelectObject( hdc, bmp );
-    BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );
+    BitBlt( hdc, 0, 0, cx, cy, srce_dc, src_x, src_y, SRCCOPY );
 
     if (blend_col != CLR_NONE)
     {
@@ -1327,6 +1333,66 @@ done:
     return ret;
 }
 
+HDC saturate_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
+                    int src_x, int src_y, int cx, int cy, COLORREF rgbFg)
+{
+    HDC hdc = NULL;
+    HBITMAP bmp = 0;
+    BITMAPINFO *info;
+
+    unsigned int *ptr;
+    void *bits;
+    int i;
+
+    /* create a dc and its device independent bitmap for doing the work,
+       shamelessly copied from the alpha-blending function above */
+    if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
+    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    info->bmiHeader.biWidth = cx;
+    info->bmiHeader.biHeight = cy;
+    info->bmiHeader.biPlanes = 1;
+    info->bmiHeader.biBitCount = 32;
+    info->bmiHeader.biCompression = BI_RGB;
+    info->bmiHeader.biSizeImage = cx * cy * 4;
+    info->bmiHeader.biXPelsPerMeter = 0;
+    info->bmiHeader.biYPelsPerMeter = 0;
+    info->bmiHeader.biClrUsed = 0;
+    info->bmiHeader.biClrImportant = 0;
+    if (!(bmp = CreateDIBSection(himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
+
+    /* bind both surfaces */
+    SelectObject(hdc, bmp);
+
+    /* copy into our dc the section that covers just the icon we we're asked for */
+    BitBlt(hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY);
+
+    /* loop every pixel of the bitmap */
+    for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
+    {
+        COLORREF orig_color = *ptr;
+
+        /* calculate the effective luminance using the constants from here, adapted to the human eye:
+           <http://bobpowell.net/grayscale.aspx> */
+        float mixed_color = (GetRValue(orig_color) * .30 +
+                             GetGValue(orig_color) * .59 +
+                             GetBValue(orig_color) * .11);
+
+        *ptr = RGBA(mixed_color, mixed_color, mixed_color, GetAValue(orig_color));
+    }
+
+done:
+
+    if (bmp)
+        DeleteObject(bmp);
+
+    if (info)
+        HeapFree(GetProcessHeap(), 0, info);
+
+    /* return the handle to our desaturated dc, that will substitute its original counterpart in the next calls */
+    return hdc;
+}
+
 /*************************************************************************
  * ImageList_DrawIndirect [COMCTL32.@]
  *
@@ -1403,6 +1469,21 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
     oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
     oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
 
+    /*
+     * If the ILS_SATURATE bit is enabled we should multiply the
+     * RGB colors of the original image by the contents of rgbFg.
+     */
+    if (fState & ILS_SATURATE)
+    {
+        hImageListDC = saturate_image(himl, pimldp->hdcDst, pimldp->x, pimldp->y,
+                                      pt.x, pt.y, cx, cy, pimldp->rgbFg);
+
+        /* shitty way of getting subroutines to blit at the right place (top left corner),
+           as our modified imagelist only contains a single image for performance reasons */
+        pt.x = 0;
+        pt.y = 0;
+    }
+
     has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
     if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
     {
@@ -1423,7 +1504,7 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
 
         if (bIsTransparent)
         {
-            bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
+            bResult = alpha_blend_image( himl, hImageListDC, pimldp->hdcDst, pimldp->x, pimldp->y,
                                          pt.x, pt.y, cx, cy, func, fStyle, blend_col );
             goto end;
         }
@@ -1433,7 +1514,7 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
 
         hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
         PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
-        alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
+        alpha_blend_image( himl, hImageListDC, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func, fStyle, blend_col );
         DeleteObject (SelectObject (hImageDC, hOldBrush));
         bResult = BitBlt( pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
         goto end;
@@ -1527,7 +1608,6 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
        }
     }
 
-    if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
     if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
     if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
 
@@ -3535,7 +3615,7 @@ static HRESULT WINAPI ImageListImpl_SetDragCursorImage(IImageList2 *iface,
     IUnknown *punk, int iDrag, int dxHotspot, int dyHotspot)
 {
     IImageList *iml2 = NULL;
-    HRESULT ret;
+    BOOL ret;
 
     if (!punk)
         return E_FAIL;