Introduction
I needed a breadcrumb bar like the one in Windows Vista so I could show a path and have the path to be clickable. But I also needed a crumb-bar in another project, and it had nothing to do with file paths. So I built this CrumbBar
controller that is generic. It can show any string with delimiters as a crumb-bar.
Features
- Any string with a delimiter can be shown as a crumbbar:
- Can go into Edit mode if clicked on (configurable on what clicks will turn it to editable).
- Send notification on what item was clicked. Notifications can be sent for both single and double clicks on all three mouse buttons.
- Support 'go back' item if not all crumb items fit in the controller.
- Support left margin and item spacing.
- Support gradient background.
- Can easily be custom drawn to implement your own drawing of the crumb items.
Create the Controller
Adding MZCrumbBar
to a dialog:
- Added a custom controller to the layout where you want to have it.
- Set the ID of the properties to something like
IDC_CRUMBBAR
. - Class name in properties must be "
MZCrumbBarCtrl
". - Then set the style flags you want, like 0x50810001. If you do not want any border (
WS_BORDER
), remove 0x00800000 from the value. - Then add a
MZCrumbBar
variable to your dialog class. - To connect the custom controller in the dialog layout with the
m_CrumbBar
variable, you need to add some code into DoDataExchange
:
void CCrumbBarDemoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_CRUMBBAR, m_CrumbBar);
}
- Then configure the controller how you want it in
OnInitDialog()
.
Configuring
Here are the options on when the controller should turn into Edit mode. Set them as StyleEx
flags in Create
, or with MZCrumbBar::Style(...)
.
#define CRU_EDITOUTSIDE 0x00000010 // Click must be outside of crumb items.
#define CRU_EDITONCLK_L 0x00000100 // Enter Edit mode on Left Click
#define CRU_EDITONDBL_L 0x00000200 // Enter edit mode on Left DblClick
#define CRU_EDITONCLK_R 0x00000400 // Enter Edit mode on Right Click
#define CRU_EDITONDBL_R 0x00000800 // Enter edit mode on Right DblClick
#define CRU_EDITONCLK_M 0x00001000 // Enter Edit mode on Middle Click
#define CRU_EDITONDBL_M 0x00002000 // Enter edit mode on Middle DblClick
#define CRU_LASTITEMCOLD 0x00010000 // Show no hover action for the last item
#define CRU_LASTITEMNOCLK 0x00020000 // Do not generate click action for the last item
#define CRU_LASTITEMNODELIMITER 0x00040000 // Do not draw a delimiter for the last item
#define CRU_DONOTSTRIPDELIMITER 0x00080000 // Do not strip double delimiter
Flags for configuring how the delimiter should be shown (set the option via the DelimiterMode(...)
function):
#define DM_STRIP 0 // Strip the delimiter char
#define DM_LEFT 1 // Show Delimiter in the Left part
#define DM_RIGHT 2 // Show Delimiter in the right part
Set Colors and Margins
m_CrumbBar.ColorDefault( RGB(255, 0, 0));
m_CrumbBar.ColorHot( RGB(255, 0, 0));
m_CrumbBar.BackgroundColor( RGB(255, 0, 0), RGB(0,0,0), true);
m_CrumbBar.Margin(10);
m_CrumbBar.ItemSpacing(6);
Using the Crumbbar
m_CrumbBar.Path(_T("C:\\MyFolder\\SubFiles1\\SubFolder2\\"));
m_CrumbBar.Delimiter(_T("\\"));
m_CrumbBar.DelimiterMode(DM_RIGHT);
MZCrumbBar::CrumbBarItem PreItem(_T(""), _T("..\\"));
m_CrumbBar.PreItem(PreItem);
m_CrumbBar.BuildCrumbbar();
CString path = m_crumbBar.Path();
CString path = m_crumbBar.GetPath( pCrumbBarItem );
Notifications
There are a few notification messages that are used to notify the owner window when things have happened:
#define NMCB_LBCLICK 1000 // User clicked with Left Mouse Button
#define NMCB_RBCLICK 1001 // User clicked with Right Mouse Button
#define NMCB_MBCLICK 1002 // User clicked with Middle Mouse Button
#define NMCB_LBDBLCLICK 1003 // User double clicked with Left Mouse Button
#define NMCB_RBDBLCLICK 1004 // User double clicked with Right Mouse Button
#define NMCB_MBDBLCLICK 1005 // User double clicked with Middle Mouse Button
#define NMCB_EDITCHANGE 1010 // User changed path by editing it
To catch the notification message, you can do this in your dialog:
afx_msg void OnCrumbBarItemClicked(NMHDR *pNotifyStruct, LRESULT* pResult) ;
BEGIN_MESSAGE_MAP(CCrumbBarDemoDlg, CDialog)
ON_NOTIFY( NMCB_LBCLICK, IDC_CRUMBBAR , OnCrumbBarItemClicked)
END_MESSAGE_MAP()
void CCrumbBarDemoDlg::OnCrumbBarItemClicked(NMHDR* pNotifyStruct, LRESULT* pResult)
{
NM_CRUMBBARITEM* pnmCrumbBarItem = (NM_CRUMBBARITEM*)pNotifyStruct;
pnmCrumbBarItem->pCrumbBarItem;
pnmCrumbBarItem->strCrumbPath;
pnmCrumbBarItem->pt;
...
}
Custom Draw the CrumbBar Items
To change the CrumbBar
to a custom look, you need to override a couple of functions.
virtual int OnMeasureItem(CDC* pDC, CrumbBarItem* pItem);
virtual int OnMeasurePreItem(CDC* pDC);
virtual void DrawCrumbItem(CrumbBarItem* pItem, CDC* pDC, CRect rc);
virtual void DrawPreItem(CrumbBarItem* pItem, CDC* pDC, CRect rc);
Take a look at CBlockCrumbBar.h/.cpp in the source for the demo app to see how it can be done.
Credits
- Borrowed Gradient code from CLabel by Norm.net
History
For full history, check the header in MZCrumbBar.cpp.
- v1.3: 2010-11-13
- Added new flag
CRU_DONOTSTRIPDELIMITER
that will keep the double delimiter. - Double delimiter is used to tell
MZCrumbarCtrl
that it should not break a path when it sees a delimiter. E.g.: "Main-Sub-Sub--Menu" -> last item is normally shown as "Sub-Menu", but with this flag, it is shown as "Sub--Menu". Since the double delimiter is not stripped, for example "\\Server\Share\Folder" -> the first item will now be shown as "\\Server" and not as "\Server".
- v1.2: 2010-04-15
- Added improvements/fixes provided by Iain Clarke
- Three more
BuildCrumbbar(...)
functions for special situations. - Refactored how a path is parsed.
- Added
CRU_LASTITEMNODELIMITER
. If style is set, the delimiter will not be shown for the last crumb-bar item. - Style can now be set using
styleEx
. - Changed default hot color to
COLOR_HOTLIGHT
. - Added possibility to store custom data in a crumb-bar item.
- Added
SetItemData
/GetItemData
of custom data to crumb-bar items.
- Fixed so that double delimiter now works again. Double delimiter should be part of the crumb-path name and not split the path.
- Changed so that items are added to
m_vCrumbItems
via the virtual function AddCrumbItem(...)
. - Fixed so that empty path parts are not added to the path.
- v1.1 - 2010-03-17 - First public version. Fixed minor draw issue.
- v1.0 - 2009-10-10 - First version.