Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Exile 1.8 - The Password Manager

, 7 Mar 2005
Yet another password manager.
exile_18_setup.zip
exile_1.8_setup.exe
exile_exe.zip
exile.exe
Exile.exe.manifest
icons.dll
md5.dll
mdx.dll
PwsInfo.dll
rc5.dll
exile_exe_staticmfc.zip
exile.exe
icons.dll
md5.dll
mdx.dll
rc5.dll
exile_src.zip
exile
Exile
Exile.exe.manifest
exile.dep
exile.dsp
exile.dsw
res
aboveimportant.ico
advanced.bmp
belowcritical.ico
belowinsignificant.ico
belownormal.ico
changeicon.bmp
cold.ico
collapsed.ico
critical.ico
editcategory.bmp
editelement.bmp
enterpassword.bmp
error.ico
exile.ico
expanded.ico
exporttoxml.bmp
find.ico
found.ico
important.ico
insertcategory.bmp
insertelement.bmp
insignificant.ico
md5hashgenerator.bmp
new.bmp
normal.ico
options.bmp
passwordgenerator.bmp
rsasecurity.bmp
rsasecurity.ico
search.cur
storageproperties.bmp
switch.bmp
unimportant.ico
veryimportant.ico
vssver.scc
Icons
res
icon1.ico
icon10.ico
icon11.ico
icon12.ico
icon13.ico
icon14.ico
icon15.ico
icon16.ico
icon17.ico
icon18.ico
icon19.ico
icon2.ico
icon20.ico
icon21.ico
icon22.ico
icon23.ico
icon24.ico
icon25.ico
icon26.ico
icon27.ico
icon28.ico
icon3.ico
icon4.ico
icon5.ico
icon6.ico
icon7.ico
icon8.ico
icon9.ico
md5
md5.dep
md5.dsp
mdx
pwsinfo
passwordstorageshellext.rgs
pwsinfo.def
pwsinfo.dep
pwsinfo.dsp
pwsinfo.dsw
PwsInfo.tlb
pwsinfops.def
pwsinfops.mk
rc5
rc5.dep
rc5.dsp
xml
exile_src_vs2003.zip
Exile.exe.manifest
Exile.dep
Exile.dsp
Exile.dsw
Exile.suo
msxml3.tlh
msxml3.tli
res
AboveImportant.ico
Advanced.bmp
BelowCritical.ico
BelowInsignificant.ico
BelowNormal.ico
ChangeIcon.bmp
Cold.ico
Critical.ico
EditCategory.bmp
EditElement.bmp
EnterPassword.bmp
Error.ico
Exile.ico
ExportToXML.bmp
Find.ico
Found.ico
Icon1.ico
Icon10.ico
Icon11.ico
Icon12.ico
Icon13.ico
Icon14.ico
icon15.ico
Icon16.ico
Icon17.ico
Icon18.ico
Icon19.ico
Icon2.ico
Icon20.ico
Icon21.ico
Icon22.ico
Icon23.ico
Icon24.ico
Icon25.ico
Icon26.ico
Icon27.ico
Icon28.ico
Icon3.ico
Icon4.ico
Icon5.ico
Icon6.ico
Icon7.ico
Icon8.ico
Icon9.ico
Important.ico
InsertCategory.bmp
InsertElement.bmp
Insignificant.ico
MD5HashGenerator.bmp
New.bmp
Normal.ico
Options.bmp
PasswordGenerator.bmp
RSASecurity.bmp
rsasecurity.ico
Search.cur
StorageProperties.bmp
Switch.bmp
Unimportant.ico
VeryImportant.ico
vssver.scc
MD5
MD5.dep
MD5.dsp
PwsInfo
PasswordStorageShellExt.rgs
PwsInfo.def
PwsInfo.dep
PwsInfo.dsp
PwsInfo.dsw
PwsInfo.tlb
PwsInfops.def
PwsInfops.mk
RC5
RC5.dep
RC5.dsp
// PropertyGrid.cpp : implementation file
//

#include "stdafx.h"
#include "PropertyGrid.h"
#include <Commctrl.h>
#include <algorithm>
#include <windowsx.h>
#include "resource.h"
#include "HotKey.h"

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

//using namespace MSXML2;
using namespace PropertyGrid;

/////////////////////////////////////////////////////////////////////////////
// CPropertyGrid

CPropertyGrid::CPropertyGrid()
{
	// Just a simple image list
	m_imgList.Create(16, 16, ILC_COLOR8 | ILC_MASK, 2, 1);
	m_imgList.Add((HICON)::LoadImage(::AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_COLLAPSED), IMAGE_ICON, 16, 16, 0));
	m_imgList.Add((HICON)::LoadImage(::AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_EXPANDED), IMAGE_ICON, 16, 16, 0));

	NONCLIENTMETRICS ncm = {0};
    ncm.cbSize = sizeof(ncm);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);

    // Fonts for category and subcategory (bold one) 
	// and for element
	LOGFONT lfBold = ncm.lfMessageFont;
    lfBold.lfWeight = FW_BOLD;

	m_hNormal = CreateFontIndirect(&(ncm.lfMessageFont));
	m_hBold = CreateFontIndirect(&lfBold);

	// Colors
	m_crCategory = RGB(222, 211, 206);
    m_crCategoryFont = RGB(132, 130, 132);
	m_crCategoryTopBorder = RGB(255, 251, 239);
    m_crSubcategory = RGB(222, 211, 206);
    m_crSubcategoryFont = RGB(0, 0, 0);
    m_crElement = RGB(255, 255, 255);
    m_crElementFont = RGB(132, 130, 132);
	m_crElementSelected = RGB(49, 109, 206);
	m_crElementSelectedFont = RGB(255, 255, 255);	

	// Cursors
	m_hArrow = ::LoadCursor(0, MAKEINTRESOURCE(IDC_ARROW));
	m_hSize = ::LoadCursor(0, MAKEINTRESOURCE(IDC_SIZEWE));

	InitializeGdiObjects();

	m_bSizing = FALSE;

	m_eiItem.pWindow = 0;

	//
	// Notification
	//

	m_pNotificationReciever = 0;
}

CPropertyGrid::~CPropertyGrid()
{
	UninitializeGdiObjects();

	// Fonts
	::DeleteObject(m_hNormal);
	::DeleteObject(m_hBold);	

	// Cursors
	::DestroyCursor(m_hArrow);
	::DestroyCursor(m_hSize);
}


BEGIN_MESSAGE_MAP(CPropertyGrid, CListCtrl)
	//{{AFX_MSG_MAP(CPropertyGrid)	
	ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)
	ON_NOTIFY_REFLECT(LVN_GETINFOTIP, OnGetinfotip)
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_SETCURSOR()
	ON_WM_LBUTTONUP()
	ON_WM_SIZE()
	ON_NOTIFY_REFLECT(NM_RETURN, OnReturn)
	ON_WM_VSCROLL()
	ON_WM_HSCROLL()
	ON_WM_ERASEBKGND()
	ON_WM_MEASUREITEM_REFLECT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPropertyGrid message handlers

void CPropertyGrid::PreSubclassWindow() 
{
	CListCtrl::PreSubclassWindow();

	CRect rcClient;
	GetClientRect(rcClient);

	// Modifying styles
	ModifyStyle(0, LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_OWNERDATA | LVS_OWNERDRAWFIXED);
	SetExtendedStyle(LVS_EX_INFOTIP);
	
	InsertColumn(0, 0, LVCFMT_LEFT, (rcClient.right - ::GetSystemMetrics(SM_CXHSCROLL)) / 2);
	InsertColumn(1, 0, LVCFMT_LEFT, (rcClient.right - ::GetSystemMetrics(SM_CXHSCROLL))/ 2);
	
	SetImageList(&m_imgList, LVSIL_SMALL);
	
	// See "Customizing a Control's Appearance Using Custom Draw" topic
	// in Platform SDK documentation
	::SendMessage(*this, CCM_SETVERSION, (WPARAM)(DWORD)5, 0);

	// Creating in-place things
	m_ctrlEdit.Create(WS_CHILD | WS_VISIBLE /*| WS_BORDER */| ES_AUTOHSCROLL, CRect(0, 0, 0, 0), 
		this, IDC_PROPERTYGRID_EDIT);
	SetWindowFont(m_ctrlEdit.GetSafeHwnd(), m_hNormal, TRUE);

	m_ctrlDateTime.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, IDC_PROPERTYGRID_DATETIME);
	SetWindowFont(m_ctrlDateTime.GetSafeHwnd(), m_hNormal, TRUE);

	m_ctrlCombo.Create(WS_CHILD | WS_VISIBLE | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST | WS_VSCROLL, 
		CRect(0, 0, 0, 0), this, IDC_PROPERTYGRID_COMBOBOX);
	m_ctrlCombo.SetItemHeight(0, 10);
	SetWindowFont(m_ctrlCombo.GetSafeHwnd(), m_hNormal, TRUE);

	m_ctrlHotKey.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, IDC_PROPERTYGRID_HOTKEY);
	SetWindowFont(m_ctrlHotKey.GetSafeHwnd(), m_hNormal, TRUE);

	GetClientRect(m_rcClient);
	m_nNameColumn = GetColumnWidth(0);
	m_nValueColumn = GetColumnWidth(1);

	SetWindowFont(*this, m_hNormal, TRUE);

	//SetWindowPos(0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE);
	GetClientRect(m_rcClient);

	SendMessage(WM_SIZE, 0, MAKELPARAM(m_rcClient.Width(), m_rcClient.Height()));
}

void CPropertyGrid::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) 
{
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
	LV_ITEM* pItem= &(pDispInfo)->item;
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

	if (pItem->mask & LVIF_TEXT)
	{
		switch(pItem->iSubItem)
		{
		case 0:
			if(GetItem(pItem->iItem, vci, lei))
			{
				// Element
				strcpy(pItem->pszText, lei->strName);
			} // if
			else
			{
				// Category
				strcpy(pItem->pszText, vci->strName);
			} // else
			break;
		case 1:
			if(GetItem(pItem->iItem, vci, lei))
			{
				// Element
				strcpy(pItem->pszText, lei->strValue);
			} // if
			break;
		default:
			break;
		} // switch
	} // if

	*pResult = 0;
}

int CPropertyGrid::GetExpandedCount()
{
	int n = 0;
	VCATEGORY::iterator vci = m_vCategories.begin();

	while(m_vCategories.end() != vci)
	{
		n += (vci->lFlags & CF_EXPANDED) ? (vci->lElements.size() + 1) : 1;
		++vci;
	} // while

	return n;
}

int CPropertyGrid::GetItem(int nItem, VCATEGORY::iterator& vci, LELEMENT::iterator& lei)
{
	vci = m_vCategories.begin();
	
	while(m_vCategories.end() != vci)
	{
		if(0 == nItem) // stopped on a category
		{
			return 0;
		} // if

		if(vci->lFlags & CF_EXPANDED)
		{
			if(vci->lElements.size() >= nItem)
			{
				lei = vci->lElements.begin();
				std::advance(lei, nItem - 1);
				return 1;
			} // if
			else
				nItem -= vci->lElements.size() + 1;
		} // if
		else
			--nItem;
		
		++vci;
	} // while

	return 0;
}

void CPropertyGrid::OnGetinfotip(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMLVGETINFOTIP *pLVGT = (NMLVGETINFOTIP*)pNMHDR;
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;
	CString strTip;

	if(GetItem(pLVGT->iItem, vci, lei))
	{
		// Element
		strTip = lei->strTip;
	} // if
	else
	{
		// Category
		strTip = vci->strTip;
	} // else

	// See NMLVGETINFOTIP description in Platform SDK documentation
	if(!pLVGT->dwFlags)
	{
#ifdef _UNICODE
		wcsncat(pLVGT->pszText, strTip, pLVGT->cchTextMax - wcslen(pLVGT->pszText));
#else
		strncat(pLVGT->pszText, strTip, pLVGT->cchTextMax - strlen(pLVGT->pszText));
#endif // _UNICODE
	} // if
	else
	{
#ifdef _UNICODE
		wcsncpy(pLVGT->pszText, strTip, pLVGT->cchTextMax);
#else
		strncpy(pLVGT->pszText, strTip, pLVGT->cchTextMax);
#endif // _UNICODE
	} // else

	*pResult = 0;
}

void CPropertyGrid::OnLButtonDown(UINT nFlags, CPoint point) 
{
	if(m_bSize)
	{
		SetCapture();
		m_bSizing = TRUE;
		return;
	} // if

	AcceptEdit();

	// Testing. If clicked on an icon (only!) expand or collapse category
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;
	UINT uFlags;

	int nItem = HitTest(point, &uFlags);

	if(LVHT_ONITEMICON & uFlags)
	{
		if(!GetItem(nItem, vci, lei)) // Category
		{
			if(vci->lFlags & CF_EXPANDED)
			{
				vci->lFlags &= ~CF_EXPANDED;
				vci->lFlags |= CF_COLLAPSED;	
			} // if
			else if(vci->lFlags & CF_COLLAPSED)
			{
				vci->lFlags &= ~CF_COLLAPSED;
				vci->lFlags |= CF_EXPANDED;
			} // else if

			if(m_pNotificationReciever)
			{
				if(m_pNotificationReciever->Ready())
					m_pNotificationReciever->CategorySelected(vci->strName, vci->strTip);
			} // if

			SetItemCount(GetExpandedCount());
		} // if
		else // Element
		{
			if(m_pNotificationReciever)
			{
				if(m_pNotificationReciever->Ready())
					m_pNotificationReciever->ElementSelected(lei->strName, lei->strTip);
			} // if
		} // else
	} // if		

	// Testing subitem
	LVHITTESTINFO hti;
	hti.pt = point;
	
	if(-1 != SubItemHitTest(&hti))
	{
		if(GetItem(hti.iItem, vci, lei) && (1 == hti.iSubItem)) // Element
		{
			BeginEdit(lei, hti.iItem);
		} // if
	} // if
	
	CListCtrl::OnLButtonDown(nFlags, point);
}

void CPropertyGrid::OnMouseMove(UINT nFlags, CPoint point) 
{
	// Need to set a sizing cursor when required
	if(!m_bSizing)
	{
		m_bSize = Between(point.x, GetColumnWidth(0), 3);
	} // if
	else
	{
		SetRedraw(FALSE);

		int nWidth = GetColumnWidth(0) + GetColumnWidth(1);

		if((point.x > 50) && (point.x < nWidth - 50))
		{
			SetColumnWidth(0, m_nNameColumn = point.x);
			SetColumnWidth(1, m_nValueColumn = (nWidth - point.x));
		} // if

		SetRedraw();
	} // else
	
	CListCtrl::OnMouseMove(nFlags, point);
}

BOOL CPropertyGrid::Between(int nValue, int nSample, int nDelta)
{
	return ((nValue >= nSample - nDelta) && (nValue <= nSample + nDelta));
}

BOOL CPropertyGrid::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{	
	//return CListCtrl::OnSetCursor(pWnd, nHitTest, message);
	return (0 != SetCursor(m_bSize ? m_hSize : m_hArrow));
}

void CPropertyGrid::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if(m_bSizing)
	{
		ReleaseCapture();
		m_bSizing = FALSE;
	} // if

	// If we're not editing anything
	if(!m_eiItem.pWindow)
		CListCtrl::OnLButtonUp(nFlags, point);
}

void CPropertyGrid::OnSize(UINT nType, int cx, int cy) 
{
	// Retain current ratio
	AcceptEdit();

	int nWidth = GetColumnWidth(0) + GetColumnWidth(1);
	
	double dCol0 = double(GetColumnWidth(0)) / double(nWidth);
	double dCol1 = double(GetColumnWidth(1)) / double(nWidth);

	CListCtrl::OnSize(nType, cx, cy);

	SetRedraw(FALSE);

	SetColumnWidth(0, m_nNameColumn = int(dCol0 * cx));
	SetColumnWidth(1, m_nValueColumn = int(dCol1 * cx));

	GetClientRect(m_rcClient);

	TRACE("Sizing\n");

	SetRedraw();

}

BOOL CPropertyGrid::CancelEdit()
{
	if(m_eiItem.pWindow)
	{
		VCATEGORY::iterator vci;
		LELEMENT::iterator lei;

		if(GetItem(m_eiItem.nItem, vci, lei))
		{
			lei->strValue = m_eiItem.strPrevious;
		} // if

		m_eiItem.pWindow->ShowWindow(SW_HIDE);
		m_eiItem.pWindow = 0;

		Invalidate();

		return TRUE;
	} // if

	Invalidate();

	return FALSE;
}

BOOL CPropertyGrid::AcceptEdit()
{
	if(m_eiItem.pWindow)
	{
		VCATEGORY::iterator vci;
		LELEMENT::iterator lei;		
		
		if(GetItem(m_eiItem.nItem, vci, lei))
		{
			// Special case for CHotKeyCtrl
			CHotKeyCtrl *pctrlHotKey;
			CComboBox *pctrlCombo;
			if(pctrlHotKey = dynamic_cast<CHotKeyCtrl *>(m_eiItem.pWindow))
			{
				m_eiItem.pWindow->SetFocus();
				lei->wHotKey = pctrlHotKey->GetHotKey();
				lei->strValue = GetModifiersString(MapModifiers(HIBYTE(lei->wHotKey))) + TCHAR(LOBYTE(lei->wHotKey));
			} // if
			else if(pctrlCombo = dynamic_cast<CComboBox *>(m_eiItem.pWindow))
			{
				if(CB_ERR != pctrlCombo->GetCurSel())
					lei->lValue = pctrlCombo->GetItemData(pctrlCombo->GetCurSel());
				else
					lei->lValue = -1;

				m_eiItem.pWindow->GetWindowText(lei->strValue);
			} // else if
			else
			{
				m_eiItem.pWindow->GetWindowText(lei->strValue);
			} // else
		} // if

		m_eiItem.pWindow->ShowWindow(SW_HIDE);
		m_eiItem.pWindow = 0;

		Invalidate();

		return TRUE;
	} // if

	Invalidate();

	return FALSE;
}

BOOL CPropertyGrid::BeginEdit(LELEMENT::iterator lei, int nItem)
{
	CRect rc;
	GetSubItemRect(nItem, 1, LVIR_BOUNDS, rc);

	if(lei->lFlags & EF_EDITBOX)
	{
		rc.left += VALUE_TEXT_LEFT_INDENT - 3;
		rc.top += VALUE_TEXT_TOP_INDENT;

		m_ctrlEdit.MoveWindow(rc);
		m_ctrlEdit.ShowWindow(SW_SHOW);
		
		m_ctrlEdit.SetWindowText(lei->strValue);
		m_ctrlEdit.SetSel(0, -1);

		m_eiItem.nItem = nItem;
		m_eiItem.pWindow = &m_ctrlEdit;
		m_eiItem.strPrevious = lei->strValue;

		m_ctrlEdit.SetFocus();
		
		return TRUE;
	} // if
	else if(lei->lFlags & EF_DATETIME)
	{
		rc.InflateRect(1, 1, 1, 1);
		m_ctrlDateTime.MoveWindow(rc);
		m_ctrlDateTime.ShowWindow(SW_SHOW);
		
		m_ctrlDateTime.SetFocus();

		m_eiItem.nItem = nItem;
		m_eiItem.pWindow = &m_ctrlDateTime;
		m_eiItem.strPrevious = lei->strValue;		

		return TRUE;
	} // if else
	else if(lei->lFlags & EF_COMBOBOX)
	{
		rc.left += VALUE_TEXT_LEFT_INDENT - 3;
		rc.top -= 1;
		rc.bottom += COMBOBOX_DROPDOWN;

		InitComboBox(*lei);

		m_ctrlCombo.MoveWindow(rc);
		m_ctrlCombo.SetWindowPos(this, 0, 0, m_nValueColumn, 14, SWP_NOMOVE | SWP_NOOWNERZORDER);
		m_ctrlCombo.ShowWindow(SW_SHOW);
		
		m_ctrlCombo.SelectString(-1, lei->strValue);		

		m_eiItem.nItem = nItem;
		m_eiItem.pWindow = &m_ctrlCombo;
		m_eiItem.strPrevious = lei->strValue;

		m_ctrlCombo.SetFocus();
		
		return TRUE;
	} // else if
	else if(lei->lFlags & EF_HOTKEY)
	{
		m_ctrlHotKey.MoveWindow(rc);
		m_ctrlHotKey.ShowWindow(SW_SHOW);
		m_ctrlHotKey.SetHotKey(LOBYTE(lei->wHotKey), HIBYTE(lei->wHotKey));
		
		m_ctrlHotKey.SetFocus();

		m_eiItem.nItem = nItem;
		m_eiItem.pWindow = &m_ctrlHotKey;
		m_eiItem.strPrevious = lei->strValue;		
	} // else if

	return FALSE;
}

void CPropertyGrid::OnReturn(NMHDR* pNMHDR, LRESULT* pResult) 
{
	AcceptEdit();
	*pResult = 0;
}

void CPropertyGrid::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	AcceptEdit();
	CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CPropertyGrid::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	AcceptEdit();
	CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CPropertyGrid::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
	if(lpDIS->CtlType != ODT_LISTVIEW)
		return;

	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

/*	//
	// Creating memory dc to speed up drawing
	//	
	HDC hDC;
	HBITMAP hBitmap, hBitmapOld;

	//
	// Coordinate transformations
	//
	POINT ptTL = { lpDIS->rcItem.left, lpDIS->rcItem.top };
	POINT ptBR = { lpDIS->rcItem.right, lpDIS->rcItem.bottom };

	//::LPtoDP(lpDIS->hDC, &ptTL, 1);
	//::LPtoDP(lpDIS->hDC, &ptBR, 1);
	
	int nW = ptBR.x - ptTL.x;
	int nH = ptBR.y - ptTL.y;

	//
	// Creating
	//
	VERIFY((hDC = ::CreateCompatibleDC(lpDIS->hDC)) != NULL);
	//VERIFY((hBitmap = ::CreateCompatibleBitmap(lpDIS->hDC, nW, nH)) != NULL);
	VERIFY((hBitmap = ::CreateBitmap(nW, nH, 1, 16, 0)) != NULL);
	VERIFY((hBitmapOld = (HBITMAP)::SelectObject(hDC, hBitmap)) != NULL);*/

	//
	// Draw what we need
	//	
	if(GetItem(lpDIS->itemID, vci, lei))
	{
		DrawElementSection(lpDIS->hDC, lpDIS->rcItem, lei->strName, lei->strValue, 
			lpDIS->itemID == GetNextItem(-1, LVNI_SELECTED), lei->strValue != lei->strInitialValue,
			lei->lFlags & EF_READONLY);
	} // if
	else
	{
		DrawCategorySection(lpDIS->hDC, lpDIS->rcItem, vci->strName, 
			lpDIS->itemID == GetNextItem(-1, LVNI_SELECTED), vci->lFlags & CF_EXPANDED);
	} // else

	//
	// Transfer
	//
/*	RECT rc = lpDIS->rcItem;
	TRACE("%d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);

	::BitBlt(lpDIS->hDC, 0, 0, nW, nH, hDC, rc.left, rc.top, SRCCOPY);

	::SelectObject(hDC, hBitmapOld);
	::DeleteObject(hBitmap);
	::DeleteDC(hDC);

	::ReleaseDC(*this, hDC);*/
}

BOOL CPropertyGrid::OnEraseBkgnd(CDC* pDC) 
{
	//UNUSED_ALWAYS(pDC);
	
	//return CListCtrl::OnEraseBkgnd(pDC);
	pDC->FillSolidRect(m_rcClient, m_crElement);

	return TRUE;
}

CString CPropertyGrid::CompactString(HDC hDC, const CString &rString, int cx)
{
	CString str(rString);
	SIZE sz;
	
	// If it already fits
	::GetTextExtentPoint32(hDC, str, str.GetLength(), &sz);
	
	if(sz.cx <= cx)
		return str;

	for(unsigned n = str.GetLength(); n >= 0; --n)
	{
		::GetTextExtentPoint32(hDC, str.Left(n) + _T("..."), CString(str.Left(n) + _T("...")).GetLength(), &sz);

		if(sz.cx <= cx)
			return str.Left(n) + _T("...");
	} // for
	
	return _T("");
}

void CPropertyGrid::DrawCategorySection(HDC hDC, const CRect &rcRect, const CString& strText, BOOL bSelected,
										BOOL bExpanded)
{
	HPEN hPen = ::CreatePen(PS_SOLID, 1, m_crCategory);

	HBRUSH hBrushOld = (HBRUSH)::SelectObject(hDC, m_brCategory);
	HPEN hPenOld = (HPEN)::SelectObject(hDC, hPen);
	HFONT hFontOld = (HFONT)::SelectObject(hDC, m_hBold);

	COLORREF crText = ::SetTextColor(hDC, m_crCategoryFont);

	// Client-rectangle wide
	::Rectangle(hDC, rcRect.left, rcRect.top, rcRect.right, rcRect.bottom);

	// Draw a line above the section
	::SelectObject(hDC, hPenOld);
	hPen = ::CreatePen(PS_SOLID, 1, m_crCategoryTopBorder);

	::SelectObject(hDC, hPen);

	::MoveToEx(hDC, rcRect.left, rcRect.top, 0);
	::LineTo(hDC, rcRect.right, rcRect.top);

	::SelectObject(hDC, hPenOld);	

	// Space for icon
	CString str = CompactString(hDC, strText, m_nNameColumn + m_nValueColumn - CATEGORY_TEXT_LEFT_INDENT);

	::TextOut(hDC, rcRect.left + CATEGORY_TEXT_LEFT_INDENT, rcRect.top + CATEGORY_TEXT_TOP_INDENT, 
		str, str.GetLength());

	// Selected
	if(bSelected)
	{
		DrawFocusRect(hDC, rcRect, strText);
	} // if

	// Icon itself
	::DrawIconEx(hDC, rcRect.left, rcRect.top, 
		m_imgList.ExtractIcon(bExpanded ? 1 : 0), 16, 16, 0, 0, DI_NORMAL);

	::SelectObject(hDC, hBrushOld);
	::SelectObject(hDC, hPenOld);
	::SelectObject(hDC, hFontOld);	

	::DeleteObject(hPen);

	::SetTextColor(hDC, crText);
}

void CPropertyGrid::DrawElementSection(HDC hDC, const CRect &rcRect, const CString &strText, 
									   const CString &strValue, BOOL bSelected, BOOL bChanged, BOOL bReadOnly)
{
	// Element and Value
	HPEN hPen = ::CreatePen(PS_SOLID, 1, m_crCategory);

	HBRUSH hBrushOld = (HBRUSH)::SelectObject(hDC, m_brCategory);
	HPEN hPenOld = (HPEN)::SelectObject(hDC, hPen);
	HFONT hFontOld = (HFONT)::SelectObject(hDC, m_hNormal);

	// Rectangle to the right
	::Rectangle(hDC, rcRect.left, rcRect.top, rcRect.left + 16, rcRect.bottom);
	
	// Some general stuff
	CString strN = CompactString(hDC, strText, m_nNameColumn - ELEMENT_TEXT_LEFT_INDENT);
	CString strV = CompactString(hDC, strValue, m_nValueColumn - VALUE_TEXT_LEFT_INDENT);

	// This applies to Element only
	if(bSelected)
	{		
		COLORREF crTextOld = ::SetTextColor(hDC, m_crElementSelectedFont);

		HBRUSH hBrush = ::CreateSolidBrush(m_crElementSelected);
		HBRUSH hBrushOld = (HBRUSH)::SelectObject(hDC, hBrush);

		HPEN hPen = ::CreatePen(PS_SOLID, 1, m_crElementSelected);
		HPEN hPenOld = (HPEN)::SelectObject(hDC, hPen);

		// Selected
		::Rectangle(hDC, rcRect.left + BORDER_WIDTH, rcRect.top + 1, rcRect.left + m_nNameColumn, rcRect.bottom);

		::TextOut(hDC, rcRect.left + ELEMENT_TEXT_LEFT_INDENT, rcRect.top + ELEMENT_TEXT_TOP_INDENT,
			strN, strN.GetLength());

		::SelectObject(hDC, hBrushOld);
		::SelectObject(hDC, hPenOld);
		::SetTextColor(hDC, crTextOld);

		::DeleteObject(hBrush);
		::DeleteObject(hPen);
	} // if
	else
	{
		COLORREF crTextOld;
		HBRUSH hBrush, hBrushOld;
		HPEN hPen, hPenOld;

		if(bReadOnly)
		{
			crTextOld = ::SetTextColor(hDC, m_crCategoryFont);

			hBrush = ::CreateSolidBrush(m_crCategory);
			hBrushOld = (HBRUSH)::SelectObject(hDC, hBrush);

			hPen = ::CreatePen(PS_SOLID, 1, m_crCategory);
			hPenOld = (HPEN)::SelectObject(hDC, hPen);
		} // if
		else
		{
			crTextOld = ::SetTextColor(hDC, m_crElementFont);

			hBrush = ::CreateSolidBrush(m_crElement);
			hBrushOld = (HBRUSH)::SelectObject(hDC, hBrush);

			hPen = ::CreatePen(PS_SOLID, 1, m_crElement);
			hPenOld = (HPEN)::SelectObject(hDC, hPen);
		} // else

		// Not selected
		::Rectangle(hDC, rcRect.left + BORDER_WIDTH, rcRect.top + 1, rcRect.left + m_nNameColumn, rcRect.bottom);

		::TextOut(hDC, rcRect.left + ELEMENT_TEXT_LEFT_INDENT, rcRect.top + ELEMENT_TEXT_TOP_INDENT,
			strN, strN.GetLength());

		::SelectObject(hDC, hBrushOld);
		::SelectObject(hDC, hPenOld);
		::SetTextColor(hDC, crTextOld);

		::DeleteObject(hBrush);
		::DeleteObject(hPen);
	} // else

	{
		HBRUSH hBrush, hBrushOld;
		HPEN hPen, hPenOld;

		hBrush = ::CreateSolidBrush(m_crElement);
		hBrushOld = (HBRUSH)::SelectObject(hDC, hBrush);

		hPen = ::CreatePen(PS_SOLID, 1, m_crElement);
		hPenOld = (HPEN)::SelectObject(hDC, hPen);

		::Rectangle(hDC, rcRect.left + m_nNameColumn, rcRect.top + 1, rcRect.right, rcRect.bottom);
		
		::SelectObject(hDC, hBrushOld);
		::SelectObject(hDC, hPenOld);

		::DeleteObject(hBrush);
		::DeleteObject(hPen);
	}
	
	// And this applies only to values
	if(bChanged)
	{
		HFONT hFontOld = (HFONT)::SelectObject(hDC, m_hBold);

		::TextOut(hDC, rcRect.left + m_nNameColumn + VALUE_TEXT_LEFT_INDENT, rcRect.top + VALUE_TEXT_TOP_INDENT, 
			strV, strV.GetLength());

		::SelectObject(hDC, hFontOld);

	} // if
	else
	{
		::TextOut(hDC, rcRect.left + m_nNameColumn + VALUE_TEXT_LEFT_INDENT, rcRect.top + VALUE_TEXT_TOP_INDENT, 
			strV, strV.GetLength());
	} // else	

	::SelectObject(hDC, hBrushOld);
	::SelectObject(hDC, hPenOld);

	::DeleteObject(hPen);

	DrawElementGrid(hDC, rcRect);
}

void CPropertyGrid::DrawElementGrid(HDC hDC, const CRect &rcRect)
{
	HPEN hPen = ::CreatePen(PS_SOLID, 1, m_crCategory);
	HPEN hPenOld = (HPEN)::SelectObject(hDC, hPen);

	// Horizontal
	::MoveToEx(hDC, rcRect.left, rcRect.bottom, 0);
	::LineTo(hDC, rcRect.right, rcRect.bottom);

	// Vertical
	::MoveToEx(hDC, rcRect.left + m_nNameColumn, rcRect.top, 0);
	::LineTo(hDC, rcRect.left + m_nNameColumn, rcRect.bottom);

	::SelectObject(hDC, hPenOld);

	::DeleteObject(hPen);
}

BOOL CPropertyGrid::LoadPropertyGridContents(MSXML2::IXMLDOMElementPtr pXML)
{
	if(_bstr_t(_T("propertyGrid")) != pXML->nodeName)
		return FALSE;

	// Iterate through all children
	MSXML2::IXMLDOMNodeListPtr pList;
	MSXML2::IXMLDOMNode *pNode;	

	if(0 == (pList = pXML->childNodes))
		return FALSE;

	long lNodes;
	lNodes = pList->length;

	for(long l = 0; l < lNodes; ++l)
	{
		if(FAILED(pList->get_item(l, &pNode)))
			return FALSE;

		LoadCategory(pNode);

		pNode->Release();
	} // for

	SetItemCount(GetExpandedCount());

	return TRUE;
}

void CPropertyGrid::LoadCategory(MSXML2::IXMLDOMNodePtr pNode)
{
	if(_bstr_t(_T("category")) != pNode->nodeName)
		return;

	MSXML2::IXMLDOMNamedNodeMapPtr pMap;
	MSXML2::IXMLDOMNodePtr pAttribute;

	CATEGORY ctg;

	if(0 == (pMap = pNode->attributes))
		return;
	
	LoadCategory(pMap, ctg);

	MSXML2::IXMLDOMNodeListPtr pNodes;

	if(0 == (pNodes = pNode->childNodes))
		return;

	LoadElements(pNodes, ctg);

	m_vCategories.push_back(ctg);
}

void CPropertyGrid::LoadCategory(MSXML2::IXMLDOMNamedNodeMapPtr pMap, CATEGORY &ctg)
{
	// General stuff
	ctg.lFlags = CF_EXPANDED;
	ctg.lID = 0;

	MSXML2::IXMLDOMNodePtr pAttribute;

	// Category name
	if(0 == (pAttribute = pMap->getNamedItem(_T("categoryName"))))
		return;	

	_variant_t vt;
	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return;

	ctg.strName = (LPCTSTR)_bstr_t(vt);

	// Category description
	if(0 == (pAttribute = pMap->getNamedItem(_T("categoryDescription"))))
		return;	
	
	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return;

	ctg.strTip = (LPCTSTR)_bstr_t(vt);
}

void CPropertyGrid::LoadElements(MSXML2::IXMLDOMNodeListPtr pNodes, CATEGORY &ctg)
{
	ELEMENT elm;

	MSXML2::IXMLDOMNode *pNode;

	long lNodes;
	lNodes = pNodes->length;

	for(long l = 0; l < lNodes; ++l)
	{
		if(FAILED(pNodes->get_item(l, &pNode)))
			return;

		if(LoadElement(pNode, elm))
			ctg.lElements.push_back(elm);

		pNode->Release();		
	} // for
}

BOOL CPropertyGrid::LoadElement(MSXML2::IXMLDOMNodePtr pNode, ELEMENT &elm)
{
	if(_bstr_t(_T("element")) != pNode->nodeName)
		return FALSE;

	MSXML2::IXMLDOMNodePtr pAttribute;
	MSXML2::IXMLDOMNamedNodeMapPtr pMap;

	if(0 == (pMap = pNode->attributes))
		return FALSE;

	// Element name
	if(0 == (pAttribute = pMap->getNamedItem(_T("elementName"))))
		return FALSE;	

	_variant_t vt;
	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return FALSE;

	elm.strName = (LPCTSTR)_bstr_t(vt);

	// Element description
	if(0 == (pAttribute = pMap->getNamedItem(_T("elementDescription"))))
		return FALSE;	
	
	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return FALSE;

	elm.strTip = (LPCTSTR)_bstr_t(vt);

	// Element type
	if(0 == (pAttribute = pMap->getNamedItem(_T("elementType"))))
		return FALSE;	
	
	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return FALSE;

	CString str = (LPCTSTR)_bstr_t(vt);

	if(_T("EditBox") == str)
	{
		elm.lFlags = EF_EDITBOX;
	} // if
	else if(_T("ComboBox") == str)
	{
		elm.lFlags = EF_COMBOBOX;

		if(!LoadComboBoxEntries(pNode->childNodes, elm))
			return FALSE;
	} // else if
	else if(_T("ReadOnly") == str)
	{
		elm.lFlags = EF_READONLY;
	} // else if
	else if(_T("HotKey") == str)
	{
		elm.lFlags = EF_HOTKEY;
	} // else if
	else
		return FALSE;

	// Element ID
	if(0 == (pAttribute = pMap->getNamedItem(_T("elementID"))))
		return FALSE; 	
	
	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return FALSE;

	elm.lID = (long)vt;

	return TRUE;
}

CString CPropertyGrid::GetElementValue(long lID)
{
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

	for(vci = m_vCategories.begin(); m_vCategories.end() != vci; ++vci)
	{
		for(lei = vci->lElements.begin(); vci->lElements.end() != lei; ++lei)
		{
			if(lID == lei->lID)
				return lei->strValue;
		} // for
	} // for

	return _T("");
}

BOOL CPropertyGrid::SetEditBoxLong(long lID, long lValue)
{
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;
	CString strText;

	strText.Format("%d", lValue);

	for(vci = m_vCategories.begin(); m_vCategories.end() != vci; ++vci)
	{
		for(lei = vci->lElements.begin(); vci->lElements.end() != lei; ++lei)
		{
			if((lID == lei->lID) && (lei->lFlags & EF_EDITBOX))
			{
				lei->strValue = lei->strInitialValue = strText;
				return TRUE;
			} // if
		} // for
	} // for

	return FALSE;
}

long CPropertyGrid::GetEditBoxLong(long lID)
{
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

	for(vci = m_vCategories.begin(); m_vCategories.end() != vci; ++vci)
	{
		for(lei = vci->lElements.begin(); vci->lElements.end() != lei; ++lei)
		{
			if((lID == lei->lID) && (lei->lFlags & EF_EDITBOX))
			{
				CString strValue = lei->strValue;
				return _ttol(strValue);
			} // if
		} // for
	} // for

	return -1;
}

long CPropertyGrid::GetComboBoxItemData(long lID)
{
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

	for(vci = m_vCategories.begin(); m_vCategories.end() != vci; ++vci)
	{
		for(lei = vci->lElements.begin(); vci->lElements.end() != lei; ++lei)
		{
			if((lID == lei->lID) && (lei->lFlags & EF_COMBOBOX))
				return lei->lValue;
		} // for
	} // for

	return -1;
}


BOOL CPropertyGrid::SetElementValue(long lID, const CString &strValue)
{
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

	for(vci = m_vCategories.begin(); m_vCategories.end() != vci; ++vci)
	{
		for(lei = vci->lElements.begin(); vci->lElements.end() != lei; ++lei)
		{
			if(lID == lei->lID)
			{
				lei->strValue = lei->strInitialValue = strValue;
				return TRUE;
			}
		} // for
	} // for

	return FALSE;
}

BOOL CPropertyGrid::SetComboBoxValue(long lID, long lValue)
{
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

	for(vci = m_vCategories.begin(); m_vCategories.end() != vci; ++vci)
	{
		for(lei = vci->lElements.begin(); vci->lElements.end() != lei; ++lei)
		{
			if((lID == lei->lID) && (lei->lFlags & EF_COMBOBOX))
			{
				lei->strValue = lei->strInitialValue = FindComboBoxString(*lei, lValue);
				lei->lValue = lValue;
				return TRUE;
			}
		} // for
	} // for

	return FALSE;
}

BOOL CPropertyGrid::SetHotKey(long lID, WORD wHotKey)
{
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

	for(vci = m_vCategories.begin(); m_vCategories.end() != vci; ++vci)
	{
		for(lei = vci->lElements.begin(); vci->lElements.end() != lei; ++lei)
		{
			if((lID == lei->lID) && (lei->lFlags & EF_HOTKEY))
			{
				lei->wHotKey = wHotKey;
				lei->strValue = lei->strInitialValue = GetModifiersString(MapModifiers(HIBYTE(wHotKey))) + 
					TCHAR(LOBYTE(wHotKey));
				return TRUE;
			}
		} // for
	} // for

	return FALSE;
}

WORD CPropertyGrid::GetHotKey(long lID)
{
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

	for(vci = m_vCategories.begin(); m_vCategories.end() != vci; ++vci)
	{
		for(lei = vci->lElements.begin(); vci->lElements.end() != lei; ++lei)
		{
			if((lID == lei->lID) && (lei->lFlags & EF_HOTKEY))
				return lei->wHotKey;
		} // for
	} // for

	return 0;
}

BOOL CPropertyGrid::LoadComboBoxEntries(MSXML2::IXMLDOMNodeListPtr pNodes, ELEMENT &elm)
{
	MSXML2::IXMLDOMNode *pNode;

	long lNodes = pNodes->length;
	elm.vComboBox.clear();

	for(long l = 0; l < lNodes; ++l)
	{
		if(FAILED(pNodes->get_item(l, &pNode)))
			return FALSE;

		if(!LoadComboBoxString(pNode, elm))
			return FALSE;

		pNode->Release();		
	} // for

	return TRUE;
}

BOOL CPropertyGrid::LoadComboBoxString(MSXML2::IXMLDOMNodePtr pNode, ELEMENT &elm)
{
	if(_bstr_t(_T("comboBox")) != pNode->nodeName)
		return FALSE;

	MSXML2::IXMLDOMNodePtr pAttribute;
	MSXML2::IXMLDOMNamedNodeMapPtr pMap;

	if(0 == (pMap = pNode->attributes))
		return FALSE;

	COMBOBOXDATA cbd;

	// Combo Box String
	if(0 == (pAttribute = pMap->getNamedItem(_T("comboBoxEntry"))))
		return FALSE;	

	_variant_t vt;
	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return FALSE;

	cbd.strData = (LPCTSTR)_bstr_t(vt);

	// Combo Box Item Data
	if(0 == (pAttribute = pMap->getNamedItem(_T("comboBoxItemData"))))
		return FALSE;	

	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return FALSE;

	cbd.lItemData = (long)vt;

	elm.vComboBox.push_back(cbd);

	return TRUE;
}

void CPropertyGrid::InitComboBox(ELEMENT &elm)
{
	m_ctrlCombo.ResetContent();

	VCOMBOBOXDATA::iterator vcsi;
	int n = 0;

	for(vcsi = elm.vComboBox.begin(); elm.vComboBox.end() != vcsi; ++vcsi, ++n)
	{
		m_ctrlCombo.AddString(vcsi->strData);
		m_ctrlCombo.SetItemData(n, vcsi->lItemData);
	} // for
}

void CPropertyGrid::DrawFocusRect(HDC hDC, const CRect &rcRect, const CString &strText)
{
	SIZE szText;
	::GetTextExtentPoint32(hDC, strText, strText.GetLength(), &szText);

	TRACE("   Drawing %d\n", szText.cx);

	//
	// Adding a few pixels to the left and to the right
	//
	RECT rcFocus = { CATEGORY_TEXT_LEFT_INDENT - CATEGORY_FOCUS_RECT_LEFT_INDENT, 
		rcRect.top + CATEGORY_FOCUS_RECT_TOP_SPACING, 
		szText.cx + CATEGORY_TEXT_LEFT_INDENT + CATEGORY_FOCUS_RECT_RIGHT_INDENT, 
		rcRect.bottom - CATEGORY_FOCUS_RECT_BOTTOM_SPACING };

	::DrawFocusRect(hDC, &rcFocus);
}

BOOL CPropertyGrid::LoadPropertyGridTheme(MSXML2::IXMLDOMElementPtr pXML)
{
	if(_bstr_t(_T("propertyGridTheme")) != pXML->nodeName)
		return FALSE;

	// Iterate through all children
	MSXML2::IXMLDOMNodeListPtr pList;
	MSXML2::IXMLDOMNode *pNode;	

	if(0 == (pList = pXML->childNodes))
		return FALSE;

	long lNodes;
	lNodes = pList->length;

	for(long l = 0; l < lNodes; ++l)
	{
		if(FAILED(pList->get_item(l, &pNode)))
			return FALSE;

		LoadThemeElement(pNode);

		pNode->Release();
	} // for

	UninitializeGdiObjects();
	InitializeGdiObjects();

	Invalidate();

	return TRUE;
}

void CPropertyGrid::LoadThemeElement(MSXML2::IXMLDOMNodePtr pNode)
{
	if(_bstr_t(_T("categorySection")) == pNode->nodeName) // Category Section
		m_crCategory = LoadThemeColor(pNode);
	else if(_bstr_t(_T("categoryFont")) == pNode->nodeName) // Category Font
		m_crCategoryFont = LoadThemeColor(pNode);
	else if(_bstr_t(_T("categoryTopBorder")) == pNode->nodeName) // Category Top Border
		m_crCategoryTopBorder = LoadThemeColor(pNode);
	else if(_bstr_t(_T("subcategorySection")) == pNode->nodeName) // Subcategory Section
		m_crSubcategory = LoadThemeColor(pNode); 
	else if(_bstr_t(_T("subcategoryFont")) == pNode->nodeName) // Subcategory Font
		m_crSubcategoryFont = LoadThemeColor(pNode);
	else if(_bstr_t(_T("elementSection")) == pNode->nodeName) // Element Section
		m_crElement = LoadThemeColor(pNode);
	else if(_bstr_t(_T("elementFont")) == pNode->nodeName) // Element Font
		m_crElementFont = LoadThemeColor(pNode);
	else if(_bstr_t(_T("elementSectionSelected")) == pNode->nodeName) // Element Section Selected
		m_crElementSelected = LoadThemeColor(pNode);
	else if(_bstr_t(_T("elementFontSelected")) == pNode->nodeName) // Element Font Selected
		m_crElementSelectedFont = LoadThemeColor(pNode);
}

COLORREF CPropertyGrid::LoadThemeColor(MSXML2::IXMLDOMNodePtr pNode)
{
	BYTE nRed = 0, nGreen = 0, nBlue = 0;

	//
	// Loading RGB color
	//
	MSXML2::IXMLDOMNodePtr pAttribute;
	MSXML2::IXMLDOMNamedNodeMapPtr pMap;

	if(0 == (pMap = pNode->attributes))
		return RGB(nRed, nGreen, nBlue);

	nRed = LoadThemeColorComponent(pMap, _T("colorRed"));
	nGreen = LoadThemeColorComponent(pMap, _T("colorGreen"));
	nBlue = LoadThemeColorComponent(pMap, _T("colorBlue"));

	return RGB(nRed, nGreen, nBlue);
}

BYTE CPropertyGrid::LoadThemeColorComponent(MSXML2::IXMLDOMNamedNodeMapPtr pMap, LPCTSTR pszAttribute)
{
	//
	// Loading Color component
	//
	
	MSXML2::IXMLDOMNodePtr pAttribute;
	
	if(0 == (pAttribute = pMap->getNamedItem(pszAttribute)))
		return 0;	

	_variant_t vt;
	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return 0;

	return (BYTE)(long)vt;
}

void CPropertyGrid::InitializeGdiObjects()
{
	// Brushes
	m_brCategory = ::CreateSolidBrush(m_crCategory);
	m_brSubcategory = ::CreateSolidBrush(m_crSubcategory);
	m_brElement = ::CreateSolidBrush(m_crElement);

	// Pens
	m_pnDot = ::CreatePen(PS_DOT, 1, RGB(0, 0, 0));
	m_pnLines = ::CreatePen(PS_SOLID, 2, m_crCategory);
}

void CPropertyGrid::UninitializeGdiObjects()
{
	// Brushes
	::DeleteObject(m_brCategory);
	::DeleteObject(m_brElement);
	::DeleteObject(m_brSubcategory);

	// Pens
	::DeleteObject(m_pnDot);
	::DeleteObject(m_pnLines);
}

void CPropertyGrid::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	TRACE("%d %d %d %d\n", lpMeasureItemStruct->CtlType, ODT_COMBOBOX, ODT_LISTBOX, ODT_MENU);
	//lpMeasureItemStruct->itemHeight = 40;
}

CString CPropertyGrid::FindComboBoxString(ELEMENT &elm, long lValue)
{
	VCOMBOBOXDATA::iterator vcbi = elm.vComboBox.begin();

	for( ; elm.vComboBox.end() != vcbi; ++vcbi)
	{
		if(lValue == vcbi->lItemData)
			return vcbi->strData;
	} // for

	return _T("");
}

BOOL CPropertyGrid::PreTranslateMessage(MSG* pMsg) 
{
	TRACE("Message %d\n", pMsg->message);
	if(WM_KEYUP == pMsg->message)
	{	
	VCATEGORY::iterator vci;
	LELEMENT::iterator lei;

	if((VK_UP == pMsg->wParam) || (VK_DOWN == pMsg->wParam))
	{
		int nItem = GetNextItem(-1, LVNI_SELECTED);
		
		if(-1 != nItem)
		{
			if(!GetItem(nItem, vci, lei)) // Category
			{
				if(m_pNotificationReciever)
				{
					if(m_pNotificationReciever->Ready())
						m_pNotificationReciever->CategorySelected(vci->strName, vci->strTip);
				} // if	
			} // if
			else // Element
			{
				if(m_pNotificationReciever)
				{
					if(m_pNotificationReciever->Ready())
						m_pNotificationReciever->ElementSelected(lei->strName, lei->strTip);
				} // if
			} // else
		} // if		
		return 1;
	} // if	
	} // if

	return CListCtrl::PreTranslateMessage(pMsg);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

AntonGogolev
Web Developer
Russian Federation Russian Federation
I'll think about it later on...

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150123.1 | Last Updated 7 Mar 2005
Article Copyright 2004 by AntonGogolev
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid