#include "cardstacklayout.h"
#include <cmath>
#include <QLabel>
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>
#include <QGraphicsOpacityEffect>
CardStackLayout::CardStackLayout(QWidget *parent, CardStackLayout::CardStackLayoutStyle style)
: QLayout(parent)
, m_cardstacklayout_style(style)
, m_horizontal_center(true)
, m_vertical_center(true)
{
m_animation_relevant.runing = false;
m_animation_relevant.anitype = 1;
m_animation_relevant.useani = true;
m_non_first_transparent = true;
m_north_spacing = 20;
m_west_spacing = 20;
setMargin(0);
setSpacing(0);
}
CardStackLayout::~CardStackLayout()
{
destoryAll();
}
void CardStackLayout::destoryAll()
{
QLayoutItem *item = NULL;
while (item = takeAt(0))
{
delete item;
}
}
void CardStackLayout::addItem(QLayoutItem *item)
{
add(item, ZBottom);
}
void CardStackLayout::addWidget(QWidget *widget, CardStackLayout::Position position)
{
add(new QWidgetItem(widget), position);
}
void CardStackLayout::add(QLayoutItem *item, CardStackLayout::Position position)
{
if(Cascade == m_cardstacklayout_style)
{
item->setAlignment(Qt::AlignHCenter);
ItemWrapper *p = new ItemWrapper(item);
if(ZTop == position)
{
m_list.push_front(p);
}
else
{
m_list.append(p);
}
reLayer();
}
// QWidget *w = item->widget();
// if(w)
// {
// w->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
// w->show();
// }
changeNonFirstTransparent();
invalidate();
}
bool CardStackLayout::hasHeightForWidth() const
{
return false;
}
int CardStackLayout::count() const
{
return m_list.size();
}
QLayoutItem *CardStackLayout::itemAt(int index) const
{
ItemWrapper *it = m_list.value(index);
if (it)
return it->item;
else
return 0;
}
QLayoutItem *CardStackLayout::takeAt(int index)
{
QLayoutItem *item = NULL;
if (index >= 0 && index < m_list.size())
{
ItemWrapper *layoutStruct = m_list.takeAt(index);
item = layoutStruct->item;
delete layoutStruct;
}
return item;
}
void CardStackLayout::setGeometry(const QRect &rect)
{
QLayout::setGeometry(rect);
QRect rcpre, rcnow;
QRect rccombination = calculateCombRect(rect);
QPoint ptsrccenter = rccombination.center();
QPoint ptdstcenter = rect.center();
int woffset = abs(ptdstcenter.rx())-abs(ptsrccenter.rx());
int hoffset = abs(ptdstcenter.ry())-abs(ptsrccenter.ry());
if(!m_list.empty())
{
ItemWrapper *p = m_list.at(0);
rcnow = rect;
rcnow.setSize(p->item->geometry().size());
if(m_horizontal_center)
{
rcnow.adjust(woffset,0,woffset,0);
}
if(m_vertical_center)
{
rcnow.adjust(0,hoffset,0,hoffset);
}
p->item->setGeometry(rcnow);
rcpre = rcnow;
}
for (int i = 1; i < m_list.size(); ++i)
{
ItemWrapper *p = m_list.at(i);
bool bok = calculateItemRect(rcpre,p,rcnow);
if(!bok){ continue;}
p->item->setGeometry(rcnow);
rcpre = rcnow;
}
}
QSize CardStackLayout::minimumSize() const
{
return calculateSize(MinimumSize);
}
QSize CardStackLayout::sizeHint() const
{
return calculateSize(SizeHint);
}
QSize CardStackLayout::calculateSize(CardStackLayout::SizeType sizeType) const
{
QSize totalSize(0,0);
QRect rcpre, rcnow,rect(0,0,0,0);
for (int i = 0; i < m_list.size(); ++i)
{
ItemWrapper *wrapper = m_list.at(i);
QSize itemSize;
if (sizeType == MinimumSize)
{
itemSize = wrapper->item->minimumSize();
}
else // (sizeType == SizeHint)
{
itemSize = wrapper->item->sizeHint();
}
ItemWrapper *p = m_list.at(i);
rcpre = (0 == i)? p->item->geometry():rcpre;
bool bok = calculateItemRect(rcpre,p,rcnow);
if(!bok){ continue;}
rcpre = rcnow;
totalSize = totalSize.expandedTo(rcnow.size());
}
return totalSize;
}
bool CardStackLayout::calculateItemRect(QRect rcpre, ItemWrapper *p, QRect &rcnow) const
{
if(NULL == p)
{
Q_ASSERT(NULL!=p);
return false;
}
QWidget *w = p->item->widget();
rcnow = rcpre;
tyPosValue::const_iterator it;
it = p->mapPos.find(North);
if(it!=p->mapPos.end())
{
rcnow.setTop(rcpre.top()+it.value());
}
else
{
rcnow.setTop(rcpre.top() + m_north_spacing);
}
it = p->mapPos.find(West);
if(it!=p->mapPos.end())
{
rcnow.setLeft(rcpre.left()+it.value());
}
else
{
rcnow.setLeft(rcpre.left() + m_west_spacing);
}
if(NULL!=w)
{
rcnow.setRight(rcnow.left()+ w->size().width());
rcnow.setBottom(rcnow.top()+ w->size().height());
}
else
{
QSize si = p->item->geometry().size();
rcnow.setRight(rcnow.left()+ si.width());
rcnow.setBottom(rcnow.top()+ si.height());
}
return true;
}
QRect CardStackLayout::calculateCombRect(QRect rclayout)
{
QRect rcpre = rclayout, rcnow, rcmax = rclayout;
if(!m_list.empty())
{
rcmax.setSize(m_list.at(0)->item->geometry().size());
rcpre = rcmax;
}
for (int i = 1; i < m_list.size(); ++i)
{
ItemWrapper *p = m_list.at(i);
bool bok = calculateItemRect(rcpre,p,rcnow);
if(!bok){ continue;}
rcmax = rcmax.united(rcnow);
rcpre = rcnow;
}
return rcmax;
}
Qt::Orientations CardStackLayout::expandingDirections() const
{
return Qt::Horizontal | Qt::Vertical;
}
void CardStackLayout::adjustWideget(QWidget *widget, long posflag, int offset)
{
if(Q_NULLPTR == widget) return;
int index;
CardStackLayout::ItemWrapper *p = find(widget,&index);
adjustItem(index,p,posflag,offset);
}
void CardStackLayout::adjustWideget(QWidget *widget, const CardStackLayout::tyPosValue &posvalue)
{
if(Q_NULLPTR == widget) return;
int index;
ItemWrapper *p = find(widget,&index);
tyPosValue::const_iterator it = posvalue.begin();
while (it != posvalue.end() )
{
adjustItem(index,p,it.key(),it.value());
++it;
}
}
void CardStackLayout::adjustWideget(int index, const CardStackLayout::tyPosValue &posvalue)
{
if(index<0 || index>=m_list.size())
return;
ItemWrapper *p = m_list.at(index);
tyPosValue::const_iterator it = posvalue.begin();
while (it != posvalue.end() )
{
adjustItem(index,p,it.key(),it.value());
++it;
}
}
void CardStackLayout::adjustItem(int index, CardStackLayout::ItemWrapper *p, long posflag, int offset)
{
if(Q_NULLPTR == p || m_animation_relevant.runing)
return;
if(posflag & ZTop || posflag & ZBottom)
{
int newIndex = offset;
int n = m_list.size();
if(posflag & ZTop)
{
newIndex = n>newIndex? newIndex: n-1;
}
else
{
newIndex = newIndex>0?0:newIndex;
newIndex = n>abs(newIndex)? (n+newIndex-1): 0;
}
switchOrder(index,newIndex,p);
}
if( posflag & North || posflag & West)
{
if(posflag & North)
{
p->mapPos[North] = offset;
}
if(posflag & West)
{
p->mapPos[West] = offset;
}
invalidate();
}
}
void CardStackLayout::changeNonFirstTransparent()
{
QGraphicsOpacityEffect* pOpacityEffect =