#ifndef __UIVERTICALLAYOUT_H__ #define __UIVERTICALLAYOUT_H__ #pragma once namespace DuiLib { class UILIB_API CVerticalLayoutUI : public CContainerUI { public: CVerticalLayoutUI(); LPCTSTR GetClass() const; LPVOID GetInterface(LPCTSTR pstrName); UINT GetControlFlags() const; void SetSepHeight(int iHeight); int GetSepHeight() const; void SetSepImmMode(bool bImmediately); bool IsSepImmMode() const; void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue); void DoEvent(TEventUI& event); void SetPos(RECT rc); void DoPostPaint(HDC hDC, const RECT& rcPaint); RECT GetThumbRect(bool bUseNew = false) const; protected: int m_iSepHeight; UINT m_uButtonState; POINT ptLastMouse; RECT m_rcNewPos; bool m_bImmMode; }; } #endif // __UIVERTICALLAYOUT_H__
#include "stdafx.h" #include "UIVerticalLayout.h" namespace DuiLib { CVerticalLayoutUI::CVerticalLayoutUI() : m_iSepHeight(0), m_uButtonState(0), m_bImmMode(false) { ptLastMouse.x = ptLastMouse.y = 0; ::ZeroMemory(&m_rcNewPos, sizeof(m_rcNewPos)); } LPCTSTR CVerticalLayoutUI::GetClass() const { return _T("VerticalLayoutUI"); } LPVOID CVerticalLayoutUI::GetInterface(LPCTSTR pstrName) { if( _tcscmp(pstrName, DUI_CTR_VERTICALLAYOUT) == 0 ) return static_cast<CVerticalLayoutUI*>(this); return CContainerUI::GetInterface(pstrName); } UINT CVerticalLayoutUI::GetControlFlags() const { if( IsEnabled() && m_iSepHeight != 0 ) return UIFLAG_SETCURSOR; else return 0; } void CVerticalLayoutUI::SetPos(RECT rc) { CControlUI::SetPos(rc); 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(); int nAdjustables = 0; int cyFixed = 0; int nEstimateNum = 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; SIZE sz = pControl->EstimateSize(szAvailable); if( sz.cy == 0 ) { nAdjustables++; } else { if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight(); if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight(); } cyFixed += sz.cy + pControl->GetPadding().top + pControl->GetPadding().bottom; nEstimateNum++; } cyFixed += (nEstimateNum - 1) * m_iChildPadding; // Place elements int cyNeeded = 0; int cyExpand = 0; if( nAdjustables > 0 ) cyExpand = MAX(0, (szAvailable.cy - cyFixed) / nAdjustables); // Position the elements SIZE szRemaining = szAvailable; int iPosY = rc.top; if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) { iPosY -= m_pVerticalScrollBar->GetScrollPos(); } int iPosX = rc.left; if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) { iPosX -= m_pHorizontalScrollBar->GetScrollPos(); } int iAdjustable = 0; int cyFixedRemaining = cyFixed; 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.cy -= rcPadding.top; SIZE sz = pControl->EstimateSize(szRemaining); if( sz.cy == 0 ) { iAdjustable++; sz.cy = cyExpand; // Distribute remaining to last element (usually round-off left-overs) if( iAdjustable == nAdjustables ) { sz.cy = MAX(0, szRemaining.cy - rcPadding.bottom - cyFixedRemaining); } if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight(); if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight(); } else { if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight(); if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight(); cyFixedRemaining -= sz.cy; } sz.cx = pControl->GetFixedWidth(); if( sz.cx == 0 ) sz.cx = szAvailable.cx - rcPadding.left - rcPadding.right; if( sz.cx < 0 ) sz.cx = 0; if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth(); if( sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth(); RECT rcCtrl = { iPosX + rcPadding.left, iPosY + rcPadding.top, iPosX + rcPadding.left + sz.cx, iPosY + sz.cy + rcPadding.top + rcPadding.bottom }; pControl->SetPos(rcCtrl); iPosY += sz.cy + m_iChildPadding + rcPadding.top + rcPadding.bottom; cyNeeded += sz.cy + rcPadding.top + rcPadding.bottom; szRemaining.cy -= sz.cy + m_iChildPadding + rcPadding.bottom; } cyNeeded += (nEstimateNum - 1) * m_iChildPadding; // Process the scrollbar ProcessScrollBar(rc, 0, cyNeeded); } void CVerticalLayoutUI::DoPostPaint(HDC hDC, const RECT& rcPaint) { if( (m_uButtonState & UISTATE_CAPTURED) != 0 && !m_bImmMode ) { RECT rcSeparator = GetThumbRect(true); CRenderEngine::DrawColor(hDC, rcSeparator, 0xAA000000); } } void CVerticalLayoutUI::SetSepHeight(int iHeight) { m_iSepHeight = iHeight; } int CVerticalLayoutUI::GetSepHeight() const { return m_iSepHeight; } void CVerticalLayoutUI::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 CVerticalLayoutUI::IsSepImmMode() const { return m_bImmMode; } void CVerticalLayoutUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue) { if( _tcscmp(pstrName, _T("sepheight")) == 0 ) SetSepHeight(_ttoi(pstrValue)); else if( _tcscmp(pstrName, _T("sepimm")) == 0 ) SetSepImmMode(_tcscmp(pstrValue, _T("true")) == 0); else CContainerUI::SetAttribute(pstrName, pstrValue); } void CVerticalLayoutUI::DoEvent(TEventUI& event) { if( m_iSepHeight != 0 ) { if( event.Type == UIEVENT_BUTTONDOWN && IsEnabled() ) { RECT rcSeparator = GetThumbRect(false); if( ::PtInRect(&rcSeparator, event.ptMouse) ) { m_uButtonState |= UISTATE_CAPTURED; 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 cy = event.ptMouse.y - ptLastMouse.y; ptLastMouse = event.ptMouse; RECT rc = m_rcNewPos; if( m_iSepHeight >= 0 ) { if( cy > 0 && event.ptMouse.y < m_rcNewPos.bottom + m_iSepHeight ) return; if( cy < 0 && event.ptMouse.y > m_rcNewPos.bottom ) return; rc.bottom += cy; if( rc.bottom - rc.top <= GetMinHeight() ) { if( m_rcNewPos.bottom - m_rcNewPos.top <= GetMinHeight() ) return; rc.bottom = rc.top + GetMinHeight(); } if( rc.bottom - rc.top >= GetMaxHeight() ) { if( m_rcNewPos.bottom - m_rcNewPos.top >= GetMaxHeight() ) return; rc.bottom = rc.top + GetMaxHeight(); } } else { if( cy > 0 && event.ptMouse.y < m_rcNewPos.top ) return; if( cy < 0 && event.ptMouse.y > m_rcNewPos.top + m_iSepHeight ) return; rc.top += cy; if( rc.bottom - rc.top <= GetMinHeight() ) { if( m_rcNewPos.bottom - m_rcNewPos.top <= GetMinHeight() ) return; rc.top = rc.bottom - GetMinHeight(); } if( rc.bottom - rc.top >= GetMaxHeight() ) { if( m_rcNewPos.bottom - m_rcNewPos.top >= GetMaxHeight() ) return; rc.top = rc.bottom - GetMaxHeight(); } } CDuiRect rcInvalidate = GetThumbRect(true); m_rcNewPos = rc; m_cxyFixed.cy = m_rcNewPos.bottom - m_rcNewPos.top; 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_SIZENS))); return; } } } CContainerUI::DoEvent(event); } RECT CVerticalLayoutUI::GetThumbRect(bool bUseNew) const { if( (m_uButtonState & UISTATE_CAPTURED) != 0 && bUseNew) { if( m_iSepHeight >= 0 ) return CDuiRect(m_rcNewPos.left, MAX(m_rcNewPos.bottom - m_iSepHeight, m_rcNewPos.top), m_rcNewPos.right, m_rcNewPos.bottom); else return CDuiRect(m_rcNewPos.left, m_rcNewPos.top, m_rcNewPos.right, MIN(m_rcNewPos.top - m_iSepHeight, m_rcNewPos.bottom)); } else { if( m_iSepHeight >= 0 ) return CDuiRect(m_rcItem.left, MAX(m_rcItem.bottom - m_iSepHeight, m_rcItem.top), m_rcItem.right, m_rcItem.bottom); else return CDuiRect(m_rcItem.left, m_rcItem.top, m_rcItem.right, MIN(m_rcItem.top - m_iSepHeight, m_rcItem.bottom)); } } }