Table of Contents

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.

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.

<PRE lang=c++>RECT ClientRect;
GetClientRect(&ClientRect);
// Set the button parameters. You must set
// these before you create the navwindow.
// If you don't, don't expect it to work ;)
// The button height is the height
// of the big buttons and the command bar
m_navwindow.SetButtonHeight(31);
// The small button width is the width
// of the little buttons on the command bar.
m_navwindow.SetSmallButtonWidth(24);
// Drop in our control.
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 HWNDs that are used by the tabbed buttons.

<PRE lang=c++>// Set the distance from the top of the client
// rect of the window where the buttons start popping back.
// If not set or set to 0, the buttons will pop back
// when the buttons are pushed past the top of the window.
m_navwindow.SetPopBack(150);
// For the sake of example, there is only one sample window for all the buttons.
// If you want a different window for each button (you probably do),
// you will want a different line and class for each window in your Mainframe.
// As these are for example, the following two lines
// and the for loop are to be erased and replaced with whatever you want.
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;
}
// Don't erase anything past here...it contains
// the rest of the parameters needed ;)

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 HWNDs 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.

Miscellaneous Notes

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.

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!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

I'm a beginner programmer and I enjoy dabbling in various programs through the use of C++, where I've used the WTL library to create GUIs. I've also programmed with C++ compiled into FastCGI for WWW use.

i am fresher, i create one application in asp.net, like having some text.. i want to add the fields which i enter in the text.if i click the button icon it will add in to the databases. help me yai need the code for that

I don't understand what you want to do. If I'm thinking right, what you want is not in design of the program, and you'll have to code it yourself. If you want to add a button, call AddButton(...). Then, if you want to detect the button click, you need to find the OnSelect function and determine what to do when you receive int i. In a rather unconventional step, I made it so when i == 0 no button is selected, while when i > 0 then a button is selected. You should use buttons[i-1] in the OnSelect function to obtain the data of the button.

If you want to remove a button from the list, I don't believe I've made that possible. You could theoretically do it by removing the button from sight, then performing an array-like removal--overwrite the button with its next.

____________________________________________________________~Life without God would be a sad life indeed.

Hm. Well for starters, it looks like you don't have atlgdix.h linked. Now my new version (sorry, still haven't uploaded it; hoping to this week) takes care of this by just using WTL's CDoubleBufferImpl.

Anyway, to bypass it in this version, copy atlgdix.h and put it in a folder that is included in your VS. I just keep it copied into my WTL folder, and it's picked up with everything else from there.

____________________________________________________________~Life without God would be a sad life indeed.

It's a hack that somewhat allows you to get the color of the Windows XP theme that uses WTL's CTheme capabilities. It returns one color of the theme and it doesn't fully match the colors of theming as according to Microsoft Office Outlook 2003, but you can modify the color as you see fit to get a based upon gradient. I've sought to eventually sit down and write my own version, but alas I haven't been able to. Anyway, I found it in the WTL Yahoo Group.

I signed on the group and checked, and the file appears to be gone. It looks like they scrubbed it a while ago as a lot of the files are missing. You can find the theming code in the source zip. It's called "xp2003colors.h".

____________________________________________________________~Life without God would be a sad life indeed.

I have finished, but I must reupload the code, which I haven't got to doing for months :X. The only issue with using WTL's inside CDoubleBufferImpl is that it doesn't receive an invalidated rect and must repaint the entire program. However, that's what I do at the moment anyway, because I was unable to find a proper method of invalidating rects, so the conversion was rather easy. If I, however, wanted to make my GUI slightly faster, by invalidating rects, I would have to move back to atlgdix.h.

-- modified at 11:42 Monday 16th April, 2007

____________________________________________________________~Life without God would be a sad life indeed.

/GR- is a setting on Visual Studio. You might want to look it up. I -think- it may be "Configuration Properties >> C/C++ >> Advanced >> Calling Convention"; it is according to VS2005 anyway. __fastcall is /Gr, so I assume that might be what the problem is. You may have to change it to __cdecl (/Gd). At least, that's what I've used and it's compiled fine.

____________________________________________________________~Life without God would be a sad life indeed.

could we write that in visual basic.I mean i surfed the whole web truying to search for any components that could help me out with this navigation bar issue,It is really killing me,.I found a component at bitlaboratory.com.Its amazing.Just what i am llking for.It also costs 80$.I am thinking of buying it..honestly it is really killing me.If any knows any resourses..dlls..components u name it in vb (classic vb or vb.net please contact me i would rea;lly appreciate that..)

This is a while ago, but if you get around to reading this--I don't think I shall ever write this program in a VB variant. VB is rather difficult to use for increasingly complicated tasks for what it's not set-up to do. However, if you worked on applying C# code, you would be able to retranslate my program into it. Don't know if I shall, but it's definitely possible.

____________________________________________________________~Life without God would be a sad life indeed.

Thanks for pointing that out! I suppose Vista must change the size of the splitter, since the splitter has always been 4 px high for me, but this change should work in the long run. I'll upload the fix next version.

____________________________________________________________~Life without God would be a sad life indeed.~Life without coffee would be a tired life indeed.

VCE...you mean the Express edition? Well, since it works for my Visual Studio, I assume it might be the express edition that gets upset. I'll change it to rcClip to make it compile for VCE users in the next version. Fortunately, I don't believe the tooltipwindow needs to have a specific rect it's sized to, since it's automatically moved and resized upon hovering over the little mini command bar buttons.

I probably should've included the license just in case people asked. All of my work, as I like it to be such, follows the GNU General Public License, and I'll probably mention it on my source code in the next upgrade.

Thanks for the feedback and sorry it took so long to get back!

____________________________________________________________~Life without God would be a sad life indeed.~Life without coffee would be a tired life indeed.

Good idea. I don't think there is anything in there that can't be done in GDI, though I think in some places it may take more lines to account for. I program in Windows XP for my clients and such, so I use GDI+ for convenience.

Using normal GDI is a good idea if you're programming in Windows 98 or Windows 2000 (that don't have the Microsoft redistributable installed).

____________________________________________________________~Life without God would be a sad life indeed.~Life without coffee would be a tired life indeed.

The Tabbed Window version is the Vertical Splitter itself, and it parents the right-hand side window and horizontal splitter, which parents the button view (the actual buttons) and top view.

Thus, if you do away with the vertical splitter, you will temporarily see nothing on the screen. However, as I have made my code in as many pieces as possible, you could then change the Tabbed View based on what you want. Like, in your intended function, I would make it inherit the Snap_Splitter.h characteristics and change the view-changing-related functions accordingly.

To answer your question, yes it should be easy to remove. If you just maintain the horizontal splitter and stick it in some fixed position without a vertical splitter, the program should still work. If it doesn't, let me know and I'll try removing the vertical splitter myself and see if I accidentally incorporated some inter-related dependency on it

____________________________________________________________~Life without coffee would be a sad [and tired] life indeed.

Oh one other thing - I don't like the way the icons are loaded (as my DLL is a shell extension, I have no concept of root folder so have no "base" to load the images from), variant to use embedded resouces would be a lot nicer for me...

Yea, I didn't work very hard on incorporating images (as you can see the only way to use the image system at the moment is to keep a folder of images in the same folder as the exe). It wasn't my focus and thus I didn't choose the best method of doing it. I could consider working on it for next version. I have had thoughts concerning embedding the images in the exe, but I never implemented it.

Really? Well thanks for pointing that out! I never noticed one. I'll definitely look for it when I go to write another piece of code.

____________________________________________________________~Life without coffee would be a sad [and tired] life indeed.

This was written in WTL. However, I do believe you can convert from WTL to MFC or put the two together. Eventually, I plan on turning this into a more universal control such as an ActiveX control or .NET control.

____________________________________________________________~Life without coffee would be a sad [and tired] life indeed.

I don't have access to the VC++ 6.0 environment, so I don't know if it's compatible with it. As for Visual Studio 2003, in order for it to be compatible, it just needs to have a new project accessing the same headers and cpps. I plan to do an update and add the Visual Studio 2003 version.

____________________________________________________________~Life without coffee would be a sad [and tired] life indeed.