protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
{
if (!OsUtils.CompositionEnabled())
{
// The OS doesn't support desktop composition, or it isn't enabled
base.OnRenderItemText(e);
return;
}
// Drawing text on glass is a bit of a pain - text generated with GDI (e.g. standard
// controls) ends up being transparent as GDI doesn't understand alpha transparency.
// GDI+ is fine drawing text on glass but it doesn't use ClearType, so the text ends
// up looking out of place, ugly or both. The proper way is using DrawThemeTextEx,
// which works fine, but requires a top-down DIB to draw to, rather than the bottom
// up ones that GDI normally uses. Hence; create top-down DIB, draw text to it and
// then AlphaBlend it in to the graphics object that we are rendering to.
// Get the rendering HDC, and create a compatible one for drawing the text to
IntPtr renderHdc = e.Graphics.GetHdc();
IntPtr memoryHdc = NativeMethods.CreateCompatibleDC(renderHdc);
// NULL Pointer
if (memoryHdc == IntPtr.Zero)
{
throw new Win32Exception();
}
NativeMethods.BITMAPINFO info = default(NativeMethods.BITMAPINFO);
info.biSize = Convert.ToUInt32(Marshal.SizeOf(typeof(NativeMethods.BITMAPINFO)));
info.biWidth = e.TextRectangle.Width;
info.biHeight = -e.TextRectangle.Height; // Negative = top-down
info.biPlanes = 1;
info.biBitCount = 32;
info.biCompression = NativeMethods.BI_RGB;
IntPtr bits = IntPtr.Zero;
// Create the top-down DIB
IntPtr dib = NativeMethods.CreateDIBSection(renderHdc, ref info, 0, ref bits, IntPtr.Zero, 0);
// NULL Pointer
if (dib == IntPtr.Zero)
{
throw new Win32Exception();
}
// Select the created DIB into our memory DC for use
// NULL Pointer
if (NativeMethods.SelectObject(memoryHdc, dib) == IntPtr.Zero)
{
throw new Win32Exception();
}
// Create a font we can use with GetThemeTextEx
IntPtr hFont = e.TextFont.ToHfont();
// And select it into the DC as well
// NULL Pointer
if (NativeMethods.SelectObject(memoryHdc, hFont) == IntPtr.Zero)
{
throw new Win32Exception();
}
// Fetch a VisualStyleRenderer suitable for toolbar text
VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.ToolBar.Button.Normal);
// Set up a RECT for the area to draw the text in
NativeMethods.RECT textRect = default(NativeMethods.RECT);
textRect.left = 0;
textRect.top = 0;
textRect.right = e.TextRectangle.Width;
textRect.bottom = e.TextRectangle.Height;
// Options for GetThemeTextEx
NativeMethods.DTTOPTS opts = default(NativeMethods.DTTOPTS);
opts.dwSize = Convert.ToUInt32(Marshal.SizeOf(opts));
opts.dwFlags = NativeMethods.DTT_COMPOSITED | NativeMethods.DTT_TEXTCOLOR;
opts.crText = Convert.ToUInt32(ColorTranslator.ToWin32(e.TextColor)); // Alpha blended text of the colour specified
// Paint the text
Marshal.ThrowExceptionForHR(NativeMethods.DrawThemeTextEx(renderer.Handle, memoryHdc, 0, 0, e.Text, -1, (uint)e.TextFormat, ref textRect, ref opts));
// Set up the AlphaBlend copy
NativeMethods.BLENDFUNCTION blendFunc = default(NativeMethods.BLENDFUNCTION);
blendFunc.BlendOp = NativeMethods.AC_SRC_OVER;
blendFunc.SourceConstantAlpha = 255;
blendFunc.AlphaFormat = NativeMethods.AC_SRC_ALPHA; // Per-pixel alpha only
// Blend the painted text into the render DC
if (!NativeMethods.AlphaBlend(renderHdc, e.TextRectangle.Left, e.TextRectangle.Top, e.TextRectangle.Width, e.TextRectangle.Height, memoryHdc, 0, 0, e.TextRectangle.Width, e.TextRectangle.Height, blendFunc))
{
throw new Win32Exception();
}
// Clean up the GDI objects
if (!NativeMethods.DeleteObject(hFont))
{
throw new Win32Exception();
}
if (!NativeMethods.DeleteObject(dib))
{
throw new Win32Exception();
}
if (!NativeMethods.DeleteDC(memoryHdc))
{
throw new Win32Exception();
}
e.Graphics.ReleaseHdc();
}