|
I fixed up CCoolBtn (as CCoolButton) to work with themes on Win/XP. I also added the ability to have the button only work as a Menu Button (no split) and to have a 2nd ID for the down-arrow part rather than an attached menu. Enjoy.
Leigh Brasington
/* >>>>>>>>>>>>>>>>>>> Here's the CoolButton.h file <<<<<<<<<<<<<<<<<<<< */
#if !defined(AFX_CoolButton_H__3A90681F_CE5F_11D3_808C_005004D6CF90__INCLUDED_)
#define AFX_CoolButton_H__3A90681F_CE5F_11D3_808C_005004D6CF90__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CoolButton.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CCoolButton window
class CCoolButton : public CButton
{
// Construction
public:
CCoolButton();
BOOL SetIDs(UINT nID1, UINT m_nID2);
BOOL AddMenuItem(UINT nMenuId,const CString strMenu, UINT nMenuFlags);
BOOL SetButtonImage(UINT nResourceId, COLORREF crMask);
void SetSplit(BOOL b) { m_bSplit = b && (m_bMenuLoaded || m_nID2); }
void SetAsDefaultBtn(BOOL b) { m_bDefaultBtn = b; }
void ClearButtonPushed();
// Attributes
protected:
CMenu m_menu;
CBitmap m_btnImage;
CImageList m_IL;
BOOL m_Initialized;
BOOL m_bPushed;
BOOL m_bMenuPushed;
BOOL m_bMenuLoaded;
BOOL m_bLoaded;
BOOL m_bDefaultBtn;
BOOL m_bActAsDefaultBtn;
BOOL m_bSplit;
BITMAP m_bm;
UINT m_nID1;
UINT m_nID2;
COLORREF m_crMask;
HBITMAP m_hbmpDisabled;
HMODULE m_themeLib; // handle to UxTheme.dll
BOOL m_bOverControl; // is the mouse over us?
BOOL m_bTracking; // are we tracking the mouse
// Operations
public:
protected:
void DrawArrow(CDC* pDC,CPoint ArrowTip);
BOOL HitMenuBtn(CPoint point);
BOOL OnMenuBtn();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCoolButton)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CCoolButton();
// Generated message map functions
protected:
//{{AFX_MSG(CCoolButton)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnSetFocus(CWnd* pOldWnd);
afx_msg void OnKillFocus(CWnd* pNewWnd);
afx_msg void OnSysColorChange();
afx_msg void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg UINT OnGetDlgCode();
afx_msg LRESULT OnMouseHover(WPARAM wparam, LPARAM lparam);
afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam);
afx_msg LRESULT OnSetStyle(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CoolButton_H__3A90681F_CE5F_11D3_808C_005004D6CF90__INCLUDED_)
/* >>>>>>>>>>>>>>>>>>> Here's the CoolButton.cpp file <<<<<<<<<<<<<<<<<<<< */
// CoolButton.cpp : implementation file
//
#include "stdafx.h"
#include "p4win.h"
#include "CoolBtn.h"
#if _MFC_VER >= 0x0700
#define USE_THEMES
#include <uxtheme.h>
#endif
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const int nDropBtnWidth = 16;
/////////////////////////////////////////////////////////////////////////////
// CCoolButton
// ========
//
// To Use:
// 1. In the RC file, create the button as BS_OWNERDRAW.
// Optionally, create a Bitmap resource 16x15 Pixels
// - normal default size for a toolbar bitmap.
//
// 2. in the header for the dialog class:
// #include "CoolBtn.h"
// then create the necessary button widgets in the //{{AFX_DATA() section:
// CCoolButton m_DblBtn;
//
// 3. In the InitDialog() for the dialog:
//
// a) Optionally, Call SetButtonImage specificing the
// Transparency color reference.
// (Usally RGB(255, 0, 255) magenta)
// m_DblBtn.SetButtonImage(IDC_BTNIMAGE, RGB(255,0,255));
//
// b) Either call CCoolButton's SetIDs function:
// m_DblBtn.SetIDs(IDC_BTNPUSH, IDC_BTNMENU);
// the first ID must be the same as the ID in the RC file!
// --or--
// Add menu item(s) to the button:
// m_DblBtn.AddMenuItem(nMenuId1, strMenu1, nMenuFlags1);
// m_DblBtn.AddMenuItem(nMenuId2, strMenu2, nMenuFlags2);
//
// If you do both SetIDs() and AddMenuItem()s, only the AddMenuItem
// will be called and the second ID will be ignored.
//
// c) Optionally, call CCoolButton's show split function:
// m_DblBtn.SetSplit(bSplit);
// The default is to show the split (TRUE). If set to FALSE, only
// the AddMenuItem()s or 2nd ID in SetIDs() will be called and the
// base id (1st ID in SetIDs()==ID in RC file) will be ignored.
//
// d) Optionally call m_DblBtn.SetAsDefaultBtn(TRUE) to make the button
// the default button.
//
// 4. Add the appropiate ON_COMMAND handlers in the parent windows message map
//
// 5. You can also call SetIDs() or SetSplit() later to dynamically change the
// button and you can later add more AddMenuItem().
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: CCoolButton
//
// DESCRIPTION:
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin as CCoolBtn
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
CCoolButton::CCoolButton()
{
m_nID2 = 0;
m_bPushed = FALSE;
m_bLoaded = FALSE;
m_bMenuPushed = FALSE;
m_bMenuLoaded = FALSE;
m_bDefaultBtn = m_bActAsDefaultBtn = FALSE;
m_bSplit = TRUE;
m_bOverControl = FALSE;
m_bTracking = FALSE;
ZeroMemory(&m_bm, sizeof m_bm);
m_menu.CreatePopupMenu();
m_themeLib = LoadLibrary("UxTheme.dll");
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: ~CCoolButton
//
// DESCRIPTION:
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
CCoolButton::~CCoolButton()
{
if(m_themeLib)
FreeLibrary(m_themeLib);
}
BEGIN_MESSAGE_MAP(CCoolButton, CButton)
//{{AFX_MSG_MAP(CCoolButton)
ON_WM_SYSKEYDOWN()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_WM_SYSCOLORCHANGE()
ON_WM_GETDLGCODE()
//}}AFX_MSG_MAP
ON_MESSAGE(BM_SETSTYLE, OnSetStyle)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover )
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave )
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCoolButton message handlers
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: SetIDs
//
// DESCRIPTION: Set the IDs
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
BOOL CCoolButton::SetIDs( UINT nID1, UINT nID2 )
{
m_nID1 = nID1;
m_nID2 = nID2;
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
UINT CCoolButton::OnGetDlgCode()
{
UINT nCode = CButton::OnGetDlgCode();
nCode |= (m_bActAsDefaultBtn ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON);
return nCode;
}
// mask for control's type
#define BS_TYPEMASK SS_TYPEMASK
LRESULT CCoolButton::OnSetStyle(WPARAM wParam, LPARAM lParam)
{
m_bActAsDefaultBtn = wParam & BS_DEFPUSHBUTTON;
// can't change control type after owner-draw is set.
// let the system process changes to other style bits
// and redrawing, while keeping owner-draw style
return DefWindowProc(BM_SETSTYLE,
(wParam & ~BS_TYPEMASK) | BS_OWNERDRAW, lParam);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: DrawItem
//
// DESCRIPTION: Called in response to draw the button
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton, Added XP support
//
////////////////////////////////////////////////////////////////////////////////
#ifdef USE_THEMES
typedef HTHEME(__stdcall *PFNOPENTHEMEDATA)(HWND hwnd, LPCWSTR pszClassList);
typedef HRESULT(__stdcall *PFNCLOSETHEMEDATA)(HTHEME hTheme);
typedef HRESULT(__stdcall *PFNDRAWTHEMEBACKGROUND)(HTHEME hTheme, HDC hdc,
int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);
typedef HRESULT(__stdcall *PFNGETTHEMEBACKGROUNDCONTENTRECT)(HTHEME hTheme, HDC hdc,
int iPartId, int iStateId, const RECT *pRect, RECT *pContentRect);
#endif
void CCoolButton::DrawItem(DRAWITEMSTRUCT* lpDIS)
{
if (lpDIS->CtlType != ODT_BUTTON)
return;
CFont *pFont = CFont::FromHandle((HFONT)GetStockObject(DEFAULT_GUI_FONT));
CDC dcMem;
CBitmap bmp;
CRect btnRect(lpDIS->rcItem);
CRect trueRect(btnRect);
CRect rectFocus(btnRect);
CDC *pDC = CDC::FromHandle(lpDIS->hDC);
BOOL bDisabled = ODS_DISABLED & lpDIS->itemState;
#ifdef USE_THEMES
HTHEME hTheme = 0;
if(m_themeLib)
{
PFNOPENTHEMEDATA pOpenThemeData = (PFNOPENTHEMEDATA)
GetProcAddress(m_themeLib, "OpenThemeData");
if(pOpenThemeData)
hTheme = (pOpenThemeData)(m_hWnd, L"Button");
}
if(hTheme)
{
// attempt to map owner draw states to theme pushbutton states
int iState = PBS_NORMAL;
if(m_bOverControl)//lpDIS->itemState & ODS_HOTLIGHT)
iState = PBS_HOT;
else if(m_bDefaultBtn || m_bActAsDefaultBtn)//lpDIS->itemState & ODS_DEFAULT)
iState = PBS_DEFAULTED;
else if(lpDIS->itemState & ODS_SELECTED)
iState = PBS_PRESSED;
HRESULT hr;
HDC hDC = lpDIS->hDC;
RECT rc = lpDIS->rcItem;
// let theme draw background
PFNDRAWTHEMEBACKGROUND pDrawThemeBackground = (PFNDRAWTHEMEBACKGROUND)
GetProcAddress(m_themeLib, "DrawThemeBackground");
if(!pDrawThemeBackground)
return;
hr = (pDrawThemeBackground)(hTheme, hDC,
BP_PUSHBUTTON, iState, &rc, 0);
if(hr != S_OK)
return;
// get rect to put content in
RECT rcContent;
PFNGETTHEMEBACKGROUNDCONTENTRECT pGetThemeBackgroundContentRect =
(PFNGETTHEMEBACKGROUNDCONTENTRECT)
GetProcAddress(m_themeLib, "GetThemeBackgroundContentRect");
if(!pGetThemeBackgroundContentRect)
return;
hr = (pGetThemeBackgroundContentRect)(hTheme, hDC,
BP_PUSHBUTTON, iState, &rc, &rcContent);
if(hr != S_OK)
return;
rectFocus = rcContent;
if (!m_bMenuPushed)
rectFocus.OffsetRect(m_bPushed,m_bPushed);
if (m_bSplit)
rectFocus.right -= nDropBtnWidth;
if (lpDIS->itemState & ODS_FOCUS || m_bPushed)
{
if (!m_bMenuPushed)
::DrawFocusRect(lpDIS->hDC, &rcContent);
}
}
else
#endif
{
////////////////////////////////////////
// Button Background //
////////////////////////////////////////
CBrush brush(GetSysColor(COLOR_BTNFACE));
pDC->FillRect(trueRect,&brush);
if (m_bDefaultBtn)
btnRect.DeflateRect(1,1);
rectFocus.DeflateRect(4,4);
if (!m_bMenuPushed)
rectFocus.OffsetRect(m_bPushed,m_bPushed);
if (m_bSplit)
rectFocus.right -= nDropBtnWidth;
////////////////////////////////////////
// Button in a normal state //
////////////////////////////////////////
if (!m_bPushed || m_bMenuPushed)
pDC->DrawFrameControl(&btnRect,DFC_BUTTON,DFCS_BUTTONPUSH);
////////////////////////////////////////
// Default Button State //
////////////////////////////////////////
if ((m_bDefaultBtn || m_bPushed) && !bDisabled)
{
pDC->FrameRect(&lpDIS->rcItem,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
if (m_bPushed && !m_bMenuPushed)
pDC->FrameRect(&btnRect,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
}
////////////////////////////////////////
// State Focus //
////////////////////////////////////////
if (lpDIS->itemState & ODS_FOCUS || m_bPushed)
{
pDC->FrameRect(&lpDIS->rcItem,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
if (!m_bMenuPushed)
pDC->DrawFocusRect(&rectFocus);
}
////////////////////////////////////////
// Action Focus //
////////////////////////////////////////
if ((lpDIS->itemAction & ODA_FOCUS))
if (!m_bMenuPushed)
pDC->DrawFocusRect(&rectFocus);
}
////////////////////////////////////////
// Draw out bitmap //
////////////////////////////////////////
// Draw out bitmap
if (m_bLoaded)
{
if (!bDisabled)
{
m_IL.DrawIndirect(pDC,0,CPoint(6+m_bPushed,6+m_bPushed), CSize(m_bm.bmWidth, m_bm.bmHeight), CPoint(0,0),ILD_NORMAL);
}
else
{
pDC->DrawState(CPoint(6+m_bPushed,6+m_bPushed), CSize(m_bm.bmWidth, m_bm.bmHeight), m_hbmpDisabled, DST_BITMAP | DSS_DISABLED);
}
}
////////////////////////////////////////
// Draw out text //
////////////////////////////////////////
pDC->SelectObject(pFont);
CRect rectText(rectFocus);
if (!m_bSplit)
rectText.right -= nDropBtnWidth;
rectText.left += m_bm.bmWidth + 2;
CString strCaption;
GetWindowText(strCaption);
pDC->SetBkMode(TRANSPARENT);
pDC->SetBkColor(GetSysColor(COLOR_BTNFACE));
if (ODS_DISABLED & lpDIS->itemState)
{
rectText.OffsetRect(1,1);
pDC->SetTextColor(GetSysColor(COLOR_WINDOW));
pDC->DrawText(strCaption,rectText,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
rectText.OffsetRect(-1,-1);
pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
pDC->DrawText(strCaption,rectText,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
}
else
{
pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
pDC->DrawText(strCaption,rectText,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
}
CRect rectSplit(btnRect);
rectSplit.DeflateRect(2,2);
rectSplit.right -= nDropBtnWidth;
////////////////////////////////////////
// Drop down split //
////////////////////////////////////////
if (m_bSplit)
{
CPen brFace(PS_SOLID,1,GetSysColor(COLOR_3DSHADOW));
pDC->SelectObject(&brFace);
pDC->MoveTo(rectSplit.right, rectSplit.top);
pDC->LineTo(rectSplit.right, rectSplit.bottom);
CPen brLite(PS_SOLID,1,GetSysColor(COLOR_3DHILIGHT));
pDC->SelectObject(&brLite);
pDC->MoveTo(rectSplit.right+1 , rectSplit.top);
pDC->LineTo(rectSplit.right+1, rectSplit.bottom);
}
////////////////////////////////////////
// Draw Arrow //
////////////////////////////////////////
rectSplit.left = rectSplit.right;
rectSplit.right += nDropBtnWidth;
CPoint pt(rectSplit.CenterPoint());
pt += CPoint(m_bPushed,m_bPushed);
CPen penBlack(PS_SOLID, 1, bDisabled ? GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_WINDOWTEXT));
pDC->SelectObject(&penBlack);
DrawArrow(pDC,pt);
////////////////////////////////////////
// Drop down state //
////////////////////////////////////////
if (m_bMenuPushed && !bDisabled)
{
rectSplit.InflateRect(1,1);
pDC->DrawEdge(rectSplit,BDR_SUNKENOUTER, BF_RECT);
}
if(hTheme)
{
PFNCLOSETHEMEDATA pCloseThemeData = (PFNCLOSETHEMEDATA)GetProcAddress(m_themeLib, "CloseThemeData");
if(!pCloseThemeData)
return;
(pCloseThemeData)(hTheme);
}
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: DrawArrow
//
// DESCRIPTION: Draws drop down arrow, we could use DrawFrameControl - a bit too
// messy
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::DrawArrow(CDC* pDC,CPoint ArrowTip)
{
CPoint ptDest;
pDC->SetPixel(ArrowTip,RGB(0,0,0));
ArrowTip -= CPoint(1,1);
pDC->MoveTo(ArrowTip);
ptDest = ArrowTip;
ptDest += CPoint(3,0);
pDC->LineTo(ptDest);
ArrowTip -= CPoint(1,1);
pDC->MoveTo(ArrowTip);
ptDest = ArrowTip;
ptDest += CPoint(5,0);
pDC->LineTo(ptDest);
ArrowTip -= CPoint(1,1);
pDC->MoveTo(ArrowTip);
ptDest = ArrowTip;
ptDest += CPoint(7,0);
pDC->LineTo(ptDest);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: OnLButtonDown
//
// DESCRIPTION: handles button pressed state, including drop down menu
//
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
if (m_bMenuPushed)
{
m_bMenuPushed = FALSE;
Invalidate();
return;
}
if (!m_bSplit || HitMenuBtn(point))
{
OnMenuBtn();
return;
}
m_bPushed = TRUE;
Invalidate();
CButton::OnLButtonDown(nFlags, point);
}
BOOL CCoolButton::OnMenuBtn()
{
if (!m_bMenuLoaded)
{
if (m_nID2)
{
GetParent()->PostMessage(WM_COMMAND, m_nID2, 0);
m_bMenuPushed = TRUE;
Invalidate();
return TRUE;
}
}
else
{
m_bMenuPushed = TRUE;
Invalidate();
CRect rc;
GetWindowRect(rc);
int x = rc.left;
int y = rc.bottom;
m_menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON,x,y,GetParent());
m_bMenuPushed = FALSE;
Invalidate();
return TRUE;
}
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: OnLButtonUp
//
// DESCRIPTION: Redraws button in normal state
//
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::ClearButtonPushed()
{
if (m_bPushed)
{
m_bPushed = FALSE;
Invalidate();
}
if (m_bMenuPushed)
{
m_bMenuPushed = FALSE;
Invalidate();
}
}
void CCoolButton::OnLButtonUp(UINT nFlags, CPoint point)
{
ClearButtonPushed();
CButton::OnLButtonUp(nFlags, point);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: OnMouseMove
//
// DESCRIPTION: Tracks mouse whilst pressed
//
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
LRESULT CCoolButton::OnMouseHover(WPARAM wparam, LPARAM lparam)
{
m_bOverControl=TRUE;
Invalidate();
return 1;
}
LRESULT CCoolButton::OnMouseLeave(WPARAM wparam, LPARAM lparam)
{
m_bTracking = FALSE;
m_bOverControl = FALSE;
Invalidate(FALSE);
return 0;
}
void CCoolButton::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bPushed)
{
ClientToScreen(&point);
if (WindowFromPoint(point) != this)
{
m_bPushed = FALSE;
Invalidate();
}
}
if (!m_bTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE|TME_HOVER;
tme.dwHoverTime = 1;
m_bTracking = _TrackMouseEvent(&tme) != FALSE;
}
CButton::OnMouseMove(nFlags, point);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: SetButtonImage
//
// DESCRIPTION: Sets the button image, COLORREF crMask specifics the transparency
// color
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
BOOL CCoolButton::SetButtonImage(UINT nResourceId, COLORREF crMask)
{
// The ID must exist also as a bitmap resource!!!
m_btnImage.LoadBitmap(nResourceId);
m_btnImage.GetObject(sizeof m_bm, &m_bm);
m_IL.Create( nResourceId, m_bm.bmWidth, 1, crMask );
m_bLoaded = TRUE;
m_crMask = crMask;
HBITMAP bmTemp;
COLORMAP mapColor;
mapColor.from = crMask;
mapColor.to = RGB(255,255,255);
bmTemp = (HBITMAP)::CreateMappedBitmap(AfxGetApp()->m_hInstance, nResourceId, IMAGE_BITMAP, &mapColor, 1);
m_hbmpDisabled = (HBITMAP)::CopyImage(bmTemp, IMAGE_BITMAP, m_bm.bmWidth, m_bm.bmHeight, LR_COPYDELETEORG);
return m_bLoaded;
}
void CCoolButton::OnSetFocus(CWnd* pOldWnd)
{
CButton::OnSetFocus(pOldWnd);
Invalidate();
}
void CCoolButton::OnKillFocus(CWnd* pNewWnd)
{
CButton::OnKillFocus(pNewWnd);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: OnSysColorChange
//
// DESCRIPTION: Called when system colors change, force a button redraw
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::OnSysColorChange()
{
CButton::OnSysColorChange();
Invalidate();
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: HitMenuBtn
//
// DESCRIPTION: Helper function to test for menu button hit...
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
// L Brasington 03/06/06 2.0 Rewritten as CCoolButton
//
////////////////////////////////////////////////////////////////////////////////
BOOL CCoolButton::HitMenuBtn(CPoint point)
{
if (!m_bMenuLoaded && !m_nID2)
return FALSE; // Don't allow menu button drop down if no menu items are loaded
ClientToScreen(&point);
CRect rect;
GetWindowRect(rect);
rect.left = rect.right - nDropBtnWidth;
return rect.PtInRect(point);
}
////////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: AddMenuItem
//
// DESCRIPTION: Adds a menu item and id to our menu.
//
// NOTES:
//
// MAINTENANCE:
// Name: Date: Version: Notes:
// NT ALMOND 210100 1.0 Origin
//
////////////////////////////////////////////////////////////////////////////////
BOOL CCoolButton::AddMenuItem(UINT nMenuId,const CString strMenu, UINT nMenuFlags)
{
BOOL bRet = m_menu.AppendMenu(nMenuFlags | MF_STRING, nMenuId, (LPCTSTR)strMenu);
m_bMenuLoaded |= bRet;
return bRet;
}
////////////////////////////////////////////////////////////////////////////////
void CCoolButton::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch ( nChar )
{
case VK_DOWN:
OnMenuBtn();
break;
}
CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
}
Leigh Brasington
|
|
|
|
|
Thanks Leigh, you could of emailed me the source
Seriously I should get round to getting a new version out.
|
|
|
|
|
I have a cool push menu button in a property page and I can drive it very easily from the mouse. Unfortunately, I can't seem to drive it very well from the keyboard which is a problem as my dialogs may be used by disabled users (mouse impaired?). I have the button specified as &Add so ALT+A should drive it but I have multiple problems:
1. If the current focus is outside of the property page (on the tabs or common buttons), then the first selection of ALT+A selects the primary value of my button. If the focus is within the property page then the first selection of ALT+A sets the focus to the button and then the second press of ALT+A will issue the default command (equivalent of a mouse left-click on the non menu side of the button).
2. Can't show the menu in any form when using the keyboard. Using the context menu button has no effect.
Any suggestions on ways around this or how to enhance the class?
Carl
|
|
|
|
|
i have an ActiveX button menu which contains a list of web site names. when you press them, it takes you to the website. Users are to be able to add/delete sites from the list. i have managed to get the name of a new site added to the list, but i am unable to link the URL to it so they can go to the page. Any ideas?
|
|
|
|
|
:-DHi,
Simple eliminate the m_pParentWnd and replace it with GetParent()
so subclassing doesn't need to call your 'Create' method.
|
|
|
|
|
Allow menu states be dynamically changed with :
void CCoolBtn::ChangeMenuFlags(UINT nMenuId, UINT nMenuFlags)
{
m_menu.CheckMenuItem(nMenuId, nMenuFlags | MF_BYCOMMAND);
}
For instance, this allows me to check/uncheck menu items to reflect the GUI state.
She's so dirty, she threw a boomerang and it wouldn't even come back.
|
|
|
|
|
Hi,
Nice class but direct subclassing does not work!
Simple eliminate the m_pParentWnd and replace it with GetParent()
so subclassing doesn't need to call your 'Create' method.
My two pence,;)
Cabbi
|
|
|
|
|
Sir;
Thanks for this nice code.
I want to use this for arrow on the left side of the button,
instead of the right side.
HOW CAN I DO THAT?
Also, how can i use bitmaps for the added menu items instead of text.
I want to use bitmaps from resources.
Please help.
Regards
amit
|
|
|
|
|
There is an unneeded semicolon character ";" in CCoolBtn::Create function.
|
|
|
|
|
Normski. - Professional Windows Programmer
|
|
|
|
|
Hi,
This really works greate for me and I am currently using this Cool Push Menu Button in my project, Ccould you give me your permission to use it freely. Please e-mail me at krishna_navuduri@yahoo.com or shreya_navuduri@yahoo.com.
Thanks for your help.
Krishna
|
|
|
|
|
Permission Granted! Pooooof!
Blogless
|
|
|
|
|
wtf
|
|
|
|
|
I wanted to add a bitmap to the submenus of this button.
Here is the code, but it fails because GetSubMenu always returns NULL.
I changed the code in this way:
class CCoolBtn : public CButton
{
// Construction
public:
CCoolBtn();
BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
BOOL SetButtonImage(UINT nResourceId, COLORREF crMask);
BOOL AddMenuItem(UINT nMenuId,const CString strMenu, UINT nFlags);
void AddImage( int nID, CBitmap& bmpEnabled, CBitmap& bmpDisabled );
...
And added the functions:
void CCoolBtn::AddImage( int nIndex, CBitmap& bmpEnabled, CBitmap& bmpDisabled )
{
UINT nNum = m_menu.GetMenuItemCount();
ASSERT( nNum > nIndex );
CMenu* pSubmenu = m_menu.GetSubMenu(nIndex);
ASSERT( pSubmenu->SetMenuItemBitmaps(nIndex, MF_BYPOSITION, &bmpEnabled, &bmpDisabled));
}
pSubmenu is always null. What is wrong with it?
Thanks
-Julie
|
|
|
|
|
Here is the code that worked, duh!
void CCoolBtn::AddImage( int nIndex, CBitmap& bmpEnabled, CBitmap& bmpDisabled )
{
ASSERT( m_menu.SetMenuItemBitmaps( nIndex, MF_BYPOSITION, &bmpEnabled, &bmpDisabled ) );
}
|
|
|
|
|
Thanks once again for the nice code.
i would be thankful if someone can tell me how can i load bitmaps from resources from this code.
regards
amit
|
|
|
|
|
Has the problem been solved?
please let me know how has you solved to me.
modified 13-Oct-18 20:34pm.
|
|
|
|
|
I found this code very useful.thanks.
i added the following functions to your code.
BOOL CCoolBtn::RemoveMenuItem(UINT nMenuId,const CString strMenu, UINT nMenuFlags)
{
BOOL bRet = m_menu.RemoveMenu( nMenuId,nMenuFlags | MF_STRING);
m_bMenuLoaded |= bRet;
return bRet;
}
BOOL CCoolBtn::EnableMenuItem(UINT nMenuId,const CString strMenu, BOOL nEnable)
{
BOOL bRet = m_menu.EnableMenuItem(nMenuId , nEnable);
m_bMenuLoaded |= bRet;
return bRet;
}
in the haeder file
BOOL RemoveMenuItem(UINT nMenuId,const CString strMenu, UINT nFlags);
BOOL EnableMenuItem(UINT nMenuId,const CString strMenu, BOOL nEnable=FALSE);
and use it like for enabling and disabling the menu items respectively:
m_button1.EnableMenuItem(IDC_BUTTON9,"HELLO",FALSE);
m_button1.EnableMenuItem(IDC_BUTTON9,"HELLO",TRUE);
say hello is your first string and IDC is the ID of the menu item.
hope somebody finds it useful
regards
amit
AMIT BAMZAI
|
|
|
|
|
i added the following functions to your code.
BOOL CCoolBtn::RemoveMenuItem(UINT nMenuId,const CString strMenu, UINT nMenuFlags)
{
BOOL bRet = m_menu.RemoveMenu( nMenuId,nMenuFlags | MF_STRING);
m_bMenuLoaded |= bRet;
return bRet;
}
BOOL CCoolBtn::EnableMenuItem(UINT nMenuId,const CString strMenu, BOOL nEnable)
{
BOOL bRet = m_menu.EnableMenuItem(nMenuId , nEnable);
m_bMenuLoaded |= bRet;
return bRet;
}
in the haeder file
BOOL RemoveMenuItem(UINT nMenuId,const CString strMenu, UINT nFlags);
BOOL EnableMenuItem(UINT nMenuId,const CString strMenu, BOOL nEnable=FALSE);
and use it like:
m_button1.EnableMenuItem(IDC_BUTTON9,"HELLO",FALSE);
m_button11.EnableMenuItem(IDC_BUTTON9,"HELLO",TRUE);
say hello is your first string and IDC is the ID of the menu item.
hope somebody finds it useful
regards
amit
AMIT BAMZAI
|
|
|
|
|
I was expecting that when the main part of the button ( not the down arrow ) was pressed an OnCommand message would have been gererated, with the ID of the button. ie in the example code this is IDC_FILE. Does anybody know how to make the CCoolBtn do this. Thanks.
Simon
|
|
|
|
|
::OnLButtonDown(...)
{
...
PostMessage(WM_COMMAND, MAKEWPARAM(GetDlgItemId(),0), (LPARAM) m_hWnd);
...
}
Normski. - Professional Windows Programmer
|
|
|
|
|
Hi Norm/Simon,
Or remove ReleaseCapture() from CCoolBtn::OnLButtonUp() which shouldn't be there.
Neville Franks, Author of ED for Windows. www.getsoft.com
|
|
|
|
|
I have also found this is a better method. I wondered if the ReleaseCapture was needed for the DrawItem to work correctly but if so it is too subtle for me to see. Even if that is the case I would rather have the default button message handled normally.
|
|
|
|
|
In DrawItem(), there is a statement:
BOOL bDefaultBtn = GetButtonStyle() & BS_DEFPUSHBUTTON;
to determine whether the button has the default button style. However, I find bDefaultBtn always returns TRUE even it isn't a default button and user has not click it yet. What's the problem?
|
|
|
|
|
This button includes a header called splitbtn.h I don't appear to have this where does it come from?
|
|
|
|
|