Drawing a drop shadow: using a mono bitmap
In an earlier article, I showed how to draw a drop shadow with the help of the ImageList control.
It occurred to me last night that there’s a simpler way to do the masking for the shadow.
In the previous article, we used a colour bitmap and a special ROP code to draw the selected brush on the output DC.
There’s an easier way: if we use a mono bitmap, SRCCOPY will do the necessary magic; as long as we’ve called
SetBkColor
and SetTextColor
appropriately.
void DrawImageListItem(CDC *pDC, int x, int y,
CImageList *piml, int nImage,
COLORREF crBack, bool bDropShadow, COLORREF crShadow)
{
if (bDropShadow)
{
// This is quite simple:
// We draw the mask in crShadow, offset slightly down & right.
// We draw the item transparently, offset slightly up & left.
// We need to know how big each item in the image list is.
int cx, cy;
ImageList_GetIconSize(piml->GetSafeHandle(), &cx, &cy);
// Drawing the drop shadow in the appropriate colour is trickier:
// we need to go via a memory DC.
// We need a memory DC, backed with some (mono) bits.
CDC memoryDC;
VERIFY(memoryDC.CreateCompatibleDC(pDC));
CBitmap memoryBitmap;
VERIFY(memoryBitmap.CreateBitmap(cx, cy, 1, 1, NULL));
CBitmap *oldMemoryBitmap = memoryDC.SelectObject(&memoryBitmap);
// Draw the mask onto it. Transparent parts of the image are white.
// Opaque parts are black.
piml->Draw(&memoryDC, nImage, CPoint(0, 0), ILD_MASK);
pDC->SetBkColor(crBack);
pDC->SetTextColor(crShadow);
pDC->BitBlt(x + 1, y, cx, cy, &memoryDC, 0, 0, SRCCOPY);
// Start cleaning up.
memoryDC.SelectObject(oldMemoryBitmap);
// That's given us a drop shadow.
// All we need to do now is put the normal image over the top.
piml->Draw(pDC, nImage, CPoint(x-1, y-1), ILD_NORMAL | ILD_TRANSPARENT);
}
else
{
// Then it's much, much simpler:
// just get the image list to draw on the DC directly.
piml->Draw(pDC, nImage, CPoint(x,y), ILD_NORMAL | ILD_TRANSPARENT);
}
}
Essentially, when given a mono bitmap as the source, BitBlt(..., SRCCOPY)
will treat black pixels as the foreground
colour, and white pixels as the background colour.