/* QSoloCards is a collection of Solitaire card games written using Qt Copyright (C) 2009 Steve Moore This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "DealAnimation.h" #include "CardAnimationLock.h" #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// DealItem::DealItem(CardStack * pDst,CardStack * pSrc) :m_pDst(pDst), m_pSrc(pSrc), m_flipList() { } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// DealItem::DealItem(const DealItem & rh) :m_pDst(NULL), m_pSrc(NULL), m_flipList() { *this=rh; } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// DealItem::~DealItem() { } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// bool DealItem::getNextCard() { bool rc=false; if (!m_flipList.empty()) { rc=m_flipList.front(); m_flipList.pop_front(); } return rc; } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// DealItem & DealItem::operator=(const DealItem & rh) { m_pSrc=rh.m_pSrc; m_pDst=rh.m_pDst; m_flipList=rh.m_flipList; return *this; } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// DealGraphicsItem::DealGraphicsItem(DealItem & dealItem,CardMoveRecord &moveRecord) :QObject(), QGraphicsPixmapItem(), m_dealItem(dealItem), m_flipCard(dealItem.getNextCard()), m_card(PlayingCard::MaxSuit,PlayingCard::MaxCardIndex), m_pGItemAni(new QGraphicsItemAnimation), m_moveRecord(moveRecord), m_timeLine(), m_delayTimer(), m_emitFinished(true) { this->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// DealGraphicsItem::~DealGraphicsItem() { } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void DealGraphicsItem::slotAniFinished() { // add the card m_dealItem.dst()->addCard(m_card,m_moveRecord); // now update the destination m_dealItem.dst()->updateStack(); // remove the item from the scene m_dealItem.src()->scene()->removeItem(this); // now if the card needs to be flipped. Flip it. If we are not // emitting a finish signal. Then disable animation for the flip. if (m_flipCard) { m_dealItem.dst()->flipCard(m_dealItem.dst()->getCardVector().size()-1,m_moveRecord,m_emitFinished); } delete m_pGItemAni; m_pGItemAni=NULL; if (m_emitFinished) { emit aniFinished(this); } } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void DealGraphicsItem::slotTimeToStart() { m_timeLine.start(); } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void DealGraphicsItem::setupAnimation(unsigned int duration,unsigned int delay,unsigned int zValue) { m_timeLine.setDuration(duration); this->connect(&m_timeLine,SIGNAL(finished()), this,SLOT(slotAniFinished())); QPointF startPt(m_dealItem.src()->getGlobalLastCardPt()); this->m_card=m_dealItem.src()->removeTopCard(m_moveRecord); PlayingCardVector cardVector; cardVector.push_back(this->m_card); QPixmap * pPixmap=m_dealItem.src()->getStackPixmap(cardVector); if (pPixmap) { this->setPixmap(*pPixmap); delete pPixmap; } // set the z value passed in this->setZValue(zValue); // add the item to the scene and move it over the stack in the // place of the cards we are going to move m_dealItem.src()->scene()->addItem(this); this->setPos(startPt); // setup the animation m_pGItemAni->setItem(this); m_pGItemAni->setTimeLine(&m_timeLine); m_pGItemAni->setPosAt (0, startPt); m_pGItemAni->setPosAt (1, m_dealItem.dst()->getGlobalCardAddPt()); m_pGItemAni->setRotationAt (0, 0); // change the rotation slightly depending on how far apart in the // x direction that stacks are apart. if (qAbs((int)(startPt.x()-m_dealItem.dst()->getGlobalCardAddPt().x()))<5) { } else if (startPt.x()>=m_dealItem.dst()->getGlobalCardAddPt().x()) { m_pGItemAni->setRotationAt (.5, 90); } else { m_pGItemAni->setRotationAt (.5, -90); } m_pGItemAni->setRotationAt (1, 0); // redraw the source stack. m_dealItem.src()->updateStack(); if (delay>0) { m_delayTimer.setSingleShot(true); m_delayTimer.setInterval(delay); this->connect(&m_delayTimer,SIGNAL(timeout()), this,SLOT(slotTimeToStart())); m_delayTimer.start(); } else { this->slotTimeToStart(); } } void DealGraphicsItem::stopAni() { bool stopping=false; if (QTimeLine::Running==m_timeLine.state()) { m_timeLine.stop(); stopping=true; } if (m_delayTimer.isActive()) { m_delayTimer.stop(); stopping=true; } if (stopping) { m_emitFinished=false; this->slotAniFinished(); } } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// DealAnimation::DealAnimation() :m_moveRecord(), m_dealItemVector(), m_graphicsItemVector(), m_aniRunning(false), m_stopAni(false), m_duration(DealAnimation::PerDealDuration), m_createMoveRecord(true) { } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// DealAnimation::~DealAnimation() { this->stopAni(); } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// bool DealAnimation::dealCards(const DealItemVector & itemVector, bool createMoveRecord) { if (m_aniRunning) { return false; } m_createMoveRecord=createMoveRecord; // clear any previous items in the move record. m_moveRecord.clear(); // clear any previous items in the dealItemVector // and set it equal to the new one. m_dealItemVector.clear(); m_dealItemVector=itemVector; if (!CardAnimationLock::getInst().animationsEnabled()) { this->noAniStackUdpates(); } else { this->buildAniStackUpdates(); CardAnimationLock::getInst().lock(); this->m_aniRunning=true; } return true; } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void DealAnimation::stopAni() { // ok we only want to do this if animation is running. if (m_aniRunning) { m_aniRunning=false; unsigned int i; // different from the case when we are cleaning these up as we go we want a hard update, and then // delete of the objects. for (i=0;istopAni(); delete m_graphicsItemVector[i]; } m_graphicsItemVector.clear(); } } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void DealAnimation::slotAniFinished(DealGraphicsItem * pDealGraphicsItem) { if (m_aniRunning) { // cleanup and finialize addition of items to new stacks. this->cleanUpGraphicsItem(pDealGraphicsItem); if (m_graphicsItemVector.empty()) { m_aniRunning=false; CardAnimationLock::getInst().unlock(); if (!m_createMoveRecord) { m_moveRecord.clear(); } emit cardsMoved(m_moveRecord); } } } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// bool DealAnimation::cardsRemaining() { bool rc=false; unsigned int i; for (i=0;ideleteLater(); break; } } } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void DealAnimation::cleanUpGraphicsItems() { unsigned int i; for (i=0;ideleteLater(); } m_graphicsItemVector.clear(); } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void DealAnimation::noAniStackUdpates() { unsigned int i; bool oneNotEmpty=true; while (oneNotEmpty) { oneNotEmpty=false; for (i=0;iremoveTopCard(m_moveRecord)); m_dealItemVector[i].dst()->addCard(card,m_moveRecord); if (flip) { m_dealItemVector[i].dst()->flipCard(-1,m_moveRecord); } m_dealItemVector[i].src()->updateStack(); m_dealItemVector[i].dst()->updateStack(); oneNotEmpty=true; } } } if (!m_createMoveRecord) { m_moveRecord.clear(); } if (m_aniRunning) { emit cardsMoved(m_moveRecord); } } /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// void DealAnimation::buildAniStackUpdates() { unsigned int i; unsigned int j=0; bool oneNotEmpty=true; while (oneNotEmpty) { oneNotEmpty=false; for (i=0;isetupAnimation(m_duration,j*PerCardDelay,j+2); this->connect(pCurrGraphicsItem,SIGNAL(aniFinished(DealGraphicsItem *)), this,SLOT(slotAniFinished(DealGraphicsItem *))); m_graphicsItemVector.push_back(pCurrGraphicsItem); oneNotEmpty=true; j++; } } } }