Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

768 lines
19 KiB

  1. /*--------------------------------------------------------------------------
  2. ctrlgrp.cpp
  3. Control group switcher
  4. Copyright (C) Microsoft Corporation, 1993 - 1999
  5. All rights reserved.
  6. Authors:
  7. matth Matthew F. Hillman, Microsoft
  8. History:
  9. 10/14/93 matth Created.
  10. 26 oct 95 garykac DBCS_FILE_CHECK
  11. --------------------------------------------------------------------------*/
  12. //#include "precomp.h"
  13. #include "stdafx.h"
  14. //#ifndef _GUISTD_H
  15. //#include "guistd.h"
  16. //#endif
  17. #ifndef _CTRLGRP_H
  18. #include "ctrlgrp.h"
  19. #endif
  20. //#ifndef _GLOBALS_H
  21. //#include "globals.h"
  22. //#endif
  23. //#include "richres.h"
  24. /*
  25. #ifdef _DEBUG
  26. #undef THIS_FILE
  27. static char BASED_CODE THIS_FILE[] = "ctrlgrp.cpp";
  28. #endif
  29. */
  30. #ifdef _DEBUG
  31. #define new DEBUG_NEW
  32. #undef THIS_FILE
  33. static char THIS_FILE[] = __FILE__;
  34. #endif
  35. // DIALOGEX structures (from MFC 4.0)
  36. #pragma pack(push, 1)
  37. typedef struct
  38. {
  39. WORD dlgVer;
  40. WORD signature;
  41. DWORD helpID;
  42. DWORD exStyle;
  43. DWORD style;
  44. WORD cdit;
  45. short x;
  46. short y;
  47. short cx;
  48. short cy;
  49. } DLGTEMPLATEEX;
  50. typedef struct
  51. {
  52. DWORD helpID;
  53. DWORD exStyle;
  54. DWORD style;
  55. short x;
  56. short y;
  57. short cx;
  58. short cy;
  59. DWORD id;
  60. } DLGITEMTEMPLATEEX;
  61. #pragma pack(pop)
  62. /*!C------------------------------------------------------------------------
  63. ControlGroupSwitcher
  64. This class is used to manage switching among groups of controls in a
  65. parent window.
  66. Primary APIs are:
  67. Create -- The pwndParent parameter is the window which will be the
  68. parent of the controls in the control groups. It is commonly a
  69. dialog. The idcAnchor parameter is the id of a control which will
  70. server as an 'anchor' for the controls. This means that the controls
  71. will created in the parent window offset by the position of the
  72. top left corner of the anchor control. This control is commonly
  73. a group box surrounding the area where the groups appear. The
  74. cgsStyle parameter specifieds whether the the controls in the groups
  75. are created right away (cgsPreCreateAll), only when that group is
  76. shown (cgsCreateOnDemand), or created each time the group is shown
  77. and destroyed when they are hidden (cgsCreateDestroyOnDemand).
  78. AddGroup -- Adds a group of controls, which can be shown using
  79. ShowGroup. The idGroup parameter identifies the group, and is used
  80. as the parameter to ShowGroup. The idd parameter is the id of the
  81. dialog template with the layout of the controls. The pfnInit
  82. parameter, if not NULL, is a function called when the group is
  83. loaded. Note that -1 is not a legal value for idGroup (it is a
  84. distinguised value meaning no group).
  85. RemoveGroup -- Removes the group specified by idGroup, destroying the
  86. controls if they have been created.
  87. ShowGroup -- Show the group specified by idGroup, hiding any other
  88. group. If -1, hides all groups.
  89. --------------------------------------------------------------------------*/
  90. #if 0
  91. BOOL CGControlInfo::MarkMem(IDebugContext * pdbc, long cRef)
  92. {
  93. if (pdbc->MarkMem(this,sizeof(*this),cRef))
  94. return fTrue;
  95. return fFalse;
  96. }
  97. void CGControlInfo::AssertValid() const
  98. {
  99. }
  100. void CGControlInfo::Dump(CDumpContext &dc) const
  101. {
  102. }
  103. #endif // DEBUG
  104. //ImplementGenericArrayConstructDestruct(RGControlInfo, CGControlInfo)
  105. //ImplementGenericArrayDebug(RGControlInfo, CGControlInfo)
  106. ControlGroup::ControlGroup(int idGroup, int idd,
  107. void (*pfnInit)(CWnd * pwndParent))
  108. : m_idGroup(idGroup), m_idd(idd), m_pfnInit(pfnInit),
  109. m_fLoaded(fFalse), m_fVisible(fFalse)
  110. {
  111. }
  112. ControlGroup::~ControlGroup()
  113. {
  114. m_rgControls.RemoveAll();
  115. }
  116. #if 0
  117. BOOL ControlGroup::MarkMem(IDebugContext * pdbc, long cRef)
  118. {
  119. if (pdbc->MarkMem(this,sizeof(*this),cRef))
  120. return fTrue;
  121. MarkCObject(pdbc,this,0);
  122. m_rgControls.MarkMem(pdbc,0);
  123. return fFalse;
  124. }
  125. void ControlGroup::AssertValid() const
  126. {
  127. m_rgControls.AssertValid();
  128. }
  129. void ControlGroup::Dump(CDumpContext &dc) const
  130. {
  131. }
  132. #endif // DEBUG
  133. void ControlGroup::LoadGroup(CWnd * pwndParent, int xOffset, int yOffset)
  134. {
  135. /*------------------------------------------------------------------------
  136. This function is mostly stolen from the Knowledge Base code for the
  137. 'multidlg' example.
  138. That's why it uses mostly raw Windows rather than MFC conventions.
  139. ------------------------------------------------------------------------*/
  140. HWND hDlg = NULL;
  141. HGLOBAL hDlgResMem = NULL;
  142. HRSRC hDlgRes = NULL;
  143. BYTE FAR *lpDlgRes = NULL;
  144. // PutAssertCanThrow();
  145. TRY
  146. {
  147. Assert(!m_fLoaded);
  148. hDlg = pwndParent->m_hWnd;
  149. Assert(hDlg);
  150. // Load the resource into memory and get a pointer to it.
  151. hDlgRes = FindResource (AfxGetResourceHandle(),
  152. MAKEINTRESOURCE(m_idd),
  153. RT_DIALOG);
  154. if (!hDlgRes)
  155. AfxThrowResourceException();
  156. hDlgResMem = LoadResource (AfxGetResourceHandle(), hDlgRes);
  157. if (!hDlgResMem)
  158. AfxThrowResourceException();
  159. lpDlgRes = (BYTE FAR *) LockResource (hDlgResMem);
  160. if (!lpDlgRes)
  161. AfxThrowResourceException();
  162. LoadWin32DialogResource(hDlg, lpDlgRes, xOffset, yOffset);
  163. m_fLoaded = fTrue;
  164. // Free the resource which we just parsed.
  165. UnlockResource (hDlgResMem);
  166. FreeResource (hDlgResMem);
  167. // Send the new child an init message
  168. if (m_pfnInit)
  169. (*m_pfnInit)(pwndParent);
  170. }
  171. CATCH_ALL(e)
  172. {
  173. if (hDlgRes && hDlgResMem)
  174. {
  175. if (lpDlgRes)
  176. UnlockResource(hDlgResMem);
  177. FreeResource(hDlgResMem);
  178. }
  179. m_rgControls.RemoveAll();
  180. THROW_LAST();
  181. }
  182. END_CATCH_ALL
  183. }
  184. void ControlGroup::LoadWin32DialogResource(
  185. HWND hDlg,
  186. BYTE FAR *lpDlgRes,
  187. int xOffset,
  188. int yOffset)
  189. {
  190. BOOL fEx;
  191. RECT rc;
  192. SMALL_RECT srct;
  193. HFONT hDlgFont;
  194. DWORD style;
  195. DWORD exstyle;
  196. DWORD dwID;
  197. WORD wCurCtrl;
  198. WORD wNumOfCtrls;
  199. LPWSTR classname;
  200. WORD FAR * lpwDlgRes;
  201. char pszaClassName[256];
  202. char pszaTitle[256];
  203. // We need to get the font of the dialog so we can set the font of
  204. // the child controls. If the dialog has no font set, it uses the
  205. // default system font, and hDlgFont equals zero.
  206. hDlgFont = (HFONT) SendMessage (hDlg, WM_GETFONT, 0, 0L);
  207. // Figure out if this is a DIALOGEX resource
  208. fEx = ((DLGTEMPLATEEX *)lpDlgRes)->signature == 0xFFFF;
  209. // Grab all the stuff we need out of the headers
  210. if (fEx)
  211. {
  212. style = ((DLGTEMPLATEEX *)lpDlgRes)->style;
  213. wNumOfCtrls = ((DLGTEMPLATEEX *)lpDlgRes)->cdit;
  214. lpDlgRes += sizeof(DLGTEMPLATEEX);
  215. }
  216. else
  217. {
  218. style = ((DLGTEMPLATE *)lpDlgRes)->style;
  219. wNumOfCtrls = ((DLGTEMPLATE *)lpDlgRes)->cdit;
  220. lpDlgRes += sizeof(DLGTEMPLATE);
  221. }
  222. // Skip the variable sized information
  223. lpwDlgRes = (LPWORD)lpDlgRes;
  224. if (0xFFFF == *lpwDlgRes)
  225. lpwDlgRes += 2; // menu by ordinal, skip ffff & ordinal
  226. else
  227. lpwDlgRes += wcslen(lpwDlgRes) + 1; // Menu by name or no menu at all
  228. if (0xFFFF == *lpwDlgRes)
  229. lpwDlgRes += 2; // classname by ordinal, skip
  230. else
  231. lpwDlgRes += wcslen(lpwDlgRes) + 1;
  232. lpwDlgRes += wcslen(lpwDlgRes) + 1; // Pass the caption
  233. // Some fields are present only if DS_SETFONT is specified.
  234. if (style & DS_SETFONT)
  235. {
  236. lpwDlgRes += fEx ? 3 : 1; // skip point size, (weight, and style)
  237. lpwDlgRes += wcslen(lpwDlgRes) + 1; // Pass face name
  238. }
  239. // Allocate space in the control info array
  240. m_rgControls.SetSize(wNumOfCtrls);
  241. // The rest of the dialog template contains ControlData structures.
  242. // We parse these structures and call CreateWindow() for each.
  243. for (wCurCtrl = 0; wCurCtrl < wNumOfCtrls; wCurCtrl++)
  244. {
  245. // ControlData coordinates are in dialog units. We need to convert
  246. // these to pixels before adding the anchor offset
  247. // Should be Word Aligned
  248. Assert(!((ULONG_PTR) lpwDlgRes & (0x1)));
  249. // Make it DWORD aligned
  250. if (((ULONG_PTR)(lpwDlgRes)) & (0x2))
  251. lpwDlgRes += 1;
  252. // Get the header info we need
  253. if (fEx)
  254. {
  255. style = ((DLGITEMTEMPLATEEX *)lpwDlgRes)->style;
  256. exstyle = ((DLGITEMTEMPLATEEX *)lpwDlgRes)->exStyle;
  257. srct = *(SMALL_RECT *)(&((DLGITEMTEMPLATEEX *)lpwDlgRes)->x);
  258. dwID = ((DLGITEMTEMPLATEEX *)lpwDlgRes)->id;
  259. lpwDlgRes = (LPWORD)((LPBYTE)lpwDlgRes + sizeof(DLGITEMTEMPLATEEX));
  260. }
  261. else
  262. {
  263. style = ((DLGITEMTEMPLATE *)lpwDlgRes)->style;
  264. exstyle = 0;
  265. srct = *(SMALL_RECT *)(&((DLGITEMTEMPLATE *)lpwDlgRes)->x);
  266. dwID = ((DLGITEMTEMPLATE *)lpwDlgRes)->id;
  267. lpwDlgRes = (LPWORD)((LPBYTE)lpwDlgRes + sizeof(DLGITEMTEMPLATE));
  268. }
  269. style &= ~WS_VISIBLE; // Create invisible!
  270. // use the rc structure as x,y,width,height
  271. rc.top = srct.Top;
  272. rc.bottom = srct.Bottom;
  273. rc.left = srct.Left;
  274. rc.right = srct.Right;
  275. MapDialogRect (hDlg, &rc); // Convert to pixels.
  276. rc.left += xOffset; // Add the offset.
  277. rc.top += yOffset;
  278. // At this point in the ControlData structure (see "Dialog Box
  279. // Resource" in online help), the class of the control may be
  280. // described either with text, or as a byte with a pre-defined
  281. // meaning.
  282. if (*lpwDlgRes == 0xFFFF)
  283. {
  284. lpwDlgRes++; // Skip the FFFF
  285. switch (*lpwDlgRes)
  286. {
  287. case 0x0080:
  288. classname = L"button"; // STRING_OK
  289. break;
  290. case 0x0081:
  291. classname = EDIT_NORMAL_WIDE;
  292. //$ The strange code below fixes 3D problems
  293. // on Win95
  294. //if (g_fWin4 && !g_fWinNT)
  295. exstyle |= WS_EX_CLIENTEDGE;
  296. break;
  297. case 0x0082:
  298. classname = L"static"; // STRING_OK
  299. break;
  300. case 0x0083:
  301. classname = L"listbox"; // STRING_OK
  302. exstyle |= WS_EX_CLIENTEDGE;
  303. break;
  304. case 0x0084:
  305. classname = L"scrollbar"; // STRING_OK
  306. break;
  307. case 0x0085:
  308. classname = L"combobox"; // STRING_OK
  309. break;
  310. default:
  311. // Next value is an atom
  312. AssertSz(fFalse,"Illegal Class Value in Dialog Template");
  313. //$Review: Can this be any atom or must it be an enumerated
  314. // value from above?
  315. }
  316. lpwDlgRes++; // passes the class identifier
  317. }
  318. else
  319. {
  320. classname = (WCHAR *)lpwDlgRes;
  321. lpwDlgRes += wcslen(lpwDlgRes) + 1;
  322. exstyle |= WS_EX_CLIENTEDGE;
  323. }
  324. //$32 review: is this correct matt?
  325. // Be sure to use the UNICODE function, all the data should
  326. // be in UNICODE
  327. m_rgControls[wCurCtrl].m_hwnd =
  328. CreateWindowExW (exstyle, classname, (LPWSTR)lpwDlgRes,
  329. style, (int) rc.left, (int) rc.top,
  330. (int) rc.right, (int) rc.bottom,
  331. hDlg, (HMENU)ULongToPtr(dwID),
  332. (HINSTANCE) AfxGetInstanceHandle(),
  333. NULL);
  334. // There is no CreateWindowExW in Win95 so convert the strings to ANSI
  335. if (m_rgControls[wCurCtrl].m_hwnd == NULL &&
  336. GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  337. {
  338. if (!WideCharToMultiByte(CP_ACP,0,classname,-1,pszaClassName,256,NULL,NULL) ||
  339. !WideCharToMultiByte(CP_ACP,0,(LPWSTR)lpwDlgRes, -1, pszaTitle, 256, NULL,NULL))
  340. {
  341. AssertSz(fFalse, "WideCharToMultiByteFailed");
  342. AfxThrowResourceException();
  343. }
  344. m_rgControls[wCurCtrl].m_hwnd =
  345. CreateWindowExA(exstyle,pszaClassName, pszaTitle,
  346. style,(int) rc.left, (int) rc.top,
  347. (int) rc.right, (int) rc.bottom,
  348. hDlg, (HMENU)ULongToPtr(dwID),
  349. (HINSTANCE) AfxGetInstanceHandle(),
  350. NULL);
  351. }
  352. if (!m_rgControls[wCurCtrl].m_hwnd)
  353. AfxThrowResourceException();
  354. MaskAccelerator(m_rgControls[wCurCtrl].m_hwnd, fTrue); // Make sure all the accelerators are disabled
  355. // Pass the window text
  356. if (0xFFFF == *lpwDlgRes)
  357. lpwDlgRes += 2;
  358. else
  359. lpwDlgRes += wcslen(lpwDlgRes) + 1;
  360. // skip over creation data
  361. lpwDlgRes = (LPWORD)((LPBYTE)lpwDlgRes + *lpwDlgRes + 2);
  362. // see DYNDLG SDK example, this is a size word in Win32
  363. // Even though the font is the right size (MapDialogRect() did
  364. // this), we also need to set the font if it's not the system font.
  365. if (hDlgFont)
  366. ::SendMessage(m_rgControls[wCurCtrl].m_hwnd,WM_SETFONT,
  367. (WPARAM)hDlgFont,(LPARAM)fFalse);
  368. }
  369. }
  370. void ControlGroup::UnloadGroup()
  371. {
  372. Assert(m_fLoaded);
  373. m_rgControls.RemoveAll();
  374. m_fLoaded = fFalse;
  375. }
  376. void ControlGroup::ShowGroup(HDWP& hdwp, BOOL fShow, CWnd * pwnd)
  377. {
  378. long i,n;
  379. UINT rgfSwp;
  380. HWND hwndInsertAfter = NULL;
  381. if (pwnd)
  382. hwndInsertAfter = pwnd->m_hWnd;
  383. Assert((fShow && !m_fVisible) || (m_fVisible && !fShow));
  384. Assert(m_fLoaded);
  385. rgfSwp = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE |(pwnd != NULL ? 0 : SWP_NOZORDER)|
  386. (fShow ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
  387. for (i = 0, n = (long)m_rgControls.GetSize(); i < n; i++)
  388. {
  389. HWND hwnd = m_rgControls[i].m_hwnd;
  390. MaskAccelerator(hwnd, !fShow);
  391. hdwp = DeferWindowPos(hdwp,hwnd,hwndInsertAfter,0,0,0,0,rgfSwp);
  392. hwndInsertAfter = hwnd;
  393. }
  394. m_fVisible = fShow;
  395. }
  396. void ControlGroup::EnableGroup(BOOL fEnable)
  397. {
  398. long i,n;
  399. Assert(m_fLoaded);
  400. for (i = 0, n = (long)m_rgControls.GetSize(); i < n; i++)
  401. {
  402. HWND hwnd = m_rgControls[i].m_hwnd;
  403. ::EnableWindow(hwnd, fEnable);
  404. }
  405. }
  406. void ControlGroup::AddControl(HWND hwnd)
  407. {
  408. Assert(m_fLoaded);
  409. int nNewIndex = (int)m_rgControls.Add(CGControlInfo());
  410. m_rgControls[nNewIndex].m_hwnd = hwnd;
  411. }
  412. void ControlGroup::RemoveControl(HWND hwnd)
  413. {
  414. long i, n;
  415. Assert(m_fLoaded);
  416. for (i = 0, n = (long)m_rgControls.GetSize(); i < n; i++)
  417. {
  418. if (m_rgControls[i].m_hwnd == hwnd)
  419. {
  420. m_rgControls.RemoveAt(i);
  421. return;
  422. }
  423. }
  424. Assert(fFalse);
  425. }
  426. void ControlGroup::MaskAccelerator(HWND hwnd, BOOL fMask)
  427. {
  428. TCHAR szText[256];
  429. TCHAR * psz;
  430. DWORD_PTR dwCtlCode;
  431. // Ignore text of controls which accept text (like edit controls)
  432. // and of static controls which have the SS_NOPREFIX style.
  433. dwCtlCode = SendMessage (hwnd, WM_GETDLGCODE, 0, 0L);
  434. if (DLGC_WANTCHARS & dwCtlCode)
  435. return;
  436. if (DLGC_STATIC & dwCtlCode)
  437. {
  438. LONG lStyle;
  439. lStyle = GetWindowLong (hwnd, GWL_STYLE);
  440. if (SS_NOPREFIX & lStyle)
  441. return;
  442. }
  443. // DBCS_OK [tatsuw]
  444. // Don't have a really long label
  445. Assert(GetWindowTextLength(hwnd) < DimensionOf(szText));
  446. GetWindowText (hwnd, szText, DimensionOf(szText));
  447. // Don't have |s in your text
  448. Assert((!fMask) || (_tcschr(szText, TEXT('|')) == NULL));
  449. psz = szText;
  450. while ((psz = _tcschr(psz, fMask ? TEXT('&') : TEXT('|'))) != NULL)
  451. {
  452. if (fMask && psz[1] == '&')
  453. {
  454. // Special! Ignore double ampersand
  455. psz++;
  456. continue;
  457. }
  458. *psz = fMask ? TEXT('|') : TEXT('&');
  459. SetWindowText(hwnd, szText);
  460. break;
  461. }
  462. }
  463. #if 0
  464. void RGPControlGroup::AssertValidGen(GEN *pgen) const
  465. {
  466. ControlGroup * pGroup = *(PControlGroup *)pgen;
  467. if (pGroup)
  468. pGroup->AssertValid();
  469. }
  470. void RGPControlGroup::MarkMemGen(IDebugContext *pdbc, GEN *pgen)
  471. {
  472. ControlGroup * pGroup = *(PControlGroup *)pgen;
  473. pGroup->MarkMem(pdbc,0);
  474. }
  475. #endif
  476. long RGPControlGroup::GroupIndex(int idGroup) const
  477. {
  478. long i, n;
  479. for (i = 0, n = (long)GetSize(); i < n; i++)
  480. if ((GetAt(i))->IDGroup() == idGroup)
  481. return i;
  482. Assert(fFalse);
  483. return -1;
  484. }
  485. ControlGroupSwitcher::ControlGroupSwitcher()
  486. : m_iGroup(-1), m_pwndParent(NULL)
  487. {
  488. }
  489. void ControlGroupSwitcher::Create(CWnd * pwndParent, int idcAnchor,
  490. int cgsStyle)
  491. {
  492. m_pwndParent = pwndParent;
  493. m_idcAnchor = idcAnchor;
  494. m_cgsStyle = cgsStyle;
  495. ComputeAnchorOffsets();
  496. }
  497. ControlGroupSwitcher::~ControlGroupSwitcher()
  498. {
  499. for (long i = 0, n = (long)m_rgpGroups.GetSize(); i < n; i++)
  500. {
  501. delete m_rgpGroups[i];
  502. m_rgpGroups[i] = NULL;
  503. }
  504. m_rgpGroups.RemoveAll();
  505. }
  506. #if 0
  507. BOOL ControlGroupSwitcher::MarkMem(IDebugContext * pdbc, long cRef)
  508. {
  509. if (pdbc->MarkMem(this,sizeof(*this),cRef))
  510. return fTrue;
  511. MarkCObject(pdbc,this,0);
  512. m_rgpGroups.MarkMem(pdbc,0);
  513. return fFalse;
  514. }
  515. void ControlGroupSwitcher::AssertValid() const
  516. {
  517. m_rgpGroups.AssertValid();
  518. }
  519. void ControlGroupSwitcher::Dump(CDumpContext &dc) const
  520. {
  521. }
  522. #endif // DEBUG
  523. void ControlGroupSwitcher::AddGroup(int idGroup, int idd,
  524. void (*pfnInit)(CWnd * pwndParent))
  525. {
  526. ControlGroup * pGroupNew = NULL;
  527. TRY
  528. {
  529. pGroupNew = new ControlGroup(idGroup, idd, pfnInit);
  530. m_rgpGroups.Add(pGroupNew);
  531. }
  532. CATCH_ALL(e)
  533. {
  534. delete pGroupNew;
  535. THROW_LAST();
  536. }
  537. END_CATCH_ALL
  538. // In a stable state now. Possibly load controls which might also throw
  539. if (m_cgsStyle == cgsPreCreateAll)
  540. pGroupNew->LoadGroup(m_pwndParent, m_xOffset, m_yOffset);
  541. }
  542. void ControlGroupSwitcher::RemoveGroup(int idGroup)
  543. {
  544. // Don't remove group being shown! Show another group first.
  545. Assert(idGroup != m_iGroup);
  546. long index;
  547. ControlGroup * pGroup;
  548. index = m_rgpGroups.GroupIndex(idGroup);
  549. pGroup = m_rgpGroups[index];
  550. delete pGroup;
  551. m_rgpGroups.RemoveAt(index);
  552. }
  553. void ControlGroupSwitcher::EnableGroup(int idGroup, BOOL fEnable)
  554. {
  555. long index;
  556. ControlGroup * pGroup;
  557. if (idGroup == -1)
  558. idGroup = m_iGroup;
  559. index = m_rgpGroups.GroupIndex(idGroup);
  560. pGroup = m_rgpGroups[index];
  561. pGroup->EnableGroup(fEnable);
  562. }
  563. void ControlGroupSwitcher::ShowGroup(int idGroup)
  564. {
  565. ControlGroup * pGroupOld = NULL;
  566. ControlGroup * pGroupNew = NULL;
  567. HDWP hdwp;
  568. int cWindows;
  569. if (m_iGroup == idGroup)
  570. return;
  571. cWindows = 0;
  572. if (m_iGroup != -1)
  573. {
  574. pGroupOld = m_rgpGroups.PGroup(m_iGroup);
  575. Assert(pGroupOld->FVisible());
  576. cWindows += pGroupOld->CControls();
  577. }
  578. if (idGroup != -1)
  579. {
  580. pGroupNew = m_rgpGroups.PGroup(idGroup);
  581. if (!pGroupNew->FLoaded())
  582. pGroupNew->LoadGroup(m_pwndParent, m_xOffset, m_yOffset);
  583. cWindows += pGroupNew->CControls();
  584. }
  585. hdwp = BeginDeferWindowPos(cWindows);
  586. if (!hdwp)
  587. AfxThrowResourceException();
  588. if (m_iGroup != -1)
  589. {
  590. pGroupOld->ShowGroup(hdwp,fFalse, NULL);
  591. if (m_cgsStyle == cgsCreateDestroyOnDemand)
  592. pGroupOld->UnloadGroup();
  593. }
  594. // Indicate we currently have no group, in case below throws
  595. m_iGroup = -1;
  596. if (idGroup != -1)
  597. {
  598. pGroupNew->ShowGroup(hdwp, fTrue, m_pwndParent->GetDlgItem(m_idcAnchor));
  599. m_iGroup = idGroup;
  600. }
  601. EndDeferWindowPos(hdwp);
  602. }
  603. void ControlGroupSwitcher::ComputeAnchorOffsets()
  604. {
  605. /*------------------------------------------------------------------------
  606. Note that anchor offset is computed relative to upper left.
  607. Intended use: Make an invisible group box where you want your controls.
  608. ------------------------------------------------------------------------*/
  609. CWnd * pwndAnchor;
  610. RECT rc;
  611. pwndAnchor = m_pwndParent->GetDlgItem(m_idcAnchor);
  612. Assert(pwndAnchor);
  613. // compute the offset of the anchor when the window is mapped
  614. // This offset is used to place the child controls in the dialog.
  615. pwndAnchor->GetWindowRect( &rc );
  616. MapWindowPoints( HWND_DESKTOP, m_pwndParent->m_hWnd, ( LPPOINT ) &rc, 2 );
  617. m_xOffset = rc.left;
  618. m_yOffset = rc.top;
  619. } // ControlGroupSwitcher::ComputeAnchorOffsets()