|
Thanks for the feedback! Am looking into your mods.
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
I accidentally draw the default frame on buttons that where disabled, but that is not how normal buttons act. I have updated the code (I simply check that bDisabled is not true before setting default frame in GetXPMode).
Another bug was that hyperlinks wasn't correctly drawn when themes was used. I solved this by drawing hyperlinks in the traditional way (that is, not using DrawThemeText).
|
|
|
|
|
The system color wasn't used to draw text caption. The code is updated.
|
|
|
|
|
Nice!
Some improvement:
void FooButton::DisabledBlt
(HDC hdcDest,
int nXDest,
int nYDest,
int nWidth,
int nHeight,
HBITMAP hBitmap,
int nXSrc,
int nYSrc)
{
ASSERT (hdcDest && hBitmap);
ASSERT (nWidth > 0 && nHeight > 0);
HDC hDC = CreateCompatibleDC (hdcDest);
ASSERT (hDC);
if (hDC) {
HDC bwDC = CreateCompatibleDC(hDC);
ASSERT (bwDC);
if (bwDC) {
struct
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[2];
} RGBBWBITMAPINFO = {
{
sizeof(BITMAPINFOHEADER),
nWidth,
nHeight,
1,
1,
BI_RGB,
0,
0,
0,
0,
0
},
{
{ 0x00, 0x00, 0x00, 0x00 },
{ 0xFF, 0xFF, 0xFF, 0x00 }
}
};
void* pbitsBW;
HBITMAP hBitmapBW = CreateDIBSection (bwDC,
(LPBITMAPINFO) &RGBBWBITMAPINFO,
DIB_RGB_COLORS, &pbitsBW, NULL, 0);
ASSERT (hBitmapBW);
if (hBitmapBW) {
SelectObject (bwDC, hBitmapBW);
SelectObject (hDC, hBitmap);
BitBlt (bwDC, 0, 0, nWidth, nHeight, hDC, nXSrc, nYSrc, SRCCOPY);
#ifdef FOO_USEXPTHEMES
if (!gThemeManager.m_bXPTheme)
#endif
FillRect (hdcDest,
CRect (nXDest, nYDest, nXDest + nWidth, nYDest + nHeight),
GetSysColorBrush (COLOR_3DFACE));
HBRUSH hb = CreateSolidBrush (GetSysColor (COLOR_3DHILIGHT));
HBRUSH oldBrush = (HBRUSH) SelectObject (hdcDest, hb);
BitBlt (hdcDest, nXDest + 1, nYDest + 1, nWidth, nHeight, bwDC, 0, 0, 0xB8074A);
hb = CreateSolidBrush (GetSysColor (COLOR_3DSHADOW));
DeleteObject (SelectObject(hdcDest, hb));
BitBlt (hdcDest, nXDest, nYDest, nWidth, nHeight, bwDC, 0, 0, 0xB8074A);
DeleteObject (SelectObject (hdcDest, oldBrush));
}
VERIFY (DeleteDC (bwDC));
}
VERIFY (DeleteDC(hDC));
}
}
You don't need to draw gray phone when XP themes are used.
|
|
|
|
|
These are the last three lines in OnLButtonUp:
CButton::OnLButtonUp (nFlags, point);
m_bMultiClicked = false;
Invalidate();
In one of my programs the button is destroyed when it is clicked. This means that the button exist when CButton::OnLButtonUp (nFlags, point) executes, but it's destroyed when next line run. Crash!
Now I have changed the order of the lines, and it seems works fine for me .
|
|
|
|
|
Good point - thanks! I'll update the code. Will also add a call to force a repaint immediately, eg:
m_bMultiClicked = false;
Invalidate();
UpdateWindow();
CButton::OnLButtonUp (nFlags, point);
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
How to enable XP themes support for this class?
If you add manifest file it does not help
|
|
|
|
|
Unfortunately, it currently doesn't support XP themes.
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
So... good project, but need some improvement.
|
|
|
|
|
Agreed - there's always room for improvement!
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
This article's forum indexes seem to be screwed up.
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
I downloaded your second verison of the demo, and during the compilation I discovered that it does not compile on my system (WinXP Prof.) with error message that COLOR_HOTLIGHT is not defined. After looking into MSDN I found that COLOR_HOTLIGHT is not defined for NT and 95, without any other explanation for XP. After changing the line to something different, just to try to recompile, it worked fine. (I changed it temporarily to "rgbPen = GetSysColor(COLOR_HIGHLIGHT);".
Have a good one!
Amer Gerzic
|
|
|
|
|
Perhaps you need to install the latest version of the Platform SDK? My copy of winuser.h defines it as:
#if(WINVER >= 0x0500)
#define COLOR_HOTLIGHT 26
... /ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
Hi,
The button in the demo responds to the shortcut key 'F', and also responds to ALT+F, CTRL+F, SHIFT+F. This default behavior is embedded somewhere in CButton class or in its base class.
Do you know how to make the button respond only to a particular combination of keys, e.g. CTRL+F?
It would be a nice feature in FooButton.
gyar
|
|
|
|
|
I think you can control this by overriding PreTranslateMessage() and ignoring the Alt+F and Shift+F keystrokes.
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
this feature is amazing but there is one "-". then pressing button as in "standart situation", it does not draws as pushed inside.. (like CHECKED state)
but awesome..
----------------------------
never stop coding.
|
|
|
|
|
Actually multi buttons behave differently in Outlook and IE. I happened to choose the IE route, although one could argue that the Outlook behavior is more appealing/intuitive. Hmm, looks like we might need another FooButton property...
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
Your way of disabling "unreferenced var warnings" is not perfect. You can simply comment out variable names in the function definition to achive the same effect. Don't modify the headers, just .cpp files. See example below.
BOOL FooButton::OnSetCursor (CWnd* /*pWnd*/, UINT /*nHitTest*/, UINT /*message*/)
{
// Don't need the code below any more
// pWnd = pWnd;
// nHitTest = nHitTest;
// message = message;
}
Also, how does your control work with XP visual styles?
Andrew
|
|
|
|
|
AndrewSmirnov wrote:
simply comment out variable names in the function definition
Good point - thanks! I'll update the code soon.
AndrewSmirnov wrote:
does your control work with XP visual styles
No, although it uses CDC::DrawFrameControl() which may honor some aspects of the current theme (unknown).
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
I do the following to prevent "unreferenced var warning"
BOOL FooButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
(void)pWnd;
(void)nHitTest;
(void)message;
}
Regards,
Simon Hughes
|
|
|
|
|
Just use the UNREFERENCED_PARAMETER(var) macro, easy to search for in code too.
|
|
|
|
|
|
First of all, great work. Small and simple, just the way I like it .
However, there are some problems to be solved.
First, there were some compiling problems for me. COLOR_HOTLIGHT wasn't defined, so I got an error in FooButton::drawDropDown. I added these lines to solve this:
<br />
#ifndef COLOR_HOTLIGHT <br />
#define COLOR_HOTLIGHT 26 <br />
#endif <br />
Second, of you select button with the keyboard you should see a focus rectangle. But I didn't do that. To solve this I made a minor change in drawFocus:
<br />
void FooButton::drawFocus<br />
(CDC* pDC,<br />
LPDRAWITEMSTRUCT lpDrawItemStruct)<br />
{<br />
ASSERT (pDC != NULL);<br />
ASSERT (lpDrawItemStruct != NULL);<br />
<br />
if (!m_bStatic)
if ((lpDrawItemStruct->itemState & ODS_FOCUS) == ODS_FOCUS) <br />
{<br />
CRect rectButton;<br />
GetClientRect (&rectButton);<br />
rectButton.left += 4;<br />
rectButton.top += 4;<br />
rectButton.right -= 4;<br />
rectButton.bottom -= 4;<br />
::DrawFocusRect (pDC->m_hDC, &rectButton);<br />
}<br />
}<br />
I just removed m_bFocus. I'm also changed the value how much the rectangle should shrink in right and bottom. The reason to this is that it look better when I solved problem number three.
Third, when I button got focus it should be the default button. So here we must draw a dark border around it. So I made some changes in FooButton::drawFrame:
<br />
void FooButton::drawFrame<br />
(CDC* pDC,<br />
LPDRAWITEMSTRUCT lpDrawItemStruct)<br />
{<br />
ASSERT (pDC != NULL);<br />
ASSERT (lpDrawItemStruct != NULL);<br />
<br />
if (!m_bStatic && !m_bHyperlink) <br />
{<br />
if (m_bHot && !m_bChecked)<br />
drawHotButtonFrame (lpDrawItemStruct);<br />
else <br />
{ <br />
UINT uFrameCtrl = DFCS_BUTTONPUSH;<br />
if (m_bChecked)<br />
uFrameCtrl |= DFCS_CHECKED;<br />
else<br />
{<br />
if (((lpDrawItemStruct->itemState & ODS_SELECTED) == ODS_SELECTED) && !m_bMulti)<br />
uFrameCtrl |= DFCS_PUSHED;<br />
}<br />
<br />
if ((lpDrawItemStruct->itemState & ODS_DISABLED) == ODS_DISABLED)<br />
uFrameCtrl |= DFCS_INACTIVE; <br />
<br />
<br />
<br />
bool darkBorder = false;<br />
bool isDown = false;<br />
<br />
if( (lpDrawItemStruct->itemState & ODS_FOCUS) != 0 <br />
)<br />
darkBorder = true;<br />
<br />
if( (lpDrawItemStruct->itemState & ODS_SELECTED) != 0)<br />
isDown = true;<br />
<br />
CRect buttonRect = lpDrawItemStruct->rcItem;<br />
CRect blackBorderRect = buttonRect;<br />
CRect innerRect = buttonRect;<br />
<br />
if(darkBorder)<br />
{<br />
innerRect.left+=1;<br />
innerRect.top+=1;<br />
innerRect.right-=1;<br />
innerRect.bottom-=1;<br />
<br />
pDC->FrameRect( &blackBorderRect,<br />
CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));<br />
}<br />
<br />
pDC->DrawFrameControl (&innerRect, DFC_BUTTON , uFrameCtrl);<br />
<br />
if (m_bMulti && m_bMultiClicked)<br />
drawMultiDropDownRegion (pDC, lpDrawItemStruct);<br />
}<br />
}<br />
}<br />
Fourth, the big default button problem . If a button got focus then it should be the default button, and all the other buttons should not be default buttons. COddButton is solving this problem, so I use this as the base class. Then I replaced CButton to COddButton in BEGIN_MESSAGE_MAP (you should replace all CButton, but I was lazy and this seems to be enough . It was also necessary to change drawFrame, just uncomment the with the IsDefault() call. And last, in the resources all buttons should not have the "Owner draw" value (COddButton fix this). Now the default button will work properly.
Now, it seems that I have added a minor problem. If the button is "hot", and you press space to click on it the text and bitmap become written twice. I guess the old text is not removed, so I think this is a simple problem to solve.
Anyway, thanks for a great button.
|
|
|
|
|
Thanks for your comments!
PEK wrote:
COLOR_HOTLIGHT
I think you need to install the latest Platform SDK.
PEK wrote:
focus rectangle
m_bFocus intentionally defaults to false because FooButton was originally written to be used for faking toolbar buttons, click-responsive static controls and hyperlinks. But I forgot to add a mutator to allow for m_bFocus to be set to true when desired.
PEK wrote:
default button
Default button rendering was omitted for the same reason, but it obviously needs to be added for completeness.
I'll update the article soon. Thanks again for your feedback!
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
Thanks for the update you did 11 July, I like it much better now . But sense I'm a very finicky person, I have to say some more, I hope you don't mind .
It still could happen that two buttons get the default "border". Set "Focus rectangle and default indicator" in the demo, and tab to the exit button and you see what I mean. I solve this with deriving FooButton from COddButton, removing FooButton::PreSubclassWindow, and change the call to m_bDefaultButton to IsDefault() in line 802 and it works as expected.
I saw that some of the colors of the frame is drawn with is black and white, but this is not necessary true. Black (the default border) could be in a different color in some extreme cases. If I use one of the dark high-contrast color schemes in windows (I don't now the name of these in English, but they look terrible , the border is white. The white line in the frame is very often in a brighter color than the background color of the button. Anyway, I did some changes in void FooButton::drawDefaultBorder:
<br />
void FooButton::drawDefaultBorder<br />
(CDC* pDC,<br />
LPDRAWITEMSTRUCT lpDrawItemStruct)<br />
{<br />
ASSERT (pDC != NULL);<br />
ASSERT (lpDrawItemStruct != NULL);<br />
<br />
FooButton::Type btnType = getType();<br />
if ((btnType != FooButton::Type::pushButton) &&<br />
(btnType != FooButton::Type::pushButtonDropDown) &&<br />
(btnType != FooButton::Type::pushButtonMulti))<br />
return;<br />
<br />
if (getFocusStyle() != FooButton::Focus::defaultFocus)<br />
return;<br />
<br />
if (((lpDrawItemStruct->itemState & ODS_FOCUS) == 0) && !IsDefault())
return;<br />
<br />
COLORREF rgbBorder = GetSysColor (COLOR_3DDKSHADOW);<br />
CBrush borderBrush (rgbBorder);<br />
CBrush* pBrush = &borderBrush;
ASSERT (pBrush != NULL);<br />
CRect innerRect = lpDrawItemStruct->rcItem;<br />
if ((lpDrawItemStruct->itemState & ODS_SELECTED) == 0) {<br />
<br />
COLORREF rgbBorder = GetSysColor (COLOR_3DDKSHADOW);<br />
CPen borderGreyPen (PS_SOLID, 1, rgbBorder);<br />
CPen* pOldPen = pDC->SelectObject (&borderGreyPen );<br />
pDC->MoveTo (innerRect.right - 2, innerRect.top + 1);<br />
pDC->LineTo (innerRect.right - 2, innerRect.bottom - 2);<br />
pDC->LineTo (innerRect.left, innerRect.bottom - 2);<br />
pDC->SelectObject (pOldPen);<br />
<br />
COLORREF rgbBrGrey = GetSysColor (COLOR_3DHILIGHT);<br />
CPen brightGreyPen (PS_SOLID, 1, rgbBrGrey);<br />
pOldPen = pDC->SelectObject (&brightGreyPen);<br />
pDC->MoveTo (innerRect.right - 3, innerRect.top + 1);<br />
pDC->LineTo (innerRect.left + 1, innerRect.top + 1);<br />
pDC->LineTo (innerRect.left + 1, innerRect.bottom - 2);<br />
pDC->SelectObject (pOldPen);<br />
<br />
COLORREF rgbDkGrey = GetSysColor (COLOR_BTNSHADOW);<br />
CPen darkGreyPen (PS_SOLID, 1, rgbDkGrey);<br />
pOldPen = pDC->SelectObject (&darkGreyPen);<br />
pDC->MoveTo (innerRect.right - 3, innerRect.top + 2);<br />
pDC->LineTo (innerRect.right - 3, innerRect.bottom - 3);<br />
pDC->LineTo (innerRect.left + 1, innerRect.bottom - 3);<br />
pDC->SelectObject (pOldPen);<br />
<br />
} else {<br />
innerRect.InflateRect (1, 1, -1, -1);<br />
pDC->FrameRect (&innerRect, pBrush);<br />
}<br />
pDC->FrameRect(&lpDrawItemStruct->rcItem, pBrush);<br />
}<br />
This seems to look good in any color scheme.
Finally I think that if focus rectangle is used and the text is not centered, the text should be moved two pixels or so to the right. Now the text is drawn in the focus rectangle.
Anyway, thanks again for a great button .
|
|
|
|
|