#include "StdAfx.h" namespace ui { Layout::Layout() : m_rcPadding(0, 0, 0, 0), m_iChildMargin(0), m_pOwner(nullptr) { } void Layout::SetOwner(Box* pOwner) { m_pOwner = pOwner; } CSize Layout::SetFloatPos(Control* pControl, UiRect rcContainer) { if (!pControl->IsVisible()) return CSize(); int childLeft = 0; int childRight = 0; int childTop = 0; int childBottm = 0; UiRect rcMargin = pControl->GetMargin(); int iPosLeft = rcContainer.left + rcMargin.left; int iPosRight = rcContainer.right - rcMargin.right; int iPosTop = rcContainer.top + rcMargin.top; int iPosBottom = rcContainer.bottom - rcMargin.bottom; CSize szAvailable(iPosRight - iPosLeft, iPosBottom - iPosTop); CSize childSize = pControl->EstimateSize(szAvailable); if (pControl->GetFixedWidth() == DUI_LENGTH_AUTO && pControl->GetFixedHeight() == DUI_LENGTH_AUTO && pControl->GetMaxWidth() == DUI_LENGTH_STRETCH) { int maxwidth = MAX(0, szAvailable.cx); if (childSize.cx > maxwidth) { pControl->SetFixedWidth(maxwidth, false); childSize = pControl->EstimateSize(szAvailable); pControl->SetFixedWidth(DUI_LENGTH_AUTO, false); } } if (childSize.cx == DUI_LENGTH_STRETCH) { childSize.cx = MAX(0, szAvailable.cx); } if (childSize.cx < pControl->GetMinWidth()) childSize.cx = pControl->GetMinWidth(); if (pControl->GetMaxWidth() >= 0 && childSize.cx > pControl->GetMaxWidth()) childSize.cx = pControl->GetMaxWidth(); if (childSize.cy == DUI_LENGTH_STRETCH) { childSize.cy = MAX(0, szAvailable.cy); } if (childSize.cy < pControl->GetMinHeight()) childSize.cy = pControl->GetMinHeight(); if (childSize.cy > pControl->GetMaxHeight()) childSize.cy = pControl->GetMaxHeight(); int childWidth = childSize.cx; int childHeight = childSize.cy; HorAlignType horAlignType = pControl->GetHorAlignType(); VerAlignType verAlignType = pControl->GetVerAlignType(); if (horAlignType == kHorAlignLeft) { childLeft = iPosLeft; childRight = childLeft + childWidth; } else if (horAlignType == kHorAlignRight) { childRight = iPosRight; childLeft = childRight - childWidth; } else if (horAlignType == kHorAlignCenter) { childLeft = iPosLeft + (iPosRight - iPosLeft - childWidth) / 2; childRight = childLeft + childWidth; } if (verAlignType == kVerAlignTop) { childTop = iPosTop; childBottm = childTop + childHeight; } else if (verAlignType == kVerAlignBottom) { childBottm = iPosBottom; childTop = childBottm - childHeight; } else if (verAlignType == kVerAlignCenter) { childTop = iPosTop + (iPosBottom - iPosTop - childHeight) / 2; childBottm = childTop + childHeight; } UiRect childPos(childLeft, childTop, childRight, childBottm); pControl->SetPos(childPos); return CSize(childPos.GetWidth(), childPos.GetHeight()); } bool Layout::SetAttribute(const std::wstring& strName, const std::wstring& strValue) { bool hasAttribute = true; if( strName == _T("padding") ) { UiRect rcPadding; LPTSTR pstr = NULL; rcPadding.left = _tcstol(strValue.c_str(), &pstr, 10); ASSERT(pstr); rcPadding.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr); rcPadding.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr); rcPadding.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr); SetPadding(rcPadding); } else if( strName == _T("childmargin") ) { SetChildMargin(_ttoi(strValue.c_str())); } else { hasAttribute = false; } return hasAttribute; } CSize Layout::ArrangeChild(const std::vector& items, UiRect rc) { CSize size; for (auto it = items.begin(); it != items.end(); it++) { Control* pControl = *it; if( !pControl->IsVisible() ) continue; CSize new_size = SetFloatPos(pControl, rc); size.cx = MAX(size.cx, new_size.cx); size.cy = MAX(size.cy, new_size.cy); } return size; } CSize Layout::AjustSizeByChild(const std::vector& items, CSize szAvailable) { CSize maxSize(-9999, -9999); CSize itemSize; for (auto it = items.begin(); it != items.end(); it++) { if (!(*it)->IsVisible()) continue; itemSize = (*it)->EstimateSize(szAvailable); if( itemSize.cx < (*it)->GetMinWidth() ) itemSize.cx = (*it)->GetMinWidth(); if( (*it)->GetMaxWidth() >= 0 && itemSize.cx > (*it)->GetMaxWidth() ) itemSize.cx = (*it)->GetMaxWidth(); if( itemSize.cy < (*it)->GetMinHeight() ) itemSize.cy = (*it)->GetMinHeight(); if( itemSize.cy > (*it)->GetMaxHeight() ) itemSize.cy = (*it)->GetMaxHeight(); maxSize.cx = MAX(itemSize.cx + (*it)->GetMargin().left + (*it)->GetMargin().right, maxSize.cx); maxSize.cy = MAX(itemSize.cy + (*it)->GetMargin().top + (*it)->GetMargin().bottom, maxSize.cy); } maxSize.cx += m_rcPadding.left + m_rcPadding.right; maxSize.cy += m_rcPadding.top + m_rcPadding.bottom; return maxSize; } UiRect Layout::GetPadding() const { return m_rcPadding; } void Layout::SetPadding(UiRect rcPadding, bool bNeedDpiScale /*= true*/) { if (bNeedDpiScale) DpiManager::GetInstance()->ScaleRect(rcPadding); m_rcPadding = rcPadding; m_pOwner->Arrange(); } int Layout::GetChildMargin() const { return m_iChildMargin; } void Layout::SetChildMargin(int iMargin) { DpiManager::GetInstance()->ScaleInt(iMargin); m_iChildMargin = iMargin; m_pOwner->Arrange(); } UiRect Layout::GetInternalPos() const { UiRect internalPos = m_pOwner->GetPos(); internalPos.Deflate(m_rcPadding); return internalPos; } ///////////////////////////////////////////////////////////////////////////////////// // // Box::Box(Layout* pLayout) : m_pLayout(pLayout), m_bAutoDestroy(true), m_bDelayedDestroy(true), m_bMouseChildEnabled(true), m_items(), OnBubbledEvent() { m_pLayout->SetOwner(this); } Box::Box(const Box& r) : Control(r), m_bAutoDestroy(r.m_bAutoDestroy), m_bDelayedDestroy(r.m_bDelayedDestroy), m_bMouseChildEnabled(r.m_bMouseChildEnabled), m_items(), OnBubbledEvent() { m_pLayout.reset(new Layout(*r.m_pLayout)), m_pLayout->SetOwner(this); } Box::~Box() { m_bDelayedDestroy = false; RemoveAll(); } void Box::SetWindow(Window* pManager, Box* pParent, bool bInit) { for (auto it = m_items.begin(); it != m_items.end(); it++) { (*it)->SetWindow(pManager, this, bInit); } Control::SetWindow(pManager, pParent, bInit); } void Box::SetAttribute(const std::wstring& strName, const std::wstring& strValue) { if (m_pLayout->SetAttribute(strName, strValue)) { } else if( strName == _T("mousechild") ) SetMouseChildEnabled(strValue == _T("true")); else Control::SetAttribute(strName, strValue); } void Box::SetPos(UiRect rc) { Control::SetPos(rc); rc.left += m_pLayout->GetPadding().left; rc.top += m_pLayout->GetPadding().top; rc.right -= m_pLayout->GetPadding().right; rc.bottom -= m_pLayout->GetPadding().bottom; CSize requiredSize; if( m_items.size() == 0) { requiredSize.cx = 0; requiredSize.cy = 0; } else { requiredSize = m_pLayout->ArrangeChild(m_items, rc); } } void Box::HandleMessageTemplate(EventArgs& msg) { if (msg.Type == kEventInternalDoubleClick || msg.Type == kEventInternalMenu || msg.Type == kEventInternalSetFocus || msg.Type == kEventInternalKillFocus) { HandleMessage(msg); return; } bool bRet = true; std::weak_ptr weakflag = GetWeakFlag(); if (this == msg.pSender) { auto callback = OnEvent.find(msg.Type); if (callback != OnEvent.end()) { bRet = callback->second(&msg); } if (weakflag.expired()) { return; } callback = OnEvent.find(kEventAll); if (callback != OnEvent.end()) { bRet = callback->second(&msg); } if (weakflag.expired()) { return; } if (bRet) { auto callback = OnXmlEvent.find(msg.Type); if (callback != OnXmlEvent.end()) { bRet = callback->second(&msg); } if (weakflag.expired()) { return; } callback = OnXmlEvent.find(kEventAll); if (callback != OnXmlEvent.end()) { bRet = callback->second(&msg); } if (weakflag.expired()) { return; } } } auto callback = OnBubbledEvent.find(msg.Type); if (callback != OnBubbledEvent.end()) { bRet = callback->second(&msg); } if (weakflag.expired()) { return; } callback = OnBubbledEvent.find(kEventAll); if (callback != OnBubbledEvent.end()) { bRet = callback->second(&msg); } if (weakflag.expired()) { return; } if (bRet) { auto callback = OnXmlBubbledEvent.find(msg.Type); if (callback != OnXmlBubbledEvent.end()) { bRet = callback->second(&msg); } if (weakflag.expired()) { return; } callback = OnXmlBubbledEvent.find(kEventAll); if (callback != OnXmlBubbledEvent.end()) { bRet = callback->second(&msg); } if (weakflag.expired()) { return; } } if (bRet) { HandleMessage(msg); } } void Box::PaintChild(IRenderContext* pRender, const UiRect& rcPaint) { UiRect rcTemp; if( !::IntersectRect(&rcTemp, &rcPaint, &m_rcItem) ) return; for (auto it = m_items.begin(); it != m_items.end(); it++) { Control* pControl = *it; if( !pControl->IsVisible() ) continue; pControl->AlphaPaint(pRender, rcPaint); } } void Box::SetVisible_(bool bVisible) { __super::SetVisible_(bVisible); for (auto it = m_items.begin(); it != m_items.end(); it++) { (*it)->SetInternVisible(IsVisible()); } } // 逻辑上,对于Container控件不公开此方法 // 调用此方法的结果是,内部子控件隐藏,控件本身依然显示,背景等效果存在 void Box::SetInternVisible(bool bVisible) { Control::SetInternVisible(bVisible); if (m_items.empty()) return; for (auto it = m_items.begin(); it != m_items.end(); it++) { // 控制子控件显示状态 // InternVisible状态应由子控件自己控制 (*it)->SetInternVisible(IsVisible()); } } void Box::SetEnabled(bool bEnabled) { if (m_bEnabled == bEnabled) return; Control::SetEnabled(bEnabled); if (m_items.empty()) return; for (auto it = m_items.begin(); it != m_items.end(); it++) { (*it)->SetEnabled(bEnabled); } Invalidate(); } CSize Box::EstimateSize(CSize szAvailable) { CSize fixedSize = m_cxyFixed; if (GetFixedWidth() == DUI_LENGTH_AUTO || GetFixedHeight() == DUI_LENGTH_AUTO) { if (!m_bReEstimateSize) { return m_szEstimateSize; } szAvailable.cx -= m_pLayout->GetPadding().left + m_pLayout->GetPadding().right; szAvailable.cy -= m_pLayout->GetPadding().top + m_pLayout->GetPadding().bottom; CSize sizeByChild = m_pLayout->AjustSizeByChild(m_items, szAvailable); if (GetFixedWidth() == DUI_LENGTH_AUTO) { fixedSize.cx = sizeByChild.cx; } if (GetFixedHeight() == DUI_LENGTH_AUTO) { fixedSize.cy = sizeByChild.cy; } m_bReEstimateSize = false; for (auto it = m_items.begin(); it != m_items.end(); it++) { if (!(*it)->IsVisible()) { continue; } if ((*it)->GetFixedWidth() == DUI_LENGTH_AUTO || (*it)->GetFixedHeight() == DUI_LENGTH_AUTO) { if ((*it)->IsReEstimateSize()) { m_bReEstimateSize = true; break; } } } m_szEstimateSize = fixedSize; } return fixedSize; } Control* Box::FindControl(FINDCONTROLPROC Proc, LPVOID pData, UINT uFlags, CPoint scrollPos) { // Check if this guy is valid if ((uFlags & UIFIND_VISIBLE) != 0 && !IsVisible()) return NULL; if ((uFlags & UIFIND_ENABLED) != 0 && !IsEnabled()) return NULL; if ((uFlags & UIFIND_HITTEST) != 0) { if (!::PtInRect(&m_rcItem, *(static_cast(pData)))) return NULL; if (!m_bMouseChildEnabled) { Control* pResult = NULL; if (pResult == NULL) pResult = Control::FindControl(Proc, pData, uFlags); return pResult; } } Control* pResult = NULL; if (pResult != NULL) return pResult; if ((uFlags & UIFIND_ME_FIRST) != 0) { Control* pControl = Control::FindControl(Proc, pData, uFlags); if (pControl != NULL) return pControl; } UiRect rc = m_rcItem; rc.left += m_pLayout->GetPadding().left; rc.top += m_pLayout->GetPadding().top; rc.right -= m_pLayout->GetPadding().right; rc.bottom -= m_pLayout->GetPadding().bottom; if ((uFlags & UIFIND_TOP_FIRST) != 0) { for (int it = (int)m_items.size() - 1; it >= 0; it--) { Control* pControl; if ((uFlags & UIFIND_HITTEST) != 0) { CPoint newPoint = *(static_cast(pData)); newPoint.Offset(scrollPos); pControl = m_items[it]->FindControl(Proc, &newPoint, uFlags); } else { pControl = m_items[it]->FindControl(Proc, pData, uFlags); } if (pControl != NULL) { if ((uFlags & UIFIND_HITTEST) != 0 && !pControl->IsFloat() && !::PtInRect(&rc, *(static_cast(pData)))) continue; else return pControl; } } } else { for (auto it = m_items.begin(); it != m_items.end(); it++) { Control* pControl; if ((uFlags & UIFIND_HITTEST) != 0) { CPoint newPoint = *(static_cast(pData)); newPoint.Offset(scrollPos); pControl = (*it)->FindControl(Proc, &newPoint, uFlags); } else { pControl = (*it)->FindControl(Proc, pData, uFlags); } if (pControl != NULL) { if ((uFlags & UIFIND_HITTEST) != 0 && !pControl->IsFloat() && !::PtInRect(&rc, *(static_cast(pData)))) continue; else return pControl; } } } if (pResult == NULL && (uFlags & UIFIND_ME_FIRST) == 0) pResult = Control::FindControl(Proc, pData, uFlags); return pResult; } Control* Box::FindSubControl(const std::wstring& pstrSubControlName) { Control* pSubControl = NULL; pSubControl = static_cast(GetWindow()->FindSubControlByName(this, pstrSubControlName)); return pSubControl; } int Box::FindSelectable(int iIndex, bool bForward /*= true*/) const { // NOTE: This is actually a helper-function for the list/combo/ect controls // that allow them to find the next enabled/available selectable item if (GetCount() == 0) return -1; iIndex = CLAMP(iIndex, 0, GetCount() - 1); if (bForward) { for (int i = iIndex; i < GetCount(); i++) { if (dynamic_cast(GetItemAt(i)) != NULL && GetItemAt(i)->IsVisible() && GetItemAt(i)->IsEnabled()) return i; } return -1; } else { for (int i = iIndex; i >= 0; --i) { if (dynamic_cast(GetItemAt(i)) != NULL && GetItemAt(i)->IsVisible() && GetItemAt(i)->IsEnabled()) return i; } return FindSelectable(0, true); } } Control* Box::GetItemAt(std::size_t iIndex) const { if( iIndex < 0 || iIndex >= m_items.size() ) return NULL; return static_cast(m_items[iIndex]); } int Box::GetItemIndex(Control* pControl) const { auto it = std::find(m_items.begin(), m_items.end(), pControl); if (it == m_items.end()) { return -1; } return it - m_items.begin(); } bool Box::SetItemIndex(Control* pControl, std::size_t iIndex) { if( iIndex < 0 || iIndex >= m_items.size() ) return false; for (auto it = m_items.begin(); it != m_items.end(); it++) { if( *it == pControl ) { Arrange(); m_items.erase(it); m_items.insert(m_items.begin() + iIndex, pControl); return true; } } return false; } int Box::GetCount() const { return (int)m_items.size(); } bool Box::Add(Control* pControl) { if( pControl == NULL) return false; if( m_pWindow != NULL ) m_pWindow->InitControls(pControl, this); if( IsVisible() ) Arrange(); else pControl->SetInternVisible(false); m_items.push_back(pControl); return true; } bool Box::AddAt(Control* pControl, std::size_t iIndex) { if( pControl == NULL) return false; if( iIndex < 0 || iIndex > m_items.size() ) { ASSERT(FALSE); return false; } if( m_pWindow != NULL ) m_pWindow->InitControls(pControl, this); if( IsVisible() ) Arrange(); else pControl->SetInternVisible(false); m_items.insert(m_items.begin() + iIndex, pControl); return true; } bool Box::Remove(Control* pControl) { if( pControl == NULL) return false; for (auto it = m_items.begin(); it != m_items.end(); it++) { if( *it == pControl ) { Arrange(); if( m_bAutoDestroy ) { if( m_bDelayedDestroy && m_pWindow ) m_pWindow->AddDelayedCleanup(pControl); else delete pControl; } m_items.erase(it); return true; } } return false; } bool Box::RemoveAt(std::size_t iIndex) { Control* pControl = GetItemAt(iIndex); if (pControl != NULL) { return Box::Remove(pControl); } return false; } void Box::RemoveAll() { if (m_bAutoDestroy) { for (auto it = m_items.begin(); it != m_items.end(); it++) { if( m_bDelayedDestroy && m_pWindow ) m_pWindow->AddDelayedCleanup((*it)); else delete (*it); } } m_items.clear(); Arrange(); } void Box::SwapChild(Control* pChild1, Control* pChild2) { ASSERT(std::find(m_items.begin(), m_items.end(), pChild1) != m_items.end()); ASSERT(std::find(m_items.begin(), m_items.end(), pChild2) != m_items.end()); std::vector::iterator it1, it2; for (auto it = m_items.begin(); it != m_items.end(); it++) { if (*it == pChild1 || *it == pChild2) { Control* child = (*it == pChild1) ? pChild2 : pChild1; it = m_items.erase(it); it = m_items.insert(it, child); } } } void Box::ResetChildIndex(Control* pChild, std::size_t iIndex) { ASSERT(std::find(m_items.begin(), m_items.end(), pChild) != m_items.end()); std::size_t oldIndex = 0; for (auto it = m_items.begin(); it != m_items.end(); it++) { if (*it == pChild) { m_items.erase(it); if (oldIndex >= iIndex) { AddAt(pChild, iIndex); } else { AddAt(pChild, iIndex - 1); } break; } oldIndex++; } } bool Box::IsAutoDestroy() const { return m_bAutoDestroy; } void Box::SetAutoDestroy(bool bAuto) { m_bAutoDestroy = bAuto; } bool Box::IsDelayedDestroy() const { return m_bDelayedDestroy; } void Box::SetDelayedDestroy(bool bDelayed) { m_bDelayedDestroy = bDelayed; } bool Box::IsMouseChildEnabled() const { return m_bMouseChildEnabled; } void Box::SetMouseChildEnabled(bool bEnable) { m_bMouseChildEnabled = bEnable; } Layout* Box::GetLayout() const { return m_pLayout.get(); } void Box::RetSetLayout(Layout* pLayout) { m_pLayout.reset(pLayout); } UiRect Box::GetPaddingPos() const { UiRect pos = GetPos(); UiRect padding = m_pLayout->GetPadding(); pos.left += padding.left; pos.top += padding.top; pos.right -= padding.right; pos.bottom -= padding.bottom; return pos; } void Box::InvokeLoadImageCache() { __super::InvokeLoadImageCache(); for (auto it = m_items.begin(); it != m_items.end(); it++) { (*it)->InvokeLoadImageCache(); } } void Box::UnLoadImageCache() { __super::UnLoadImageCache(); for (auto it = m_items.begin(); it != m_items.end(); it++) { (*it)->UnLoadImageCache(); } } void Box::ClearImageCache() { __super::ClearImageCache(); for (auto it = m_items.begin(); it != m_items.end(); it++) { (*it)->ClearImageCache(); } } UINT Box::GetControlFlags() const { return UIFLAG_DEFAULT; // Box 默认不支持 TAB 切换焦点 } ///////////////////////////////////////////////////////////////////////////////////// // // ScrollableBox::ScrollableBox(Layout* pLayout) : Box(pLayout), m_pVerticalScrollBar(), m_pHorizontalScrollBar(), m_nVerScrollUnitPixels(30), m_nHerScrollUnitPixels(30), m_bScrollProcess(false), m_bScrollBarFloat(true), m_bHoldEnd(false), m_bDefaultDisplayScrollbar(true), m_rcScrollBarPadding(), m_ptLastTouchPos(-1, -1), m_scrollAnimation(), m_renderOffsetYAnimation() { m_rcScrollBarPadding.left = m_rcScrollBarPadding.top = m_rcScrollBarPadding.right = m_rcScrollBarPadding.bottom = 0; } ScrollableBox::ScrollableBox(const ScrollableBox& r): Box(r), m_nVerScrollUnitPixels(r.m_nVerScrollUnitPixels), m_nHerScrollUnitPixels(r.m_nHerScrollUnitPixels), m_bScrollProcess(r.m_bScrollProcess), m_bScrollBarFloat(r.m_bScrollBarFloat), m_bHoldEnd(r.m_bHoldEnd), m_bDefaultDisplayScrollbar(r.m_bDefaultDisplayScrollbar), m_rcScrollBarPadding(r.m_rcScrollBarPadding), m_ptLastTouchPos(r.m_ptLastTouchPos), m_scrollAnimation(), m_renderOffsetYAnimation() { m_pVerticalScrollBar.reset(new ScrollBar(*m_pVerticalScrollBar.get())); m_pVerticalScrollBar->SetOwner(this); m_pHorizontalScrollBar.reset(new ScrollBar(*m_pHorizontalScrollBar.get())); m_pHorizontalScrollBar->SetOwner(this); } void ScrollableBox::SetAttribute(const std::wstring& pstrName, const std::wstring& pstrValue) { if( pstrName == _T("vscrollbar") ) { EnableScrollBar(pstrValue == _T("true"), GetHorizontalScrollBar() != NULL); } else if( pstrName == _T("vscrollbarstyle") ) { EnableScrollBar(true, GetHorizontalScrollBar() != NULL); if( GetVerticalScrollBar() ) GetVerticalScrollBar()->ApplyAttributeList(pstrValue); } else if( pstrName == _T("hscrollbar") ) { EnableScrollBar(GetVerticalScrollBar() != NULL, pstrValue == _T("true")); } else if( pstrName == _T("hscrollbarstyle") ) { EnableScrollBar(GetVerticalScrollBar() != NULL, true); if( GetHorizontalScrollBar() ) GetHorizontalScrollBar()->ApplyAttributeList(pstrValue); } else if( pstrName == _T("scrollbarpadding") ) { UiRect rcScrollbarPadding; LPTSTR pstr = NULL; rcScrollbarPadding.left = _tcstol(pstrValue.c_str(), &pstr, 10); ASSERT(pstr); rcScrollbarPadding.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr); rcScrollbarPadding.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr); rcScrollbarPadding.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr); SetScrollBarPadding(rcScrollbarPadding); } else if( pstrName == _T("vscrollunit") ) SetVerScrollUnitPixels(_ttoi(pstrValue.c_str())); else if (pstrName == _T("hscrollunit")) SetHorScrollUnitPixels(_ttoi(pstrValue.c_str())); else if( pstrName == _T("scrollbarfloat") ) SetScrollBarFloat(pstrValue == _T("true")); else if( pstrName == _T("defaultdisplayscrollbar") ) SetDefaultDisplayScrollbar(pstrValue == _T("true")); else if( pstrName == _T("holdend") ) SetHoldEnd(pstrValue == _T("true")); else Box::SetAttribute(pstrName, pstrValue); } void ScrollableBox::SetPos(UiRect rc) { bool bEndDown = false; if (IsHoldEnd() && IsVScrollBarValid() && GetScrollRange().cy - GetScrollPos().cy == 0) { bEndDown = true; } SetPosInternally(rc); if (bEndDown && IsVScrollBarValid()) { EndDown(false, false); } } void ScrollableBox::SetPosInternally(UiRect rc) { Control::SetPos(rc); UiRect rcRaw = rc; rc.left += m_pLayout->GetPadding().left; rc.top += m_pLayout->GetPadding().top; rc.right -= m_pLayout->GetPadding().right; rc.bottom -= m_pLayout->GetPadding().bottom; CSize requiredSize = CalcRequiredSize(rc); ProcessVScrollBar(rcRaw, requiredSize.cy); ProcessHScrollBar(rcRaw, requiredSize.cx); } CSize ScrollableBox::CalcRequiredSize(const UiRect& rc) { CSize requiredSize; if (m_items.size() == 0) { requiredSize.cx = 0; requiredSize.cy = 0; } else { UiRect childSize = rc; if (!m_bScrollBarFloat && m_pVerticalScrollBar && m_pVerticalScrollBar->IsValid()) { childSize.right -= m_pVerticalScrollBar->GetFixedWidth(); } if (!m_bScrollBarFloat && m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsValid()) { childSize.bottom -= m_pHorizontalScrollBar->GetFixedHeight(); } requiredSize = m_pLayout->ArrangeChild(m_items, childSize); } return requiredSize; } void ScrollableBox::HandleMessage(EventArgs& event) { if( !IsMouseEnabled() && event.Type > kEventMouseBegin && event.Type < kEventMouseEnd ) { if( m_pParent != NULL ) m_pParent->HandleMessageTemplate(event); else Box::HandleMessage(event); return; } if( m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsValid() && m_pVerticalScrollBar->IsEnabled() ) { if( event.Type == kEventKeyDown ) { switch( event.chKey ) { case VK_DOWN: LineDown(); return; case VK_UP: LineUp(); return; case VK_NEXT: PageDown(); return; case VK_PRIOR: PageUp(); return; case VK_HOME: HomeUp(); return; case VK_END: EndDown(); return; } } else if( event.Type == kEventMouseScrollWheel ) { int deltaValue = event.wParam; if (deltaValue > 0 ) { LineUp(abs(deltaValue)); } else { LineDown(abs(deltaValue)); } return; } else if (event.Type == kEventTouchDown || event.Type == kEventPointDown) { if (IsEnabled()) { SetMouseFocused(true); m_ptLastTouchPos = event.ptMouse; return; } } else if (event.Type == kEventTouchMove || event.Type == kEventPointMove) { if (IsMouseFocused()) { int detaValue = event.ptMouse.y - m_ptLastTouchPos.y; if (detaValue == 0) return; m_ptLastTouchPos = event.ptMouse; if (detaValue > 0) { TouchUp(abs(detaValue)); } else { TouchDown(abs(detaValue)); } return; } } else if (event.Type == kEventTouchUp || event.Type == kEventPointUp) { if (IsMouseFocused()) { SetMouseFocused(false); m_ptLastTouchPos = event.ptMouse; return; } } } else if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsValid() && m_pHorizontalScrollBar->IsEnabled() ) { if( event.Type == kEventKeyDown ) { switch( event.chKey ) { case VK_DOWN: LineRight(); return; case VK_UP: LineLeft(); return; case VK_NEXT: PageRight(); return; case VK_PRIOR: PageLeft(); return; case VK_HOME: HomeLeft(); return; case VK_END: EndRight(); return; } } else if( event.Type == kEventMouseScrollWheel ) { int deltaValue = event.wParam; if (deltaValue > 0 ) { LineLeft(); return; } else { LineRight(); return; } } } Box::HandleMessage(event); } bool ScrollableBox::MouseEnter(EventArgs& msg) { bool bRet = __super::MouseEnter(msg); if (bRet && m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsValid() && m_pVerticalScrollBar->IsEnabled()) { if (m_pVerticalScrollBar->IsAutoHideScroll()) { m_pVerticalScrollBar->SetVisible(true); } } if (bRet && m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsValid() && m_pHorizontalScrollBar->IsEnabled()) { if (m_pHorizontalScrollBar->IsAutoHideScroll()) { m_pHorizontalScrollBar->SetVisible(true); } } return bRet; } bool ScrollableBox::MouseLeave(EventArgs& msg) { bool bRet = __super::MouseLeave(msg); if (bRet && m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsValid() && m_pVerticalScrollBar->IsEnabled()) { if (m_pVerticalScrollBar->GetThumbState() == kControlStateNormal && m_pVerticalScrollBar->IsAutoHideScroll()) { m_pVerticalScrollBar->SetVisible(false); } } if (bRet && m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsValid() && m_pHorizontalScrollBar->IsEnabled()) { if (m_pHorizontalScrollBar->GetThumbState() == kControlStateNormal && m_pHorizontalScrollBar->IsAutoHideScroll()) { m_pHorizontalScrollBar->SetVisible(false); } } return bRet; } void ScrollableBox::PaintChild(IRenderContext* pRender, const UiRect& rcPaint) { UiRect rcTemp; if( !::IntersectRect(&rcTemp, &rcPaint, &m_rcItem) ) return; for (auto it = m_items.begin(); it != m_items.end(); it++) { Control* pControl = *it; if( !pControl->IsVisible() ) continue; if (pControl->IsFloat()) { pControl->AlphaPaint(pRender, rcPaint); } else { CSize scrollPos = GetScrollPos(); UiRect rcNewPaint = GetPaddingPos(); AutoClip alphaClip(pRender, rcNewPaint, m_bClip); rcNewPaint.Offset(scrollPos.cx, scrollPos.cy); rcNewPaint.Offset(GetRenderOffset().x, GetRenderOffset().y); CPoint ptOffset(scrollPos.cx, scrollPos.cy); CPoint ptOldOrg = pRender->OffsetWindowOrg(ptOffset); pControl->AlphaPaint(pRender, rcNewPaint); pRender->SetWindowOrg(ptOldOrg); } } if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible()) { m_pHorizontalScrollBar->AlphaPaint(pRender, rcPaint); } if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) { m_pVerticalScrollBar->AlphaPaint(pRender, rcPaint); } static bool bFirstPaint = true; if (bFirstPaint) { bFirstPaint = false; LoadImageCache(true); } } void ScrollableBox::SetMouseEnabled(bool bEnabled) { if (m_pVerticalScrollBar != NULL) m_pVerticalScrollBar->SetMouseEnabled(bEnabled); if (m_pHorizontalScrollBar != NULL) m_pHorizontalScrollBar->SetMouseEnabled(bEnabled); Box::SetMouseEnabled(bEnabled); } void ScrollableBox::SetWindow(Window* pManager, Box* pParent, bool bInit) { if (m_pVerticalScrollBar != NULL) m_pVerticalScrollBar->SetWindow(pManager, this, bInit); if (m_pHorizontalScrollBar != NULL) m_pHorizontalScrollBar->SetWindow(pManager, this, bInit); Box::SetWindow(pManager, pParent, bInit); } Control* ScrollableBox::FindControl(FINDCONTROLPROC Proc, LPVOID pData, UINT uFlags, CPoint scrollPos) { // Check if this guy is valid if ((uFlags & UIFIND_VISIBLE) != 0 && !IsVisible()) return NULL; if ((uFlags & UIFIND_ENABLED) != 0 && !IsEnabled()) return NULL; if ((uFlags & UIFIND_HITTEST) != 0) { if (!::PtInRect(&m_rcItem, *(static_cast(pData)))) return NULL; if (!m_bMouseChildEnabled) { Control* pResult = NULL; if (m_pVerticalScrollBar != NULL) pResult = m_pVerticalScrollBar->FindControl(Proc, pData, uFlags); if (pResult == NULL && m_pHorizontalScrollBar != NULL) pResult = m_pHorizontalScrollBar->FindControl(Proc, pData, uFlags); if (pResult == NULL) pResult = Control::FindControl(Proc, pData, uFlags); return pResult; } } Control* pResult = NULL; if (m_pVerticalScrollBar != NULL) pResult = m_pVerticalScrollBar->FindControl(Proc, pData, uFlags); if (pResult == NULL && m_pHorizontalScrollBar != NULL) pResult = m_pHorizontalScrollBar->FindControl(Proc, pData, uFlags); if (pResult != NULL) return pResult; CPoint ptNewScrollPos(GetScrollPos().cx, GetScrollPos().cy); return Box::FindControl(Proc, pData, uFlags, ptNewScrollPos); } CSize ScrollableBox::GetScrollPos() const { CSize sz; if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsValid() ) sz.cy = m_pVerticalScrollBar->GetScrollPos(); if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsValid() ) sz.cx = m_pHorizontalScrollBar->GetScrollPos(); return sz; } CSize ScrollableBox::GetScrollRange() const { CSize sz; if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsValid() ) sz.cy = m_pVerticalScrollBar->GetScrollRange(); if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsValid() ) sz.cx = m_pHorizontalScrollBar->GetScrollRange(); return sz; } void ScrollableBox::SetScrollPos(CSize szPos) { if (szPos.cy < 0) { szPos.cy = 0; m_scrollAnimation.Reset(); } else if (szPos.cy > GetScrollRange().cy) { szPos.cy = GetScrollRange().cy; m_scrollAnimation.Reset(); } int cx = 0; int cy = 0; if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsValid() ) { int iLastScrollPos = m_pVerticalScrollBar->GetScrollPos(); m_pVerticalScrollBar->SetScrollPos(szPos.cy); cy = m_pVerticalScrollBar->GetScrollPos() - iLastScrollPos; } if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsValid() ) { int iLastScrollPos = m_pHorizontalScrollBar->GetScrollPos(); m_pHorizontalScrollBar->SetScrollPos(szPos.cx); cx = m_pHorizontalScrollBar->GetScrollPos() - iLastScrollPos; } if( cx == 0 && cy == 0 ) return; LoadImageCache(cy > 0); Invalidate(); if( m_pWindow != NULL ) { m_pWindow->SendNotify(this, kEventScrollChange); } } void ScrollableBox::LoadImageCache(bool bFromTopLeft) { CSize scrollPos = GetScrollPos(); auto forEach = [this, scrollPos](ui::Control* pControl) { if (!pControl->IsVisible()) return; if (pControl->IsFloat()) return; UiRect rcTemp; UiRect rcImageCachePos = GetPos(); rcImageCachePos.Offset(scrollPos.cx, scrollPos.cy); rcImageCachePos.Offset(GetRenderOffset().x, GetRenderOffset().y); rcImageCachePos.Inflate(UiRect(0, 730, 0, 730)); UiRect controlPos = pControl->GetPos(); if (!::IntersectRect(&rcTemp, &rcImageCachePos, &controlPos)) { pControl->UnLoadImageCache(); } else { pControl->InvokeLoadImageCache(); } }; if (!bFromTopLeft) { std::for_each(m_items.rbegin(), m_items.rend(), forEach); } else { std::for_each(m_items.begin(), m_items.end(), forEach); } } void ScrollableBox::SetScrollPosY(int y) { CSize scrollPos = GetScrollPos(); scrollPos.cy = y; SetScrollPos(scrollPos); } void ScrollableBox::SetScrollPosX(int x) { CSize scrollPos = GetScrollPos(); scrollPos.cx = x; SetScrollPos(scrollPos); } void ScrollableBox::LineUp(int deltaValue, bool withAnimation) { int cyLine = GetVerScrollUnitPixels(); if (cyLine == 0) { cyLine = 20; } if (deltaValue != DUI_NOSET_VALUE) { cyLine = min(cyLine, deltaValue); } CSize scrollPos = GetScrollPos(); if (scrollPos.cy <= 0) { return; } if (!withAnimation) { scrollPos.cy -= cyLine; if (scrollPos.cy < 0) { scrollPos.cy = 0; } SetScrollPos(scrollPos); } else { m_scrollAnimation.SetStartValue(scrollPos.cy); if (m_scrollAnimation.IsPlaying()) { if (m_scrollAnimation.GetEndValue() > m_scrollAnimation.GetStartValue()) { m_scrollAnimation.SetEndValue(scrollPos.cy - cyLine); } else { m_scrollAnimation.SetEndValue(m_scrollAnimation.GetEndValue() - cyLine); } } else { m_scrollAnimation.SetEndValue(scrollPos.cy - cyLine); } m_scrollAnimation.SetSpeedUpRatio(0); m_scrollAnimation.SetSpeedDownfactorA(-0.012); m_scrollAnimation.SetSpeedDownRatio(0.5); m_scrollAnimation.SetTotalMillSeconds(DUI_NOSET_VALUE); m_scrollAnimation.SetCallback(nbase::Bind(&ScrollableBox::SetScrollPosY, this, std::placeholders::_1)); m_scrollAnimation.Start(); } } void ScrollableBox::LineDown(int deltaValue, bool withAnimation) { int cyLine = GetVerScrollUnitPixels(); if (cyLine == 0) { cyLine = 20; } if (deltaValue != DUI_NOSET_VALUE) { cyLine = min(cyLine, deltaValue); } CSize scrollPos = GetScrollPos(); if (scrollPos.cy >= GetScrollRange().cy) { return; } if (!withAnimation) { scrollPos.cy += cyLine; if (scrollPos.cy < 0) { scrollPos.cy = 0; } SetScrollPos(scrollPos); } else { m_scrollAnimation.SetStartValue(scrollPos.cy); if (m_scrollAnimation.IsPlaying()) { if (m_scrollAnimation.GetEndValue() < m_scrollAnimation.GetStartValue()) { m_scrollAnimation.SetEndValue(scrollPos.cy + cyLine); } else { m_scrollAnimation.SetEndValue(m_scrollAnimation.GetEndValue() + cyLine); } } else { m_scrollAnimation.SetEndValue(scrollPos.cy + cyLine); } m_scrollAnimation.SetSpeedUpRatio(0); m_scrollAnimation.SetSpeedDownfactorA(-0.012); m_scrollAnimation.SetSpeedDownRatio(0.5); m_scrollAnimation.SetTotalMillSeconds(DUI_NOSET_VALUE); m_scrollAnimation.SetCallback(nbase::Bind(&ScrollableBox::SetScrollPosY, this, std::placeholders::_1)); m_scrollAnimation.Start(); } } void ScrollableBox::LineLeft(int detaValue) { int cxLine = GetHorScrollUnitPixels(); if (cxLine == 0) { cxLine = 20; } if (detaValue != DUI_NOSET_VALUE) { cxLine = min(cxLine, detaValue); } CSize scrollPos = GetScrollPos(); if (scrollPos.cx <= 0) { return; } scrollPos.cx -= cxLine; if (scrollPos.cx < 0) { scrollPos.cx = 0; } SetScrollPos(scrollPos); /*m_scrollAnimation.SetStartValue(scrollPos.cx); if (m_scrollAnimation.IsPlaying()) { if (m_scrollAnimation.GetEndValue() > m_scrollAnimation.GetStartValue()) { m_scrollAnimation.SetEndValue(scrollPos.cx - cxLine); } else { m_scrollAnimation.SetEndValue(m_scrollAnimation.GetEndValue() - cxLine); } } else { m_scrollAnimation.SetEndValue(scrollPos.cx - cxLine); } m_scrollAnimation.SetSpeedUpRatio(0); m_scrollAnimation.SetSpeedDownfactorA(-0.012); m_scrollAnimation.SetSpeedDownRatio(0.5); m_scrollAnimation.SetTotalMillSeconds(DUI_NOSET_VALUE); m_scrollAnimation.SetCallback(nbase::Bind(&ScrollableBox::SetScrollPosX, this, std::placeholders::_1)); m_scrollAnimation.Start();*/ } void ScrollableBox::LineRight(int detaValue) { int cxLine = GetHorScrollUnitPixels(); if (cxLine == 0) { cxLine = 20; } if (detaValue != DUI_NOSET_VALUE) { cxLine = min(cxLine, detaValue); } CSize scrollPos = GetScrollPos(); if (scrollPos.cx >= GetScrollRange().cx) { return; } scrollPos.cx += cxLine; if (scrollPos.cx > GetScrollRange().cx) { scrollPos.cx = GetScrollRange().cx; } SetScrollPos(scrollPos); //m_scrollAnimation.SetStartValue(scrollPos.cx); //if (m_scrollAnimation.IsPlaying()) { // if (m_scrollAnimation.GetEndValue() < m_scrollAnimation.GetStartValue()) { // m_scrollAnimation.SetEndValue(scrollPos.cx + cxLine); // } // else { // m_scrollAnimation.SetEndValue(m_scrollAnimation.GetEndValue() + cxLine); // } //} //else { // m_scrollAnimation.SetEndValue(scrollPos.cx + cxLine); //} //m_scrollAnimation.SetSpeedUpRatio(0); //m_scrollAnimation.SetSpeedDownfactorA(-0.012); //m_scrollAnimation.SetSpeedDownRatio(0.5); //m_scrollAnimation.SetTotalMillSeconds(DUI_NOSET_VALUE); //m_scrollAnimation.SetCallback(nbase::Bind(&ScrollableBox::SetScrollPosX, this, std::placeholders::_1)); //m_scrollAnimation.Start(); } void ScrollableBox::PageUp() { CSize sz = GetScrollPos(); int iOffset = m_rcItem.bottom - m_rcItem.top - m_pLayout->GetPadding().top - m_pLayout->GetPadding().bottom; if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsValid() ) iOffset -= m_pHorizontalScrollBar->GetFixedHeight(); sz.cy -= iOffset; SetScrollPos(sz); } void ScrollableBox::PageDown() { CSize sz = GetScrollPos(); int iOffset = m_rcItem.bottom - m_rcItem.top - m_pLayout->GetPadding().top - m_pLayout->GetPadding().bottom; if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsValid() ) iOffset -= m_pHorizontalScrollBar->GetFixedHeight(); sz.cy += iOffset; SetScrollPos(sz); } void ScrollableBox::HomeUp() { CSize sz = GetScrollPos(); sz.cy = 0; SetScrollPos(sz); } void ScrollableBox::EndDown(bool arrange, bool withAnimation) { if (arrange) { SetPosInternally(GetPos()); } int renderOffsetY = GetScrollRange().cy - GetScrollPos().cy + (m_renderOffsetYAnimation.GetEndValue() - GetRenderOffset().y); if (withAnimation == true && IsVScrollBarValid() && renderOffsetY > 0) { PlayRenderOffsetYAnimation(-renderOffsetY); } CSize sz = GetScrollPos(); sz.cy = GetScrollRange().cy; SetScrollPos(sz); } void ScrollableBox::PageLeft() { CSize sz = GetScrollPos(); int iOffset = m_rcItem.right - m_rcItem.left - m_pLayout->GetPadding().left - m_pLayout->GetPadding().right; //if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsValid() ) iOffset -= m_pVerticalScrollBar->GetFixedWidth(); sz.cx -= iOffset; SetScrollPos(sz); } void ScrollableBox::PageRight() { CSize sz = GetScrollPos(); int iOffset = m_rcItem.right - m_rcItem.left - m_pLayout->GetPadding().left - m_pLayout->GetPadding().right; //if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsValid() ) iOffset -= m_pVerticalScrollBar->GetFixedWidth(); sz.cx += iOffset; SetScrollPos(sz); } void ScrollableBox::HomeLeft() { CSize sz = GetScrollPos(); sz.cx = 0; SetScrollPos(sz); } void ScrollableBox::EndRight() { CSize sz = GetScrollPos(); sz.cx = GetScrollRange().cx; SetScrollPos(sz); } void ScrollableBox::TouchUp(int deltaValue) { CSize scrollPos = GetScrollPos(); if (scrollPos.cy <= 0) { return; } scrollPos.cy = scrollPos.cy - deltaValue; SetScrollPos(scrollPos); } void ScrollableBox::TouchDown(int deltaValue) { CSize scrollPos = GetScrollPos(); if (scrollPos.cy >= GetScrollRange().cy) { return; } scrollPos.cy = scrollPos.cy + deltaValue; SetScrollPos(scrollPos); } void ScrollableBox::EnableScrollBar(bool bEnableVertical, bool bEnableHorizontal) { if( bEnableVertical && !m_pVerticalScrollBar ) { m_pVerticalScrollBar.reset(new ScrollBar); m_pVerticalScrollBar->SetVisible_(false); m_pVerticalScrollBar->SetScrollRange(0); m_pVerticalScrollBar->SetOwner(this); m_pVerticalScrollBar->SetWindow(m_pWindow, NULL, false); m_pVerticalScrollBar->SetClass(_T("vscrollbar")); } else if( !bEnableVertical && m_pVerticalScrollBar ) { m_pVerticalScrollBar.reset(); } if( bEnableHorizontal && !m_pHorizontalScrollBar ) { m_pHorizontalScrollBar.reset(new ScrollBar); m_pHorizontalScrollBar->SetVisible_(false); m_pHorizontalScrollBar->SetScrollRange(0); m_pHorizontalScrollBar->SetHorizontal(true); m_pHorizontalScrollBar->SetOwner(this); m_pHorizontalScrollBar->SetWindow(m_pWindow, NULL, false); m_pHorizontalScrollBar->SetClass(_T("hscrollbar")); } else if( !bEnableHorizontal && m_pHorizontalScrollBar ) { m_pHorizontalScrollBar.reset(); } Arrange(); } ScrollBar* ScrollableBox::GetVerticalScrollBar() const { return m_pVerticalScrollBar.get(); } ScrollBar* ScrollableBox::GetHorizontalScrollBar() const { return m_pHorizontalScrollBar.get(); } void ScrollableBox::ProcessVScrollBar(UiRect rc, int cyRequired) { UiRect rcScrollBarPos = rc; rcScrollBarPos.left += m_rcScrollBarPadding.left; rcScrollBarPos.top += m_rcScrollBarPadding.top; rcScrollBarPos.right -= m_rcScrollBarPadding.right; rcScrollBarPos.bottom -= m_rcScrollBarPadding.bottom; if( m_pVerticalScrollBar == NULL ) return; rc.left += m_pLayout->GetPadding().left; rc.top += m_pLayout->GetPadding().top; rc.right -= m_pLayout->GetPadding().right; rc.bottom -= m_pLayout->GetPadding().bottom; int nHeight = rc.bottom - rc.top; if (cyRequired > nHeight && !m_pVerticalScrollBar->IsValid()) { m_pVerticalScrollBar->SetScrollRange(cyRequired - nHeight); m_pVerticalScrollBar->SetScrollPos(0); m_bScrollProcess = true; SetPos(m_rcItem); m_bScrollProcess = false; return; } // No scrollbar required if( !m_pVerticalScrollBar->IsValid() ) return; // Scroll not needed anymore? int cyScroll = cyRequired - nHeight; if( cyScroll <= 0 && !m_bScrollProcess) { m_pVerticalScrollBar->SetScrollPos(0); m_pVerticalScrollBar->SetScrollRange(0); SetPos(m_rcItem); } else { UiRect rcVerScrollBarPos(rcScrollBarPos.right - m_pVerticalScrollBar->GetFixedWidth(), rcScrollBarPos.top, rcScrollBarPos.right, rcScrollBarPos.bottom); m_pVerticalScrollBar->SetPos(rcVerScrollBarPos); if( m_pVerticalScrollBar->GetScrollRange() != cyScroll ) { int iScrollPos = m_pVerticalScrollBar->GetScrollPos(); m_pVerticalScrollBar->SetScrollRange(::abs(cyScroll)); if( !m_pVerticalScrollBar->IsValid() ) { m_pVerticalScrollBar->SetScrollPos(0); } if( iScrollPos > m_pVerticalScrollBar->GetScrollPos() ) { SetPos(m_rcItem); } } } } void ScrollableBox::ProcessHScrollBar(UiRect rc, int cxRequired) { UiRect rcScrollBarPos = rc; rcScrollBarPos.left += m_rcScrollBarPadding.left; rcScrollBarPos.top += m_rcScrollBarPadding.top; rcScrollBarPos.right -= m_rcScrollBarPadding.right; rcScrollBarPos.bottom -= m_rcScrollBarPadding.bottom; if (m_pHorizontalScrollBar == NULL) return; rc.left += m_pLayout->GetPadding().left; rc.top += m_pLayout->GetPadding().top; rc.right -= m_pLayout->GetPadding().right; rc.bottom -= m_pLayout->GetPadding().bottom; int nWidth = rc.right - rc.left; if (cxRequired > nWidth && !m_pHorizontalScrollBar->IsValid()) { m_pHorizontalScrollBar->SetScrollRange(cxRequired - nWidth); m_pHorizontalScrollBar->SetScrollPos(0); m_bScrollProcess = true; SetPos(m_rcItem); m_bScrollProcess = false; return; } // No scrollbar required if (!m_pHorizontalScrollBar->IsValid()) return; // Scroll not needed anymore? int cxScroll = cxRequired - nWidth; if (cxScroll <= 0 && !m_bScrollProcess) { m_pHorizontalScrollBar->SetScrollPos(0); m_pHorizontalScrollBar->SetScrollRange(0); SetPos(m_rcItem); } else { UiRect rcVerScrollBarPos(rcScrollBarPos.left, rcScrollBarPos.bottom - m_pHorizontalScrollBar->GetFixedHeight(), rcScrollBarPos.right, rcScrollBarPos.bottom); m_pHorizontalScrollBar->SetPos(rcVerScrollBarPos); if (m_pHorizontalScrollBar->GetScrollRange() != cxScroll) { int iScrollPos = m_pHorizontalScrollBar->GetScrollPos(); m_pHorizontalScrollBar->SetScrollRange(::abs(cxScroll)); if (!m_pHorizontalScrollBar->IsValid()) { m_pHorizontalScrollBar->SetScrollPos(0); } if (iScrollPos > m_pHorizontalScrollBar->GetScrollPos()) { SetPos(m_rcItem); } } } } bool ScrollableBox::IsVScrollBarValid() const { if (m_pVerticalScrollBar) { return m_pVerticalScrollBar->IsValid(); } return false; } bool ScrollableBox::IsHScrollBarValid() const { if (m_pHorizontalScrollBar) { return m_pHorizontalScrollBar->IsValid(); } return false; } void ScrollableBox::ReomveLastItemAnimation() { int nStartRang = GetScrollRange().cy; SetPosInternally(GetPos()); int nEndRang = GetScrollRange().cy; int nRenderOffset = nEndRang - nStartRang + (m_renderOffsetYAnimation.GetEndValue() - GetRenderOffset().y); if (nRenderOffset < 0) { PlayRenderOffsetYAnimation(-nRenderOffset); } } void ScrollableBox::PlayRenderOffsetYAnimation(int nRenderY) { m_renderOffsetYAnimation.SetStartValue(nRenderY); m_renderOffsetYAnimation.SetEndValue(0); m_renderOffsetYAnimation.SetSpeedUpRatio(0.3); m_renderOffsetYAnimation.SetSpeedUpfactorA(0.003); m_renderOffsetYAnimation.SetSpeedDownRatio(0.7); m_renderOffsetYAnimation.SetTotalMillSeconds(DUI_NOSET_VALUE); m_renderOffsetYAnimation.SetMaxTotalMillSeconds(650); std::function playCallback = nbase::Bind(&ScrollableBox::SetRenderOffsetY, this, std::placeholders::_1); m_renderOffsetYAnimation.SetCallback(playCallback); m_renderOffsetYAnimation.Start(); } bool ScrollableBox::IsAtEnd() const { return GetScrollRange().cy <= GetScrollPos().cy; } bool ScrollableBox::IsHoldEnd() const { return m_bHoldEnd; } void ScrollableBox::SetHoldEnd(bool bHoldEnd) { m_bHoldEnd = bHoldEnd; } int ScrollableBox::GetVerScrollUnitPixels() const { return m_nVerScrollUnitPixels; } void ScrollableBox::SetVerScrollUnitPixels(int nUnitPixels) { DpiManager::GetInstance()->ScaleInt(nUnitPixels); m_nVerScrollUnitPixels = nUnitPixels; } int ScrollableBox::GetHorScrollUnitPixels() const { return m_nHerScrollUnitPixels; } void ScrollableBox::SetHorScrollUnitPixels(int nUnitPixels) { DpiManager::GetInstance()->ScaleInt(nUnitPixels); m_nHerScrollUnitPixels = nUnitPixels; } bool ScrollableBox::GetScrollBarFloat() const { return m_bScrollBarFloat; } void ScrollableBox::SetScrollBarFloat(bool bScrollBarFloat) { m_bScrollBarFloat = bScrollBarFloat; } ui::UiRect ScrollableBox::GetScrollBarPadding() const { return m_rcScrollBarPadding; } void ScrollableBox::SetScrollBarPadding(UiRect rcScrollBarPadding) { DpiManager::GetInstance()->ScaleRect(rcScrollBarPadding); m_rcScrollBarPadding = rcScrollBarPadding; } bool ScrollableBox::GetDefaultDisplayScrollbar() const { return m_bDefaultDisplayScrollbar; } void ScrollableBox::SetDefaultDisplayScrollbar(bool bDefaultDisplay) { m_bDefaultDisplayScrollbar = bDefaultDisplay; } void ScrollableBox::ClearImageCache() { __super::ClearImageCache(); if (m_pHorizontalScrollBar) m_pHorizontalScrollBar->ClearImageCache(); if (m_pVerticalScrollBar) m_pVerticalScrollBar->ClearImageCache(); } } // namespace ui