mirror of
https://github.com/duilib/duilib.git
synced 2026-10-18 14:50:35 +08:00
333 lines
12 KiB
C++
333 lines
12 KiB
C++
#include "stdafx.h"
|
|
#include "UIHorizontalLayout.h"
|
|
|
|
namespace DuiLib
|
|
{
|
|
CHorizontalLayoutUI::CHorizontalLayoutUI() : m_iSepWidth(0), m_uButtonState(0), m_bImmMode(false)
|
|
{
|
|
m_ptLastMouse.x = m_ptLastMouse.y = 0;
|
|
::ZeroMemory(&m_rcNewPos, sizeof(m_rcNewPos));
|
|
}
|
|
|
|
LPCTSTR CHorizontalLayoutUI::GetClass() const
|
|
{
|
|
return DUI_CTR_HORIZONTALLAYOUT;
|
|
}
|
|
|
|
LPVOID CHorizontalLayoutUI::GetInterface(LPCTSTR pstrName)
|
|
{
|
|
if( _tcscmp(pstrName, DUI_CTR_HORIZONTALLAYOUT) == 0 ) return static_cast<CHorizontalLayoutUI*>(this);
|
|
return CContainerUI::GetInterface(pstrName);
|
|
}
|
|
|
|
UINT CHorizontalLayoutUI::GetControlFlags() const
|
|
{
|
|
if( IsEnabled() && m_iSepWidth != 0 ) return UIFLAG_SETCURSOR;
|
|
else return 0;
|
|
}
|
|
|
|
void CHorizontalLayoutUI::SetPos(RECT rc, bool bNeedInvalidate)
|
|
{
|
|
CControlUI::SetPos(rc, bNeedInvalidate);
|
|
rc = m_rcItem;
|
|
|
|
// 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_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) rc.right -= m_pVerticalScrollBar->GetFixedWidth();
|
|
if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
|
|
|
|
if( m_items.GetSize() == 0) {
|
|
ProcessScrollBar(rc, 0, 0);
|
|
return;
|
|
}
|
|
|
|
// Determine the minimum size
|
|
SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };
|
|
if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() )
|
|
szAvailable.cx += m_pHorizontalScrollBar->GetScrollRange();
|
|
if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() )
|
|
szAvailable.cy += m_pVerticalScrollBar->GetScrollRange();
|
|
|
|
int cyNeeded = 0;
|
|
int nAdjustables = 0;
|
|
int cxFixed = 0;
|
|
int nEstimateNum = 0;
|
|
SIZE szControlAvailable;
|
|
int iControlMaxWidth = 0;
|
|
int iControlMaxHeight = 0;
|
|
for( int it1 = 0; it1 < m_items.GetSize(); it1++ ) {
|
|
CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);
|
|
if( !pControl->IsVisible() ) continue;
|
|
if( pControl->IsFloat() ) continue;
|
|
szControlAvailable = szAvailable;
|
|
RECT rcPadding = pControl->GetPadding();
|
|
szControlAvailable.cy -= rcPadding.top + rcPadding.bottom;
|
|
iControlMaxWidth = pControl->GetFixedWidth();
|
|
iControlMaxHeight = pControl->GetFixedHeight();
|
|
if (iControlMaxWidth <= 0) iControlMaxWidth = pControl->GetMaxWidth();
|
|
if (iControlMaxHeight <= 0) iControlMaxHeight = pControl->GetMaxHeight();
|
|
if (szControlAvailable.cx > iControlMaxWidth) szControlAvailable.cx = iControlMaxWidth;
|
|
if (szControlAvailable.cy > iControlMaxHeight) szControlAvailable.cy = iControlMaxHeight;
|
|
SIZE sz = { 0 };
|
|
if (pControl->GetFixedWidth() == 0) {
|
|
nAdjustables++;
|
|
sz.cy = pControl->GetFixedHeight();
|
|
}
|
|
else {
|
|
sz = pControl->EstimateSize(szControlAvailable);
|
|
if (sz.cx == 0) {
|
|
nAdjustables++;
|
|
}
|
|
else {
|
|
if (sz.cx < pControl->GetMinWidth()) sz.cx = pControl->GetMinWidth();
|
|
if (sz.cx > pControl->GetMaxWidth()) sz.cx = pControl->GetMaxWidth();
|
|
}
|
|
}
|
|
|
|
cxFixed += sz.cx + pControl->GetPadding().left + pControl->GetPadding().right;
|
|
|
|
sz.cy = MAX(sz.cy, 0);
|
|
if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
|
|
if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();
|
|
cyNeeded = MAX(cyNeeded, sz.cy + rcPadding.top + rcPadding.bottom);
|
|
nEstimateNum++;
|
|
}
|
|
cxFixed += (nEstimateNum - 1) * m_iChildPadding;
|
|
|
|
// Place elements
|
|
int cxNeeded = 0;
|
|
int cxExpand = 0;
|
|
if( nAdjustables > 0 ) cxExpand = MAX(0, (szAvailable.cx - cxFixed) / nAdjustables);
|
|
// Position the elements
|
|
SIZE szRemaining = szAvailable;
|
|
int iPosX = rc.left;
|
|
if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {
|
|
iPosX -= m_pHorizontalScrollBar->GetScrollPos();
|
|
}
|
|
int iEstimate = 0;
|
|
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;
|
|
}
|
|
|
|
iEstimate += 1;
|
|
RECT rcPadding = pControl->GetPadding();
|
|
szRemaining.cx -= rcPadding.left;
|
|
|
|
szControlAvailable = szRemaining;
|
|
szControlAvailable.cy -= rcPadding.top + rcPadding.bottom;
|
|
iControlMaxWidth = pControl->GetFixedWidth();
|
|
iControlMaxHeight = pControl->GetFixedHeight();
|
|
if (iControlMaxWidth <= 0) iControlMaxWidth = pControl->GetMaxWidth();
|
|
if (iControlMaxHeight <= 0) iControlMaxHeight = pControl->GetMaxHeight();
|
|
if (szControlAvailable.cx > iControlMaxWidth) szControlAvailable.cx = iControlMaxWidth;
|
|
if (szControlAvailable.cy > iControlMaxHeight) szControlAvailable.cy = iControlMaxHeight;
|
|
cxFixedRemaining = cxFixedRemaining - (rcPadding.left + rcPadding.right);
|
|
if (iEstimate > 1) cxFixedRemaining = cxFixedRemaining - m_iChildPadding;
|
|
SIZE sz = pControl->EstimateSize(szControlAvailable);
|
|
if (pControl->GetFixedWidth() == 0 || sz.cx == 0) {
|
|
iAdjustable++;
|
|
sz.cx = cxExpand;
|
|
// Distribute remaining to last element (usually round-off left-overs)
|
|
if( iAdjustable == nAdjustables ) {
|
|
sz.cx = MAX(0, szRemaining.cx - rcPadding.right - 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();
|
|
cxFixedRemaining -= sz.cx;
|
|
}
|
|
|
|
sz.cy = pControl->GetMaxHeight();
|
|
if( sz.cy == 0 ) sz.cy = szAvailable.cy - rcPadding.top - rcPadding.bottom;
|
|
if( sz.cy < 0 ) sz.cy = 0;
|
|
if( sz.cy > szControlAvailable.cy ) sz.cy = szControlAvailable.cy;
|
|
if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
|
|
|
|
UINT iChildAlign = GetChildVAlign();
|
|
if (iChildAlign == DT_VCENTER) {
|
|
int iPosY = (rc.bottom + rc.top) / 2;
|
|
if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {
|
|
iPosY += m_pVerticalScrollBar->GetScrollRange() / 2;
|
|
iPosY -= m_pVerticalScrollBar->GetScrollPos();
|
|
}
|
|
RECT rcCtrl = { iPosX + rcPadding.left, iPosY - sz.cy/2, iPosX + sz.cx + rcPadding.left, iPosY + sz.cy - sz.cy/2 };
|
|
pControl->SetPos(rcCtrl, false);
|
|
}
|
|
else if (iChildAlign == DT_BOTTOM) {
|
|
int iPosY = rc.bottom;
|
|
if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {
|
|
iPosY += m_pVerticalScrollBar->GetScrollRange();
|
|
iPosY -= m_pVerticalScrollBar->GetScrollPos();
|
|
}
|
|
RECT rcCtrl = { iPosX + rcPadding.left, iPosY - rcPadding.bottom - sz.cy, iPosX + sz.cx + rcPadding.left, iPosY - rcPadding.bottom };
|
|
pControl->SetPos(rcCtrl, false);
|
|
}
|
|
else {
|
|
int iPosY = rc.top;
|
|
if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {
|
|
iPosY -= m_pVerticalScrollBar->GetScrollPos();
|
|
}
|
|
RECT rcCtrl = { iPosX + rcPadding.left, iPosY + rcPadding.top, iPosX + sz.cx + rcPadding.left, iPosY + sz.cy + rcPadding.top };
|
|
pControl->SetPos(rcCtrl, false);
|
|
}
|
|
|
|
iPosX += sz.cx + m_iChildPadding + rcPadding.left + rcPadding.right;
|
|
cxNeeded += sz.cx + rcPadding.left + rcPadding.right;
|
|
szRemaining.cx -= sz.cx + m_iChildPadding + rcPadding.right;
|
|
}
|
|
cxNeeded += (nEstimateNum - 1) * m_iChildPadding;
|
|
|
|
// Process the scrollbar
|
|
ProcessScrollBar(rc, cxNeeded, cyNeeded);
|
|
}
|
|
|
|
void CHorizontalLayoutUI::DoPostPaint(HDC hDC, const RECT& rcPaint)
|
|
{
|
|
if( (m_uButtonState & UISTATE_CAPTURED) != 0 && !m_bImmMode ) {
|
|
RECT rcSeparator = GetThumbRect(true);
|
|
CRenderEngine::DrawColor(hDC, rcSeparator, 0xAA000000);
|
|
}
|
|
}
|
|
|
|
void CHorizontalLayoutUI::SetSepWidth(int iWidth)
|
|
{
|
|
m_iSepWidth = iWidth;
|
|
}
|
|
|
|
int CHorizontalLayoutUI::GetSepWidth() const
|
|
{
|
|
return m_iSepWidth;
|
|
}
|
|
|
|
void CHorizontalLayoutUI::SetSepImmMode(bool bImmediately)
|
|
{
|
|
if( m_bImmMode == bImmediately ) return;
|
|
if( (m_uButtonState & UISTATE_CAPTURED) != 0 && !m_bImmMode && m_pManager != NULL ) {
|
|
m_pManager->RemovePostPaint(this);
|
|
}
|
|
|
|
m_bImmMode = bImmediately;
|
|
}
|
|
|
|
bool CHorizontalLayoutUI::IsSepImmMode() const
|
|
{
|
|
return m_bImmMode;
|
|
}
|
|
|
|
void CHorizontalLayoutUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
|
|
{
|
|
if( _tcscmp(pstrName, _T("sepwidth")) == 0 ) SetSepWidth(_ttoi(pstrValue));
|
|
else if( _tcscmp(pstrName, _T("sepimm")) == 0 ) SetSepImmMode(_tcscmp(pstrValue, _T("true")) == 0);
|
|
else CContainerUI::SetAttribute(pstrName, pstrValue);
|
|
}
|
|
|
|
void CHorizontalLayoutUI::DoEvent(TEventUI& event)
|
|
{
|
|
if( m_iSepWidth != 0 ) {
|
|
if( event.Type == UIEVENT_BUTTONDOWN && IsEnabled() )
|
|
{
|
|
RECT rcSeparator = GetThumbRect(false);
|
|
if( ::PtInRect(&rcSeparator, event.ptMouse) ) {
|
|
m_uButtonState |= UISTATE_CAPTURED;
|
|
m_ptLastMouse = event.ptMouse;
|
|
m_rcNewPos = m_rcItem;
|
|
if( !m_bImmMode && m_pManager ) m_pManager->AddPostPaint(this);
|
|
return;
|
|
}
|
|
}
|
|
if( event.Type == UIEVENT_BUTTONUP )
|
|
{
|
|
if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
|
|
m_uButtonState &= ~UISTATE_CAPTURED;
|
|
m_rcItem = m_rcNewPos;
|
|
if( !m_bImmMode && m_pManager ) m_pManager->RemovePostPaint(this);
|
|
NeedParentUpdate();
|
|
return;
|
|
}
|
|
}
|
|
if( event.Type == UIEVENT_MOUSEMOVE )
|
|
{
|
|
if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
|
|
LONG cx = event.ptMouse.x - m_ptLastMouse.x;
|
|
m_ptLastMouse = event.ptMouse;
|
|
RECT rc = m_rcNewPos;
|
|
if( m_iSepWidth >= 0 ) {
|
|
if( cx > 0 && event.ptMouse.x < m_rcNewPos.right - m_iSepWidth ) return;
|
|
if( cx < 0 && event.ptMouse.x > m_rcNewPos.right ) return;
|
|
rc.right += cx;
|
|
if( rc.right - rc.left <= GetMinWidth() ) {
|
|
if( m_rcNewPos.right - m_rcNewPos.left <= GetMinWidth() ) return;
|
|
rc.right = rc.left + GetMinWidth();
|
|
}
|
|
if( rc.right - rc.left >= GetMaxWidth() ) {
|
|
if( m_rcNewPos.right - m_rcNewPos.left >= GetMaxWidth() ) return;
|
|
rc.right = rc.left + GetMaxWidth();
|
|
}
|
|
}
|
|
else {
|
|
if( cx > 0 && event.ptMouse.x < m_rcNewPos.left ) return;
|
|
if( cx < 0 && event.ptMouse.x > m_rcNewPos.left - m_iSepWidth ) return;
|
|
rc.left += cx;
|
|
if( rc.right - rc.left <= GetMinWidth() ) {
|
|
if( m_rcNewPos.right - m_rcNewPos.left <= GetMinWidth() ) return;
|
|
rc.left = rc.right - GetMinWidth();
|
|
}
|
|
if( rc.right - rc.left >= GetMaxWidth() ) {
|
|
if( m_rcNewPos.right - m_rcNewPos.left >= GetMaxWidth() ) return;
|
|
rc.left = rc.right - GetMaxWidth();
|
|
}
|
|
}
|
|
|
|
CDuiRect rcInvalidate = GetThumbRect(true);
|
|
m_rcNewPos = rc;
|
|
m_cxyFixed.cx = m_rcNewPos.right - m_rcNewPos.left;
|
|
|
|
if( m_bImmMode ) {
|
|
m_rcItem = m_rcNewPos;
|
|
NeedParentUpdate();
|
|
}
|
|
else {
|
|
rcInvalidate.Join(GetThumbRect(true));
|
|
rcInvalidate.Join(GetThumbRect(false));
|
|
if( m_pManager ) m_pManager->Invalidate(rcInvalidate);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
if( event.Type == UIEVENT_SETCURSOR )
|
|
{
|
|
RECT rcSeparator = GetThumbRect(false);
|
|
if( IsEnabled() && ::PtInRect(&rcSeparator, event.ptMouse) ) {
|
|
::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE)));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
CContainerUI::DoEvent(event);
|
|
}
|
|
|
|
RECT CHorizontalLayoutUI::GetThumbRect(bool bUseNew) const
|
|
{
|
|
if( (m_uButtonState & UISTATE_CAPTURED) != 0 && bUseNew) {
|
|
if( m_iSepWidth >= 0 ) return CDuiRect(m_rcNewPos.right - m_iSepWidth, m_rcNewPos.top, m_rcNewPos.right, m_rcNewPos.bottom);
|
|
else return CDuiRect(m_rcNewPos.left, m_rcNewPos.top, m_rcNewPos.left - m_iSepWidth, m_rcNewPos.bottom);
|
|
}
|
|
else {
|
|
if( m_iSepWidth >= 0 ) return CDuiRect(m_rcItem.right - m_iSepWidth, m_rcItem.top, m_rcItem.right, m_rcItem.bottom);
|
|
else return CDuiRect(m_rcItem.left, m_rcItem.top, m_rcItem.left - m_iSepWidth, m_rcItem.bottom);
|
|
}
|
|
}
|
|
}
|