|
Hello,
Yet another option I would love to see (implementation below) are correctly drawn disabled checkmark menu items. You can see a checked and disabled one, XP-style here.
For this, the method DrawXPCheckmark becomes (warning: this is based on version 3.01):
BOOL BCMenu::DrawXPCheckmark(CDC *dc, const CRect& rc, BOOL bSelected, BOOL bDisabled, HBITMAP hbmCheck, COLORREF selcolor) const
{
if(bDisabled)
{
COLORREF clr =GetSysColor(COLOR_3DSHADOW);
dc->Draw3dRect(rc,clr,clr);
}
else
{
COLORREF clrCheckBack =bSelected ? LightenColor(selcolor,0.6) : LightenColor(GetSysColor(COLOR_BTNFACE),0.25);
CBrush brushin;
brushin.CreateSolidBrush(clrCheckBack);
dc->FillRect(rc,&brushin);
brushin.DeleteObject();
dc->Draw3dRect(rc,selcolor,selcolor);
}
int x = rc.left + (rc.Width() - 8)/2;
int y = rc.top + (rc.Height() - 7)/2 + 1;
COLORREF clrCheckMark =GetSysColor(bDisabled ? COLOR_3DSHADOW : COLOR_MENUTEXT);
if(!hbmCheck)
{
if(bDisabled)
DrawCheckMark(dc,x+1,y+1,GetSysColor(COLOR_3DHILIGHT));
DrawCheckMark(dc,x,y,clrCheckMark);
}
else
{
if(bDisabled)
DrawRadioDot(dc,x+1,y+1,GetSysColor(COLOR_3DHILIGHT));
DrawRadioDot(dc,x,y,clrCheckMark);
}
return TRUE;
}
|
|
|
|
|
Levente,
Thanks for the suggestion, I'll add it to the next release.
Brent
|
|
|
|
|
Brent,
I am throwing together a menu bar (that is, a toolbar that has text buttons which run a popupmenu underneath when pressed), based on a '99 DiLascia article in MSJ. I intend to use a slightly modified version of your menu for the submenus. Are you interested in this stuff? I could surely use some help/suggestions when drawing the buttons in XP style. Maybe I will also post an article (not sure about this, since I'm running out of time with a couple of other projects).
Levente
|
|
|
|
|
Before I tried to use BCMenu on dialog, and I simply couldn't get it to work. Has anybody tried and succeeded?
|
|
|
|
|
Download the Dialog based example at the top of the article. Also refer to item number 6 in the 3.01 update notes.
Brent
|
|
|
|
|
I really wish that BCMenu can have accelarators that supports left justification in future versions, cos' the Windows OS itself uses left justifications for accelarators text, and right justifications in accelarator text in menus makes the thing go ugly.
Hope that Brent Corkum can do something about this! Thanks Brent!!!!!!!
|
|
|
|
|
BCMenu has always right justified the accelarator text as does MS Office XP and MS Visual Studio 6. Now some applications left justify the accelerators such as Wordpad, Notepad, and IE. The default CMenu also left justifies accelarators. So there's no standard way of doing this. As far as being ugly, well to each their own. So in the next release I'll look at adding an option to change the way the accelarators are justified. However the default will be right justified because this is the way I like it.
Thanks for you comment.
Brent
|
|
|
|
|
Hello,
There is yet another (minor) thing missing from this superb OD menu class. Namely, when you change the selected menu item using the keyboard and the menu includes some disabled items, Microsoft's menu will draw a "focus" rectangle around disabled items also, to let you see where your current pseudo-selection is.
This makes sense and BCMenu is a little bit handicapped without it. Can we please have this feature also? Thanks :->
Best regards,
Levente
|
|
|
|
|
You learn something new everyday. I had never noticed this since I never use the keyboard with a menu. I'll have to think about how to do this???
Brent
|
|
|
|
|
first: this class is really wonderful, the only little problem until now was its hunger for resources. But I have a little prolem. I have bitmaps with another transparent color then RGB(192,192,192). In the previous version of bc-menu I changed the statement
m_bitmapBackground=RGB(192,192,192);
to my color. But in the newest version that doesnt' work. There is also a line in
void BCMenu::GetTransparentBitmap(CBitmap &bmp)
..
.
col=..
but these 2 changings don't seem to be enough.
Thank You
Dieter
|
|
|
|
|
Dieter,
I just gave it a try and it seems to work. Did you forget to change the
m_bitmapBackgroundFlag
member variable to TRUE as well? I personally use the
void SetBitmapBackground(COLORREF color);
void UnSetBitmapBackground(void);
member functions to define a different background color for a bitmap. Somthing like:
m_menu.SetBitmapBackground(RGB(255,0,255));
m_menu.ModifyODMenu(NULL,ID_WINDOW_CASCADE,IDB_BITMAP9);
m_menu.UnSetBitmapBackground();
If the IDB_BITMAP9 bitmap had a magenta background instead of the standard RGB(192,192,192) background.
Brent
|
|
|
|
|
oh sorry, I stupidly really forgot to do this. Th new look in XP style is super.
I couldn't use the version with shadow until now, because resource. But now all is perfect!
CU
Dieter
|
|
|
|
|
Hello,
First, this is excellent code. But I have some problems with it.
1) The menus are always (both with and without accelerators) too wide. Almost twice as wide as they should, and the right side is left blank. If an item has a "tab+accelerator_text" at the end, that is properly aligned to the right, but the wasted space in the middle is too much.
2) The space (height) taken up by the separators is too much.
3) Checkmarks are not properly aligned and are somewhat too small.
4) Height of submenu items is too small. I read your reply that there should be handlers for the menu-related messages in the class that has an OD menu, but I put those in the frame class (SDI), why isn't that enough?
I am running on Windows XP with the classic Windows theme. My menu font is Verdana 9pt.
Best regards,
Levente
|
|
|
|
|
Hello again,
I found the cause for issue 1: in method MeasureItem there is code like this:
if(Win32s != GetShellType())
VERIFYX(::GetTextExtentPoint32W(...));
#ifndef UNICODE
else // Can't be UNICODE for Win32s
{
...
}
#endif
Well, it turns our that because I use some special VERIFY/ASSERT macros that expand to more than one line, the code above was alwas going through the else written for Win32s(ux). The solution is to simply wrap the VERIFY into {}.
I also solved the height of the separator, it now looks more like the MS menu. Again in method MeasureItem, at the beginning where the size of a separator is calculated, I canged it to this:
// Compute size of separators
lpMIS->itemWidth = 0;
if(IsLunaMenuStyle())
{
lpMIS->itemHeight = GetSystemMetrics(SM_CYBORDER) + 2;
}
else
{
int temp = GetSystemMetrics(SM_CYMENU) >> 1;
lpMIS->itemHeight = (temp > (m_iconY+CM_PAD)/2) ? temp : (m_iconY+CM_PAD)/2;
}
Best regards,
Levente
|
|
|
|
|
The latest 3.03 release dels with some of your issues. The checkmarks and the separator height have been adjusted to look more MS like. There's also a setting that will narrow the menu's (see the update information). I also read you comments on using custom MACRO's which clears up my confusion since no one else has complained about the width.
With regards to item#4, if a class defines a BCMenu object and uses it, it should also define the message handlers.
Brent
|
|
|
|
|
Hi,
I have figured out how to give the BCMenu a flat look just like in the Office XP product.
I will distribute the source code as it is wanted, as it is fairly complex.
Mike Jackson
|
|
|
|
|
Why don't you just create a new article and upload it? Let's not keep us curious here?
--
Alex Marbus
www.marbus.net
But then again, I could be wrong.
|
|
|
|
|
For everyones information, ive emailed my code to Brent for consideration in future releases of this class.
Im somewhat reluctant to distribute a modified version of his code, which is why I havent posted the code in the group.
Using a hook is the right idea, however i did have to modify Brent's code to get the alignment & various other things right.
|
|
|
|
|
Hi,
See the source in WTL distribution or in Bjarne Viksoe WTL XP Menu class
I don't recall the details, but more or less is as follows : (The main idea is to install a windows CBT hook to monitor creation of windows and obtain a handle to the menu window)
Steps:
Create a CMenuWindow : public CWindowImpl<CMenuWindow>
Implement OnNcPaint
Before Creation of the "menu"
Call SetHookEx CBT hook, monitor creation / destruction of windows. There exists a
"magic number" #XXXXX for the menu window class.
If code = Creation
Subclass the window handle obtained
(In WTL CMenuWindow* pwnd = new CMenuWindow ;
pwnd->SubclassWindow (hwnd);
....)
-- the object deletes itself in OnFinalMessage)
If code = destruction
Clenup
Show the menu (track)
Remove windows hook.
It works fine. I've been hacking a little to make it work with WTL 7 and MDI
There exists an old PSDK sample "FakeMenu" that uses another approach: it emulates completely a menu by capturing the mouse, filtering messages and implementing a MessageLoop.
Regards,
R.
|
|
|
|
|
Great Job Man!
This is one of the most awsome tutorials iv seen..
Its Very cool. Has alota features. and is so dam simple.
Thx alot.
Keep up the good work
www.Static-Code.com
|
|
|
|
|
I have some menus that have been loaded from resource that then go through a routine to merge menu items from default menu. Since I have no resource with all the items, I'd like to take that HMENU and import it into a BCMenu. Does this seem doable? I took a stab at it but I'm still having problems getting it to work. Here's what I have.
BOOL BCMenu::ImportMenu(HMENU hMenu, BOOL bTopLevel)
{
if (!Attach(hMenu))
return false;
int count = GetMenuItemCount();
for(int i=0; i < count; ++i) {
CString str;
CMenu *pSub = GetSubMenu(i);
UINT nFlags = GetMenuState( i, MF_BYPOSITION );
int nID = GetMenuItemID(i);
GetMenuString(i,str,MF_BYPOSITION);
nFlags &= ~MF_STRING;
if (bTopLevel)
nFlags |= MF_POPUP;
else
nFlags |= MF_OWNERDRAW;
if(nFlags & MF_POPUP){
if (!pSub) {
pSub = new CMenu;
}
nID = (int)((HMENU)pSub->m_hMenu);
m_AllSubMenus.Add((HMENU)pSub->m_hMenu);
m_SubMenus.Add((HMENU)pSub->m_hMenu);
}
BCMenuData *mdata = new BCMenuData;
m_MenuList.Add(mdata);
mdata->SetString(str);
mdata->menuIconNormal = -1;
mdata->xoffset=-1;
mdata->nFlags = nFlags;
mdata->nID = nID;
if (bTopLevel) {
CMenu::ModifyMenu(i,nFlags | MF_BYPOSITION, nID, str);
} else {
CMenu::ModifyMenu(i,nFlags | MF_BYPOSITION, nID, (LPCTSTR)mdata);
}
if (pSub) {
if (pSub->m_hMenu) {
BCMenu *pMenuNew = new BCMenu();
pMenuNew->ImportMenu((HMENU)pSub->m_hMenu, FALSE);
}
}
}
Detach();
return(TRUE);
}
Thanks for your help!
Kim
|
|
|
|
|
The problem with this is that the HMENU is most likely associated with a CMenu object, not a BCMenu object. So the only real way to do this, is have your function create a BCMenu object, return its handle, then use this new handle by substituting it for the old handle. This is the only way you can get it to call BCMenu's DrawItem and MeasureItem functions when you make it ownerdrawn. It is possible to call BCMenu's functions for CMenu objects but this is more much more difficult and error prone. You basically got to intercept the DrawItem and MeasureItem messages and process them yourself.
Yuk.
Brent
|
|
|
|
|
I can't add bitmaped checkmark in popup menu. Ideas?
Also when use somthing like this:
BCMenu popup;
popup.LoadMenu(IDR_POPMENU);
BCMenu *pSub = ( BCMenu * ) popup.GetSubMenu(0);
CPoint pos;
GetCursorPos(&pos);
popup.CheckMenuItem( ID_P1, MF_BYCOMMAND | MF_CHECKED );
popup.ModifyODMenuW( NULL, ID_P1, &bmp ); //loaded in init();
pSub->TrackPopupMenu(0, pos.x, pos.y, this, NULL);
popup.DestroyMenu();
popup menu display a dark rect before ID_P1 menu item.
|
|
|
|
|
I'm using your menu in a dialog. When I use "Styles->Border->Thin" and "Extended Styles->Static edge" in the dialog properties and using a menuitem as a non-popup item (like a button in the menu), the icon is to big and is drawed into the dialog frame. How to fix this?
|
|
|
|
|
Thank youn for menu -- it is real cool.
I added to my app -- works perfect, but i have the same items in System menu and i whant them to look like you new style menus.
//........
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL) {
CString strAboutMenu;
CBitmap bmp;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty()){
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX_ALW, "&Always on Top\tCtrl+T");
}
//...........................................
|
|
|
|
|