// XTPPropertyGrid.cpp : implementation of the CXTPPropertyGrid class.
//
// This file is a part of the XTREME PROPERTYGRID MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Resource.h"
#include "Common/Resource.h"

#include "Common/XTPResourceManager.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPImageManager.h"
#include "Common/XTPToolTipContext.h"
#include "Common/XTPMarkupRender.h"
#include "Common/XTPMaskEditT.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPColorManager.h"

#include "XTPPropertyGridDefines.h"
#include "XTPPropertyGridInplaceEdit.h"
#include "XTPPropertyGridInplaceButton.h"
#include "XTPPropertyGridInplaceList.h"
#include "XTPPropertyGridItem.h"
#include "XTPPropertyGridPaintManager.h"
#include "XTPPropertyGrid.h"
#include "XTPPropertyGridView.h"

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

const int SPLITTER_HEIGHT = 3;
const int TOOLBAR_HEIGHT = 25;

//////////////////////////////////////////////////////////////////////////
// CXTPPropertyGridUpdateContext

CXTPPropertyGridUpdateContext::CXTPPropertyGridUpdateContext()
{
	m_nSelected = 0;
	m_nTopIndex = 0;
	m_propertySort = xtpGridSortAlphabetical;


}

//////////////////////////////////////////////////////////////////////////
// CXTPPropertyGridVerb

CXTPPropertyGridVerb::CXTPPropertyGridVerb()
{
	m_nID = 0;
	m_nIndex = -1;
	m_pVerbs = 0;

}

//////////////////////////////////////////////////////////////////////////
// CXTPPropertyGridVerbs

CXTPPropertyGridVerbs::CXTPPropertyGridVerbs()
{
	m_pGrid = 0;


}

CXTPPropertyGridVerbs::~CXTPPropertyGridVerbs()
{
	for (int i = 0; i < m_arrVerbs.GetSize(); i++)
		m_arrVerbs[i]->InternalRelease();
}

void CXTPPropertyGridVerbs::RemoveAll()
{
	if (IsEmpty())
		return;

	for (int i = 0; i < m_arrVerbs.GetSize(); i++)
		m_arrVerbs[i]->InternalRelease();

	m_arrVerbs.RemoveAll();

	m_pGrid->OnVerbsChanged();
}

int CXTPPropertyGridVerbs::GetCount() const
{
	return (int)m_arrVerbs.GetSize();
}

void CXTPPropertyGridVerbs::Add(LPCTSTR strCaption, UINT nID)
{
	CXTPPropertyGridVerb* pVerb = new CXTPPropertyGridVerb();

	pVerb->m_nID = nID;
	pVerb->m_strCaption = strCaption;
	pVerb->m_pVerbs = this;
	pVerb->m_rcPart.SetRectEmpty();
	pVerb->m_ptClick = CPoint(0);

	pVerb->m_nIndex = (UINT)m_arrVerbs.Add(pVerb);

	m_pGrid->OnVerbsChanged();
}


/////////////////////////////////////////////////////////////////////////////
// CXTPPropertyGridToolBar

CXTPPropertyGridToolBar::CXTPPropertyGridToolBar()
{
	m_cxLeftBorder = m_cxRightBorder = m_cyBottomBorder = m_cyTopBorder = 0;
}

CXTPPropertyGridToolBar::~CXTPPropertyGridToolBar()
{
}

BEGIN_MESSAGE_MAP(CXTPPropertyGridToolBar, CToolBar)
	//{{AFX_MSG_MAP(CToolBar)
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_NCCALCSIZE()
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CXTPPropertyGridToolBar::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMLVCUSTOMDRAW* lpLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
	*pResult = CDRF_DODEFAULT;

	switch (lpLVCD->nmcd.dwDrawStage)
	{
	case CDDS_PREPAINT:
		CWnd* pGrid = GetParent();
		HBRUSH hBrush = (HBRUSH)pGrid->GetParent()->SendMessage(WM_CTLCOLORSTATIC,
			(WPARAM)lpLVCD->nmcd.hdc, (LPARAM)pGrid->m_hWnd);

		::FillRect(lpLVCD->nmcd.hdc, &lpLVCD->nmcd.rc, hBrush ? hBrush : GetSysColorBrush(COLOR_3DFACE));
		break;
	}
}


BOOL CXTPPropertyGridToolBar::OnEraseBkgnd(CDC*)
{
	return TRUE;
}

void CXTPPropertyGridToolBar::OnNcCalcSize(BOOL /*bCalcValidRects*/, NCCALCSIZE_PARAMS* /*lpncsp*/)
{
}

void CXTPPropertyGridToolBar::OnPaint()
{
	CPaintDC dc(this);

	CXTPClientRect rc(this);
	CXTPBufferDC memDC(dc, rc);
	memDC.FillSolidRect(rc, GetXtremeColor(COLOR_3DFACE));

	CToolBar::DefWindowProc(WM_PAINT, (WPARAM)memDC.m_hDC, 0);
}

void CXTPPropertyGridToolBar::OnUpdateCmdUI(CFrameWnd* /*pTarget*/, BOOL /*bDisableIfNoHndler*/)
{
}

BOOL CXTPPropertyGridToolBar::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	CXTPPropertyGrid* pGrid = (CXTPPropertyGrid*)GetParent();
	if (pGrid->GetToolTipContext())
	{
		pGrid->GetToolTipContext()->FilterToolTipMessage(this, message, wParam, lParam);
	}

	return CWnd::OnWndMsg(message, wParam, lParam, pResult);
}


/////////////////////////////////////////////////////////////////////////////
// CXTPPropertyGrid

CXTPPropertyGrid::CXTPPropertyGrid()
{
	RegisterWindowClass();

	m_pView = 0;
	m_bViewVisible = TRUE;

	m_hCursorSplit = XTPResourceManager()->LoadCursor(XTP_IDC_VSPLITBAR);
	XTPResourceManager()->AssertValid(m_hCursorSplit != 0);

	m_hCursorHand = AfxGetApp()->LoadStandardCursor(MAKEINTRESOURCE(32649));

	if (m_hCursorHand == 0)
		m_hCursorHand = XTPResourceManager()->LoadCursor(XTP_IDC_HAND);


	m_pPaintManager = new CXTPPropertyGridPaintManager(this);
	m_pPaintManager->RefreshMetrics();

	m_themeCurrent = xtpGridThemeDefault;

	m_pVerbs = new CXTPPropertyGridVerbs;
	m_pVerbs->m_pGrid = this;

	m_nVerbsHeight = 25;
	m_nFocusedVerb = -1;
	m_bVerbActivate = FALSE;
	m_bVerbsVisible = FALSE;
	m_bEnableTooltips = TRUE;

	m_bHelpVisible = TRUE;
	m_bToolBarVisible = FALSE;
	m_nHelpHeight = 58;
	m_bPreSubclassWindow = TRUE;

	m_bTabItems = FALSE;
	m_bTabCaptions = TRUE;
	m_bVariableItemsHeight = FALSE;

	m_borderStyle = xtpGridBorderStaticEdge;

	m_bShowInplaceButtonsAlways = FALSE;

	LOGFONT lfIcon;
	VERIFY(CXTPDrawHelpers::GetIconLogFont(&lfIcon));
	lfIcon.lfWeight = FW_NORMAL;
	lfIcon.lfItalic = FALSE;
	VERIFY(m_pPaintManager->GetItemMetrics()->m_fontNormal.CreateFontIndirect(&lfIcon));

	lfIcon.lfWeight = FW_BOLD;
	VERIFY(m_pPaintManager->GetItemMetrics()->m_fontBold.CreateFontIndirect(&lfIcon));

	lfIcon.lfUnderline = 1;
	lfIcon.lfWeight = FW_NORMAL;
	VERIFY(m_pPaintManager->GetItemMetrics()->m_fontUnderline.CreateFontIndirect(&lfIcon));


	m_bHighlightChanged = FALSE;
	m_bHighlightChangedButton = TRUE;

	m_pImageManager = new CXTPImageManager;

	m_pInplaceEdit = new CXTPPropertyGridInplaceEdit;
	m_pInplaceListBox = new CXTPPropertyGridInplaceList;

	m_bVariableHelpHeight = TRUE;

	m_pToolTipContext = new CXTPToolTipContext;

	m_bHideSelection = FALSE;

	m_bMultiSelect = FALSE;

	m_pMarkupContext = NULL;

	m_bAllowEdit = TRUE;


}

BOOL CXTPPropertyGrid::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/)
{
	return XTPDrawHelpers()->RegisterWndClass(hInstance, XTPPROPERTYGRID_CLASSNAME, 0);
}

CXTPPropertyGrid::~CXTPPropertyGrid()
{
	if (m_pView)
	{
		delete m_pView;
	}

	CMDTARGET_RELEASE(m_pVerbs);
	CMDTARGET_RELEASE(m_pImageManager);

	SAFE_DELETE(m_pInplaceEdit);
	SAFE_DELETE(m_pInplaceListBox);

	CMDTARGET_RELEASE(m_pPaintManager);

	CMDTARGET_RELEASE(m_pToolTipContext);

	XTPMarkupReleaseContext(m_pMarkupContext);
}

void CXTPPropertyGrid::SetInplaceEdit(CXTPPropertyGridInplaceEdit*  pInplaceEdit)
{
	ASSERT(pInplaceEdit);

	SAFE_DELETE(m_pInplaceEdit);
	m_pInplaceEdit = pInplaceEdit;
}

void CXTPPropertyGrid::SetInplaceList(CXTPPropertyGridInplaceList*  pInplaceList)
{
	ASSERT(pInplaceList);

	SAFE_DELETE(m_pInplaceListBox);
	m_pInplaceListBox = pInplaceList;
}


CXTPPropertyGridView* CXTPPropertyGrid::CreateView() const
{
	return new CXTPPropertyGridView();
}

CXTPPropertyGridView& CXTPPropertyGrid::GetGridView() const
{
	if (m_pView == 0)
	{
		m_pView = CreateView();
		m_pView->m_pGrid = (CXTPPropertyGrid*)this;
	}

	return *m_pView;
}

CXTPPropertyGridItem* CXTPPropertyGrid::FindItem(LPCTSTR strCaption) const
{
	return GetGridView().m_pCategories->FindItem(strCaption);
}

CXTPPropertyGridItem* CXTPPropertyGrid::FindItem(UINT nID) const
{
	return GetGridView().m_pCategories->FindItem(nID);
}

CXTPPropertyGridItem* CXTPPropertyGrid::AddCategory(LPCTSTR strCaption, CXTPPropertyGridItem* pCategory)
{
	return GetGridView().AddCategory(strCaption, pCategory);
}

CXTPPropertyGridItem* CXTPPropertyGrid::InsertCategory(int nIndex, LPCTSTR strCaption, CXTPPropertyGridItem* pCategory)
{
	return GetGridView().InsertCategory(nIndex, strCaption, pCategory);
}

void CXTPPropertyGrid::SetPropertySort (XTPPropertyGridSortOrder sort)
{
	GetGridView().SetPropertySort(sort);
}

XTPPropertyGridSortOrder CXTPPropertyGrid::GetPropertySort () const
{
	return GetGridView().m_properetySort;
}

int CXTPPropertyGrid::GetCount() const
{
	return GetGridView().GetCount();
}

void CXTPPropertyGrid::SetVariableSplitterPos(BOOL bVariable)
{
	GetGridView().m_bVariableSplitterPos = bVariable;
}

BOOL CXTPPropertyGrid::GetVariableSplitterPos() const
{
	return GetGridView().m_bVariableSplitterPos;
}



IMPLEMENT_DYNAMIC(CXTPPropertyGrid, CWnd)

BEGIN_MESSAGE_MAP(CXTPPropertyGrid, CWnd)
	//{{AFX_MSG_MAP(CXTPPropertyGrid)
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
	ON_WM_SETFOCUS()
	ON_WM_KILLFOCUS()
	ON_WM_SIZE()
	ON_WM_SETCURSOR()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_COMMAND(XTP_IDC_PROPERTYGRID_ALPHABETIC, OnSortAlphabetic)
	ON_COMMAND(XTP_IDC_PROPERTYGRID_CATEGORIZED, OnSortCategorized)
	ON_WM_SYSCOLORCHANGE()
	ON_WM_KEYDOWN()
	ON_WM_GETDLGCODE()
	//}}AFX_MSG_MAP
	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
	ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

UINT CXTPPropertyGrid::OnGetDlgCode()
{
	return DLGC_WANTALLKEYS;
}

BOOL CXTPPropertyGrid::CreateGridView(DWORD dwListStyle)
{
	CXTPEmptyRect rect;

	if (dwListStyle == NULL)
	{
		dwListStyle = m_bVariableItemsHeight ? LBS_OWNERDRAWVARIABLE | LBS_NOINTEGRALHEIGHT :
			LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT;
	}

	if (m_bMultiSelect)
	{
		dwListStyle |= LBS_MULTIPLESEL | LBS_EXTENDEDSEL;
	}

	// Must be owner draw.
	ASSERT((dwListStyle & (LBS_OWNERDRAWVARIABLE|LBS_OWNERDRAWFIXED)) != 0);

	m_bVariableItemsHeight = (dwListStyle & LBS_OWNERDRAWVARIABLE) != 0;

	if (!GetGridView().CreateEx(0, _T("LISTBOX"), NULL,
		WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE |
		LBS_NOTIFY | WS_VSCROLL | WS_TABSTOP | dwListStyle, rect, this, 0))
	{
		TRACE0("Error creating property grid view.\n");
		return FALSE;
	}

	GetGridView().ResetContent();
	SetStandardColors();

	return TRUE;
}

BOOL CXTPPropertyGrid::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwListStyle /*= LBS_OWNERDRAWFIXED|LBS_NOINTEGRALHEIGHT*/)
{
	if (!CreateEx(0, XTPPROPERTYGRID_CLASSNAME, _T(""),
		WS_TABSTOP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD | WS_GROUP, rect, pParentWnd, nID))
	{
		TRACE0("Error creating property grid.\n");
		return FALSE;
	}

	if (!CreateGridView(dwListStyle))
		return FALSE;

	Reposition(rect.right - rect.left, rect.bottom - rect.top);

	SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
		SWP_SHOWWINDOW|SWP_NOZORDER);

	return TRUE;
}

BOOL CXTPPropertyGrid::PreCreateWindow(CREATESTRUCT& cs)
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	//
	// PreCreateWindow is called when a control is dynamically
	// created. We want to set m_bPreSubclassWindow to FALSE
	// here so the control is initialized from CWnd::Create and
	// not CWnd::PreSubclassWindow.
	//

	m_bPreSubclassWindow = FALSE;

	return TRUE;
}

void CXTPPropertyGrid::PreSubclassWindow()
{
	CWnd::PreSubclassWindow();

	if (m_bPreSubclassWindow)
	{
		ModifyStyle(0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

		// Initialize the control.
		VERIFY(CreateGridView(NULL));

		Reposition();
	}
}

void CXTPPropertyGrid::SetVariableItemsHeight(BOOL bVariable /*= TRUE*/)
{
	if (m_bVariableItemsHeight == bVariable)
		return;

	m_bVariableItemsHeight = bVariable;

	RecreateView();
}

void CXTPPropertyGrid::RecreateView()
{
	CXTPPropertyGridView& wndView = GetGridView();
	if (!wndView.GetSafeHwnd())
		return;

	wndView.ResetContent();
	wndView.DestroyWindow();

	DWORD dwListStyle = m_bVariableItemsHeight ? LBS_OWNERDRAWVARIABLE | LBS_NOINTEGRALHEIGHT : LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT;
	if (m_bMultiSelect)
	{
		dwListStyle |= LBS_MULTIPLESEL | LBS_EXTENDEDSEL;
	}

	VERIFY(GetGridView().CreateEx(0, _T("LISTBOX"), NULL, WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | WS_TABSTOP | dwListStyle, CXTPEmptyRect(), this, 0));

	wndView.Refresh();

	Reposition();
}

void CXTPPropertyGrid::EnableMultiSelect(BOOL bMultiSelect)
{
	if (m_bMultiSelect == bMultiSelect)
		return;

	m_bMultiSelect = bMultiSelect;

	RecreateView();
}

/////////////////////////////////////////////////////////////////////////////
// CXTPPropertyGrid message handlers

BOOL CXTPPropertyGrid::OnEraseBkgnd(CDC*)
{
	return TRUE;
}

void CXTPPropertyGrid::OnPaint()
{
	CPaintDC dcPaint(this);
	CXTPBufferDC dc(dcPaint);

	m_pPaintManager->FillPropertyGrid(&dc);
}

LRESULT CXTPPropertyGrid::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/)
{
	CDC* pDC = CDC::FromHandle((HDC)wParam);
	if (pDC)
	{
		m_pPaintManager->FillPropertyGrid(pDC);
	}

	return TRUE;
}

CWnd* CXTPPropertyGrid::GetNextGridTabItem(BOOL bForward)
{
	CWnd* pThis = this;
	CWnd* pParent = pThis->GetParent();

	if (!pThis || !pParent)
	{
		ASSERT(FALSE);
		return 0 ;
	}

	if ((pParent->GetExStyle() & WS_EX_CONTROLPARENT) && (pParent->GetStyle() & WS_CHILD))
	{
		pParent = pParent->GetParent();
	}

	CWnd* pNextItem = pParent->GetNextDlgTabItem(pThis, bForward);

	if (pNextItem == pThis)
		return NULL;

	return pNextItem;
}

void CXTPPropertyGrid::OnNavigate(XTPPropertyGridUI nUIElement, BOOL bForward, CXTPPropertyGridItem* pItem)
{
	int nNextElement = bForward ? +1 : -1;
	int nUI = nUIElement + nNextElement;

	CXTPPropertyGridView& wndView = GetGridView();

	if (pItem == NULL)
		pItem = wndView.GetSelectedItem();

	if (m_bTabItems)
		nUIElement = (XTPPropertyGridUI)-3;

	while (nUI != nUIElement)
	{
		if (nUI == xtpGridUIViewPrev)
		{
			nUI += nNextElement;

			if (m_bTabItems)
			{
				int nIndex = !bForward && pItem ? pItem->m_nIndex - 1 : 0;
				if (nIndex >= 0)
				{
					wndView.SetFocus();
					wndView.SetCurSel(nIndex);
					wndView.OnSelectionChanged();

					if (bForward)
						return;

					nUI = xtpGridUIInplaceButton;
					pItem = wndView.GetSelectedItem();
				}
			}
		}
		if (nUI == xtpGridUIView)
		{
			if (m_bTabCaptions)
			{
				wndView.SetFocus();
				wndView.FocusInplaceButton(NULL);
				return;
			}
			nUI += nNextElement;
		}
		if (nUI == xtpGridUIInplaceEdit)
		{
			if (pItem && pItem->GetFlags() & xtpGridItemHasEdit)
			{
				pItem->OnSelect();
				pItem->SetFocusToInplaceControl();
				return;
			}
			nUI += nNextElement;
		}
		if (nUI == xtpGridUIInplaceControl)
		{
			if (pItem && pItem->OnInpaceControlFocus(bForward))
			{
				return;
			}
			nUI += nNextElement;
		}
		if (nUI == xtpGridUIInplaceButton)
		{
			CXTPPropertyGridInplaceButtons* pButtons = pItem ? pItem->GetInplaceButtons() : NULL;
			if (pItem && pButtons && pButtons->GetCount() > 0)
			{
				int nIndex = bForward ? -1 : pButtons->GetCount();

				if (wndView.m_pFocusedButton && wndView.m_pFocusedButton->GetItem() == pItem)
					nIndex = wndView.m_pFocusedButton->GetIndex();

				for (;;)
				{
					if (bForward) nIndex++; else nIndex--;

					CXTPPropertyGridInplaceButton* pButton = pButtons->GetAt(nIndex);
					if (!pButton)
						break;

					if (!pItem->IsInplaceButtonVisible(pButton) || !pButton->GetTabStop())
						continue;

					wndView.FocusInplaceButton(pButton);
					return;
				}

			}
			nUI += nNextElement;
		}
		if (nUI == xtpGridUIViewNext)
		{
			if (m_bTabItems)
			{
				int nIndex = bForward ? (pItem ? pItem->m_nIndex + 1 : 0) : wndView.GetCount() - 1;
				if (nIndex < wndView.GetCount())
				{
					wndView.SetFocus();
					wndView.SetCurSel(nIndex);
					wndView.OnSelectionChanged();

					if (bForward)
					{
						if (!m_bTabCaptions)
						{
							nUI = xtpGridUIView;
						}
						else
							return;
					}
					pItem = wndView.GetSelectedItem();
				}
			}

			nUI += nNextElement;
		}
		if (nUI == xtpGridUIVerb)
		{
			if (IsVerbsVisible())
			{
				m_nFocusedVerb = bForward ? 0 : m_pVerbs->GetCount() - 1;
				m_bVerbActivate = TRUE;
				SetFocus();
				m_bVerbActivate = FALSE;
				Invalidate(FALSE);
				return;
			}
			nUI += nNextElement;
		}
		if (nUI == xtpGridUIParentNext || nUI == xtpGridUIParentPrev)
		{

			CWnd* pWndNext = GetNextGridTabItem(!bForward);

			if (pWndNext != NULL)
			{
				pWndNext->SetFocus();
				return;
			}

			nUI = (nUI == xtpGridUIParentNext) ? xtpGridUIViewPrev : xtpGridUIVerb;
		}
		if (nUI < xtpGridUIParentPrev || nUI > xtpGridUIParentNext)
		{
			ASSERT(FALSE);
			return;
		}
	}
}

void CXTPPropertyGrid::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	if (m_nFocusedVerb != -1 && IsVerbsVisible())
	{
		if (m_nFocusedVerb >= m_pVerbs->GetCount())
			m_nFocusedVerb = m_pVerbs->GetCount() -1;

		BOOL bForward = GetKeyState(VK_SHIFT) >= 0;
		CXTPDrawHelpers::KeyToLayout(this, nChar);

		if ((nChar == VK_TAB) && bForward && (m_nFocusedVerb == m_pVerbs->GetCount() -1))
		{
			OnNavigate(xtpGridUIVerb, TRUE, NULL);
			return;

		}
		else if ((nChar == VK_TAB) && !bForward && (m_nFocusedVerb == 0))
		{
			OnNavigate(xtpGridUIVerb, FALSE, NULL);
			return;
		}
		else if (nChar == VK_RIGHT || nChar == VK_DOWN || ((nChar == VK_TAB) && bForward))
		{
			m_nFocusedVerb++;
			if (m_nFocusedVerb >= m_pVerbs->GetCount())
				m_nFocusedVerb = 0;
			Invalidate(FALSE);
		}
		else if (nChar == VK_LEFT || nChar == VK_UP || nChar == VK_TAB)
		{
			m_nFocusedVerb--;
			if (m_nFocusedVerb < 0)
				m_nFocusedVerb = m_pVerbs->GetCount() -1;
			Invalidate(FALSE);
		}
		else if (nChar == VK_RETURN)
		{
			CRect rcPart = m_pVerbs->GetAt(m_nFocusedVerb)->GetPart();
			OnVerbClick(m_nFocusedVerb, CPoint(rcPart.left, rcPart.bottom));
		}
	}

	CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CXTPPropertyGrid::OnKillFocus(CWnd* pNewWnd)
{
	if (m_nFocusedVerb != -1)
	{
		m_nFocusedVerb = -1;
		Invalidate(FALSE);
	}
	CWnd::OnKillFocus(pNewWnd);
}

void CXTPPropertyGrid::OnSetFocus(CWnd* pOldWnd)
{
	if (!m_bVerbActivate)
	{
		if (pOldWnd && pOldWnd == GetNextGridTabItem(FALSE) && GetKeyState(VK_SHIFT) < 0)
		{
			OnNavigate(xtpGridUIParentNext, FALSE, NULL);
		}
		else if (pOldWnd && pOldWnd == GetNextGridTabItem(TRUE) && GetKeyState(VK_SHIFT) >= 0)
		{
			OnNavigate(xtpGridUIParentPrev, TRUE, NULL);
		}
		else
		{
			GetGridView().SetFocus();
		}
	}
	else
	{
		CWnd::OnSetFocus(pOldWnd);
	}
}

void CXTPPropertyGrid::OnSize(UINT nType, int cx, int cy)
{
	CWnd::OnSize(nType, cx, cy);

	if (!GetGridView().GetSafeHwnd())
		return;

	Reposition(cx, cy);
}

int CXTPPropertyGrid::HitTest(CPoint pt)
{
	CXTPClientRect rc(this);

	if (m_bHelpVisible)
	{
		CRect rcSplitter(CPoint(rc.left, rc.bottom - SPLITTER_HEIGHT - m_nHelpHeight), CSize(rc.Width(), SPLITTER_HEIGHT));

		if (m_bVariableHelpHeight && rcSplitter.PtInRect(pt))
			return xtpGridHitHelpSplitter;

		rc.bottom -= SPLITTER_HEIGHT + m_nHelpHeight;
	}
	if (IsVerbsVisible())
	{
		CRect rcSplitter(CPoint(rc.left, rc.bottom - SPLITTER_HEIGHT - m_nVerbsHeight), CSize(rc.Width(), SPLITTER_HEIGHT));

		if (rcSplitter.PtInRect(pt))
			return xtpGridHitVerbsSplitter;

		CRect rcVerbs(rc);
		rcVerbs.top = rc.bottom - m_nVerbsHeight;

		if (rcVerbs.PtInRect(pt))
		{
			CWindowDC dc(this);
			int nIndex = m_pPaintManager->HitTestVerbs(&dc, rcVerbs, pt);
			if (nIndex != -1)
			{
				return xtpGridHitFirstVerb + nIndex;
			}
		}
	}

	return xtpGridHitError;
}

BOOL CXTPPropertyGrid::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
	if (nHitTest == HTCLIENT)
	{
		CPoint point;

		GetCursorPos(&point);
		ScreenToClient(&point);

		int nHit = HitTest(point);

		if (nHit == xtpGridHitHelpSplitter || nHit == xtpGridHitVerbsSplitter)
		{
			SetCursor(m_hCursorSplit);
			return TRUE;
		}
		if ((nHit != -1) && (nHit >= xtpGridHitFirstVerb))
		{
			SetCursor(m_hCursorHand);
			return TRUE;
		}
	}

	return CWnd::OnSetCursor(pWnd, nHitTest, message);
}

void CXTPPropertyGrid::OnInvertTracker(CRect rect)
{
	ASSERT_VALID(this);
	ASSERT(!rect.IsRectEmpty());
	ASSERT((GetStyle() & WS_CLIPCHILDREN) == 0);

	// pat-blt without clip children on
	CDC* pDC = GetDC();

	CBrush brush(GetXtremeColor(COLOR_3DFACE));
	CBrush* pBrush = (CBrush*)pDC->SelectObject(&brush);
	pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT);
	pDC->SelectObject(pBrush);

	ReleaseDC(pDC);
}

void CXTPPropertyGrid::OnSelectionChanged(CXTPPropertyGridItem* pItem)
{
	if (!m_hWnd)
		return;

	CXTPClientRect rc(this);
	CRect rcHelp(rc);
	rcHelp.top = rc.bottom - m_nHelpHeight;

	if (pItem) SendNotifyMessage(XTP_PGN_SELECTION_CHANGED, (LPARAM)pItem);

	InvalidateRect(rcHelp, FALSE);
}

void CXTPPropertyGrid::OnVerbsChanged()
{
	if (m_bVerbsVisible != IsVerbsVisible() && GetGridView().m_nLockUpdate == 0)
	{
		Reposition();
	}
	else if (GetSafeHwnd() && GetGridView().m_nLockUpdate == 0)
	{
		Invalidate(FALSE);
	}
}

void CXTPPropertyGrid::OnVerbClick(int nIndex, CPoint pt)
{
	ClientToScreen(&pt);
	ASSERT(nIndex < m_pVerbs->GetCount());

	CXTPPropertyGridVerb* pVerb = m_pVerbs->GetAt(nIndex);
	pVerb->m_ptClick = pt;

	SendNotifyMessage(XTP_PGN_VERB_CLICK, (LPARAM)pVerb);
}

void CXTPPropertyGrid::OnMouseMove(UINT nFlags, CPoint point)
{
	CWnd::OnMouseMove(nFlags, point);

}

void CXTPPropertyGrid::OnRButtonDown(UINT nFlags, CPoint point)
{
	CWnd::OnRButtonDown(nFlags, point);

}

void CXTPPropertyGrid::OnRButtonUp(UINT nFlags, CPoint point)
{
	CWnd::OnRButtonUp(nFlags, point);


}

void CXTPPropertyGrid::OnLButtonUp(UINT nFlags, CPoint point)
{

	if ((m_nFocusedVerb != -1) && (m_nFocusedVerb == HitTest(point) - xtpGridHitFirstVerb))
	{
		OnVerbClick(m_nFocusedVerb, point);
	}
	else
	{
		CWnd::OnLButtonUp(nFlags, point);
	}

}

void CXTPPropertyGrid::OnLButtonDown(UINT nFlags, CPoint point)
{
	int nHitTest = HitTest(point);

	if ((nHitTest != -1) && (nHitTest >= xtpGridHitFirstVerb))
	{
		m_nFocusedVerb = nHitTest - xtpGridHitFirstVerb;
		m_bVerbActivate = TRUE;
		SetFocus();
		m_bVerbActivate = FALSE;
		Invalidate(FALSE);
		return;

	}
	SetFocus();

	if ((nHitTest == xtpGridHitHelpSplitter) || (nHitTest == xtpGridHitVerbsSplitter))
	{
		SetCapture();
		CXTPClientRect rc(this);
		BOOL bHelpHitTest = nHitTest == xtpGridHitHelpSplitter;

		CRect rcAvail = bHelpHitTest ? CRect(0, 20 + TOOLBAR_HEIGHT, rc.right, rc.bottom) :
			CRect(0, 20 + TOOLBAR_HEIGHT, rc.right, rc.bottom - (IsHelpVisible() ? m_nHelpHeight + SPLITTER_HEIGHT : 0));

		ModifyStyle(WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, FALSE);

		m_rectTracker.SetRect(0, point.y, rc.Width(), point.y + 3);

		OnInvertTracker(m_rectTracker);

		BOOL bAccept = FALSE;
		while (GetCapture() == this)
		{
			MSG msg;
			if (!GetMessage(&msg, NULL, 0, 0))
				break;

			if (msg.message == WM_PAINT)
			{
				OnInvertTracker(m_rectTracker);
				::DispatchMessage(&msg);
				OnInvertTracker(m_rectTracker);
			}
			else if (msg.message == WM_MOUSEMOVE)
			{
				point = CPoint(msg.lParam);
				point.y = __min(point.y, rcAvail.bottom - 20);
				point.y = __max((int)point.y, int(rcAvail.top));

				if (m_rectTracker.top != point.y)
				{
					OnInvertTracker(m_rectTracker);
					m_rectTracker.OffsetRect(0, point.y - m_rectTracker.top);
					OnInvertTracker(m_rectTracker);
				}
			}
			else if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) break;
			else if (msg.message == WM_LBUTTONUP)
			{
				bAccept = TRUE;
				break;
			}
			else  ::DispatchMessage(&msg);
		}

		ReleaseCapture();

		if (bAccept)
		{
			if (bHelpHitTest) m_nHelpHeight = rcAvail.bottom - m_rectTracker.top -2; else
				m_nVerbsHeight = rcAvail.bottom - m_rectTracker.top -2;
			Reposition(rc.Width(), rc.Height());
		}
		Invalidate(FALSE);
		ModifyStyle(0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS, FALSE);
		return;
	}

	CWnd::OnLButtonDown(nFlags, point);

}

void CXTPPropertyGrid::Reposition()
{
	if (GetSafeHwnd() == 0)
		return;

	CXTPClientRect rc(this);
	Reposition(rc.Width(), rc.Height());
}

void CXTPPropertyGrid::Reposition(int cx, int cy)
{
	CXTPPropertyGridView* pView = &GetGridView();

	if (pView->m_nLockUpdate > 0)
		return;

	if (GetSafeHwnd() == 0)
		return;

	CRect rcView(0, 0, cx, cy);

	int nMinViewHeight = 20 + (m_bToolBarVisible ? TOOLBAR_HEIGHT : 0);

	if (m_bHelpVisible)
	{
		if (cy > nMinViewHeight && cy - m_nHelpHeight - SPLITTER_HEIGHT < nMinViewHeight && m_bVariableHelpHeight)
		{
			m_nHelpHeight = max(0, cy - SPLITTER_HEIGHT - nMinViewHeight);
		}

		rcView.bottom -= m_nHelpHeight + SPLITTER_HEIGHT;
	}

	if (IsVerbsVisible())
	{
		rcView.bottom -= m_nVerbsHeight + SPLITTER_HEIGHT;
	}

	m_bVerbsVisible = IsVerbsVisible();

	if (m_bToolBarVisible)
	{
		ASSERT(m_wndToolbar.GetSafeHwnd());
		CRect rcToolBar(0, 0, cx, TOOLBAR_HEIGHT);
		m_wndToolbar.MoveWindow(rcToolBar);

		rcView.top += TOOLBAR_HEIGHT;
	}

	if (!m_bViewVisible)
	{
		if (m_bVerbsVisible) m_nVerbsHeight += rcView.Height() + SPLITTER_HEIGHT;

		pView->ShowWindow(SW_HIDE);
	}
	else
	{
		pView->MoveWindow(rcView);
		pView->Invalidate(FALSE);
	}
	Invalidate(FALSE);
}

void CXTPPropertyGrid::CreateToolbar()
{
#if _MSC_VER < 1200
	m_wndToolbar.Create(this, TBSTYLE_TRANSPARENT | TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE | WS_BORDER, 0);
#else
	m_wndToolbar.CreateEx(this, TBSTYLE_TRANSPARENT | TBSTYLE_FLAT, WS_BORDER | WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP);
#endif

	CXTPResourceManager::AssertValid(XTPResourceManager()->LoadToolBar(&m_wndToolbar, XTP_IDR_PROPERTYGRID_TOOLBAR));
}

void CXTPPropertyGrid::ShowToolBar(BOOL bShow)
{
	if (bShow && !m_wndToolbar.GetSafeHwnd())
	{
		CreateToolbar();
	}
	else
	{
		if (m_wndToolbar.GetSafeHwnd())
			m_wndToolbar.ShowWindow(bShow ? SW_SHOW : SW_HIDE);
	}

	m_bToolBarVisible = bShow;

	Reposition();
	RefreshToolBarButtons();
}

void CXTPPropertyGrid::RefreshToolBarButtons()
{
	if (m_bToolBarVisible)
	{
		m_wndToolbar.GetToolBarCtrl().SetState(XTP_IDC_PROPERTYGRID_CATEGORIZED, TBSTATE_ENABLED | (GetGridView().m_properetySort == xtpGridSortCategorized ? TBSTATE_CHECKED : 0));
		m_wndToolbar.GetToolBarCtrl().SetState(XTP_IDC_PROPERTYGRID_ALPHABETIC, TBSTATE_ENABLED | (GetGridView().m_properetySort == xtpGridSortAlphabetical ? TBSTATE_CHECKED : 0));
	}
}

void CXTPPropertyGrid::ShowHelp(BOOL bShow)
{
	m_bHelpVisible = bShow;

	Reposition();
}

void CXTPPropertyGrid::ShowView(BOOL bShow)
{
	m_bViewVisible = bShow;

	Reposition();
}

void CXTPPropertyGrid::OnSortAlphabetic()
{
	SetPropertySort(xtpGridSortAlphabetical);
}

void CXTPPropertyGrid::OnSortCategorized()
{
	SetPropertySort(xtpGridSortCategorized);
}

void CXTPPropertyGrid::OnSortChanged()
{
	RefreshToolBarButtons();
	OnSelectionChanged(NULL);
	SendNotifyMessage(XTP_PGN_SORTORDER_CHANGED, (LPARAM)GetDlgCtrlID());
}

LRESULT CXTPPropertyGrid::SendNotifyMessage(WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
{
	return GetOwner()->SendMessage(XTPWM_PROPERTYGRID_NOTIFY, wParam, lParam);
}

void CXTPPropertyGrid::SetStandardColors()
{
	m_pPaintManager->GetItemMetrics()->SetDefaultValues();

	m_pPaintManager->RefreshMetrics();
	RedrawControl();
}

void CXTPPropertyGrid::RedrawControl()
{
	if (GetSafeHwnd())
	{
		RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_INVALIDATE | RDW_ERASE);
	}
}

void CXTPPropertyGrid::SetCustomColors(
	COLORREF clrHelpBack, COLORREF clrHelpFore, COLORREF clrViewLine,
	COLORREF clrViewBack, COLORREF clrViewFore, COLORREF clrCategoryFore)
{
	CXTPPropertyGridItemMetrics* pMetrics = m_pPaintManager->GetItemMetrics();

	pMetrics->m_clrHelpBack.SetCustomValue(clrHelpBack);
	pMetrics->m_clrHelpFore.SetCustomValue(clrHelpFore);
	pMetrics->m_clrLine.SetCustomValue(clrViewLine);
	pMetrics->m_clrBack.SetCustomValue(clrViewBack);
	pMetrics->m_clrFore.SetCustomValue(clrViewFore);
	pMetrics->m_clrCategoryFore.SetCustomValue(clrCategoryFore);

	RedrawControl();
}

void CXTPPropertyGrid::ResetContent()
{
	m_pVerbs->RemoveAll();
	GetGridView().ResetContent();

	GetGridView().m_nLockUpdate++;
	GetGridView().m_pCategories->Clear();
	GetGridView().m_nLockUpdate--;
}

CXTPPropertyGridItems* CXTPPropertyGrid::GetCategories() const
{
	return GetGridView().m_pCategories;
}

CXTPPropertyGridItem* CXTPPropertyGrid::AddCategory(int nID, CXTPPropertyGridItem* pCategory)
{
	CString strCaption;
	VERIFY(strCaption.LoadString(nID));
	CXTPPropertyGridItem* pItem = GetGridView().AddCategory(strCaption, pCategory);
	pItem->SetID(nID);
	return pItem;
}

CXTPPropertyGridItem* CXTPPropertyGrid::InsertCategory(int nIndex, int nID, CXTPPropertyGridItem* pCategory)
{
	CString strCaption;
	VERIFY(strCaption.LoadString(nID));
	CXTPPropertyGridItem* pItem = GetGridView().InsertCategory(nIndex, strCaption, pCategory);
	pItem->SetID(nID);
	return pItem;
}


void CXTPPropertyGrid::SetFont(CFont* pFont)
{
	LOGFONT lf;
	if (pFont->GetLogFont(&lf))
	{
		CXTPPropertyGridItemMetrics* pMetrics = m_pPaintManager->GetItemMetrics();

		pMetrics->m_fontNormal.DeleteObject();
		pMetrics->m_fontBold.DeleteObject();
		pMetrics->m_fontUnderline.DeleteObject();

		lf.lfWeight = FW_NORMAL;
		VERIFY(pMetrics->m_fontNormal.CreateFontIndirect(&lf));

		lf.lfWeight = FW_BOLD;
		VERIFY(pMetrics->m_fontBold.CreateFontIndirect(&lf));

		if (m_pInplaceEdit->GetSafeHwnd())
		{
			m_pInplaceEdit->SetFont(&pMetrics->m_fontNormal);
		}

		lf.lfUnderline = 1;
		lf.lfWeight = FW_NORMAL;
		VERIFY(pMetrics->m_fontUnderline.CreateFontIndirect(&lf));


		Refresh();
		Reposition();
	}
}

void CXTPPropertyGrid::Refresh()
{
	GetGridView().SetPropertySort(GetPropertySort(), TRUE);
}


void CXTPPropertyGrid::SaveExpandingState(CXTPPropertyGridItems* pItems, CXTPPropertyGridUpdateContext& context)
{
	int nTopIndex = GetGridView().GetTopIndex();

	for (int nItem = 0; nItem < pItems->GetCount(); nItem++)
	{
		CXTPPropertyGridItem* pItem = pItems->GetAt(nItem);

		if (pItem->GetID() != 0)
		{
			if (pItem->HasChilds())
			{
				BOOL bExpanded = pItem->IsExpanded();
				context.m_mapState.SetAt(pItem->GetID(), bExpanded);
			}

			if (pItem->IsSelected()) context.m_nSelected = pItem->GetID();
			if (pItem->GetIndex() == nTopIndex) context.m_nTopIndex= pItem->GetID();
		}
		SaveExpandingState(pItem->GetChilds(), context);
	}
}

void CXTPPropertyGrid::RestoreExpandingState(CXTPPropertyGridItems* pItems, CXTPPropertyGridUpdateContext& context)
{
	for (int nItem = 0; nItem < pItems->GetCount(); nItem++)
	{
		CXTPPropertyGridItem* pItem = pItems->GetAt(nItem);

		BOOL bExpanded;
		if (pItem->GetID() != 0 && context.m_mapState.Lookup(pItem->GetID(), bExpanded))
		{
			if (bExpanded)
				pItem->Expand();
			else
				pItem->Collapse();
		}
		RestoreExpandingState(pItem->GetChilds(), context);
	}
}

void CXTPPropertyGrid::BeginUpdate(CXTPPropertyGridUpdateContext& context, BOOL bResetContent)
{
	GetGridView().m_nLockUpdate = 1;
	GetGridView().SetRedraw(FALSE);

	context.m_nSelected = 0;
	context.m_nTopIndex = 0;
	context.m_propertySort = GetPropertySort();

	if (bResetContent)
	{
		SaveExpandingState(GetCategories(), context);
		ResetContent();
	}
	else
	{
		GetGridView().ResetContent();
	}
}

void CXTPPropertyGrid::EndUpdate(CXTPPropertyGridUpdateContext& context)
{
	RestoreExpandingState(GetCategories(), context);
	GetGridView().m_nLockUpdate = 0;

	GetGridView().SetPropertySort(context.m_propertySort, TRUE, FALSE);
	if (context.m_nSelected > 0 || context.m_nTopIndex > 0)
	{
		for (int i = 0; i < GetGridView().GetCount(); i++)
		{
			CXTPPropertyGridItem* pItem = GetGridView().GetItem(i);

			if (context.m_nTopIndex > 0 && pItem && pItem->GetID() == context.m_nTopIndex)
			{
				SetTopIndex(pItem->GetIndex());
				context.m_nTopIndex = 0;
				if (context.m_nSelected == 0)
					break;
			}

			if (context.m_nSelected > 0 && pItem && pItem->GetID() == context.m_nSelected)
			{
				pItem->Select();
				break;
			}
		}
	}

	GetGridView().SetRedraw(TRUE);

	Reposition();
}

void CXTPPropertyGrid::SetVerbsHeight(int nHeight)
{
	ASSERT(nHeight > 0);
	m_nVerbsHeight = nHeight;

	Reposition();
}

void CXTPPropertyGrid::SetHelpHeight(int nHeight)
{

	ASSERT(nHeight > 0);
	m_nHelpHeight = nHeight;

	Reposition();
}

void CXTPPropertyGrid::SetViewDivider(double dDivider)
{
	ASSERT(dDivider > 0 && dDivider < 1);
	GetGridView().m_dDivider = dDivider;

	Reposition();
}

double CXTPPropertyGrid::GetViewDivider() const
{
	return GetGridView().m_dDivider;
}

void CXTPPropertyGrid::SetViewDividerPos(int nDivider, BOOL bLockDivider /*= FALSE*/)
{
	if (bLockDivider)
	{
		GetGridView().LockDivider();
	}

	GetGridView().SetDividerPos(nDivider);

	Reposition();
}

CXTPPropertyGridItem* CXTPPropertyGrid::GetSelectedItem() const
{
	return GetGridView().GetSelectedItem();
}

CXTPPropertyGridItem* CXTPPropertyGrid::GetItem(int nIndex) const
{
	return GetGridView().GetItem(nIndex);
}

int CXTPPropertyGrid::GetSelectedItems(CArray<int, int>* pItems) const
{
	CXTPPropertyGridView* pView = &GetGridView();

	if (pView->GetStyle() & LBS_MULTIPLESEL)
	{
		int nCount = pView->GetSelCount();
		if (!pItems)
			return nCount;

		pItems->SetSize(nCount);
		pView->GetSelItems(nCount, pItems->GetData());
	}
	else
	{
		CXTPPropertyGridItem* pItem = GetSelectedItem();
		if (!pItems)
			return pItem ? 1 : 0;

		if (pItem)
		{
			pItems->RemoveAll();
			pItems->Add(pItem->GetIndent());
		}

	}

	return (int)pItems->GetSize();
}

int CXTPPropertyGrid::GetTopIndex() const
{
	return GetGridView().GetTopIndex();
}

void CXTPPropertyGrid::SetTopIndex(int nIndex)
{
	GetGridView().SetTopIndex(nIndex);
}

void CXTPPropertyGrid::SetTheme(XTPPropertyGridPaintTheme paintTheme)
{
	if (paintTheme == xtpGridThemeDefault) SetCustomTheme(new CXTPPropertyGridPaintManager(this));
	else if (paintTheme == xtpGridThemeCool) SetCustomTheme(new CXTPPropertyGridCoolTheme(this));
	else if (paintTheme == xtpGridThemeDelphi) SetCustomTheme(new CXTPPropertyGridDelphiTheme(this));
	else if (paintTheme == xtpGridThemeNativeWinXP) SetCustomTheme(new CXTPPropertyGridNativeXPTheme(this));
	else if (paintTheme == xtpGridThemeOffice2003) SetCustomTheme(new CXTPPropertyGridOffice2003Theme(this));
	else if (paintTheme == xtpGridThemeSimple) SetCustomTheme(new CXTPPropertyGridSimpleTheme(this));
	else if (paintTheme == xtpGridThemeWhidbey) SetCustomTheme(new CXTPPropertyGridWhidbeyTheme(this));
	else if (paintTheme == xtpGridThemeOfficeXP) SetCustomTheme(new CXTPPropertyGridOfficeXPTheme(this));
	else if (paintTheme == xtpGridThemeOffice2007) SetCustomTheme(new CXTPPropertyGridOffice2007Theme(this));
	else if (paintTheme == xtpGridThemeVisualStudio2010) SetCustomTheme(new CXTPPropertyGridVisualStudio2010Theme(this));
	else
	{
		ASSERT(FALSE);
	}

	m_themeCurrent = paintTheme;
}

void CXTPPropertyGrid::SetCustomTheme(CXTPPropertyGridPaintManager* pPaintManager)
{
	CXTPPropertyGridItemMetrics* pMetrics = m_pPaintManager->m_pMetrics;
	m_pPaintManager->m_pMetrics = 0;

	ASSERT(m_pPaintManager);
	CMDTARGET_RELEASE(m_pPaintManager);

	m_pPaintManager = pPaintManager;

	CMDTARGET_RELEASE(m_pPaintManager->m_pMetrics);
	m_pPaintManager->m_pMetrics = pMetrics;
	m_pPaintManager->RefreshMetrics();

	RedrawControl();
}

CXTPImageManager* CXTPPropertyGrid::GetImageManager() const
{
	return m_pImageManager ? m_pImageManager : XTPImageManager();
}

void CXTPPropertyGrid::SetImageManager(CXTPImageManager* pImageManager)
{
	if (m_pImageManager)
		m_pImageManager->InternalRelease();

	m_pImageManager = pImageManager;
}

void CXTPPropertyGrid::OnSysColorChange()
{
	CWnd::OnSysColorChange();

	m_pPaintManager->RefreshMetrics();
	RedrawControl();
}

BOOL CXTPPropertyGrid::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
{
	ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW);

	// need to handle both ANSI and UNICODE versions of the message
	TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
	TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;

	CString strTipText;

	// don't handle the message if no string resource found
	if (!XTPResourceManager()->LoadString(&strTipText, (UINT)pNMHDR->idFrom))
		return FALSE;

#ifndef _UNICODE
	if (pNMHDR->code == TTN_NEEDTEXTA)
		lstrcpyn(pTTTA->szText, strTipText, _countof(pTTTA->szText));
	else
		_mbstowcsz(pTTTW->szText, strTipText, _countof(pTTTW->szText));
#else
	if (pNMHDR->code == TTN_NEEDTEXTA)
		_wcstombsz(pTTTA->szText, strTipText, _countof(pTTTA->szText));
	else
		lstrcpyn(pTTTW->szText, strTipText, _countof(pTTTW->szText));
#endif
	*pResult = 0;

	// bring the tooltip window above other popup windows
	::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
		SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER);

	return TRUE;    // message was handled
}


BOOL CXTPPropertyGrid::IsLayoutRTL() const
{
	return GetExStyle() & WS_EX_LAYOUTRTL ? TRUE : FALSE;
}

void CXTPPropertyGrid::SetLayoutRTL(CWnd* pWnd, BOOL bRTLLayout)
{
	pWnd->ModifyStyleEx(bRTLLayout ? 0 : WS_EX_LAYOUTRTL, !bRTLLayout ? 0 : WS_EX_LAYOUTRTL);

	// walk through HWNDs to avoid creating temporary CWnd objects
	// unless we need to call this function recursively
	for (CWnd* pChild = pWnd->GetWindow(GW_CHILD); pChild != NULL;
		pChild = pChild->GetWindow(GW_HWNDNEXT))
	{

		// send to child windows after parent
		SetLayoutRTL(pChild, bRTLLayout);
	}
}


void CXTPPropertyGrid::SetLayoutRTL(BOOL bRightToLeft)
{
	if (!XTPSystemVersion()->IsLayoutRTLSupported())
		return;

	SetLayoutRTL(this, bRightToLeft);

	if (m_pInplaceEdit && m_pInplaceEdit->GetSafeHwnd())
	{
		m_pInplaceEdit->HideWindow();
		m_pInplaceEdit->m_bDelayCreate = TRUE;
	}

	if (GetSelectedItem()) GetSelectedItem()->OnSelect();

	Reposition();
	RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW | RDW_INVALIDATE | RDW_ERASE);
}

void CXTPPropertyGrid::AllowEdit(BOOL bAllowEdit)
{
	m_bAllowEdit = bAllowEdit;
	Reposition();
}

void CXTPPropertyGrid::SetBorderStyle(XTPPropertyGridBorderStyle borderStyle)
{
	m_borderStyle = borderStyle;

	Reposition();

	if (GetGridView().GetSafeHwnd())
	{
		GetGridView().SetWindowPos(0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
	}
}

XTPPropertyGridBorderStyle CXTPPropertyGrid::GetBorderStyle() const
{
	return m_borderStyle;
}


BOOL CXTPPropertyGrid::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	if (m_pMarkupContext)
	{
		CXTPPropertyGridItem* pItem = GetSelectedItem();
		if (pItem && pItem->GetMarkupDescription())
		{
			if (XTPMarkupRelayMessage(pItem->GetMarkupDescription(), message, wParam, lParam, pResult))
				return TRUE;
		}
	}

	return CWnd::OnWndMsg(message, wParam, lParam, pResult);
}

void CXTPPropertyGrid::EnableMarkup(BOOL bEnable)
{
	if (bEnable && m_pMarkupContext)
		return;

	XTPMarkupReleaseContext(m_pMarkupContext);

	if (bEnable)
	{
		m_pMarkupContext = XTPMarkupCreateContext(m_hWnd);
	}

	Refresh();
}

void CXTPPropertyGrid::RefeshBindings(CXTPPropertyGridItem* pItem)
{
	if (pItem)
	{
		pItem->OnBeforeInsert();
	}

	CXTPPropertyGridItems* pItems = pItem ? pItem->GetChilds() : GetCategories();

	for (int i = 0; i < pItems->GetCount(); i++)
	{
		CXTPPropertyGridItem* pChild = pItems->GetAt(i);
		RefeshBindings(pChild);
	}
}

COLORREF CXTPPropertyGrid::GetHelpBackColor() const
{
	return m_pPaintManager->GetItemMetrics()->m_clrHelpBack;
}

COLORREF CXTPPropertyGrid::GetHelpForeColor() const
{
	return m_pPaintManager->GetItemMetrics()->m_clrHelpFore;
}