void CWeightHorizontalLayoutUI::SetPos(RECT rc)
{
CControlUI::SetPos(rc);
rc = m_rcItem;
std::map<CControlUI*, int /*width*/> mapAjust;
// Adjust for inset
rc.left += m_rcInset.left;
rc.top += m_rcInset.top;
rc.right -= m_rcInset.right;
rc.bottom -= m_rcInset.bottom;
if (m_items.GetSize() == 0) {
ProcessScrollBar(rc, 0, 0);
return;
}
if (!m_bScrollFloat && m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible())
rc.right -= m_pVerticalScrollBar->GetFixedWidth();
if (!m_bScrollFloat && m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible())
rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
ResetWeightDisplayControlState();
// 读取当前子控件的权重
m_mapWeight.clear();
for (int i = 0; i < m_items.GetSize(); i++) {
DuiLib::CControlUI* pControl = static_cast<DuiLib::CControlUI*>(m_items[i]);
if (pControl == nullptr) continue;
CStdString strweight = pControl->GetCustomAttribute(L"weight");
int nweight = _ttoi(strweight.GetData());
m_mapWeight[i] = nweight;
}
m_mapWeightCache = m_mapWeight;
// 查找最小权重控件
auto HideMinWeigth = [&](int index) -> bool {
CControlUI* pControl = static_cast<CControlUI*>(m_items[index]);
if (pControl && pControl->IsVisible()) {
pControl->SetInternVisible(false);
m_arrWeightHideControl.push_back(pControl);
return true;
}
return false;
};
// Determine the width of elements that are sizeable
SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };
if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible())
szAvailable.cx += m_pHorizontalScrollBar->GetScrollRange();
int nAdjustables = 0;
int cxFixed = 0;
int nEstimateNum = 0;
int cxExpand = 0;
std::pair<int, int> min_weight; // first:control index, second:weight
std::map<CControlUI*, int /*width*/> m_mapEstimateWidth; // 试算时控件的预设宽度
std::map<CControlUI*, int /*width*/> m_mapBookWidth;
do {
// 查找出当前权重值最小,并且显示着的控件
min_weight = std::make_pair(999, 999);
std::for_each(m_mapWeight.begin(), m_mapWeight.end(), [&](std::pair<int, int> item)-> void {
CControlUI* pControl = static_cast<CControlUI*>(m_items[item.first]);
if (item.second <= min_weight.second && pControl->IsVisible())
min_weight = item;
});
// 已经找到后从map中移除,以避免下次查找的还是这个控件
auto min_it = std::find_if(m_mapWeight.begin(), m_mapWeight.end(), [min_weight](std::pair<int, int> item)-> bool {
return (item.first == min_weight.first && item.second == item.second);
});
if (min_it != m_mapWeight.end()) m_mapWeight.erase(min_it);
// 试算中
nAdjustables = 0;
cxFixed = 0;
nEstimateNum = 0;
for (int it1 = 0; it1 < m_items.GetSize(); it1++) {
CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);
if (pControl->IsFloat()) continue;
if (!pControl->IsVisible()) continue;
SIZE sz = pControl->EstimateSize(szAvailable);
if (sz.cx == 0) {
nAdjustables++;
}
else {
if (sz.cx < pControl->GetMinWidth()) sz.cx = pControl->GetMinWidth();
if (sz.cx > pControl->GetMaxWidth()) sz.cx = pControl->GetMaxWidth();
}
m_mapEstimateWidth[pControl] = sz.cx;
cxFixed += sz.cx + pControl->GetPadding().left + pControl->GetPadding().right;
nEstimateNum++;
}
cxFixed += (nEstimateNum - 1) * m_iChildPadding;
cxExpand = 0;
if (nAdjustables > 0) cxExpand = max(0, (szAvailable.cx - cxFixed) / nAdjustables);
// 此处下节解释
// 如果小于空间不够,先尝试从低到高缩减带有adjust属性的控件
if (szAvailable.cx - cxFixed < 0) {
std::vector<std::pair<CControlUI*, int>> adj_ctrls;
for (int it1 = 0; it1 < m_items.GetSize(); it1++) {
CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);
if (pControl->IsFloat()) continue;
//if (!pControl->IsVisible()) continue;
if (pControl->GetCustomAttribute(L"adjustwidth") == NULL ||
_tcscmp(pControl->GetCustomAttribute(L"adjustwidth"), L"true")) continue;
adj_ctrls.push_back(std::make_pair(pControl, m_mapWeightCache[it1]));
}
// 自小到大按权重,先尝试最小权重
std::sort(adj_ctrls.begin(), adj_ctrls.end(), [&](std::pair<CControlUI*, int> lhs,
std::pair<CControlUI*, int> rhs) -> bool {
return lhs.second < rhs.second;
});
for (auto it = adj_ctrls.begin(); it != adj_ctrls.end(); it++) {
auto ctrl = it->first;
if (m_mapEstimateWidth[ctrl] > ctrl->GetMinWidth()) {
int sub_width = min(abs(szAvailable.cx - cxFixed), m_mapEstimateWidth[ctrl] - ctrl->GetMinWidth());
m_mapEstimateWidth[ctrl] = m_mapEstimateWidth[ctrl] - sub_width; // 新的试算宽度
m_mapBookWidth[ctrl] = m_mapEstimateWidth[ctrl];
cxFixed -= sub_width;
if (szAvailable.cx - cxFixed >= 0) break; // 已经满足排列空间
}
}
}
// 空间不够,从权重最小的依次隐藏
} while (szAvailable.cx - cxFixed < 0 && HideMinWeigth(min_weight.first));
// Position the elements
SIZE szRemaining = szAvailable;
int iPosX = rc.left;
if (m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) {
iPosX -= m_pHorizontalScrollBar->GetScrollPos();
}
int iAdjustable = 0;
int cxFixedRemaining = cxFixed;
for (int it2 = 0; it2 < m_items.GetSize(); it2++) {
CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
if (!pControl->IsVisible()) continue;
if (pControl->IsFloat()) {
SetFloatPos(it2);
continue;
}
RECT rcPadding = pControl->GetPadding();
szRemaining.cx -= rcPadding.left;
SIZE sz = pControl->EstimateSize(szRemaining);
if (sz.cx == 0) {
iAdjustable++;
sz.cx = cxExpand;
//最后一个自适应尺寸大小无需另行计算
//if( iAdjustable == nAdjustables ) {
// sz.cx = MAX(0, szRemaining.cx -cxFixedRemaining);
//}
if (sz.cx < pControl->GetMinWidth()) sz.cx = pControl->GetMinWidth();
if (sz.cx > pControl->GetMaxWidth()) sz.cx = pControl->GetMaxWidth();
}
else {
if (sz.cx < pControl->GetMinWidth()) sz.cx = pControl->GetMinWidth();
if (sz.cx > pControl->GetMaxWidth()) sz.cx = pControl->GetMaxWidth();
}
sz.cy = pControl->GetFixedHeight();
if (sz.cy == 0) sz.cy = rc.bottom - rc.top - rcPadding.top - rcPadding.bottom;
if (sz.cy < 0) sz.cy = 0;
if (sz.cy < pControl->GetMinHeight()) sz.cy = pControl->GetMinHeight();
if (sz.cy > pControl->GetMaxHeight()) sz.cy = pControl->GetMaxHeight();
//padding不算控件宽度//2012/09/12
//RECT rcCtrl = { iPosX + rcPadding.left, rc.top + rcPadding.top, iPosX + sz.cx + rcPadding.left + rcPadding.right, rc.top + rcPadding.top + sz.cy};
if (m_mapBookWidth.find(pControl) != m_mapBookWidth.end() &&
m_mapBookWidth[pControl] != sz.cx) {
sz.cx = m_mapBookWidth[pControl];
}
RECT rcCtrl = { iPosX + rcPadding.left, rc.top + rcPadding.top, min(iPosX + sz.cx + rcPadding.left, rc.right) , rc.top + rcPadding.top + sz.cy };
pControl->SetPos(rcCtrl);
iPosX += sz.cx + m_iChildPadding + rcPadding.left + rcPadding.right;
szRemaining.cx -= sz.cx + m_iChildPadding + rcPadding.right;
if (m_bWholeDisplay && rcCtrl.right > rc.left + szAvailable.cx)
m_arrWholeDisplayControl.push_back(pControl);
}
// Process the scrollbar
ProcessScrollBar(rc, 0, 0);
}
原文:http://blog.csdn.net/int_tulip/article/details/54929868