cdxCDynamicControlsManager.cpp
上传用户:cbxyz2008
上传日期:2007-01-02
资源大小:45k
文件大小:15k
源码类别:

Static控件

开发平台:

Visual C++

  1. // cdxCDynamicControlsManager.cpp: implementation of the cdxCDynamicControlsManager class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. /*
  5.  * you should define OEMRESOURCE
  6.  * in your project settings (C/C++, General) !
  7.  */
  8. #include "stdafx.h"
  9. #include "cdxCDynamicControlsManager.h"
  10. #include <winuser.h>
  11. #include <afxmt.h>
  12. #ifndef OBM_SIZE
  13. #define OBM_SIZE 32766
  14. #pragma message("*** NOTE: cdxCDynamicControlsManager.cpp: Please define OEMRESOURCE in your project settings !")
  15. // taken from WinresRc.h
  16. // if not used for any reason
  17. #endif
  18. #ifdef _DEBUG
  19. #define new DEBUG_NEW
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23. /////////////////////////////////////////////////////////////////////////////
  24. // Some static variables
  25. /////////////////////////////////////////////////////////////////////////////
  26. #define REGVAL_NOSTATE -1
  27. #define REGVAL_VISIBLE 1
  28. #define REGVAL_HIDDEN 0
  29. #define REGVAL_MAXIMIZED 1
  30. #define REGVAL_ICONIC 0
  31. #define REGVAL_INVALID 0
  32. #define REGVAL_VALID 1
  33. /*
  34.  * registry value names
  35.  * (for StoreWindowPosition()/RestoreWindowPosition())
  36.  */
  37. static LPCTSTR lpszRegVal_Left = _T("Left"),
  38. lpszRegVal_Right = _T("Right"),
  39. lpszRegVal_Top = _T("Top"),
  40. lpszRegVal_Bottom = _T("Bottom"),
  41. lpszRegVal_Visible = _T("Visibility"),
  42. lpszRegVal_State = _T("State"),
  43. lpszRegVal_Valid = _T("(valid)");
  44. /////////////////////////////////////////////////////////////////////////////
  45. // cdxCDynamicControlsManager::ControlData
  46. /////////////////////////////////////////////////////////////////////////////
  47. /////////////////////////////////////////////////////////////////////////////
  48. // construction/destruction
  49. /////////////////////////////////////////////////////////////////////////////
  50. /*
  51.  * constructor
  52.  * copies all paramaters and gets the controls initial position using
  53.  * GetWindowPos
  54.  */
  55. cdxCDynamicControlsManager::ControlData::ControlData(cdxCDynamicControlsManager & rMaster, CWnd & ctrl, BYTE dX1pcnt, BYTE dX2pcnt, BYTE dY1pcnt, BYTE dY2pcnt)
  56. : m_rMaster(rMaster), m_Ctrl(ctrl),
  57. m_pNext(NULL), m_pPrev(NULL)
  58. {
  59. ASSERT(::IsWindow(ctrl.m_hWnd)); // control must have already been created !
  60. //
  61. // get initial values
  62. //
  63. m_dX1pcnt = dX1pcnt;
  64. m_dX2pcnt = dX2pcnt;
  65. m_dY1pcnt = dY1pcnt;
  66. m_dY2pcnt = dY2pcnt;
  67. WINDOWPLACEMENT wpl;
  68. VERIFY( ctrl.GetWindowPlacement(&wpl) );
  69. m_rectOriginal = wpl.rcNormalPosition;
  70. //
  71. // link us to the cdxCDynamicControlsManager's list
  72. //
  73. if(m_pNext = m_rMaster.m_pFirst)
  74. m_pNext->m_pPrev = this;
  75. m_pPrev = NULL;
  76. m_rMaster.m_pFirst = this;
  77. }
  78. /*
  79.  * detach from list
  80.  * The m_Ctrl deletes all children by itself
  81.  */
  82. cdxCDynamicControlsManager::ControlData::~ControlData()
  83. {
  84. if(m_pPrev)
  85. {
  86. if(m_pPrev->m_pNext = m_pNext)
  87. m_pNext->m_pPrev = m_pPrev;
  88. }
  89. else
  90. {
  91. ASSERT(m_rMaster.m_pFirst == this);
  92. if(m_rMaster.m_pFirst = m_pNext)
  93. m_pNext->m_pPrev = NULL;
  94. }
  95. }
  96. /////////////////////////////////////////////////////////////////////////////
  97. // members
  98. /////////////////////////////////////////////////////////////////////////////
  99. /*
  100.  * called by cdxCDynamicControlsManager::ReorganizeControls() if the size of the window has been changed.
  101.  * repositions all controls applied to this ControlData
  102.  */
  103. void cdxCDynamicControlsManager::ControlData::OnSize(const CSize & szDelta)
  104. {
  105. CRect rectNew;
  106. rectNew.left = m_rectOriginal.left   + (szDelta.cx * (int)m_dX1pcnt) / 100;
  107. rectNew.right = m_rectOriginal.right  + (szDelta.cx * (int)m_dX2pcnt) / 100;
  108. rectNew.top = m_rectOriginal.top    + (szDelta.cy * (int)m_dY1pcnt) / 100;
  109. rectNew.bottom = m_rectOriginal.bottom + (szDelta.cy * (int)m_dY2pcnt) / 100;
  110. m_Ctrl.Position(rectNew.left,rectNew.top,rectNew.Width(),rectNew.Height(),true);
  111. }
  112. /////////////////////////////////////////////////////////////////////////////
  113. // cdxCDynamicControlsManager
  114. /////////////////////////////////////////////////////////////////////////////
  115. /////////////////////////////////////////////////////////////////////////////
  116. // handling events from CWnd
  117. /////////////////////////////////////////////////////////////////////////////
  118. /*
  119.  * this function initializes the following members:
  120.  * m_pWnd - the window handle
  121.  * m_szCurrent - the current window's size
  122.  * m_szMin - the minimum window's size (taken from current size)
  123.  * m_szMax - the maximum window's size (set to (0,0) <=> don't change maximum)
  124.  * m_wndSizeIcon - the icon (if wanted)
  125.  *
  126.  * parameters:
  127.  * rWnd - the window to supervise
  128.  * fd - in which directions can we size the window (does only apply to user-sizing)
  129.  * bSizeIcon - do you want a sizable icon ?
  130.  * pBaseClientSize- if non-zero, this defines the real (normal) size of the
  131.  * window relative to all furher calculations will be made.
  132.  * if zero, the current window's size will be taken.
  133.  */
  134. void cdxCDynamicControlsManager::DoInitWindow(CWnd & rWnd, Freedom fd, bool bSizeIcon, const CSize * pBaseClientSize)
  135. {
  136. ASSERT(m_pWnd == NULL); // you MUST NOT call this function twice !
  137. ASSERT(::IsWindow(rWnd.m_hWnd)); // rWnd MUST already exist !!
  138. m_pWnd = &rWnd;
  139. m_Freedom = fd;
  140. //
  141. // get current's window size
  142. //
  143. CRect rect;
  144. m_pWnd->GetWindowRect(&rect);
  145. CRect rectClient;
  146. m_pWnd->GetClientRect(&rectClient);
  147. if(!pBaseClientSize)
  148. {
  149. m_szClientRelative.cx = rectClient.Width();
  150. m_szClientRelative.cy = rectClient.Height();
  151. m_szMin.cx = rect.Width();
  152. m_szMin.cy = rect.Height();
  153. }
  154. else
  155. {
  156. ASSERT((pBaseClientSize->cx > 0) && (pBaseClientSize->cy > 0));
  157. m_szClientRelative = *pBaseClientSize;
  158. m_szMin.cx = m_szClientRelative.cx + (rect.Width() - rectClient.Width());
  159. m_szMin.cy = m_szClientRelative.cy + (rect.Height() - rectClient.Height());
  160. }
  161. m_szMax.cx = 0;
  162. m_szMax.cy = 0;
  163. //
  164. // set up icon if wanted
  165. //
  166. if(bSizeIcon)
  167. {
  168. VERIFY( m_pWndSizeIcon = new cdxCSizeIconCtrl );
  169. VERIFY( m_pWndSizeIcon->Create(m_pWnd,m_idSizeIcon) ); // creates my control; id is SIZE_CONTROL_ID
  170. AddSzControl(*m_pWndSizeIcon,mdRepos,mdRepos);
  171. m_pWndSizeIcon->ShowWindow(SW_SHOW); // finally - show it
  172. }
  173. }
  174. /////////////////////////////////////////////////////////////////////////////
  175. // control positioning
  176. /////////////////////////////////////////////////////////////////////////////
  177. /*
  178.  * Reposition (with current rectangle size)
  179.  */
  180. void cdxCDynamicControlsManager::ReorganizeControlsAdvanced(const CRect & rectWin, CRect rectClient, bool bRedraw)
  181. {
  182. ASSERT(IsReady());
  183. //
  184. // we won't go smaller with the whole window than
  185. // m_szMin
  186. //
  187. if(rectWin.Width() < m_szMin.cx)
  188. rectClient.right += (m_szMin.cx - rectWin.Width());
  189. if(rectWin.Height() < m_szMin.cy)
  190. rectClient.bottom += (m_szMin.cy - rectWin.Height());
  191. //
  192. // we new replace all controls
  193. //
  194. CSize szDelta;
  195. szDelta.cx = rectClient.Width() - m_szClientRelative.cx;
  196. szDelta.cy = rectClient.Height() - m_szClientRelative.cy;
  197. for(ControlData *sz = m_pFirst; sz; sz = sz->GetNext())
  198. sz->OnSize(szDelta);
  199. if(bRedraw && m_pWnd->IsWindowVisible())
  200. {
  201. m_pWnd->Invalidate();
  202. m_pWnd->UpdateWindow();
  203. }
  204. }
  205. /////////////////////////////////////////////////////////////////////////////
  206. /////////////////////////////////////////////////////////////////////////////
  207. // misc
  208. /////////////////////////////////////////////////////////////////////////////
  209. /*
  210.  * change minimum and maximum height of window.
  211.  * if bResizeIfNecessary is true, FixWindowSize() will be called past
  212.  * applying new values
  213.  *
  214.  * returns false if szMin and szMax are illegal (e.g. szMin > szMax)
  215.  */
  216. bool cdxCDynamicControlsManager::SetMinMaxSize(const CSize & szMin, const CSize & szMax, bool bResizeIfNecessary)
  217. {
  218. ASSERT(IsReady()); // DoInitWindow() not called ?
  219. if((szMin.cx > szMax.cx) ||
  220. (szMin.cy > szMax.cy) ||
  221. !szMax.cx ||
  222. !szMax.cy)
  223. {
  224. return false;
  225. }
  226. m_szMin = szMin;
  227. m_szMax = szMax;
  228. if(bResizeIfNecessary)
  229. FixWindowSize();
  230. return true;
  231. }
  232. /*
  233.  * this function ensure that the window's size is between m_szMin and m_szMax.
  234.  * returns true if window size has been changed
  235.  */
  236. bool cdxCDynamicControlsManager::FixWindowSize(void)
  237. {
  238. ASSERT(IsReady()); // use DoInitWindow() first !
  239. CSize szCurrent = GetWindowSize(*m_pWnd),
  240. szDelta;
  241. if(szCurrent.cx > m_szMax.cx)
  242. szDelta.cx = m_szMax.cx - szCurrent.cx; // is negative
  243. else
  244. if(szCurrent.cx < m_szMin.cx)
  245. szDelta.cx = m_szMin.cx - szCurrent.cx; // is positive
  246. else
  247. szDelta.cx = 0;
  248. if(szCurrent.cy > m_szMax.cy)
  249. szDelta.cy = m_szMax.cy - szCurrent.cy; // is negative
  250. else
  251. if(szCurrent.cy < m_szMin.cy)
  252. szDelta.cy = m_szMin.cy - szCurrent.cy; // is positive
  253. else
  254. szDelta.cy = 0;
  255. if(!szDelta.cx && !szDelta.cy)
  256. return false; // nothing to do
  257. StretchWindow(*m_pWnd,szDelta);
  258. return true;
  259. }
  260. /////////////////////////////////////////////////////////////////////////////
  261. /*
  262.  * hide and show icon
  263.  */
  264. void cdxCDynamicControlsManager::HideSizeIcon(void)
  265. {
  266. if(m_pWndSizeIcon && ::IsWindow(m_pWndSizeIcon->m_hWnd))
  267. m_pWndSizeIcon->ShowWindow(SW_HIDE);
  268. }
  269. void cdxCDynamicControlsManager::ShowSizeIcon(void)
  270. {
  271. if(m_pWndSizeIcon && ::IsWindow(m_pWndSizeIcon->m_hWnd))
  272. m_pWndSizeIcon->ShowWindow(SW_SHOW);
  273. }
  274. /////////////////////////////////////////////////////////////////////////////
  275. // static functions: window sizing
  276. /////////////////////////////////////////////////////////////////////////////
  277. /*
  278.  * stretches the window by szDelta (i.e. if szDelta is 100, the window is enlarged by 100 pixels)
  279.  * stretching means that the center point of the window remains
  280.  *
  281.  * returns false if the window would be smaller than (1,1)
  282.  *
  283.  * NOTE: this function does NOT care of the min/max dimensions of a window
  284.  *
  285.  * STATIC
  286.  */
  287. bool cdxCDynamicControlsManager::StretchWindow(CWnd & rWnd, const CSize & szDelta)
  288. {
  289. ASSERT(::IsWindow(rWnd.m_hWnd));
  290. WINDOWPLACEMENT wpl;
  291. rWnd.GetWindowPlacement(&wpl);
  292. wpl.rcNormalPosition.left -= szDelta.cx / 2;
  293. wpl.rcNormalPosition.right += (szDelta.cx + 1) / 2;
  294. wpl.rcNormalPosition.top -= szDelta.cy / 2;
  295. wpl.rcNormalPosition.bottom += (szDelta.cy + 1) / 2;
  296. wpl.flags = SW_SHOWNA;
  297. if((wpl.rcNormalPosition.left >= wpl.rcNormalPosition.right) ||
  298. (wpl.rcNormalPosition.top >= wpl.rcNormalPosition.bottom))
  299. return false;
  300. VERIFY( rWnd.SetWindowPlacement(&wpl) );
  301. return true;
  302. }
  303. /*
  304.  * stretch window by a percent value
  305.  * the algorithm calculates the new size for both dimensions by:
  306.  *
  307.  *  newWid = oldWid + (oldWid * iAddPcnt) / 100
  308.  *
  309.  * NOTE: iAddPcnt may even be nagtive, but it MUST be greater than -100.
  310.  * NOTE: this function does NOT care of the min/max dimensions of a window
  311.  *
  312.  * The function will return false if the new size would be empty.
  313.  *
  314.  * STATIC
  315.  */
  316. bool cdxCDynamicControlsManager::StretchWindow(CWnd & rWnd, int iAddPcnt)
  317. {
  318. ASSERT(::IsWindow(rWnd.m_hWnd));
  319. CSize szDelta = GetWindowSize(rWnd);
  320. szDelta.cx = (szDelta.cx * iAddPcnt) / 100;
  321. szDelta.cy = (szDelta.cy * iAddPcnt) / 100;
  322. return StretchWindow(rWnd,szDelta);
  323. }
  324. /*
  325.  * get current window's size
  326.  *
  327.  * STATIC
  328.  */
  329. CSize cdxCDynamicControlsManager::GetWindowSize(CWnd & rWnd)
  330. {
  331. ASSERT(::IsWindow(rWnd.m_hWnd));
  332. CRect rect;
  333. rWnd.GetWindowRect(&rect);
  334. return CSize(rect.Width(),rect.Height());
  335. }
  336. /////////////////////////////////////////////////////////////////////////////
  337. // static functions: window & registry
  338. /////////////////////////////////////////////////////////////////////////////
  339. /*
  340.  * stores a window's position and visiblity to the registry.
  341.  *
  342.  * return false if any error occured
  343.  *
  344.  * STATIC
  345.  */
  346. bool cdxCDynamicControlsManager::StoreWindowPosition(CWnd & rWnd, LPCTSTR lpszProfile)
  347. {
  348. ASSERT(::IsWindow(rWnd.m_hWnd) && lpszProfile && *lpszProfile);
  349. // can't use an empty profile section string; see CWinApp::GetProfileInt() for further information
  350. WINDOWPLACEMENT wpl;
  351. VERIFY( rWnd.GetWindowPlacement(&wpl) );
  352. BOOL bVisible = rWnd.IsWindowVisible();
  353. int iState = REGVAL_NOSTATE;
  354. if(rWnd.IsIconic())
  355. iState = REGVAL_ICONIC;
  356. else
  357. if(rWnd.IsZoomed())
  358. iState = REGVAL_MAXIMIZED;
  359. return AfxGetApp()->WriteProfileInt(lpszProfile, lpszRegVal_Valid, REGVAL_INVALID) && // invalidate first
  360. AfxGetApp()->WriteProfileInt(lpszProfile, lpszRegVal_Left, wpl.rcNormalPosition.left) &&
  361. AfxGetApp()->WriteProfileInt(lpszProfile, lpszRegVal_Right, wpl.rcNormalPosition.right) &&
  362. AfxGetApp()->WriteProfileInt(lpszProfile, lpszRegVal_Top, wpl.rcNormalPosition.top) &&
  363. AfxGetApp()->WriteProfileInt(lpszProfile, lpszRegVal_Bottom, wpl.rcNormalPosition.bottom) &&
  364. AfxGetApp()->WriteProfileInt(lpszProfile, lpszRegVal_Visible, bVisible ? REGVAL_VISIBLE : REGVAL_HIDDEN) &&
  365. AfxGetApp()->WriteProfileInt(lpszProfile, lpszRegVal_State, iState) &&
  366. AfxGetApp()->WriteProfileInt(lpszProfile, lpszRegVal_Valid, REGVAL_VALID); // validate position
  367. }
  368. /*
  369.  * load the registry data stored by StoreWindowPosition()
  370.  * returns true if data have been found in the registry
  371.  *
  372.  * STATIC
  373.  */
  374. bool cdxCDynamicControlsManager::RestoreWindowPosition(CWnd & rWnd, LPCTSTR lpszProfile, UINT restoreFlags)
  375. {
  376. ASSERT(::IsWindow(rWnd.m_hWnd) && lpszProfile && *lpszProfile);
  377. // can't use an empty profile section string; see CWinApp::GetProfileInt() for further information
  378. WINDOWPLACEMENT wpl;
  379. bool ok;
  380. VERIFY( rWnd.GetWindowPlacement(&wpl) );
  381. //
  382. // first, we check whether the position had been saved successful any time before
  383. //
  384. if( ok = (AfxGetApp()->GetProfileInt(lpszProfile,lpszRegVal_Valid,REGVAL_INVALID) == REGVAL_VALID) )
  385. {
  386. int iState = AfxGetApp()->GetProfileInt(lpszProfile, lpszRegVal_State, REGVAL_NOSTATE);
  387. //
  388. // get window's previous normal position
  389. //
  390. wpl.rcNormalPosition.left = AfxGetApp()->GetProfileInt(lpszProfile, lpszRegVal_Left, wpl.rcNormalPosition.left);
  391. wpl.rcNormalPosition.right = AfxGetApp()->GetProfileInt(lpszProfile, lpszRegVal_Right, wpl.rcNormalPosition.right);
  392. wpl.rcNormalPosition.top = AfxGetApp()->GetProfileInt(lpszProfile, lpszRegVal_Top, wpl.rcNormalPosition.top);
  393. wpl.rcNormalPosition.bottom = AfxGetApp()->GetProfileInt(lpszProfile, lpszRegVal_Bottom, wpl.rcNormalPosition.bottom);
  394. wpl.showCmd = SW_SHOWNORMAL;
  395. VERIFY( rWnd.SetWindowPlacement(&wpl) );
  396. if(restoreFlags & rflg_state)
  397. {
  398. //
  399. // I have problems in maximizing a window
  400. // - if I do so, the window's restore position will be set to
  401. //   the maximized version.
  402. //   That is quite ugly thus I recommend not to use this option.
  403. // HELP IS WELCOME !!!
  404. //
  405. TRACE(_T("*** NOTE[cdxCDynamicControlsManager::RestoreWindowPosition()]: Restoring a window's state is not fully supported for now - see documentation !n"));
  406. if(iState == REGVAL_MAXIMIZED)
  407. {
  408. rWnd.ShowWindow(SW_MAXIMIZE);
  409. }
  410. else
  411. if(iState == REGVAL_ICONIC)
  412. {
  413. rWnd.ShowWindow(SW_MINIMIZE);
  414. }
  415. }
  416. if(restoreFlags & rflg_visibility)
  417. {
  418. int i = AfxGetApp()->GetProfileInt(lpszProfile, lpszRegVal_Visible, REGVAL_NOSTATE);
  419. if(i == REGVAL_VISIBLE)
  420. rWnd.ShowWindow(SW_SHOW);
  421. else
  422. if(i == REGVAL_HIDDEN)
  423. rWnd.ShowWindow(SW_HIDE);
  424. }
  425. }
  426. return ok;
  427. }