ResizableLayout.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // This file is part of ResizableLib
  4. // https://github.com/ppescher/resizablelib
  5. //
  6. // Copyright (C) 2000-2015 by Paolo Messina
  7. // mailto:ppescher@hotmail.com
  8. //
  9. // The contents of this file are subject to the Artistic License 2.0
  10. // http://opensource.org/licenses/Artistic-2.0
  11. //
  12. // If you find this code useful, credits would be nice!
  13. //
  14. /////////////////////////////////////////////////////////////////////////////
  15. /*!
  16. * @file
  17. * @brief Interface for the CResizableLayout class.
  18. */
  19. #if !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_)
  20. #define AFX_RESIZABLELAYOUT_H__INCLUDED_
  21. #include <afxtempl.h>
  22. #include "ResizableMsgSupport.h"
  23. #if _MSC_VER > 1000
  24. #pragma once
  25. #endif // _MSC_VER > 1000
  26. /*! @addtogroup CoreComponents
  27. * @{
  28. */
  29. //! @brief Special type for layout alignment
  30. /*!
  31. * Implements anchor points as a percentage of the parent window client area.
  32. * Control corners are always kept at a fixed distance from their anchor points,
  33. * thus allowing a control to resize proportionally as the parent window is resized.
  34. */
  35. typedef struct tagANCHOR
  36. {
  37. int cx; //!< horizontal component, in percent
  38. int cy; //!< vertical component, in percent
  39. tagANCHOR() {}
  40. tagANCHOR(int x, int y)
  41. {
  42. cx = x;
  43. cy = y;
  44. }
  45. } ANCHOR, *PANCHOR, *LPANCHOR;
  46. /*! @defgroup ConstAnchors Alignment Constants
  47. * Define common layout alignment constants for anchor points.
  48. * @{
  49. */
  50. //! Anchor to the top-left corner
  51. const ANCHOR TOP_LEFT(0, 0);
  52. //! Anchor to the top edge and center horizontally
  53. const ANCHOR TOP_CENTER(50, 0);
  54. //! Anchor to the top-right corner
  55. const ANCHOR TOP_RIGHT(100, 0);
  56. //! Anchor to the left edge and center vertically
  57. const ANCHOR MIDDLE_LEFT(0, 50);
  58. //! Anchor to the center
  59. const ANCHOR MIDDLE_CENTER(50, 50);
  60. //! Anchor to the right edge and center vertically
  61. const ANCHOR MIDDLE_RIGHT(100, 50);
  62. //! Anchor to the bottom-left corner
  63. const ANCHOR BOTTOM_LEFT(0, 100);
  64. //! Anchor to the bottom edge and center horizontally
  65. const ANCHOR BOTTOM_CENTER(50, 100);
  66. //! Anchor to the bottom-right corner
  67. const ANCHOR BOTTOM_RIGHT(100, 100);
  68. // @}
  69. //! @brief Holds a control layout settings
  70. /*!
  71. * Layout settings specify how a control must be moved and resized with respect to
  72. * the parent window and how it reacts to dynamic changes to its size when painting
  73. * its client area, with special care for flickering.
  74. */
  75. typedef struct tagLAYOUTINFO
  76. {
  77. //! Handle of the window the layout of which is being defined
  78. HWND hWnd;
  79. //! Identification number assigned to the callback slot
  80. UINT nCallbackID;
  81. //! Window class name to identify standard controls
  82. TCHAR sWndClass[MAX_PATH];
  83. //! Anchor point for the top-left corner
  84. ANCHOR anchorTopLeft;
  85. //! Fixed distance for the top-left corner
  86. SIZE marginTopLeft;
  87. //! Anchor point for the bottom-right corner
  88. ANCHOR anchorBottomRight;
  89. //! Fixed distance for the bottom-right corner
  90. SIZE marginBottomRight;
  91. //! Flag that enables support for custom windows
  92. BOOL bMsgSupport;
  93. //! Redraw settings for anti-flickering and proper painting
  94. RESIZEPROPERTIES properties;
  95. tagLAYOUTINFO() : hWnd(NULL), nCallbackID(0), bMsgSupport(FALSE)
  96. {
  97. sWndClass[0] = 0;
  98. }
  99. tagLAYOUTINFO(HWND hwnd, ANCHOR tl_type, SIZE tl_margin,
  100. ANCHOR br_type, SIZE br_margin)
  101. :
  102. hWnd(hwnd), nCallbackID(0), bMsgSupport(FALSE),
  103. anchorTopLeft(tl_type), marginTopLeft(tl_margin),
  104. anchorBottomRight(br_type), marginBottomRight(br_margin)
  105. {
  106. sWndClass[0] = 0;
  107. }
  108. } LAYOUTINFO, *PLAYOUTINFO, *LPLAYOUTINFO;
  109. //! @brief Layout manager implementation
  110. /*!
  111. * Derive from this class to implement resizable windows, adding the ability
  112. * to dinamically resize and reposition child controls.
  113. * Special care is taken to ensure a smooth animation during the resize
  114. * operations performed by the users, without annoying flickering effects.
  115. */
  116. class CResizableLayout
  117. {
  118. private:
  119. //@{
  120. //! @brief Collection of layout settings for each control
  121. CMap<HWND, HWND, POSITION, POSITION> m_mapLayout;
  122. CList<LAYOUTINFO, LAYOUTINFO&> m_listLayout;
  123. CList<LAYOUTINFO, LAYOUTINFO&> m_listLayoutCB;
  124. //@}
  125. //@{
  126. //! @brief Used for clipping implementation
  127. HRGN m_hOldClipRgn;
  128. int m_nOldClipRgn;
  129. //@}
  130. //@{
  131. //! @brief Used for advanced anti-flickering
  132. RECT m_rectClientBefore;
  133. BOOL m_bNoRecursion;
  134. //@}
  135. //! @brief Apply clipping settings for the specified control
  136. void ClipChildWindow(const LAYOUTINFO &layout, CRgn* pRegion) const;
  137. //! @brief Helper function to calculate new layout
  138. void CalcNewChildPosition(const LAYOUTINFO &layout,
  139. const CRect &rectParent, CRect &rectChild, UINT& uFlags) const;
  140. protected:
  141. //! @brief Override to initialize resize properties (clipping, refresh)
  142. virtual void InitResizeProperties(LAYOUTINFO& layout) const;
  143. //! @brief Override to specify clipping for unsupported windows
  144. virtual BOOL LikesClipping(const LAYOUTINFO &layout) const;
  145. //! @brief Override to specify refresh for unsupported windows
  146. virtual BOOL NeedsRefresh(const LAYOUTINFO &layout,
  147. const CRect &rectOld, const CRect &rectNew) const;
  148. //! @brief Clip controls in the layout out of the specified device context
  149. BOOL ClipChildren(CDC* pDC, BOOL bUndo);
  150. //! @brief Get the layout clipping region
  151. void GetClippingRegion(CRgn* pRegion) const;
  152. //! @brief Override for scrollable or expanding parent windows
  153. virtual void GetTotalClientRect(LPRECT lpRect) const;
  154. //@{
  155. //! @brief Add anchor points for the specified control to the layout
  156. void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight);
  157. void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft)
  158. {
  159. AddAnchor(hWnd, anchorTopLeft, anchorTopLeft);
  160. }
  161. void AddAnchor(UINT nID, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight)
  162. {
  163. AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID),
  164. anchorTopLeft, anchorBottomRight);
  165. }
  166. void AddAnchor(UINT nID, ANCHOR anchorTopLeft)
  167. {
  168. AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID),
  169. anchorTopLeft, anchorTopLeft);
  170. }
  171. //@}
  172. //@{
  173. //! @brief Add anchor points for all the remaining controls to the layout
  174. void AddAllOtherAnchors(ANCHOR anchor);
  175. void AddAllOtherAnchors()
  176. {
  177. AddAllOtherAnchors(TOP_LEFT);
  178. }
  179. //@}
  180. //! @brief Add a callback slot to the layout for dynamic controls or anchor points
  181. UINT AddAnchorCallback();
  182. //@{
  183. //! @brief Get position and size of a control in the layout from the parent's client area
  184. BOOL GetAnchorPosition(HWND hWnd, const CRect &rectParent,
  185. CRect &rectChild, UINT* lpFlags = NULL) const
  186. {
  187. POSITION pos;
  188. if (!m_mapLayout.Lookup(hWnd, pos))
  189. return FALSE;
  190. UINT uTmpFlags;
  191. CalcNewChildPosition(m_listLayout.GetAt(pos), rectParent, rectChild,
  192. (lpFlags != NULL) ? (*lpFlags) : uTmpFlags);
  193. return TRUE;
  194. }
  195. BOOL GetAnchorPosition(UINT nID, const CRect &rectParent,
  196. CRect &rectChild, UINT* lpFlags = NULL) const
  197. {
  198. return GetAnchorPosition(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID),
  199. rectParent, rectChild, lpFlags);
  200. }
  201. //@}
  202. //@{
  203. //! @brief Get margins surrounding a control in the layout with the given size
  204. BOOL GetAnchorMargins(HWND hWnd, const CSize &sizeChild, CRect &rectMargins) const;
  205. BOOL GetAnchorMargins(UINT nID, const CSize &sizeChild, CRect &rectMargins) const
  206. {
  207. return GetAnchorMargins(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID),
  208. sizeChild, rectMargins);
  209. }
  210. //@}
  211. //@{
  212. //! @brief Remove a control from the layout
  213. BOOL RemoveAnchor(HWND hWnd)
  214. {
  215. POSITION pos;
  216. if (!m_mapLayout.Lookup(hWnd, pos))
  217. return FALSE;
  218. m_listLayout.RemoveAt(pos);
  219. return m_mapLayout.RemoveKey(hWnd);
  220. }
  221. BOOL RemoveAnchor(UINT nID)
  222. {
  223. return RemoveAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID));
  224. }
  225. //@}
  226. //! @brief Reset the layout content
  227. void RemoveAllAnchors()
  228. {
  229. m_mapLayout.RemoveAll();
  230. m_listLayout.RemoveAll();
  231. m_listLayoutCB.RemoveAll();
  232. }
  233. //! @brief Reposition and size all the controls in the layout
  234. void ArrangeLayout() const;
  235. //! @brief Override to provide dynamic control's layout info
  236. virtual BOOL ArrangeLayoutCallback(LAYOUTINFO& layout) const;
  237. //! @brief Override to provide the parent window
  238. virtual CWnd* GetResizableWnd() const = 0;
  239. //! @brief Enhance anti-flickering
  240. void HandleNcCalcSize(BOOL bAfterDefault, LPNCCALCSIZE_PARAMS lpncsp, LRESULT& lResult);
  241. //! @brief Enable resizable style for top level parent windows
  242. void MakeResizable(LPCREATESTRUCT lpCreateStruct);
  243. public:
  244. CResizableLayout()
  245. {
  246. m_bNoRecursion = FALSE;
  247. m_hOldClipRgn = ::CreateRectRgn(0,0,0,0);
  248. m_nOldClipRgn = 0;
  249. }
  250. virtual ~CResizableLayout()
  251. {
  252. ::DeleteObject(m_hOldClipRgn);
  253. // just for safety
  254. RemoveAllAnchors();
  255. }
  256. };
  257. // @}
  258. #endif // !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_)