Index: dll/win32/comctl32/imagelist.c =================================================================== --- dll/win32/comctl32/imagelist.c (revision 65811) +++ dll/win32/comctl32/imagelist.c (working copy) @@ -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 */ @@ -1227,7 +1227,7 @@ } -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 +1252,9 @@ 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 +1327,66 @@ 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: + */ + 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 +1463,21 @@ 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 +1498,7 @@ 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 +1508,7 @@ 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 +1602,6 @@ } } - 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"); Index: dll/win32/comctl32/toolbar.c =================================================================== --- dll/win32/comctl32/toolbar.c (revision 65811) +++ dll/win32/comctl32/toolbar.c (working copy) @@ -696,10 +696,12 @@ const NMTBCUSTOMDRAW *tbcd, DWORD dwItemCDFlag) { HIMAGELIST himl = NULL; - BOOL draw_masked = FALSE; + BOOL draw_masked = FALSE, draw_desaturated = FALSE; INT index; INT offset = 0; UINT draw_flags = ILD_TRANSPARENT; + IMAGEINFO info = {0}; + BITMAP bm = {0}; if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) { @@ -707,7 +709,18 @@ if (!himl) { himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); - draw_masked = TRUE; + + ImageList_GetImageInfo(himl, index, &info); + GetObjectW(info.hbmImage, sizeof(bm), &bm); + + if (bm.bmBitsPixel == 32) + { + draw_desaturated = TRUE; + } + else + { + draw_masked = TRUE; + } } } else if (tbcd->nmcd.uItemState & CDIS_CHECKED || @@ -738,9 +751,34 @@ index, himl, left, top, offset); if (draw_masked) + { + /* code path for drawing flat disabled icons without alpha channel */ TOOLBAR_DrawMasked (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); + } + else if (draw_desaturated) + { + /* code path for drawing disabled, alpha-blended (32bpp) icons */ + IMAGELISTDRAWPARAMS imldp = {0}; + + imldp.cbSize = sizeof(imldp); + imldp.himl = himl; + imldp.i = index; + imldp.hdcDst = tbcd->nmcd.hdc, + imldp.x = offset + left; + imldp.y = offset + top; + imldp.rgbBk = CLR_NONE; + imldp.rgbFg = CLR_DEFAULT; + imldp.fStyle = ILD_TRANSPARENT; + imldp.fState = ILS_ALPHA | ILS_SATURATE; + imldp.Frame = 192; + + ImageList_DrawIndirect (&imldp); + } else + { + /* code path for drawing standard icons as-is */ ImageList_Draw (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); + } } /* draws a blank frame for a toolbar button */