/***********************************************************************/ /* Copyright (C) 2002 Definitive Solutions, Inc. All Rights Reserved. */ /* THIS COMPUTER PROGRAM IS PROPRIETARY AND CONFIDENTIAL TO DEFINITIVE */ /* SOLUTIONS, INC. AND ITS LICENSORS AND CONTAINS TRADE SECRETS OF */ /* DEFINITIVE SOLUTIONS, INC. THAT ARE PROVIDED PURSUANT TO A WRITTEN */ /* AGREEMENT CONTAINING RESTRICTIONS ON USE AND DISCLOSURE. ANY USE, */ /* REPRODUCTION, OR TRANSFER EXCEPT AS PROVIDED IN SUCH AGREEMENT */ /* IS STRICTLY PROHIBITED. */ /***********************************************************************/ #include "stdafx.h" #include "MyPropertyPage.h" #include "MyHyperlink.h" #include "MyListCtrl.h" #include "MyStatic.h" #include "MyEdit.h" #include "MyApp.h" #include "MyLog.h" #include "Generic.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // MyPropertyPage property page IMPLEMENT_DYNCREATE(MyPropertyPage, CPropertyPage) // Constructor. MyPropertyPage::MyPropertyPage(UINT uiResourceID, int nDialogTemplateWidth /* = 0 */ , int nDialogTemplateHeight /* = 0 */ , UINT uiTitleId /* = 0U */ ) : CPropertyPage(uiResourceID, uiTitleId) , m_bCalledAlready(false) , m_nDialogTemplateWidth(nDialogTemplateWidth) , m_nDialogTemplateHeight(nDialogTemplateHeight) { //{{AFX_DATA_INIT(MyPropertyPage) //}}AFX_DATA_INIT } // Default constructor. MyPropertyPage::MyPropertyPage() : m_bCalledAlready(false) , m_nDialogTemplateWidth(0) , m_nDialogTemplateHeight(0) { } // Destructor. /* virtual */ MyPropertyPage::~MyPropertyPage() { POSITION pos(m_plControlInfo.GetHeadPosition()); while (pos) { delete static_cast (m_plControlInfo.GetNext(pos)); } } // void MyPropertyPage::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(MyPropertyPage) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(MyPropertyPage, CPropertyPage) //{{AFX_MSG_MAP(MyPropertyPage) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // MyPropertyPage message handlers // Load this control - called externally by the derived dialog box. void MyPropertyPage::SetControlInfo(UINT uiCtrlID, UINT uiCtrlInfo) { VALIDATE; _ASSERTE(-1 != uiCtrlID && "Can't put -1 IDs here - how would I keep them separate? Give each control a unique name/number"); // Try to find an existing one. MyPPControlInfo* pCI = GetControlInfo(uiCtrlID); // Not there yet, create one. if (! pCI) { pCI = new MyPPControlInfo; pCI->m_bSetExternally = true; m_plControlInfo.AddTail(pCI); } // Now that we have one, populate (or re-populate) it. if (pCI) { ASSERT_POINTER(pCI, MyPPControlInfo); pCI->uiID = uiCtrlID; pCI->uiInfo = uiCtrlInfo; VERIFY(::GetClassName(GetDlgItem(pCI->uiID)->GetSafeHwnd(), pCI->sClassName.GetBuffer(64), 64)); pCI->sClassName.ReleaseBuffer(); } } // This class' use only! void MyPropertyPage::SetControlInfoInternal(UINT uiCtrlID, UINT uiCtrlInfo) { VALIDATE; _ASSERTE(-1 != uiCtrlID && "Can't put -1 IDs here - how would I keep them separate? Give each control a unique name/number"); // Try to find an existing one. MyPPControlInfo* pCI = GetControlInfo(uiCtrlID); // Not there yet, create one. if (! pCI) { pCI = new MyPPControlInfo; pCI->m_bSetExternally = false; m_plControlInfo.AddTail(pCI); } // Now that we have one, populate (or re-populate) it. if (pCI) { ASSERT_POINTER(pCI, MyPPControlInfo); pCI->uiID = uiCtrlID; pCI->uiInfo = uiCtrlInfo; VERIFY(::GetClassName(GetDlgItem(pCI->uiID)->GetSafeHwnd(), pCI->sClassName.GetBuffer(64), 64)); pCI->sClassName.ReleaseBuffer(); } } // Find the control info for this control ID, if it exists. MyPPControlInfo* MyPropertyPage::GetControlInfo(UINT uiID) const { VALIDATE; POSITION pos(m_plControlInfo.GetHeadPosition()); MyPPControlInfo* pCI = NULL; while (pos) { pCI = static_cast (m_plControlInfo.GetNext(pos)); ASSERT_POINTER(pCI, MyPPControlInfo); if (pCI && pCI->uiID == uiID) { break; } else { pCI = NULL; } } return pCI; } // /* virtual */ BOOL MyPropertyPage::OnSetActive() { VALIDATE; // This must appear before doing anything to the controls. CPropertyPage::OnSetActive(); // This is called every time the page is activated, but this stuff only // needs to happen once. if (! m_bCalledAlready) { m_bCalledAlready = true; // Set a default control info item on each control in the dialog, based // on the quadrant it occupies, and its control type. Note that we // only do this if the border is stretchy; otherwise we assume the // caller doesn't want strecthiness. DWORD dwStyle(GetStyle()); if (dwStyle & WS_THICKFRAME) { SetDefaultControlInfos(); } // Set up tool tips for each control on the dialog. Except those that // do their own tooltipping. We set the max width to allow multiline // tips. m_ToolTip.Create(this, TTS_ALWAYSTIP | 0x40 /* TTS_BALLOON */ ); m_ToolTip.Activate(true); m_ToolTip.SetMaxTipWidth(SHRT_MAX); m_ToolTip.SetDelayTime(333); CWnd* pControl = GetWindow(GW_CHILD); while (pControl) { if (! pControl->IsKindOf(RUNTIME_CLASS(MyHyperlink)) && ! pControl->IsKindOf(RUNTIME_CLASS(MyListCtrl))) { ASSERT_VALID(pControl); int nID(pControl->GetDlgCtrlID()); if (-1 != nID && 65535 != nID && IDOK != nID && IDCANCEL != nID) { // Load the tooltip string from the string table. We don't // check the return from LoadString as we have some more // sophisticated error checking farther along. CString sTip; sTip.LoadString(nID); int nTipLen(sTip.GetLength()); // ?? Why are we doing this? if (sTip.IsEmpty()) { nTipLen = ::LoadString(AfxGetInstanceHandle(), nID, sTip.GetBuffer(512), 512); sTip.ReleaseBuffer(); _ASSERTE(sTip.IsEmpty() && "I don't think this ever corrects any problems!"); } // If this is a static control, it must have SS_NOTIFY // set so that it gets mouse messages, so make tips work. #ifdef _DEBUG DWORD dwStyle(pControl->GetStyle()); if (pControl->IsKindOf(RUNTIME_CLASS(CStatic)) || pControl->IsKindOf(RUNTIME_CLASS(MyStatic))) { if (! (dwStyle & SS_NOTIFY)) { _ASSERTE(! "Style must include SS_NOTIFY so that tooltips work"); } } // Check for misssing string table entries. Note: if you // want a MyStatic control with no tooltip, add a string // with one space in it in the string table. _ASSERTE((IDOK == nID || IDCANCEL == nID || ID_HELP == nID || 65535 == nID || 1 < nTipLen || sTip == " ") && "You forgot to add (or populate) a string to the string " "table for this control to enable its tooltip"); #endif // End: Do some automated checking here for my benefit. sTip.TrimLeft(); sTip.TrimRight(); if (! sTip.IsEmpty()) { _ASSERTE(80 >= sTip.GetLength() && "Maximum tooltip lenth is 80 chars"); VERIFY(AddTipToControl(pControl)); } } } pControl = pControl->GetWindow(GW_HWNDNEXT); } // Fake a WM_SIZE message so that the OnSize() handler is called; // this ensures that the sizing done there gets done initially. CRect rc; GetClientRect(rc); OnSize(NULL, rc.Width(), rc.Height()); } return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } // Not a member of MyPropertyPage. BOOL CALLBACK MyPPEnumChildCallback(HWND hwndControl, LPARAM lParam) { bool bReturn(false); MyPPToolTipLParam* pttlp = reinterpret_cast (lParam); ASSERT_POINTER(pttlp, MyPPToolTipLParam); ASSERT_VALID(pttlp->m_pToolTip); ASSERT_VALID(pttlp->m_pControl); if (pttlp && pttlp->m_pToolTip && pttlp->m_pControl) { CWnd* pWndSubControl = CWnd::FromHandle(hwndControl); ASSERT_VALID(pWndSubControl); VERIFY(bReturn = pttlp->m_pToolTip->AddTool(pWndSubControl, pttlp->m_pControl->GetDlgCtrlID())); } _ASSERTE(bReturn); return bReturn; } // Add tooltips to this control and all its subcontrols (for comboboxes). bool MyPropertyPage::AddTipToControl(CWnd* pControl) { VALIDATE; ASSERT_VALID(pControl); _ASSERTE(::IsWindow(pControl->GetSafeHwnd())); bool bReturn(false); if (pControl) { // First add tip to the control itself. if (m_ToolTip.AddTool(pControl, pControl->GetDlgCtrlID())) { //TRACE(" Added tool tip for hwnd %d.\n", pControl->GetDlgCtrlID()); bReturn = true; // Now add tip to all children; this is only needed for ComboBoxes. // (Need to pass two things and have only one lParam, so we built a // helper structure.) We dont care if it fails. MyPPToolTipLParam ttlp; ttlp.m_pToolTip = &m_ToolTip; ttlp.m_pControl = pControl; ::EnumChildWindows(pControl->GetSafeHwnd(), MyPPEnumChildCallback, reinterpret_cast (&ttlp)); } } return bReturn; } // BOOL MyPropertyPage::PreTranslateMessage(MSG* pMsg) { VALIDATE; // The call to Activate() is required to fix a Microsoft bug. // FIX: CToolTipCtrl Stops Working After Dialog Is Displayed (Q143313) if (m_hWnd && pMsg && m_ToolTip.m_hWnd) { m_ToolTip.Activate(true); m_ToolTip.RelayEvent(pMsg); return CPropertyPage::PreTranslateMessage(pMsg); } return false; } // Set control info based on type and location. Which quadrant is this // control in? Interestingly, this is the same value as the control word! // // 00 01 // ============ // 00 | 0 | 1 // | -----+----- // 02 | 2 | 3 // // Note that we don't overwrite a control word that the user set by calling // SetControlInfo( ) on a control from their dialog's OnInitDialog( ). void MyPropertyPage::SetDefaultControlInfos() { VALIDATE; CWnd* pControl = NULL; // See if any of the controls are already set to stretch vertically. If // not, we want to do it, because there must be at least one control that // stretches vertically. UINT uiStretchVertID(0U); pControl = GetWindow(GW_CHILD); while (pControl) { UINT uiID(pControl->GetDlgCtrlID()); MyPPControlInfo* pCI = GetControlInfo(uiID); if (pCI) { ASSERT_POINTER(pCI, MyPPControlInfo); if (pCI->uiInfo & RESIZE_VERT) { uiStretchVertID = pCI->uiID; break; } } pControl = pControl->GetWindow(GW_HWNDNEXT); } // See if any of the controls are already set to stretch horizontally. If // not, we want to do it, because there must be at least one control that // stretches horizontally. UINT uiStretchHorzID(0U); pControl = GetWindow(GW_CHILD); while (pControl) { UINT uiID(pControl->GetDlgCtrlID()); MyPPControlInfo* pCI = GetControlInfo(uiID); if (pCI) { ASSERT_POINTER(pCI, MyPPControlInfo); if (pCI->uiInfo & RESIZE_HORZ) { uiStretchHorzID = pCI->uiID; break; } } pControl = pControl->GetWindow(GW_HWNDNEXT); } // Do the stuff that we can do per control. CRect rcParent; GetClientRect(rcParent); pControl = GetWindow(GW_CHILD); while (pControl) { UINT uiControl(0U); ASSERT_VALID(pControl); UINT uiID(pControl->GetDlgCtrlID()); MyPPControlInfo* pCI = GetControlInfo(uiID); // Don't want to overwrite what the user set. if (! pCI || ! pCI->m_bSetExternally) { ASSERT_NULL_OR_POINTER(pCI, MyPPControlInfo); // First, set the anchoring for each control. CRect rcControl; pControl->GetWindowRect(rcControl); ScreenToClient(rcControl); if (rcControl.left + ((rcControl.right - rcControl.left) / 2) > rcParent.right / 2) { uiControl = ANCHOR_RIGHT; } if (rcControl.top + ((rcControl.bottom - rcControl.top) / 2) > rcParent.bottom / 2) { uiControl += ANCHOR_BOTTOM; } // Now, we have to set some control types to stretch horizontally. CRuntimeClass* pRC = pControl->GetRuntimeClass(); ASSERT_POINTER(pRC, CRuntimeClass); if (pRC) { if (0 == lstrcmpi(pRC->m_lpszClassName, "CStatic") || 0 == lstrcmpi(pRC->m_lpszClassName, "CEdit") || 0 == lstrcmpi(pRC->m_lpszClassName, "MyEdit") || 0 == lstrcmpi(pRC->m_lpszClassName, "MyStatic") || 0 == lstrcmpi(pRC->m_lpszClassName, "CRichEditCtrl") || 0 == lstrcmpi(pRC->m_lpszClassName, "CComboBox") || 0 == lstrcmpi(pRC->m_lpszClassName, "MyCombobox") || 0 == lstrcmpi(pRC->m_lpszClassName, "CListBox")) { uiStretchHorzID = uiID; uiControl |= RESIZE_HORZ; DoControlsAffectedByHorzStretch(uiID); } else if (0 == lstrcmpi(pRC->m_lpszClassName, "CTempWnd")) { // We don't want to stretch pictures - they look horrible! // This code also keeps us from automatically stretching // buttons with pictures. CStatic* pStatic = static_cast (pControl); ASSERT_VALID(pStatic); if (pStatic && ! pStatic->GetIcon() && ! pStatic->GetBitmap()) { uiStretchHorzID = uiID; uiControl |= RESIZE_HORZ; DoControlsAffectedByHorzStretch(uiID); } } else { //DOMYLOGD (" Skipped %d %s\n", uiID, pRC->m_lpszClassName); } } // If the client didn't set one, we must set exactly one control to // stretch vertically. We prefer listboxes and comboboxes, but // will take edits if we have to. Here, we take the first listbox // or combobox we come across. if (! uiStretchVertID) { if (0 == lstrcmpi(pRC->m_lpszClassName, "CListbox") || 0 == lstrcmpi(pRC->m_lpszClassName, "MyCombobox") || 0 == lstrcmpi(pRC->m_lpszClassName, "CCombobox")) { uiStretchVertID = uiID; uiControl |= RESIZE_VERT; DoControlsAffectedByVertStretch(uiID); } } // Here we actually set the control into. SetControlInfoInternal(uiID, uiControl); } // Get the next control. pControl = pControl->GetWindow(GW_HWNDNEXT); //DOMYLOGD ("Control %d Word %x\n", uiID, uiControl); } // If either there was no horz or vert stretchy control, we're going to // need to know the tallest edit control. Note that this requires the // edit control to have a member variable assigned to it; otherwise, it // is just a CTempWnd type. UINT uiTallestID(0U); if (! uiStretchVertID || ! uiStretchHorzID) { int nHeightMax(0); pControl = GetWindow(GW_CHILD); while (pControl) { ASSERT_VALID(pControl); UINT uiID(pControl->GetDlgCtrlID()); CRuntimeClass* pRC = pControl->GetRuntimeClass(); ASSERT_POINTER(pRC, CRuntimeClass); if (pRC) { if (0 == lstrcmpi(pRC->m_lpszClassName, "CEdit") || 0 == lstrcmpi(pRC->m_lpszClassName, "MyEdit") || 0 == lstrcmpi(pRC->m_lpszClassName, "CRichEditCtrl")) { CRect rcControl; pControl->GetWindowRect(rcControl); if (nHeightMax < rcControl.Height()) { uiTallestID = uiID; nHeightMax = rcControl.Height(); } } } pControl = pControl->GetWindow(GW_HWNDNEXT); } } // Finally, we have to revisit the vert size issue. If the user didn't set // a control to stretch vert, and there were no listboxes or comboxes that // we had done above, then we look for an edit control; we prefer the // "tallest" one. if (! uiStretchVertID) { // If we found a tallest edit control, make it vert stretchy. if (uiTallestID) { UINT uiControl(0U); MyPPControlInfo* pCI = GetControlInfo(uiTallestID); if (pCI) { ASSERT_POINTER(pCI, MyPPControlInfo); uiControl = pCI->uiInfo; } SetControlInfo(uiTallestID, uiControl | RESIZE_VERT); } else { _ASSERTE(! "Could not find a listbox, combobox, or even an edit control to stretch vertically - you need to call SetControlInfo yourself from your dialog classes OnInitDialog()"); } } // Finally, we have to revisit the horz size issue. If the user didn't set // a control to stretch horz, and there were no listboxes or comboxes that // we had done above, then we look for an edit control; we prefer the // "tallest" one. if (! uiStretchHorzID) { // If we found a tallest edit control, make it horz stretchy. if (uiTallestID) { UINT uiControl(0U); MyPPControlInfo* pCI = GetControlInfo(uiTallestID); if (pCI) { ASSERT_POINTER(pCI, MyPPControlInfo); uiControl = pCI->uiInfo; } SetControlInfo(uiTallestID, uiControl | RESIZE_HORZ); } else { _ASSERTE(! "Could not find a listbox, combobox, or even an edit control to stretch horizontally - you need to call SetControlInfo yourself from your dialog classes OnInitDialog()"); } } } // Any control that is in the path of one we just made horz stretchy must be // made to anchor to the of the sent control that its on (left or right) and be // made not stretchy; else the one we just made horz stretchy would paint over // it. void MyPropertyPage::DoControlsAffectedByVertStretch(UINT uiIDVert) { VALIDATE; // Get the rectangle we are tying to protect, to the right of Vert control. // // +-----------------------X----------------X---------------------------+ // | ^ ^ | // | | | | // | +================+ | // | | Control | | // | +================+ | // | | | | // | V V | // +-----------------------X----------------X---------------------------+ // // The four corners of the rectangle we want are marked with "X"'s above. CWnd* pControlVert = GetDlgItem(uiIDVert); ASSERT_VALID(pControlVert); CRect rcVert; pControlVert->GetWindowRect(rcVert); ScreenToClient(rcVert); CRect rcDlg; GetClientRect(rcDlg); CRect rcSweep(rcVert.left, rcDlg.top, rcVert.right, rcDlg.bottom); // Now check each control (excluding the sent one, of course). if (pControlVert) { CWnd* pControl = GetWindow(GW_CHILD); while (pControl) { UINT uiID(pControl->GetDlgCtrlID()); if (uiID != uiIDVert) { MyPPControlInfo* pCI = GetControlInfo(uiID); if (! pCI || ! pCI->m_bSetExternally) { ASSERT_NULL_OR_POINTER(pCI, MyPPControlInfo); CRect rcControl; pControl->GetWindowRect(rcControl); ScreenToClient(rcControl); CRect rcIntersect; if (rcIntersect.IntersectRect(rcSweep, rcControl)) { UINT uiControl(pCI ? pCI->uiInfo : 0U); uiControl |= (rcControl.top < rcVert.top) ? ANCHOR_TOP : ANCHOR_BOTTOM; uiControl &= ~ ((rcControl.top < rcVert.top) ? ANCHOR_BOTTOM : ANCHOR_TOP); uiControl &= ~ RESIZE_VERT; SetControlInfoInternal(uiID, uiControl); } } } pControl = pControl->GetWindow(GW_HWNDNEXT); } } } // Any control that is in the path of one we just made horz stretchy must be // made to anchor to the side of the sent control that its on (left or right) // and be made not stretchy; else the one we just made horz stretchy would // paint over it. void MyPropertyPage::DoControlsAffectedByHorzStretch(UINT uiIDHorz) { VALIDATE; // Get the rectangle we are tying to protect, to the right of horz control. // // +--------------------------------------------------------------------+ // | | // | | // X <---------------------+================+-------------------------->X // | | Control | | // X <---------------------+================+-------------------------->X // | | // | | // +--------------------------------------------------------------------+ // // The four corners of the rectangle we want are marked with "X"'s above. CWnd* pControlHorz = GetDlgItem(uiIDHorz); ASSERT_VALID(pControlHorz); CRect rcHorz; pControlHorz->GetWindowRect(rcHorz); ScreenToClient(rcHorz); CRect rcDlg; GetClientRect(rcDlg); CRect rcSweep(rcDlg.left, rcHorz.top, rcDlg.right, rcHorz.bottom); // Now check each control (excluding the sent one, of course). if (pControlHorz) { CWnd* pControl = GetWindow(GW_CHILD); while (pControl) { UINT uiID(pControl->GetDlgCtrlID()); if (uiID != uiIDHorz) { MyPPControlInfo* pCI = GetControlInfo(uiID); if (! pCI || ! pCI->m_bSetExternally) { ASSERT_NULL_OR_POINTER(pCI, MyPPControlInfo); CRect rcControl; pControl->GetWindowRect(rcControl); ScreenToClient(rcControl); CRect rcIntersect; if (rcIntersect.IntersectRect(rcSweep, rcControl)) { UINT uiControl(pCI ? pCI->uiInfo : 0U); uiControl |= (rcControl.left < rcHorz.left) ? ANCHOR_LEFT : ANCHOR_RIGHT; uiControl &= ~ ((rcControl.left < rcHorz.left) ? ANCHOR_RIGHT : ANCHOR_LEFT); uiControl &= ~ RESIZE_HORZ; SetControlInfoInternal(uiID, uiControl); } } } pControl = pControl->GetWindow(GW_HWNDNEXT); } } } // Called from OnBeginPrinting() in the view. /* virtual */ void MyPropertyPage::HandleBeginPrinting() { VALIDATE; TRACE(" Base method MyPropertyPage::HandleBeginPrinting() called.\n"); } // Called from OnEndPrinting() in the view. /* virtual */ void MyPropertyPage::HandleEndPrinting(CDC* pDC, CPrintInfo* pInfo) { VALIDATE; DOMYLOGT ("Base method MyPropertyPage::HandleEndPrinting() called.\n"); } // Print to the sent DC. NOTE: returns TRUE if it completely printed out the // proppage; that is, that there were no space limitations on the current page. // This is how it requests another print page from the caller. /* virtual */ bool MyPropertyPage::PrintPropPage(PRINTPROPPAGEARGS& pppa) { VALIDATE; ASSERT_VALID(pppa.pDC); ASSERT_VALID(pppa.pfontNormal); ASSERT_VALID(pppa.pfontBold); _ASSERTE(0 < m_nDialogTemplateWidth && "Although this is optional in the ctor, it's required for printing"); _ASSERTE(0 < m_nDialogTemplateHeight && "Although this is optional in the ctor, it's required for printing"); _ASSERTE(pppa.bReallyPrint && "Always TRUE?"); _ASSERTE(0 < pppa.nPrintMargin); HRESULT hr(S_OK); bool bPrintedCompletely(true); // We only print if we are at the top of a new page. We update the // variable so the caller knows the page is not empty anymore. if (*pppa.pbWorkAreaEmpty) { *pppa.pbWorkAreaEmpty = false; // Get the original size of the dialog box (unstretched) in screen // pixels. int nDialogW(Generic::GetHorzPixels(this, m_nDialogTemplateWidth)); int nDialogH(Generic::GetVertPixels(this, m_nDialogTemplateHeight)); //DOMYLOGD ("nDialogW: <%d>, nDialogH: <%d>\n", nDialogW, nDialogH); // Get the print page recangle in printer pixels (600 dpi, e.g.). int nPrintoutW(pppa.prcClip->right - pppa.prcClip->left); int nPrintoutH(pppa.prcClip->bottom - pppa.prcClip->top); //DOMYLOGD ("nPrintoutW: <%d>, nPrintoutH: <%d>\n", nPrintoutW, nPrintoutH); // Get the scaling factors from these two numbers. double dScalingW((double) nPrintoutW / (double) nDialogW); double dScalingH((double) nPrintoutH / (double) nDialogH); //DOMYLOGD ("dScalingW: <%g> - dScalingH: <%g>\n", dScalingW, dScalingH); //DOMYLOGD ("pppa.prcClip: <%d>, <%d>, <%d>, <%d>\n", // pppa.prcClip->left, pppa.prcClip->top, pppa.prcClip->right, // pppa.prcClip->bottom); // Iterate the children of this dialog. if (pppa.bReallyPrint) { CRect rcDraw; CWnd* pwndChild = GetWindow(GW_CHILD); while (pwndChild && IsChild(pwndChild)) { // Get the text for this control. CString sText; pwndChild->GetWindowText(sText); sText.TrimLeft(); sText.TrimRight(); // Set the location for this control. if (! sText.IsEmpty()) { CRect rcChild; pwndChild->GetWindowRect(rcChild); ScreenToClient(rcChild); //DOMYLOGD ("rcChild: <%d>, <%d>, <%d>, <%d> (%s)\n", // rcChild.left, rcChild.top, rcChild.right, rcChild.bottom, // sText); rcDraw.left = pppa.prcClip->left + (int) ((double) rcChild.left * dScalingW); rcDraw.top = pppa.prcClip->top + (int) ((double) rcChild.top * dScalingH); rcDraw.right = pppa.prcClip->left + (int) ((double) rcChild.right * dScalingW); rcDraw.bottom = pppa.prcClip->top + (int) ((double) rcChild.bottom * dScalingH); //DOMYLOGD ("rcDraw : <%d>, <%d>, <%d>, <%d>\n", rcDraw.left, // rcDraw.top, rcDraw.right, rcDraw.bottom); // If this is a groupbox, make it bold. Note that groupboxes // are of style "Button", but generally do not have these // to styles; so this is how we distinguish them from // pushbuttons. CString sClass; ::GetClassName(pwndChild->GetSafeHwnd(), sClass.GetBuffer(255), 255); sClass.ReleaseBuffer(); DWORD dwStyle(pwndChild->GetStyle()); DOMYLOG ("Class <%s>, style <%x>, text <%s>.\n", sClass, dwStyle, sText); if (0 == sClass.CompareNoCase("Button") && 0 != (SS_BLACKFRAME & dwStyle) && 0 == (WS_TABSTOP & dwStyle) && 0 == (WS_GROUP & dwStyle)) { // Print the text in bold. pppa.pDC->SelectObject(pppa.pfontBold); // Draw the containing box. (Make the top line prettier.) CBrush brHollow; EC_B(brHollow.CreateStockObject(HOLLOW_BRUSH)); CBrush* pbrushOld = pppa.pDC->SelectObject(&brHollow); _ASSERTE(pbrushOld); int nExtra((double) Generic::GetVertPixels(this, 3) * dScalingH); EC_B(pppa.pDC->Rectangle(rcDraw)); pppa.pDC->SelectObject(pbrushOld); rcDraw.top -= nExtra; } else { pppa.pDC->SelectObject(pppa.pfontNormal); } // If this is a radio button, only print it if it is the // one that's selected. We use the first two to verify it's // not a groupbox, and the second two to verify it's a radio. bool bPrintTheControl(true); if (0 == sClass.CompareNoCase("Button") && (WS_TABSTOP & dwStyle || WS_GROUP & dwStyle) && (BS_RADIOBUTTON & dwStyle || BS_AUTORADIOBUTTON & dwStyle)) { if (0 == (static_cast (pwndChild))->GetCheck()) { bPrintTheControl = false; } } // Draw the text for this control, and update the clip // rectangle for the next control. if (bPrintTheControl) { EC_B(0 < pppa.pDC->DrawText(sText, rcDraw, DT_LEFT | DT_TOP | DT_WORDBREAK | DT_NOCLIP)); // This is extremely handy for debugging - don't delete it. #ifdef _DEBUG_NOT_CURRENTLY_IN_USE CBrush brHollow; EC_B(brHollow.CreateStockObject(HOLLOW_BRUSH)); CBrush* pbrushOld = pppa.pDC->SelectObject(&brHollow); _ASSERTE(pbrushOld); EC_B(pppa.pDC->Rectangle(rcDraw)); pppa.pDC->SelectObject(pbrushOld); #endif } } // Get the next window in the managers list (may or may not be // a child of this dialog). pwndChild = pwndChild->GetWindow(GW_HWNDNEXT); } } // We have to set the bottom so that the caller knows where to continue // printing at. Also, we return TRUE if we did *NOT* print out because // of space limitations on the current page. int nNewBottom(pppa.prcClip->top + (dScalingH * nDialogH)); bPrintedCompletely = nNewBottom <= pppa.prcClip->bottom; if (bPrintedCompletely) { pppa.prcClip->bottom = nNewBottom; } } return bPrintedCompletely; } // Prints page header. /* virtual */ void MyPropertyPage::PrintPageHeader(PRINTPROPPAGEARGS& pppa) { VALIDATE; _ASSERTE(pppa.prcClip); // Space down a little if we're the first tab to print. if (1U == pppa.uiPage) { *pppa.pnY += pppa.nLeading; } // Print the first line. if (pppa.bReallyPrint) pppa.pDC->MoveTo(pppa.nPrintMargin, *pppa.pnY); if (pppa.bReallyPrint) pppa.pDC->LineTo(pppa.pInfo->m_rectDraw.right - pppa.nPrintMargin, *pppa.pnY); *pppa.pnY += pppa.nGap; // Print the page title. Note that it can be either set programmatically, // or the one on the dialog template. if (pppa.bReallyPrint) pppa.pDC->MoveTo(pppa.nPrintMargin, *pppa.pnY); CRect rcClip(pppa.nPrintMargin, *pppa.pnY, pppa.prcClip->right, pppa.prcClip->bottom); int nHeight(0); CString sTitle(m_psp.pszTitle); if (sTitle.IsEmpty()) { GetWindowText(sTitle); } if (pppa.bReallyPrint) nHeight = pppa.pDC->DrawText(sTitle, &rcClip, DT_LEFT | DT_TOP | DT_WORDBREAK | DT_NOCLIP); *pppa.pnY += nHeight + pppa.nGap; // Print the second line. if (pppa.bReallyPrint) pppa.pDC->MoveTo(pppa.nPrintMargin, *pppa.pnY); if (pppa.bReallyPrint) pppa.pDC->LineTo(pppa.pInfo->m_rectDraw.right - pppa.nPrintMargin, *pppa.pnY); *pppa.pnY += pppa.nGap; } // Return the string of descriptive text about this tab (usually < 40 chars). /* virtual */ CString MyPropertyPage::GetDescriptiveText() const { VALIDATE; _ASSERTE(! "You must implement this in your derived class!"); return "You must implement this in your derived class"; } // Set the title of this page. Not as easy as one would hope. void MyPropertyPage::SetPageTitle(const CString& sTitle) const { VALIDATE; _ASSERTE(! sTitle.IsEmpty()); CString sTitleLocal(sTitle); int nTitleLen(sTitleLocal.GetLength()); TCITEM tci = { 0 }; tci.mask = TCIF_TEXT; tci.pszText = sTitleLocal.GetBuffer(nTitleLen); CTabCtrl* pTabCtrl = ((CPropertySheet*) GetParent())->GetTabControl(); ASSERT_VALID(pTabCtrl); int nPageNumber(((CPropertySheet*) GetParent())->GetActiveIndex()); pTabCtrl->SetItem(nPageNumber, &tci); sTitleLocal.ReleaseBuffer(); }