nim_duilib/duilib/Core/Box.cpp
jiajia_deng 4933d1f2bc Remove dependency on shared
Signed-off-by: jiajia_deng <2894220@gmail.com>
2019-09-20 16:27:58 +08:00

1710 lines
46 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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>
}
/////////////////////////////////////////////////////////////////////////////////////
//
//
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<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