/***********************************************************************/ /* 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 "MyDialog.h" #include "MyRegistry.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 ///////////////////////////////////////////////////////////////////////////// // Statics UINT MyDialog::m_uiDialogIcon(0U); ///////////////////////////////////////////////////////////////////////////// // MyDialog dialog // Constructor. MyDialog::MyDialog(UINT uiResource, const CString& sName, const CString& sRegPlacementsKey, CWnd* pParent /* = NULL */ , bool bHidden /* = false */ , UINT uiDialogIcon /* = 0U */ ) : CDialog(uiResource, pParent) , m_sName(sName) , m_sRegPlacementsKey(sRegPlacementsKey) , m_nOldCx(0) , m_nOldCy(0) , m_nMinWidth(0) , m_nMinHeight(0) , m_bHidden(bHidden) { CommonConstruct(); // Override for this dialog, optionally. Note that the caller will have // to set this value back to what it was, or else this new icon will be // the one used for all subsequently created dialogs. if (uiDialogIcon) { MyDialog::m_uiDialogIcon = uiDialogIcon; } } // Constructor. MyDialog::MyDialog(LPCTSTR pszResource, const CString& sName, const CString& sRegPlacementsKey, CWnd* pParent /* = NULL */ , bool bHidden /* = false */ , UINT uiDialogIcon /* = 0U */ ) : CDialog(pszResource, pParent) , m_sName(sName) , m_sRegPlacementsKey(sRegPlacementsKey) , m_nOldCx(0) , m_nOldCy(0) , m_nMinWidth(0) , m_nMinHeight(0) , m_bHidden(bHidden) { CommonConstruct(); // Override for this dialog, optionally. Note that the caller will have // to set this value back to what it was, or else this new icon will be // the one used for all subsequently created dialogs. if (uiDialogIcon) { MyDialog::m_uiDialogIcon = uiDialogIcon; } } // ClassWizard hates it when you have AFX_DATA_INIT in more than one place! void MyDialog::CommonConstruct() { VALIDATE; _ASSERTE(! m_sName.IsEmpty()); //{{AFX_DATA_INIT(MyDialog) //}}AFX_DATA_INIT } // Destructor. /* virtual */ MyDialog::~MyDialog() { POSITION pos(m_plControlInfo.GetHeadPosition()); while (pos) { delete static_cast (m_plControlInfo.GetNext(pos)); } } // void MyDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(MyDialog) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(MyDialog, CDialog) //{{AFX_MSG_MAP(MyDialog) ON_WM_DESTROY() ON_WM_SIZE() ON_WM_CREATE() ON_WM_GETMINMAXINFO() ON_WM_PAINT() ON_WM_NCHITTEST() ON_WM_MOUSEMOVE() //}}AFX_MSG_MAP END_MESSAGE_MAP() // Load this control - called externally by the derived dialog box. void MyDialog::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. ControlInfo* pCI = GetControlInfo(uiCtrlID); // Not there yet, create one. if (! pCI) { pCI = new ControlInfo; pCI->m_bSetExternally = true; m_plControlInfo.AddTail(pCI); } // Now that we have one, populate (or re-populate) it. if (pCI) { ASSERT_POINTER(pCI, ControlInfo); 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 MyDialog::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. ControlInfo* pCI = GetControlInfo(uiCtrlID); // Not there yet, create one. if (! pCI) { pCI = new ControlInfo; pCI->m_bSetExternally = false; m_plControlInfo.AddTail(pCI); } // Now that we have one, populate (or re-populate) it. if (pCI) { ASSERT_POINTER(pCI, ControlInfo); 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. ControlInfo* MyDialog::GetControlInfo(UINT uiID) const { VALIDATE; POSITION pos(m_plControlInfo.GetHeadPosition()); ControlInfo* pCI = NULL; while (pos) { pCI = static_cast (m_plControlInfo.GetNext(pos)); ASSERT_POINTER(pCI, ControlInfo); if (pCI && pCI->uiID == uiID) { break; } else { pCI = NULL; } } return pCI; } // Store the original size of the dialog template. We want to make this the // minimum allowable size. int MyDialog::OnCreate(LPCREATESTRUCT lpCreateStruct) { VALIDATE; _ASSERTE(800 >= lpCreateStruct->cx && "This dialog box will not fit on an 800600 screen!"); _ASSERTE(600 >= lpCreateStruct->cy && "This dialog box will not fit on an 800600 screen!"); if (CDialog::OnCreate(lpCreateStruct) == -1) { return -1; } m_nMinWidth = lpCreateStruct->cx; m_nMinHeight = lpCreateStruct->cy; return 0; } // Use the sizes from the template of the dialog to restrict this. void MyDialog::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { VALIDATE; if (m_nMinWidth) { lpMMI->ptMinTrackSize.x = m_nMinWidth; lpMMI->ptMinTrackSize.y = m_nMinHeight; } else { CDialog::OnGetMinMaxInfo(lpMMI); } } // WM_INITDIALOG BOOL MyDialog::OnInitDialog() { VALIDATE; HRESULT hr(S_OK); // This must appear before doing anything to the controls. CDialog::OnInitDialog(); // Set icon to the one you set in the constructor, if any. if (0U < m_uiDialogIcon) { HICON hIcon(NULL); EC_B(hIcon = AfxGetApp()->LoadIcon(m_uiDialogIcon)); EC_V(SetIcon(hIcon, /* bBigIcon */ false)); } // 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!"); } // Begin: Do some automated checking here for my benefit. #ifdef _DEBUG // Get the style, to see if this has the 'Notify' style. DWORD dwStyle(pControl->GetStyle()); _ASSERTE((! pControl->IsKindOf(RUNTIME_CLASS(MyStatic)) || (dwStyle & SS_NOTIFY)) && "This is a MyStatic - the style " "must include SS_NOTIFY so that tooltips work"); // If this is a temporary, like an IDC_STATIC*, we probably // don't want a tip for it. bool bIsTemp(NULL == CWnd::FromHandlePermanent(pControl-> GetSafeHwnd())); // See if this probably should have had a tip, and warn me. // 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 || bIsTemp == true || 0 < nTipLen) && "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 length is 80 chars"); VERIFY(AddTipToControl(pControl)); } } } pControl = pControl->GetWindow(GW_HWNDNEXT); } // Restore the previous run's position (but only if it exists in the Registry). MyRegistry reg; if (reg.Open(HKEY_CURRENT_USER, m_sRegPlacementsKey, /* bCreate */ false)) { WINDOWPLACEMENT wp = { sizeof(wp) }; if (reg.ReadValueBinary(m_sName, reinterpret_cast (&wp), reinterpret_cast (wp.length))) { VERIFY(SetWindowPlacement(&wp)); } } // We don't want to make the dialog flash; this is mostly for apps that // use system tray icons. Generic::RestoreWindowPlacement(this, m_sRegPlacementsKey, m_sName, m_bHidden ? SW_HIDE : -1); // 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 MyDialog. BOOL CALLBACK EnumChildCallback(HWND hwndControl, LPARAM lParam) { bool bReturn(false); ToolTipLParam* pttlp = reinterpret_cast (lParam); ASSERT_POINTER(pttlp, ToolTipLParam); 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 MyDialog::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. ToolTipLParam ttlp; ttlp.m_pToolTip = &m_ToolTip; ttlp.m_pControl = pControl; ::EnumChildWindows(pControl->GetSafeHwnd(), EnumChildCallback, reinterpret_cast (&ttlp)); } } return bReturn; } // BOOL MyDialog::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.Activate(true); m_ToolTip.RelayEvent(pMsg); return CDialog::PreTranslateMessage(pMsg); } return false; } // Add gripper to dialog. void MyDialog::OnPaint() { VALIDATE; HRESULT hr(S_OK); if (! m_bHidden) { CDialog::OnPaint(); // Only if the dialog has the resizing border. DWORD dwStyle(::GetWindowLong(GetSafeHwnd(), GWL_STYLE)); if (dwStyle & WS_THICKFRAME) { // Create the rectangle that contains the gripper. CRect rc; GetClientRect(rc); rc.left = rc.right - GetSystemMetrics(SM_CXHSCROLL); rc.top = rc.bottom - GetSystemMetrics(SM_CYVSCROLL); // Create a region that will contain only the bottom triangular // half of the grabber retangle. POINT aPoints[3]; aPoints[0].x = rc.right; aPoints[0].y = rc.top; aPoints[1].x = rc.left; aPoints[1].y = rc.bottom; aPoints[2].x = rc.right; aPoints[2].y = rc.bottom; CRgn rgnClip; EC_B(rgnClip.CreatePolygonRgn(aPoints, sizeof(aPoints) / sizeof(POINT), WINDING)); // This section is for testing only, not for Release Mode. #ifdef _DEBUG int nSize(rgnClip.GetRegionData(NULL, 0)); PRGNDATA prdClip = (PRGNDATA) new BYTE[nSize]; ::ZeroMemory(prdClip, nSize); _ASSERTE(NULLREGION != rgnClip.GetRegionData(prdClip, nSize)); _ASSERTE(ERROR != rgnClip.GetRegionData(prdClip, nSize)); delete prdClip; prdClip = NULL; #endif // Using the tiny clipping region, draw the gripper. CClientDC dc(this); #ifdef TESTING_ CBrush br; EC_B(br.CreateSolidBrush(RGB_RED)); EC_B(dc.FillRgn(&rgnClip, &br)); #else int nType(dc.SelectClipRgn(&rgnClip, RGN_COPY)); _ASSERTE(ERROR != nType); EC_B(dc.DrawFrameControl(rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP)); #endif } } } // This just allows the user to grab the grabber when the mouse is over it, // by pretending that it's in the bottom-right corner. UINT MyDialog::OnNcHitTest(CPoint point) { VALIDATE; UINT uiPlace(CDialog::OnNcHitTest(point)); // Only if the dialog has the resizing border. DWORD dwStyle(::GetWindowLong(GetSafeHwnd(), GWL_STYLE)); if (dwStyle & WS_THICKFRAME) { if (HTCLIENT == uiPlace) { CRect rc; GetWindowRect(rc); rc.left = rc.right - GetSystemMetrics(SM_CXHSCROLL); rc.top = rc.bottom - GetSystemMetrics(SM_CYVSCROLL); if (rc.PtInRect(point)) { uiPlace = HTBOTTOMRIGHT; } } } return uiPlace; } // WM_SIZE void MyDialog::OnSize(UINT nType, int cx, int cy) { VALIDATE; // Do not call. CDialog::OnSize(nType, cx, cy); if (! m_bHidden) { int nDx(cx - m_nOldCx); int nDy(cy - m_nOldCy); if (m_nOldCx && SIZE_MINIMIZED != nType) { // Move and size the controls using the information we got in SetControlInfo(). POSITION pos(m_plControlInfo.GetHeadPosition()); while (pos) { ControlInfo* pCI = static_cast (m_plControlInfo.GetNext(pos)); ASSERT_POINTER(pCI, ControlInfo); if (pCI) { // We often get WM_SIZE before the window has been created, so check. UINT uiInfo(pCI->uiInfo); CWnd* pCtrl = GetDlgItem(pCI->uiID); ASSERT_NULL_OR_POINTER(pCtrl, CWnd); if (pCtrl) { // Do nothing if anchored to top and/or left. if (uiInfo) { // Save the old position of the control, so that // later we can invalidate it to avoid ugly left // over pieces. CRect rcCtrlOldClient(pCI->rcClient); pCtrl->GetWindowRect(pCI->rcClient); ScreenToClient(pCI->rcClient); // Modify the control's rectangle based on the new // size and the flags. UINT uiControl(pCI->uiInfo); if (uiControl & RESIZE_HORZ) { pCI->rcClient.right += nDx; } else if (uiControl & ANCHOR_RIGHT) { pCI->rcClient.OffsetRect(nDx, 0); } if (uiControl & RESIZE_VERT) { pCI->rcClient.bottom += nDy; } else if (uiControl & ANCHOR_BOTTOM) { pCI->rcClient.OffsetRect(0, nDy); } // Invalidate the area where the control *used* to // be, to avoid ugly painting. (But only some // types - other controls cause too much flashing, // or don't have this problem.) if (0 == pCI->sClassName.CompareNoCase("BUTTON") || 0 == pCI->sClassName.CompareNoCase("STATIC") || 0 == pCI->sClassName.CompareNoCase("EDIT")) { InvalidateRect(rcCtrlOldClient); } // Move the control to the new position. pCtrl->MoveWindow(pCI->rcClient); } } } } } m_nOldCx = cx; m_nOldCy = cy; // Here we force a repaint of the square where the gripper *used* to be. // This fixes the problem of little pieces of the gripper being left behind. static CRect rcGripper; InvalidateRect(&rcGripper); rcGripper.right = cx; rcGripper.bottom = cy; rcGripper.top = rcGripper.bottom - GetSystemMetrics(SM_CYHSCROLL); rcGripper.left = rcGripper.right - GetSystemMetrics(SM_CXVSCROLL); InvalidateRect(&rcGripper); } } // WM_DESTROY void MyDialog::OnDestroy() { VALIDATE; HRESULT hr(S_OK); CDialog::OnDestroy(); // Save the position for the next time. EC_H(Generic::SaveWindowPlacement(this, m_sRegPlacementsKey, m_sName)); EC_FAIL(s, m_sRegPlacementsKey); EC_FAIL(s, m_sName); } // 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 MyDialog::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()); ControlInfo* pCI = GetControlInfo(uiID); if (pCI) { ASSERT_POINTER(pCI, ControlInfo); 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()); ControlInfo* pCI = GetControlInfo(uiID); if (pCI) { ASSERT_POINTER(pCI, ControlInfo); 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()); ControlInfo* pCI = GetControlInfo(uiID); // Don't want to overwrite what the user set. if (! pCI || ! pCI->m_bSetExternally) { ASSERT_NULL_OR_POINTER(pCI, ControlInfo); // 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); ControlInfo* pCI = GetControlInfo(uiTallestID); if (pCI) { ASSERT_POINTER(pCI, ControlInfo); 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); ControlInfo* pCI = GetControlInfo(uiTallestID); if (pCI) { ASSERT_POINTER(pCI, ControlInfo); 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 MyDialog::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) { ControlInfo* pCI = GetControlInfo(uiID); if (! pCI || ! pCI->m_bSetExternally) { ASSERT_NULL_OR_POINTER(pCI, ControlInfo); 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 MyDialog::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) { ControlInfo* pCI = GetControlInfo(uiID); if (! pCI || ! pCI->m_bSetExternally) { ASSERT_NULL_OR_POINTER(pCI, ControlInfo); 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); } } }