delphic++builderalpha-transparencyc++builder-2010

Copying transparent (32bit alpha) bitmap from TImageList in ComboBox DrawItem event


I am customizing OnDrawItem event to draw icons next to item names. Here is my code so far for the event OnDrawItem:

void __fastcall Form1::ComboBox1DrawItem(TWinControl *Control, int Index,
                                         TRect &Rect, TOwnerDrawState State)
{
TComboBox* CB = static_cast<TComboBox*>(Control);
CB->Canvas->FillRect(Rect);

boost::scoped_ptr<Graphics::TBitmap> bitmap(new Graphics::TBitmap());
bitmap->PixelFormat = pf32bit;
bitmap->AlphaFormat = afPremultiplied;

ImageList1->GetBitmap(Index, bitmap.get());

bitmap->AlphaFormat = afPremultiplied;

if (bitmap->Canvas->Handle)
    {
    // structure for alpha blending
    BLENDFUNCTION bf;
    bf.BlendOp              = AC_SRC_OVER;
    bf.BlendFlags           = 0;
    bf.SourceConstantAlpha  = 0xFF;         // 0x00 (transparent) through 0xFF (opaque)
    bf.AlphaFormat          = AC_SRC_ALPHA; // Use bitmap alpha

    ::AlphaBlend(CB->Canvas->Handle,    // handle to destination DC
             Rect.Left + 2,             // x-coord of upper-left corner
             Rect.Top,                  // y-coord of upper-left corner
             bitmap->Width,             // destination width
             bitmap->Height,            // destination height
             bitmap->Canvas->Handle,    // handle to source DC
             0,                         // x-coord of upper-left corner
             0,                         // y-coord of upper-left corner
             bitmap->Width,             // source width
             bitmap->Height,            // source height
             bf                         // alpha-blending function
            );
    }

    Rect = Bounds(Rect.Left + 20 + 2, Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top);

    DrawTextW(CB->Canvas->Handle, CB->Items->Strings[Index].c_str(), -1, &Rect, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
}

The problem of course is getting a transparent TImageList1 to copy to transparent TBitmap preserving 32-bit alpha transparency/semi-transparency. Currently I get it out with white background in the resulting TBitmap.

Just to be clear, TImageList ColorDepth is set to cd32bit with DrawingStyle = dsTransparent before loading images to it and the images on it are transparent, no problems there.

What is the trick to solve this?

UPDATE AND MY FINAL SOLUTION

Based on a reply here here is my final working code for someone else who might need it in the future. This of course is just a template code which you might want to customize further to your own needs.

void __fastcall TForm1::ComboBox1DrawItem(TWinControl *Control, int Index, TRect &Rect, TOwnerDrawState State)
{
if (Index >= 0)
        {
        TComboBox* CB     = static_cast<TComboBox*>(Control);
        CB->Canvas->FillRect(Rect);
        // Note - ImageList1 already has DrawingStyle set to dsTransparent          
        ImageList1->Draw(CB->Canvas, Rect.Left + 2, Rect.Top, 0);
        Rect = Bounds(Rect.Left + ImageList1->Width + 2 + 2, Rect.Top, Rect.Right - Rect.Left - ImageList1->Width - 2, Rect.Bottom - Rect.Top);
        DrawTextW(CB->Canvas->Handle, CB->Items->Strings[Index].c_str(), -1, &Rect, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
        }
}

Solution

  • You don't need to try and grab the original bitmap from the imagelist because the imagelist itself knows how to draw honoring transparency information. You can use its Draw method for that.

    Otherwise, an answer here suggests that setting AlphaFormat to 'afIgnored' before calling GetBitmap should preserve transparency.