/** * @file XTPTaskDialogClient.cpp * * @copyright * (c) 1998-2025 Codejock Software, All Rights Reserved. * * This source file is the property of Codejock Software and must not be * redistributed by any means without the explicit written permission of * Codejock Software. * * The use of this source code is governed by the terms and conditions specified * in the Toolkit Pro license agreement. Codejock Software grants you, as a * single software developer, the limited right to use this software on one * computer only. * * Contact Information: * support@codejock.com * http://www.codejock.com * */ #include "stdafx.h" #include "Controls/Resource.h" #include "Common/XTPTypeId.h" #include "Common/XTPCasting.h" #include "Common/XTPFramework.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPSynchro.h" #include "Common/XTPApplication.h" #include "Common/XTPSingleton.h" #include "Common/XTPGdiObjects.h" #include "Common/XTPImageManager.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPResourceManager.h" #include "Common/XTPMarkupRender.h" #include "Common/XTPColorManager.h" #include "Common/XTPWinThemeWrapper.h" #include "Common/XTPSystemMetrics.h" #include "Common/Base/Types/XTPSize.h" #include "Controls/Util/XTPControlTheme.h" #include "Controls/Button/XTPButtonTheme.h" #include "Controls/Dialog/XTPTaskDialogControls.h" #include "Controls/Button/XTPButton.h" #ifdef _XTP_INCLUDE_MARKUP # include # include "Markup/XTPMarkupObject.h" # include "Markup/XTPMarkupInputElement.h" # include "Markup/XTPMarkupFrameworkContentElement.h" # include "Markup/XTPMarkupString.h" # include "Markup/XTPMarkupRoutedEventArgs.h" # include "Markup/XTPMarkupContext.h" # include "Markup/XTPMarkupDelegate.h" # include "Markup/Text/XTPMarkupTextElement.h" # include "Markup/Text/XTPMarkupInline.h" # include "Markup/Text/XTPMarkupSpan.h" # include "Markup/Text/XTPMarkupHyperlink.h" #endif #include "Controls/Dialog/XTPTaskDialogAPI.h" #include "Controls/Dialog/XTPTaskDialogClient.h" #include "Common/Base/Diagnostic/XTPDisableNoisyWarnings.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(XTP_DPI_X(2)) , m_bExpanded(FALSE) , m_bVerification(FALSE) , m_bUseSysIcons(FALSE) , m_bThemeReady(FALSE) , m_hIconFooter(NULL) , m_hIconMain(NULL) , m_pImageManager(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_pConfig(NULL) , m_pBtnVerify(NULL) , m_pBtnExpando(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_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; m_pImageManager = new CXTPImageManager(); } #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); 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); 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, TRUE); m_mapWndSize.RemoveAll(); } CXTPTaskDialogClient::~CXTPTaskDialogClient() { DeleteControls(); DestroyWindow(); SAFE_DELETE(m_pImageManager); } #include "Common/Base/Diagnostic/XTPBeginAfxMap.h" 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() #include "Common/Base/Diagnostic/XTPEndAfxMap.h" //--------------------------------------------------------------------------- // 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 CXTPMarkupHyperlink* pHyperLink = MARKUP_DYNAMICCAST(CXTPMarkupHyperlink, pSender); if (NULL != pHyperLink) { CXTPMarkupString* pTag = MARKUP_DYNAMICCAST(CXTPMarkupString, pHyperLink->GetTag()); if (NULL != pTag) { 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) && m_strMainInstruction.m_pUIElement) { if (XTPMarkupRelayMessage(m_strMainInstruction.m_pUIElement, message, wParam, lParam, pResult)) return TRUE; } else if (m_strContent.m_rcFinalRect.PtInRect(ptMouse) && m_strContent.m_pUIElement) { if (XTPMarkupRelayMessage(m_strContent.m_pUIElement, message, wParam, lParam, pResult)) return TRUE; } else if (m_strFooter.m_rcFinalRect.PtInRect(ptMouse) && m_strFooter.m_pUIElement) { if (XTPMarkupRelayMessage(m_strFooter.m_pUIElement, message, wParam, lParam, pResult)) return TRUE; } else if (m_strExpandedInformation.m_rcFinalRect.PtInRect(ptMouse) && m_strExpandedInformation.m_pUIElement) { 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, XTPToWPARAM(m_bVerification)); return 0; } if (hWnd && m_pBtnExpando->GetSafeHwnd() == hWnd) { m_bExpanded = !m_bExpanded; SendNotify(TDN_EXPANDO_BUTTON_CLICKED, XTPToWPARAM(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 = XTPSystemMetrics()->GetSmallIconSize(); m_sizeIconMain = XTPSystemMetrics()->GetIconSize(); m_ptMargin = XTPDlu2Pix(XTP_DPI_X(xtpDluMargin), XTP_DPI_X(xtpDluMargin)); m_ptPadding = XTPDlu2Pix(XTP_DPI_X(xtpDluPadding), XTP_DPI_X(xtpDluPadding)); m_ptBtnSpacing = CPoint(XTPDlu2Pix(XTP_DPI_X(xtpDluBtnSpacing), XTP_DPI_X(xtpDluBtnSpacing)).x, 0); if (!m_bThemeReady) m_ptBtnSpacing = CPoint(m_ptMargin.x, 2); m_nMinClientWidth = XTPDlu2Pix(XTP_DPI_X(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 && XTP_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); _ASSERTE(!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_xtpFontLarge); 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_pImageManager->Lookup(xtpTaskDialogIconRight)) { CXTPButton* pButton = DYNAMIC_DOWNCAST(CXTPButton, pLinkButton); if (pButton == NULL) { TRACE0("Error creating command link button.\n"); SAFE_DELETE(pButton); return FALSE; } CXTPImageManagerIcon* pIcon = m_pImageManager->GetImage(xtpTaskDialogIconRight); if (pIcon) { CSize sz(pIcon->GetRecommendedExtent().cx, pIcon->GetRecommendedExtent().cx); pButton->SetIcon(sz, pIcon); pIcon->InternalAddRef(); } } 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( DWORD(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_xtpFont); 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(XTP_DPI_X(10), XTP_DPI_Y(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(XTP_DPI_X(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(XTP_DPI_X(10), XTP_DPI_Y(2)); CSize sizeButton = CalcButtonSize(strButtonText, &point, XTPDlu2Pix(XTP_DPI_X(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); #ifdef _XTP_INCLUDE_MARKUP CXTPButton* pXtpButton = DYNAMIC_DOWNCAST(CXTPButton, pButton); if (NULL != pXtpButton && NULL != pXtpButton->GetMarkupContext()) { pXtpButton->GetMarkupContext()->AddHandler( CXTPMarkupHyperlink::m_pClickEvent, CreateMarkupClassDelegate(this, &CXTPTaskDialogClient::OnMarkupHyperlinkClick)); } #endif } return TRUE; } BOOL CXTPTaskDialogClient::CreateClient(BOOL bMoveWindow) { DeleteControls(); if (m_bEnableMarkup) { m_pMarkupContext = XTPMarkupCreateContext(m_hWnd, TRUE); } #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_xtpFont, this); m_wndExpandedInformation.Create(rect, m_strExpandedInformation.m_strCaption, &m_xtpFont, this); m_wndFooter.Create(rect, m_strFooter.m_strCaption, &m_xtpFont, 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. } static CXTPModuleHandle modUser32Dll; if (modUser32Dll.LoadLibrary(_T("user32.dll"))) { hNewIcon = XTPResourceManager()->CreateIconFromResource(modUser32Dll, 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 || !XTP_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); } } _ASSERTE(hNewIcon != NULL); return hNewIcon; } void CXTPTaskDialogClient::CreateIcons() { CXTPResourceManager::CManageState manageState; // Switch to Toolkit resources manageState.Undo(); // 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()); CString type = _T("RT_XAML"); HMODULE hModule = XTPResourceManager()->GetResourceHandle(); if (IsLinkButtonsUsed() && IsLinkButtonsIconVisible() && m_pImageManager->Lookup(xtpTaskDialogIconRight) == FALSE) { m_pImageManager->SetVectorIcon(hModule, type, IDR_XAML_ICON_TASKDLG_ARROW_RIGHT, xtpTaskDialogIconRight, XTPToUIntChecked(XTP_DPI_X(20))); } manageState.Redo(); } void CXTPTaskDialogClient::CreateFonts() { CXTPNonClientMetrics ncm; ncm.lfMenuFont.lfCharSet = XTPResourceManager()->GetFontCharset(); ncm.lfCaptionFont.lfCharSet = XTPResourceManager()->GetFontCharset(); m_xtpFont.DeleteObject(); m_xtpFontLarge.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_xtpFont.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_xtpFontLarge.CreateFontIndirect(&ncm.lfMenuFont); } else { m_xtpFont.CreateFontIndirect(&ncm.lfMenuFont); m_xtpFontLarge.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, static_cast(nButtonID))) { SAFE_DELETE(pButton); return NULL; } m_mapWndSize[pButton] = sizeButton; if (pTheme) { pButton->SetTheme(pTheme); } pButton->SetFont(&m_xtpFont); if (m_pMarkupContext) { pButton->EnableMarkup(); } return pButton; } CButton* CXTPTaskDialogClient::AddCommandButton(int nButtonID, int nIDLabel, CSize sizeButton) { CString strButton; XTPResourceManager()->LoadString(&strButton, XTPToUInt(nIDLabel)); _ASSERTE(!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_xtpFont, XTP_DPI_X(330), XTP_DPI_X(7)); else XTPCalcTextSize(strCaptText, sizeCaptText, m_xtpFont); } CXTPEmptySize sizeNoteText; CString strNoteText = XTPExtractSubString(strButton, 1); if (!strNoteText.IsEmpty()) { sizeNoteText.cx = nMaxWidth; if (nMaxWidth == 0) XTPCalcIdealTextSize(strNoteText, sizeNoteText, m_xtpFont, XTP_DPI_X(330), XTP_DPI_X(7)); else XTPCalcTextSize(strNoteText, sizeNoteText, m_xtpFont); } 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 (UINT nIDString = UINT(XTP_IDS_TASK_OK); nIDString <= UINT(XTP_IDS_TASK_CLOSE); ++nIDString) { CString strButton; XTPResourceManager()->LoadString(&strButton, nIDString); _ASSERTE(!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_pImageManager->Lookup(xtpTaskDialogIconRight)) cxWidth -= m_pImageManager->GetImage(xtpTaskDialogIconRight)->GetRecommendedExtent().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_xtpFontLarge, XTP_DPI_X(120), XTP_DPI_X(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_pImageManager->Lookup(xtpTaskDialogIconRight)) cxWidth += m_pImageManager->GetImage(xtpTaskDialogIconRight)->GetRecommendedExtent().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_pImageManager->Lookup(xtpTaskDialogIconRight)) cxMaxWidth -= m_pImageManager->GetImage(xtpTaskDialogIconRight)->GetRecommendedExtent().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_xtpFontLarge.GetSafeHandle(), COLORREF_NULL); sizeCaptText = XTPMarkupMeasureElement(pButton->GetMarkupUIElement(), cxMaxWidth, INT_MAX); } else if (XTPCalcTextSize(strCaptText, sizeCaptText, m_xtpFontLarge, &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_xtpFont, &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 - XTP_DPI_X(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 + XTP_DPI_Y(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 + XTP_DPI_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 + XTP_DPI_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_xtpFontLarge : m_xtpFont, XTP_DPI_X(bLargeFont ? 275 : 330), XTP_DPI_X(bLargeFont ? 14 : 7))) { nMinWidth = max(nMinWidth, sizeText.cx); } } else { if (XTPCalcIdealTextSize(strItemText, sizeText, bLargeFont ? m_xtpFontLarge : m_xtpFont, XTP_DPI_X(bLargeFont ? 275 : 330), XTP_DPI_X(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_xtpFontLarge : m_xtpFont, 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_xtpFontLarge : m_xtpFont)) { 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 - XTP_DPI_Y(2); return rcCommand; } int CXTPTaskDialogClient::CalcClientWidth() { int nIdealWidth = m_nMinClientWidth; if (HasFixedWidth()) { CSize sizeBase = XTPToDWORDChecked(::GetDialogBaseUnits()); int cxWidth = ::MulDiv(XTPToIntChecked(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 + XTP_DPI_Y(1)); int nLinkTop = m_rcContent.bottom + m_ptPadding.y; if (nLinkTop < m_ptMargin.y * 4 - XTP_DPI_Y(3)) nLinkTop = m_ptMargin.y * 4 - XTP_DPI_Y(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 + XTP_DPI_Y(3); } } m_rcRadioButtons.bottom = nLinkTop; } else { m_rcRadioButtons = CRect(m_rcContent.left + XTP_DPI_X(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 + XTP_DPI_X(1), nLinkTop + XTP_DPI_Y(1), m_ptMargin.y + nIdealWidth - XTP_DPI_X(1), nLinkTop + XTP_DPI_Y(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 - XTP_DPI_X(1), nBottom + m_ptMargin.y + XTP_DPI_Y(1)); nBottom += m_rcFooter.Height() + 2 * m_ptMargin.y + XTP_DPI_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 - XTP_DPI_X(3), (rcParent.top + rcParent.bottom - szClient.cy) / 2 - XTP_DPI_Y(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(), XTP_DPI_Y(1), m_cr3DLight); } if (!m_rcFooter.IsRectEmpty()) { pDC->FillSolidRect(rect.left, m_rcCommandButtons.bottom, rect.Width(), XTP_DPI_Y(1), m_cr3DLight); pDC->FillSolidRect(rect.left, m_rcCommandButtons.bottom + XTP_DPI_Y(1), rect.Width(), XTP_DPI_Y(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(), XTP_DPI_Y(1), m_cr3DLight); pDC->FillSolidRect(rect.left, m_rcExpandedInformation.top - m_ptMargin.y + XTP_DPI_Y(1), rect.Width(), XTP_DPI_Y(1), m_cr3DHighLight); } } else { if (!m_rcFooter.IsRectEmpty()) { pDC->FillSolidRect(rect.left, m_rcCommandButtons.bottom + XTP_DPI_Y(1), rect.Width(), XTP_DPI_Y(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(), XTP_DPI_Y(1), m_cr3DShadow); } } } void CXTPTaskDialogClient::DrawIcon(CDC* pDC, HICON hIcon, CPoint pt, CSize sz) { DWORD dwLayout = XTPDrawHelpers()->GetLayout(pDC); if (dwLayout & LAYOUT_RTL) XTPDrawHelpers()->SetLayout(pDC, dwLayout | LAYOUT_BITMAPORIENTATIONPRESERVED); ::DrawIconEx(*pDC, pt.x, pt.y, hIcon, sz.cx, sz.cy, 0, NULL, DI_NORMAL); if (dwLayout & LAYOUT_RTL) XTPDrawHelpers()->SetLayout(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_xtpFontLarge); } 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_xtpFont); } } 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_xtpFont); } } void CXTPTaskDialogClient::DrawFootNote(CDC* pDC) { if (m_rcFooter.IsRectEmpty()) return; if (m_hIconFooter) DrawIcon(pDC, m_hIconFooter, CPoint(m_ptMargin.x + XTP_DPI_X(2), m_rcFooter.top), m_sizeIconFooter); if (!::IsWindow(m_wndFooter.m_hWnd)) DrawText(pDC, m_strFooter, m_rcFooter, m_crFooterText, &m_xtpFont); } 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); }