Game Accessibility Library logo SourceForge.net Logo
Game Accessibility Suite: CATGUI/CATMenu_Win32.cpp Source File

CATMenu_Win32.cpp

Go to the documentation of this file.
00001 //---------------------------------------------------------------------------
00002 /// \file GGMenu_Win32.cpp
00003 /// \brief Win32-specific calls for Menu/GUI
00004 /// \ingroup CATGUI
00005 ///
00006 /// Copyright (c) 2003-2008 by Michael Ellison.
00007 /// See COPYING.txt for the \ref gaslicense License (MIT License).
00008 ///
00009 // $Author: mikeellison $
00010 // $Date: 2008-01-25 05:11:25 -0600 (Fri, 25 Jan 2008) $
00011 // $Revision:   $
00012 // $NoKeywords: $
00013 //
00014 //---------------------------------------------------------------------------
00015 #include "CATMenu.h"
00016 #include "CATWindow.h"
00017 #include <map>
00018 const CATUInt32 kCATMAXMENUHEIGHT = 400;
00019 
00020 
00021 void CATMenu::ClearMenu()
00022 {
00023     fIdMap.clear();
00024 
00025     if (fMenuId == 0)
00026         return;
00027 
00028     // Destroy submenus in reverse order - otherwise boundschecker horks...
00029     // Most likely, windows automagically deallocates submenus, but not 100% sure, and 
00030     // BoundsChecker doesn't seem to think so, so....
00031     HMENU menuId = 0;
00032     while (CATSUCCEEDED(fMenuStack.Pop(menuId)))
00033     {
00034         DestroyMenu(menuId);
00035     }
00036 
00037     // Clean up top-level menu handle
00038     DestroyMenu((HMENU)fMenuId);
00039     fMenuId = 0;
00040 }
00041 
00042 
00043 void CATMenu::DoMenu()
00044 {
00045     BuildMenu();
00046 
00047     if (fMenuId == 0)
00048         return;
00049 
00050     this->GetWindow()->OSHideToolTip();
00051 
00052     // Let the user select something from the popup menu.
00053     // On return, it will return the curItem->id we set when appending the menu.
00054     // Since id == 0 is illegal, we can safely ignore 0 returns.
00055     CATRect absRect = this->GetRectAbs(true);
00056 
00057     //CATRect wndRect = this->GetWindow()->OSGetWndRect();
00058 
00059     CATInt32 vAlign  = 0;
00060     CATInt32 left    = absRect.left; //fRect.left + wndRect.left;
00061     CATInt32 top     = absRect.top;  //fRect.top + wndRect.top;
00062 
00063     POINT cursorPos;
00064     ::GetCursorPos(&cursorPos);
00065 
00066     switch (fMenuStyle)
00067     {     
00068     case CATMENUSTYLE_UPMOUSE:
00069         vAlign  = TPM_BOTTOMALIGN;
00070         left    = cursorPos.x;
00071         top     = cursorPos.y;
00072         break;
00073 
00074     case CATMENUSTYLE_DOWNMOUSE:
00075         vAlign  = TPM_TOPALIGN;
00076         left    = cursorPos.x;
00077         top     = cursorPos.y;
00078         break;
00079 
00080     case CATMENUSTYLE_UP:
00081         vAlign  = TPM_BOTTOMALIGN;
00082         break;
00083 
00084     case CATMENUSTYLE_DOWN:
00085     default:
00086         vAlign  = TPM_TOPALIGN;
00087         top     = absRect.bottom; // fRect.bottom + wndRect.top;
00088         break;
00089     }
00090 
00091     CATInt32 itemId = TrackPopupMenuEx( (HMENU)fMenuId,
00092                                         TPM_LEFTALIGN | vAlign| TPM_RETURNCMD | TPM_LEFTBUTTON,
00093                                         left,
00094                                         top,
00095                                         this->GetWindow()->OSGetWnd(),   
00096                                         0);
00097 
00098 
00099     if (itemId == 0)
00100         return;
00101 
00102     CATMENUITEM* selected = 0;
00103     std::map<CATUInt32,CATMENUITEM*>::iterator iter = fIdMap.find(itemId);
00104     if (iter != fIdMap.end())   
00105     {
00106         selected = iter->second;
00107         // IF use alternate command is selected, issue it and return w/o changing the selection
00108         if (selected->AltCommand.IsEmpty() == false)
00109         {
00110 
00111             ((CATGuiObj*)fParent)->OnCommand( CATCommand(selected->AltCommand,1.0f),0);
00112             return;
00113         }
00114 
00115         this->SetCurItem(selected);
00116     }
00117     else
00118     {
00119         CATASSERT(false,"Invalid item id in menu!");
00120     }
00121 
00122     ((CATGuiObj*)fParent)->OnCommand(this->GetCommand(),this);      
00123 }
00124 
00125 
00126 void CATMenu::CreateSubMenu( std::vector<CATMENUITEM*>& itemList, HMENU parentMenu)
00127 {
00128     CATUInt32 numItems = itemList.size();
00129     CATUInt32 i;
00130 
00131     for (i = 0; i < numItems; i++)
00132     {
00133         CATMENUITEM* curItem = itemList[i];
00134 
00135         // Create submenus/menu items
00136         if (curItem->IsSubMenu)
00137         {
00138             HMENU subMenu = ::CreatePopupMenu();
00139             fMenuStack.Push(subMenu);
00140             CreateSubMenu(curItem->Children, subMenu);              
00141             // Create a submenu and recurse
00142 
00143             MENUITEMINFO mi;
00144             mi.cbSize      = sizeof(mi);
00145             mi.fMask       = MIIM_ID | MIIM_DATA /*| MIIM_STRING*/ | MIIM_SUBMENU | MIIM_TYPE;            
00146             mi.fType       = MFT_OWNERDRAW; //MFT_STRING;
00147             mi.dwItemData  = (ULONG_PTR)curItem;                            
00148             mi.cch         = curItem->DisplayText.Length();
00149             mi.dwTypeData  = curItem->DisplayText.GetUnicodeBuffer();
00150             mi.hSubMenu    = subMenu;
00151             mi.wID         = this->fIdCount;
00152 
00153             // Store mapping of id -> menu item
00154             this->fIdMap.insert(std::make_pair(fIdCount,curItem));
00155             fIdCount++;
00156 
00157             ::InsertMenuItem(parentMenu,i,TRUE,&mi);
00158             curItem->DisplayText.ReleaseBuffer();            
00159         }
00160         else
00161         {
00162             // Standard menu item - insert it and continue
00163             MENUITEMINFO mi;
00164             mi.cbSize      = sizeof(mi);
00165 
00166             // Normal items...
00167             if (curItem->DisplayText.IsEmpty() == false)
00168             {
00169                 mi.fMask       = MIIM_ID | MIIM_DATA /*| MIIM_STRING*/ | MIIM_STATE | MIIM_TYPE;
00170                 mi.fState      = (curItem == this->fCurSel)?MFS_CHECKED:MFS_ENABLED;
00171                 mi.fType       = MFT_OWNERDRAW; //MFT_STRING;
00172                 mi.dwItemData  = (ULONG_PTR)curItem;
00173                 mi.cch         = curItem->DisplayText.Length();
00174                 mi.dwTypeData  = curItem->DisplayText.GetUnicodeBuffer();
00175                 mi.wID         = this->fIdCount;
00176             }
00177             // Seperators
00178             else
00179             {
00180                 mi.fMask       = MIIM_FTYPE | MIIM_DATA;
00181                 mi.fType       = MFT_SEPARATOR | MFT_OWNERDRAW;
00182                 mi.dwItemData  = (ULONG_PTR)curItem;
00183 
00184             }
00185 
00186             // Store mapping of id -> menu item
00187             this->fIdMap.insert(std::make_pair(fIdCount,curItem));
00188             fIdCount++;
00189 
00190             ::InsertMenuItem(parentMenu,i,TRUE,&mi);
00191             curItem->DisplayText.ReleaseBuffer();                           
00192         }
00193     }
00194 }
00195 
00196 void CATMenu::BuildMenu()
00197 {      
00198     ClearMenu();   
00199     fMenuId = (CATUInt32)::CreatePopupMenu();   
00200     CreateSubMenu(this->fRootList, (HMENU)fMenuId); 
00201     fMenuDirty = false;
00202 }
00203 
00204 void CATMenu::OSOnMeasureItem(CATMENUITEM* menuItem, CATUInt32& width, CATUInt32& height)
00205 {
00206     // Setup fonts
00207     CATFONT measureFont = this->GetWindow()->OSGetFont(fFontName,fFontSize);
00208     HWND hwnd = this->GetWindow()->OSGetWnd();
00209     HDC curDC = ::GetDC(hwnd);
00210     CATFONT oldFont = (HFONT)::SelectObject(curDC,measureFont);
00211 
00212     // Calc size of text
00213     SIZE textSize;
00214     textSize.cx = 0;
00215     textSize.cy = 0;
00216     CATString filtered = FilterGUIString(menuItem->DisplayText);
00217 
00218     if (filtered.IsEmpty() == false)
00219     {
00220         ::GetTextExtentExPoint( curDC, 
00221             filtered, 
00222             filtered.Length(),
00223             this->GetWindow()->GetRect().Width(),
00224             NULL,
00225             NULL,
00226             &textSize);
00227 
00228     }
00229 
00230     height = CATMax((CATUInt32)(textSize.cy + 2), (CATUInt32)10 );
00231     width  = textSize.cx + 25;
00232 
00233     // Restore fonts/cleanup
00234     ::SelectObject(curDC,oldFont);
00235     ::ReleaseDC(hwnd,curDC);
00236     this->GetWindow()->OSReleaseFont(measureFont);
00237 
00238     if (menuItem->BaseMenu->ForceWidth())
00239     {
00240         CATRect controlRect = menuItem->BaseMenu->GetRect();
00241         // Force the width of the menu to be the same as the control.
00242         // Windows seems to add about 1.5 chars for '<' caret and space.
00243         width  = controlRect.Width() - (textSize.cx/filtered.Length())*1.5;
00244     }
00245 }
00246 
00247 void CATMenu::OSOnDrawItem( CATMENUITEM* menuItem, bool selected, CATDRAWCONTEXT hDC, CATRect rect )
00248 {                        
00249     CATColor  colorFore = GetColorFore();
00250     CATColor  colorBack = GetColorBack();
00251 
00252     RECT drawRect;
00253     ::SetRect(&drawRect, rect.left, rect.top,rect.right,rect.bottom);
00254 
00255     if (selected & ODS_SELECTED)
00256     {
00257         CATSwap(colorFore,colorBack);
00258     }
00259 
00260     HBRUSH bgBrush = ::CreateSolidBrush(RGB(colorBack.r, colorBack.g, colorBack.b));
00261     ::FillRect(hDC, &drawRect, bgBrush);
00262 
00263     // Draw selection dot.
00264     if ((menuItem == fCurSel) && (fShowSel))
00265     {                           
00266         CATInt32 startX = drawRect.left + 2;
00267         CATInt32 startY = ((drawRect.top + drawRect.bottom)/2);
00268 
00269         HPEN fgPen = ::CreatePen( PS_SOLID,2,RGB(colorFore.r, colorFore.g, colorFore.b));
00270         HPEN oldPen = (HPEN)::SelectObject(hDC, fgPen);
00271 
00272         ::MoveToEx( hDC, 
00273             startX,
00274             startY - 3,
00275             0);
00276 
00277         ::LineTo(   hDC,
00278             startX + 5,
00279             startY );
00280 
00281         ::MoveToEx( hDC, 
00282             startX,
00283             startY + 3,
00284             0);
00285 
00286         ::LineTo(   hDC,
00287             startX + 5,
00288             startY );
00289 
00290         ::SelectObject(hDC, oldPen);
00291         ::DeleteObject(fgPen);
00292     }
00293 
00294 
00295 
00296     if (menuItem->IsSubMenu)
00297     {
00298         CATInt32 startX = drawRect.right - 8;
00299         CATInt32 startY = ((drawRect.top + drawRect.bottom)/2);
00300 
00301         HPEN fgPen = ::CreatePen( PS_SOLID,2,RGB(colorFore.r, colorFore.g, colorFore.b));
00302         HPEN oldPen = (HPEN)::SelectObject(hDC, fgPen);
00303 
00304         ::MoveToEx( hDC, 
00305             startX,
00306             startY - 3,
00307             0);
00308 
00309         ::LineTo(   hDC,
00310             startX + 5,
00311             startY );
00312 
00313         ::MoveToEx( hDC, 
00314             startX,
00315             startY + 3,
00316             0);
00317 
00318         ::LineTo(   hDC,
00319             startX + 5,
00320             startY );
00321 
00322 
00323         ::SelectObject(hDC, oldPen);
00324         ::DeleteObject(fgPen);
00325     }
00326 
00327     int oldMode = ::SetBkMode(hDC,TRANSPARENT);
00328     COLORREF oldColor = ::SetTextColor(hDC,RGB(colorFore.r,colorFore.g,colorFore.b));
00329 
00330     if (menuItem->DisplayText.IsEmpty())
00331     {
00332         // Just do a line - no text there.
00333         CATInt32 yPos    = (drawRect.top + drawRect.bottom)/2;
00334         HPEN linePen   = ::CreatePen(PS_SOLID,1,RGB(colorFore.r, colorFore.g, colorFore.b));
00335         HPEN oldPen    = (HPEN)::SelectObject(hDC, linePen);
00336 
00337         ::MoveToEx  (hDC, drawRect.left  + 2, yPos, NULL);
00338         ::LineTo    (hDC, drawRect.right - 2, yPos);
00339 
00340         ::SelectObject(hDC,oldPen);
00341         ::DeleteObject(oldPen);
00342 
00343     }
00344     else
00345     {
00346         // Setup fonts      
00347         CATFONT drawFont = this->GetWindow()->OSGetFont(fFontName,fFontSize);
00348         CATFONT oldFont = (HFONT)::SelectObject(hDC,drawFont);
00349 
00350         // Draw
00351         DWORD textStyle = DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE;
00352 
00353         RECT rcText;
00354         ::SetRect(&rcText, drawRect.left, drawRect.top, drawRect.right, drawRect.bottom);
00355         rcText.left += 10;
00356 
00357 
00358         CATString filtered = FilterGUIString(menuItem->DisplayText);
00359         ::DrawTextEx( hDC, 
00360             filtered.GetUnicodeBuffer(), 
00361             filtered.LengthCalc(),
00362             &rcText,textStyle,NULL);
00363         filtered.ReleaseBuffer();
00364         ::SelectObject(hDC,oldFont);
00365         this->GetWindow()->OSReleaseFont(drawFont);
00366     }
00367 
00368 
00369 
00370 
00371     // Restore fonts/cleanup
00372     ::SetTextColor(hDC,oldColor);
00373     ::SetBkMode(hDC, oldMode);
00374 
00375     ::DeleteObject(bgBrush);
00376     ::ExcludeClipRect(hDC,drawRect.left,drawRect.top,drawRect.right, drawRect.bottom);
00377 }

Generated on Mon Feb 11 04:09:55 2008 for Game Accessibility Suite by doxygen 1.5.4