nim_duilib/duilib/Core/Box.cpp

1710 lines
46 KiB
C++
Raw Normal View History

2019-04-19 17:19:57 +08:00
#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<Control*>& 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<Control*>& 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<nbase::WeakFlag> 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());
}
}
// <20>߼<EFBFBD><DFBC>ϣ<EFBFBD><CFA3><EFBFBD><EFBFBD><EFBFBD>Container<65>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˷<EFBFBD><CBB7><EFBFBD>
// <20><><EFBFBD>ô˷<C3B4><CBB7><EFBFBD><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD><EFBFBD>ǣ<EFBFBD><C7A3>ڲ<EFBFBD><DAB2>ӿؼ<D3BF><D8BC><EFBFBD><EFBFBD>أ<EFBFBD><D8A3>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȼ<EFBFBD><C8BB>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void Box::SetInternVisible(bool bVisible)
{
Control::SetInternVisible(bVisible);
if (m_items.empty()) return;
for (auto it = m_items.begin(); it != m_items.end(); it++) {
// <20><><EFBFBD><EFBFBD><EFBFBD>ӿؼ<D3BF><D8BC><EFBFBD>ʾ״̬
// InternVisible״̬Ӧ<CCAC><D3A6><EFBFBD>ӿؼ<D3BF><D8BC>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD>
(*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<LPPOINT>(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<LPPOINT>(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<LPPOINT>(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<LPPOINT>(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<LPPOINT>(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<Control*>(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<ListContainerElement*>(GetItemAt(i)) != NULL
&& GetItemAt(i)->IsVisible()
&& GetItemAt(i)->IsEnabled()) return i;
}
return -1;
}
else {
for (int i = iIndex; i >= 0; --i) {
if (dynamic_cast<ListContainerElement*>(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<Control*>(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<Control*>::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 Ĭ<>ϲ<EFBFBD>֧<EFBFBD><D6A7> TAB <20>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD>
}
2019-04-19 17:19:57 +08:00
/////////////////////////////////////////////////////////////////////////////////////
//
//
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);
2019-04-19 17:19:57 +08:00
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<LPPOINT>(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<void(int)> 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