mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-11 00:44:27 -05:00
858 lines
23 KiB
C++
858 lines
23 KiB
C++
|
/*
|
||
|
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 <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "CardStack.h"
|
||
|
#include <QtGui/QPainter>
|
||
|
#include <QtCore/QTimer>
|
||
|
#include <QtGui/QCursor>
|
||
|
#include <QtGui/QGraphicsSceneHoverEvent>
|
||
|
#include <QtGui/QGraphicsSceneMouseEvent>
|
||
|
#include <QtGui/QApplication>
|
||
|
#include "CardPixmaps.h"
|
||
|
#include "CardAnimationLock.h"
|
||
|
|
||
|
#include <iostream>
|
||
|
|
||
|
CardStackMap CardStack::m_cardStackMap;
|
||
|
bool CardStack::m_lockUserInteraction=false;
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
CardStack::CardStack()
|
||
|
:QObject(),QGraphicsPixmapItem(),
|
||
|
m_hintHighlightIndex(-1),
|
||
|
m_stackName(),
|
||
|
m_cardVector(),
|
||
|
m_highlighted(false),
|
||
|
m_showRedealCircle(false),
|
||
|
m_autoFaceUp(false),
|
||
|
m_mouseMoved(false),
|
||
|
m_dragStartPos(0,0),
|
||
|
m_flipAni(),
|
||
|
m_dragStack(this)
|
||
|
{
|
||
|
// set the name of this stack and add it to the map of stacks.
|
||
|
m_stackName=QString::number((qlonglong)this);
|
||
|
m_cardStackMap[this->stackName()]=this;
|
||
|
|
||
|
// accept drops and mouse hover events
|
||
|
this->setAcceptDrops(true);
|
||
|
this->setAcceptHoverEvents(true);
|
||
|
|
||
|
this->setZValue(1);
|
||
|
|
||
|
this->setCursor(Qt::PointingHandCursor);
|
||
|
this->setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
|
||
|
|
||
|
// call update stack to set the initial view of the stack as empty.
|
||
|
this->updateStack();
|
||
|
|
||
|
|
||
|
this->connect(&m_flipAni,SIGNAL(flipComplete(CardStack *)),
|
||
|
this,SLOT(slotFlipComplete(CardStack *)));
|
||
|
|
||
|
this->connect(&m_dragStack,SIGNAL(cardsMoved(const CardMoveRecord &)),
|
||
|
this,SLOT(slotDragCardsMoved(const CardMoveRecord &)));
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
CardStack::~CardStack()
|
||
|
{
|
||
|
// remove the pointer from the map of stacks to the class.
|
||
|
m_cardStackMap.erase(this->stackName());
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::allCardsFaceUp()const
|
||
|
{
|
||
|
bool rc=true;
|
||
|
unsigned int i;
|
||
|
|
||
|
for(i=0;i<this->m_cardVector.size();i++)
|
||
|
{
|
||
|
if (!this->m_cardVector[i].isFaceUp())
|
||
|
{
|
||
|
rc=false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::cardsAscendingTopToBottom()const
|
||
|
{
|
||
|
bool rc=true;
|
||
|
const PlayingCardVector & cardVector=this->getCardVector();
|
||
|
int i;
|
||
|
|
||
|
// see if the cards are in descending order from
|
||
|
// index 0 to n.
|
||
|
for (i=cardVector.size()-1;i>0;i--)
|
||
|
{
|
||
|
if (cardVector[i]>cardVector[i-1])
|
||
|
{
|
||
|
rc=false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::cardsDecendingTopToBottom()const
|
||
|
{
|
||
|
bool rc=true;
|
||
|
const PlayingCardVector & cardVector=this->getCardVector();
|
||
|
int i;
|
||
|
|
||
|
// see if the cards are in descending order from
|
||
|
// index 0 to n.
|
||
|
for (i=cardVector.size()-1;i>0;i--)
|
||
|
{
|
||
|
if (cardVector[i]<cardVector[i-1])
|
||
|
{
|
||
|
rc=false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::setTopCardUp(bool faceUp)
|
||
|
{
|
||
|
if (this->m_cardVector.size()>0 && faceUp!=this->m_cardVector[this->m_cardVector.size()-1].isFaceUp())
|
||
|
{
|
||
|
flipCard(-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::flipCard(int index,bool aniIfEnabled)
|
||
|
{
|
||
|
bool rc=false;
|
||
|
if (this->m_cardVector.size()>0)
|
||
|
{
|
||
|
// if index is less than 0 assume it is the last card.
|
||
|
if (index<0)
|
||
|
{
|
||
|
index=this->m_cardVector.size()-1;
|
||
|
}
|
||
|
|
||
|
if (index<(int)this->m_cardVector.size())
|
||
|
{
|
||
|
if (aniIfEnabled)
|
||
|
{
|
||
|
m_flipAni.flipCard(this);
|
||
|
}
|
||
|
this->m_cardVector[index].setFaceUp(!this->m_cardVector[index].isFaceUp());
|
||
|
this->updateStack();
|
||
|
rc=true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::flipCard(int index,CardMoveRecord & moveRecord,bool aniIfEnabled)
|
||
|
{
|
||
|
bool rc=flipCard(index,aniIfEnabled);
|
||
|
if (rc)
|
||
|
{
|
||
|
// if index is less than 0 assume it is the last card.
|
||
|
if (index<0)
|
||
|
{
|
||
|
index=this->m_cardVector.size()-1;
|
||
|
}
|
||
|
|
||
|
moveRecord.push_back(CardMoveRecordItem(this->stackName(),index));
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::addCard(const PlayingCard & newCard)
|
||
|
{
|
||
|
m_cardVector.push_back(newCard);
|
||
|
|
||
|
if (isFlipAniRunning())
|
||
|
{
|
||
|
m_flipAni.stopAni();
|
||
|
this->updateStack();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::addCards(const PlayingCardVector & cardVector)
|
||
|
{
|
||
|
for(unsigned int i=0;i<cardVector.size();i++)
|
||
|
{
|
||
|
m_cardVector.push_back(cardVector[i]);
|
||
|
}
|
||
|
|
||
|
if (isFlipAniRunning())
|
||
|
{
|
||
|
m_flipAni.stopAni();
|
||
|
this->updateStack();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::addCard(const PlayingCard & newCard,CardMoveRecord & moveRecord,bool justUpdateRec)
|
||
|
{
|
||
|
if (!justUpdateRec)
|
||
|
{
|
||
|
this->addCard(newCard);
|
||
|
}
|
||
|
|
||
|
PlayingCardVector cardVector;
|
||
|
cardVector.push_back(newCard);
|
||
|
moveRecord.push_back(CardMoveRecordItem(this->stackName(),CardMoveRecordItem::AddCards,cardVector));
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::addCards(const PlayingCardVector & cardVector,CardMoveRecord & moveRecord,bool justUpdateRec)
|
||
|
{
|
||
|
if (!justUpdateRec)
|
||
|
{
|
||
|
this->addCards(cardVector);
|
||
|
}
|
||
|
moveRecord.push_back(CardMoveRecordItem(this->stackName(),CardMoveRecordItem::AddCards,cardVector));
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
PlayingCard CardStack::removeTopCard()
|
||
|
{
|
||
|
PlayingCard card(PlayingCard::MaxSuit,PlayingCard::MaxCardIndex);
|
||
|
|
||
|
if (!this->m_cardVector.empty())
|
||
|
{
|
||
|
card=m_cardVector.back();
|
||
|
this->m_cardVector.pop_back();
|
||
|
}
|
||
|
return card;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
PlayingCard CardStack::removeTopCard(CardMoveRecord & moveRecord)
|
||
|
{
|
||
|
PlayingCard card(PlayingCard::MaxSuit,PlayingCard::MaxCardIndex);
|
||
|
card=this->removeTopCard();
|
||
|
|
||
|
// if the card is valid update the moveRecord
|
||
|
if (card.isValid())
|
||
|
{
|
||
|
PlayingCardVector cardVector;
|
||
|
cardVector.push_back(card);
|
||
|
|
||
|
moveRecord.push_back(CardMoveRecordItem(this->stackName(),CardMoveRecordItem::RemoveCards,cardVector));
|
||
|
}
|
||
|
|
||
|
return card;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::removeCardsStartingAt(unsigned int index,PlayingCardVector & removedCards)
|
||
|
{
|
||
|
bool rc=false;
|
||
|
|
||
|
if (index<this->m_cardVector.size())
|
||
|
{
|
||
|
rc=true;
|
||
|
|
||
|
unsigned int i;
|
||
|
|
||
|
removedCards.clear();
|
||
|
|
||
|
for(i=index;i<this->m_cardVector.size();i++)
|
||
|
{
|
||
|
removedCards.push_back(this->m_cardVector[i]);
|
||
|
}
|
||
|
|
||
|
while(m_cardVector.size()>index)
|
||
|
{
|
||
|
this->m_cardVector.pop_back();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::removeCardsStartingAt(unsigned int index,
|
||
|
PlayingCardVector & removedCards,
|
||
|
CardMoveRecord & moveRecord,
|
||
|
bool justUpdateRec)
|
||
|
{
|
||
|
bool rc=false;
|
||
|
|
||
|
|
||
|
if (!justUpdateRec)
|
||
|
{
|
||
|
rc=this->removeCardsStartingAt(index,removedCards);
|
||
|
}
|
||
|
else if (index<this->m_cardVector.size())
|
||
|
{
|
||
|
rc=true;
|
||
|
|
||
|
unsigned int i;
|
||
|
|
||
|
removedCards.clear();
|
||
|
|
||
|
for(i=index;i<this->m_cardVector.size();i++)
|
||
|
{
|
||
|
removedCards.push_back(this->m_cardVector[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (rc)
|
||
|
{
|
||
|
// ok now add the move records for removal of the cards from this stack
|
||
|
// it will be a remove and then a flip of the card before if it is face down
|
||
|
moveRecord.push_back(CardMoveRecordItem(this->stackName(),CardMoveRecordItem::RemoveCards,removedCards));
|
||
|
|
||
|
// also if we are in autoflip mode add that to the flip record.
|
||
|
if (0!=index && this->m_autoFaceUp && !this->m_cardVector[index-1].isFaceUp())
|
||
|
{
|
||
|
moveRecord.push_back(CardMoveRecordItem(this->stackName(),index-1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::removeAllCards()
|
||
|
{
|
||
|
// stop any flip animation we have going.
|
||
|
m_flipAni.stopAni();
|
||
|
|
||
|
m_cardVector.clear();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::getMovableCards(PlayingCardVector & cardVector,
|
||
|
unsigned int & index) const
|
||
|
{
|
||
|
bool rc=false;
|
||
|
|
||
|
if (this->m_cardVector.size()>0)
|
||
|
{
|
||
|
int moveIndex=-1;
|
||
|
// ok let's go up the stack and find the last card that we can move
|
||
|
for (int i=this->m_cardVector.size()-1;i>=0;i--)
|
||
|
{
|
||
|
if (this->canMoveCard((unsigned int)i))
|
||
|
{
|
||
|
moveIndex=i;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// did we get an index of a card.
|
||
|
if (moveIndex>=0)
|
||
|
{
|
||
|
rc=true;
|
||
|
|
||
|
|
||
|
for(unsigned int j=(unsigned int)moveIndex;j<this->m_cardVector.size();j++)
|
||
|
{
|
||
|
cardVector.push_back(this->m_cardVector[j]);
|
||
|
}
|
||
|
|
||
|
index=(unsigned int)moveIndex;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::updateStack()
|
||
|
{
|
||
|
QPixmap * pPixmap=NULL;
|
||
|
|
||
|
if (this->isFlipAniRunning())
|
||
|
{
|
||
|
PlayingCardVector cardVector(this->m_cardVector);
|
||
|
|
||
|
// the stack should have at least one card ie the one being flipped
|
||
|
// but make sure.
|
||
|
if (this->m_cardVector.size()>0)
|
||
|
{
|
||
|
cardVector.pop_back();
|
||
|
}
|
||
|
|
||
|
pPixmap=getStackPixmap(cardVector,m_highlighted,m_hintHighlightIndex);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPixmap=getStackPixmap(this->m_cardVector,m_highlighted,m_hintHighlightIndex);
|
||
|
}
|
||
|
|
||
|
if (NULL!=pPixmap)
|
||
|
{
|
||
|
this->setPixmap(*pPixmap);
|
||
|
delete pPixmap;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
QPixmap * CardStack::getStackPixmap(const PlayingCardVector & cardVector,
|
||
|
bool highlighted,
|
||
|
int hintHighlightIndex)
|
||
|
{
|
||
|
bool hl=((hintHighlightIndex>=0 ||
|
||
|
(HintHighlightNoCards==hintHighlightIndex && 0==cardVector.size()))||
|
||
|
highlighted);
|
||
|
|
||
|
QPixmap * pPixmap=NULL;
|
||
|
|
||
|
// if the stack is not empty either show a card or the card back
|
||
|
if (cardVector.size()>0)
|
||
|
{
|
||
|
PlayingCard card(cardVector[cardVector.size()-1]);
|
||
|
|
||
|
|
||
|
if (card.isFaceUp())
|
||
|
{
|
||
|
pPixmap=new QPixmap(CardPixmaps::getInst().getCardPixmap(card,hl));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPixmap=new QPixmap(CardPixmaps::getInst().getCardBackPixmap(hl));
|
||
|
}
|
||
|
}
|
||
|
// if the stack is empty show the empty pixmap.
|
||
|
else
|
||
|
{
|
||
|
pPixmap=new QPixmap(CardPixmaps::getInst().getCardNonePixmap(hl,this->m_showRedealCircle));
|
||
|
}
|
||
|
|
||
|
return pPixmap;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::updateAllStacks()
|
||
|
{
|
||
|
CardStackMap::iterator it;
|
||
|
|
||
|
CardPixmaps::getInst().clearPixmapCache();
|
||
|
|
||
|
for (it=m_cardStackMap.begin();it!=m_cardStackMap.end();it++)
|
||
|
{
|
||
|
it->second->updateStack();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::clearAllStacks()
|
||
|
{
|
||
|
CardStackMap::iterator it;
|
||
|
|
||
|
for (it=m_cardStackMap.begin();it!=m_cardStackMap.end();it++)
|
||
|
{
|
||
|
it->second->removeAllCards();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
CardStack * CardStack::getStackByName(const std::string & stackName)
|
||
|
{
|
||
|
CardStack * pStack=NULL;
|
||
|
|
||
|
CardStackMap::iterator it=m_cardStackMap.find(stackName);
|
||
|
|
||
|
if (m_cardStackMap.end()!=it)
|
||
|
{
|
||
|
pStack=it->second;
|
||
|
}
|
||
|
|
||
|
return pStack;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::isCardStack(QGraphicsItem * pGraphicsItem)
|
||
|
{
|
||
|
CardStack * pCardStack=getStackByName(QString::number((qlonglong)pGraphicsItem).toStdString());
|
||
|
bool rc=false;
|
||
|
|
||
|
if (NULL!=pCardStack)
|
||
|
{
|
||
|
rc=true;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::processCardMoveRecord(ProcessCardMoveRecordType type,
|
||
|
CardMoveRecord moveRecord)
|
||
|
{
|
||
|
while(!moveRecord.empty())
|
||
|
{
|
||
|
CardMoveRecordItem currItem(((CardStack::RedoMove==type)?moveRecord.front():moveRecord.back()));
|
||
|
CardStack * pStack=CardStack::m_cardStackMap[currItem.stackName()];
|
||
|
const PlayingCardVector & cardVector=currItem.cardVector();
|
||
|
unsigned int i;
|
||
|
|
||
|
CardMoveRecordItem::MoveType moveType=currItem.moveType();
|
||
|
|
||
|
// for undo we are actually undoing something that was done
|
||
|
// so we need to AddCards if they were removed or RemoveCards
|
||
|
// if they were added
|
||
|
if (CardStack::UndoMove==type)
|
||
|
{
|
||
|
if (CardMoveRecordItem::RemoveCards==moveType)
|
||
|
{
|
||
|
moveType=CardMoveRecordItem::AddCards;
|
||
|
}
|
||
|
else if (CardMoveRecordItem::AddCards==moveType)
|
||
|
{
|
||
|
moveType=CardMoveRecordItem::RemoveCards;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch(moveType)
|
||
|
{
|
||
|
// remove cards to a stack
|
||
|
case CardMoveRecordItem::RemoveCards:
|
||
|
{
|
||
|
for (i=0;i<cardVector.size();i++)
|
||
|
{
|
||
|
pStack->removeTopCard();
|
||
|
}
|
||
|
pStack->updateStack();
|
||
|
}
|
||
|
break;
|
||
|
// add cards to a stack
|
||
|
case CardMoveRecordItem::AddCards:
|
||
|
{
|
||
|
pStack->addCards(cardVector);
|
||
|
pStack->updateStack();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// for this case we are just going to flip the card over
|
||
|
case CardMoveRecordItem::FlipCard:
|
||
|
{
|
||
|
// in this case we just want to flip the last card
|
||
|
if (pStack->m_cardVector.size()>0)
|
||
|
{
|
||
|
unsigned int flipIndex=0;
|
||
|
bool isValid=false;
|
||
|
if (currItem.flipIndex()<0)
|
||
|
{
|
||
|
flipIndex=pStack->m_cardVector.size()-1;
|
||
|
isValid=true;
|
||
|
}
|
||
|
else if (currItem.flipIndex()<(int)(pStack->m_cardVector.size()))
|
||
|
{
|
||
|
flipIndex=(unsigned int)currItem.flipIndex();
|
||
|
isValid=true;
|
||
|
}
|
||
|
|
||
|
if (isValid)
|
||
|
{
|
||
|
pStack->m_cardVector[flipIndex].setFaceUp(!pStack->m_cardVector[flipIndex].isFaceUp());
|
||
|
pStack->updateStack();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
};
|
||
|
|
||
|
if (CardStack::RedoMove==type)
|
||
|
{
|
||
|
moveRecord.pop_front();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
moveRecord.pop_back();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::showHint(CardStack * pSrc,
|
||
|
unsigned int srcCardIndex,
|
||
|
CardStack * pDst)
|
||
|
{
|
||
|
if (NULL!=pSrc && NULL!=pDst)
|
||
|
{
|
||
|
pSrc->slotHintHighlight(srcCardIndex);
|
||
|
pDst->slotDelayedHintHighlight();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::slotDelayedHintHighlight()
|
||
|
{
|
||
|
QTimer::singleShot(1000,this,SLOT(slotHintHighlight()));
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::slotHintHighlight(int index)
|
||
|
{
|
||
|
// if the index is less than 0 then the last card should be highlighted
|
||
|
// or the card pad if no cards are in the stack.
|
||
|
if (index<0)
|
||
|
{
|
||
|
this->m_hintHighlightIndex=HintHighlightNoCards;
|
||
|
|
||
|
if (this->m_cardVector.size()>0)
|
||
|
{
|
||
|
this->m_hintHighlightIndex=this->m_cardVector.size()-1;
|
||
|
}
|
||
|
}
|
||
|
else if (index<(int)this->m_cardVector.size())
|
||
|
{
|
||
|
this->m_hintHighlightIndex=index;
|
||
|
}
|
||
|
|
||
|
this->updateStack();
|
||
|
|
||
|
QTimer::singleShot(1000,this,SLOT(slotHintHighlightComplete()));
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::slotHintHighlightComplete()
|
||
|
{
|
||
|
this->m_hintHighlightIndex=-1;
|
||
|
this->updateStack();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::slotFlipComplete(CardStack * pSrc)
|
||
|
{
|
||
|
Q_UNUSED(pSrc);
|
||
|
|
||
|
this->updateStack();
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::slotDragCardsMoved(const CardMoveRecord & initRecord)
|
||
|
{
|
||
|
CardMoveRecord moveRecord(initRecord);
|
||
|
|
||
|
// if we are in autotop card up flip the top card. and emit a signal
|
||
|
// that we moved the cards.
|
||
|
if (!this->isEmpty() && this->isAutoTopCardUp())
|
||
|
{
|
||
|
int lastIndex=this->m_cardVector.size()-1;
|
||
|
|
||
|
if (!this->m_cardVector[lastIndex].isFaceUp())
|
||
|
{
|
||
|
this->flipCard(lastIndex,moveRecord);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
emit cardsMovedByDragDrop(moveRecord);
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// for this case when all cards are directly stacked on top of each other
|
||
|
// if there are cards in the stack we will always just return the last card.
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool CardStack::getCardIndex(const QPointF & pos,unsigned int & index)
|
||
|
{
|
||
|
Q_UNUSED(pos);
|
||
|
|
||
|
bool rc=false;
|
||
|
|
||
|
if (this->m_cardVector.size()>0)
|
||
|
{
|
||
|
index=this->m_cardVector.size()-1;
|
||
|
rc=true;
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||
|
{
|
||
|
if (m_lockUserInteraction || this->isFlipAniRunning() || CardAnimationLock::getInst().isDemoRunning())
|
||
|
{
|
||
|
QGraphicsPixmapItem::mousePressEvent(event);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
this->m_mouseMoved=false;
|
||
|
this->m_dragStartPos=event->pos();
|
||
|
|
||
|
}
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||
|
{
|
||
|
if (m_lockUserInteraction || this->isFlipAniRunning() || CardAnimationLock::getInst().isDemoRunning())
|
||
|
{
|
||
|
QGraphicsPixmapItem::mouseReleaseEvent(event);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!m_mouseMoved)
|
||
|
{
|
||
|
|
||
|
unsigned int index;
|
||
|
|
||
|
if (this->isEmpty())
|
||
|
{
|
||
|
emit padClicked(this);
|
||
|
}
|
||
|
else if (this->getCardIndex(event->pos(),index))
|
||
|
{
|
||
|
if (this->canMoveCard(index))
|
||
|
{
|
||
|
PlayingCardVector moveCards;
|
||
|
CardMoveRecord moveRecord;
|
||
|
|
||
|
// create a move record and a vector containing the cards
|
||
|
// but don't remove them.
|
||
|
if (CardStack::removeCardsStartingAt(index,moveCards,
|
||
|
moveRecord,true))
|
||
|
{
|
||
|
emit movableCardsClicked(this,moveCards,moveRecord);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
emit cardClicked(this,index);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (m_dragStack.cardDragStarted())
|
||
|
{
|
||
|
m_dragStack.mouseReleaseEvent(event);
|
||
|
}
|
||
|
}
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||
|
{
|
||
|
if (m_lockUserInteraction || this->isFlipAniRunning() || CardAnimationLock::getInst().isDemoRunning())
|
||
|
{
|
||
|
QGraphicsPixmapItem::mouseMoveEvent(event);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
QPointF posDiff=(event->pos()-this->m_dragStartPos);
|
||
|
if ( (qAbs(posDiff.x()) + qAbs((int)posDiff.y()))< QApplication::startDragDistance())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
m_mouseMoved=true;
|
||
|
|
||
|
if (!m_dragStack.cardDragStarted())
|
||
|
{
|
||
|
unsigned int index=0;
|
||
|
bool haveCardIndex=this->getCardIndex(event->pos(),index);
|
||
|
|
||
|
if (haveCardIndex && this->canMoveCard(index))
|
||
|
{
|
||
|
unsigned int i;
|
||
|
PlayingCardVector dragCardVector;
|
||
|
|
||
|
for (i=index;i<this->m_cardVector.size();i++)
|
||
|
{
|
||
|
dragCardVector.push_back(this->m_cardVector[i]);
|
||
|
}
|
||
|
|
||
|
m_dragStack.startCardMove(event->scenePos(),index,dragCardVector);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_dragStack.mouseMoveEvent(event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void CardStack::hoverMoveEvent(QGraphicsSceneHoverEvent * event)
|
||
|
{
|
||
|
unsigned int index;
|
||
|
|
||
|
if (this->getCardIndex(event->pos(),index) &&
|
||
|
this->canMoveCard(index))
|
||
|
{
|
||
|
this->setCursor(Qt::OpenHandCursor);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
this->setCursor(Qt::PointingHandCursor);
|
||
|
}
|
||
|
|
||
|
QGraphicsPixmapItem::hoverMoveEvent(event);
|
||
|
}
|