#include "StdAfx.h" #include "UITileLayout.h" namespace DuiLib { IMPLEMENT_DUICONTROL(CTileLayoutUI) CTileLayoutUI::CTileLayoutUI() : m_nColumns(1) { m_szItem.cx = m_szItem.cy = 0; } LPCTSTR CTileLayoutUI::GetClass() const { return _T("TileLayoutUI"); } LPVOID CTileLayoutUI::GetInterface(LPCTSTR pstrName) { if( _tcsicmp(pstrName, DUI_CTR_TILELAYOUT) == 0 ) return static_cast(this); return CContainerUI::GetInterface(pstrName); } SIZE CTileLayoutUI::GetItemSize() const { if(m_pManager != NULL) return m_pManager->GetDPIObj()->Scale(m_szItem); return m_szItem; } void CTileLayoutUI::SetItemSize(SIZE szItem) { if( m_szItem.cx != szItem.cx || m_szItem.cy != szItem.cy ) { m_szItem = szItem; NeedUpdate(); } } int CTileLayoutUI::GetColumns() const { return m_nColumns; } void CTileLayoutUI::SetColumns(int nCols) { if( nCols <= 0 ) return; m_nColumns = nCols; NeedUpdate(); } void CTileLayoutUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue) { if( _tcsicmp(pstrName, _T("itemsize")) == 0 ) { SIZE szItem = { 0 }; LPTSTR pstr = NULL; szItem.cx = _tcstol(pstrValue, &pstr, 10); ASSERT(pstr); szItem.cy = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr); SetItemSize(szItem); } else if( _tcsicmp(pstrName, _T("columns")) == 0 ) SetColumns(_ttoi(pstrValue)); else CContainerUI::SetAttribute(pstrName, pstrValue); } void CTileLayoutUI::SetPos(RECT rc, bool bNeedInvalidate) { CControlUI::SetPos(rc, bNeedInvalidate); rc = m_rcItem; // 内边距调整 RECT rcInset = GetInset(); rc.left += rcInset.left; rc.top += rcInset.top; rc.right -= rcInset.right; rc.bottom -= rcInset.bottom; if (m_items.GetSize() == 0) { ProcessScrollBar(rc, 0, 0); return; } // 预留滚动条空间 if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) rc.right -= m_pVerticalScrollBar->GetFixedWidth(); if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight(); SIZE szItem = GetItemSize(); if (szItem.cx <= 0) szItem.cx = 100; if (szItem.cy <= 0) szItem.cy = 100; int cxItemWithPadding = szItem.cx + m_iChildPadding; m_nColumns = (rc.right - rc.left) / cxItemWithPadding; if (m_nColumns <= 0) m_nColumns = 1; if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) { int nTotalWidth = rc.right - rc.left + m_pHorizontalScrollBar->GetScrollRange(); m_nColumns = nTotalWidth / cxItemWithPadding; if (m_nColumns <= 0) m_nColumns = 1; } int cyNeeded = 0; int iCount = 0; int nVisibleCount = 0; POINT ptTile = { rc.left, rc.top }; if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) ptTile.y -= m_pVerticalScrollBar->GetScrollPos(); int iPosX = rc.left; if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) { iPosX -= m_pHorizontalScrollBar->GetScrollPos(); ptTile.x = iPosX; } for (int it1 = 0; it1 < m_items.GetSize(); it1++) { CControlUI* pControl = static_cast(m_items[it1]); if (!pControl->IsVisible()) continue; if (pControl->IsFloat()) { SetFloatPos(it1); continue; } nVisibleCount++; RECT rcTile = { ptTile.x, ptTile.y, ptTile.x + szItem.cx, ptTile.y + szItem.cy }; RECT rcPos = { rcTile.left, rcTile.top, rcTile.left + szItem.cx, rcTile.top + szItem.cy }; pControl->SetPos(rcPos, bNeedInvalidate); iCount++; if (iCount % m_nColumns == 0) { ptTile.x = iPosX; ptTile.y += szItem.cy + m_iChildPadding; } else { ptTile.x += szItem.cx + m_iChildPadding; } } // 修正1:按“实际行数”计算内容高度,避免最后一个元素正好换行时多算一行 if (nVisibleCount > 0) { int nRows = (nVisibleCount - 1) / m_nColumns + 1; cyNeeded = nRows * szItem.cy + (nRows - 1) * m_iChildPadding; } else { cyNeeded = 0; } // 修正2:滚动中的内容总高度需要补回当前滚动偏移 if (m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) cyNeeded += m_pVerticalScrollBar->GetScrollPos(); ProcessScrollBar(rc, 0, cyNeeded); } }