
|

|
Radial context menu ... |
... with tips |
Mouse gesture with a graphical user interface.
Introduction
Some time ago, as I was looking for some kind of mouse gesture add-on for my web browser, I came across this web site. There, one can get an add-on for the browsers Firefox and Mozilla, which implements mouse gestures with a graphical front end. I was slightly confused by this fact - 'Mouse gesture with GUI?', I thought. What could this look like? I took a look at the screenshots and was immediately enthused. The add-on merged the advantages of context menus with that of mouse gestures in a clever way: fast execution of commands as with mouse gestures were combined with an easy to understand context menu. In this way one learns the often used gestures very fast while one still has access to the gestures one doesn't recall at any time. Especially less experienced users will profit from this concept. For instance, my wife and my kids won't browse the web without this extension anymore
. So if you're using Firefox or Mozilla, go and get your copy of this real great extension!
I planned to implement this ingenious concept for the use with some of my projects for a long time, but had too less free time. Until now...
How it works
As soon as the user presses the right mouse button, a round menu pops up, displaying up to eight icons. The user now may move the mouse in one of eight directions. As soon as (s)he releases the right mouse button, the function below the mouse cursor will be executed. Since mouse gestures don't work precisely on pixels, the radial menu will follow the mouse cursor on demand. The cursor also doesn't need to be exactly over the icon to select a function. To find out which function to use, the menu checks all points on a thought line from the current cursor position to the center of the radial menu. If the line intersects an icon's area, then it is assumed that the user meant this icon. In this way fast acting professionals will get the right result, too. For users who are new to your program and/or can't recall every mouse gesture (or even don't know what the icon stands for), the menu pops up some kind of tool tips after a short delay time. That way even inexperienced users or users who don't like mouse gestures will quickly get along with this concept.
To build up more complex menus (with more than 8 items), one can build up submenus. That way one can implement gestures such as 'right, then up', too.
Using the code
The radial context menu is implemented to watch for the right mouse button. To activate such a menu, you will need to install a handler for the WM_RBUTTONDOWN
window message. The radial context menu object can either be instantiated in this handler method, in the constructor of your CWnd
-derived class, or in the OnCreate()
handler method.
The size of the icons, the colors and fonts to use should be set up before one sets up the menu items themselves. By default the radial menu will use the system colors and fonts as well as an icon size of 16x16 pixels.
CRadialContextMenu & SetBkColor(COLORREF clr = ::GetSysColor(COLOR_BTNFACE));
CRadialContextMenu & SetIconSize(CSize size = CSize(16, 16));
CRadialContextMenu & SetIconSize(int cx, int cy);
CRadialContextMenu & SetTipFont(CFont * pFont);
CRadialContextMenu & SetTipColors(COLORREF color1, COLORREF color2,
COLORREF textcolor = ::GetSysColor(COLOR_BTNTEXT));
Having set up the outwardness, one might go on to set up the menu items.
CRadialContextMenu & AddToolBar(CToolBar * pBar);
CRadialContextMenu & SetMenuItem(UINT uID, EIconPosition pos,
const CString & tip = "");
CRadialContextMenu & SetMenuItem(UINT uID, HICON hIcon,
EIconPosition pos, const CString & tip = "");
CRadialContextMenu & SetMenuItem(CRadialContextMenu * pSubmenu,
HICON hIcon, EIconPosition pos,
const CString & tip = "");
CRadialContextMenu & EnableMenuItem(UINT uID, bool bEnable = true);
CRadialContextMenu & EnableMenuItem(EIconPosition pos, bool bEnable = true);
Now one might call this method.
bool TrackRadialMenu(CWnd * pReceiver);
to pop up the radial context menu. The method won't return unless the user releases the right mouse button or presses the ESC key. The return value indicates whether the user selected a valid item. If it returns true
, then a WM_COMMAND
message was sent to the window given as the argument.
Thus an exemplary implementation of a WM_RBUTTONDOWN
handler might look like this:
void CMyOwnWindow::OnRButtonDown(UINT nFlags, CPoint point)
{
CRadialContextMenu()
.AddToolBar(&m_wndToolbar)
.SetMenuItem(ID_FILE_NEW, CRadialContextMenu::ICON_TOP)
.SetMenuItem(ID_FILE_OPEN, CRadialContextMenu::ICON_RIGHT)
.SetMenuItem(ID_FILE_SAVE, CRadialContextMenu::ICON_BOTTOM)
.SetMenuItem(ID_FILE_PRINT, CRadialContextMenu::ICON_LEFT)
.EnableMenuItem(ID_FILE_SAVE, GetDocument()->IsModified())
.TrackRadialMenu(this);
}
History
- July, 20 2005 - first implementation.