UITileLayout.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #include "StdAfx.h"
  2. #include "UITileLayout.h"
  3. namespace DuiLib
  4. {
  5. IMPLEMENT_DUICONTROL(CTileLayoutUI)
  6. CTileLayoutUI::CTileLayoutUI() : m_nColumns(1)
  7. {
  8. m_szItem.cx = m_szItem.cy = 0;
  9. }
  10. LPCTSTR CTileLayoutUI::GetClass() const
  11. {
  12. return _T("TileLayoutUI");
  13. }
  14. LPVOID CTileLayoutUI::GetInterface(LPCTSTR pstrName)
  15. {
  16. if( _tcsicmp(pstrName, DUI_CTR_TILELAYOUT) == 0 ) return static_cast<CTileLayoutUI*>(this);
  17. return CContainerUI::GetInterface(pstrName);
  18. }
  19. SIZE CTileLayoutUI::GetItemSize() const
  20. {
  21. if(m_pManager != NULL) return m_pManager->GetDPIObj()->Scale(m_szItem);
  22. return m_szItem;
  23. }
  24. void CTileLayoutUI::SetItemSize(SIZE szItem)
  25. {
  26. if( m_szItem.cx != szItem.cx || m_szItem.cy != szItem.cy ) {
  27. m_szItem = szItem;
  28. NeedUpdate();
  29. }
  30. }
  31. int CTileLayoutUI::GetColumns() const
  32. {
  33. return m_nColumns;
  34. }
  35. void CTileLayoutUI::SetColumns(int nCols)
  36. {
  37. if( nCols <= 0 ) return;
  38. m_nColumns = nCols;
  39. NeedUpdate();
  40. }
  41. void CTileLayoutUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
  42. {
  43. if( _tcsicmp(pstrName, _T("itemsize")) == 0 ) {
  44. SIZE szItem = { 0 };
  45. LPTSTR pstr = NULL;
  46. szItem.cx = _tcstol(pstrValue, &pstr, 10); ASSERT(pstr);
  47. szItem.cy = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
  48. SetItemSize(szItem);
  49. }
  50. else if( _tcsicmp(pstrName, _T("columns")) == 0 ) SetColumns(_ttoi(pstrValue));
  51. else CContainerUI::SetAttribute(pstrName, pstrValue);
  52. }
  53. void CTileLayoutUI::SetPos(RECT rc, bool bNeedInvalidate)
  54. {
  55. CControlUI::SetPos(rc, bNeedInvalidate);
  56. rc = m_rcItem;
  57. // 内边距调整
  58. RECT rcInset = GetInset();
  59. rc.left += rcInset.left;
  60. rc.top += rcInset.top;
  61. rc.right -= rcInset.right;
  62. rc.bottom -= rcInset.bottom;
  63. if (m_items.GetSize() == 0)
  64. {
  65. ProcessScrollBar(rc, 0, 0);
  66. return;
  67. }
  68. // 预留滚动条空间
  69. if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible())
  70. rc.right -= m_pVerticalScrollBar->GetFixedWidth();
  71. if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible())
  72. rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
  73. // ========== 核心:固定子控件尺寸(不再动态计算) ==========
  74. SIZE szItem = GetItemSize();
  75. // 确保ItemSize有效,避免除0
  76. if (szItem.cx <= 0) szItem.cx = 100; // 兜底默认宽度
  77. if (szItem.cy <= 0) szItem.cy = 100; // 兜底默认高度
  78. // ========== 核心:固定列数计算(基于固定宽度+水平间距) ==========
  79. int cxItemWithPadding = szItem.cx + m_iChildPadding; // 单个子控件占宽(含水平间距)
  80. m_nColumns = (rc.right - rc.left) / cxItemWithPadding;
  81. if (m_nColumns <= 0) m_nColumns = 1;
  82. // 滚动条兼容处理
  83. if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible())
  84. {
  85. int nTotalWidth = rc.right - rc.left + m_pHorizontalScrollBar->GetScrollRange();
  86. m_nColumns = nTotalWidth / cxItemWithPadding;
  87. if (m_nColumns <= 0) m_nColumns = 1;
  88. }
  89. // 布局初始化
  90. int cyNeeded = 0;
  91. int iCount = 0;
  92. POINT ptTile = { rc.left, rc.top };
  93. // 垂直滚动条偏移
  94. if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible())
  95. ptTile.y -= m_pVerticalScrollBar->GetScrollPos();
  96. // 水平滚动条偏移
  97. int iPosX = rc.left;
  98. if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible())
  99. {
  100. iPosX -= m_pHorizontalScrollBar->GetScrollPos();
  101. ptTile.x = iPosX;
  102. }
  103. // ========== 遍历子控件:固定宽高+固定间距布局 ==========
  104. for (int it1 = 0; it1 < m_items.GetSize(); it1++)
  105. {
  106. CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);
  107. if (!pControl->IsVisible()) continue;
  108. if (pControl->IsFloat())
  109. {
  110. SetFloatPos(it1);
  111. continue;
  112. }
  113. // ========== 核心1:固定子控件位置(无动态尺寸计算) ==========
  114. RECT rcTile = {
  115. ptTile.x, // 左
  116. ptTile.y, // 上
  117. ptTile.x + szItem.cx, // 右(固定宽度)
  118. ptTile.y + szItem.cy // 下(固定高度)
  119. };
  120. // 忽略子控件自身padding,强制使用固定尺寸(如需保留padding可删除此段)
  121. // RECT rcPadding = pControl->GetPadding();
  122. // rcTile.left += rcPadding.left;
  123. // rcTile.right -= rcPadding.right;
  124. // rcTile.top += rcPadding.top;
  125. // rcTile.bottom -= rcPadding.bottom;
  126. // ========== 核心2:强制子控件尺寸为ItemSize(覆盖所有动态计算) ==========
  127. RECT rcPos = {
  128. rcTile.left,
  129. rcTile.top,
  130. rcTile.left + szItem.cx,
  131. rcTile.top + szItem.cy
  132. };
  133. pControl->SetPos(rcPos, bNeedInvalidate);
  134. // ========== 核心3:固定间距更新坐标 ==========
  135. iCount++;
  136. // 换行:重置X坐标,Y坐标 += 固定高度 + 垂直间距
  137. if (iCount % m_nColumns == 0)
  138. {
  139. ptTile.x = iPosX;
  140. ptTile.y += szItem.cy + m_iChildPadding; // 垂直间距 = m_iChildPadding
  141. }
  142. // 不换行:X坐标 += 固定宽度 + 水平间距
  143. else
  144. {
  145. ptTile.x += szItem.cx + m_iChildPadding; // 水平间距 = m_iChildPadding
  146. }
  147. // 更新总高度(用于滚动条)
  148. cyNeeded = ptTile.y - rc.top + szItem.cy;
  149. if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible())
  150. cyNeeded += m_pVerticalScrollBar->GetScrollPos();
  151. }
  152. // 处理滚动条
  153. ProcessScrollBar(rc, 0, cyNeeded);
  154. }
  155. }