Table of Contents
Introduction
Recently, a client requested an Outlook 2003 style navigation bar for his WTL project. Not finding a suitable control on CodeProject in WTL, I decided to create one. I hope you find this control useful for your own projects; appropriate attribution of credit would be appreciated.
An Outlook 2003 navigation bar is equivalent to a tabbed window system that changes two views at once. It can accommodate any number of "tabs", although it works best with a relatively mediocre amount.
This project requires:
- WTL 7.5 or later.
- atlgdix.h from www.viksoe.dk.
- GDI+ from Microsoft.
The Features
Outlook Style View Switching -- Outlook takes care of a tremendous number of details to appropriately handle tooltips, window resizing, sticky splitter, etc. I have tried to implement each of these capabilities, and in a few cases, improved on them.
Chevron Menu -- Like the Outlook version, there is a chevron menu (it is, however, not themed...this may be added in a future version) on the command bar. Buttons that don't fit on the command bar or as a big button are placed on it below the Navigation Pane Options.
Navigation Pane Options --The Navigation Pane Options dialog box lets you swap and inactivate buttons from your view in order to customize your layout to what you like best. The Navigation Pane Options is fully operational (except that the hotkey system works like all the other Windows listboxes of the same kind...and that's not a good thing), with hovering and appropriate selection. Its list view is custom, and can be accessed in ChecklistView.h.
Theme Support -- This program has basic theme support. Not much to say here except that it changes based on the Windows theme, which you may find useful for applying extra eye-candy to your program. Most of this is assimilated from Roger Headrick's theming code.
How to Use It
The Necessary Code
This code is to be put after you've made all the status bars and have updated the layout. First, we need to get the client rect, set our parameters that must be set before the window is created, and then create the window.
RECT ClientRect;
GetClientRect(&ClientRect);
m_navwindow.SetButtonHeight(31);
m_navwindow.SetSmallButtonWidth(24);
m_hWndClient = m_navwindow.Create(m_hWnd, ClientRect,
L"Nav_Main", WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
Then, we set the distance from the top that the buttons start popping back (so that you don't cover up anything important). This can be set at any place in the program, as it always defaults to zero if not set (in fact, you can edit the tabbed buttons so that it sets the pop-back differently based on what view it's showing). The following for
loop is to define the windows and their HWND
s that are used by the tabbed buttons.
m_navwindow.SetPopBack(150);
button_view.resize(9);
button_view_top.resize(9);
for (size_t view_increment = 0; view_increment <
button_view.size(); view_increment++)
{
button_view[view_increment].Create(m_navwindow, rcDefault,
NULL, WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
button_view_top[view_increment].Create(
m_navwindow.m_HorizontalSplitter, rcDefault,
NULL, WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
std::wostringstream vertical_caption;
vertical_caption << L"Vertical " << view_increment;
button_view[view_increment].window_caption = vertical_caption.str();
button_view[view_increment].is_horizontal = false;
std::wostringstream horizontal_caption;
horizontal_caption << L"Horizontal " << view_increment;
button_view_top[view_increment].window_caption =
horizontal_caption.str();
button_view_top[view_increment].is_horizontal = true;
button_view_top[view_increment].pop_back_amount =
m_navwindow.m_HorizontalSplitter.pop_back_y;
}
We then set the font of the buttons, and then, most importantly, create them. The first argument is the button's caption, the second the image path it uses as a big button, the third the image path it uses as a button on the command bar, and the last two, respectively, are the HWND
s to what will appear on the right hand side across from the vertical bar and what will appear on the top side across the horizontal bar.
Then, we set the splitter position of the vertical splitter to the chosen width, and the default buttons to what we want to see... a value of 5 means that we will be seeing the first four buttons added with AddButtonWithView
on top of a command bar showing the other five. For an alternate example, if you SetDefaultButtons(4)
, you will see three big buttons on top of a command bar holding the other six.
m_navwindow.SetButtonFont(L"Arial", 8, FontStyleBold);
m_navwindow.AddButtonWithView(L"Print",
L"RolloutIcons\\Print_2.tif",
L"RolloutIcons\\Print_2_Small.tif",
button_view[0], button_view_top[0]);
m_navwindow.AddButtonWithView(L"Add",
L"RolloutIcons\\Add_2.tif",
L"RolloutIcons\\Add_2_Small.tif",
button_view[1], button_view_top[1]);
m_navwindow.AddButtonWithView(L"Edit",
L"RolloutIcons\\Edit_2.tif",
L"RolloutIcons\\Edit_2_Small.tif",
button_view[2], button_view_top[2]);
m_navwindow.AddButtonWithView(L"Delete",
L"RolloutIcons\\Delete_2.tif",
L"RolloutIcons\\Delete_2_Small.tif",
button_view[3], button_view_top[3]);
m_navwindow.AddButtonWithView(L"Search",
L"RolloutIcons\\Search_2.tif",
L"RolloutIcons\\Search_2_Small.tif",
button_view[4], button_view_top[4]);
m_navwindow.AddButtonWithView(L"Back",
L"RolloutIcons\\Back_2.tif",
L"RolloutIcons\\Back_2_Small.tif",
button_view[5], button_view_top[5]);
m_navwindow.AddButtonWithView(L"Forward",
L"RolloutIcons\\Forward_2.tif",
L"RolloutIcons\\Forward_2_Small.tif",
button_view[6], button_view_top[6]);
m_navwindow.AddButtonWithView(L"Save",
L"RolloutIcons\\Save_2.tif",
L"RolloutIcons\\Save_2_Small.tif",
button_view[7], button_view_top[7]);
m_navwindow.AddButtonWithView(L"Exit",
L"RolloutIcons\\Exit_2.tif",
L"RolloutIcons\\Exit_2_Small.tif",
button_view[8], button_view_top[8]);
m_navwindow.SetSplitterPos(242);
m_navwindow.SetDefaultButtons(5);
Miscellaneous Notes
- If you don't set the default buttons, it'll default to 0.
- If you don't specify a larger image-path, there will just be text on the button, and it will align with the left-hand side of the button view.
- If you don't specify a smaller image-path, the buttons will still show up on the command bar, but they won't be visible to the human eye without moving the mouse there.
- The
ButtonView_Tabbed
is to be treated as a vertical splitter.
- Icons won't be painted if the size of the bar is too small.
- There are several pieces of this program that, while some are optional, some are absolutely needed. The absolutely needed pieces of code are located in the ButtonView Items and Required Items filters/folders. The ButtonView Tabbed version is there for practical use, and serves to demonstrate how you can use my code (through inheritance and some necessary overriding) and add features to it if you wish. However, if you choose to use a different class implementing the ButtonView template, you must supply support for a horizontal and vertical splitter, or else the ButtonView simply won't work.
- If you wish to make a list of buttons that don't act as tabs and just do functions instead of opening views, overwrite the function
OnSelect
. It takes one integer for an argument, and it is the ID of the button, with 0 being the topmost one. You can then check and run various functions based on what i
is.
Documentation
The following is the documentation of functions you may use from ButtonView_Tabbed. There are other functions, but they serve as internal functions. These are the ones you would use.
AddButtonWithView(std::wstring caption, std::wstring imagepath, std::wstring imagepath_small, HWND right_side, HWND top_side)
-- Adds a button to the bottom of the 'list' of buttons. caption
is self-explanatory, and carries onto the button's tooltip when it's on the command bar; imagepath
and imagepath_small
are self-explanatory, and right_side
and top_side
are the handles to the windows that will appear on the right side and above of the button view.
AddButton(std::wstring caption, std::wstring imagepath, std::wstring imagepath_small)
-- ButtonView core function. Same as AddButtonWithView
, but doesn't add with views. AddButtonWithView
calls this and then adds a view in its own lines.
SetButtonFont(std::wstring type, Gdiplus::REAL size, INT style)
-- Sets the style of the buttons (type
is font, size
is font size, and style
is the add-on to the button, such as bold).
SetDefaultButtons(int i)
-- Sets the number (i
- 1, as command bar is considered a button under this setting) of buttons that you will see when the window starts up.
SetPopBack(int pop_back_amount)
-- Sets the distance in pixels away from the top of the client window. Defaults to 0, the top of the client window, if not set.
SetButtonHeight(int i)
-- Sets the pixel height of the big buttons and the command bar.
SetSmallButtonWidth(int i)
-- Sets the pixel width of the buttons on the command bar. Chevron always stays at 24 pixel width.
OnSelect(int i)
-- ButtonView core function. The function that gets called when a button is selected. Purposefully, this is blank and is to be overridden in every class that uses the ButtonView template. If you set the ButtonView's button_is_selected
parameter equal to i
, you will receive the selected tab effect on the Print button. If not, then clicking the button will just be like clicking a normal button...it'll flash when you click it, and then revert back to normal upon release.
Swap_Buttons(int i, int j)
-- ButtonView core function. It is the function that is called when changes have been made to the Navigation Pane Options, where i
is the old button and j
is the new button. It is intentionally left blank by default, as the necessary swapping is done beforehand. You should override this and add the necessary lines for swapping the functions and views and stuff of the buttons. ButtonView_Tabbed
overrides and replaces it with code to switch the view of the buttons.
Credits
I would like to thank Viksoe for his atlgdix.h for the off-screen drawing (no flicker for the buttons or my sample exe and its sample windows), Roger Headrick for his color theming code, Terry Denham for his snap splitter, and finally, Firefox and tom-cat.com for supplying the icons I was able to change and fit into my sample program. I also would like to thank anyone that I've forgotten to thank in name.
History
- Version 1.0 -- Navigation sidebar released!