UIVerticalLayout.cpp 12 KB

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