//////////////////////////////////////////////////////////////////////
//
// Разработчик: Алексей Фёдоров aka АЛьФ, mailto: alf@dorex.pro
//
//////////////////////////////////////////////////////////////////////
//
// FormExMenu.cpp: implementation of the CFormExMenu class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "addin.h"
#include "FormExMenu.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

extern CBkEndUI * pBkEndUI;
extern HINSTANCE hDllInstance;
static LONG hMeasureItemWndProc = 0;
static HFONT hFontG = NULL;

LRESULT CALLBACK MeasureItemWndProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
	if(nMessage == WM_MEASUREITEM)
	{
		CWnd* pParent = CWnd::FromHandle(hWnd);
		CClientDC dc(pParent);
		HFONT hFont = (HFONT)::SelectObject(dc.GetSafeHdc(), hFontG);

		if (hFont != 0) {
			LPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT) lParam;

			CString str = (LPCSTR)lpMeasureItemStruct->itemData;
			int cx = 0;
			int n = 1;
			int nn = 0;
			int nn1 = nn;
			while(TRUE)
			{
				nn1 = nn;
				nn = str.Find("\r\n", nn);
				if (nn < 0)	break;
				cx = max(cx, dc.GetTextExtent(str.Mid(nn1,nn - nn1)).cx);
				n++;
				nn++;
			}

			lpMeasureItemStruct->itemWidth	= 25 + max(cx, dc.GetTextExtent(str.Mid(nn1)).cx);

			lpMeasureItemStruct->itemHeight = dc.GetTextExtent(str).cy*n;
			lpMeasureItemStruct->itemHeight += 6;

			if (lpMeasureItemStruct->itemHeight < 3)
				lpMeasureItemStruct->itemHeight = 3;

			// Делаем поправку на сепаратор
			if(lpMeasureItemStruct->itemID == 0)
				lpMeasureItemStruct->itemHeight = 6 + 1;

			::SelectObject(dc.GetSafeHdc(), hFont);
		}
	}
	
	return ::CallWindowProc((WNDPROC)hMeasureItemWndProc,hWnd, nMessage, wParam, lParam);
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CFormExMenu,CMenu);

CFormExMenu::CFormExMenu(HFONT hFont):CMenu()
{
	InnerConstruct(hFont);
}

CFormExMenu::CFormExMenu():CMenu()
{
	InnerConstruct(NULL);
}

void CFormExMenu::InnerConstruct( HFONT hFont)
{
	m_hFont = hFont;
	m_pParent = NULL;
	m_bHasPictures = FALSE;
	m_crSelected = COLORREF(RGB(182, 189, 210));
	m_crSelectedBr = COLORREF(RGB(10, 36, 106));
	m_crSelectedFont = COLORREF(RGB(255, 255, 255));//GetSysColor(COLOR_BTNFACE);
	m_crBrush = GetSysColor(COLOR_BTNFACE);
	m_crFont = GetSysColor(COLOR_BTNTEXT);
}

CFormExMenu::PCFormExMenu CFormExMenu::Create(HFONT hFont, CWnd* pParent)
{
	CFormExMenu::PCFormExMenu Menu(new CFormExMenu(hFont));
	Menu->m_pParent = pParent;
	return Menu;
}

CFormExMenu::PCFormExMenu CFormExMenu::Create(HFONT hFont, PCFormExMenu pParentMenu)
{
	CFormExMenu::PCFormExMenu Menu;
	Menu = Create(hFont, pParentMenu->m_pParent);
	Menu->Copy(*pParentMenu);
	return Menu;
}

CFormExMenu::~CFormExMenu()
{
//Msg("CFormExMenu::~CFormExMenu");

// 	while(m_pSubMenu.GetSize())
// 	{
// 		//CFormExMenu* pSubMenu = m_pSubMenu.GetAt(0);
// 		//delete pSubMenu;
// 		m_pSubMenu.RemoveAt(0);
// 	}
	if((m_pParent != NULL) && (hMeasureItemWndProc != 0))
	{
		::SetWindowLong(m_pParent->GetSafeHwnd(),GWL_WNDPROC,hMeasureItemWndProc);
		hMeasureItemWndProc = NULL;
	}
	//m_Images.DeleteImageList(); // этот код и так выполняется в деструкторе CImageList!
}

void CFormExMenu::Init(CBLContext* pCont)
{
	int crSelected = -1;
	int crSelectedBr = -1;
	int crSelectedFont = -1;
	int crBrush = -1;
	int crFont = -1;
	if(pCont && pCont->IsKindOf(RUNTIME_CLASS(CValueListContext)))
	{
		CValueListContext* pValCont = (CValueListContext*)pCont;
		CPtrArray * pItems = (CPtrArray*)pValCont->GetPValueList();
		if(pItems)
		{
			int sz = pItems->GetSize();
			for(int i = 0; i < sz; i++)
			{
				CValueItem* pItem = (CValueItem*)pItems->GetAt(i);
				if(pItem)
				{
					CString s = pItem->m_text;

					if(s.CompareNoCase("ЦветФонаВыделения") == 0)
						crSelected = pItem->m_value.GetNumeric();
					else if(s.CompareNoCase("ЦветРамкиВыделения") == 0)
						crSelectedBr = pItem->m_value.GetNumeric();
					else if(s.CompareNoCase("ЦветШрифтаВыделения") == 0)
						crSelectedFont = pItem->m_value.GetNumeric();
					else if(s.CompareNoCase("ЦветФона") == 0)
						crBrush = pItem->m_value.GetNumeric();
					else if(s.CompareNoCase("ЦветШрифта") == 0)
						crFont = pItem->m_value.GetNumeric();

				}
			}
		}
	}

	m_bHasPictures = FALSE;

	if(m_pParent)
	{
		if(hMeasureItemWndProc == 0) hMeasureItemWndProc = ::GetWindowLong(m_pParent->GetSafeHwnd(),GWL_WNDPROC);
		::SetWindowLong(m_pParent->GetSafeHwnd(),GWL_WNDPROC,(LONG)MeasureItemWndProc);
		hFontG = m_hFont;
	}
	if(crSelected != -1)
		m_crSelected = (COLORREF)crSelected;
	if(crSelectedBr != -1)
		m_crSelectedBr = (COLORREF)crSelectedBr;
	if(crSelectedFont != -1)
		m_crSelectedFont = (COLORREF)crSelectedFont;
	if(crBrush != -1)
		m_crBrush = (COLORREF)crBrush;
	if(crFont != -1)
		m_crFont = (COLORREF)crFont;
}

void CFormExMenu::Init(CBLContext* pCont, CPictureHolder7* pPictureHolder7)
//int crSelected, int crSelectedBr, int crSelectedFont, int crBrush, int crFont, CPictureHolder7* pPictureHolder7)
{
	Init(pCont);
	if(pPictureHolder7)
	{
		CDC dc;
		CDC* DesktopDC = CWnd::GetDesktopWindow()->GetDC();
		if (dc.CreateCompatibleDC(DesktopDC))
		{
			CSize size = pPictureHolder7->GetSize();
			CBitmap bitmap;
			if (bitmap.CreateCompatibleBitmap(DesktopDC, size.cx, size.cy))
			{
				CBitmap* pOldbitmap = dc.SelectObject(&bitmap);
				CRect rect(CPoint(0,0), size);
				dc.FillSolidRect(0,0, size.cx, size.cy, RGB(0x00, 0x80, 0x80));
				pPictureHolder7->Render(dc, rect, 0, NULL);
				dc.SelectObject(pOldbitmap);
				if (m_Images.Create(16, 15, ILC_COLOR32|ILC_MASK, 2, 0))
					m_bHasPictures = m_Images.Add(&bitmap, RGB(0x00, 0x80, 0x80)) == 0;
			}
		}
		CWnd::GetDesktopWindow()->ReleaseDC(DesktopDC);
	}
}

BOOL CFormExMenu::AppendMenu(UINT nFlags, PCFormExMenu pSubMenu /*= NULL*/, LPCTSTR lpszNewItem /*= NULL*/)
{
	HMENU hMenu = NULL;
	if(pSubMenu)
	{
		//m_pSubMenu.Add(pSubMenu);
		m_SubMenuVector.push_back(pSubMenu);
		
		pSubMenu->Copy(*this);
		hMenu = pSubMenu->GetSafeHmenu();
	}
	return /*CMenu::*/::AppendMenu(m_hMenu, nFlags, (UINT)hMenu, lpszNewItem);
}

void CFormExMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	CString str = (LPCSTR)lpDrawItemStruct->itemData;
	CString strUP(str);
	strUP.TrimLeft();

    CRect RFull(lpDrawItemStruct->rcItem); // Ограничивающий пункт прямоугольник
	// Зона значка
	CRect RIcon(RFull.left,RFull.top,RFull.left+20,RFull.top+20);
	// зона текста
	CRect RText(RFull.left,RFull.top,RFull.right,RFull.bottom);
	if (m_bHasPictures || m_bHasCheck)
	{
		RText.left = RIcon.right;
	}

	// получаем контекст, на котором будем рисовать
	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	CFont* pOldFont = NULL;
	if(m_hFont)
	{
		CFont* pFont = CFont::FromHandle(m_hFont);
		pOldFont = pDC->SelectObject(pFont);
	}
	bool bSoftDisabled = false;
	if(strUP.Left(10).CompareNoCase("[DISABLED]") == 0)
	{
		strUP = strUP.Mid(10);
		str = str.Mid(10);
		bSoftDisabled = true;
	}


	pDC->FillSolidRect(&RFull, m_crBrush); //pDC->GetBkColor()); // фон
	pDC->SetTextColor(m_crFont);

	if(lpDrawItemStruct->itemID == 0) // если этот пункт - это Separator
	{
		CPen pen;
		pen.CreatePen(PS_SOLID, 1, m_crFont);
		CPen* pOldPen = pDC->SelectObject(&pen);

		// рисуем сепаратор
		CRect RSep(RFull.left+1,RFull.top+(RFull.bottom-RFull.top)/2 - 1,RFull.right-1,RFull.top+(RFull.bottom-RFull.top)/2 + 1);
		pDC->Draw3dRect(&RSep, GetSysColor(COLOR_BTNSHADOW), GetSysColor(COLOR_WINDOW));
		//pDC->MoveTo(RFull.left+5,  RFull.top+(RFull.bottom-RFull.top)/2);
		//pDC->LineTo(RFull.right, RFull.top+(RFull.bottom-RFull.top)/2);

		pDC->SelectObject(pOldPen);
		DeleteObject(pen);
	}

	else if ((lpDrawItemStruct->itemState & ODS_SELECTED) &&
			 (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) )
	{
		// Если пункт выделен - то рисуем выделение
		if (!(lpDrawItemStruct->itemState & ODS_GRAYED) && !bSoftDisabled) // проверка доступен ли пункт
		{
			pDC->SetTextColor(m_crSelectedFont);
			pDC->FillSolidRect(&RFull, m_crSelected); // фон
			shared_ptr<CBrush> br(new CBrush);
			br->CreateSolidBrush(m_crSelectedBr);
			pDC->FrameRect(&RFull, br.get()); // рамка
			//delete br;
		};
	};
	if ((lpDrawItemStruct->itemState & ODS_GRAYED) && (lpDrawItemStruct->itemID != 0)) // проверка доступен ли пункт
	{
		pDC->FillSolidRect(&RFull, GetSysColor(COLOR_INFOBK)); // фон
	}

	if(m_bHasPictures == TRUE && strUP.Left(6).CompareNoCase("[ICON:") == 0)
	{
		int n = strUP.Find("]");
		DWORD ico = 0;
		if(n > 6)
		{
			ico = (DWORD)atol(strUP.Mid(6, n - 6));
		}
		if((ico != 0) && (ico <= m_Images.GetImageCount()))
		{
			CPoint		ptBmp;
			ptBmp = CPoint(RIcon.left+1, 
							RIcon.top+1);

			if ((lpDrawItemStruct->itemState & ODS_GRAYED) || bSoftDisabled)
				m_Images.Draw(pDC, ico-1, ptBmp, ILD_BLEND50 /*ILD_TRANSPARENT*/);
			else
				m_Images.Draw(pDC, ico-1, ptBmp, ILD_NORMAL /*ILD_TRANSPARENT*/);
			str = strUP.Mid(n+1);
		}
	}
	else
	if(lpDrawItemStruct->itemState & ODS_CHECKED) // если пункт в состоянии checked
	{
		HBITMAP		hBmp;
		CBitmap*	pBmp;
		BITMAP		bmp;
		CSize		szBmp;
		CPoint		ptBmp;
		ZeroMemory(&bmp, sizeof(BITMAP));
		
		// Загружаем значёк checked
		hBmp = ::LoadBitmap(NULL, MAKEINTRESOURCE(32760));
		pBmp = CBitmap::FromHandle(hBmp);
		pBmp->GetBitmap(&bmp);
		szBmp = pBmp->GetBitmapDimension();
		//szBmp = CSize(bmp.bmWidth, bmp.bmHeight);
		ptBmp = CPoint(RIcon.left+1, 
						RIcon.top+1);
		// рисуем состояние
		pDC->DrawState(ptBmp, szBmp, hBmp, DSS_NORMAL|DSS_UNION);
		DeleteObject(hBmp);
	}

	// Устанавливаем цвет фона и границу надписи
	//pDC->SetBkColor(TextColor);
	RText.left += 5;
	RText.top += 3;
	RText.bottom -= 3;

	// если пункт недоступен - устанавливаем соответствующий цвет текста
	if ((lpDrawItemStruct->itemState & ODS_GRAYED) || bSoftDisabled)
	{
		pDC->SetTextColor(RGB(0xFF,0xFF,0xFF));
		RText.left++;
		RText.right++;
		pDC->DrawText(str, &RText, DT_EXPANDTABS|DT_LEFT|DT_VCENTER| DT_EDITCONTROL );
		pDC->SetBkMode(TRANSPARENT);
		pDC->SetTextColor(RGB(0x80,0x80,0x80)); //GetSysColor(COLOR_GRAYTEXT));
		RText.top--;
		RText.bottom--;
		RText.left--;
		RText.right--;
		pDC->DrawText(str, &RText, DT_EXPANDTABS|DT_LEFT|DT_VCENTER| DT_EDITCONTROL );
		pDC->SetBkMode(OPAQUE);
	}
	else // Рисуем текст пункта
		pDC->DrawText(str, &RText, DT_EXPANDTABS|DT_LEFT|DT_VCENTER| DT_EDITCONTROL );

	if(pOldFont)
	{
		pOldFont = pDC->SelectObject(pOldFont);
	}
}

void CFormExMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	if(m_pParent)
	{
		CClientDC dc(m_pParent);
		HFONT hFont = (HFONT)::SelectObject(dc.GetSafeHdc(), m_hFont);

		if (hFont != 0) {

			CString str = (LPCSTR)lpMeasureItemStruct->itemData;
			CString strUP(str);
			strUP.TrimLeft();
			int nWPlus = 5;
			if (m_bHasPictures || m_bHasCheck)
			{
				nWPlus = 25;
			}
			if(strUP.Left(10).CompareNoCase("[DISABLED]") == 0)
			{
				strUP = strUP.Mid(10);
				str = str.Mid(10);
			}
			if(m_bHasPictures == TRUE && strUP.Left(6).CompareNoCase("[ICON:") == 0)
			{
				int n = strUP.Find("]");
				DWORD ico = 0;
				if(n > 6)
					ico = (DWORD)atol(strUP.Mid(6, n - 6));

				if((ico != 0) && (ico <= m_Images.GetImageCount()))
					str = strUP.Mid(n+1);
			}
			int cx = 0;
			int n = 1;
			int nn = 0;
			int nn1 = nn;
			while(TRUE)
			{
				nn1 = nn;
				nn = str.Find("\r\n", nn);
				if (nn < 0)	break;
				cx = max(cx, dc.GetTextExtent(str.Mid(nn1,nn - nn1)).cx);
				n++;
				nn++;
			}

			lpMeasureItemStruct->itemWidth	= nWPlus + max(cx, dc.GetTextExtent(str.Mid(nn1)).cx);
//			lpMeasureItemStruct->itemWidth	= nWPlus + dc.GetTextExtent(str).cx;

			lpMeasureItemStruct->itemHeight = dc.GetTextExtent(str).cy*n;
			lpMeasureItemStruct->itemHeight += 6;

			if (lpMeasureItemStruct->itemHeight < 3)
				lpMeasureItemStruct->itemHeight = 3;

			// Делаем поправку на сепаратор
			if(lpMeasureItemStruct->itemID == 0)
				lpMeasureItemStruct->itemHeight = 6 + 1;

			::SelectObject(dc.GetSafeHdc(), hFont);
		}
	}
}

void CFormExMenu::Copy(const CFormExMenu& SourceMenu)
{
	m_bHasPictures = SourceMenu.m_bHasPictures;
	if(m_bHasPictures) 
		m_Images.Create(const_cast<CImageList*>(&SourceMenu.m_Images));
	m_crSelected = SourceMenu.m_crSelected;
	m_crSelectedBr = SourceMenu.m_crSelectedBr;
	m_crBrush = SourceMenu.m_crBrush;
	m_crSelectedFont = SourceMenu.m_crSelectedFont;
	m_crFont = SourceMenu.m_crFont;
}
