/* -*- 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"
#include "cxicon.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)
		{
			NSNavCenterImage* 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->CompletelyLoaded()) 
			{
				// Now we draw this bad boy.
				if (pImage->m_BadImage) 
				{		 
					// display broken icon.
					HDC tempDC = ::CreateCompatibleDC(hDC);
					HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC,  NSNavCenterImage::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::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;
}
