I would like to update some toolbar-like code we have to have a Vista/Win7 gradient roundedness to them.
Currently, the buttons have the Windows 2000 look & feel: blocky, single-tone.
I've played around with the XP themes, and using DrawThemeBackground, DrawThemeEdge, etc.; but I'm very dissatisfied with the theme drawing mechanics (the buttons are large, and the theme draws them as 2-tone, top half and bottom half, which looks okay when the buttons are small - it gives them a halfway decent appearance of being a gradient or having a rounded quality to them. But as large as these buttons are, they look stupid.
Experimenting by simply observing how many of the controls are drawn in various apps and controls, I can see that most of them seem to use gradients - where the top of the control appears a light color and fades to the bottom to a darker color - OR - where it is a lighter color than the background at the top, increases towards near-white at the middle, then fades back to a darker color towards the bottom.
I'm not really sure where to go from here. DrawThemeXXX seem to be inadequate. I don't really want to replace the entire control with a new one that has improved drawing but would require that I swap out some of the code for how the current custom control works, and risk various problems with some other library. I'd rather just have a way to draw arbitrary objects in the style of the current version of Windows that I'm running on. I would have thought that the theme drawing functions would have covered this. But they're fairly brain damaged, as I described.
Can someone point me towards 'How are modern C++ applications supposed to draw custom GUI elements so that they might reasonably expect a graceful appearance under XP, Vista, and Windows 7?'
We use MFC, Gdiplus, and raw Win32 APIs in our code, currently.
Here's to hoping someone knows a great deal about drawing modern GUIs under Windows from C++!
Just so that this isn't a wall of text, here's the current version of the paint handler, which draws the button with an etched border when 'hot-tracking' and both an etched border and the icon + text "depressed" (shifted by 1,1) when in a pressed state:
void CPlacesButton::PaintButton(CDC & dc, CRect & rcClient)
{
const int kLabelHeight = 8;
COLORREF clrHiLt = GetSysColor(COLOR_BTNHIGHLIGHT);
COLORREF clrShdo = GetSysColor(COLOR_BTNSHADOW);
COLORREF clrText = GetSysColor(COLOR_BTNTEXT);
COLORREF clrFace = GetSysColor(COLOR_BTNFACE);
// draw the button's background & border
if (m_bPressed || m_bDrawPressed || m_bMouseOnButton)
{
COLORREF clrDarkened = Darken(clrFace, -0.01f);
dc.FillRect(rcClient, &CBrush(clrDarkened));
//dc.Draw3dRect(rcClient, clrShdo, clrHiLt);
//dc.RoundRect(&rcClient, CPoint(10,10));
dc.DrawEdge(&rcClient, EDGE_ETCHED, BF_RECT|BF_FLAT);
//dc.DrawFrameControl(&rcClient, DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);
}
// else if (m_bMouseOnButton) // hot draw
// //dc.Draw3dRect(rcClient, clrShdo, clrHiLt);
// dc.DrawEdge(&rcClient, EDGE_ETCHED, BF_RECT);
// //dc.RoundRect(&rcClient, CPoint(10,10));
else
dc.FillRect(rcClient, &CBrush(clrFace));
// use transparent mode for everything that follows
dc.SetBkMode(TRANSPARENT);
// center icon
CPoint ptIcon((rcClient.Width() - m_nIconSize) / 2, ((rcClient.Height() - m_nIconSize) / 2) - kLabelHeight);
if (m_bPressed || m_bDrawPressed)
ptIcon.Offset(1, 1);
// determine the state to draw ourselves in
const UINT nState = DST_ICON | (IsEnabled() ? DSS_NORMAL : DSS_DISABLED);
// draw our icon
dc.DrawState(ptIcon, CSize(m_nIconSize, m_nIconSize), m_hIcon, nState, (HBRUSH)NULL);
// create & select the font to use for the button's label
CFont guiFont;
VERIFY(guiFont.CreateStockObject(DEFAULT_GUI_FONT));
AutoSelectGDIObject select_font(dc, guiFont);
// determine clipping rect for label
CRect rcText(0, ptIcon.y+m_nIconSize+kLabelHeight, rcClient.Width(), ptIcon.y+m_nIconSize+kLabelHeight);
rcText.InflateRect(0,20);
if (m_bPressed || m_bDrawPressed)
rcText.OffsetRect(1, 1);
dc.SetTextColor(clrText);
if (IsEnabled())
dc.DrawText(m_strCaption, rcText, DT_VCENTER|DT_SINGLELINE|DT_CENTER);
else
dc.GrayString(NULL, NULL, (LPARAM)(LPCTSTR)m_strCaption, 0, rcText.TopLeft().x, rcText.TopLeft().y, rcText.Width(), rcText.Height());
}
I left some of the commented out variations in the code to indicate some hints as to what other possibilities I've tried. However, they're just a hint, as the complete alternate examples are not present.