UIVerticalLayout.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. #include "stdafx.h"
  2. #include "UIVerticalLayout.h"
  3. namespace DuiLib
  4. {
  5. CVerticalLayoutUI::CVerticalLayoutUI()
  6. : m_iSepHeight(0),
  7. m_uButtonState(0),
  8. m_bImmMode(false)
  9. {
  10. __super::m_dwFillMode = GRADIENT_FILL_MODE::VET;
  11. ptLastMouse.x = ptLastMouse.y = 0;
  12. ::ZeroMemory(&m_rcNewPos, sizeof(m_rcNewPos));
  13. }
  14. LPCTSTR CVerticalLayoutUI::GetClass() const
  15. {
  16. return _T("VerticalLayoutUI");
  17. }
  18. LPVOID CVerticalLayoutUI::GetInterface(LPCTSTR pstrName)
  19. {
  20. if( _tcscmp(pstrName, DUI_CTR_VERTICALLAYOUT) == 0 ) return static_cast<CVerticalLayoutUI*>(this);
  21. return CContainerUI::GetInterface(pstrName);
  22. }
  23. UINT CVerticalLayoutUI::GetControlFlags() const
  24. {
  25. if( IsEnabled() && m_iSepHeight != 0 ) return UIFLAG_SETCURSOR;
  26. else return 0;
  27. }
  28. void CVerticalLayoutUI::SetPos(RECT rc, bool bNeedInvalidate)
  29. {
  30. CControlUI::SetPos(rc, bNeedInvalidate);
  31. rc = m_rcItem;
  32. // Adjust for inset
  33. rc.left += m_rcInset.left;
  34. rc.top += m_rcInset.top;
  35. rc.right -= m_rcInset.right;
  36. rc.bottom -= m_rcInset.bottom;
  37. if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) rc.right -= m_pVerticalScrollBar->GetFixedWidth();
  38. if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
  39. if( m_items.GetSize() == 0) {
  40. ProcessScrollBar(rc, 0, 0);
  41. return;
  42. }
  43. // Determine the minimum size
  44. SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };
  45. if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() )
  46. szAvailable.cx += m_pHorizontalScrollBar->GetScrollRange();
  47. int nAdjustables = 0;
  48. int cyFixed = 0;
  49. int nEstimateNum = 0;
  50. for( int it1 = 0; it1 < m_items.GetSize(); it1++ ) {
  51. CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);
  52. if( !pControl->IsVisible() ) continue;
  53. if( pControl->IsFloat() ) continue;
  54. SIZE sz = pControl->EstimateSize(szAvailable);
  55. if( sz.cy == 0 ) {
  56. nAdjustables++;
  57. }
  58. else {
  59. if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
  60. if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();
  61. }
  62. cyFixed += sz.cy + pControl->GetPadding().top + pControl->GetPadding().bottom;
  63. nEstimateNum++;
  64. }
  65. cyFixed += (nEstimateNum - 1) * m_iChildPadding;
  66. // Place elements
  67. int cyNeeded = 0;
  68. int cyExpand = 0;
  69. if( nAdjustables > 0 ) cyExpand = MAX(0, (szAvailable.cy - cyFixed) / nAdjustables);
  70. // Position the elements
  71. SIZE szRemaining = szAvailable;
  72. int iPosY = rc.top;
  73. if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {
  74. iPosY -= m_pVerticalScrollBar->GetScrollPos();
  75. }
  76. int iPosX = rc.left;
  77. if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {
  78. iPosX -= m_pHorizontalScrollBar->GetScrollPos();
  79. }
  80. int iAdjustable = 0;
  81. int cyFixedRemaining = cyFixed;
  82. for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {
  83. CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
  84. if( !pControl->IsVisible() ) continue;
  85. if( pControl->IsFloat() ) {
  86. SetFloatPos(it2);
  87. continue;
  88. }
  89. RECT rcPadding = pControl->GetPadding();
  90. szRemaining.cy -= rcPadding.top;
  91. SIZE sz = pControl->EstimateSize(szRemaining);
  92. if( sz.cy == 0 ) {
  93. iAdjustable++;
  94. sz.cy = cyExpand;
  95. // Distribute remaining to last element (usually round-off left-overs)
  96. if( iAdjustable == nAdjustables ) {
  97. sz.cy = MAX(0, szRemaining.cy - rcPadding.bottom - cyFixedRemaining);
  98. }
  99. if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
  100. if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();
  101. }
  102. else {
  103. if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
  104. if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();
  105. cyFixedRemaining -= sz.cy;
  106. }
  107. sz.cx = pControl->GetFixedWidth();
  108. if( sz.cx == 0 ) sz.cx = szAvailable.cx - rcPadding.left - rcPadding.right;
  109. if( sz.cx < 0 ) sz.cx = 0;
  110. if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();
  111. if( sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth();
  112. RECT rcCtrl = { iPosX + rcPadding.left, iPosY + rcPadding.top, iPosX + rcPadding.left + sz.cx, iPosY + sz.cy + rcPadding.top + rcPadding.bottom };
  113. pControl->SetPos(rcCtrl, false);
  114. iPosY += sz.cy + m_iChildPadding + rcPadding.top + rcPadding.bottom;
  115. cyNeeded += sz.cy + rcPadding.top + rcPadding.bottom;
  116. szRemaining.cy -= sz.cy + m_iChildPadding + rcPadding.bottom;
  117. }
  118. cyNeeded += (nEstimateNum - 1) * m_iChildPadding;
  119. // Process the scrollbar
  120. ProcessScrollBar(rc, 0, cyNeeded);
  121. }
  122. void CVerticalLayoutUI::DoPostPaint(HDC hDC, const RECT& rcPaint)
  123. {
  124. if( (m_uButtonState & UISTATE_CAPTURED) != 0 && !m_bImmMode ) {
  125. RECT rcSeparator = GetThumbRect(true);
  126. CRenderEngine::DrawColor(hDC, rcSeparator, 0xAA000000);
  127. }
  128. }
  129. void CVerticalLayoutUI::SetSepHeight(int iHeight)
  130. {
  131. m_iSepHeight = iHeight;
  132. }
  133. int CVerticalLayoutUI::GetSepHeight() const
  134. {
  135. return m_iSepHeight;
  136. }
  137. void CVerticalLayoutUI::SetSepImmMode(bool bImmediately)
  138. {
  139. if( m_bImmMode == bImmediately ) return;
  140. if( (m_uButtonState & UISTATE_CAPTURED) != 0 && !m_bImmMode && m_pManager != NULL ) {
  141. m_pManager->RemovePostPaint(this);
  142. }
  143. m_bImmMode = bImmediately;
  144. }
  145. bool CVerticalLayoutUI::IsSepImmMode() const
  146. {
  147. return m_bImmMode;
  148. }
  149. void CVerticalLayoutUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
  150. {
  151. if( _tcscmp(pstrName, _T("sepheight")) == 0 ) SetSepHeight(_ttoi(pstrValue));
  152. else if( _tcscmp(pstrName, _T("sepimm")) == 0 ) SetSepImmMode(_tcscmp(pstrValue, _T("true")) == 0);
  153. else CContainerUI::SetAttribute(pstrName, pstrValue);
  154. }
  155. void CVerticalLayoutUI::DoEvent(TEventUI& event)
  156. {
  157. if( m_iSepHeight != 0 ) {
  158. if( event.Type == UIEVENT_BUTTONDOWN && IsEnabled() )
  159. {
  160. RECT rcSeparator = GetThumbRect(false);
  161. if( ::PtInRect(&rcSeparator, event.ptMouse) ) {
  162. m_uButtonState |= UISTATE_CAPTURED;
  163. ptLastMouse = event.ptMouse;
  164. m_rcNewPos = m_rcItem;
  165. if( !m_bImmMode && m_pManager ) m_pManager->AddPostPaint(this);
  166. return;
  167. }
  168. }
  169. if( event.Type == UIEVENT_BUTTONUP )
  170. {
  171. if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
  172. m_uButtonState &= ~UISTATE_CAPTURED;
  173. m_rcItem = m_rcNewPos;
  174. if( !m_bImmMode && m_pManager ) m_pManager->RemovePostPaint(this);
  175. NeedParentUpdate();
  176. return;
  177. }
  178. }
  179. if( event.Type == UIEVENT_MOUSEMOVE )
  180. {
  181. if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
  182. LONG cy = event.ptMouse.y - ptLastMouse.y;
  183. ptLastMouse = event.ptMouse;
  184. RECT rc = m_rcNewPos;
  185. if( m_iSepHeight >= 0 ) {
  186. if( cy > 0 && event.ptMouse.y < m_rcNewPos.bottom + m_iSepHeight ) return;
  187. if( cy < 0 && event.ptMouse.y > m_rcNewPos.bottom ) return;
  188. rc.bottom += cy;
  189. if( rc.bottom - rc.top <= GetMinHeight() ) {
  190. if( m_rcNewPos.bottom - m_rcNewPos.top <= GetMinHeight() ) return;
  191. rc.bottom = rc.top + GetMinHeight();
  192. }
  193. if( rc.bottom - rc.top >= GetMaxHeight() ) {
  194. if( m_rcNewPos.bottom - m_rcNewPos.top >= GetMaxHeight() ) return;
  195. rc.bottom = rc.top + GetMaxHeight();
  196. }
  197. }
  198. else {
  199. if( cy > 0 && event.ptMouse.y < m_rcNewPos.top ) return;
  200. if( cy < 0 && event.ptMouse.y > m_rcNewPos.top + m_iSepHeight ) return;
  201. rc.top += cy;
  202. if( rc.bottom - rc.top <= GetMinHeight() ) {
  203. if( m_rcNewPos.bottom - m_rcNewPos.top <= GetMinHeight() ) return;
  204. rc.top = rc.bottom - GetMinHeight();
  205. }
  206. if( rc.bottom - rc.top >= GetMaxHeight() ) {
  207. if( m_rcNewPos.bottom - m_rcNewPos.top >= GetMaxHeight() ) return;
  208. rc.top = rc.bottom - GetMaxHeight();
  209. }
  210. }
  211. CDuiRect rcInvalidate = GetThumbRect(true);
  212. m_rcNewPos = rc;
  213. m_cxyFixed.cy = m_rcNewPos.bottom - m_rcNewPos.top;
  214. if( m_bImmMode ) {
  215. m_rcItem = m_rcNewPos;
  216. NeedParentUpdate();
  217. }
  218. else {
  219. rcInvalidate.Join(GetThumbRect(true));
  220. rcInvalidate.Join(GetThumbRect(false));
  221. if( m_pManager ) m_pManager->Invalidate(rcInvalidate);
  222. }
  223. return;
  224. }
  225. }
  226. if( event.Type == UIEVENT_SETCURSOR )
  227. {
  228. RECT rcSeparator = GetThumbRect(false);
  229. if( IsEnabled() && ::PtInRect(&rcSeparator, event.ptMouse) ) {
  230. ::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZENS)));
  231. return;
  232. }
  233. }
  234. }
  235. CContainerUI::DoEvent(event);
  236. }
  237. RECT CVerticalLayoutUI::GetThumbRect(bool bUseNew) const
  238. {
  239. if( (m_uButtonState & UISTATE_CAPTURED) != 0 && bUseNew) {
  240. if( m_iSepHeight >= 0 )
  241. return CDuiRect(m_rcNewPos.left, MAX(m_rcNewPos.bottom - m_iSepHeight, m_rcNewPos.top),
  242. m_rcNewPos.right, m_rcNewPos.bottom);
  243. else
  244. return CDuiRect(m_rcNewPos.left, m_rcNewPos.top, m_rcNewPos.right,
  245. MIN(m_rcNewPos.top - m_iSepHeight, m_rcNewPos.bottom));
  246. }
  247. else {
  248. if( m_iSepHeight >= 0 )
  249. return CDuiRect(m_rcItem.left, MAX(m_rcItem.bottom - m_iSepHeight, m_rcItem.top), m_rcItem.right,
  250. m_rcItem.bottom);
  251. else
  252. return CDuiRect(m_rcItem.left, m_rcItem.top, m_rcItem.right,
  253. MIN(m_rcItem.top - m_iSepHeight, m_rcItem.bottom));
  254. }
  255. }
  256. }