Introduction

Have you seen these nice little windows that come up in Windows XP when you
go to special folders like the Control Panel, My Pictures etc. ? They show up a list of possible and popular tasks for the folder and/or selected
items. With this "Top ten" list of things, Windows thinks you would like to do, it's much faster for a beginner than
searching for the right command in the toolbar or menu. I thought that this user help would also fit in my own applications, so I wrote this
class to simulate this new control.

Background

It's not to hard to write your own control with this behavior. But as I tried to do this I found out that Windows
uses a lot of different colors (here: different kinds of blue) - and I'm quite unsure how to get these colors without
depending on the theme-thing. So I tried to get almost the same colors, no matter if the way was right. Be sure that there
will be theme support in the near future.

As this does not seem to be an official control there's no wording for this. So I used the Spy++ to see the class names decided to name it
DirectUI and call the boxes as "groups" and the clickable items as simply "item".

Using the code

This class can now use Themes as a new style. If you'd like to activate them just include a
#define USE_THEMES in your StdAfx.h. Otherwise the self-made XP-style
will be used.

Add the two files to your project and make sure to have a CMemDC class in your project, or use
the one provided in the sample. Insert the window CWndDirectUI anywhere you want, just like a normal control. Before compiling
make sure that you have a hand cursor named IDC_MYHAND in your resource.

By default the control is drawn using the style "Themed" (see screenshot above). You can change the style manually any time by simply calling
SetStyle() using CWndDirectUI::styleOffice, CWndDirectUI::styleXPclassic, CWndDirectUI::styleXP
or CWndDirectUI::styleThemed.
For retrieving the current style use GetStyle(). Please be carefull when switching to the office style after the user was able to use
the control, as in this style there's no expand/collapse button, so previously collapsed groups can't be expanded by the user withg this style.

For manual expand/collapse use the functions ExpandGroup(groupNr, expand).

To fill the control the best way is to use the function InitFromMenu(UINT id). Pass a menu id containing a
2D menu (no further submenus). It will automatically create the groups from the first level and add the submenu items
below. If you'd like you can insert toolbar icons using SetToolbarImages(UINT uiToolbar) by simply
passing a toolbar id. Please insert all items into 1 toolbar, as you can use this
function only with 1 toolbar at the moment. By the way: scrollbars will automatically show if there are too many items for displaying in the control.

To use images with more than 16 colors use the SetToolbarImages(uiToolbar, uiAlternateImages, nFlagColor, clBackground, nWidth)
function with the following parameters:

uiAlternateImages: resource id of the hi-color bitmap

nFlagColor: See CImageList::Create() for more info. Default is
ILC_COLOR8 for 256 color images

clBackground: Background color used for maps (default is purple)

nWidth: Button width (default is 16)

For manually adding groups and items please see the class definition and the functions AddGroup(),
AddItemCommand() etc.
So for every action the user does simply set a new list - that's all!
When the user selects an item in the list the commands come to your application like normal menu commands, so
process them like you process all the other commands.
Please check this site if you'd like to use it in e.g. a dockable window. There are lots of classes for this
so I see no reason to re-invent the wheel again.

Using static text and edit controls

By now two new items are include with CWndUI: static text and an edit control.
If you'd like to use these items you have to insert them manually to the list by using
AddItemCommand(). So to add a static text and an edit control take a look at the
following piece of code from the sample:

These new items have caused a few changes to the existing code, so if you used this class
before and created own controls based on this class please check the code. The
CDirectUIItemEdit uses the popular CInPlaceEdit class created
by Zafir Anjum (and modified a little for my class) - thank you for your code! In case you are
interested in how to use inplace controls take a look at this class, perhaps you find some
idea how to do it. As I have no screenshot on how CDirectUIItemStatic and
CDirectUIItemEdit are "officially" painted I just used it the way I think it could
be. If you have any detailed information please send me an image or modified code.

In case you'd like to extend the control the next step would be a combined class that holds
an edit control and a button beside (like "Find" or "Go"), but that's your homework

For the future... what's missing?

There are a few things not implemented in this first version, e.g.:

Keyboard support - only the mouse can access this control

Focus rect when button is down, and all the behavior that comes with handling the focus

And ... this is my first code using themes. Please tell me if I have made some mistakes!

Compatibility and Testing

The code was tested using Windows XP Home and Visual C++ 6.0 . It should run on all versions starting with Windows 98
and Visual C++ 5. I haven't tested the code too well, so please tell me if
there's a bug. I'm sorry, but in the demo (only there) the resources are mixed up in English
and German.

Copyright and Credits

Feel free to use this code in any application (freeware, shareware, commercial, ...) as long you
keep the copyright in the code and documentation, as well as credits.

Thanks a lot to Keith Rule for his CMemDC class!

Thanks to David Yuheng Zhao for his CVisualStylesXP class.

Thanks to all of you who found a bug (see discussions below), you are mentioned inside the code!

Thanks to Zafir Anjum for his CInPlaceEdit class I used!

Thanks to Mathieu Dubaele for his help with the edit item.

History

July 27, 2004: Two new items added, lot of code changed

May 8, 2004: Now supports Themes as a new style

May 2, 2004: Support for hi-color icons, thanks to Dany Cantin for his code for hi-color
toolbars

December 1, 2003: Bugfix (GDI resources), thanks to Michel Wassink and the others
who helped me finding the bug.

March 1, 2003:

BugFix: When a group is collapsed you can still select an item (OnHittest)

BugFix: When scrolled the OnHittest returns wrong results

BugFix: Warning for IDC_HAND is fixed

Example: How to use in a dialog (select the menu item DIRECTUI_WINDOW, Show dialog for an example)

Share

About the Author

I started programming on the C64 by the "trial and error" method. Years later my parents got their first PC (Atari PC4, AT 8 MHz) where I started with Turbo Pascal. The next steps led to Turbo Pascal for Windows, Visual C++ 1.52c, and finally Visual C++ 6.

A lot of code, tipps and help came from this site for my later projects. Thanks again to all who helped me, even if they don't know it. I'm trying to share code (which is worth sharing) so others can get the help I got (and still need) for everyday problems.

This is a great control, but it doesn't seem to work in a dialog. If
you change the sample to fill the control used with the dialog the same
as the one used with the view, you will see that the mouse messages never make it to the dialog version: the cursor never changes and items don't highlight as the mouse moves.

Thanks for this Control who is very great !
But i have a little problem when i use this control with a Dialog Box. I use the funciton that you use in the DemoDlg. When i use this, i can expand the tree with the mouse. If use a edit instead of the static control i can expand the group but i can too write text on the control.
If somebody have can fix this litle bug...
Thx for this very gret control
Regards
Nicolas

Explicitly setting the style to top alignment. I tried various alternatives and observed no difference apart from the fact that one of top, bottom, left or right is needed to avoid the assertion failure (which is evident from the ASSERT statement in bartool.cpp).

The assertion that fails is an added assertion in the newer MFC distribution that isn't in the older one. There were two; now there are three of them.

I have found that when hovering over an item, the item is underlined. However, my appication has a split view in it, one of the panes being this control, and the other pane to show something depending on what is chosen from the control. If the mouse is moved very quickly from the control pane to the other pane, highlighting an item first, the underline stays when the mouse is actually over the other pane.

The first thing i would like to mention here is it's really a very good control. Thanx for the control. Now about my problem. I am using Web Browser control in my application which acts as Windows Explorer. Web Browser control has inbuild side panel to show the functionalities avaliable in Menu.

Now, the problem lies here in this inbuild functionality. I want to modify the options of the side panel. Here i don't want to display "Publish this file to the web" and "Email this file" when user selects a file from Web Browser control.

Your control is really great, but unfortunately it doesn't work on Win98.

I start the demo application and maximize the client window. Then I wildly click into your menu. Open categories, click on some items, close categories, click on items in another category, open a group, close another group, etc.
Just wildly click on everything of the menu in no particular order.

Then after about 2 minutes or so, all GDI resources crash. The font changes, the background color of the menu changes, the icons are not drawn correctly, some items get underlined in white without mouse on it.

Unfortunately I cannot send you a screenshot because the system reports that there aren't enough memory resources for this operation.

I have found a bug.. I have got the control with a lot of groups and items. I have added these items manually using the AddItem function. Everything seemed to work fine, apart from the following.

Say you have Group 1 with 6 items, and Group 2 with 6 also. Expand both groups. Click on an item, and it works fine. Collapse Group one, and click on the group 2 items. Sometimes group one items are executed if the mouse is clicked between the group 2 items. I am going to work on this one.

But finally I found the bug: When a previous group was collapsed the control continues to do a HitTest on the (not displayed) items and caused wrong results. I fixed this with this single line of code:

I'm not quite sure what you mean. I guess you want to replace the items in each group by a list control. If so, it'll be a lot of work...

A list control could help you doing a few things as multi-colum etc. As the "original" control does only the things I already do I see no reason to use this control. I would suggest to simply change (or inherit) my classes and add the functionality you miss. This should not be too hard.

So when you really want to use the list control you'll have to create some of them (1 for each group) whenever the groups change. Then you need to reposition them any time you scroll the control or resize it. You need to calculate the correct size that is needed so you can paint the group correctly. Don't forget to hide/show them on minimize/maximize the group... Does not seem to be an easy job, hmm? Perhaps you can take a look to the grouping function of the XP list control as seen in the explorers drive list. Perhaps you can overwrite the behaviour to simulate this window.

As you see I'm really sure that your idea would not be an easy thing, sorry...