// XTPTaskDialogClient.cpp: implementation of the CXTPTaskDialogClient class.
//
// This file is a part of the XTREME CONTROLS 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/XTPImageManager.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPResourceManager.h"
#include "Common/XTPMarkupRender.h"
#include "Common/XTPColorManager.h"
#include "Common/XTPWinThemeWrapper.h"
#include "../Util/XTPControlTheme.h"

#include "../Button/XTPButtonTheme.h"
#include "XTPTaskDialogControls.h"
#include "../Button/XTPButton.h"

#ifdef _XTP_INCLUDE_MARKUP
#include <Markup/XTPMarkupObject.h>
#include <Markup/XTPMarkupInputElement.h>
#include <Markup/Text/XTPMarkupInline.h>
#include <Markup/Text/XTPMarkupSpan.h>
#include <Markup/Text/XTPMarkupRun.h>
#include <Markup/XTPMarkupContext.h>
#endif

#include "XTPTaskDialogAPI.h"
#include "XTPTaskDialogClient.h"

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

//---------------------------------------------------------------------------
// dialog units used for dynamic layout.
//---------------------------------------------------------------------------
enum XTPDluMetrics
{
	xtpDluMinClient        = 180, // minimum client width.
	xtpDluMaxClient        = 265, // maximum client width when using command links.
	xtpDluMaxVerify        = 146, // maximum width for verify and expando buttons.
	xtpDluPadding          = 2,   // padding used for button and content.
	xtpDluBtnSpacing       = 3,   // spacing between common buttons.
	xtpDluMargin           = 5,   // non-client margin.
};


#ifndef LAYOUT_BITMAPORIENTATIONPRESERVED
#define LAYOUT_BITMAPORIENTATIONPRESERVED 0x00000008
#endif

#define IDC_INPUTBOX 544

CXTPTaskDialogClient::CStringMarkup::CStringMarkup()
{
	m_pUIElement = NULL;
	m_pClient = NULL;
}

CXTPTaskDialogClient::CStringMarkup::~CStringMarkup()
{
	XTPMarkupReleaseElement(m_pUIElement);
}

void CXTPTaskDialogClient::CStringMarkup::SetCaption(const CString& strCaption)
{
	m_strCaption = strCaption;
	XTPMarkupReleaseElement(m_pUIElement);

	if (!m_strCaption.IsEmpty() && m_pClient && m_pClient->m_pMarkupContext)
	{
		m_pUIElement = XTPMarkupParseText(m_pClient->m_pMarkupContext, m_strCaption);
	}
}

void CXTPTaskDialogClient::CStringMarkup::SetFinalRect(const CRect& rcFinalRect)
{
	m_rcFinalRect = rcFinalRect;
}

//===========================================================================
// CXTPTaskDialogClient
//===========================================================================
CXTPTaskDialogClient::CXTPTaskDialogClient()
	: m_nMaxClientWidth(0)
	, m_nMinClientWidth(0)
	, m_nPadding(2)
	, m_bExpanded(FALSE)
	, m_bVerification(FALSE)
	, m_bUseSysIcons(FALSE)
	, m_bThemeReady(FALSE)
	, m_hIconFooter(NULL)
	, m_hIconMain(NULL)
	, m_crContent(COLORREF_NULL)
	, m_crContentText(COLORREF_NULL)
	, m_crFooter(COLORREF_NULL)
	, m_crFooterText(COLORREF_NULL)
	, m_crMainText(COLORREF_NULL)
	, m_cr3DLight(COLORREF_NULL)
	, m_cr3DShadow(COLORREF_NULL)
	, m_cr3DHighLight(COLORREF_NULL)
	, m_ptMargin(0,0)
	, m_ptPadding(0,0)
	, m_ptBtnSpacing(0,0)
	, m_ptBorder(0,0)
	, m_pBtnVerify(NULL)
	, m_pBtnExpando(NULL)
	, m_pConfig(NULL)
{
	m_rcMainInstruction.SetRectEmpty();
	m_rcContent.SetRectEmpty();
	m_rcCommandButtons.SetRectEmpty();
	m_rcFooter.SetRectEmpty();
	m_rcExpandedInformation.SetRectEmpty();
	m_rcLinkButtons.SetRectEmpty();
	m_rcRadioButtons.SetRectEmpty();

	m_sizeCommandButton = CSize(0, 0);
	m_sizeIconFooter = CSize(0, 0);
	m_sizeIconMain = CSize(0, 0);

	m_nSelRadioButtonID = 0;

	m_pMarkupContext = NULL;

	m_pIconLinkGlyph = NULL;
	m_bMessageBoxStyle = FALSE;

	m_strMainInstruction.m_pClient = this;
	m_strContent.m_pClient = this;
	m_strFooter.m_pClient = this;
	m_strVerificationText.m_pClient = this;
	m_strExpandedInformation.m_pClient = this;
	m_strExpandedControlText.m_pClient = this;
	m_strCollapsedControlText.m_pClient = this;

	m_bEnableMarkup = FALSE;
	m_bShowInputBox = FALSE;
}

#define SAFE_DELETE_WINDOW(ptr) if (ptr) { ptr->DestroyWindow(); delete ptr; ptr = NULL; }

void CXTPTaskDialogClient::DeleteControls()
{
	SAFE_DELETE_WINDOW(m_pBtnVerify);
	SAFE_DELETE_WINDOW(m_pBtnExpando);

	CMDTARGET_RELEASE(m_pIconLinkGlyph);

	int i;
	for (i = 0; i < m_arrLinkButtons.GetSize(); ++i)
	{
		CButton* pButton = m_arrLinkButtons[i];
		SAFE_DELETE_WINDOW(pButton);
	}
	m_arrLinkButtons.RemoveAll();

	for (i = 0; i < m_arrRadioButtons.GetSize(); ++i)
	{
		CButton* pButton = m_arrRadioButtons[i];
		SAFE_DELETE_WINDOW(pButton);
	}
	m_arrRadioButtons.RemoveAll();

	for (i = 0; i < m_arrCommandButtons.GetSize(); ++i)
	{
		CButton* pButton = m_arrCommandButtons[i];
		SAFE_DELETE_WINDOW(pButton);
	}
	m_arrCommandButtons.RemoveAll();

	SAFE_DELETE_HICON(m_hIconFooter);
	SAFE_DELETE_HICON(m_hIconMain);

	CMDTARGET_RELEASE(m_pIconLinkGlyph);

	m_wndProgressBar.DestroyWindow();
	m_wndFooter.DestroyWindow();
	m_wndExpandedInformation.DestroyWindow();
	m_wndContent.DestroyWindow();

	m_strMainInstruction.SetCaption(_T(""));
	m_strContent.SetCaption(_T(""));
	m_strFooter.SetCaption(_T(""));
	m_strVerificationText.SetCaption(_T(""));
	m_strExpandedInformation.SetCaption(_T(""));
	m_strExpandedControlText.SetCaption(_T(""));
	m_strCollapsedControlText.SetCaption(_T(""));
	XTPMarkupReleaseContext(m_pMarkupContext);

	m_mapWndSize.RemoveAll();
}

CXTPTaskDialogClient::~CXTPTaskDialogClient()
{
	DeleteControls();
	DestroyWindow();
}

BEGIN_MESSAGE_MAP(CXTPTaskDialogClient, CWnd)
	//{{AFX_MSG_MAP(CXTPTaskDialogClient)
	ON_WM_SETTINGCHANGE()
	ON_WM_SYSCOLORCHANGE()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_CTLCOLOR()
	ON_WM_DESTROY()
	ON_EN_CHANGE(IDC_INPUTBOX, OnInputBoxChanged)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//---------------------------------------------------------------------------
// CXTPTaskDialogClient message handlers
//---------------------------------------------------------------------------

void CXTPTaskDialogClient::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
	CDialog::OnSettingChange(uFlags, lpszSection);
	RefreshMetrics();
}

void CXTPTaskDialogClient::OnSysColorChange()
{
	CDialog::OnSysColorChange();
	RefreshMetrics();
}

BOOL CXTPTaskDialogClient::OnEraseBkgnd(CDC* pDC)
{
	UNREFERENCED_PARAMETER(pDC);
	return TRUE;
}

void CXTPTaskDialogClient::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	CXTPBufferDC memDC(dc);

	CXTPClientRect rcClient(this);

	if (!memDC.GetSafeHdc())
		return;

	DrawBackground(&memDC, rcClient);
	memDC.SetBkMode(TRANSPARENT);


	DrawMainInstruction(&memDC);
	DrawContent(&memDC);
	DrawExpandedInfo(&memDC);
	DrawFootNote(&memDC);
}

HBRUSH CXTPTaskDialogClient::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	int i;

	for (i = 0; i < m_arrRadioButtons.GetSize(); i++)
	{
		if (m_arrRadioButtons[i] == pWnd)
		{
			pDC->SetBkColor(m_crContent);
			return GetSysColorBrush(m_bThemeReady ? COLOR_WINDOW : COLOR_3DFACE);
		}
	}

	for (i = 0; i < m_arrLinkButtons.GetSize(); i++)
	{
		if (m_arrLinkButtons[i] == pWnd)
		{
			pDC->SetBkColor(m_crContent);
			return GetSysColorBrush(m_bThemeReady ? COLOR_WINDOW : COLOR_3DFACE);
		}
	}


	return CWnd::OnCtlColor(pDC, pWnd, nCtlColor);

}

HRESULT CXTPTaskDialogClient::SendNotify(UINT uNotify, WPARAM wParam /*=0*/, LPARAM lParam /*=0*/)
{
	if (m_pConfig->pfCallback)
	{
		return m_pConfig->pfCallback(m_hWnd, uNotify,
			wParam, lParam, m_pConfig->lpCallbackData);
	}
	return E_FAIL;
}

BOOL CXTPTaskDialogClient::CanCancel() const
{
	if (GetDlgItem(IDCANCEL))
		return TRUE;

	return ((m_pConfig->dwFlags & TDF_ALLOW_DIALOG_CANCELLATION) != 0);
}

void CXTPTaskDialogClient::OnMarkupHyperlinkClick(CXTPMarkupObject* pSender, CXTPMarkupRoutedEventArgs* pArgs)
{
	pSender;
	pArgs;

#ifdef _XTP_INCLUDE_MARKUP
	if (pSender->IsKindOf(MARKUP_TYPE(CXTPMarkupHyperlink)))
	{
		CXTPMarkupString* pTag = MARKUP_STATICCAST(CXTPMarkupString, ((CXTPMarkupHyperlink*)pSender)->GetTag());
		SendNotify(TDN_HYPERLINK_CLICKED, (WPARAM)0, (LPARAM)(pTag ? (LPCWSTR)*pTag : (LPCWSTR)NULL));

		pArgs->SetHandled();
	}
#endif
}

BOOL CXTPTaskDialogClient::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	// To Handle Hyperlinks:
	if (m_pMarkupContext)
	{
		CPoint ptMouse(0);
		GetCursorPos(&ptMouse);
		ScreenToClient(&ptMouse);

		if (m_strMainInstruction.m_rcFinalRect.PtInRect(ptMouse))
		{
			if (XTPMarkupRelayMessage(m_strMainInstruction.m_pUIElement, message, wParam, lParam, pResult))
				return TRUE;
		}
		else if (m_strContent.m_rcFinalRect.PtInRect(ptMouse))
		{
			if (XTPMarkupRelayMessage(m_strContent.m_pUIElement, message, wParam, lParam, pResult))
				return TRUE;
		}
		else if (m_strFooter.m_rcFinalRect.PtInRect(ptMouse))
		{
			if (XTPMarkupRelayMessage(m_strFooter.m_pUIElement, message, wParam, lParam, pResult))
				return TRUE;
		}
		else if (m_strExpandedInformation.m_rcFinalRect.PtInRect(ptMouse))
		{
			if (XTPMarkupRelayMessage(m_strExpandedInformation.m_pUIElement, message, wParam, lParam, pResult))
				return TRUE;
		}
		else
		{
			if (XTPMarkupRelayMessage(m_pMarkupContext, message, wParam, lParam, pResult))
				return TRUE;
		}

	}

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


LRESULT CXTPTaskDialogClient::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_COMMAND:
		{
			if (HIWORD(wParam) == BN_CLICKED)
			{
				int nID = (int)LOWORD(wParam);
				HWND hWnd = (HWND)lParam;

				if (hWnd && m_arrRadioButtons.GetSize() > 0)
				{
					for (int i = 0; i < m_arrRadioButtons.GetSize(); i++)
					{
						if (m_arrRadioButtons[i]->GetSafeHwnd() == hWnd )
						{
							if (m_arrRadioButtons[i]->GetCheck())
							{
								m_nSelRadioButtonID = nID;
								SendNotify(TDN_RADIO_BUTTON_CLICKED, (WPARAM)m_nSelRadioButtonID);
							}
							return TRUE;
						}
					}
				}


				if (hWnd && (hWnd == m_wndFooter.GetSafeHwnd()
					|| hWnd == m_wndContent.GetSafeHwnd()
					|| hWnd == m_wndExpandedInformation.GetSafeHwnd()))
				{
					CXTPTaskDialogLinkCtrl* pWnd = (CXTPTaskDialogLinkCtrl*)CWnd::FromHandle(hWnd);
					CXTPTaskDialogLinkCtrl::LINKITEM* pItem = pWnd->GetFocusedLink();
					if (pItem)
					{
						SendNotify(TDN_HYPERLINK_CLICKED, (WPARAM)0, (LPARAM)XTP_CT2CW(pItem->strUrl));
						return 1;
					}
				}

				if (hWnd && m_pBtnVerify->GetSafeHwnd() == hWnd)
				{
					m_bVerification = !m_bVerification;
					SendNotify(TDN_VERIFICATION_CLICKED, m_bVerification);
					return 0;
				}

				if (hWnd && m_pBtnExpando->GetSafeHwnd() == hWnd)
				{
					m_bExpanded = !m_bExpanded;
					SendNotify(TDN_EXPANDO_BUTTON_CLICKED, m_bExpanded);
					OnExpandExpandoClicked();
					return 0;
				}

				if (nID == IDCANCEL)
				{
					if (!CanCancel())
						return FALSE;
				}

				if (SendNotify(TDN_BUTTON_CLICKED, (WPARAM)nID) == 0)
				{
					if (nID == IDCANCEL)
					{
						OnCancel();
					}
					else if (nID == IDOK)
					{
						OnOK();
					}
					else
					{
						EndDialog(nID);
					}
				}
				return 0;

			}
			break;
		}
	}

	return CDialog::WindowProc(message, wParam, lParam);
}


//---------------------------------------------------------------------------
// Initialization
//---------------------------------------------------------------------------

void CXTPTaskDialogClient::RefreshMetrics()
{
	CXTPWinThemeWrapper themeApi;
	m_bThemeReady = m_bMessageBoxStyle || themeApi.IsAppThemeReady();

	m_ptBorder.x      = ::GetSystemMetrics(SM_CXEDGE) + ::GetSystemMetrics(SM_CXBORDER);
	m_ptBorder.y      = ::GetSystemMetrics(SM_CYEDGE) + ::GetSystemMetrics(SM_CYBORDER);
	m_sizeIconFooter.cx     = ::GetSystemMetrics(SM_CXSMICON);
	m_sizeIconFooter.cy     = ::GetSystemMetrics(SM_CYSMICON);
	m_sizeIconMain.cx = ::GetSystemMetrics(SM_CXICON);
	m_sizeIconMain.cy = ::GetSystemMetrics(SM_CYICON);

	m_ptMargin     = XTPDlu2Pix(xtpDluMargin, xtpDluMargin);
	m_ptPadding    = XTPDlu2Pix(xtpDluPadding, xtpDluPadding);

	m_ptBtnSpacing = CPoint(XTPDlu2Pix(xtpDluBtnSpacing, xtpDluBtnSpacing).x, 0);

	if (!m_bThemeReady)
		m_ptBtnSpacing = CPoint(m_ptMargin.x, 2);

	m_nMinClientWidth = XTPDlu2Pix(xtpDluMinClient, 0).x - m_ptMargin.x * 2;


	CRect rcScreen = XTPMultiMonitor()->GetWorkArea(m_pConfig->hwndParent);
	m_nMaxClientWidth = rcScreen.Width() - ((m_ptBorder.x*2) + (m_ptMargin.x*2));

	if (m_nMinClientWidth > m_nMaxClientWidth)
		m_nMinClientWidth = m_nMaxClientWidth;

	RefreshColors();
}

void CXTPTaskDialogClient::RefreshColors()
{
	XTPColorManager()->RefreshColors();

	COLORREF crWindow = GetXtremeColor(COLOR_WINDOW);
	COLORREF crWindowText = GetXtremeColor(COLOR_WINDOWTEXT);
	COLORREF crBtnFace = GetXtremeColor(COLOR_BTNFACE);
	COLORREF crBtnText = GetXtremeColor(COLOR_BTNTEXT);
	m_cr3DShadow = GetXtremeColor(COLOR_3DSHADOW);
	m_cr3DHighLight = GetXtremeColor(COLOR_3DHILIGHT);
	m_cr3DLight  = XTPColorManager()->LightColor(crBtnFace, m_cr3DShadow, 750);

	m_crContent = crBtnFace;
	m_crMainText = m_crContentText = crBtnText;

	if (m_bThemeReady)
	{
		m_crContent = crWindow;
		m_crContentText = crWindowText;

		m_crMainText = RGB(0x00, 0x33, 0x99);

		if (!XTPColorManager()->LongColor(m_crMainText, crWindow, 1, 50))
			m_crMainText = m_crContentText;
	}

	m_crFooter = crBtnFace;
	m_crFooterText = crBtnText;

	m_wndContent.SetBackColor(m_crContent);
	m_wndContent.SetTextColor(m_crContentText);
	m_wndExpandedInformation.SetBackColor(IsExpandFooterArea() ? m_crFooter : m_crContent);
	m_wndExpandedInformation.SetTextColor(IsExpandFooterArea() ? m_crFooterText : m_crContentText);
	m_wndFooter.SetBackColor(m_crFooter);
	m_wndFooter.SetTextColor(m_crFooterText);
}

CString CXTPTaskDialogClient::LoadItemString(PCWSTR pszBuffer)
{
	CString strItem;

	if (pszBuffer && IS_INTRESOURCE(pszBuffer))
	{
		UINT uID = (UINT)(UINT_PTR)pszBuffer;

		if (::FindResource(m_pConfig->hInstance, MAKEINTRESOURCE((uID>>4)+1), RT_STRING))
			XTPLoadStringInst(m_pConfig->hInstance, uID, &strItem);
		else
			XTPResourceManager()->LoadString(&strItem, uID);

		ASSERT(!strItem.IsEmpty());
	}
	else
	{
		strItem = pszBuffer;
	}

	return strItem;
}

void CXTPTaskDialogClient::LoadStrings()
{
	m_strMainInstruction.SetCaption(LoadItemString(m_pConfig->pszMainInstruction));
	m_strContent.SetCaption(LoadItemString(m_pConfig->pszContent));
	m_strFooter.SetCaption(LoadItemString(m_pConfig->pszFooter));
	m_strVerificationText.SetCaption(LoadItemString(m_pConfig->pszVerificationText));
	m_strExpandedInformation.SetCaption(LoadItemString(m_pConfig->pszExpandedInformation));

	if (!m_strExpandedInformation.IsEmpty())
	{
		m_strExpandedControlText.SetCaption(LoadItemString(m_pConfig->pszExpandedControlText));
		m_strCollapsedControlText.SetCaption(LoadItemString(m_pConfig->pszCollapsedControlText));

		if (m_strExpandedControlText.IsEmpty() && m_strCollapsedControlText.IsEmpty())
		{
			CXTPResourceManager::AssertValid(XTPResourceManager()->LoadString(&m_strExpandedControlText.m_strCaption, XTP_IDS_TASK_HIDE_DETAILS));
			CXTPResourceManager::AssertValid(XTPResourceManager()->LoadString(&m_strCollapsedControlText.m_strCaption, XTP_IDS_TASK_SEE_DETAILS));
		}
		else if (m_strExpandedControlText.IsEmpty())
		{
			m_strExpandedControlText = m_strCollapsedControlText;
		}
		else if (m_strCollapsedControlText.IsEmpty())
		{
			m_strCollapsedControlText = m_strExpandedControlText;
		}
	}
}

BOOL CXTPTaskDialogClient::CreateCommandButtons()
{
	if ((m_pConfig->dwCommonButtons & TDCBF_OK_BUTTON) || (!m_pConfig->pButtons && !m_pConfig->dwCommonButtons))
	{
		if (AddCommandButton(IDOK, XTP_IDS_TASK_OK, m_sizeCommandButton) == NULL)
		{
			TRACE0("Failed to create OK button.\n");
			return FALSE;
		}
	}

	if (m_pConfig->dwCommonButtons & TDCBF_YES_BUTTON)
	{
		if (AddCommandButton(IDYES, XTP_IDS_TASK_YES, m_sizeCommandButton) == NULL)
		{
			TRACE0("Failed to create YES button.\n");
			return FALSE;
		}
	}

	if (m_pConfig->dwCommonButtons & TDCBF_NO_BUTTON)
	{
		if (AddCommandButton(IDNO, XTP_IDS_TASK_NO, m_sizeCommandButton) == NULL)
		{
			TRACE0("Failed to create NO button.\n");
			return FALSE;
		}
	}

	if (m_pConfig->dwCommonButtons & TDCBF_RETRY_BUTTON)
	{
		if (AddCommandButton(IDRETRY, XTP_IDS_TASK_RETRY, m_sizeCommandButton) == NULL)
		{
			TRACE0("Failed to create RETRY button.\n");
			return FALSE;
		}
	}

	if (m_pConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
	{
		if (AddCommandButton(IDCANCEL, XTP_IDS_TASK_CANCEL, m_sizeCommandButton) == NULL)
		{
			TRACE0("Failed to create CANCEL button.\n");
			return FALSE;
		}
	}

	if (m_pConfig->dwCommonButtons & TDCBF_CLOSE_BUTTON)
	{
		if (AddCommandButton(IDCLOSE, XTP_IDS_TASK_CLOSE, m_sizeCommandButton) == NULL)
		{
			TRACE0("Failed to create CLOSE button.\n");
			return FALSE;
		}
	}


	return TRUE;
}

BOOL CXTPTaskDialogClient::CreateLinkButtons()
{
	if (m_pConfig->pButtons == NULL || m_pConfig->cButtons == 0)
		return TRUE;

	for (UINT i = 0; i < m_pConfig->cButtons; ++i)
	{
		CString strButtonText = LoadItemString(m_pConfig->pButtons[i].pszButtonText);

		if (IsLinkButtonsUsed())
		{
			CXTPTaskButtonTheme* pTheme = new CXTPTaskButtonTheme(m_bThemeReady);
			pTheme->SetTitleFont(&m_fontLarge);

			CButton* pLinkButton = CreateButton(m_pConfig->pButtons[i].nButtonID,
				strButtonText, CSize(0, 0), BS_PUSHBUTTON | BS_MULTILINE | WS_TABSTOP, pTheme);

			if (pLinkButton == NULL)
			{
				TRACE0("Error creating command link button.\n");
				return FALSE;
			}

			if (m_pIconLinkGlyph)
			{
				CXTPButton* pButton = DYNAMIC_DOWNCAST(CXTPButton, pLinkButton);
				if (pButton == NULL)
				{
					TRACE0("Error creating command link button.\n");
					SAFE_DELETE(pButton);
					return FALSE;
				}

				m_pIconLinkGlyph->InternalAddRef(); // Lets share one icon!
				pButton->SetIcon(m_pIconLinkGlyph->GetExtent(), m_pIconLinkGlyph);
			}
			m_arrLinkButtons.Add(pLinkButton);
		}
		else
		{
			CSize sizeButton = CalcButtonSize(strButtonText);
			sizeButton.cx = max(m_sizeCommandButton.cx, sizeButton.cx);

			if (AddCommandButton(m_pConfig->pButtons[i].nButtonID, strButtonText, sizeButton) == NULL)
			{
				TRACE0("Failed to create OK button.\n");
				return FALSE;
			}
		}
	}

	return TRUE;
}

#ifndef PBS_MARQUEE
#define PBS_MARQUEE             0x08
#endif

BOOL CXTPTaskDialogClient::CreateProgressBar()
{
	if (!IsProgressBarVisible())
		return TRUE;

	if (!m_wndProgressBar.Create(WS_CHILD | WS_VISIBLE |
		(m_pConfig->dwFlags & TDF_SHOW_MARQUEE_PROGRESS_BAR ? PBS_MARQUEE : 0), CRect(0, 0, 0, 0), this, 0))
		return FALSE;

	return TRUE;
}

BOOL CXTPTaskDialogClient::CreateInputBox()
{
	if (!m_bShowInputBox)
		return TRUE;

	if (!m_wndInputBox.CreateEx(WS_EX_CLIENTEDGE, _T("EDIT"), m_strInputBoxText, WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, CRect(0, 0, 0, 0), this, IDC_INPUTBOX))
		return FALSE;

	m_wndInputBox.SetFont(&m_font);

	return TRUE;
}

BOOL CXTPTaskDialogClient::CreateRadioButtons()
{
	if (m_pConfig->pRadioButtons == NULL)
		return TRUE;

	for (UINT i = 0; i < m_pConfig->cRadioButtons; ++i)
	{
		CString strButton = LoadItemString(m_pConfig->pRadioButtons[i].pszButtonText);

		int nButtonID = m_pConfig->pRadioButtons[i].nButtonID;

		CPoint point(10,2);
		CButton* pButton = CreateButton(nButtonID, strButton,
			CalcButtonSize(strButton, &point), BS_AUTORADIOBUTTON | BS_TEXT | BS_MULTILINE | BS_TOP);

		if (pButton == NULL)
		{
			TRACE0("Error creating radio button.\n");
			return FALSE;
		}

		if ((m_pConfig->dwFlags & TDF_NO_DEFAULT_RADIO_BUTTON) == 0)
		{
			if (m_pConfig->nDefaultRadioButton == nButtonID)
			{
				pButton->SetCheck(TRUE);
				m_nSelRadioButtonID = nButtonID;
				pButton->ModifyStyle(0, WS_TABSTOP);
			}
			if (m_pConfig->nDefaultRadioButton == 0 && i == 0)
			{
				pButton->SetCheck(TRUE);
				m_nSelRadioButtonID = nButtonID;
				pButton->ModifyStyle(0, WS_TABSTOP);
			}
		}
		else if (i == 0)
		{
			pButton->ModifyStyle(0, WS_TABSTOP);
		}

		m_arrRadioButtons.Add(pButton);
	}

	return TRUE;
}

BOOL CXTPTaskDialogClient::CreateVerifyExpandButtons()
{
	// create expando button.
	if (!m_strExpandedInformation.IsEmpty())
	{
		CString strButtonText = IsExpandedByDefault()? m_strExpandedControlText: m_strCollapsedControlText;

		CString strButtonSize = m_strExpandedControlText.m_strCaption.GetLength() > m_strCollapsedControlText.m_strCaption.GetLength()
			? m_strExpandedControlText : m_strCollapsedControlText;

		CSize sizeButton = CalcButtonSize(strButtonSize, NULL, XTPDlu2Pix(xtpDluMaxVerify,0).x);

		CButton* pButton = CreateButton(0, strButtonText, sizeButton,
			BS_PUSHBUTTON | BS_MULTILINE | WS_TABSTOP, new CXTPTaskButtonThemeExpando);

		if (pButton == NULL)
		{
			TRACE0("Error creating Expando button.\n");
			return FALSE;
		}

		m_pBtnExpando = DYNAMIC_DOWNCAST(CXTPButton, pButton);
		if (m_pBtnExpando == NULL)
		{
			TRACE0("Error creating Expando button.\n");
			SAFE_DELETE(pButton);
			return FALSE;
		}

		m_bExpanded = IsExpandedByDefault();
		m_pBtnExpando->SetChecked(m_bExpanded);
	}

	// create verification text check box.
	if (!m_strVerificationText.IsEmpty())
	{
		CString strButtonText = m_strVerificationText;
		CPoint point(10, 2);
		CSize sizeButton = CalcButtonSize(strButtonText, &point, XTPDlu2Pix(xtpDluMaxVerify,0).x);

		CButton* pButton = CreateButton(0, strButtonText, sizeButton,
			BS_AUTOCHECKBOX | BS_MULTILINE | BS_TOP | BS_LEFT | WS_TABSTOP);

		if (pButton == NULL)
		{
			TRACE0("Error creating Verification check box.\n");
			return FALSE;
		}

		m_bVerification = ((m_pConfig->dwFlags & TDF_VERIFICATION_FLAG_CHECKED) != 0);
		m_pBtnVerify = pButton;
		m_pBtnVerify->SetCheck(m_bVerification);
	}

	return TRUE;
}

BOOL CXTPTaskDialogClient::CreateClient(BOOL bMoveWindow)
{
	DeleteControls();

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

#ifdef _XTP_INCLUDE_MARKUP
	if (m_pMarkupContext)
	{
		m_pMarkupContext->AddHandler(CXTPMarkupHyperlink::m_pClickEvent, CreateMarkupClassDelegate(this, &CXTPTaskDialogClient::OnMarkupHyperlinkClick));
	}
#endif

	RefreshMetrics();

	LoadStrings();
	CreateIcons();
	CreateFonts();

	m_sizeCommandButton = CalcCommandButtonSize();

	if (!CreateLinkButtons() ||         // create command link buttons.
		!CreateCommandButtons())        // create common buttons OK, Cancel, etc.
	{
		return FALSE;
	}

	// If hyperlinks are enabled, creating the links now with a zero size
	// will extract all hyperlink information from the string so the layout
	// can be determined correctly. The links will be resized when RecalcLayout
	// is called.

	if (IsHyperlinksEnabled())
	{
		CXTPEmptyRect rect;
		m_wndContent.Create(rect, m_strContent.m_strCaption, &m_font, this);
		m_wndExpandedInformation.Create(rect, m_strExpandedInformation.m_strCaption, &m_font, this);
		m_wndFooter.Create(rect, m_strFooter.m_strCaption, &m_font, this);
	}

	if (!CreateProgressBar() ||
		!CreateRadioButtons() ||        // create radio buttons.
		!CreateInputBox() ||            // create input box.
		!CreateVerifyExpandButtons())   // create verify and expando buttons.
	{
		return FALSE;
	}


	RecalcLayout(bMoveWindow);

	return TRUE;
}

void CXTPTaskDialogClient::OnDestroy()
{
	if (m_wndInputBox.GetSafeHwnd())
	{
		m_wndInputBox.GetWindowText(m_strInputBoxText);
	}

	CDialog::OnDestroy();
}

void CXTPTaskDialogClient::UpdateZOrder()
{
	ZOrder(&m_wndContent);

	if (!IsExpandFooterArea())
		ZOrder(&m_wndExpandedInformation);

	ZOrder(&m_wndProgressBar);

	int i;

	for (i = 0; i < (int)m_arrRadioButtons.GetSize(); i++)
	{
		ZOrder(m_arrRadioButtons[i]);
	}

	ZOrder(&m_wndInputBox);

	for (i = 0; i < (int)m_arrLinkButtons.GetSize(); i++)
	{
		ZOrder(m_arrLinkButtons[i]);
	}

	ZOrder(m_pBtnExpando);
	ZOrder(m_pBtnVerify);

	for (i = 0; i < (int)m_arrCommandButtons.GetSize(); i++)
	{
		ZOrder(m_arrCommandButtons[i]);
	}

	ZOrder(&m_wndFooter);

	if (IsExpandFooterArea())
		ZOrder(&m_wndExpandedInformation);

}


void CXTPTaskDialogClient::ZOrder(CWnd* pWnd)
{
	if (!pWnd || !pWnd->GetSafeHwnd() )
		return;

	pWnd->SetWindowPos(&CWnd::wndBottom, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSIZE);
}

HICON CXTPTaskDialogClient::LoadSysIcon(PCWSTR lpwzIcon, CSize sizeIcon)
{
	DWORD dwID = 0;
	HICON hNewIcon = 0;

	if (m_bUseSysIcons)
	{
		switch ((ULONG_PTR)lpwzIcon)
		{
		case (ULONG_PTR)TD_ERROR_ICON:       dwID = 0x0067; break;
		case (ULONG_PTR)TD_WARNING_ICON:     dwID = 0x0065; break;
		case (ULONG_PTR)TD_INFORMATION_ICON: dwID = 0x0068; break;
		case (ULONG_PTR)TD_QUESTION_ICON:    dwID = 0x0066; break;
		case (ULONG_PTR)TD_SHIELD_ICON:      dwID = 0x006a; break; // vista and later.
		}

		hNewIcon = XTPResourceManager()->CreateIconFromResource(
			CXTPModuleHandle(_T("user32.dll")), MAKEINTRESOURCE(dwID), sizeIcon);
	}

	if (hNewIcon == NULL)
	{
		switch ((ULONG_PTR)lpwzIcon)
		{
		case (ULONG_PTR)TD_ERROR_ICON:       dwID = XTP_IDI_TASKERROR;  break;
		case (ULONG_PTR)TD_WARNING_ICON:     dwID = XTP_IDI_TASKWARN;   break;
		case (ULONG_PTR)TD_INFORMATION_ICON: dwID = XTP_IDI_TASKINFO;   break;
		case (ULONG_PTR)TD_SHIELD_ICON:      dwID = XTP_IDI_TASKSHIELD; break;
		case (ULONG_PTR)TD_QUESTION_ICON:    dwID = XTP_IDI_TASKQUESTION; break;
		}

		hNewIcon = XTPResourceManager()->LoadIcon(MAKEINTRESOURCE(dwID), sizeIcon);
	}
	return hNewIcon;
}

HICON CXTPTaskDialogClient::CreateIcon(HICON hIcon, PCWSTR lpwzIcon, CSize sizeIcon, BOOL bUseHandle)
{
	HICON hNewIcon = NULL;

	if (bUseHandle && hIcon != NULL)
	{
		hNewIcon = ::CopyIcon(hIcon);
	}
	else if (!bUseHandle)
	{
		if (m_pConfig->hInstance == NULL || lpwzIcon == NULL || !IS_INTRESOURCE(lpwzIcon))
		{
			return FALSE;
		}

		if (lpwzIcon == TD_ERROR_ICON ||
			lpwzIcon == TD_WARNING_ICON ||
			lpwzIcon == TD_INFORMATION_ICON ||
			lpwzIcon == TD_SHIELD_ICON ||
			lpwzIcon == TD_QUESTION_ICON)
		{
			hNewIcon = LoadSysIcon(lpwzIcon, sizeIcon);
		}
		else
		{
			hNewIcon = XTPResourceManager()->CreateIconFromResource(
				m_pConfig->hInstance, (LPTSTR)lpwzIcon, sizeIcon);
		}
	}

	ASSERT(hNewIcon != NULL);
	return hNewIcon;
}

void CXTPTaskDialogClient::CreateIcons()
{
	CXTPResourceManager::CManageState manageState; // Switch to Toolkit resources

	// create small icon.
	SAFE_DELETE_HICON(m_hIconFooter);
	m_hIconFooter = CreateIcon(m_pConfig->hFooterIcon, m_pConfig->pszFooterIcon, m_sizeIconFooter, IsFooterIconHandleUsed());

	// create large icon.
	SAFE_DELETE_HICON(m_hIconMain);
	m_hIconMain = CreateIcon(m_pConfig->hMainIcon, m_pConfig->pszMainIcon, m_sizeIconMain, IsMainIconHandleUsed());

	if (IsLinkButtonsUsed() && IsLinkButtonsIconVisible() && m_pIconLinkGlyph == 0)
	{
		m_pIconLinkGlyph = new CXTPImageManagerIcon(0, 20, 20);

		BOOL bRTLLayout = (m_pConfig->dwFlags & TDF_RTL_LAYOUT);

		CXTPImageManagerIconHandle hIconGlyph;
		CXTPImageManagerIconHandle hIconGlyphHot;

		HBITMAP hBitmap = (HBITMAP)CXTPImageManagerIcon::LoadAlphaBitmap(XTP_IDB_GLYPH);
		if (bRTLLayout)
		{
			hIconGlyph = CXTPImageManagerIcon::InvertAlphaBitmap(hBitmap);
			DeleteObject(hBitmap);
		}
		else
		{
			hIconGlyph = hBitmap;
		}

		hBitmap = (HBITMAP)CXTPImageManagerIcon::LoadAlphaBitmap(XTP_IDB_GLYPH_HOT);

		if (bRTLLayout)
		{
			hIconGlyphHot = CXTPImageManagerIcon::InvertAlphaBitmap(hBitmap);
			DeleteObject(hBitmap);
		}
		else
		{
			hIconGlyphHot = hBitmap;
		}

		m_pIconLinkGlyph->SetIcon(hIconGlyph);
		m_pIconLinkGlyph->SetHotIcon(hIconGlyphHot);
	}
}

void CXTPTaskDialogClient::CreateFonts()
{
	NONCLIENTMETRICS ncm;
	ncm.cbSize = sizeof(NONCLIENTMETRICS);
	::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);

	ncm.lfMenuFont.lfCharSet = XTPResourceManager()->GetFontCharset();
	ncm.lfCaptionFont.lfCharSet = XTPResourceManager()->GetFontCharset();

	m_font.DeleteObject();
	m_fontLarge.DeleteObject();

	if (m_bThemeReady)
	{
		CWindowDC dc(NULL);

		if (_tcscmp(ncm.lfMenuFont.lfFaceName, _T("Segoe UI")) == 0)
			ncm.lfMenuFont.lfQuality = 5;

		ncm.lfMenuFont.lfWeight = FW_NORMAL;
		ncm.lfMenuFont.lfItalic = 0;
		m_font.CreateFontIndirect(&ncm.lfMenuFont);

		ncm.lfMenuFont.lfHeight = ::MulDiv(-12, ::GetDeviceCaps(dc.m_hDC, LOGPIXELSY), 72);

		if (_tcscmp(ncm.lfMenuFont.lfFaceName, _T("Segoe UI")) != 0)
			ncm.lfMenuFont.lfWeight = FW_BOLD;
		m_fontLarge.CreateFontIndirect(&ncm.lfMenuFont);
	}
	else
	{
		m_font.CreateFontIndirect(&ncm.lfMenuFont);
		m_fontLarge.CreateFontIndirect(&ncm.lfCaptionFont);
	}
}

//---------------------------------------------------------------------------
// Button
//---------------------------------------------------------------------------

CButton *CXTPTaskDialogClient::CreateButton(int nButtonID, LPCTSTR lpszLabel, CSize sizeButton, DWORD dwButtonStyle /*=BS_PUSHBUTTON | BS_MULTILINE*/, CXTPButtonTheme* pTheme /*=NULL*/)
{
	CXTPButton* pButton = new CXTPButton;

	if (pTheme)
		dwButtonStyle |= BS_LEFT;

	CRect rcButton = XTPSize2Rect(sizeButton);
	if (!pButton->Create(lpszLabel, WS_CHILD | WS_VISIBLE |
		dwButtonStyle, rcButton, this, nButtonID))
	{
		SAFE_DELETE(pButton);
		return NULL;
	}
	m_mapWndSize[pButton] = sizeButton;

	if (pTheme)
	{
		pButton->SetTheme(pTheme);
	}

	pButton->SetFont(&m_font);

	if (m_pMarkupContext)
	{
		pButton->EnableMarkup();
	}

	return pButton;
}

CButton *CXTPTaskDialogClient::AddCommandButton(int nButtonID, int nIDLabel, CSize sizeButton)
{
	CString strButton;
	XTPResourceManager()->LoadString(&strButton, nIDLabel);
	ASSERT(!strButton.IsEmpty());

	return AddCommandButton(nButtonID, strButton, sizeButton);
}

CButton *CXTPTaskDialogClient::AddCommandButton(int nButtonID, LPCTSTR lpszLabel, CSize sizeButton)
{
	CButton* pButton = CreateButton(nButtonID, lpszLabel, sizeButton, BS_PUSHBUTTON | BS_MULTILINE | WS_TABSTOP);
	if (pButton)
	{
		m_arrCommandButtons.Add(pButton);
		return pButton;
	}

	return NULL;
}

CSize CXTPTaskDialogClient::CalcButtonSize(CString strButton, CPoint* pMarginButton /*=NULL*/, int nMaxWidth /*=0*/)
{
	CPoint ptMarginButton;
	ptMarginButton.x = m_ptBtnSpacing.x + m_ptMargin.x;
	ptMarginButton.y = m_ptPadding.y;

	if (pMarginButton == NULL)
		pMarginButton = &ptMarginButton;

	if (m_pMarkupContext)
	{
		CXTPMarkupUIElement* pUIElement = XTPMarkupParseText(m_pMarkupContext, strButton);
		if (pUIElement)
		{
			CSize sz = XTPMarkupMeasureElement(pUIElement, nMaxWidth == 0 ? INT_MAX : nMaxWidth);
			XTPMarkupReleaseElement(pUIElement);

			return CSize(sz.cx + pMarginButton->x * 2, sz.cy + pMarginButton->y * 2);
		}
	}

	CXTPEmptySize sizeCaptText;
	CString strCaptText = XTPExtractSubString(strButton, 0);
	if (!strCaptText.IsEmpty())
	{
		sizeCaptText.cx = nMaxWidth;

		XTPDrawHelpers()->StripMnemonics(strCaptText);

		if (nMaxWidth == 0)
			XTPCalcIdealTextSize(strCaptText, sizeCaptText, m_font, 330, 7);
		else
			XTPCalcTextSize(strCaptText, sizeCaptText, m_font);
	}

	CXTPEmptySize sizeNoteText;
	CString strNoteText = XTPExtractSubString(strButton, 1);
	if (!strNoteText.IsEmpty())
	{
		sizeNoteText.cx = nMaxWidth;

		if (nMaxWidth == 0)
			XTPCalcIdealTextSize(strNoteText, sizeNoteText, m_font, 330, 7);
		else
			XTPCalcTextSize(strNoteText, sizeNoteText, m_font);
	}

	CXTPEmptySize sizeButton;
	sizeButton.cx = max(sizeCaptText.cx, sizeNoteText.cx) + (pMarginButton->x * 2);
	sizeButton.cy = sizeCaptText.cy + sizeNoteText.cy + (pMarginButton->y * 2);

	return sizeButton;
}

CSize CXTPTaskDialogClient::CalcCommandButtonSize()
{
	CXTPEmptySize sizeCommon;

	for (int nIDString = XTP_IDS_TASK_OK; nIDString <= XTP_IDS_TASK_CLOSE; ++nIDString)
	{
		CString strButton;
		XTPResourceManager()->LoadString(&strButton, nIDString);
		ASSERT(!strButton.IsEmpty());

		CSize sizeButton = CalcButtonSize(strButton);
		sizeCommon.cx = max(sizeCommon.cx, sizeButton.cx);
		sizeCommon.cy = max(sizeCommon.cy, sizeButton.cy);
	}

	return sizeCommon;
}

int CXTPTaskDialogClient::CalcLinkButtonIdealWidth(CString strButton, int cxWidth)
{
	if (strButton.IsEmpty() || !HasLinkButtons())
		return 0;

	cxWidth -= ((m_ptMargin.x*2) + m_nPadding);

	if (m_pIconLinkGlyph)
		cxWidth -= m_pIconLinkGlyph->GetExtent().cx - m_nPadding;

	CStringMarkup strCaptText;
	strCaptText.m_pClient = this;
	strCaptText.SetCaption(XTPExtractSubString(strButton, 0));
	int nCaptionWidth = 0;

	if (strCaptText.m_pUIElement)
		nCaptionWidth = CalcIdealTextWidth(strCaptText, cxWidth, TRUE);
	else
	{
		CSize sizeText(cxWidth, 0);
		if (XTPCalcIdealTextSize(strCaptText, sizeText, m_fontLarge, 120, 30))
		{
			nCaptionWidth = sizeText.cx;
		}
	}

	CStringMarkup strNoteText;
	strNoteText.m_pClient = this;
	strNoteText.SetCaption(XTPExtractSubString(strButton, 1));
	int nNoteWidth = CalcIdealTextWidth(strNoteText, cxWidth, FALSE);

	cxWidth = max(nCaptionWidth, nNoteWidth);
	if (m_pIconLinkGlyph)
		cxWidth += m_pIconLinkGlyph->GetExtent().cx;

	return cxWidth + m_ptMargin.x * 2 + m_nPadding;
}

CSize CXTPTaskDialogClient::CalcLinkButtonSize(CXTPButton* pButton, CString strButton, int cxMaxWidth)
{
	if (strButton.IsEmpty() || !HasLinkButtons())
		return CXTPEmptySize();

	cxMaxWidth -= ((m_ptMargin.x*2) + m_nPadding);

	if (m_pIconLinkGlyph)
		cxMaxWidth -= m_pIconLinkGlyph->GetExtent().cx;


	// get the initial text size.
	CXTPEmptySize sizeButton;

	BOOL bWordWrap = FALSE;

	// extract the title string and determine text size.
	CString strCaptText = XTPExtractSubString(strButton, 0);
	CSize sizeCaptText(cxMaxWidth, 0);

	if (pButton->GetMarkupUIElement())
	{
		XTPMarkupSetDefaultFont(pButton->GetMarkupContext(), (HFONT)m_fontLarge.GetSafeHandle(), COLORREF_NULL);

		sizeCaptText = XTPMarkupMeasureElement(pButton->GetMarkupUIElement(), cxMaxWidth, INT_MAX);

	}
	else if (XTPCalcTextSize(strCaptText, sizeCaptText, m_fontLarge, &bWordWrap))
	{
		// if the string spans multiple rows, set the max width.
		if (bWordWrap)
			sizeCaptText.cx = cxMaxWidth;
	}
	else
	{
		sizeCaptText.cx = 0;
	}

	// extract the note string and determine text size.
	CString strNoteText = XTPExtractSubString(strButton, 1);
	CSize sizeNoteText(cxMaxWidth, 0);
	if (XTPCalcTextSize(strNoteText, sizeNoteText, m_font, &bWordWrap))
	{
		// if the string spans multiple rows, set the max width.
		if (bWordWrap)
			sizeNoteText.cx = cxMaxWidth;
	}
	else
	{
		sizeNoteText.cx = 0;
	}

	// add padding around text.
	sizeButton.cx = max(sizeCaptText.cx, sizeNoteText.cx) + m_ptMargin.x * 2 + m_nPadding;
	sizeButton.cy = sizeCaptText.cy + sizeNoteText.cy + m_ptMargin.y * 2 /*+ m_nPadding*/;

	return sizeButton;
}

BOOL CXTPTaskDialogClient::MoveButton(CButton* pButton, int x, int y, int cx, int cy, BOOL bRedraw /*=FALSE*/)
{
	// position the button.
	if (IsWindow(pButton) && pButton->SetWindowPos(NULL, x, y, cx, cy, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE))
	{
		// invalidate.
		if (bRedraw)
			pButton->RedrawWindow();

		return TRUE;
	}

	return FALSE;
}

void CXTPTaskDialogClient::SetCommandButtonPos()
{
	int x = m_rcCommandButtons.left, y = m_rcCommandButtons.top +  m_ptMargin.y - 1;

	int i, nCount = (int)m_arrCommandButtons.GetSize();
	for (i = 0; i < nCount; i++)
	{
		CButton* pButton = m_arrCommandButtons[i];

		CXTPEmptySize sizeButton;
		if (m_mapWndSize.Lookup(pButton, sizeButton))
		{
			// no more room, adjust height.
			if (x !=  m_rcCommandButtons.left && x + sizeButton.cx > m_rcCommandButtons.right)
			{
				x = m_rcCommandButtons.left;
				y += sizeButton.cy + m_ptBtnSpacing.y;
			}

			MoveButton(pButton, x, y, sizeButton.cx, sizeButton.cy);

			x += sizeButton.cx + m_ptBtnSpacing.x;
		}
	}
}

void CXTPTaskDialogClient::SetLinkButtonPos()
{
	int nTop = m_rcLinkButtons.top + m_ptMargin.x + m_ptPadding.y / 2 + 2;

	int nCount = (int)m_arrLinkButtons.GetSize();
	for (int i = 0; i < nCount; ++i)
	{
		CSize sizeButton;
		if (m_mapWndSize.Lookup(m_arrLinkButtons[i], sizeButton))
		{
			MoveButton(m_arrLinkButtons[i], m_rcLinkButtons.left, nTop, m_rcLinkButtons.Width(), sizeButton.cy);
			nTop += sizeButton.cy;
		}
	}
}

void CXTPTaskDialogClient::SetVerifyButtonPos()
{
	CXTPEmptySize sizeVerify;
	if (IsWindow(m_pBtnVerify) && m_mapWndSize.Lookup(m_pBtnVerify, sizeVerify))
	{
		CXTPEmptyRect rcButton;
		rcButton.left = m_ptMargin.x + 3;
		rcButton.right = rcButton.left + sizeVerify.cx;

		// vertically center.
		rcButton.top = m_rcCommandButtons.top + (m_rcCommandButtons.Height() - sizeVerify.cy)/2;

		CXTPEmptySize sizeExpando;
		if (IsWindow(m_pBtnExpando) && m_mapWndSize.Lookup(m_pBtnExpando, sizeExpando))
		{
			rcButton.top = m_rcCommandButtons.top + m_ptMargin.y + sizeExpando.cy;
		}

		rcButton.bottom = rcButton.top + sizeVerify.cy;
		MoveButton(m_pBtnVerify, rcButton);
	}
}

void CXTPTaskDialogClient::SetExpandoButtonPos()
{
	CXTPEmptySize sizeExpando;
	if (IsWindow(m_pBtnExpando) && m_mapWndSize.Lookup(m_pBtnExpando, sizeExpando))
	{
		CXTPEmptyRect rcButton;
		rcButton.left = m_ptMargin.x + 3;
		rcButton.right = rcButton.left + sizeExpando.cx;

		// vertically center.
		rcButton.top = m_rcCommandButtons.top + (m_rcCommandButtons.Height()-sizeExpando.cy)/2;

		CXTPEmptySize sizeVerify;
		if (IsWindow(m_pBtnVerify) && m_mapWndSize.Lookup(m_pBtnVerify, sizeVerify))
		{
			rcButton.top = m_rcCommandButtons.top + m_ptMargin.y;
		}

		rcButton.bottom = rcButton.top + sizeExpando.cy;
		MoveButton(m_pBtnExpando, rcButton);
	}
}

void CXTPTaskDialogClient::SetLinkCtrlPos()
{
	if (IsHyperlinksEnabled())
	{
		if (m_wndContent) m_wndContent.MoveWindow(m_rcContent);
		if (m_wndExpandedInformation) m_wndExpandedInformation.MoveWindow(m_rcExpandedInformation);
		if (m_wndFooter) m_wndFooter.MoveWindow(m_rcFooter);

		if (m_wndExpandedInformation) m_wndExpandedInformation.ShowWindow(m_bExpanded ? SW_SHOWNOACTIVATE : SW_HIDE);
	}
}

//---------------------------------------------------------------------------
// Layout
//---------------------------------------------------------------------------

int CXTPTaskDialogClient::CalcIdealTextWidth(const CStringMarkup& strItemText, int nMinWidth, BOOL bLargeFont)
{
	if (strItemText.IsEmpty())
		return nMinWidth;

	CSize sizeText(nMinWidth, 0);

	if (strItemText.m_pUIElement)
	{
		if (XTPCalcIdealTextSize(m_pMarkupContext, strItemText.m_pUIElement, sizeText,
			bLargeFont? m_fontLarge: m_font,
			bLargeFont? 275: 330,
			bLargeFont? 14: 7))
		{
			nMinWidth = max(nMinWidth, sizeText.cx);
		}
	}
	else
	{
		if (XTPCalcIdealTextSize(strItemText, sizeText,
			bLargeFont? m_fontLarge: m_font,
			bLargeFont? 275: 330,
			bLargeFont? 14: 7))
		{
			nMinWidth = max(nMinWidth, sizeText.cx);
		}
	}
	return nMinWidth;
}
CRect CXTPTaskDialogClient::CalcTextRect(const CStringMarkup& strItemText, int nWidth, BOOL bLargeFont)
{
	CRect rcItemText(0, 0, 0, 0);

	if (strItemText.m_pUIElement)
	{
		XTPMarkupSetDefaultFont(m_pMarkupContext, bLargeFont? m_fontLarge: m_font, COLORREF_NULL);

		CSize sizeText = XTPMarkupMeasureElement(strItemText.m_pUIElement, nWidth, INT_MAX);
		rcItemText.SetRect(0, 0, nWidth, sizeText.cy);
	}
	else
	{
		CSize sizeText(nWidth, 0);
		if (XTPCalcTextSize(strItemText, sizeText, bLargeFont? m_fontLarge: m_font))
		{
			rcItemText.SetRect(0, 0, nWidth, sizeText.cy);
		}
	}

	return rcItemText;
}

CRect CXTPTaskDialogClient::CalcCommandRect(int nWidth)
{
	CRect rcCommand(0, 0, nWidth, 0);

	if (m_pBtnExpando == 0 && m_pBtnVerify == 0 && m_arrCommandButtons.GetSize() == 0)
		return rcCommand;

	int nMinHeight = 0;
	int nLeftMargin = 0;

	CXTPEmptySize sizeButton;
	if (m_pBtnVerify && m_mapWndSize.Lookup(m_pBtnVerify, sizeButton))
	{
		nMinHeight = sizeButton.cy;
		nLeftMargin = sizeButton.cx;
	}

	if (m_pBtnExpando && m_mapWndSize.Lookup(m_pBtnExpando, sizeButton))
	{
		nMinHeight += sizeButton.cy;
		nLeftMargin = max(nLeftMargin, sizeButton.cx);
	}

	if (nLeftMargin)
		nWidth -= nLeftMargin + m_ptBtnSpacing.x;

	int i, nCount = (int)m_arrCommandButtons.GetSize();
	int x = 0;
	int nMaxWidth = 0;

	for (i = 0; i < nCount; i++)
	{
		CButton* pButton = m_arrCommandButtons[i];

		if (m_mapWndSize.Lookup(pButton, sizeButton))
		{
			// no more room, adjust height.
			if (x != 0 && x + sizeButton.cx > nWidth)
			{
				nMaxWidth = max(nMaxWidth, x - m_ptBtnSpacing.x);
				x = 0;
				rcCommand.bottom += m_ptBtnSpacing.y;
			}

			// first button in row, adjust height.
			if (x == 0)
				rcCommand.bottom += sizeButton.cy;

			x += sizeButton.cx + m_ptBtnSpacing.x;
		}
	}
	nMaxWidth = max(nMaxWidth, x - m_ptBtnSpacing.x);

	rcCommand.left = nWidth - nMaxWidth;
	if (nLeftMargin)
		rcCommand.left += nLeftMargin + m_ptBtnSpacing.x;

	if (nMinHeight > rcCommand.Height())
		rcCommand.bottom = rcCommand.top + nMinHeight;

	rcCommand.bottom += m_ptMargin.y * 2 - 2;

	return rcCommand;
}

int CXTPTaskDialogClient::CalcClientWidth()
{
	int nIdealWidth = m_nMinClientWidth;

	if (HasFixedWidth())
	{
		CSize sizeBase = ::GetDialogBaseUnits();
		int cxWidth = ::MulDiv(m_pConfig->cxWidth, sizeBase.cx, 4);

		nIdealWidth = max(cxWidth - m_ptMargin.x * 2, nIdealWidth);
		return nIdealWidth;
	}

	int nCommandButtonWidth = -m_ptBtnSpacing.x + m_ptMargin.x * 2, nCount, i;

	nCount = (int)m_arrCommandButtons.GetSize();
	for (i = 0; i < nCount; ++i)
	{
		CSize size;
		if (m_mapWndSize.Lookup(m_arrCommandButtons[i], size))
			nCommandButtonWidth += size.cx + m_ptBtnSpacing.x;
	}

	if (!HasLinkButtons())
	{
		nIdealWidth = max(nIdealWidth, nCommandButtonWidth);
	}

	if (m_pBtnVerify->GetSafeHwnd())
	{
		CSize size;
		if (m_mapWndSize.Lookup(m_pBtnVerify, size))
		{
			nIdealWidth = max(nIdealWidth, size.cx + nCommandButtonWidth + m_ptMargin.x);
		}
	}

	if (m_pBtnExpando->GetSafeHwnd())
	{
		CSize size;
		if (m_mapWndSize.Lookup(m_pBtnExpando , size))
		{
			nIdealWidth = max(nIdealWidth, size.cx + nCommandButtonWidth + m_ptMargin.x);
		}
	}

	int nMainIconMargin = (m_hIconMain ? (m_sizeIconMain.cx + m_ptMargin.x): 0);
	int nFooterIconMargin = (m_hIconFooter ? (m_sizeIconFooter.cx + m_ptMargin.x): 0);
	int nExpanIconMargin = IsExpandFooterArea() ? nFooterIconMargin : nMainIconMargin;

	nCount = (int)m_arrRadioButtons.GetSize();
	for (i = 0; i < nCount; ++i)
	{
		CSize size;
		if (m_mapWndSize.Lookup(m_arrRadioButtons[i], size))
			nIdealWidth = max(nIdealWidth, size.cx + nMainIconMargin);
	}



	CXTPEmptySize size;
	if (m_mapWndSize.Lookup(m_pBtnVerify, size))
		nIdealWidth = max(nIdealWidth, size.cx);

	if (m_mapWndSize.Lookup(m_pBtnExpando, size))
		nIdealWidth = max(nIdealWidth, size.cx);


	int nWidth = CalcIdealTextWidth(m_strMainInstruction, nIdealWidth - nMainIconMargin, TRUE);
	nIdealWidth = max(nIdealWidth, nWidth + nMainIconMargin);

	nWidth = CalcIdealTextWidth(m_strContent, nIdealWidth - nMainIconMargin, FALSE);
	nIdealWidth = max(nIdealWidth, nWidth + nMainIconMargin);

	if (HasLinkButtons())
	{
		for (i = 0; i < (int)m_pConfig->cButtons; ++i)
		{
			CString strButton = LoadItemString(m_pConfig->pButtons[i].pszButtonText);

			nWidth = CalcLinkButtonIdealWidth(strButton, nIdealWidth - nMainIconMargin);
			nIdealWidth = max(nIdealWidth, 2 + nWidth + nMainIconMargin);
		}
	}


	nWidth = CalcIdealTextWidth(m_strExpandedInformation, nIdealWidth - nExpanIconMargin, FALSE);
	nIdealWidth = max(nIdealWidth, nWidth + nExpanIconMargin);

	nWidth = CalcIdealTextWidth(m_strFooter, nIdealWidth - nFooterIconMargin, FALSE);
	nIdealWidth = max(nIdealWidth, nWidth + nFooterIconMargin);

	nIdealWidth = min(nIdealWidth, m_nMaxClientWidth);

	return nIdealWidth;
}


CSize CXTPTaskDialogClient::CalcDynamicLayout(int nIdealWidth)
{
	int nMainIconMargin = m_hIconMain ? (m_sizeIconMain.cx + m_ptMargin.x) : 0;
	int nFooterIconMargin = m_hIconFooter ? (m_sizeIconFooter.cx + m_ptMargin.x) : 0;

	m_rcMainInstruction = CalcTextRect(m_strMainInstruction, nIdealWidth - nMainIconMargin, TRUE);
	if (!m_rcMainInstruction.IsRectEmpty())
		m_rcMainInstruction.OffsetRect(m_ptMargin.x + nMainIconMargin, m_ptMargin.y);

	m_rcContent = CalcTextRect(m_strContent, nIdealWidth - nMainIconMargin, FALSE);
	m_rcContent.OffsetRect(m_ptMargin.x + nMainIconMargin,
		m_rcMainInstruction.bottom + m_ptMargin.y + 1);

	int nLinkTop = m_rcContent.bottom + m_ptPadding.y;

	if (nLinkTop < m_ptMargin.y * 4 - 3)
		nLinkTop = m_ptMargin.y * 4 - 3;

	if (!IsExpandFooterArea())
	{
		if (!m_strExpandedInformation.IsEmpty())
		{
			if (m_bExpanded)
			{
				m_rcExpandedInformation = CalcTextRect(m_strExpandedInformation, nIdealWidth - nMainIconMargin, FALSE);
				m_rcExpandedInformation.OffsetRect(m_ptMargin.x + nMainIconMargin, nLinkTop + m_ptPadding.y);
			}
			else
			{
				m_rcExpandedInformation.SetRect(m_rcContent.left, nLinkTop, m_rcContent.right, nLinkTop + m_ptPadding.y);
			}

			nLinkTop += m_rcExpandedInformation.Height() + m_ptPadding.y;
		}
		else
		{
			m_rcExpandedInformation.SetRect(m_rcContent.left, nLinkTop, m_rcContent.right, nLinkTop);
		}
	}

	if (m_wndProgressBar.GetSafeHwnd())
	{
		CRect rcProgressBar(m_rcContent.left, nLinkTop + m_ptMargin.y, nIdealWidth + m_ptMargin.x, nLinkTop + m_ptMargin.y * 5/2);
		m_wndProgressBar.MoveWindow(rcProgressBar);

		nLinkTop += rcProgressBar.Height() + m_ptMargin.y;
	}

	if (m_arrRadioButtons.GetSize() > 0)
	{
		nLinkTop +=  m_ptMargin.y;
		m_rcRadioButtons = CRect(m_rcContent.left + m_ptMargin.x, nLinkTop, nIdealWidth, nLinkTop);

		for (int i = 0; i < m_arrRadioButtons.GetSize(); i++)
		{
			CButton* pButton = m_arrRadioButtons[i];

			CSize sizeButton;
			if (m_mapWndSize.Lookup(pButton, sizeButton))
			{
				pButton->MoveWindow(m_rcRadioButtons.left, nLinkTop, sizeButton.cx, sizeButton.cy);

				nLinkTop += sizeButton.cy + 3;
			}
		}
		m_rcRadioButtons.bottom = nLinkTop;
	}
	else
	{
		m_rcRadioButtons = CRect(m_rcContent.left + 1, nLinkTop, m_rcContent.right, nLinkTop);
	}

	if (m_wndInputBox.GetSafeHwnd())
	{
		CRect rcInputBox(m_rcContent.left, nLinkTop + m_ptMargin.y, nIdealWidth + m_ptMargin.x, nLinkTop + m_ptMargin.y + m_ptMargin.y * 2);
		m_wndInputBox.MoveWindow(rcInputBox);

		nLinkTop += rcInputBox.Height() + m_ptMargin.y;
	}

	m_rcLinkButtons = CRect(m_rcContent.left + 1, nLinkTop + 1, m_ptMargin.y + nIdealWidth - 1, nLinkTop + 1);

	for (int i = 0; i < (int)m_arrLinkButtons.GetSize(); ++i)
	{
		CString strButton = LoadItemString(m_pConfig->pButtons[i].pszButtonText);
		CButton* pButton = m_arrLinkButtons[i];

		CSize sizeButton = CalcLinkButtonSize((CXTPButton*)pButton, strButton, m_rcLinkButtons.Width());
		sizeButton.cx = m_rcLinkButtons.Width();

		m_mapWndSize[pButton] = sizeButton;

		m_rcLinkButtons.bottom += sizeButton.cy;
	}
	if (m_arrLinkButtons.GetSize() > 0) m_rcLinkButtons.bottom += m_ptMargin.y;

	m_rcCommandButtons = CalcCommandRect(nIdealWidth);
	m_rcCommandButtons.OffsetRect(m_ptMargin.x, m_rcLinkButtons.bottom  + m_ptMargin.y + m_ptPadding.y);

	int nBottom = m_rcCommandButtons.bottom;
	if (!m_strFooter.IsEmpty())
	{
		m_rcFooter = CalcTextRect(m_strFooter, nIdealWidth - nFooterIconMargin, FALSE);
		m_rcFooter.OffsetRect(m_ptMargin.x + nFooterIconMargin - 1, nBottom + m_ptMargin.y + 1);

		nBottom += m_rcFooter.Height() + 2 * m_ptMargin.y + 1;
	}

	if (IsExpandFooterArea())
	{
		if (!m_strExpandedInformation.IsEmpty() && m_bExpanded)
		{
			m_rcExpandedInformation = CalcTextRect(m_strExpandedInformation, nIdealWidth, FALSE);
			m_rcExpandedInformation.OffsetRect(m_ptMargin.x, nBottom + m_ptMargin.y);
			nBottom += m_rcExpandedInformation.Height() + 2 * m_ptMargin.y;
		}
		else
		{
			m_rcExpandedInformation.SetRect(m_rcFooter.left, nBottom, m_rcFooter.right, nBottom);
		}

	}

	return CSize(nIdealWidth + m_ptMargin.x * 2, nBottom);
}

void CXTPTaskDialogClient::RecalcLayout(BOOL bMoveWindow)
{
	UpdateZOrder();

	CSize szClient = CalcDynamicLayout(CalcClientWidth());

	SetCommandButtonPos();
	SetLinkButtonPos();
	SetVerifyButtonPos();
	SetExpandoButtonPos();
	SetLinkCtrlPos();

	m_strContent.SetFinalRect(m_rcContent);
	m_strMainInstruction.SetFinalRect(m_rcMainInstruction);
	m_strExpandedInformation.SetFinalRect(m_rcExpandedInformation);
	m_strFooter.SetFinalRect(m_rcFooter);

	ResizeParentToFit(szClient, bMoveWindow);
	RedrawWindow(0, 0, RDW_ALLCHILDREN | RDW_INVALIDATE);
}

BOOL CXTPTaskDialogClient::ResizeParentToFit(CSize szClient, BOOL bMoveWindow)
{
	CXTPWindowRect rc(this);

	CRect rcParent = IsPositionRelativeToWindow()?
		CXTPWindowRect(m_pConfig->hwndParent): XTPMultiMonitor()->GetWorkArea(m_pConfig->hwndParent);

	CPoint ptPos((rcParent.left + rcParent.right - szClient.cx) / 2 - 3,
		(rcParent.top + rcParent.bottom - szClient.cy) / 2 - 12);

	CRect rcWindow(ptPos, szClient);

	AdjustWindowRectEx(rcWindow, GetStyle(), FALSE, GetExStyle());
	//rcWindow.InflateRect(m_ptMargin.x, m_ptMargin.y);

	if (bMoveWindow)
		MoveWindow(rcWindow);
	else
		SetWindowPos(0, 0, 0, rcWindow.Width(), rcWindow.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
	return TRUE;
}

//---------------------------------------------------------------------------
// Rendering
//---------------------------------------------------------------------------

void CXTPTaskDialogClient::DrawBackground(CDC* pDC, CRect rect)
{
	pDC->FillSolidRect(&rect, m_crFooter);

	if (m_bThemeReady)
	{
		pDC->FillSolidRect(rect.left, rect.top, rect.Width(), m_rcCommandButtons.top, m_crContent);

		if (m_rcCommandButtons.top != m_rcCommandButtons.bottom)
		{
			pDC->FillSolidRect(rect.left, m_rcCommandButtons.top,  rect.Width(), 1, m_cr3DLight);
		}

		if (!m_rcFooter.IsRectEmpty())
		{
			pDC->FillSolidRect(rect.left, m_rcCommandButtons.bottom,  rect.Width(), 1, m_cr3DLight);
			pDC->FillSolidRect(rect.left, m_rcCommandButtons.bottom + 1,  rect.Width(), 1, m_cr3DHighLight);
		}

		if (m_bExpanded && !m_strExpandedInformation.IsEmpty() && IsExpandFooterArea() && !m_rcExpandedInformation.IsRectEmpty())
		{
			pDC->FillSolidRect(rect.left, m_rcExpandedInformation.top - m_ptMargin.y,  rect.Width(), 1, m_cr3DLight);
			pDC->FillSolidRect(rect.left, m_rcExpandedInformation.top - m_ptMargin.y + 1,  rect.Width(), 1, m_cr3DHighLight);
		}
	}
	else
	{
		if (!m_rcFooter.IsRectEmpty())
		{
			pDC->FillSolidRect(rect.left, m_rcCommandButtons.bottom + 1, rect.Width(), 1, m_cr3DShadow);
		}
		if (m_bExpanded && !m_strExpandedInformation.IsEmpty() && IsExpandFooterArea() && !m_rcExpandedInformation.IsRectEmpty())
		{
			pDC->FillSolidRect(rect.left, m_rcExpandedInformation.top - m_ptMargin.y,  rect.Width(), 1, m_cr3DShadow);
		}
	}
}

void CXTPTaskDialogClient::DrawIcon(CDC* pDC, HICON hIcon, CPoint pt, CSize sz)
{
	DWORD dwLayout = XTPDrawHelpers()->IsContextRTL(pDC);
	if (dwLayout & LAYOUT_RTL)
		XTPDrawHelpers()->SetContextRTL(pDC, dwLayout | LAYOUT_BITMAPORIENTATIONPRESERVED);

	::DrawIconEx(*pDC, pt.x, pt.y, hIcon, sz.cx, sz.cy, 0, NULL, DI_NORMAL);

	if (dwLayout & LAYOUT_RTL)
		XTPDrawHelpers()->SetContextRTL(pDC, dwLayout);

}

void CXTPTaskDialogClient::DrawText(CDC* pDC, const CStringMarkup& strItemText, CRect rcItem, COLORREF clrText, CFont* pFont)
{
	if (!rcItem.IsRectEmpty() && !strItemText.IsEmpty())
	{
		if (strItemText.m_pUIElement)
		{
			XTPMarkupSetDefaultFont(m_pMarkupContext, (HFONT)pFont->GetSafeHandle(), clrText);
			XTPMarkupRenderElement(strItemText.m_pUIElement, pDC->GetSafeHdc(), strItemText.m_rcFinalRect);
		}
		else
		{
			pDC->SetTextColor(clrText);

			CXTPFontDC fontDC(pDC, pFont);
			pDC->DrawText(strItemText, rcItem, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_TOP);
		}
	}
}

void CXTPTaskDialogClient::DrawMainInstruction(CDC* pDC)
{
	if (m_hIconMain)
	{
		DrawIcon(pDC, m_hIconMain, m_ptMargin, m_sizeIconMain);
	}

	DrawText(pDC, m_strMainInstruction, m_rcMainInstruction, m_crMainText, &m_fontLarge);
}

void CXTPTaskDialogClient::DrawContent(CDC* pDC)
{
	if (m_rcContent.IsRectEmpty())
		return;

	if (!::IsWindow(m_wndContent.m_hWnd))
	{
		DrawText(pDC, m_strContent, m_rcContent, m_crContentText, &m_font);
	}
}

void CXTPTaskDialogClient::DrawExpandedInfo(CDC* pDC)
{
	if (m_rcExpandedInformation.IsRectEmpty() || m_strExpandedInformation.IsEmpty() || !m_bExpanded)
		return;

	if (!::IsWindow(m_wndExpandedInformation.m_hWnd))
	{
		DrawText(pDC, m_strExpandedInformation, m_rcExpandedInformation, IsExpandFooterArea() ? m_crFooterText : m_crContentText, &m_font);
	}
}

void CXTPTaskDialogClient::DrawFootNote(CDC* pDC)
{
	if (m_rcFooter.IsRectEmpty())
		return;

	if (m_hIconFooter)
	{
		DrawIcon(pDC, m_hIconFooter, CPoint(m_ptMargin.x + 2, m_rcFooter.top), m_sizeIconFooter);
	}

	if (!::IsWindow(m_wndFooter.m_hWnd))
	{
		DrawText(pDC, m_strFooter, m_rcFooter, m_crFooterText, &m_font);
	}
}

void CXTPTaskDialogClient::OnExpandExpandoClicked()
{
	if (!m_pBtnExpando)
		return;

	CString strButtonText = m_bExpanded ? m_strExpandedControlText: m_strCollapsedControlText;
	m_pBtnExpando->SetWindowText(strButtonText);
	m_pBtnExpando->SetChecked(m_bExpanded);

	RecalcLayout();
}

void CXTPTaskDialogClient::OnInputBoxChanged()
{
	SendNotify(TDN_INPUTBOX_CHANGED);
}