зеркало из https://github.com/mozilla/gecko-dev.git
2624 строки
60 KiB
C++
2624 строки
60 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
// dropmenu.cpp
|
|
// Implements a popup menu in which you can drag and drop
|
|
|
|
#include "stdafx.h"
|
|
#include "dropmenu.h"
|
|
|
|
#define nIMG_SPACE 4
|
|
#define MAX_DROPMENU_ITEM_LENGTH 45
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Class CDropMenuButton
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CDropMenuButton::CDropMenuButton(void)
|
|
{
|
|
|
|
m_bButtonPressed = FALSE;
|
|
m_bMenuShowing = FALSE;
|
|
m_bFirstTime = FALSE;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Messages for CDropMenuButton
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
BEGIN_MESSAGE_MAP(CDropMenuButton, CStationaryToolbarButton)
|
|
//{{AFX_MSG_MAP(CWnd)
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_MESSAGE(DM_MENUCLOSED, OnMenuClosed)
|
|
|
|
//}}AFX_MSG_MAP
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
void CDropMenuButton::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
CStationaryToolbarButton::OnLButtonDown(nFlags, point);
|
|
|
|
m_bButtonPressed = TRUE;
|
|
}
|
|
|
|
void CDropMenuButton::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if(m_bMenuShowing)
|
|
{
|
|
if(m_bFirstTime)
|
|
{
|
|
ReleaseCapture();
|
|
m_eState = eBUTTON_DOWN;
|
|
RedrawWindow();
|
|
m_bFirstTime = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CStationaryToolbarButton::OnMouseMove(nFlags, point);
|
|
}
|
|
}
|
|
|
|
void CDropMenuButton::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
if(m_bButtonPressed && m_bEnabled && m_bHaveFocus)
|
|
{
|
|
OnAction();
|
|
m_bMenuShowing = TRUE;
|
|
m_bFirstTime = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CStationaryToolbarButton::OnLButtonUp(nFlags, point);
|
|
m_bMenuShowing = FALSE;
|
|
}
|
|
m_bButtonPressed = FALSE;
|
|
}
|
|
|
|
LRESULT CDropMenuButton::OnMenuClosed(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
|
|
m_bMenuShowing = FALSE;
|
|
m_eState = eNORMAL;
|
|
RedrawWindow();
|
|
|
|
return 1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Class CDropMenuItem
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
CDropMenuItem::CDropMenuItem(UINT nFlags, CString szText, UINT nCommandID,
|
|
HBITMAP hUnselectedBitmap, HBITMAP hSelectedBitmap,
|
|
BOOL bShowFeedback, void *pUserData)
|
|
{
|
|
m_nIconType = BUILTIN_BITMAP;
|
|
|
|
if(nFlags & MF_SEPARATOR)
|
|
{
|
|
m_bIsSeparator = TRUE;
|
|
}
|
|
else if(nFlags == MF_STRING)
|
|
{
|
|
m_bIsSeparator = FALSE;
|
|
char *pCutText = fe_MiddleCutString(szText.GetBuffer(szText.GetLength() + 1), MAX_DROPMENU_ITEM_LENGTH);
|
|
m_szText = pCutText;
|
|
szText.ReleaseBuffer();
|
|
free(pCutText);
|
|
m_hUnselectedBitmap = hUnselectedBitmap;
|
|
|
|
m_hSelectedBitmap = (hSelectedBitmap == NULL) ? hUnselectedBitmap : hSelectedBitmap;
|
|
|
|
m_nCommandID = nCommandID;
|
|
m_pSubMenu = NULL;
|
|
}
|
|
m_bIsEmpty = TRUE;
|
|
m_unselectedBitmapSize.cx = m_unselectedBitmapSize.cy = 0;
|
|
m_selectedBitmapSize.cx = m_selectedBitmapSize.cy = 0;
|
|
m_textSize.cx = m_textSize.cy = 0;
|
|
m_totalSize.cx = m_totalSize.cy = 0;
|
|
m_menuItemRect.SetRectEmpty();
|
|
m_bShowFeedback = bShowFeedback;
|
|
m_pUserData = pUserData;
|
|
|
|
}
|
|
|
|
CDropMenuItem::CDropMenuItem(UINT nFlags, CString szText, UINT nCommandID, CDropMenu *pSubMenu, BOOL bIsEmpty,
|
|
HBITMAP hUnselectedBitmap, HBITMAP hSelectedBitmap, BOOL bShowFeedback, void *pUserData)
|
|
{
|
|
if(nFlags & MF_POPUP)
|
|
{
|
|
m_bIsSeparator = FALSE;
|
|
char *pCutText = fe_MiddleCutString(szText.GetBuffer(szText.GetLength() + 1), MAX_DROPMENU_ITEM_LENGTH);
|
|
m_szText = pCutText;
|
|
szText.ReleaseBuffer();
|
|
|
|
free(pCutText);
|
|
|
|
m_hUnselectedBitmap = hUnselectedBitmap;
|
|
m_hSelectedBitmap = (hSelectedBitmap == NULL) ? hUnselectedBitmap : hSelectedBitmap;
|
|
|
|
m_nCommandID = nCommandID;
|
|
m_pSubMenu = pSubMenu;
|
|
}
|
|
m_bIsEmpty = bIsEmpty;
|
|
m_unselectedBitmapSize.cx = m_unselectedBitmapSize.cy = 0;
|
|
m_selectedBitmapSize.cx = m_selectedBitmapSize.cy = 0;
|
|
m_textSize.cx = m_textSize.cy = 0;
|
|
m_totalSize.cx = m_totalSize.cy = 0;
|
|
m_menuItemRect.SetRectEmpty();
|
|
m_bShowFeedback = bShowFeedback;
|
|
m_pUserData = pUserData;
|
|
}
|
|
|
|
CDropMenuItem::~CDropMenuItem()
|
|
{
|
|
|
|
if(IsSubMenu())
|
|
{
|
|
CDropMenu *pSubMenu = GetSubMenu();
|
|
pSubMenu->DestroyDropMenu();
|
|
delete pSubMenu;
|
|
}
|
|
}
|
|
void CDropMenuItem::GetMenuItemRect(LPRECT rect)
|
|
{
|
|
rect->left = m_menuItemRect.left;
|
|
rect->right = m_menuItemRect.right;
|
|
rect->top = m_menuItemRect.top;
|
|
rect->bottom = m_menuItemRect.bottom;
|
|
|
|
}
|
|
|
|
void CDropMenuItem::SetMenuItemRect(LPRECT rect)
|
|
{
|
|
m_menuItemRect.left = rect->left;
|
|
m_menuItemRect.right = rect->right;
|
|
m_menuItemRect.top = rect->top;
|
|
m_menuItemRect.bottom = rect->bottom;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Class CDropMenuDropTarget
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
CDropMenuDropTarget::CDropMenuDropTarget(CWnd *pOwner)
|
|
{
|
|
m_pOwner = pOwner;
|
|
|
|
}
|
|
|
|
|
|
DROPEFFECT CDropMenuDropTarget::OnDragEnter(CWnd * pWnd, COleDataObject * pDataObject,
|
|
DWORD dwKeyState, CPoint point)
|
|
{
|
|
return OnDragOver(pWnd, pDataObject, dwKeyState, point);
|
|
|
|
}
|
|
|
|
DROPEFFECT CDropMenuDropTarget::OnDragOver(CWnd * pWnd, COleDataObject * pDataObject,
|
|
DWORD dwKeyState, CPoint point )
|
|
{
|
|
CDropMenuDragData dragData(pDataObject, point);
|
|
m_pOwner->SendMessage(DT_DRAGGINGOCCURRED, (WPARAM) 0, (LPARAM)(&dragData));
|
|
|
|
return dragData.m_DropEffect;
|
|
}
|
|
|
|
BOOL CDropMenuDropTarget::OnDrop(CWnd * pWnd, COleDataObject * pDataObject,
|
|
DROPEFFECT dropEffect, CPoint point)
|
|
{
|
|
CDropMenuDragData* dragData = new CDropMenuDragData(pDataObject, point);
|
|
m_pOwner->SendMessage(DT_DROPOCCURRED, (WPARAM) 0, (LPARAM)(dragData));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// End CDropMenuDropTarget implementation
|
|
|
|
// CDropMenuColumn
|
|
CDropMenuColumn::CDropMenuColumn(int nFirstItem, int nLastItem, int nWidth, int nHeight)
|
|
{
|
|
m_nFirstItem = nFirstItem;
|
|
m_nLastItem = nLastItem;
|
|
m_nWidth = nWidth;
|
|
m_nHeight = nHeight;
|
|
m_bHasSubMenu = FALSE;
|
|
}
|
|
|
|
|
|
#define NOSELECTION -1
|
|
#define MENU_BORDER_SIZE 3
|
|
|
|
#define SUBMENU_WIDTH 9
|
|
#define SUBMENU_HEIGHT 11
|
|
|
|
#define SUBMENU_LEFT_MARGIN 3
|
|
#define SUBMENU_RIGHT_MARGIN 7
|
|
|
|
#define IDT_SUBMENU_OFF 16384
|
|
#define SUBMENU_DELAY_OFF_MS 400
|
|
|
|
#define IDT_SUBMENU_ON 16385
|
|
#define SUBMENU_DELAY_ON_MS 400
|
|
|
|
#define IDT_HAVE_FOCUS 16386
|
|
#define HAVE_FOCUS_DELAY 400
|
|
|
|
#define IDT_UNHOOK 16387
|
|
#define UNHOOK_DELAY 100
|
|
|
|
#define SEPARATOR_SPACE 2
|
|
#define SEPARATOR_HEIGHT 2
|
|
#define SEPARATOR_WIDTH 2
|
|
#define SPACE_BETWEEN_ITEMS 2
|
|
|
|
static HHOOK currentMouseHook;
|
|
static HHOOK currentKeyboardHook;
|
|
static CDropMenu * currentMenu = NULL; //This refers to a submenu of the current dropmenu
|
|
static CDropMenu * gLastMenu = NULL; //This refers to the most recent complete dropmenu
|
|
static LONG oldFrameProc;
|
|
static UINT gUnhookTimer = 0;
|
|
|
|
CDropMenu* CDropMenu::GetLastDropMenu()
|
|
{
|
|
return gLastMenu;
|
|
}
|
|
|
|
void CDropMenu::SetLastDropMenu(CDropMenu* menu)
|
|
{
|
|
gLastMenu = menu;
|
|
}
|
|
|
|
CDropMenu::CDropMenu()
|
|
{
|
|
|
|
m_pMenuItemArray.SetSize(0, 10);
|
|
|
|
m_WidestImage = 0;
|
|
m_WidestText = 0;
|
|
|
|
m_nSelectedItem = -1;
|
|
m_eSelectedItemSelType = eNONE;
|
|
m_bShowing = FALSE;
|
|
m_pDropTarget = NULL;
|
|
|
|
|
|
m_pUnselectedItem = NULL;
|
|
m_pSelectedItem = NULL;
|
|
|
|
m_nSelectTimer = 0;
|
|
m_nUnselectTimer = 0;
|
|
|
|
m_pMenuParent = NULL;
|
|
m_pShowingSubmenu = NULL;
|
|
|
|
m_bDropOccurring = FALSE;
|
|
m_bDragging = FALSE;
|
|
m_bRight = TRUE;
|
|
m_bMouseUsed = TRUE;
|
|
m_bIsOpen = FALSE;
|
|
m_pOverflowMenuItem = NULL;
|
|
m_bAboutToShow = FALSE;
|
|
m_pParentMenuItem = NULL;
|
|
m_hSubmenuUnselectedBitmap = NULL;
|
|
m_hSubmenuSelectedBitmap = NULL;
|
|
m_pUserData = NULL;
|
|
}
|
|
|
|
CDropMenu::~CDropMenu()
|
|
{
|
|
// Clear out any dangling pointers.
|
|
if(currentMenu == this) {
|
|
currentMenu = NULL;
|
|
}
|
|
if(gLastMenu == this) {
|
|
gLastMenu = NULL;
|
|
}
|
|
|
|
int nCount = m_pMenuItemArray.GetSize();
|
|
|
|
for(int i = 0; i < nCount; i++)
|
|
{
|
|
CDropMenuItem *pItem = (CDropMenuItem *)m_pMenuItemArray[i];
|
|
if(pItem != m_pOverflowMenuItem)
|
|
delete pItem;
|
|
}
|
|
|
|
int nColumnCount = m_pColumnArray.GetSize();
|
|
|
|
for(int j = 0 ; j < nColumnCount; j++)
|
|
delete (CDropMenuColumn*)m_pColumnArray[j];
|
|
|
|
if(m_pDropTarget)
|
|
delete m_pDropTarget;
|
|
|
|
if(m_pOverflowMenuItem != NULL)
|
|
delete m_pOverflowMenuItem;
|
|
|
|
m_pMenuItemArray.RemoveAll();
|
|
|
|
if(m_pMenuParent == NULL)
|
|
{
|
|
if(m_hSubmenuSelectedBitmap != NULL)
|
|
{
|
|
::DeleteObject(m_hSubmenuSelectedBitmap);
|
|
m_hSubmenuSelectedBitmap = NULL;
|
|
}
|
|
|
|
if(m_hSubmenuUnselectedBitmap != NULL)
|
|
{
|
|
::DeleteObject(m_hSubmenuUnselectedBitmap);
|
|
m_hSubmenuUnselectedBitmap = NULL;
|
|
}
|
|
}
|
|
|
|
if(m_pMenuParent != NULL && m_pMenuParent->m_pShowingSubmenu == this)
|
|
m_pMenuParent->m_pShowingSubmenu = NULL;
|
|
|
|
m_pMenuParent = NULL;
|
|
m_bShowing = FALSE;
|
|
|
|
|
|
}
|
|
|
|
UINT CDropMenu::GetMenuItemCount(void)
|
|
{
|
|
return m_pMenuItemArray.GetSize();
|
|
}
|
|
|
|
void CDropMenu::AppendMenu(UINT nFlags, UINT nIDNewItem, CString szText, BOOL bShowFeedback,
|
|
HBITMAP hUnselectedBitmap, HBITMAP hSelectedBitmap,
|
|
void* icon, IconType iconType, void *pUserData)
|
|
{
|
|
|
|
CDropMenuItem *pMenuItem = new CDropMenuItem(nFlags, szText, nIDNewItem,
|
|
hUnselectedBitmap, hSelectedBitmap, bShowFeedback, pUserData);
|
|
|
|
pMenuItem->SetIcon(icon, iconType);
|
|
m_pMenuItemArray.Add(pMenuItem);
|
|
}
|
|
|
|
void CDropMenu::AppendMenu(UINT nFlags, UINT nIDNewItem, CDropMenu *pSubMenu, BOOL bIsEmpty, CString szText,
|
|
BOOL bShowFeedback, HBITMAP hUnselectedBitmap, HBITMAP hSelectedBitmap,
|
|
void* icon, IconType iconType, void *pUserData)
|
|
{
|
|
CDropMenuItem *pMenuItem = new CDropMenuItem(nFlags, szText, nIDNewItem, pSubMenu, bIsEmpty,
|
|
hUnselectedBitmap, hSelectedBitmap, bShowFeedback, pUserData);
|
|
pMenuItem->SetIcon(icon, iconType);
|
|
m_pMenuItemArray.Add(pMenuItem);
|
|
}
|
|
|
|
void CDropMenu::DeleteMenu(UINT nPosition, UINT nFlags)
|
|
{
|
|
CDropMenuItem *pItem;
|
|
|
|
if(nFlags == MF_BYPOSITION)
|
|
{
|
|
UINT nCount = m_pMenuItemArray.GetSize();
|
|
|
|
if(nPosition >= 0 && nPosition < nCount)
|
|
{
|
|
pItem = (CDropMenuItem *)m_pMenuItemArray[nPosition];
|
|
m_pMenuItemArray.RemoveAt(nPosition, 1);
|
|
}
|
|
}
|
|
else if(nFlags == MF_BYCOMMAND)
|
|
{
|
|
int nCommandPosition = FindCommand(nPosition);
|
|
if(nCommandPosition != -1)
|
|
{
|
|
pItem = (CDropMenuItem *)m_pMenuItemArray[nCommandPosition];
|
|
m_pMenuItemArray.RemoveAt(nCommandPosition, 1);
|
|
}
|
|
}
|
|
|
|
if(pItem != m_pOverflowMenuItem)
|
|
delete pItem;
|
|
|
|
}
|
|
|
|
void CDropMenu::CreateOverflowMenuItem(UINT nCommand, CString szText, HBITMAP hUnselectedBitmap, HBITMAP hSelectedBitmap)
|
|
{
|
|
|
|
m_pOverflowMenuItem = new CDropMenuItem(MF_STRING, szText, nCommand, hUnselectedBitmap,
|
|
hSelectedBitmap, FALSE);
|
|
|
|
}
|
|
|
|
LRESULT CALLBACK EXPORT HandleMouseEvents(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(nCode < 0)
|
|
return CallNextHookEx(currentMouseHook, nCode, wParam, lParam);
|
|
|
|
MOUSEHOOKSTRUCT *mouseHook = (MOUSEHOOKSTRUCT*)lParam;
|
|
|
|
if(currentMenu != NULL)
|
|
{
|
|
//only want to deactivate if point is not in our menu or in our parent or children
|
|
if(nCode >= 0 && (wParam == WM_NCLBUTTONDOWN || wParam == WM_LBUTTONDOWN ||
|
|
((wParam == WM_LBUTTONUP || wParam == WM_NCLBUTTONUP) && currentMenu->IsDragging())))
|
|
{
|
|
|
|
if(currentMenu != NULL && !currentMenu->PointInMenus(mouseHook->pt))
|
|
{
|
|
currentMenu->Deactivate();
|
|
}
|
|
}
|
|
}
|
|
return CallNextHookEx(currentMouseHook, nCode, wParam, lParam);
|
|
|
|
}
|
|
|
|
LRESULT CALLBACK EXPORT HandleKeyboardEvents(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
|
|
if(nCode < 0)
|
|
{
|
|
return CallNextHookEx(currentKeyboardHook, nCode, wParam, lParam);
|
|
}
|
|
|
|
//only want to handle on a keydown
|
|
if(!(HIWORD(lParam) & KF_UP) && currentMenu != NULL)
|
|
{
|
|
currentMenu->HandleKeystroke(wParam);
|
|
}
|
|
|
|
//we don't want to pass the keyboard event onwards
|
|
return 1;
|
|
}
|
|
|
|
LRESULT CALLBACK EXPORT FrameProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(uMsg == WM_ACTIVATE)
|
|
{
|
|
if(LOWORD(wParam) == WA_INACTIVE && !currentMenu->IsShowingMenu((HWND)lParam))
|
|
{
|
|
currentMenu->Deactivate();
|
|
}
|
|
|
|
}
|
|
|
|
return CallWindowProc((WNDPROC)oldFrameProc, hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
// oppX and oppY refer to the x and y coordinates if the menu has to open in the opposite direction. Default is to not use them
|
|
void CDropMenu::TrackDropMenu(CWnd *pParent, int x, int y, BOOL bDragging, CDropMenuDropTarget *pDropTarget, BOOL bShowFeedback, int oppX, int oppY)
|
|
{
|
|
if(!m_bShowing)
|
|
{
|
|
m_bShowFeedback = bShowFeedback;
|
|
m_bDragging = bDragging;
|
|
m_bHasSubMenu = FALSE;
|
|
m_pParent = pParent;
|
|
m_bFirstPaint =TRUE;
|
|
if(m_pMenuParent != NULL)
|
|
{
|
|
m_bRight = m_pMenuParent->m_bRight;
|
|
}
|
|
|
|
// m_bNotDestroyed = TRUE;
|
|
if(GetMenuItemCount() == 0)
|
|
GetTopLevelParent()->SendMessage(DM_FILLINMENU, 0, (LPARAM)this);
|
|
|
|
|
|
|
|
m_bShowing = TRUE;
|
|
m_bAboutToShow = FALSE;
|
|
m_bIsOpen = TRUE;
|
|
|
|
if(m_hSubmenuUnselectedBitmap == NULL)
|
|
m_hSubmenuUnselectedBitmap = ::LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(IDB_SUBMENU1));
|
|
|
|
if(m_hSubmenuSelectedBitmap == NULL)
|
|
m_hSubmenuSelectedBitmap = ::LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(IDB_SUBMENU2));
|
|
|
|
if(!::IsWindow(m_hWnd))
|
|
{
|
|
CWnd::CreateEx(0, AfxRegisterWndClass( CS_SAVEBITS ,
|
|
theApp.LoadStandardCursor(IDC_ARROW),
|
|
(HBRUSH)(COLOR_MENU + 1), NULL),"test", WS_POPUP , 0, 0, 0,0, pParent->m_hWnd, NULL, NULL);
|
|
|
|
SetDropMenuTarget(pDropTarget);
|
|
}
|
|
else delete pDropTarget;
|
|
|
|
CSize size = GetMenuSize();
|
|
|
|
CPoint startPoint = FindStartPoint(x, y, size, oppX, oppY);
|
|
|
|
if(m_pMenuParent == NULL)
|
|
{
|
|
if(gLastMenu !=NULL)
|
|
{
|
|
//we only want one drop menu open at a time, so close the last one if one is
|
|
//still open. This will probably only happen on drag and drop.
|
|
gLastMenu->Deactivate();
|
|
}
|
|
|
|
oldFrameProc = SetWindowLong(GetParentFrame()->m_hWnd, GWL_WNDPROC, (LONG)FrameProc);
|
|
#ifdef _WIN32
|
|
currentMouseHook = SetWindowsHookEx(WH_MOUSE, HandleMouseEvents, AfxGetInstanceHandle(), GetCurrentThreadId());
|
|
currentKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, HandleKeyboardEvents, AfxGetInstanceHandle(),GetCurrentThreadId());
|
|
#else
|
|
currentMouseHook = SetWindowsHookEx(WH_MOUSE, HandleMouseEvents, AfxGetInstanceHandle(), GetCurrentTask());
|
|
currentKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, HandleKeyboardEvents, AfxGetInstanceHandle(), GetCurrentTask());
|
|
#endif
|
|
gLastMenu = this;
|
|
}
|
|
|
|
SetWindowPos(NULL, startPoint.x, startPoint.y,
|
|
size.cx + (2*MENU_BORDER_SIZE), size.cy + (2 * MENU_BORDER_SIZE),
|
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
|
ShowWindow(SW_SHOWNA);
|
|
//SetActiveWindow();
|
|
}
|
|
else delete pDropTarget;
|
|
}
|
|
|
|
void CDropMenu::SetDropMenuTarget(CDropMenuDropTarget *pDropTarget)
|
|
{
|
|
|
|
m_pDropTarget = pDropTarget;
|
|
|
|
DragAcceptFiles();
|
|
m_pDropTarget->Register(this);
|
|
|
|
}
|
|
|
|
BOOL CDropMenu::PointInMenus(POINT pt)
|
|
{
|
|
|
|
CRect rect;
|
|
|
|
GetWindowRect(&rect);
|
|
|
|
if(rect.PtInRect(pt))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
CDropMenu *menu = m_pMenuParent;
|
|
|
|
while(menu != NULL && IsWindow(menu->m_hWnd))
|
|
{
|
|
menu->GetWindowRect(&rect);
|
|
if(rect.PtInRect(pt))
|
|
{
|
|
return TRUE;
|
|
}
|
|
menu=menu->m_pMenuParent;
|
|
}
|
|
|
|
menu = m_pShowingSubmenu;
|
|
|
|
while(menu !=NULL && IsWindow(menu->m_hWnd))
|
|
{
|
|
menu->GetWindowRect(&rect);
|
|
if(rect.PtInRect(pt))
|
|
{
|
|
return TRUE;
|
|
}
|
|
menu = menu->m_pShowingSubmenu;
|
|
}
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void CDropMenu::HandleKeystroke(WPARAM key)
|
|
{
|
|
//Make all open windows know that we are in keyboard mode still
|
|
CDropMenu *pMenu = this;
|
|
|
|
while(pMenu != NULL)
|
|
{
|
|
pMenu->m_bMouseUsed = FALSE;
|
|
pMenu = pMenu->m_pMenuParent;
|
|
}
|
|
|
|
if(key == VK_ESCAPE || !m_bDragging)
|
|
{
|
|
switch(key)
|
|
{
|
|
case VK_ESCAPE: currentMenu->Deactivate();
|
|
break;
|
|
case VK_UP: HandleUpArrow();
|
|
break;
|
|
case VK_DOWN: HandleDownArrow();
|
|
break;
|
|
case VK_LEFT: HandleLeftArrow();
|
|
break;
|
|
case VK_RIGHT: HandleRightArrow();
|
|
break;
|
|
case VK_RETURN: HandleReturnKey();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
BOOL CDropMenu::OnCommand( WPARAM wParam, LPARAM lParam )
|
|
{
|
|
ShowWindow(SW_HIDE);
|
|
|
|
m_pParent->SendMessage(WM_COMMAND, wParam, lParam);
|
|
|
|
return 1;
|
|
}
|
|
|
|
BOOL CDropMenu::DestroyWindow(void)
|
|
{
|
|
return(CWnd::DestroyWindow());
|
|
}
|
|
|
|
|
|
void CDropMenu::Deactivate(void)
|
|
{
|
|
if(m_pMenuParent != NULL)
|
|
{
|
|
m_pMenuParent->SendMessage(DM_CLOSEALLMENUS, 0, 0);
|
|
|
|
}
|
|
ShowWindow(SW_HIDE);
|
|
}
|
|
|
|
BOOL CDropMenu::ShowWindow( int nCmdShow )
|
|
{
|
|
if(nCmdShow == SW_HIDE && IsWindowVisible())
|
|
{
|
|
m_bIsOpen = FALSE;
|
|
if(m_pMenuParent != NULL)
|
|
{
|
|
//Turn on parent's focus timer
|
|
m_pMenuParent->m_nHaveFocusTimer = m_pMenuParent->SetTimer(IDT_HAVE_FOCUS, HAVE_FOCUS_DELAY, NULL);
|
|
// we only want the parent to be the current menu if the parent hasn't already
|
|
// brought up a new submenu. Otherwise we have timing conflicts
|
|
if(m_pMenuParent->m_bShowing &&
|
|
(m_pMenuParent->m_pShowingSubmenu == this || m_pMenuParent->m_pShowingSubmenu == NULL))
|
|
{
|
|
currentMenu = m_pMenuParent;
|
|
}
|
|
|
|
}
|
|
KillTimer(m_nHaveFocusTimer);
|
|
|
|
//if this is the top level parent then the hook needs to be destroyed
|
|
if(m_pMenuParent == NULL)
|
|
{
|
|
UnhookWindowsHookEx(currentMouseHook);
|
|
UnhookWindowsHookEx(currentKeyboardHook);
|
|
SetWindowLong(GetParentFrame()->m_hWnd, GWL_WNDPROC, (LONG)oldFrameProc);
|
|
currentMenu = NULL;
|
|
gLastMenu = NULL;
|
|
}
|
|
OnTimer(IDT_SUBMENU_OFF);
|
|
m_bShowing = FALSE;
|
|
m_nSelectedItem = -1;
|
|
|
|
if(m_pShowingSubmenu)
|
|
{
|
|
//check to see if it's valid first because we may
|
|
//want to deactivate before it was created due to
|
|
//the timer never having been called to create it
|
|
if(IsWindow(m_pShowingSubmenu->m_hWnd))
|
|
{
|
|
m_pShowingSubmenu->ShowWindow(SW_HIDE);
|
|
}
|
|
m_pShowingSubmenu = NULL;
|
|
}
|
|
if(m_pMenuParent == NULL)
|
|
{
|
|
m_pParent->PostMessage(DM_MENUCLOSED, 0, 0);
|
|
|
|
}
|
|
}
|
|
else if(nCmdShow == SW_SHOWNA)
|
|
{
|
|
if(m_pMenuParent != NULL)
|
|
{
|
|
//since we are being shown, turn off parent's focus timer
|
|
m_pMenuParent->KillTimer(m_nHaveFocusTimer);
|
|
}
|
|
|
|
m_nHaveFocusTimer = SetTimer(IDT_HAVE_FOCUS, HAVE_FOCUS_DELAY, NULL);
|
|
currentMenu = this;
|
|
|
|
}
|
|
|
|
return CWnd::ShowWindow(nCmdShow);
|
|
|
|
|
|
}
|
|
|
|
void CDropMenu::PostNcDestroy(void )
|
|
{
|
|
CWnd::PostNcDestroy();
|
|
}
|
|
|
|
void CDropMenu::DestroyDropMenu(void)
|
|
{
|
|
DestroyWindow();
|
|
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Messages for CDropMenu
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
BEGIN_MESSAGE_MAP(CDropMenu, CWnd)
|
|
//{{AFX_MSG_MAP(CWnd)
|
|
ON_WM_PAINT()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_RBUTTONDOWN()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_NCHITTEST()
|
|
ON_MESSAGE(DT_DROPOCCURRED, OnDropTargetDropOccurred)
|
|
ON_MESSAGE(DT_DRAGGINGOCCURRED, OnDropTargetDraggingOccurred)
|
|
ON_MESSAGE(DM_CLOSEALLMENUS, OnCloseAllMenus)
|
|
ON_WM_TIMER()
|
|
ON_WM_ACTIVATE()
|
|
ON_WM_DESTROY()
|
|
//}}AFX_MSG_MAP
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
void CDropMenu::OnPaint()
|
|
{
|
|
CRect updateRect;
|
|
|
|
|
|
if(GetUpdateRect(&updateRect))
|
|
{
|
|
CPaintDC dcPaint(this); // device context for painting
|
|
|
|
CRect rcClient;
|
|
|
|
GetClientRect(&rcClient);
|
|
|
|
HDC hSrcDC = dcPaint.m_hDC;
|
|
|
|
HDC hMemDC = ::CreateCompatibleDC(hSrcDC);
|
|
HBITMAP hbmMem = CreateCompatibleBitmap(hSrcDC,
|
|
rcClient.Width(),
|
|
rcClient.Height());
|
|
|
|
//
|
|
// Select the bitmap into the off-screen DC.
|
|
//
|
|
COLORREF rgbOldBk = ::SetBkColor(hMemDC, sysInfo.m_clrMenu);
|
|
|
|
HBITMAP hbmOld = (HBITMAP)::SelectObject(hMemDC, hbmMem);
|
|
|
|
HBRUSH brFace = sysInfo.m_hbrMenu;
|
|
::FillRect(hMemDC, rcClient, brFace);
|
|
|
|
CRect intersectRect;
|
|
int nNumColumns = m_pColumnArray.GetSize();
|
|
int nFirstItem, nLastItem;
|
|
CDropMenuColumn *pColumn;
|
|
int nStartX = 0;
|
|
|
|
for(int j = 0; j <=m_nLastVisibleColumn; j++)
|
|
{
|
|
int y = MENU_BORDER_SIZE;
|
|
|
|
pColumn = (CDropMenuColumn*)m_pColumnArray[j];
|
|
|
|
nFirstItem = pColumn->GetFirstItem();
|
|
nLastItem = pColumn->GetLastItem();
|
|
|
|
for(int i = nFirstItem; i <= nLastItem; i++)
|
|
{
|
|
CDropMenuItem *item = (CDropMenuItem*)m_pMenuItemArray[i];
|
|
|
|
if(m_bShowFeedback)
|
|
y += SPACE_BETWEEN_ITEMS;
|
|
|
|
if(item->IsSeparator())
|
|
{
|
|
CRect separatorRect(nStartX + MENU_BORDER_SIZE, y, nStartX + MENU_BORDER_SIZE + pColumn->GetWidth(), y + SEPARATOR_SPACE * 2 + SEPARATOR_HEIGHT);
|
|
|
|
if(intersectRect.IntersectRect(separatorRect, updateRect))
|
|
{
|
|
DrawSeparator(hMemDC, separatorRect.left, y, separatorRect.Width() - (2 * MENU_BORDER_SIZE));
|
|
}
|
|
y += SEPARATOR_SPACE * 2 + SEPARATOR_HEIGHT;
|
|
}
|
|
else
|
|
{
|
|
CRect itemRect;
|
|
|
|
item->GetMenuItemRect(itemRect);
|
|
if(intersectRect.IntersectRect(itemRect, updateRect))
|
|
{
|
|
CRect rect(nStartX + MENU_BORDER_SIZE, y ,nStartX + MENU_BORDER_SIZE + pColumn->GetWidth(), y + itemRect.Height());
|
|
|
|
DrawItem(pColumn, item, rect, hMemDC, i == m_nSelectedItem,
|
|
(i == m_nSelectedItem) ? m_eSelectedItemSelType : eNONE);
|
|
}
|
|
|
|
y += itemRect.Height();
|
|
}
|
|
|
|
}
|
|
nStartX += pColumn->GetWidth();
|
|
if(j < m_nLastVisibleColumn)
|
|
{
|
|
DrawVerticalSeparator(hMemDC, nStartX, MENU_BORDER_SIZE, rcClient.Height() - (2 * MENU_BORDER_SIZE));
|
|
nStartX += SEPARATOR_WIDTH;
|
|
}
|
|
}
|
|
// need to make sure selection type shows up
|
|
if(m_nSelectedItem != NOSELECTION && m_eSelectedItemSelType != eNONE)
|
|
{
|
|
CRect itemRect;
|
|
CDropMenuItem *item = (CDropMenuItem*)m_pMenuItemArray[m_nSelectedItem];
|
|
|
|
if(!item->IsSeparator())
|
|
{
|
|
item->GetMenuItemRect(itemRect);
|
|
|
|
CRect rect(itemRect.left, itemRect.top ,itemRect.left + ((CDropMenuColumn*)m_pColumnArray[item->GetColumn()])->GetWidth(), itemRect.top + itemRect.Height());
|
|
|
|
DrawItem((CDropMenuColumn*)m_pColumnArray[item->GetColumn()], item, rect, hMemDC, TRUE, m_eSelectedItemSelType );
|
|
}
|
|
|
|
}
|
|
DrawBorders(hMemDC, rcClient);
|
|
|
|
::BitBlt(hSrcDC, 0, 0, rcClient.Width(), rcClient.Height(), hMemDC, 0, 0,
|
|
SRCCOPY);
|
|
|
|
::SetBkColor(hMemDC, rgbOldBk);
|
|
|
|
::SelectObject(hMemDC, hbmOld);
|
|
::DeleteObject(hbmMem);
|
|
|
|
::DeleteDC(hMemDC);
|
|
}
|
|
if(m_bFirstPaint)
|
|
{
|
|
MSG msg;
|
|
|
|
PeekMessage(&msg, this->m_hWnd, WM_LBUTTONUP, WM_LBUTTONUP, PM_REMOVE);
|
|
m_bFirstPaint = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
void CDropMenu::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if(!m_bMouseUsed)
|
|
{
|
|
m_bMouseUsed = TRUE;
|
|
return;
|
|
}
|
|
|
|
m_bMouseUsed = TRUE;
|
|
|
|
KeepMenuAroundIfClosing();
|
|
ChangeSelection(point);
|
|
}
|
|
|
|
UINT CDropMenu::OnNcHitTest( CPoint point )
|
|
{
|
|
return CWnd::OnNcHitTest(point);
|
|
}
|
|
|
|
void CDropMenu::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
//if we haven't painted yet then the user hasn't had a chance to mouse up.
|
|
if(m_bFirstPaint || m_nSelectedItem == NOSELECTION)
|
|
return;
|
|
|
|
MenuSelectionType eSelType;
|
|
int nSelection = FindSelection(point, eSelType);
|
|
|
|
if(nSelection != -1)
|
|
{
|
|
CDropMenuItem *pItem = (CDropMenuItem *)m_pMenuItemArray[nSelection];
|
|
|
|
if(!pItem->IsSubMenu())
|
|
{
|
|
SendMessage(WM_COMMAND, (WPARAM) pItem->GetCommand(), (LPARAM) m_hWnd);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CDropMenu::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
// we want our frame to stay the active window. Causes flicker
|
|
GetParentFrame()->SetActiveWindow();
|
|
}
|
|
|
|
void CDropMenu::OnRButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
// we want our frame to stay the active window. Causes flicker
|
|
GetParentFrame()->SetActiveWindow();
|
|
}
|
|
|
|
|
|
LRESULT CDropMenu::OnDropTargetDraggingOccurred(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (wParam == 0)
|
|
{
|
|
CDropMenuDragData* pData = (CDropMenuDragData*)lParam;
|
|
KeepMenuAroundIfClosing();
|
|
ChangeSelection(pData->m_PointHit);
|
|
|
|
// Ok, now we need to figure out what our drag feedback should be.
|
|
// note that point is already in our coordinates since we got it from our drop target
|
|
MenuSelectionType eSelType;
|
|
int nSelection = FindSelection(pData->m_PointHit, eSelType);
|
|
|
|
if(nSelection != -1)
|
|
{
|
|
CDropMenuItem *pItem = (CDropMenuItem *)m_pMenuItemArray[nSelection];
|
|
pData->m_nCommand = pItem->GetCommand();
|
|
pData->eSelType = eSelType;
|
|
m_pParent->SendMessage(DT_DRAGGINGOCCURRED, 1, lParam);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pParent->SendMessage(DT_DRAGGINGOCCURRED, 1, lParam);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
LRESULT CDropMenu::OnDropTargetDropOccurred(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (wParam == 0)
|
|
{
|
|
CDropMenuDragData* pData = (CDropMenuDragData*)lParam;
|
|
|
|
// Ok, now we need to figure out what our drag feedback should be.
|
|
// note that point is already in our coordinates since we got it from our drop target
|
|
MenuSelectionType eSelType;
|
|
int nSelection = FindSelection(pData->m_PointHit, eSelType);
|
|
|
|
if(nSelection != -1)
|
|
{
|
|
CDropMenuItem *pItem = (CDropMenuItem *)m_pMenuItemArray[nSelection];
|
|
pData->m_nCommand = pItem->GetCommand();
|
|
pData->eSelType = eSelType;
|
|
m_pParent->SendMessage(DT_DROPOCCURRED, 1, lParam);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pParent->SendMessage(DT_DROPOCCURRED, 1, lParam);
|
|
}
|
|
|
|
ShowWindow(SW_HIDE);
|
|
|
|
return 1;
|
|
}
|
|
|
|
LRESULT CDropMenu::OnCloseAllMenus(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
|
|
if(m_pMenuParent != NULL)
|
|
{
|
|
m_pMenuParent->PostMessage(DM_CLOSEALLMENUS, wParam, lParam);
|
|
}
|
|
|
|
ShowWindow(SW_HIDE);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
void CDropMenu::OnTimer( UINT nIDEvent )
|
|
{
|
|
if(nIDEvent == IDT_SUBMENU_OFF)
|
|
{
|
|
KillTimer(m_nUnselectTimer);
|
|
|
|
if(m_pUnselectedItem != NULL && m_pUnselectedItem->GetSubMenu()->m_bShowing==FALSE)
|
|
{
|
|
m_pUnselectedItem->GetSubMenu()->ShowWindow(SW_HIDE);
|
|
}
|
|
m_pUnselectedItem = NULL;
|
|
|
|
}
|
|
else if(nIDEvent == IDT_SUBMENU_ON)
|
|
{
|
|
KillTimer(m_nSelectTimer);
|
|
|
|
if(m_bShowing)
|
|
{
|
|
|
|
if(m_pSelectedItem)
|
|
{
|
|
CDropMenu *pSubMenu = m_pSelectedItem->GetSubMenu();
|
|
if(pSubMenu && pSubMenu->m_bAboutToShow)
|
|
ShowSubmenu(m_pSelectedItem);
|
|
else
|
|
m_pSelectedItem = NULL;
|
|
|
|
}
|
|
m_nSelectTimer = 0;
|
|
}
|
|
}
|
|
else if(nIDEvent == IDT_HAVE_FOCUS)
|
|
{
|
|
if(m_nSelectedItem != -1 && m_bMouseUsed)
|
|
{
|
|
CDropMenuItem *pItem = (CDropMenuItem*)m_pMenuItemArray[m_nSelectedItem];
|
|
|
|
CPoint point;
|
|
|
|
GetCursorPos(&point);
|
|
|
|
ScreenToClient(&point);
|
|
|
|
CRect rcClient, rect;
|
|
GetClientRect(rcClient);
|
|
|
|
if (!rcClient.PtInRect(point) && m_pShowingSubmenu == NULL )
|
|
{
|
|
pItem->GetMenuItemRect(rect);
|
|
rect.left = 0;
|
|
rect.right = rcClient.right;
|
|
|
|
m_nSelectedItem = -1;
|
|
|
|
InvalidateRect(&rect);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void CDropMenu::OnActivate( UINT nState, CWnd* pWndOther, BOOL bMinimized )
|
|
{
|
|
if(nState == WA_ACTIVE)
|
|
{
|
|
pWndOther->SetActiveWindow();
|
|
}
|
|
}
|
|
|
|
void CDropMenu::OnDestroy( )
|
|
{
|
|
m_pDropTarget->Revoke();
|
|
CWnd::OnDestroy();
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Helpers for CDropMenu
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void CDropMenu::DrawSeparator(HDC hDC, int x, int y, int nWidth)
|
|
{
|
|
|
|
HPEN pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
|
|
HPEN pOldPen = (HPEN)::SelectObject(hDC, pen);
|
|
|
|
#if defined (WIN32)
|
|
::MoveToEx(hDC, x, y + SEPARATOR_SPACE, NULL);
|
|
#else
|
|
::MoveTo(hDC, x, y + SEPARATOR_SPACE);
|
|
#endif
|
|
::LineTo(hDC, x + nWidth, y + SEPARATOR_SPACE);
|
|
|
|
::SelectObject(hDC, pOldPen);
|
|
::DeleteObject(pen);
|
|
|
|
#if defined(WIN32)
|
|
pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHILIGHT));
|
|
#else
|
|
pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
|
|
#endif
|
|
|
|
pOldPen = (HPEN)::SelectObject(hDC, pen);
|
|
|
|
#if defined(WIN32)
|
|
::MoveToEx(hDC, x, y + SEPARATOR_SPACE + 1, NULL);
|
|
#else
|
|
::MoveTo(hDC, x, y + SEPARATOR_SPACE + 1);
|
|
#endif
|
|
|
|
::LineTo(hDC, x + nWidth, y + SEPARATOR_SPACE + 1);
|
|
|
|
::SelectObject(hDC, pOldPen);
|
|
::DeleteObject(pen);
|
|
|
|
}
|
|
|
|
void CDropMenu::DrawVerticalSeparator(HDC hDC, int x, int y, int nHeight)
|
|
{
|
|
HPEN pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
|
|
HPEN pOldPen = (HPEN)::SelectObject(hDC, pen);
|
|
|
|
#if defined (WIN32)
|
|
::MoveToEx(hDC, x + SEPARATOR_SPACE, y, NULL);
|
|
#else
|
|
::MoveTo(hDC, x + SEPARATOR_SPACE, y);
|
|
#endif
|
|
::LineTo(hDC, x + SEPARATOR_SPACE, y + nHeight);
|
|
|
|
::SelectObject(hDC, pOldPen);
|
|
::DeleteObject(pen);
|
|
|
|
#if defined(WIN32)
|
|
pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHILIGHT));
|
|
#else
|
|
pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
|
|
#endif
|
|
|
|
pOldPen = (HPEN)::SelectObject(hDC, pen);
|
|
|
|
#if defined(WIN32)
|
|
::MoveToEx(hDC, x + SEPARATOR_SPACE + 1, y, NULL);
|
|
#else
|
|
::MoveTo(hDC, x + SEPARATOR_SPACE + 1, y);
|
|
#endif
|
|
|
|
::LineTo(hDC, x + SEPARATOR_SPACE + 1, y + nHeight);
|
|
|
|
::SelectObject(hDC, pOldPen);
|
|
::DeleteObject(pen);
|
|
}
|
|
|
|
void CDropMenu::DrawBorders(HDC hDC, CRect rcClient)
|
|
{
|
|
|
|
//Draw inner rect which is all BTN_FACE
|
|
RECT rect;
|
|
::SetRect(&rect, rcClient.left + 2, rcClient.top + 2, rcClient.right - 2, rcClient.bottom - 2);
|
|
::FrameRect(hDC, &rect, sysInfo.m_hbrBtnFace);
|
|
|
|
#if defined(WIN32)
|
|
HPEN pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHILIGHT));
|
|
#else
|
|
HPEN pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
|
|
#endif
|
|
|
|
HPEN pOldPen = (HPEN)::SelectObject(hDC, pen);
|
|
|
|
#if defined(WIN32)
|
|
::MoveToEx(hDC, rcClient.left + 1, rcClient.bottom - 1, NULL);
|
|
#else
|
|
::MoveTo(hDC, rcClient.left + 1, rcClient.bottom - 1);
|
|
#endif
|
|
::LineTo(hDC, rcClient.left + 1, rcClient.top + 1);
|
|
::LineTo(hDC, rcClient.right - 1, rcClient.top + 1);
|
|
|
|
::SelectObject(hDC, pOldPen);
|
|
::DeleteObject(pen);
|
|
|
|
pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNFACE));
|
|
|
|
pOldPen = (HPEN)::SelectObject(hDC, pen);
|
|
|
|
#if defined(WIN32)
|
|
::MoveToEx(hDC, rcClient.left, rcClient.bottom - 1, NULL);
|
|
#else
|
|
::MoveTo(hDC, rcClient.left, rcClient.bottom - 1);
|
|
#endif
|
|
|
|
::LineTo(hDC, rcClient.left, rcClient.top);
|
|
::LineTo(hDC, rcClient.right - 1, rcClient.top);
|
|
|
|
::SelectObject(hDC, pOldPen);
|
|
::DeleteObject(pen);
|
|
|
|
pen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
|
|
|
|
pOldPen = (HPEN)::SelectObject(hDC, pen);
|
|
|
|
#if defined(WIN32)
|
|
::MoveToEx(hDC, rcClient.right - 1, rcClient.top, NULL);
|
|
#else
|
|
::MoveTo(hDC, rcClient.right - 1, rcClient.top);
|
|
#endif
|
|
|
|
::LineTo(hDC, rcClient.right - 1 , rcClient.bottom - 1);
|
|
::LineTo(hDC, rcClient.left - 1, rcClient.bottom - 1);
|
|
|
|
::SelectObject(hDC, pOldPen);
|
|
::DeleteObject(pen);
|
|
|
|
pen = ::CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
|
|
|
|
pOldPen = (HPEN)::SelectObject(hDC, pen);
|
|
|
|
#if defined(WIN32)
|
|
::MoveToEx(hDC, rcClient.right - 2, rcClient.top + 1, NULL);
|
|
#else
|
|
::MoveTo(hDC, rcClient.right - 2, rcClient.top + 1);
|
|
#endif
|
|
::LineTo(hDC, rcClient.right - 2, rcClient.bottom - 2);
|
|
::LineTo(hDC, rcClient.left, rcClient.bottom -2);
|
|
|
|
::SelectObject(hDC, pOldPen);
|
|
::DeleteObject(pen);
|
|
|
|
}
|
|
|
|
|
|
void CDropMenu::DrawItem(CDropMenuColumn *pColumn, CDropMenuItem *pItem, CRect rc, HDC hDC, BOOL bIsSelected, MenuSelectionType eSelType)
|
|
{
|
|
// Extract the goods from lpDI
|
|
ASSERT(pItem != NULL);
|
|
|
|
// Get proper colors and paint the background first
|
|
COLORREF rgbTxt;
|
|
HBRUSH brFace;
|
|
COLORREF rgbOldBk;
|
|
|
|
if (bIsSelected && (eSelType == eNONE || eSelType == eON))
|
|
{
|
|
rgbOldBk = ::SetBkColor(hDC, sysInfo.m_clrHighlight);
|
|
|
|
brFace = sysInfo.m_hbrHighlight;
|
|
rgbTxt = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
|
|
}
|
|
else
|
|
{
|
|
rgbOldBk = ::SetBkColor(hDC, sysInfo.m_clrMenu);
|
|
|
|
brFace = sysInfo.m_hbrMenu;
|
|
rgbTxt = ::GetSysColor(COLOR_MENUTEXT);
|
|
}
|
|
|
|
::FillRect(hDC, rc, brFace);
|
|
|
|
if(eSelType == eABOVE)
|
|
DrawSeparator(hDC, rc.left, rc.top - SEPARATOR_SPACE - 2, rc.Width() / 2);
|
|
else if(eSelType == eBELOW)
|
|
DrawSeparator(hDC, rc.left, rc.bottom - SEPARATOR_HEIGHT - SEPARATOR_SPACE + 2, rc.Width() / 2);
|
|
|
|
CDC *pDC = CDC::FromHandle(hDC);
|
|
// Now paint the bitmap, left side of menu
|
|
rc.left += nIMG_SPACE;
|
|
CSize imgSize = DrawImage(pDC, rc, pColumn, pItem, bIsSelected, eSelType);
|
|
|
|
// And now the text
|
|
HFONT MenuFont;
|
|
#if defined(WIN32)
|
|
NONCLIENTMETRICS ncm;
|
|
ncm.cbSize = sizeof(NONCLIENTMETRICS);
|
|
if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0))
|
|
{
|
|
MenuFont = theApp.CreateAppFont( ncm.lfMenuFont );
|
|
}
|
|
else
|
|
{
|
|
MenuFont = (HFONT)::GetStockObject(SYSTEM_FONT);
|
|
}
|
|
#else // Win16
|
|
MenuFont = (HFONT)::GetStockObject(SYSTEM_FONT);
|
|
#endif // WIN32
|
|
|
|
HFONT pOldFont = (HFONT)::SelectObject(hDC, MenuFont);
|
|
int nOldBkMode = ::SetBkMode(hDC, TRANSPARENT);
|
|
COLORREF rgbOldTxt = ::SetTextColor(hDC, rgbTxt);
|
|
|
|
//Figure out where text should go in relation to bitmaps
|
|
rc.left += imgSize.cx + nIMG_SPACE + (pColumn->GetWidestImage()-imgSize.cx);
|
|
|
|
//Deal with the case where there is a tab for an accelerator
|
|
CString label=pItem->GetText();
|
|
|
|
DrawText(hDC, (const char*)label, -1, &rc, DT_LEFT | DT_VCENTER | DT_SINGLELINE |DT_EXPANDTABS);
|
|
|
|
::SetBkMode(hDC, nOldBkMode);
|
|
::SetTextColor(hDC, rgbOldTxt);
|
|
::SelectObject(hDC, pOldFont);
|
|
|
|
#if defined(WIN32)
|
|
if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0))
|
|
{
|
|
theApp.ReleaseAppFont(MenuFont);
|
|
}
|
|
#endif
|
|
|
|
// Draw submenu bitmap
|
|
if(pItem->IsSubMenu() && !pItem->IsEmpty())
|
|
{
|
|
HBITMAP pSubmenuBitmap;
|
|
|
|
if(bIsSelected && (eSelType == eNONE || eSelType == eON))
|
|
{
|
|
pSubmenuBitmap = m_hSubmenuSelectedBitmap;
|
|
}
|
|
else
|
|
{
|
|
pSubmenuBitmap = m_hSubmenuUnselectedBitmap;
|
|
}
|
|
|
|
// Create a scratch DC and select our bitmap into it.
|
|
HDC pBmpDC = CreateCompatibleDC(hDC);
|
|
HBITMAP pOldBmp = (HBITMAP)::SelectObject(pBmpDC, pSubmenuBitmap);
|
|
|
|
// Center the image horizontally and vertically
|
|
CPoint ptDst(rc.right - SUBMENU_WIDTH - SUBMENU_RIGHT_MARGIN, rc.top +
|
|
(((rc.Height() - SUBMENU_HEIGHT) + 1) / 2));
|
|
|
|
// Call the handy transparent blit function to paint the bitmap over
|
|
// the background.
|
|
::FEU_TransBlt(hDC, ptDst.x, ptDst.y,SUBMENU_WIDTH, SUBMENU_HEIGHT,
|
|
pBmpDC, 0, 0, WFE_GetUIPalette(GetParentFrame()),RGB(255, 0, 255) );
|
|
|
|
// Cleanup
|
|
::SelectObject(pBmpDC, pOldBmp);
|
|
::DeleteDC(pBmpDC);
|
|
|
|
}
|
|
::SetBkColor(hDC, rgbOldBk);
|
|
|
|
} // END OF FUNCTION CDropMenu::DrawItem()
|
|
|
|
/****************************************************************************
|
|
*
|
|
* CDropMenu::DrawImage
|
|
*
|
|
* PARAMETERS:
|
|
* pDC - pointer to device context to draw on
|
|
* rect - bounding rectangle to draw in
|
|
* pItem - pointer to CDropMenuItem that contains the data
|
|
* bIsSelected - whether this item is selected
|
|
*
|
|
* RETURNS:
|
|
* width of the image, in pixels
|
|
*
|
|
* DESCRIPTION:
|
|
* Protected helper function for drawing the bitmap image in a menu
|
|
* item. We return the size of the painted image so the caller can
|
|
* position the menu text after the image.
|
|
*
|
|
****************************************************************************/
|
|
|
|
CSize CDropMenu::DrawImage(CDC * pDC, const CRect & rect, CDropMenuColumn *pColumn, CDropMenuItem * pItem, BOOL bIsSelected,
|
|
MenuSelectionType eSelType)
|
|
{
|
|
CSize sizeImg;
|
|
|
|
sizeImg.cx = sizeImg.cy = 0;
|
|
|
|
HBITMAP hImg = (bIsSelected && (!m_bShowFeedback || eSelType == eON || eSelType == eNONE)) ?
|
|
pItem->GetSelectedBitmap() : pItem->GetUnselectedBitmap();
|
|
if (hImg != NULL)
|
|
{
|
|
// Get image dimensions
|
|
BITMAP bmp;
|
|
GetObject(hImg, sizeof(bmp), &bmp);
|
|
|
|
sizeImg.cx = bmp.bmWidth;
|
|
sizeImg.cy = bmp.bmHeight;
|
|
|
|
// Create a scratch DC and select our bitmap into it.
|
|
HDC hBmpDC = ::CreateCompatibleDC(pDC->m_hDC);
|
|
HBITMAP hOldBmp = (HBITMAP)SelectObject(hBmpDC, hImg);
|
|
|
|
// Center the image horizontally and vertically
|
|
CPoint ptDst(rect.left + (pColumn->GetWidestImage() - sizeImg.cx)/2, rect.top +
|
|
(((rect.Height() - sizeImg.cy) + 1) / 2));
|
|
|
|
// Call the handy transparent blit function to paint the bitmap over
|
|
// the background.
|
|
|
|
if (pItem->GetIconType() == LOCAL_FILE)
|
|
{
|
|
HICON hIcon = pItem->GetLocalFileIcon();
|
|
DrawIconEx(pDC->m_hDC, ptDst.x, ptDst.y, hIcon, 0, 0, 0, NULL, DI_NORMAL);
|
|
}
|
|
else if (pItem->GetIconType() == ARBITRARY_URL)
|
|
{
|
|
CRDFImage* pImage = pItem->GetCustomIcon();
|
|
HDC hDC = pDC->m_hDC;
|
|
int left = ptDst.x;
|
|
int top = ptDst.y;
|
|
int imageWidth = 16;
|
|
int imageHeight = 16;
|
|
COLORREF bkColor = (bIsSelected && (!m_bShowFeedback || eSelType == eON || eSelType == eNONE)) ?
|
|
GetSysColor(COLOR_HIGHLIGHT) : GetSysColor(COLOR_MENU);
|
|
if (pImage && pImage->FrameLoaded())
|
|
{
|
|
// Now we draw this bad boy.
|
|
if (pImage->m_BadImage)
|
|
{
|
|
// display broken icon.
|
|
HDC tempDC = ::CreateCompatibleDC(hDC);
|
|
HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC, CRDFImage::m_hBadImageBitmap);
|
|
::StretchBlt(hDC,
|
|
left, top,
|
|
imageWidth, imageHeight,
|
|
tempDC, 0, 0,
|
|
imageWidth, imageHeight, SRCCOPY);
|
|
::SelectObject(tempDC, hOldBmp);
|
|
::DeleteDC(tempDC);
|
|
}
|
|
else if (pImage->bits )
|
|
{
|
|
// Center the image.
|
|
long width = pImage->bmpInfo->bmiHeader.biWidth;
|
|
long height = pImage->bmpInfo->bmiHeader.biHeight;
|
|
int xoffset = (imageWidth-width)/2;
|
|
int yoffset = (imageHeight-height)/2;
|
|
if (xoffset < 0) xoffset = 0;
|
|
if (yoffset < 0) yoffset = 0;
|
|
if (width > imageWidth) width = imageWidth;
|
|
if (height > imageHeight) height = imageHeight;
|
|
|
|
HPALETTE hPal = WFE_GetUIPalette(NULL);
|
|
HPALETTE hOldPal = ::SelectPalette(hDC, hPal, TRUE);
|
|
|
|
::RealizePalette(hDC);
|
|
|
|
if (pImage->maskbits)
|
|
{
|
|
WFE_StretchDIBitsWithMask(hDC, TRUE, NULL,
|
|
left+xoffset, top+xoffset,
|
|
width, height,
|
|
0, 0, width, height,
|
|
pImage->bits, pImage->bmpInfo,
|
|
pImage->maskbits, FALSE, bkColor);
|
|
}
|
|
else
|
|
{
|
|
::StretchDIBits(hDC,
|
|
left+xoffset, top+xoffset,
|
|
width, height,
|
|
0, 0, width, height, pImage->bits, pImage->bmpInfo, DIB_RGB_COLORS,
|
|
SRCCOPY);
|
|
}
|
|
|
|
::SelectPalette(hDC, hOldPal, TRUE);
|
|
}
|
|
}
|
|
}
|
|
else ::BitBlt(pDC->m_hDC, ptDst.x, ptDst.y, sizeImg.cx, sizeImg.cy, hBmpDC, 0, 0, SRCCOPY);
|
|
|
|
// Cleanup
|
|
::SelectObject(hBmpDC, hOldBmp);
|
|
::DeleteDC(hBmpDC);
|
|
|
|
}
|
|
|
|
return(sizeImg);
|
|
|
|
} // END OF FUNCTION CTreeMenu::DrawImage()
|
|
|
|
CDropMenuDropTarget *CDropMenu::GetDropMenuDropTarget(CWnd *pOwner)
|
|
{
|
|
|
|
return new CDropMenuDropTarget(pOwner);
|
|
}
|
|
|
|
CSize CDropMenu::GetMenuSize(void)
|
|
{
|
|
CSize totalSize, itemSize;
|
|
|
|
int nColumnHeight = MENU_BORDER_SIZE, nColumnWidth = 0;
|
|
|
|
|
|
CalculateItemDimensions();
|
|
int nCount = m_pMenuItemArray.GetSize();
|
|
|
|
int nScreenLeft = 0;
|
|
int nScreenRight = GetSystemMetrics(SM_CXFULLSCREEN);
|
|
int nScreenTop = 0;
|
|
int nScreenBottom = GetSystemMetrics(SM_CYFULLSCREEN);
|
|
#ifdef XP_WIN32
|
|
RECT rect;
|
|
if(SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rect,0))
|
|
{
|
|
nScreenLeft = rect.left;
|
|
nScreenRight = rect.right;
|
|
nScreenTop = rect.top;
|
|
nScreenBottom = rect.bottom;
|
|
}
|
|
#endif
|
|
|
|
int nStartX= MENU_BORDER_SIZE;
|
|
int nOldStartX = MENU_BORDER_SIZE;
|
|
|
|
int nMaxColumnHeight = 0;
|
|
|
|
int nNumColumns = m_pColumnArray.GetSize();
|
|
CSize columnSize;
|
|
CDropMenuColumn *pColumn;
|
|
m_nLastVisibleColumn = nNumColumns - 1;
|
|
|
|
for(int i = 0; i < nNumColumns; i++)
|
|
{
|
|
pColumn = (CDropMenuColumn *)m_pColumnArray[i];
|
|
if(pColumn->GetHasSubMenu())
|
|
pColumn->SetWidth(pColumn->GetWidth() + SUBMENU_LEFT_MARGIN + SUBMENU_RIGHT_MARGIN + SUBMENU_WIDTH);
|
|
else
|
|
pColumn->SetWidth(pColumn->GetWidth() + SUBMENU_RIGHT_MARGIN);
|
|
|
|
columnSize = CalculateColumn(pColumn, nStartX);
|
|
|
|
if(nScreenLeft + nStartX + columnSize.cx >= nScreenRight)
|
|
{
|
|
//if we have more than one column, don't put in the last separator
|
|
if(nNumColumns > 1)
|
|
{
|
|
if(m_pOverflowMenuItem != NULL)
|
|
{
|
|
if(i > 0)
|
|
nStartX = AddOverflowItem(i - 1, nOldStartX);
|
|
else
|
|
nStartX = AddOverflowItem(i, nStartX - SEPARATOR_WIDTH);
|
|
}
|
|
|
|
|
|
}
|
|
m_nLastVisibleColumn = i - 1;
|
|
break;
|
|
}
|
|
|
|
if(columnSize.cy > nMaxColumnHeight)
|
|
nMaxColumnHeight = columnSize.cy;
|
|
|
|
nOldStartX = nStartX;
|
|
nStartX += columnSize.cx;
|
|
if(i + 1 < nNumColumns)
|
|
nStartX += SEPARATOR_WIDTH;
|
|
}
|
|
|
|
totalSize.cy = nMaxColumnHeight;
|
|
totalSize.cx = ((nNumColumns > 1) ? nStartX - SEPARATOR_WIDTH : nStartX);
|
|
return totalSize;
|
|
}
|
|
|
|
CSize CDropMenu::CalculateColumn(CDropMenuColumn *pColumn, int nStartX)
|
|
{
|
|
int nStart = pColumn->GetFirstItem();
|
|
int nEnd = pColumn->GetLastItem();
|
|
int nColumnWidth = pColumn->GetWidth();
|
|
int nItemHeight;
|
|
|
|
CSize totalSize(0, MENU_BORDER_SIZE);
|
|
CSize itemSize;
|
|
for(int i = nStart; i <= nEnd; i++)
|
|
{
|
|
CDropMenuItem *item = (CDropMenuItem*)m_pMenuItemArray[i];
|
|
|
|
if(m_bShowFeedback)
|
|
totalSize.cy += SPACE_BETWEEN_ITEMS;
|
|
|
|
if(item->IsSeparator())
|
|
{
|
|
|
|
CRect rect (nStartX, totalSize.cy, nStartX + nColumnWidth, totalSize.cy + SEPARATOR_SPACE * 2 + SEPARATOR_HEIGHT);
|
|
item->SetMenuItemRect(rect);
|
|
|
|
nItemHeight = SEPARATOR_SPACE * 2 + SEPARATOR_HEIGHT;
|
|
|
|
}
|
|
else
|
|
{
|
|
itemSize=MeasureItem(item);
|
|
CRect rect(nStartX, totalSize.cy, nStartX + nColumnWidth, totalSize.cy + itemSize.cy);
|
|
|
|
item->SetMenuItemRect(rect);
|
|
|
|
nItemHeight = itemSize.cy;
|
|
|
|
}
|
|
|
|
totalSize.cy += nItemHeight;
|
|
|
|
}
|
|
return CSize(pColumn->GetWidth(), totalSize.cy);
|
|
}
|
|
|
|
//returns the x coordinate of the right side of this last column
|
|
int CDropMenu::AddOverflowItem(int nColumn, int nStartX)
|
|
{
|
|
int nScreenTop = 0;
|
|
int nScreenBottom = GetSystemMetrics(SM_CYFULLSCREEN);
|
|
#ifdef XP_WIN32
|
|
RECT rect;
|
|
if(SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rect,0))
|
|
{
|
|
nScreenTop = rect.top;
|
|
nScreenBottom = rect.bottom;
|
|
}
|
|
#endif
|
|
|
|
CDropMenuColumn *pColumn = (CDropMenuColumn *)m_pColumnArray[nColumn];
|
|
|
|
int nPosition = pColumn->GetLastItem();
|
|
|
|
CDropMenuItem *pLastItem = (CDropMenuItem*)m_pMenuItemArray[nPosition];
|
|
|
|
if(pLastItem == m_pOverflowMenuItem)
|
|
return pColumn->GetWidth();
|
|
|
|
int nHeight = pColumn->GetHeight();
|
|
CRect overflowRect;
|
|
CRect itemRect;
|
|
CDropMenuItem *pItem;
|
|
|
|
CSize overflowSize = MeasureItem(m_pOverflowMenuItem);
|
|
overflowSize.cx += pColumn->GetWidestImage();
|
|
|
|
while(nScreenTop + nHeight + overflowSize.cy > nScreenBottom)
|
|
{
|
|
pItem = (CDropMenuItem*)m_pMenuItemArray[nPosition];
|
|
pItem->GetMenuItemRect(&itemRect);
|
|
|
|
|
|
nHeight -= itemRect.Height();
|
|
nPosition--;
|
|
}
|
|
|
|
// add 1 since we've subtracted 1 away
|
|
pColumn->SetLastItem(nPosition + 1);
|
|
pColumn->SetHeight(nHeight + overflowSize.cy);
|
|
m_pOverflowMenuItem->SetColumn(nColumn);
|
|
if(overflowSize.cx > pColumn->GetWidth())
|
|
pColumn->SetWidth(overflowSize.cx);
|
|
m_pMenuItemArray.InsertAt(nPosition + 1, m_pOverflowMenuItem, 1);
|
|
itemRect.SetRect(nStartX, nHeight, nStartX + pColumn->GetWidth(), nHeight + overflowSize.cy);
|
|
m_pOverflowMenuItem->SetMenuItemRect(itemRect);
|
|
return (nStartX + pColumn->GetWidth());
|
|
|
|
}
|
|
|
|
void CDropMenu::CalculateItemDimensions(void)
|
|
{
|
|
|
|
int numItems = m_pMenuItemArray.GetSize();
|
|
|
|
int nScreenTop = 0;
|
|
int nScreenBottom = GetSystemMetrics(SM_CYFULLSCREEN);
|
|
#ifdef XP_WIN32
|
|
RECT rect;
|
|
if(SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rect,0))
|
|
{
|
|
nScreenTop = rect.top;
|
|
nScreenBottom = rect.bottom;
|
|
}
|
|
#endif
|
|
|
|
int nNumCols = 0;
|
|
int nColumnHeight = nScreenBottom + 1;
|
|
int nColumnWidth = 0;
|
|
CSize textSize, unselectedBitmapSize, selectedBitmapSize, itemSize;
|
|
CDropMenuColumn *pColumn = NULL;
|
|
int nMaxBitmapSize = 0, nMaxTextSize = 0;
|
|
|
|
int nCount = m_pColumnArray.GetSize();
|
|
|
|
//make sure column array is empty
|
|
for(int j = 0 ; j < nCount; j++)
|
|
delete (CDropMenuColumn*)m_pColumnArray[j];
|
|
|
|
m_pColumnArray.RemoveAll();
|
|
|
|
for(int i=0; i<numItems; i++)
|
|
{
|
|
CDropMenuItem *item = (CDropMenuItem*)m_pMenuItemArray[i];
|
|
|
|
CalculateOneItemsDimensions(item);
|
|
|
|
textSize = item->GetTextSize();
|
|
selectedBitmapSize = item->GetSelectedBitmapSize();
|
|
unselectedBitmapSize = item->GetUnselectedBitmapSize();
|
|
itemSize = MeasureItem(item);
|
|
|
|
if(nScreenTop + nColumnHeight + itemSize.cy > nScreenBottom)
|
|
{
|
|
pColumn = new CDropMenuColumn;
|
|
pColumn->SetHasSubMenu(FALSE);
|
|
pColumn->SetFirstItem(i);
|
|
|
|
m_pColumnArray.Add(pColumn);
|
|
nColumnHeight = nColumnWidth = 0;
|
|
nMaxBitmapSize = 0, nMaxTextSize = 0;
|
|
nNumCols++;
|
|
}
|
|
|
|
item->SetColumn(nNumCols - 1);
|
|
pColumn->SetLastItem(i);
|
|
|
|
if(unselectedBitmapSize.cx > nMaxBitmapSize)
|
|
nMaxBitmapSize = unselectedBitmapSize.cx;
|
|
|
|
if(selectedBitmapSize.cx > nMaxBitmapSize)
|
|
nMaxBitmapSize= selectedBitmapSize.cx;
|
|
|
|
if(textSize.cx > nMaxTextSize)
|
|
nMaxTextSize = textSize.cx;
|
|
|
|
if(item->IsSubMenu())
|
|
pColumn->SetHasSubMenu(TRUE);
|
|
|
|
nColumnHeight += itemSize.cy;
|
|
if(m_bShowFeedback)
|
|
nColumnHeight += SPACE_BETWEEN_ITEMS;
|
|
|
|
pColumn->SetHeight(nColumnHeight);
|
|
|
|
pColumn->SetWidth(nMaxBitmapSize + nMaxTextSize + ( nIMG_SPACE * 3));
|
|
pColumn->SetWidestImage(nMaxBitmapSize);
|
|
if(item == m_pOverflowMenuItem)
|
|
return;
|
|
}
|
|
|
|
if(m_pOverflowMenuItem != NULL)
|
|
CalculateOneItemsDimensions(m_pOverflowMenuItem);
|
|
|
|
}
|
|
|
|
void CDropMenu::CalculateOneItemsDimensions(CDropMenuItem* item)
|
|
{
|
|
CSize unselectedBitmapSize, selectedBitmapSize, textSize;
|
|
CString text;
|
|
|
|
if(!item->IsSeparator())
|
|
{
|
|
unselectedBitmapSize = MeasureBitmap(item->GetUnselectedBitmap());
|
|
item->SetUnselectedBitmapSize(unselectedBitmapSize);
|
|
|
|
selectedBitmapSize = MeasureBitmap(item->GetSelectedBitmap());
|
|
item->SetSelectedBitmapSize(selectedBitmapSize);
|
|
|
|
if(item->IsSubMenu())
|
|
{
|
|
m_bHasSubMenu = TRUE;
|
|
}
|
|
|
|
|
|
text = item->GetText();
|
|
|
|
textSize = MeasureText(text);
|
|
|
|
|
|
item->SetTextSize(textSize);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* CTreeMenu::MeasureBitmap
|
|
*
|
|
* PARAMETERS:
|
|
* pBitmap: The bitmap to measure
|
|
*
|
|
* RETURNS:
|
|
* The size of the bitmap
|
|
*
|
|
* DESCRIPTION:
|
|
* Given a bitmap, this returns its dimensions
|
|
*
|
|
****************************************************************************/
|
|
|
|
CSize CDropMenu::MeasureBitmap(HBITMAP hBitmap)
|
|
{
|
|
|
|
CSize size;
|
|
|
|
if (hBitmap != NULL)
|
|
{
|
|
BITMAP bmp;
|
|
GetObject(hBitmap, sizeof(bmp), &bmp);
|
|
|
|
size.cx = bmp.bmWidth;
|
|
size.cy = bmp.bmHeight;
|
|
}
|
|
else
|
|
size.cx = size.cy = 0;
|
|
|
|
return size;
|
|
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* CTreeMenu::MeasureText
|
|
*
|
|
* PARAMETERS:
|
|
* text: The CString text to be measured
|
|
*
|
|
* RETURNS:
|
|
* Returns the size of the text in the current font
|
|
*
|
|
* DESCRIPTION:
|
|
* Given a CString this returns the dimensions of that text
|
|
*
|
|
****************************************************************************/
|
|
|
|
CSize CDropMenu::MeasureText(CString text)
|
|
{
|
|
|
|
HFONT hMenuFont;
|
|
|
|
#if defined(WIN32)
|
|
NONCLIENTMETRICS ncm;
|
|
ncm.cbSize = sizeof(NONCLIENTMETRICS);
|
|
if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0))
|
|
{
|
|
hMenuFont = theApp.CreateAppFont( ncm.lfMenuFont );
|
|
}
|
|
else
|
|
{
|
|
hMenuFont = (HFONT)::GetStockObject(SYSTEM_FONT);
|
|
}
|
|
#else // Win16
|
|
hMenuFont = (HFONT)::GetStockObject(SYSTEM_FONT);
|
|
#endif // WIN32
|
|
|
|
HDC hDC = ::GetDC(m_hWnd);
|
|
|
|
HFONT hOldFont = (HFONT) ::SelectObject(hDC, hMenuFont);
|
|
CSize sizeTxt = ::GetTabbedTextExtent(hDC, (LPCSTR)text, strlen(text), 0, NULL);
|
|
::SelectObject(hDC, hOldFont);
|
|
|
|
#if defined(WIN32)
|
|
if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0))
|
|
{
|
|
theApp.ReleaseAppFont(hMenuFont);
|
|
}
|
|
#endif
|
|
|
|
|
|
::ReleaseDC(m_hWnd, hDC);
|
|
|
|
return sizeTxt;
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* CTreeMenu::MeasureItem
|
|
*
|
|
* PARAMETERS:
|
|
* lpMI - pointer to LPMEASUREITEMSTRUCT
|
|
*
|
|
* RETURNS:
|
|
* void
|
|
*
|
|
* DESCRIPTION:
|
|
* We must override this function to inform the system of our menu
|
|
* item dimensions, since we're owner draw style.
|
|
*
|
|
****************************************************************************/
|
|
//menu item and end of accelerator
|
|
|
|
CSize CDropMenu::MeasureItem(CDropMenuItem *pItem)
|
|
{
|
|
ASSERT(pItem != NULL);
|
|
|
|
CSize size;
|
|
|
|
if(pItem->IsSeparator())
|
|
{
|
|
size.cx = 0;
|
|
size.cy = SEPARATOR_SPACE * 2 + SEPARATOR_HEIGHT;
|
|
}
|
|
else
|
|
{
|
|
// First, get all of the dimensions
|
|
CSize unselectedSizeImg=pItem->GetUnselectedBitmapSize();
|
|
CSize selectedSizeImg = pItem->GetSelectedBitmapSize();
|
|
CSize sizeText=pItem->GetTextSize();
|
|
|
|
size.cx = sizeText.cx + (nIMG_SPACE * 2);
|
|
|
|
int maxImageHeight = max(unselectedSizeImg.cy, selectedSizeImg.cy);
|
|
|
|
size.cy = max(maxImageHeight, sizeText.cy) + 4;
|
|
}
|
|
return size;
|
|
|
|
}
|
|
|
|
void CDropMenu::ChangeSelection(CPoint point)
|
|
{
|
|
if(m_bShowing)
|
|
{
|
|
MenuSelectionType eSelType;
|
|
int nSelection = FindSelection(point, eSelType);
|
|
|
|
eSelType = m_bShowFeedback ? eSelType : eNONE;
|
|
|
|
if(m_nSelectedItem != nSelection || m_eSelectedItemSelType != eSelType)
|
|
{
|
|
SelectMenuItem(m_nSelectedItem, FALSE, TRUE, m_eSelectedItemSelType);
|
|
SelectMenuItem(nSelection, TRUE, TRUE, eSelType);
|
|
}
|
|
}
|
|
}
|
|
|
|
int CDropMenu::FindSelection(CPoint point, MenuSelectionType &eSelType)
|
|
{
|
|
|
|
eSelType = eNONE;
|
|
int nNumColumns = m_pColumnArray.GetSize();
|
|
CRect colRect;
|
|
CDropMenuColumn *pColumn;
|
|
int nStartX = MENU_BORDER_SIZE;
|
|
int nColumnWidth;
|
|
|
|
for(int i = 0; i < nNumColumns; i++)
|
|
{
|
|
|
|
pColumn = (CDropMenuColumn*)m_pColumnArray[i];
|
|
nColumnWidth = pColumn->GetWidth();
|
|
|
|
colRect.SetRect(nStartX, 0, nStartX + nColumnWidth, pColumn->GetHeight());
|
|
|
|
if(colRect.PtInRect(point))
|
|
{
|
|
|
|
return (FindSelectionInColumn(pColumn, point, eSelType));
|
|
}
|
|
else
|
|
{
|
|
nStartX += nColumnWidth + SEPARATOR_WIDTH;
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int CDropMenu::FindSelectionInColumn(CDropMenuColumn *pColumn, CPoint point, MenuSelectionType &eSelType)
|
|
{
|
|
|
|
int y = MENU_BORDER_SIZE;
|
|
|
|
if(point.y >=0 && point.y <= MENU_BORDER_SIZE)
|
|
return 0;
|
|
|
|
int nFeedbackHeight = m_bShowFeedback ? SPACE_BETWEEN_ITEMS : 0;
|
|
CDropMenuItem *item;
|
|
int nFirstItem = pColumn->GetFirstItem();
|
|
int nLastItem = pColumn->GetLastItem();
|
|
|
|
for(int i = nFirstItem; i <= nLastItem; i++)
|
|
{
|
|
item = (CDropMenuItem*)m_pMenuItemArray[i];
|
|
|
|
CRect rect;
|
|
|
|
item->GetMenuItemRect(rect);
|
|
|
|
if( point.y >= y && point.y < y + rect.Height() + nFeedbackHeight)
|
|
{
|
|
if(item->GetShowFeedback())
|
|
eSelType = FindSelectionType(item, point.y - y, rect.Height() + nFeedbackHeight);
|
|
return i;
|
|
}
|
|
|
|
y += rect.Height() + nFeedbackHeight;
|
|
}
|
|
|
|
//if we're in the border between the bottom and the last menu item
|
|
if(point.y >= y && point.y <= y + 2*MENU_BORDER_SIZE)
|
|
{
|
|
if(item->GetShowFeedback())
|
|
eSelType = eBELOW;
|
|
return i - 1;
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
MenuSelectionType CDropMenu::FindSelectionType(CDropMenuItem *pItem, int y, int nHeight)
|
|
{
|
|
if(pItem->IsSubMenu())
|
|
{
|
|
if (y >= 0 && y <= nHeight/4.0)
|
|
return eABOVE;
|
|
else if (y <= 3.0*nHeight/4.0)
|
|
return eON;
|
|
else return eBELOW;
|
|
}
|
|
else
|
|
{
|
|
if(y >= 0 && y <= nHeight / 2.0)
|
|
return eABOVE;
|
|
else
|
|
return eBELOW;
|
|
}
|
|
}
|
|
|
|
void CDropMenu::SelectMenuItem(int nItemIndex, BOOL bIsSelected, BOOL bHandleSubmenus, MenuSelectionType eSelType)
|
|
{
|
|
|
|
RECT rcClient;
|
|
|
|
GetClientRect(&rcClient);
|
|
|
|
if(nItemIndex != -1)
|
|
{
|
|
CDropMenuItem *item = (CDropMenuItem*)m_pMenuItemArray[nItemIndex];
|
|
|
|
InvalidateMenuItemRect(item);
|
|
|
|
|
|
if(!bIsSelected)
|
|
{
|
|
|
|
m_pShowingSubmenu = NULL;
|
|
|
|
m_nSelectedItem = -1;
|
|
m_eSelectedItemSelType = eNONE;
|
|
|
|
if(bHandleSubmenus && item->IsSubMenu() && !item->IsEmpty() && item->GetSubMenu()->m_bShowing)
|
|
{
|
|
if(m_pUnselectedItem == NULL)
|
|
{
|
|
item->GetSubMenu()->m_bShowing = FALSE;
|
|
m_pUnselectedItem = item;
|
|
m_nUnselectTimer = SetTimer(IDT_SUBMENU_OFF ,SUBMENU_DELAY_OFF_MS, NULL);
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
m_nSelectedItem = nItemIndex;
|
|
m_eSelectedItemSelType = eSelType;
|
|
if(m_nSelectTimer != 0)
|
|
{
|
|
KillTimer(m_nSelectTimer);
|
|
}
|
|
|
|
if(bHandleSubmenus && item->IsSubMenu() && !item->IsEmpty() && (eSelType == eON || eSelType == eNONE))
|
|
{
|
|
m_pShowingSubmenu = item->GetSubMenu();
|
|
m_pSelectedItem = item;
|
|
m_pSelectedItem->GetSubMenu()->m_bAboutToShow = TRUE;
|
|
m_nSelectTimer = SetTimer(IDT_SUBMENU_ON, SUBMENU_DELAY_ON_MS, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CDropMenu::NoSubmenusShowing(void)
|
|
{
|
|
CWnd *child = GetWindow(GW_CHILD);
|
|
|
|
if(child != NULL)
|
|
{
|
|
while(child != NULL)
|
|
{
|
|
if(child->IsWindowVisible())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
child = GetWindow(GW_HWNDNEXT);
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CDropMenu *CDropMenu::GetMenuParent(void)
|
|
{
|
|
|
|
return m_pMenuParent;
|
|
}
|
|
|
|
BOOL CDropMenu::IsDescendant(CWnd *pDescendant)
|
|
{
|
|
CDropMenu *pSubmenu = m_pShowingSubmenu;
|
|
|
|
while(pSubmenu != NULL)
|
|
{
|
|
if(pSubmenu == pDescendant)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
pSubmenu = pSubmenu->m_pShowingSubmenu;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CDropMenu::IsAncestor(CWnd *pAncestor)
|
|
{
|
|
|
|
CDropMenu *pMenu = this;
|
|
|
|
while(pMenu->m_pParent == pMenu->m_pMenuParent)
|
|
{
|
|
if(pMenu->m_pMenuParent == pAncestor)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
pMenu = pMenu->m_pMenuParent;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//Sees if the hwnd is either this menu, an ancestor or a submenu
|
|
BOOL CDropMenu::IsShowingMenu(HWND hwnd)
|
|
{
|
|
|
|
if(hwnd == m_hWnd)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
CDropMenu *menu = m_pMenuParent;
|
|
|
|
while(menu != NULL)
|
|
{
|
|
if(hwnd == menu->m_hWnd)
|
|
{
|
|
return TRUE;
|
|
}
|
|
menu=menu->m_pMenuParent;
|
|
}
|
|
|
|
menu = m_pShowingSubmenu;
|
|
|
|
while(menu !=NULL)
|
|
{
|
|
if(hwnd == menu->m_hWnd)
|
|
{
|
|
return TRUE;
|
|
}
|
|
menu = menu->m_pShowingSubmenu;
|
|
}
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void CDropMenu::DropMenuTrackDropMenu(CDropMenu *pParent, int x, int y, BOOL bDragging, CDropMenuDropTarget *pDropTarget,
|
|
BOOL bShowFeedback, int oppX, int oppY)
|
|
{
|
|
m_pMenuParent = pParent;
|
|
|
|
pParent->m_pShowingSubmenu = this;
|
|
|
|
TrackDropMenu(pParent, x, y, bDragging, pDropTarget, bShowFeedback, oppX, oppY);
|
|
}
|
|
|
|
int CDropMenu::FindCommand(UINT nCommand)
|
|
{
|
|
|
|
int nCount = m_pMenuItemArray.GetSize();
|
|
|
|
for(int i = 0; i < nCount; i++)
|
|
{
|
|
CDropMenuItem * pItem = (CDropMenuItem*)m_pMenuItemArray[i];
|
|
if(!pItem->IsSeparator())
|
|
{
|
|
if(pItem->GetCommand() == nCommand)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
CPoint CDropMenu::FindStartPoint(int x, int y, CSize size, int oppX, int oppY)
|
|
{
|
|
|
|
int nScreenLeft = 0;
|
|
int nScreenRight = GetSystemMetrics(SM_CXFULLSCREEN);
|
|
int nScreenTop = 0;
|
|
int nScreenBottom = GetSystemMetrics(SM_CYFULLSCREEN);
|
|
#ifdef XP_WIN32
|
|
RECT rect;
|
|
if(SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rect,0))
|
|
{
|
|
nScreenLeft = rect.left;
|
|
nScreenRight = rect.right;
|
|
nScreenTop = rect.top;
|
|
nScreenBottom = rect.bottom;
|
|
}
|
|
#endif
|
|
|
|
|
|
if(oppX == -1)
|
|
{
|
|
CRect parentRect;
|
|
m_pParent->GetWindowRect(&parentRect);
|
|
|
|
oppX = m_bRight ? parentRect.left : parentRect.right;
|
|
}
|
|
|
|
int nRoomToRight = nScreenRight - (m_bRight ? x : oppX);
|
|
int nRoomToLeft = (m_bRight ? oppX : x) - nScreenLeft;
|
|
|
|
// if we are opening to the right we need to make sure we don't go off the right
|
|
// side of the screen.
|
|
if(m_bRight)
|
|
{
|
|
//if we will extend past the right
|
|
if(x + size.cx > nScreenRight)
|
|
{
|
|
// if we can fit to the left
|
|
if(oppX - size.cx > nScreenLeft)
|
|
{
|
|
if(m_pMenuParent != NULL)
|
|
{
|
|
x = oppX - size.cx;
|
|
//if it's not the top level menu we want it to overlap its parent
|
|
x -= 2;
|
|
}
|
|
else
|
|
{
|
|
x = oppX - size.cx;
|
|
}
|
|
|
|
m_bRight = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//see where we have more space
|
|
if(nRoomToRight >= nRoomToLeft)
|
|
x = nScreenRight - size.cx;
|
|
else
|
|
{
|
|
x = nScreenLeft;
|
|
m_bRight = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else if(m_pMenuParent != NULL)
|
|
{
|
|
// if we are a submenu we want to overlap our parent
|
|
x -= 5;
|
|
}
|
|
}
|
|
// if we are opening to the left we need to make sure we don't go off the left
|
|
// side of the screen
|
|
else
|
|
{
|
|
//if we will extend past the left
|
|
if(x - size.cx < nScreenLeft)
|
|
{
|
|
// if we can fit to the right
|
|
if(oppX + size.cx < nScreenRight)
|
|
{
|
|
x = oppX;
|
|
//if it's not the top level menu we want it to overlap its parent
|
|
if(m_pMenuParent != NULL)
|
|
{
|
|
x -= 5;
|
|
}
|
|
m_bRight = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if(nRoomToRight >= nRoomToLeft)
|
|
{
|
|
x = nScreenRight - size.cx;
|
|
m_bRight = TRUE;
|
|
}
|
|
else
|
|
x = nScreenLeft;
|
|
}
|
|
}
|
|
else if(m_pMenuParent != NULL)
|
|
{
|
|
x -= size.cx;
|
|
// if we are a submenu we want to overlap our parent
|
|
x -= 2;
|
|
}
|
|
}
|
|
|
|
if(y + size.cy > nScreenBottom)
|
|
{
|
|
y -= ((y + size.cy) - nScreenBottom);
|
|
|
|
}
|
|
|
|
return CPoint(x, y);
|
|
}
|
|
|
|
void CDropMenu::HandleUpArrow(void)
|
|
{
|
|
int nSelection;
|
|
|
|
// need to deal with separators
|
|
if(m_nSelectedItem == NOSELECTION || m_nSelectedItem == 0)
|
|
{
|
|
nSelection = GetMenuItemCount() - 1;
|
|
}
|
|
else
|
|
{
|
|
nSelection = m_nSelectedItem - 1;
|
|
}
|
|
|
|
while(((CDropMenuItem *)m_pMenuItemArray[nSelection])->IsSeparator())
|
|
{
|
|
nSelection = (nSelection == 0) ? GetMenuItemCount() - 1 : nSelection - 1;
|
|
}
|
|
|
|
SelectMenuItem(m_nSelectedItem, FALSE, FALSE, eNONE);
|
|
SelectMenuItem(nSelection, TRUE, FALSE, eNONE);
|
|
}
|
|
|
|
void CDropMenu::HandleDownArrow(void)
|
|
{
|
|
int nSelection;
|
|
int nNumItems = GetMenuItemCount() - 1;
|
|
|
|
// need to deal with separators
|
|
if(m_nSelectedItem == NOSELECTION || m_nSelectedItem == nNumItems)
|
|
{
|
|
nSelection = 0;
|
|
}
|
|
else
|
|
{
|
|
nSelection = m_nSelectedItem + 1;
|
|
}
|
|
|
|
while(((CDropMenuItem *)m_pMenuItemArray[nSelection])->IsSeparator())
|
|
{
|
|
nSelection = (nSelection == nNumItems - 1) ? 0 : nSelection + 1;
|
|
}
|
|
|
|
SelectMenuItem(m_nSelectedItem, FALSE, FALSE, eNONE);
|
|
SelectMenuItem(nSelection, TRUE, FALSE, eNONE);
|
|
}
|
|
|
|
|
|
void CDropMenu::HandleLeftArrow(void)
|
|
{
|
|
|
|
if(m_pMenuParent != NULL)
|
|
{
|
|
m_bShowing = FALSE;
|
|
|
|
m_pMenuParent->m_bMouseUsed = FALSE;
|
|
ShowWindow(SW_HIDE);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void CDropMenu::HandleRightArrow(void)
|
|
{
|
|
if(m_nSelectedItem != NOSELECTION)
|
|
{
|
|
CDropMenuItem *pItem = (CDropMenuItem *)m_pMenuItemArray[m_nSelectedItem];
|
|
if(pItem->IsSubMenu())
|
|
{
|
|
m_pShowingSubmenu = pItem->GetSubMenu();
|
|
m_pShowingSubmenu->m_nSelectedItem = 0;
|
|
m_pShowingSubmenu->m_bMouseUsed = FALSE;
|
|
ShowSubmenu(pItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CDropMenu::HandleReturnKey(void)
|
|
{
|
|
if(m_nSelectedItem != NOSELECTION)
|
|
{
|
|
CDropMenuItem *pItem = (CDropMenuItem *)m_pMenuItemArray[m_nSelectedItem];
|
|
|
|
if(pItem->IsSubMenu())
|
|
{
|
|
HandleRightArrow();
|
|
}
|
|
else
|
|
{
|
|
#ifdef _WIN32
|
|
SendMessage(WM_COMMAND, MAKEWPARAM(pItem->GetCommand(), 0), 0);
|
|
#else
|
|
SendMessage(WM_COMMAND, (WPARAM) pItem->GetCommand(), MAKELPARAM( m_hWnd, 0 ));
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void CDropMenu::ShowSubmenu(CDropMenuItem *pItem)
|
|
{
|
|
|
|
CRect rcClient, rect;
|
|
|
|
GetClientRect(rcClient);
|
|
|
|
pItem->GetMenuItemRect(rect);
|
|
|
|
CDropMenuDropTarget *pDropTarget = GetDropMenuDropTarget(pItem->GetSubMenu());
|
|
ClientToScreen(rect);
|
|
|
|
m_pShowingSubmenu = pItem->GetSubMenu();
|
|
|
|
pItem->GetSubMenu()->SetSubmenuBitmaps(m_hSubmenuSelectedBitmap, m_hSubmenuUnselectedBitmap);
|
|
|
|
if(m_bRight)
|
|
{
|
|
pItem->GetSubMenu()->DropMenuTrackDropMenu(this, rect.right, rect.top - 2, m_bDragging, pDropTarget, m_bShowFeedback, rect.left);
|
|
}
|
|
else
|
|
{
|
|
pItem->GetSubMenu()->DropMenuTrackDropMenu(this, rect.left, rect.top - 2, m_bDragging, pDropTarget, m_bShowFeedback, rect.right);
|
|
}
|
|
|
|
pItem->GetSubMenu()->m_pParentMenuItem = pItem;
|
|
|
|
}
|
|
|
|
int CDropMenu::FindMenuItemPosition(CDropMenuItem* pMenuItem)
|
|
{
|
|
int nCount = m_pMenuItemArray.GetSize();
|
|
|
|
for(int i = 0; i < nCount; i++)
|
|
if(m_pMenuItemArray[i] == pMenuItem)
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
void CDropMenu::SetSubmenuBitmaps(HBITMAP hSelectedBitmap, HBITMAP hUnselectedBitmap)
|
|
{
|
|
|
|
m_hSubmenuUnselectedBitmap = hUnselectedBitmap;
|
|
m_hSubmenuSelectedBitmap = hSelectedBitmap;
|
|
|
|
}
|
|
|
|
void CDropMenu::InvalidateMenuItemRect(CDropMenuItem *pMenuItem)
|
|
{
|
|
|
|
CRect rcClient;
|
|
CRect rect;
|
|
|
|
GetClientRect(&rcClient);
|
|
|
|
pMenuItem->GetMenuItemRect(rect);
|
|
int nColumn = pMenuItem->GetColumn();
|
|
CDropMenuColumn *pColumn= (CDropMenuColumn*)m_pColumnArray[nColumn];
|
|
|
|
rect.right = rect.left + pColumn->GetWidth();
|
|
rect.top -= 2;
|
|
rect.bottom += 2;
|
|
InvalidateRect(rect, TRUE);
|
|
}
|
|
|
|
void CDropMenu::InvalidateMenuItemIconRect(CDropMenuItem *pMenuItem)
|
|
{
|
|
|
|
CRect rcClient;
|
|
CRect rect;
|
|
|
|
GetClientRect(&rcClient);
|
|
|
|
pMenuItem->GetMenuItemRect(rect);
|
|
int nColumn = pMenuItem->GetColumn();
|
|
CDropMenuColumn *pColumn= (CDropMenuColumn*)m_pColumnArray[nColumn];
|
|
|
|
rect.left += nIMG_SPACE;
|
|
rect.right = rect.left + 16;
|
|
|
|
InvalidateRect(rect, TRUE);
|
|
}
|
|
|
|
void CDropMenu::KeepMenuAroundIfClosing(void)
|
|
{
|
|
// if there is movement on this menu, then it is showing even
|
|
// if it's been told to go away before.
|
|
m_bShowing = TRUE;
|
|
if(m_pMenuParent)
|
|
{
|
|
CDropMenuItem *pSelectedItem = m_pMenuParent->m_nSelectedItem != -1 ? (CDropMenuItem*)m_pMenuParent->m_pMenuItemArray[m_pMenuParent->m_nSelectedItem] : NULL;
|
|
|
|
CDropMenu *pSubMenu = pSelectedItem && pSelectedItem->IsSubMenu() ? pSelectedItem->GetSubMenu() : NULL;
|
|
if((pSubMenu && pSubMenu != this) || !pSubMenu)
|
|
{
|
|
|
|
KillTimer(m_pMenuParent->m_nSelectTimer);
|
|
KillTimer(m_pMenuParent->m_nUnselectTimer);
|
|
m_pMenuParent->m_pUnselectedItem = NULL;
|
|
m_pMenuParent->m_nSelectTimer = 0;
|
|
m_pMenuParent->m_pShowingSubmenu = this;
|
|
|
|
//We need to make the menu item this belongs to the selected menu item.
|
|
int nPosition = m_pMenuParent->FindMenuItemPosition(m_pParentMenuItem);
|
|
|
|
if(nPosition != -1)
|
|
{
|
|
|
|
if(pSelectedItem)
|
|
{
|
|
m_pMenuParent->InvalidateMenuItemRect(pSelectedItem);
|
|
}
|
|
|
|
m_pMenuParent->m_nSelectedItem = nPosition;
|
|
m_pMenuParent->m_eSelectedItemSelType = eON;
|
|
m_pMenuParent->m_pSelectedItem = m_pParentMenuItem;
|
|
|
|
m_pMenuParent->InvalidateMenuItemRect(m_pParentMenuItem);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
CWnd *CDropMenu::GetTopLevelParent(void)
|
|
{
|
|
|
|
CDropMenu *pMenu = this;
|
|
|
|
while(pMenu->m_pMenuParent != NULL)
|
|
{
|
|
pMenu = pMenu->m_pMenuParent;
|
|
}
|
|
|
|
return pMenu->m_pParent;
|
|
}
|
|
|
|
void CDropMenu::LoadComplete(HT_Resource r)
|
|
{
|
|
// Need to invalidate the line that corresponds to this particular resource.
|
|
HT_Resource parent = HT_GetParent(r);
|
|
if (parent)
|
|
{
|
|
// The offset of this node from its direct parent determines the line that should be
|
|
// invalidated.
|
|
int childIndex = HT_GetNodeIndex(HT_GetView(r), r);
|
|
int parentIndex = HT_GetNodeIndex(HT_GetView(parent), parent);
|
|
|
|
if (parent == HT_TopNode(HT_GetView(r)))
|
|
parentIndex = -1;
|
|
|
|
// Need to count up from the parent index to the child index and only include nodes
|
|
// with indentation equal to the child index.
|
|
int indentation = HT_GetItemIndentation(r);
|
|
int offset = 0;
|
|
for (int i = parentIndex + 1; i < childIndex; i++)
|
|
{
|
|
int otherIndentation = HT_GetItemIndentation(HT_GetNthItem(HT_GetView(r), i));
|
|
if (otherIndentation == indentation)
|
|
offset++;
|
|
}
|
|
|
|
CDropMenuItem *item = (CDropMenuItem*)m_pMenuItemArray[offset];
|
|
InvalidateMenuItemIconRect(item);
|
|
}
|
|
}
|