From 082d5732b08c791b9f8696614efd7db097582014 Mon Sep 17 00:00:00 2001 From: defnax Date: Wed, 17 Feb 2010 01:14:52 +0000 Subject: [PATCH] added game plugin solocards git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@2346 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- plugins/qsolocards_plugin/._.DS_Store | Bin 0 -> 82 bytes plugins/qsolocards_plugin/._QSoloCards.icns | Bin 0 -> 218 bytes plugins/qsolocards_plugin/About.cpp | 96 + plugins/qsolocards_plugin/About.h | 34 + .../qsolocards_plugin/CardAnimationLock.cpp | 66 + plugins/qsolocards_plugin/CardAnimationLock.h | 57 + plugins/qsolocards_plugin/CardDeck.cpp | 123 + plugins/qsolocards_plugin/CardDeck.h | 56 + plugins/qsolocards_plugin/CardMoveRecord.cpp | 68 + plugins/qsolocards_plugin/CardMoveRecord.h | 62 + plugins/qsolocards_plugin/CardPixmaps.cpp | 193 + plugins/qsolocards_plugin/CardPixmaps.h | 93 + plugins/qsolocards_plugin/CardStack.cpp | 857 ++ plugins/qsolocards_plugin/CardStack.h | 238 + plugins/qsolocards_plugin/DealAnimation.cpp | 480 + plugins/qsolocards_plugin/DealAnimation.h | 149 + plugins/qsolocards_plugin/DragCardStack.cpp | 209 + plugins/qsolocards_plugin/DragCardStack.h | 58 + plugins/qsolocards_plugin/FlipAnimation.cpp | 193 + plugins/qsolocards_plugin/FlipAnimation.h | 75 + plugins/qsolocards_plugin/FreeCellBoard.cpp | 693 ++ plugins/qsolocards_plugin/FreeCellBoard.h | 93 + plugins/qsolocards_plugin/FreeCellDeck.cpp | 50 + plugins/qsolocards_plugin/FreeCellDeck.h | 35 + plugins/qsolocards_plugin/FreeCellFree.cpp | 59 + plugins/qsolocards_plugin/FreeCellFree.h | 36 + plugins/qsolocards_plugin/FreeCellHome.cpp | 57 + plugins/qsolocards_plugin/FreeCellHome.h | 37 + plugins/qsolocards_plugin/FreeCellStack.cpp | 95 + plugins/qsolocards_plugin/FreeCellStack.h | 45 + plugins/qsolocards_plugin/GameBoard.cpp | 434 + plugins/qsolocards_plugin/GameBoard.h | 213 + plugins/qsolocards_plugin/GameMgr.cpp | 107 + plugins/qsolocards_plugin/GameMgr.h | 62 + plugins/qsolocards_plugin/Help.cpp | 76 + plugins/qsolocards_plugin/Help.h | 40 + plugins/qsolocards_plugin/KlondikeBoard.cpp | 770 ++ plugins/qsolocards_plugin/KlondikeBoard.h | 115 + .../qsolocards_plugin/KlondikeFlipStack.cpp | 259 + plugins/qsolocards_plugin/KlondikeFlipStack.h | 62 + .../qsolocards_plugin/KlondikeHomeStack.cpp | 75 + plugins/qsolocards_plugin/KlondikeHomeStack.h | 40 + plugins/qsolocards_plugin/KlondikeStack.cpp | 91 + plugins/qsolocards_plugin/KlondikeStack.h | 44 + plugins/qsolocards_plugin/Makefile | 142 + plugins/qsolocards_plugin/Makefile.Debug | 991 ++ plugins/qsolocards_plugin/Makefile.Release | 991 ++ plugins/qsolocards_plugin/PlayingCard.cpp | 174 + plugins/qsolocards_plugin/PlayingCard.h | 100 + plugins/qsolocards_plugin/QSoloCards.icns | Bin 0 -> 129301 bytes plugins/qsolocards_plugin/QSoloCards.qrc | 15 + .../qsolocards_plugin/QSoloCardsPlugin.cpp | 53 + plugins/qsolocards_plugin/QSoloCardsPlugin.h | 48 + .../qsolocards_plugin/Spider3DeckBoard.cpp | 181 + plugins/qsolocards_plugin/Spider3DeckBoard.h | 43 + plugins/qsolocards_plugin/SpiderBoard.cpp | 754 ++ plugins/qsolocards_plugin/SpiderBoard.h | 101 + plugins/qsolocards_plugin/SpiderHomeStack.cpp | 70 + plugins/qsolocards_plugin/SpiderHomeStack.h | 46 + plugins/qsolocards_plugin/SpiderStack.cpp | 175 + plugins/qsolocards_plugin/SpiderStack.h | 67 + plugins/qsolocards_plugin/SpideretteBoard.cpp | 182 + plugins/qsolocards_plugin/SpideretteBoard.h | 43 + .../qsolocards_plugin/StackToStackAniMove.cpp | 290 + .../qsolocards_plugin/StackToStackAniMove.h | 102 + .../qsolocards_plugin/StackToStackFlipAni.cpp | 334 + .../qsolocards_plugin/StackToStackFlipAni.h | 80 + plugins/qsolocards_plugin/VCardStack.cpp | 333 + plugins/qsolocards_plugin/VCardStack.h | 88 + plugins/qsolocards_plugin/YukonBoard.cpp | 488 + plugins/qsolocards_plugin/YukonBoard.h | 80 + plugins/qsolocards_plugin/help/._gpl3.html | Bin 0 -> 197 bytes .../qsolocards_plugin/help/FreeCellHelp.html | 62 + .../qsolocards_plugin/help/KlondikeHelp.html | 81 + .../help/Spider3DeckHelp.html | 70 + .../qsolocards_plugin/help/SpiderHelp.html | 78 + .../help/SpideretteHelp.html | 71 + plugins/qsolocards_plugin/help/YukonHelp.html | 67 + plugins/qsolocards_plugin/help/gpl3.html | 692 ++ .../qsolocards_plugin/images/anglo_bitmap.svg | 10159 ++++++++++++++++ .../qsolocards_plugin/images/greenfelt.png | Bin 0 -> 1019 bytes .../qsolocards_plugin/images/sol128x128.png | Bin 0 -> 7325 bytes plugins/qsolocards_plugin/images/sol16x16.png | Bin 0 -> 719 bytes .../qsolocards_plugin/images/sol256x256.png | Bin 0 -> 14179 bytes plugins/qsolocards_plugin/images/sol32x32.png | Bin 0 -> 2431 bytes .../qsolocards_plugin/images/sol512x512.png | Bin 0 -> 26991 bytes plugins/qsolocards_plugin/main.cpp | 28 + plugins/qsolocards_plugin/mainwindow.cpp | 653 + plugins/qsolocards_plugin/mainwindow.h | 117 + .../object_script.qsolocards_plugin.Debug | 64 + .../object_script.qsolocards_plugin.Release | 64 + .../qsolocards_plugin/qsolocards_plugin.pro | 106 + 92 files changed, 24978 insertions(+) create mode 100644 plugins/qsolocards_plugin/._.DS_Store create mode 100644 plugins/qsolocards_plugin/._QSoloCards.icns create mode 100644 plugins/qsolocards_plugin/About.cpp create mode 100644 plugins/qsolocards_plugin/About.h create mode 100644 plugins/qsolocards_plugin/CardAnimationLock.cpp create mode 100644 plugins/qsolocards_plugin/CardAnimationLock.h create mode 100644 plugins/qsolocards_plugin/CardDeck.cpp create mode 100644 plugins/qsolocards_plugin/CardDeck.h create mode 100644 plugins/qsolocards_plugin/CardMoveRecord.cpp create mode 100644 plugins/qsolocards_plugin/CardMoveRecord.h create mode 100644 plugins/qsolocards_plugin/CardPixmaps.cpp create mode 100644 plugins/qsolocards_plugin/CardPixmaps.h create mode 100644 plugins/qsolocards_plugin/CardStack.cpp create mode 100644 plugins/qsolocards_plugin/CardStack.h create mode 100644 plugins/qsolocards_plugin/DealAnimation.cpp create mode 100644 plugins/qsolocards_plugin/DealAnimation.h create mode 100644 plugins/qsolocards_plugin/DragCardStack.cpp create mode 100644 plugins/qsolocards_plugin/DragCardStack.h create mode 100644 plugins/qsolocards_plugin/FlipAnimation.cpp create mode 100644 plugins/qsolocards_plugin/FlipAnimation.h create mode 100644 plugins/qsolocards_plugin/FreeCellBoard.cpp create mode 100644 plugins/qsolocards_plugin/FreeCellBoard.h create mode 100644 plugins/qsolocards_plugin/FreeCellDeck.cpp create mode 100644 plugins/qsolocards_plugin/FreeCellDeck.h create mode 100644 plugins/qsolocards_plugin/FreeCellFree.cpp create mode 100644 plugins/qsolocards_plugin/FreeCellFree.h create mode 100644 plugins/qsolocards_plugin/FreeCellHome.cpp create mode 100644 plugins/qsolocards_plugin/FreeCellHome.h create mode 100644 plugins/qsolocards_plugin/FreeCellStack.cpp create mode 100644 plugins/qsolocards_plugin/FreeCellStack.h create mode 100644 plugins/qsolocards_plugin/GameBoard.cpp create mode 100644 plugins/qsolocards_plugin/GameBoard.h create mode 100644 plugins/qsolocards_plugin/GameMgr.cpp create mode 100644 plugins/qsolocards_plugin/GameMgr.h create mode 100644 plugins/qsolocards_plugin/Help.cpp create mode 100644 plugins/qsolocards_plugin/Help.h create mode 100644 plugins/qsolocards_plugin/KlondikeBoard.cpp create mode 100644 plugins/qsolocards_plugin/KlondikeBoard.h create mode 100644 plugins/qsolocards_plugin/KlondikeFlipStack.cpp create mode 100644 plugins/qsolocards_plugin/KlondikeFlipStack.h create mode 100644 plugins/qsolocards_plugin/KlondikeHomeStack.cpp create mode 100644 plugins/qsolocards_plugin/KlondikeHomeStack.h create mode 100644 plugins/qsolocards_plugin/KlondikeStack.cpp create mode 100644 plugins/qsolocards_plugin/KlondikeStack.h create mode 100644 plugins/qsolocards_plugin/Makefile create mode 100644 plugins/qsolocards_plugin/Makefile.Debug create mode 100644 plugins/qsolocards_plugin/Makefile.Release create mode 100644 plugins/qsolocards_plugin/PlayingCard.cpp create mode 100644 plugins/qsolocards_plugin/PlayingCard.h create mode 100644 plugins/qsolocards_plugin/QSoloCards.icns create mode 100644 plugins/qsolocards_plugin/QSoloCards.qrc create mode 100644 plugins/qsolocards_plugin/QSoloCardsPlugin.cpp create mode 100644 plugins/qsolocards_plugin/QSoloCardsPlugin.h create mode 100644 plugins/qsolocards_plugin/Spider3DeckBoard.cpp create mode 100644 plugins/qsolocards_plugin/Spider3DeckBoard.h create mode 100644 plugins/qsolocards_plugin/SpiderBoard.cpp create mode 100644 plugins/qsolocards_plugin/SpiderBoard.h create mode 100644 plugins/qsolocards_plugin/SpiderHomeStack.cpp create mode 100644 plugins/qsolocards_plugin/SpiderHomeStack.h create mode 100644 plugins/qsolocards_plugin/SpiderStack.cpp create mode 100644 plugins/qsolocards_plugin/SpiderStack.h create mode 100644 plugins/qsolocards_plugin/SpideretteBoard.cpp create mode 100644 plugins/qsolocards_plugin/SpideretteBoard.h create mode 100644 plugins/qsolocards_plugin/StackToStackAniMove.cpp create mode 100644 plugins/qsolocards_plugin/StackToStackAniMove.h create mode 100644 plugins/qsolocards_plugin/StackToStackFlipAni.cpp create mode 100644 plugins/qsolocards_plugin/StackToStackFlipAni.h create mode 100644 plugins/qsolocards_plugin/VCardStack.cpp create mode 100644 plugins/qsolocards_plugin/VCardStack.h create mode 100644 plugins/qsolocards_plugin/YukonBoard.cpp create mode 100644 plugins/qsolocards_plugin/YukonBoard.h create mode 100644 plugins/qsolocards_plugin/help/._gpl3.html create mode 100644 plugins/qsolocards_plugin/help/FreeCellHelp.html create mode 100644 plugins/qsolocards_plugin/help/KlondikeHelp.html create mode 100644 plugins/qsolocards_plugin/help/Spider3DeckHelp.html create mode 100644 plugins/qsolocards_plugin/help/SpiderHelp.html create mode 100644 plugins/qsolocards_plugin/help/SpideretteHelp.html create mode 100644 plugins/qsolocards_plugin/help/YukonHelp.html create mode 100644 plugins/qsolocards_plugin/help/gpl3.html create mode 100644 plugins/qsolocards_plugin/images/anglo_bitmap.svg create mode 100644 plugins/qsolocards_plugin/images/greenfelt.png create mode 100644 plugins/qsolocards_plugin/images/sol128x128.png create mode 100644 plugins/qsolocards_plugin/images/sol16x16.png create mode 100644 plugins/qsolocards_plugin/images/sol256x256.png create mode 100644 plugins/qsolocards_plugin/images/sol32x32.png create mode 100644 plugins/qsolocards_plugin/images/sol512x512.png create mode 100644 plugins/qsolocards_plugin/main.cpp create mode 100644 plugins/qsolocards_plugin/mainwindow.cpp create mode 100644 plugins/qsolocards_plugin/mainwindow.h create mode 100644 plugins/qsolocards_plugin/object_script.qsolocards_plugin.Debug create mode 100644 plugins/qsolocards_plugin/object_script.qsolocards_plugin.Release create mode 100644 plugins/qsolocards_plugin/qsolocards_plugin.pro diff --git a/plugins/qsolocards_plugin/._.DS_Store b/plugins/qsolocards_plugin/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..460d887a2e21de5e7ccf222b0fdc4fbe43f67e75 GIT binary patch literal 82 ucmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u>uf-_(4Dn2M%x+Dgyuy>I7i` literal 0 HcmV?d00001 diff --git a/plugins/qsolocards_plugin/._QSoloCards.icns b/plugins/qsolocards_plugin/._QSoloCards.icns new file mode 100644 index 0000000000000000000000000000000000000000..f98f3396f72d957e33fce531ba0f59c038a2405b GIT binary patch literal 218 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@d_XY@oxb!7-S~rIWq{rc<8iaNJtQa z4i_I#9HaxJ8)OPH0GS372dd%m3l1*HFG>xmEJy__*#;z45aOYso-Pawp2_)n#cr87 rsbIBEW)^NHZbqiMjuwU{x+Vq&Cc2Jhu7. +*/ + +#include "About.h" +#include +#include +#include +#include +#include +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +About::About(QWidget * pParent) + :QDialog(pParent) +{ + this->setWindowTitle(tr("About QSoloCards").trimmed()); + + // Layout the dialog a Vbox that will be the top level. And contain the HBox that has the icon and text + // and then the dialogButtonBox for the close button. + QVBoxLayout * pLayout=new QVBoxLayout; + + QHBoxLayout * pMainLayout=new QHBoxLayout; + + QLabel * pIconLabel=new QLabel(this); + + pIconLabel->setPixmap(QPixmap(":/images/sol128x128.png")); + + pMainLayout->addWidget(pIconLabel,0,Qt::AlignTop|Qt::AlignLeft); + + QLabel * pWordsLabel=new QLabel(this); + + pWordsLabel->setWordWrap(true); + + // set the text for the about box. The .pro file is setup to pass + // VER_MAJ, VER_MIN, VER_PAT as a param when the file is compiled + // So, version info is contained only in the .pro file and can be + // easily changed in one place. + pWordsLabel->setText(tr("

QSoloCards %1.%2.%3

" + "

A collection of Solitaire Games written in Qt.

" + "

" + "

" + "

Copyright 2009 Steve Moore

" + "

" + "

License: GPLv3

" + "

" + "

" + "

Graphics: Playing cards are a modified version of the anglo_bitmap cards from Gnome-Games' AisleRiot.

" + ).arg(QString::number(VER_MAJ)).arg(QString::number(VER_MIN)).arg(QString::number(VER_PAT))); + + connect(pWordsLabel,SIGNAL(linkActivated(QString)), + this,SLOT(slotLinkActivated(QString))); + + pMainLayout->addWidget(pWordsLabel,0,Qt::AlignTop|Qt::AlignHCenter); + + + pLayout->addLayout(pMainLayout,20); + + QDialogButtonBox * pButtonBox=new QDialogButtonBox(this); + + pButtonBox->addButton(QDialogButtonBox::Close); + + pLayout->addWidget(pButtonBox,1); + + connect(pButtonBox, SIGNAL(rejected()), this, SLOT(reject())); + + // don't allow resizing the window. + pLayout->setSizeConstraint(QLayout::SetFixedSize); + + this->setLayout(pLayout); +} +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +About::~About() +{ +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +void About::slotLinkActivated(const QString & link) +{ + emit showLink(link); +} diff --git a/plugins/qsolocards_plugin/About.h b/plugins/qsolocards_plugin/About.h new file mode 100644 index 000000000..39fce3eb1 --- /dev/null +++ b/plugins/qsolocards_plugin/About.h @@ -0,0 +1,34 @@ +/* + 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 . +*/ + +#ifndef ABOUT_H +#define ABOUT_H +#include + +class About: public QDialog +{ + Q_OBJECT +public: + About(QWidget * pParent); + ~About(); +public slots: + void slotLinkActivated(const QString & link); +signals: + void showLink(const QString & link); +}; +#endif // ABOUT_H diff --git a/plugins/qsolocards_plugin/CardAnimationLock.cpp b/plugins/qsolocards_plugin/CardAnimationLock.cpp new file mode 100644 index 000000000..80ecd7949 --- /dev/null +++ b/plugins/qsolocards_plugin/CardAnimationLock.cpp @@ -0,0 +1,66 @@ +/* + 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 "CardAnimationLock.h" +#include "CardStack.h" + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +CardAnimationLock::~CardAnimationLock() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +CardAnimationLock & CardAnimationLock::getInst() +{ + static CardAnimationLock aniLock; + + return aniLock; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void CardAnimationLock::lock() +{ + if (m_aniEnabled && !m_demoStarted) + { + CardStack::lockUserInteration(); + emit animationStarted(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void CardAnimationLock::unlock() +{ + if (m_aniEnabled && !m_demoStarted) + { + CardStack::lockUserInteration(false); + emit animationComplete(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +CardAnimationLock::CardAnimationLock() + :m_aniEnabled(true), + m_demoStarted(false) +{ +} + diff --git a/plugins/qsolocards_plugin/CardAnimationLock.h b/plugins/qsolocards_plugin/CardAnimationLock.h new file mode 100644 index 000000000..30ef47338 --- /dev/null +++ b/plugins/qsolocards_plugin/CardAnimationLock.h @@ -0,0 +1,57 @@ +/* + 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 . +*/ + +#ifndef CARDANIMATIONLOCK_H +#define CARDANIMATIONLOCK_H + +#include + +class CardAnimationLock:public QObject +{ + Q_OBJECT +public: + virtual ~CardAnimationLock(); + + static CardAnimationLock & getInst(); + + inline void setDemoMode(bool isDemo){m_demoStarted=isDemo;} + inline bool isDemoRunning()const{return m_demoStarted;} + + inline bool animationsEnabled()const{return m_aniEnabled;} + inline void enableAnimations(bool enabled){m_aniEnabled=enabled;} + + // The lock just sends a single not to allow user interaction, + // and calls the static lockUserInteraction function of CardStack. + // The signal is used by mainwindow to know when not to allow menu + // items to be clicked. + void lock(); + void unlock(); + +signals: + void animationStarted(); + void animationComplete(); + +protected: + CardAnimationLock(); + +private: + bool m_aniEnabled; + bool m_demoStarted; +}; + +#endif diff --git a/plugins/qsolocards_plugin/CardDeck.cpp b/plugins/qsolocards_plugin/CardDeck.cpp new file mode 100644 index 000000000..7281de1cf --- /dev/null +++ b/plugins/qsolocards_plugin/CardDeck.cpp @@ -0,0 +1,123 @@ +/* + 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 "CardDeck.h" + +#include + + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +CardDeck::CardDeck(unsigned short numDecks) + :m_deckOfCards(), + m_shuffledCardVector(), + m_numDecks(numDecks) +{ + // This creates the default deck of cards that will be used + for (unsigned short i=0;ishuffle(); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////// +CardDeck::CardDeck(const PlayingCardVector & cardsForDeck, unsigned short numDecks) + :m_deckOfCards(), + m_shuffledCardVector(), + m_numDecks(numDecks) +{ + for (unsigned short i=0;im_deckOfCards.push_back(cardsForDeck[j]); + } + } + + this->shuffle(); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////// +CardDeck::~CardDeck() +{ +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Create a shuffled deck by generating a vector of playing cards. And then randomly generating an index +// into that vector. And then pull the card out of that vector and adding it to the end of another vector. +// +////////////////////////////////////////////////////////////////////////////////////////////////////////// +void CardDeck::shuffle() +{ + PlayingCardVector cardVector; + + cardVector=this->m_deckOfCards; + + if (this->m_shuffledCardVector.size()>0) + { + this->m_shuffledCardVector.clear(); + } + + qsrand(QDateTime::currentDateTime().toTime_t()); + + + while(cardVector.size()>0) + { + unsigned int index=qrand()%cardVector.size(); + + // make sure our random number is not off the end of the vector + if (index>=cardVector.size()) + { + index=cardVector.size()-1; + } + + this->m_shuffledCardVector.push_back(cardVector[index]); + cardVector.erase(cardVector.begin()+index); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////// +PlayingCard CardDeck::next() +{ + // create an invalid card. + PlayingCard playingCard(PlayingCard::MaxSuit,PlayingCard::MaxCardIndex); + + // if we have any cards left get the first one and return it. + // then remove that card from the vector. + if (this->m_shuffledCardVector.size()>0) + { + playingCard=this->m_shuffledCardVector[0]; + this->m_shuffledCardVector.erase(this->m_shuffledCardVector.begin()); + } + + return playingCard; +} diff --git a/plugins/qsolocards_plugin/CardDeck.h b/plugins/qsolocards_plugin/CardDeck.h new file mode 100644 index 000000000..47de6992d --- /dev/null +++ b/plugins/qsolocards_plugin/CardDeck.h @@ -0,0 +1,56 @@ +/* + 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 . +*/ + +#ifndef CARDDECK_H +#define CARDDECK_H + +#include + +#include "PlayingCard.h" + +typedef std::vector PlayingCardVector; + +class CardDeck +{ + public: + // by default we just want to include one complete deck. + CardDeck(unsigned short numDecks=1); + + // this constructor adds a little flexibility. So, that a deck of only certain cards + // can be built easily. + CardDeck(const PlayingCardVector & cardsForDeck, unsigned short numDecks=1); + ~CardDeck(); + + // will clear any remaining cards in the shuffled deck and create a new shuffled deck + // this function is automatically called by the constructor. + void shuffle(); + + inline bool isEmpty() const {return m_shuffledCardVector.empty();} + + // get the next card in the shuffled deck. + PlayingCard next(); + + private: + PlayingCardVector m_deckOfCards; + PlayingCardVector m_shuffledCardVector; + + unsigned short m_numDecks; +}; + + +#endif // CARDDECK_H diff --git a/plugins/qsolocards_plugin/CardMoveRecord.cpp b/plugins/qsolocards_plugin/CardMoveRecord.cpp new file mode 100644 index 000000000..0fc433bc3 --- /dev/null +++ b/plugins/qsolocards_plugin/CardMoveRecord.cpp @@ -0,0 +1,68 @@ +/* + 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 "CardMoveRecord.h" + + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +CardMoveRecordItem::CardMoveRecordItem(const std::string & stackName, + int flipIndex) + :m_moveType(CardMoveRecordItem::FlipCard), + m_cardVector(), + m_flipIndex(flipIndex), + m_stackName(stackName) +{ +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +CardMoveRecordItem::CardMoveRecordItem(const std::string & stackName, + MoveType m_type, + const PlayingCardVector & cardVector) + :m_moveType(m_type), + m_cardVector(cardVector), + m_flipIndex(-1), + m_stackName(stackName) +{ +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +CardMoveRecordItem::CardMoveRecordItem(const CardMoveRecordItem & rh) +{ + *this=rh; +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +CardMoveRecordItem::~CardMoveRecordItem() +{ +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +CardMoveRecordItem & CardMoveRecordItem::operator=(const CardMoveRecordItem & rh) +{ + m_moveType=rh.moveType(); + m_cardVector=rh.cardVector(); + m_flipIndex=rh.flipIndex(); + m_stackName=rh.stackName(); + + return *this; +} diff --git a/plugins/qsolocards_plugin/CardMoveRecord.h b/plugins/qsolocards_plugin/CardMoveRecord.h new file mode 100644 index 000000000..2e15f372b --- /dev/null +++ b/plugins/qsolocards_plugin/CardMoveRecord.h @@ -0,0 +1,62 @@ +/* + 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 . +*/ + +#ifndef CARDMOVERECORD_H +#define CARDMOVERECORD_H + +#include "CardDeck.h" +#include +#include + +class CardMoveRecordItem +{ + public: + enum MoveType + { + AddCards=0, + RemoveCards=1, + FlipCard=2 + }; + + CardMoveRecordItem(const std::string & stackName, + int flipIndex=-1); // Case where we are just flipping a card + CardMoveRecordItem(const std::string & stackName, + MoveType m_type, + const PlayingCardVector & cardVector); // case where we are adding or removing cards + CardMoveRecordItem(const CardMoveRecordItem & rh); + + virtual ~CardMoveRecordItem(); + + CardMoveRecordItem & operator=(const CardMoveRecordItem & rh); + + inline MoveType moveType() const {return m_moveType;} + inline const PlayingCardVector & cardVector() const {return m_cardVector;} + inline int flipIndex() const {return m_flipIndex;} + inline const std::string & stackName() const{return m_stackName;} + + private: + MoveType m_moveType; + PlayingCardVector m_cardVector; + int m_flipIndex; + std::string m_stackName; +}; + +typedef std::list CardMoveRecord; + + +#endif // CARDMOVERECORD_H diff --git a/plugins/qsolocards_plugin/CardPixmaps.cpp b/plugins/qsolocards_plugin/CardPixmaps.cpp new file mode 100644 index 000000000..95090de82 --- /dev/null +++ b/plugins/qsolocards_plugin/CardPixmaps.cpp @@ -0,0 +1,193 @@ +/* + 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 "CardPixmaps.h" +#include +#include + +const qreal CardPixmaps::CardWidthToHeight=.66; +const QString CardPixmaps::EmptyStackName("empty"); +const QString CardPixmaps::EmptyStackRedealName("emtpy_redeal"); +const QString CardPixmaps::CardBackName("back"); +const QString CardPixmaps::TransparentNoCard("transparent"); + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +CardPixmaps::~CardPixmaps() +{ + delete m_pSvgRendCard; +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +CardPixmaps & CardPixmaps::getInst() +{ + static CardPixmaps cardPixmaps; + + return cardPixmaps; +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +void CardPixmaps::setCardWidth(unsigned int width) +{ + m_cardSize.setWidth(width); + m_cardSize.setHeight(width/CardWidthToHeight); +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +void CardPixmaps::setCardHeight(unsigned int height) +{ + m_cardSize.setHeight(height); + m_cardSize.setWidth(height*CardWidthToHeight); +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +CardPixmaps::CardPixmaps() + :m_pSvgRendCard(new QSvgRenderer(QString(":/images/anglo_bitmap.svg"))), + m_pixmapMap(), + m_cardSize(0,0) +{ +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +const QPixmap & CardPixmaps::getCardPixmap(const QString & imageName,bool highlighted) +{ + QString fullImageName(""); + + if (highlighted) + { + fullImageName+="hl_"; + } + fullImageName+=imageName; + + CardPixmapMap::iterator it=m_pixmapMap.find(fullImageName.toStdString()); + + if (m_pixmapMap.end()!=it) + { + return it->second; + } + + QPainter painter; + + QPixmap dummyPix(m_cardSize); + + dummyPix.fill(Qt::transparent); + + m_pixmapMap[fullImageName.toStdString()]=dummyPix; + painter.begin(&m_pixmapMap[fullImageName.toStdString()]); + if (imageName==EmptyStackName || imageName==EmptyStackRedealName) + { + drawEmptyStack(painter,highlighted,imageName==EmptyStackRedealName); + } + else if (imageName==TransparentNoCard) + { + } + else if (highlighted) + { + drawHighlightedCard(painter,imageName); + } + else + { + QRect pixRect(QPoint(0,0),m_cardSize); + + m_pSvgRendCard->render(&painter,imageName,pixRect); + } + + painter.end(); + + return m_pixmapMap[fullImageName.toStdString()]; +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +void CardPixmaps::drawEmptyStack(QPainter & painter,bool highlighted,bool redealCircle) +{ + QPoint topLeft(0,0); + QPen pen; + + + pen.setColor(QColor("#006520")); + + pen.setWidth(3); + painter.setPen(pen); + + + QRect rect(topLeft,m_cardSize); + + painter.setRenderHint(QPainter::Antialiasing,true); + + + if (redealCircle) + { + QPoint ellipseCenter(rect.left()+rect.width()/2, + rect.top()+rect.height()/2); + + pen.setWidth(10); + painter.setBrush(QColor("#006520")); + painter.drawEllipse(ellipseCenter, + rect.width()/3,rect.width()/3); + } + + painter.setBrush(Qt::transparent); + + // draw the highlight rect if necessary. + if (highlighted) + { + painter.setBrush(QBrush(QColor("#806000"),Qt::Dense4Pattern)); + } + + painter.drawRoundedRect(rect.adjusted(1,1,-1,-1),6.0,6.0); +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +void CardPixmaps::drawHighlightedCard(QPainter & painter,const QString & imageName) +{ + // for the highlighted case we are going to manipulate the original + // image and change the background of the card to a yellowish color + // to highlight it. + + // A QImage is necessary in Format_ARGB32_Premultiplied or Format_ARGB32 + // is required to use the composite modes. So, draw the pixmap on the + // QImage. And then render the result in our pixmap. + + QRect pixRect(QPoint(0,0),m_cardSize); + + QImage image(m_cardSize,QImage::Format_ARGB32_Premultiplied); + + image.fill(Qt::transparent); + + QPainter imagePainter; + + imagePainter.begin(&image); + + imagePainter.setPen(Qt::NoPen); + + imagePainter.setBrush(QColor("#ffff90")); + imagePainter.drawPixmap(QPoint(0,0),getCardPixmap(imageName)); + + imagePainter.setCompositionMode(QPainter::CompositionMode_Darken); + imagePainter.drawRoundedRect(pixRect.adjusted(0,0,-1,-1),4.0,4.0); + + imagePainter.end(); + painter.drawImage(QPoint(0,0),image); +} diff --git a/plugins/qsolocards_plugin/CardPixmaps.h b/plugins/qsolocards_plugin/CardPixmaps.h new file mode 100644 index 000000000..47bce4f67 --- /dev/null +++ b/plugins/qsolocards_plugin/CardPixmaps.h @@ -0,0 +1,93 @@ +/* + 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 . +*/ + +#ifndef CARDPIXMAPS_H +#define CARDPIXMAPS_H + +#include "PlayingCard.h" +#include +#include +#include +#include + +typedef std::map CardPixmapMap; + + +class CardPixmaps +{ +public: + static const qreal CardWidthToHeight; // This is the percentage of the height to the width + // that is used to render a card. + + static const QString EmptyStackName; + static const QString EmptyStackRedealName; + static const QString CardBackName; + static const QString TransparentNoCard; + + ~CardPixmaps(); + + static CardPixmaps & getInst(); + + + void setCardWidth(unsigned int width); + void setCardHeight(unsigned int height); + + inline const QSize & getCardSize() {return m_cardSize;} + + inline void clearPixmapCache(){m_pixmapMap.clear();} + + // functions to make it easier to get card pixmaps. + const QPixmap & getCardPixmap(const PlayingCard & card,bool highlighted=false) + {return getCardPixmap(card.asString(),highlighted);} + + const QPixmap & getCardBackPixmap(bool highlighted=false) + {return getCardPixmap(CardBackName,highlighted);} + + const QPixmap & getTransparentPixmap() + {return getCardPixmap(TransparentNoCard);} + + // the redeal circle is just a circle in the middle of the empty stack that indicates that + // you can d-click on the stack to recycle the cards. Used in games like Klondike where + // can go through the flip stack multiple times + const QPixmap & getCardNonePixmap(bool highlighted=false,bool redealCircle=false) + {return getCardPixmap(redealCircle?EmptyStackRedealName:EmptyStackName,highlighted);} + + +protected: + CardPixmaps(); + +private: + const QPixmap & getCardPixmap(const QString & imageName, bool highlighted=false); + void drawEmptyStack(QPainter & painter,bool highlighted,bool redealCircle); + void drawHighlightedCard(QPainter & painter,const QString & imageName); + + + QSvgRenderer * m_pSvgRendCard; // the svg render will be created the first time + // it is needed. It has to be done after Qt is initialized. + // And we just want to create it once. Loading it is fairly + // expensive. + CardPixmapMap m_pixmapMap; // this is a map of cards that is built as a card is needed. + // It will also contain the card back. And highlighted + // versions of cards. + QSize m_cardSize; // this is the card size that is used for every card + // that is drawn. The height of a card is determined + // from the width. So, the value is set by calling + // setCardWidth. +}; + +#endif diff --git a/plugins/qsolocards_plugin/CardStack.cpp b/plugins/qsolocards_plugin/CardStack.cpp new file mode 100644 index 000000000..0e4e36325 --- /dev/null +++ b/plugins/qsolocards_plugin/CardStack.cpp @@ -0,0 +1,857 @@ +/* + 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 "CardStack.h" +#include +#include +#include +#include +#include +#include +#include "CardPixmaps.h" +#include "CardAnimationLock.h" + +#include + +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;im_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]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;iupdateStack(); + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +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 (indexm_cardVector.size()) + { + rc=true; + + unsigned int i; + + removedCards.clear(); + + for(i=index;im_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 (indexm_cardVector.size()) + { + rc=true; + + unsigned int i; + + removedCards.clear(); + + for(i=index;im_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;jm_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;iremoveTopCard(); + } + 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;im_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); +} diff --git a/plugins/qsolocards_plugin/CardStack.h b/plugins/qsolocards_plugin/CardStack.h new file mode 100644 index 000000000..6e07cdf63 --- /dev/null +++ b/plugins/qsolocards_plugin/CardStack.h @@ -0,0 +1,238 @@ +/* + 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 . +*/ + +#ifndef CARDSTACK_H +#define CARDSTACK_H + +#include +#include + +#include "CardMoveRecord.h" + +#include "FlipAnimation.h" +#include "DragCardStack.h" + +#include +#include + +class CardStack; + +typedef std::map CardStackMap; + + +class CardStack: public QObject,public QGraphicsPixmapItem +{ + Q_OBJECT +public: + enum ProcessCardMoveRecordType + { + UndoMove=0, + RedoMove=1 + }; + + enum + { + HintHighlightNoCards=-2 + }; + + CardStack(); + virtual ~CardStack(); + + inline const std::string stackName()const{return m_stackName.toStdString();} + + inline bool isFlipAniRunning()const {return m_flipAni.isAniRunning();} + + + bool allCardsFaceUp()const; + + // top is in this case the last card in the stack. bottom is index 0 + bool cardsAscendingTopToBottom()const; + bool cardsDecendingTopToBottom()const; + + void setTopCardUp(bool faceUp=true); + + bool flipCard(int index,bool aniIfEnabled=true); + bool flipCard(int index,CardMoveRecord & moveRecord,bool aniIfEnabled=true); + + inline void setAutoTopCardUp(bool autoFaceUp=true){this->m_autoFaceUp=autoFaceUp;} + inline bool isAutoTopCardUp()const {return m_autoFaceUp;} + + + inline bool isHighlighted() const {return m_highlighted;} + inline void setHighlighted(bool state=true){m_highlighted=state;} + + inline int hintHighlightIndex() const {return m_hintHighlightIndex;} + + + inline bool showRedealCircle(){return m_showRedealCircle;} + inline void setShowRedealCircle(bool state=true){m_showRedealCircle=state;} + + void addCard(const PlayingCard & newCard); + void addCards(const PlayingCardVector & cardVector); + + void addCard(const PlayingCard & newCard,CardMoveRecord & moveRecord,bool justUpdateRec=false); + void addCards(const PlayingCardVector & cardVector,CardMoveRecord & moveRecord,bool justUpdateRec=false); + + + // pull the top card off of the stack + PlayingCard removeTopCard(); + PlayingCard removeTopCard(CardMoveRecord & moveRecord); + + // the cardVector contains the cards that were removed if the index is valid. + bool removeCardsStartingAt(unsigned int index,PlayingCardVector & removedCards); + bool removeCardsStartingAt(unsigned int index,PlayingCardVector & removedCards, + CardMoveRecord & moveRecord,bool justUpdateRec=false); + + void removeAllCards(); + + inline bool isEmpty() const {return m_cardVector.empty();} + + const PlayingCardVector & getCardVector()const{return m_cardVector;} + + virtual bool canAddCards(const PlayingCardVector &){return false;} + + // this function will return the cards at the end of the stack that can be moved. + // the function canMoveCards that can be overridden by subclasses controls the + // cards that can be moved. This function can also be overridden if something other + // than the default of just cards at the end of the stack is desired. + // + // the cards that can be moved will be added to the end of the card vector passed in + // the start index of the cards is also set if the function returns true + // the function returns true if it has cards that can be moved or false if it has none. + + // this function has been added to aid in creating hints for moving cards + virtual bool getMovableCards(PlayingCardVector &, unsigned int & index) const; + + // this function gets the point in the scene that a card would be added to this stack. + inline virtual QPointF getGlobalCardAddPt() const {return mapToScene(QPointF(0,0));}; + inline virtual QPointF getGlobalLastCardPt() const {return mapToScene(QPointF(0,0));}; + inline virtual QPointF getGlobalCardPt(int index) const {Q_UNUSED(index);return mapToScene(QPointF(0,0));}; + + // this function will update the bounding rectangle for the cards. And update the + // pixmap for the stack. The default implementation implementation just calls + // getStackPixmap. Subclasses may want to override this version to record bounding + // rectangles for cards and then call the base class. + virtual void updateStack(); + + // this function returns a pointer to a pixmap of the stack. The pixmap is the responsiblity + // of the caller to free. This function can be overridden in subclasses to create + // different look for the stack when drawn or cards from it are dragged to a different + // stack. + virtual QPixmap * getStackPixmap(const PlayingCardVector & cardVector, + bool highlighted=false, + int hintHighlightIndex=-1); + + // override in subclasses for scoring per stack if desired. + virtual int score() const{return 0;} + + /////////////////////////////////////////////////////////////////////////////// + // public static functions + /////////////////////////////////////////////////////////////////////////////// + static void updateAllStacks(); + + static void clearAllStacks(); + + static inline void lockUserInteration(bool lock=true){m_lockUserInteraction=lock;} + static inline bool isUserInteractionLocked() {return m_lockUserInteraction;} + + static CardStack * getStackByName(const std::string & stackName); + + static bool isCardStack(QGraphicsItem *); + + static void processCardMoveRecord(ProcessCardMoveRecordType type, + CardMoveRecord moveRecord); + + // this is a helper function that will show a move hint by highlighting the src widget starting with the + // srcCardIndex in the stack for one second. And then highlighting the last card in the dest stack for + // one second. + static void showHint(CardStack * pSrcWidget,unsigned int srcCardIndex,CardStack * pDstWidget); + +public slots: + // the slotDelayedHintHighlight() allows you to call slotHintHighlight() for the src stack + // and slotDelayedHintHighlight() for the destination stack at the same time. + void slotDelayedHintHighlight(); // show a hint highlight delayed + void slotHintHighlight(int index=-1); // show the highlight hint immediately it will timeout in one second + void slotHintHighlightComplete(); + + void slotFlipComplete(CardStack * pSrc); + + void slotDragCardsMoved(const CardMoveRecord & moveRecord); + +signals: + // when a card is clicked this signal is emitted + void cardClicked(CardStack * pCardStackWidget,unsigned int index); + // This signal is emitted when there are no cards + // in the stack and the pad area where the first card would be is clicked + void padClicked(CardStack * pCardStackWidget); + + // this signal indicates that cards where clicked, but they are also movable + // and it includes a move record of what would happen if the card was moved. This + // can be used to make the move by calling processCardMoveRecord. If the move is accepted + // the add move can be added to the move record. And then processCardMoveRecord can be + // called to perform the move. The index is the index of the card that was clicked. + void movableCardsClicked(CardStack * pCardStack, + const PlayingCardVector & cardVector, + const CardMoveRecord &); + + // the card record will contain all changes made by the drag and + // drop. The remove from one stack. The flip of the card if in + // autoCardUp mode and the card under the remove cards was face + // down. And then the add of the cards to the other stack. + // The signal will be emitted by the stack that started the drag + // operation. + void cardsMovedByDragDrop(const CardMoveRecord &); + +protected: + int m_hintHighlightIndex; + + // subclasses should reimplement canMoveCard and canAddCards + // for the rules of whatever game they are implementing. + virtual bool canMoveCard(unsigned int index) const{Q_UNUSED(index); return false;} + virtual bool getCardIndex(const QPointF & pos,unsigned int & index); + + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + + virtual void hoverMoveEvent ( QGraphicsSceneHoverEvent * event ); + +private: + QString m_stackName; + PlayingCardVector m_cardVector; + bool m_highlighted; + bool m_showRedealCircle; + bool m_autoFaceUp; + bool m_mouseMoved; // set to true if the mouse is moved while the button is down + // using this to determine a mouse click on the CardStack. The + // mouse should not move. + QPointF m_dragStartPos; // used to figure out when the mouse has been moved enough to + // start a drag operation + + FlipAnimation m_flipAni; + DragCardStack m_dragStack; + + /////////////////////////////////////////////////////////////////////////////// + // static variables + /////////////////////////////////////////////////////////////////////////////// + static CardStackMap m_cardStackMap; // this is a map that contains all of the current instances + // of CardStack. They are mapped by a unique name to a + // pointer to the instance. + static bool m_lockUserInteraction; +}; + +#endif diff --git a/plugins/qsolocards_plugin/DealAnimation.cpp b/plugins/qsolocards_plugin/DealAnimation.cpp new file mode 100644 index 000000000..b4ef55e10 --- /dev/null +++ b/plugins/qsolocards_plugin/DealAnimation.cpp @@ -0,0 +1,480 @@ +/* + 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++; + } + } + } +} diff --git a/plugins/qsolocards_plugin/DealAnimation.h b/plugins/qsolocards_plugin/DealAnimation.h new file mode 100644 index 000000000..1f5ae29a3 --- /dev/null +++ b/plugins/qsolocards_plugin/DealAnimation.h @@ -0,0 +1,149 @@ +/* + 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 . +*/ + +#ifndef __DEALANIMATION_H__ +#define __DEALANIMATION_H__ + +#include + +#include "CardStack.h" +#include "CardMoveRecord.h" +#include +#include + +#include +#include +#include + +// DealItems can be used to define the cards that will be dealt to a stack. +// The DealItem can then be added to the DealItemVector which is the overall +// definition of the deal. +class DealItem +{ +public: + DealItem(CardStack * pDst,CardStack * pSrc); + DealItem(const DealItem & rh); + ~DealItem(); + + inline bool isEmpty()const{return (m_flipList.empty() || m_pSrc->isEmpty());} + inline void addCard(bool flip){m_flipList.push_back(flip);} + + // returns the flip value of the next card and pops it off the list. + bool getNextCard(); + + inline CardStack * dst(){return m_pDst;} + inline CardStack * src(){return m_pSrc;} + + DealItem & operator=(const DealItem & rh); + +private: + CardStack * m_pDst; + CardStack * m_pSrc; + std::list m_flipList; // the list allows a record of how many cards to deal from the + // src to the dst and which ones need to be flipped. + // The cards will only be flipped once added to the dst stack. +}; + +typedef std::vector DealItemVector; + +class DealGraphicsItem:public QObject,public QGraphicsPixmapItem +{ + Q_OBJECT +public: + DealGraphicsItem(DealItem & dealItem,CardMoveRecord & moveRecord); + virtual ~DealGraphicsItem(); + + inline DealItem & getItem(){return m_dealItem;} + + void setupAnimation(unsigned int duration,unsigned int delay,unsigned int zValue); + + inline bool flipCard()const{return m_flipCard;} + + inline const PlayingCard & card()const{return m_card;} + + void stopAni(); + +signals: + void aniFinished(DealGraphicsItem *); +public slots: + void slotAniFinished(); + void slotTimeToStart(); + +private: + DealItem & m_dealItem; + bool m_flipCard; + PlayingCard m_card; + QGraphicsItemAnimation * m_pGItemAni; + CardMoveRecord & m_moveRecord; + QTimeLine m_timeLine; + QTimer m_delayTimer; + bool m_emitFinished; +}; + +typedef std::vector DealGraphicsItemVector; + +class DealAnimation: public QObject +{ + Q_OBJECT +public: + enum + { + PerDealDuration=400, + PerCardDelay=60 + }; + + DealAnimation(); + virtual ~DealAnimation(); + + // this duration may not be the total for the entire deal. This the duration for one round. + // So, if you have ten stacks and are dealing 5 cards to eacy stack. The entire duration will + // be the duration x 5. + inline void setDuration(int durInMilSecs=PerDealDuration){m_duration=durInMilSecs;} + inline int getDuration()const{return m_duration;} + + // the option of sending the complete signal is for cases like the initial deal of the cards. + // In that case the caller does not care when it is done as long as the user can't do anything + // until the deal is complete. The use of the CardAnimationLock will ensure this whether or not + // the caller wants to get the notification. + bool dealCards(const DealItemVector & itemVector,bool createMoveRecord=true); + + void stopAni(); + +signals: + void cardsMoved(const CardMoveRecord & moveRecord); + +public slots: + void slotAniFinished(DealGraphicsItem * pDealGraphicsItem); + +private: + bool cardsRemaining(); + void cleanUpGraphicsItem(DealGraphicsItem * pDealGraphicsItem); + void cleanUpGraphicsItems(); + void noAniStackUdpates(); + void buildAniStackUpdates(); + + CardMoveRecord m_moveRecord; + DealItemVector m_dealItemVector; + DealGraphicsItemVector m_graphicsItemVector; + bool m_aniRunning; + bool m_stopAni; + int m_duration; + bool m_createMoveRecord; +}; + +#endif diff --git a/plugins/qsolocards_plugin/DragCardStack.cpp b/plugins/qsolocards_plugin/DragCardStack.cpp new file mode 100644 index 000000000..d4d0460f6 --- /dev/null +++ b/plugins/qsolocards_plugin/DragCardStack.cpp @@ -0,0 +1,209 @@ +/* + 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 "DragCardStack.h" +#include "CardStack.h" + +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +DragCardStack::DragCardStack(CardStack * pSrc) + :QObject(),QGraphicsPixmapItem(), + m_cardVector(), + m_pSrc(pSrc), + m_size(0,0), + m_cursorPt(0,0), + m_dragStarted(false), + m_pDst(NULL) +{ + this->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + this->setCursor(Qt::ClosedHandCursor); +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +DragCardStack::~DragCardStack() +{ +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +void DragCardStack::startCardMove(const QPointF & globalMousePt, + unsigned int startCardIndex, + const PlayingCardVector & moveCards) +{ + if (startCardIndexgetCardVector().size() && + moveCards.size()>0) + { + this->m_cardVector.clear(); + this->m_cardVector=moveCards; + + QPixmap * pPixmap=m_pSrc->getStackPixmap(this->m_cardVector); + + if (NULL!=pPixmap) + { + this->setPixmap(*pPixmap); + m_size=pPixmap->size(); + delete pPixmap; + } + + // set the z value to 2 so it will be on top of the + // stacks. + this->setZValue(2); + + + QPointF startPt=m_pSrc->getGlobalCardPt(startCardIndex); + + // this gets the relative position of the mouse on the new object. + m_cursorPt.setX(globalMousePt.x()-startPt.x()); + m_cursorPt.setY(globalMousePt.y()-startPt.y()); + + // add the item to the scene and move it over the stack in the + // place of the cards that we want to move + m_pSrc->scene()->addItem(this); + this->setPos(startPt); + + // remove the cards from the stack and repaint + unsigned int i; + + for(i=m_pSrc->getCardVector().size()-1;i>=startCardIndex && !m_pSrc->isEmpty();i--) + { + m_pSrc->removeTopCard(); + } + m_pSrc->updateStack(); + m_pSrc->setCursor(Qt::ClosedHandCursor); + + + m_dragStarted=true; + + m_pDst=NULL; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +void DragCardStack::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event); + + if (m_dragStarted) + { + m_dragStarted=false; + m_pSrc->scene()->removeItem(this); + + if (NULL!=m_pDst && + this->m_pDst->canAddCards(this->m_cardVector)) + { + CardMoveRecord moveRecord; + + moveRecord.push_back(CardMoveRecordItem(this->m_pSrc->stackName(), + CardMoveRecordItem::RemoveCards, + this->m_cardVector)); + + m_pDst->addCards(this->m_cardVector,moveRecord); + m_pDst->setHighlighted(false); + m_pDst->updateStack(); + + emit cardsMoved(moveRecord); + + m_pDst=NULL; + } + else + { + m_pSrc->addCards(this->m_cardVector); + m_pSrc->updateStack(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// +void DragCardStack::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (m_dragStarted) + { + // get the topleft from the mouse pos and then adjust for where the mouse + // is positioned on the card. + QPointF topLeft(event->scenePos()); + topLeft.rx()-=m_cursorPt.x(); + topLeft.ry()-=m_cursorPt.y(); + + // move the card to it's new place. + this->setPos(topLeft); + + // calc our bounding rect. + QRectF boundingRect(topLeft,QSizeF(m_size.width(),m_size.height())); + + // now find which items this item intersects with. + QList intersectItems=this->scene()->items(boundingRect); + + CardStack * pNewDst=NULL; + + qreal largestArea=0; + + for(int i=0;isceneBoundingRect(); + + if (boundingCurr.contains(event->scenePos())) + { + pNewDst=pCurrDst; + break; + } + else + { + QRectF commonRect(boundingRect.intersected(boundingCurr)); + + qreal currArea=commonRect.width()*commonRect.height(); + + if (currArea>largestArea) + { + largestArea=currArea; + pNewDst=pCurrDst; + } + } + } + } + + if (pNewDst!=this->m_pDst) + { + if (NULL!=this->m_pDst) + { + this->m_pDst->setHighlighted(false); + this->m_pDst->updateStack(); + } + this->m_pDst=pNewDst; + + if (NULL!=this->m_pDst && + this->m_pDst->canAddCards(this->m_cardVector)) + { + this->m_pDst->setHighlighted(true); + this->m_pDst->updateStack(); + } + } + } +} diff --git a/plugins/qsolocards_plugin/DragCardStack.h b/plugins/qsolocards_plugin/DragCardStack.h new file mode 100644 index 000000000..be4d7d4e2 --- /dev/null +++ b/plugins/qsolocards_plugin/DragCardStack.h @@ -0,0 +1,58 @@ +/* + 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 . +*/ +#ifndef __DRAGCARDSTACK_H__ +#define __DRAGCARDSTACK_H__ + +#include +#include +#include "CardDeck.h" +#include "CardMoveRecord.h" + +class CardStack; + +class DragCardStack:public QObject,public QGraphicsPixmapItem +{ + Q_OBJECT +public: + DragCardStack(CardStack * pSrc); + virtual ~DragCardStack(); + + inline bool cardDragStarted()const{return m_dragStarted;} + + void startCardMove(const QPointF & globalMousePt, + unsigned int startCardIndex, + const PlayingCardVector & moveCards); + +signals: + void cardsMoved(const CardMoveRecord & moveRecord); + +protected: + friend class CardStack; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + +private: + PlayingCardVector m_cardVector; + CardStack * m_pSrc; + QSize m_size; + QPoint m_cursorPt; + bool m_dragStarted; + CardStack * m_pDst; +}; + +#endif diff --git a/plugins/qsolocards_plugin/FlipAnimation.cpp b/plugins/qsolocards_plugin/FlipAnimation.cpp new file mode 100644 index 000000000..679d8f0f8 --- /dev/null +++ b/plugins/qsolocards_plugin/FlipAnimation.cpp @@ -0,0 +1,193 @@ +/* + 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 "FlipAnimation.h" +#include "CardStack.h" +#include "CardAnimationLock.h" + +#include + + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// +FlipAnimation::FlipAnimation() + :m_pSrc(NULL), + m_card(), + m_timeLine(), + m_pItemAni(NULL), + m_pPixmapItem(NULL), + m_flipPtReached(false), + m_aniRunning(false) +{ + // connect up the slot so we will know when it is finished. + this->connect(&m_timeLine,SIGNAL(finished()), + this,SLOT(slotAniFinished())); + + this->connect(&m_timeLine,SIGNAL(valueChanged(qreal)), + this,SLOT(slotFlipAniProgress(qreal))); +} + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// +FlipAnimation::~FlipAnimation() +{ + delete m_pItemAni; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// +void FlipAnimation::flipCard(CardStack * pSrc,int duration) +{ + // if animation is off just immediately emit the flipComplete + // signal + if (!CardAnimationLock::getInst().animationsEnabled() || + pSrc->isEmpty()) + { + emit flipComplete(pSrc); + } + else + { + // first if we have an animation running stop it. + this->stopAni(); + m_pSrc=pSrc; + runAnimation(duration); + } + +} + + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// +void FlipAnimation::stopAni() +{ + if (this->isAniRunning()) + { + m_aniRunning=false; + + this->m_timeLine.stop(); + + // remove the animation object + m_pSrc->scene()->removeItem(m_pPixmapItem); + delete m_pPixmapItem; + m_pPixmapItem=NULL; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// +bool FlipAnimation::isAniRunning() const +{ + return m_aniRunning; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// +void FlipAnimation::slotAniFinished() +{ + m_aniRunning=false; + + emit flipComplete(m_pSrc); + + // remove the animation object + m_pSrc->scene()->removeItem(m_pPixmapItem); + delete m_pPixmapItem; + m_pPixmapItem=NULL; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// +void FlipAnimation::slotFlipAniProgress(qreal currProgress) +{ + if (currProgress>=.5 && !m_flipPtReached) + { + m_flipPtReached=true; + + m_card.setFaceUp(!m_card.isFaceUp()); + + PlayingCardVector cardVector; + + cardVector.push_back(m_card); + + QPixmap * pPixmap=m_pSrc->getStackPixmap(cardVector); + + if (pPixmap) + { + m_pPixmapItem->setPixmap(*pPixmap); + delete pPixmap; + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// +void FlipAnimation::runAnimation(int duration) +{ + m_flipPtReached=false; + + delete m_pItemAni; + delete m_pPixmapItem; + + m_timeLine.setDuration(duration); + m_pItemAni=new QGraphicsItemAnimation; + m_pPixmapItem=new QGraphicsPixmapItem; + + m_card=m_pSrc->getCardVector()[m_pSrc->getCardVector().size()-1]; + + PlayingCardVector cardVector; + + cardVector.push_back(m_card); + + QPixmap * pPixmap=m_pSrc->getStackPixmap(cardVector); + + if (pPixmap) + { + m_pPixmapItem->setPixmap(*pPixmap); + delete pPixmap; + } + + m_pPixmapItem->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + QPointF initPt(m_pSrc->getGlobalLastCardPt()); + + QPoint halfWayPt(initPt.x()+pPixmap->width()/2,initPt.y()+pPixmap->height()/2); + + // set the z value to 2 so it will be on top of the + // stacks. + m_pPixmapItem->setZValue(2); + + // add the item to the scene and move it over the stack in the + // place of the card we are going to flip + m_pSrc->scene()->addItem(m_pPixmapItem); + m_pPixmapItem->setPos(initPt); + + // setup the animation + m_pItemAni->setItem(m_pPixmapItem); + m_pItemAni->setTimeLine(&m_timeLine); + + m_pItemAni->setPosAt (0, initPt); + m_pItemAni->setPosAt (.5, halfWayPt); + m_pItemAni->setPosAt (1, initPt); + + m_pItemAni->setScaleAt( 0, 1, 1 ); + m_pItemAni->setScaleAt( 0.5, 0.0, 1 ); + m_pItemAni->setScaleAt( 1, 1, 1 ); + + + m_aniRunning=true; + m_timeLine.start(); +} diff --git a/plugins/qsolocards_plugin/FlipAnimation.h b/plugins/qsolocards_plugin/FlipAnimation.h new file mode 100644 index 000000000..5d13b05cd --- /dev/null +++ b/plugins/qsolocards_plugin/FlipAnimation.h @@ -0,0 +1,75 @@ +/* + 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 . +*/ +#ifndef __FLIPANIMATION_H__ +#define __FLIPANIMATION_H__ + +#include "CardMoveRecord.h" + +#include +#include +#include +#include +#include + +class CardStack; + +// This animation is different from the DealAnimation and StackToStackAniMove in that +// it will require the stack to change during the animation. Since, the effect of the +// animation is to show a card flipping the stack below it will be shown. And the stack +// needs to be shown without the card in it when it is exposed by the animation. So, the +// animation is a combination of the FlipAnimation object and CardStack object to get the +// flip effect. +class FlipAnimation: public QObject +{ + Q_OBJECT +public: + FlipAnimation(); + virtual ~FlipAnimation(); + + // This animation is specifically for flipping the last card in a + // stack. Cases where a card is flipped that is under other cards + // is not covered. If needed it can be added later. Something where + // the cards on top of it are pivoted out of the way, doing + // a flip of the desired card, and pivoting the cards back down on + // top of the flip card would be a very nice effect. + void flipCard(CardStack * pSrc,int duration=300); + + void stopAni(); + + bool isAniRunning() const; + +signals: + void flipComplete(CardStack * pSrc); + +public slots: + void slotAniFinished(); + void slotFlipAniProgress(qreal currProgress); + +private: + void runAnimation(int duration); + + CardStack * m_pSrc; + PlayingCard m_card; + QTimeLine m_timeLine; + QGraphicsItemAnimation * m_pItemAni; + QGraphicsPixmapItem * m_pPixmapItem; + bool m_flipPtReached; + bool m_aniRunning; +}; + +#endif diff --git a/plugins/qsolocards_plugin/FreeCellBoard.cpp b/plugins/qsolocards_plugin/FreeCellBoard.cpp new file mode 100644 index 000000000..32fc04daa --- /dev/null +++ b/plugins/qsolocards_plugin/FreeCellBoard.cpp @@ -0,0 +1,693 @@ +/* + 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 "FreeCellBoard.h" +#include "CardPixmaps.h" +#include "CardDeck.h" +#include "CardAnimationLock.h" + +#include + +#include + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +FreeCellBoard::FreeCellBoard() + :GameBoard(NULL,QString(tr("Freecell")).trimmed(),QString("Freecell")), + m_pDeck(NULL), + m_freeVector(), + m_stackVector(), + m_homeVector(), + m_cheat(false) +{ + this->setHelpFile(":/help/FreeCellHelp.html"); +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +FreeCellBoard::~FreeCellBoard() +{ +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::undoMove() +{ + GameBoard::undoMove(); + + this->setNumStackMoveCards(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::redoMove() +{ + GameBoard::redoMove(); + + this->setNumStackMoveCards(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +bool FreeCellBoard::getHint(CardStack * & pSrc, + unsigned int & srcIndex, + CardStack * & pDst) +{ + bool rc=false; + unsigned int i; + unsigned int j; + + + // first see if we have any cards from the free cells to move + // home + for (i=0;im_freeVector.size() && !rc;i++) + { + if (!this->m_freeVector[i]->isEmpty()) + { + const PlayingCardVector & cardVector=this->m_freeVector[i]->getCardVector(); + PlayingCardVector moveCards; + + srcIndex=cardVector.size()-1; + + moveCards.push_back(cardVector[srcIndex]); + + for (j=0;jm_homeVector.size();j++) + { + if (this->m_homeVector[j]->canAddCards(moveCards)) + { + pSrc=this->m_freeVector[i]; + pDst=this->m_homeVector[j]; + rc=true; + break; + } + } + } + } + + // now see if there are any cards in the stacks to move home + if (!rc) + { + for (i=0;im_stackVector.size() && !rc;i++) + { + if (!this->m_stackVector[i]->isEmpty()) + { + const PlayingCardVector & cardVector=this->m_stackVector[i]->getCardVector(); + PlayingCardVector moveCards; + + srcIndex=cardVector.size()-1; + + moveCards.push_back(cardVector[srcIndex]); + + for (j=0;jm_homeVector.size();j++) + { + if (this->m_homeVector[j]->canAddCards(moveCards)) + { + pSrc=this->m_stackVector[i]; + pDst=this->m_homeVector[j]; + rc=true; + break; + } + } + } + } + } + + // now see if we can move cards from the free cells to the stacks + if (!rc) + { + for (i=0;im_freeVector.size() && !rc;i++) + { + if (!this->m_freeVector[i]->isEmpty()) + { + PlayingCardVector moveCards; + + if (this->m_freeVector[i]->getMovableCards(moveCards,srcIndex)) + { + for (j=0;jm_stackVector.size();j++) + { + if (this->m_stackVector[j]->canAddCards(moveCards)) + { + pSrc=this->m_freeVector[i]; + pDst=this->m_stackVector[j]; + rc=true; + break; + } + } + } + } + } + } + + // now look for stack to stack moves + if (!rc) + { + for (i=0;im_stackVector.size() && !rc;i++) + { + if (!this->m_stackVector[i]->isEmpty()) + { + PlayingCardVector moveCards; + + if (this->m_stackVector[i]->getMovableCards(moveCards,srcIndex)) + { + // look through the stacks if we couldn't move the card home + for (j=0;jm_stackVector.size();j++) + { + // make sure not the same stackVector and that we are not moving + // the last card in a stack to an empty stack. Moving the last + // card in a stack to an empty stack doesn't do anything. And lastly + // if the cards can be added we have a match. + if (i!=j && + !(0==srcIndex && this->m_stackVector[j]->isEmpty()) && + this->m_stackVector[j]->canAddCards(moveCards)) + { + pSrc=this->m_stackVector[i]; + pDst=this->m_stackVector[j]; + rc=true; + break; + } + } + } + } + } + } + + + // now look to move something to a free cell if all else has failed + // for now just going to be a basic move an available card from the first + // stack with cards in it to the free cell. + if (!rc) + { + // first find an open free cell. If we don't have one no need to continue. + pDst=NULL; + + for (i=0;im_freeVector.size();i++) + { + if (this->m_freeVector[i]->isEmpty()) + { + pDst=this->m_freeVector[i]; + break; + } + } + + if (NULL!=pDst) + { + for (i=0;im_stackVector.size();i++) + { + if (!this->m_stackVector[i]->isEmpty()) + { + PlayingCardVector moveCards; + + + if (this->m_stackVector[i]->getMovableCards(moveCards,srcIndex) && + pDst->canAddCards(moveCards)) + { + pSrc=this->m_stackVector[i]; + rc=true; + break; + } + } + } + } + } + + + return rc; +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::newGame() +{ + // call the base class to clean up + GameBoard::newGame(); + + CardDeck deck; + unsigned int i; + + + // add all the cards to the deck + while(!deck.isEmpty()) + { + this->m_pDeck->addCard(deck.next()); + } + + // setup the deal of cards + DealItemVector dealItemVector; + + // Create the dealItemVector to direct the DealAnimation object on + // how to deal the cards. + for (i=0;im_stackVector.size();i++) + { + unsigned int j; + unsigned int cardsInStack=((i<4)?7:6); + + dealItemVector.push_back(DealItem(this->m_stackVector[i],m_pDeck)); + + for (j=0;jsetCheat(cheat); + } +} + + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::slotCardsMoved(const CardMoveRecord & moveRecord) +{ + GameBoard::slotCardsMoved(moveRecord); + + this->setNumStackMoveCards(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::slotFreeCardsClicked(CardStack * pCardStack, + const PlayingCardVector & cardVector, + const CardMoveRecord & startMoveRecord) +{ + Q_UNUSED(pCardStack); + + CardStack * pEmptyStack=NULL; + CardStack * pMoveStack=NULL; + unsigned int i; + + // ok look for where we would move the cards to. We will look first at the home stacks. + // After the home stacks the next priority will be a non-empty stack and then lastly + // an empty stack. + + for (i=0;im_homeVector.size();i++) + { + if (this->m_homeVector[i]->canAddCards(cardVector)) + { + pMoveStack=this->m_homeVector[i]; + break; + } + } + + // if we did not find a match continue to look + if (NULL==pMoveStack) + { + for (i=0;im_stackVector.size();i++) + { + if (this->m_stackVector[i]->canAddCards(cardVector)) + { + if (this->m_stackVector[i]->isEmpty()) + { + pEmptyStack=this->m_stackVector[i]; + } + else + { + pMoveStack=this->m_stackVector[i]; + break; + } + } + } + } + + if (NULL!=pMoveStack || NULL!=pEmptyStack) + { + if (NULL==pMoveStack) + { + pMoveStack=pEmptyStack; + } + + CardMoveRecord moveRecord(startMoveRecord); + pMoveStack->addCards(cardVector,moveRecord,true); + + // perform the move of the cards and animate it if animations + // are enabled + m_sToSAniMove.moveCards(moveRecord); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::slotStackCardsClicked(CardStack * pCardStack, + const PlayingCardVector & cardVector, + const CardMoveRecord & startMoveRecord) +{ + CardStack * pEmptyStack=NULL; + CardStack * pMoveStack=NULL; + unsigned int i; + + // ok look for where we would move the cards to. We will look first at the home stacks. + // After the home stacks the next priority will be a non-empty stack then an empty stack. + // And lastly a free cell. + + for (i=0;im_homeVector.size();i++) + { + if (this->m_homeVector[i]->canAddCards(cardVector)) + { + pMoveStack=this->m_homeVector[i]; + break; + } + } + + // if we did not find a match continue to look + if (NULL==pMoveStack) + { + for (i=0;im_stackVector.size();i++) + { + if (this->m_stackVector[i]!=pCardStack) + { + if (this->m_stackVector[i]->canAddCards(cardVector)) + { + if (this->m_stackVector[i]->isEmpty()) + { + pEmptyStack=this->m_stackVector[i]; + } + else + { + pMoveStack=this->m_stackVector[i]; + break; + } + } + } + } + } + + // now look in the free cells + if (NULL==pMoveStack) + { + for (i=0;im_freeVector.size();i++) + { + if (this->m_freeVector[i]->canAddCards(cardVector)) + { + pMoveStack=this->m_freeVector[i]; + break; + } + } + } + + if (NULL!=pMoveStack || NULL!=pEmptyStack) + { + if (NULL==pMoveStack) + { + pMoveStack=pEmptyStack; + } + + CardMoveRecord moveRecord(startMoveRecord); + pMoveStack->addCards(cardVector,moveRecord,true); + + // perform the move of the cards and animate it if animations + // are enabled + m_sToSAniMove.moveCards(moveRecord); + } + +} + + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::calcScore() +{ + int score=0; + + for(unsigned int i=0;im_homeVector.size();i++) + { + score+=this->m_homeVector[i]->score(); + } + + emit scoreChanged(score,""); +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::resizeEvent (QResizeEvent * event) +{ + unsigned int i; + + GameBoard::resizeEvent(event); + + + QSize cardSize(CardPixmaps::getInst().getCardSize()); + + QPointF currPos(GameBoard::LayoutSpacing,GameBoard::LayoutSpacing); + + for (i=0;isetPos(currPos); + currPos.rx()+=cardSize.width()+GameBoard::LayoutSpacing; + } + + currPos.rx()+=(cardSize.width() + GameBoard::LayoutSpacing)/2; + + m_pDeck->setPos(currPos); + + currPos.setX(GameBoard::LayoutSpacing*7 + cardSize.width()*6); + + + for (i=0;isetPos(currPos); + currPos.rx()+=cardSize.width()+GameBoard::LayoutSpacing; + } + + currPos.setY(GameBoard::LayoutSpacing*2+cardSize.height()); + currPos.setX(GameBoard::LayoutSpacing*2+cardSize.width()); + for (i=0;isetPos(currPos); + currPos.rx()+=cardSize.width()+GameBoard::LayoutSpacing; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +bool FreeCellBoard::runDemo(bool stopWhenNoMore) +{ + bool rc=true; + + if (!GameBoard::runDemo(false)) + { + // if we didn't find a move. Try to just move a card to a freecell. + CardStack * pDst=NULL; + bool foundMove=false; + CardStack * pSrc=NULL; + unsigned int srcIndex=0; + PlayingCardVector moveCards; + unsigned int i; + + for (i=0;im_freeVector.size();i++) + { + if (this->m_freeVector[i]->isEmpty()) + { + pDst=this->m_freeVector[i]; + break; + } + } + + if (NULL!=pDst) + { + for (i=0;im_stackVector.size();i++) + { + if (!this->m_stackVector[i]->isEmpty()) + { + if (this->m_stackVector[i]->getMovableCards(moveCards,srcIndex) && + pDst->canAddCards(moveCards)) + { + pSrc=this->m_stackVector[i]; + foundMove=true; + break; + } + } + } + } + + // if we found a move create the move record. And call the stack to stack + // animation to move it. + if (foundMove) + { + CardMoveRecord moveRecord; + + pSrc->removeCardsStartingAt(srcIndex,moveCards,moveRecord,true); + pDst->addCards(moveCards,moveRecord,true); + + m_sToSAniMove.moveCards(moveRecord,this->getDemoCardAniTime()); + } + else + { + if (stopWhenNoMore) + { + stopDemo(); + rc=false; + } + else + { + rc=false; + } + } + } + + return rc; + +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::createStacks() +{ + this->setCardResizeAlg(10,ResizeByWidth); + + unsigned int i; + + // first create the home widgets where the cards need to be eventually stacked to + // win the game. + for(i=0;i<4;i++) + { + this->m_homeVector.push_back(new FreeCellHome); + this->m_scene.addItem(m_homeVector[i]); + } + + // now create the free cells + for(i=0;i<4;i++) + { + this->m_freeVector.push_back(new FreeCellFree); + this->m_scene.addItem(m_freeVector[i]); + this->connect(this->m_freeVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + this->connect(this->m_freeVector[i],SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotFreeCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord))); + } + + // now create the 8 rows for the stacks. + for (i=0;i<8;i++) + { + this->m_stackVector.push_back(new FreeCellStack); + this->m_scene.addItem(m_stackVector[i]); + this->connect(this->m_stackVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + this->connect(this->m_stackVector[i],SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotStackCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord))); + } + + this->m_pDeck=new FreeCellDeck; + this->m_scene.addItem(this->m_pDeck); +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +bool FreeCellBoard::isGameWon()const +{ + bool rc=true; + + for (unsigned int i=0;im_homeVector.size();i++) + { + if (!this->m_homeVector[i]->isStackComplete()) + { + rc=false; + break; + } + } + + return rc; +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +bool FreeCellBoard::isGameWonNotComplete()const +{ + bool rc=true; + + for (unsigned int i=0;im_stackVector.size();i++) + { + if (!this->m_stackVector[i]->cardsAscendingTopToBottom()) + { + rc=false; + break; + } + } + + return rc; +} + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// +void FreeCellBoard::setNumStackMoveCards() +{ + // as a convience allow dragging of cards if there would be enough + // freecells to move the cards + unsigned int numDragCards=1; + unsigned int i; + + for (i=0;iisEmpty()) + { + numDragCards++; + } + } + + // in the case that we might be dragging the cards to a free + // space, we don't want the free space to count. It would not + // be a free space to dump a card. So, it can't be counted. + if (numDragCards>1) + { + numDragCards--; + } + + for (i=0;iisEmpty()) + { + numDragCards++; + } + } + + for (i=0;isetMaxMoveCards(numDragCards); + } +} diff --git a/plugins/qsolocards_plugin/FreeCellBoard.h b/plugins/qsolocards_plugin/FreeCellBoard.h new file mode 100644 index 000000000..a35aedb9f --- /dev/null +++ b/plugins/qsolocards_plugin/FreeCellBoard.h @@ -0,0 +1,93 @@ +/* + 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 . +*/ + +#ifndef __FREECELLBOARD_H__ +#define __FREECELLBOARD_H__ + +#include "GameBoard.h" +#include "FreeCellDeck.h" +#include "FreeCellFree.h" +#include "FreeCellStack.h" +#include "FreeCellHome.h" +#include "VCardStack.h" + +#include + +class FreeCellBoard: public GameBoard +{ + Q_OBJECT +public: + FreeCellBoard(); + virtual ~FreeCellBoard(); + + virtual void undoMove(); + virtual void redoMove(); + + bool getHint(CardStack * & pSrc, + unsigned int & srcIndex, + CardStack * & pDst); + + inline bool hasDemo() const {return true;} + + void newGame(); + + void addGameMenuItems(QMenu & menu); + + void loadSettings(const QSettings & settings); + void saveSettings(QSettings & settings); + + inline bool isCheating() const {return m_cheat;} + + void setCheat(bool cheat); + + inline bool supportsScore() const{return true;} +public slots: + virtual void slotCardsMoved(const CardMoveRecord &); + + void slotFreeCardsClicked(CardStack * pCardStackWidget, + const PlayingCardVector & cardVector, + const CardMoveRecord &); + void slotStackCardsClicked(CardStack * pCardStackWidget, + const PlayingCardVector & cardVector, + const CardMoveRecord &); + +protected: + void calcScore(); + + virtual void resizeEvent (QResizeEvent * event); + + bool runDemo(bool stopWhenNoMore=true); + + void createStacks(); + bool isGameWon()const; + bool isGameWonNotComplete()const; + + void setNumStackMoveCards(); + +private: + + FreeCellDeck * m_pDeck; // the deck will only be used for the initial deal of cards + + std::vector m_freeVector; // free cells that any card can be placed in there will be 4 + std::vector m_stackVector; // we will have 8 items in this vector + std::vector m_homeVector; // we will have 4 items in this vector one for each suit + + bool m_cheat; +}; + +#endif diff --git a/plugins/qsolocards_plugin/FreeCellDeck.cpp b/plugins/qsolocards_plugin/FreeCellDeck.cpp new file mode 100644 index 000000000..83416dded --- /dev/null +++ b/plugins/qsolocards_plugin/FreeCellDeck.cpp @@ -0,0 +1,50 @@ +/* + 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 "FreeCellDeck.h" +#include "CardPixmaps.h" + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +FreeCellDeck::FreeCellDeck() + :CardStack() +{ +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +FreeCellDeck::~FreeCellDeck() +{ +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void FreeCellDeck::updateStack() +{ + // after the initial deal of cards we want this + // stack to be transparent. So, if the stack + // is empty use the transparent card pixmap. + if (this->isEmpty()) + { + this->setPixmap(CardPixmaps::getInst().getTransparentPixmap()); + } + else + { + CardStack::updateStack(); + } +} diff --git a/plugins/qsolocards_plugin/FreeCellDeck.h b/plugins/qsolocards_plugin/FreeCellDeck.h new file mode 100644 index 000000000..658204d55 --- /dev/null +++ b/plugins/qsolocards_plugin/FreeCellDeck.h @@ -0,0 +1,35 @@ +/* + 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 . +*/ + +#ifndef __FREECELLDECK_H__ +#define __FREECELLDECK_H__ + +#include "CardStack.h" + +class FreeCellDeck: public CardStack +{ + Q_OBJECT +public: + FreeCellDeck(); + virtual ~FreeCellDeck(); + + virtual void updateStack(); + +}; + +#endif diff --git a/plugins/qsolocards_plugin/FreeCellFree.cpp b/plugins/qsolocards_plugin/FreeCellFree.cpp new file mode 100644 index 000000000..5f7ad6cf0 --- /dev/null +++ b/plugins/qsolocards_plugin/FreeCellFree.cpp @@ -0,0 +1,59 @@ +/* + 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 "FreeCellFree.h" + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +FreeCellFree::FreeCellFree() + :CardStack() +{ +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +FreeCellFree::~FreeCellFree() +{ +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +bool FreeCellFree::canAddCards(const PlayingCardVector & newCardVector) +{ + bool rc=false; + + if (1==newCardVector.size() && this->isEmpty()) + { + rc=true; + } + + return rc; +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +bool FreeCellFree::canMoveCard(unsigned int index) const +{ + bool rc=false; + + if (0==index && this->getCardVector().size()==1) + { + rc=true; + } + return rc; +} diff --git a/plugins/qsolocards_plugin/FreeCellFree.h b/plugins/qsolocards_plugin/FreeCellFree.h new file mode 100644 index 000000000..65e1832ef --- /dev/null +++ b/plugins/qsolocards_plugin/FreeCellFree.h @@ -0,0 +1,36 @@ +/* + 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 . +*/ + +#ifndef __FREECELLFREE_H__ +#define __FREECELLFREE_H__ + +#include "CardStack.h" + +class FreeCellFree : public CardStack +{ + Q_OBJECT +public: + FreeCellFree(); + ~FreeCellFree(); + + bool canAddCards(const PlayingCardVector &); +protected: + bool canMoveCard(unsigned int index) const; +}; + +#endif // __FREECELLFREE_H__ diff --git a/plugins/qsolocards_plugin/FreeCellHome.cpp b/plugins/qsolocards_plugin/FreeCellHome.cpp new file mode 100644 index 000000000..3a3a44ba6 --- /dev/null +++ b/plugins/qsolocards_plugin/FreeCellHome.cpp @@ -0,0 +1,57 @@ +/* + 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 "FreeCellHome.h" + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +FreeCellHome::FreeCellHome() + :CardStack() +{ +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +FreeCellHome::~FreeCellHome() +{ +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +bool FreeCellHome::canAddCards(const PlayingCardVector & newCardVector) +{ + bool rc=false; + const PlayingCardVector & cardVector=this->getCardVector(); + + if (1==newCardVector.size()) + { + + if (this->isEmpty() && PlayingCard::Ace==newCardVector[0].getIndex()) + { + rc=true; + } + else if (!this->isEmpty() && + cardVector[cardVector.size()-1].isSameSuit(newCardVector[0]) && + cardVector[cardVector.size()-1].isNextCardIndex(newCardVector[0])) + { + rc=true; + } + } + + return rc; +} diff --git a/plugins/qsolocards_plugin/FreeCellHome.h b/plugins/qsolocards_plugin/FreeCellHome.h new file mode 100644 index 000000000..dfabb73f7 --- /dev/null +++ b/plugins/qsolocards_plugin/FreeCellHome.h @@ -0,0 +1,37 @@ +/* + 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 . +*/ + +#ifndef __FREECELLHOME_H__ +#define __FREECELLHOME_H__ + +#include "CardStack.h" + +class FreeCellHome : public CardStack +{ + Q_OBJECT +public: + FreeCellHome(); + ~FreeCellHome(); + + inline bool isStackComplete(){return getCardVector().size()==PlayingCard::MaxCardIndex;} + + inline int score() const {return getCardVector().size();} + bool canAddCards(const PlayingCardVector &); +}; + +#endif // __FREECELLHOME_H__ diff --git a/plugins/qsolocards_plugin/FreeCellStack.cpp b/plugins/qsolocards_plugin/FreeCellStack.cpp new file mode 100644 index 000000000..978e2f6f4 --- /dev/null +++ b/plugins/qsolocards_plugin/FreeCellStack.cpp @@ -0,0 +1,95 @@ +/* + 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 "FreeCellStack.h" + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +FreeCellStack::FreeCellStack() + :m_cheat(false), + m_maxMoveCards(1) +{ +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +FreeCellStack::~FreeCellStack() +{ +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +bool FreeCellStack::canAddCards(const PlayingCardVector & newCardVector) +{ + if (m_cheat) + { + return true; + } + + bool rc=false; + const PlayingCardVector & cardVector=this->getCardVector(); + + if (newCardVector.size()>0) + { + // if there are no cards in the stack then we will accept any cards + if (0==cardVector.size()) + { + rc=true; + } + else if (cardVector.size()>0 && + (cardVector[cardVector.size()-1].isRed() ^ newCardVector[0].isRed()) && + cardVector[cardVector.size()-1].isPrevCardIndex(newCardVector[0])) + { + rc=true; + } + } + + return rc; +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +bool FreeCellStack::canMoveCard(unsigned int index) const +{ + bool rc=false; + const PlayingCardVector & cardVector=this->getCardVector(); + + if (index. +*/ + +#ifndef __FREECELLSTACK_H__ +#define __FREECELLSTACK_H__ + +#include "VCardStack.h" + +class FreeCellStack : public VCardStack +{ + Q_OBJECT +public: + FreeCellStack(); + ~FreeCellStack(); + inline bool isCheating() const{return m_cheat;} + + inline void setCheat(bool cheat=true){m_cheat=cheat;} + + bool canAddCards(const PlayingCardVector &); + + inline void setMaxMoveCards(unsigned int maxMoveCards){m_maxMoveCards=((maxMoveCards>1)?(maxMoveCards):(1));} +protected: + bool canMoveCard(unsigned int index) const; + +private: + bool m_cheat; + unsigned int m_maxMoveCards; +}; + +#endif // __FREECELLSTACK_H__ diff --git a/plugins/qsolocards_plugin/GameBoard.cpp b/plugins/qsolocards_plugin/GameBoard.cpp new file mode 100644 index 000000000..d438b7ce6 --- /dev/null +++ b/plugins/qsolocards_plugin/GameBoard.cpp @@ -0,0 +1,434 @@ +/* + 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 "GameBoard.h" +#include +#include "CardPixmaps.h" +#include +#include +#include + +#include "CardAnimationLock.h" + +#include + +/////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// +GameBoard::GameBoard(QWidget * pParent, + const QString & gameName, + const QString & gameSettingsId) + :QGraphicsView(pParent), + m_scene(), + m_sToSAniMove(), + m_dealAni(), + m_gameName(gameName), + m_gameSettingsId(gameSettingsId), + m_gamePixmap(":/images/sol32x32.png"), + m_undoStack(), + m_redoStack(), + m_helpFile(""), + m_numColsOrRows(1), + m_resizeType(ResizeByWidth), + m_demoRunning(false), + m_pDemoSrcPrev(NULL), + m_pDemoDstPrev(NULL), + m_demoCardsPrev(), + m_demoCardAniTime(GameBoard::DemoNormalCardAniTime), + m_stacksCreated(false) +{ + // set the background image + this->setBackgroundBrush(QImage(":/images/greenfelt.png")); + this->setCacheMode(QGraphicsView::CacheBackground); + + // add the scene to the view. + // and set it to rescale. + this->setScene(&m_scene); + + // turnoff the scroll bars on the view + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + + // hook up the animation signal for stack to stack moves. This will enable us + // to update things just like it was a drag and drop move + this->connect(&m_sToSAniMove,SIGNAL(cardsMoved(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + + this->connect(&m_dealAni,SIGNAL(cardsMoved(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); +} + +/////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// +GameBoard::~GameBoard() +{ + CardAnimationLock::getInst().setDemoMode(false); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::setCardResizeAlg(unsigned int colsOrRows,CardResizeType resizeType) +{ + if (colsOrRows<1) + { + colsOrRows=1; + } + + m_numColsOrRows=colsOrRows; + + m_resizeType=resizeType; + + this->updateCardSize(this->size()); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::updateCardSize(const QSize & newSize) +{ + if (GameBoard::ResizeByHeight==m_resizeType) + { + CardPixmaps::getInst().setCardHeight((newSize.height()-(LayoutSpacing*(m_numColsOrRows+1)))/m_numColsOrRows); + } + else + { + CardPixmaps::getInst().setCardWidth((newSize.width()-(LayoutSpacing*(m_numColsOrRows+1)))/m_numColsOrRows); + } +} +//////////////////////////////////////////////////////////////////////////////// +// ok go through and restore the last state of all stacks +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::undoMove() +{ + if (!this->m_undoStack.empty()) + { + CardMoveRecord moveRecord(m_undoStack.top()); + + CardStack::processCardMoveRecord(CardStack::UndoMove,m_undoStack.top()); + m_undoStack.pop(); + + // if we no longer have any undo info let users know. + if (!this->canUndoMove()) + { + emit undoAvail(false); + } + + bool canRedo=this->canRedoMove(); + + m_redoStack.push(moveRecord); + + // if we didn't have a redo previously and now have one + // emit a signal to tell listeners about it. + if (!canRedo) + { + emit redoAvail(true); + } + + // calc the score with the changes + this->calcScore(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// ok go through and redo the last state of all stacks +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::redoMove() +{ + if (!this->m_redoStack.empty()) + { + CardMoveRecord moveRecord(m_redoStack.top()); + + CardStack::processCardMoveRecord(CardStack::RedoMove,m_redoStack.top()); + m_redoStack.pop(); + + // emit a signal that we are out of redo info + if (!this->canRedoMove()) + { + emit redoAvail(false); + } + + bool canUndo=this->canUndoMove(); + m_undoStack.push(moveRecord); + + // emit a signal that we now have undo info + if (!canUndo) + { + emit undoAvail(true); + } + + // calc the score with the changes + this->calcScore(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +bool GameBoard::canUndoMove() const +{ + return !m_undoStack.empty(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +bool GameBoard::canRedoMove() const +{ + return !m_redoStack.empty(); +} + +//////////////////////////////////////////////////////////////////////////////// +// adding some to the undo stack also means that the redo stack is cleared. +// since +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::addUndoMove(const CardMoveRecord &moveRecord) +{ + bool canUndo=this->canUndoMove(); + + m_undoStack.push(moveRecord); + + // send a signal that we now have undo info + if (!canUndo) + { + emit undoAvail(true); + } + + // clear the redo stack because we have made a move + while(!m_redoStack.empty()) + { + m_redoStack.pop(); + } + + // since we have made a move the redo stack is now gone. + emit redoAvail(false); + + // calc the score with the changes + this->calcScore(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::clearUndoRedoStacks() +{ + while (!this->m_undoStack.empty()) + { + m_undoStack.pop(); + } + + while (!this->m_redoStack.empty()) + { + m_redoStack.pop(); + } + + emit undoAvail(false); + emit redoAvail(false); + + // calc the score with the changes + this->calcScore(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::restartGame() +{ + this->stopDemo(); + while (!this->m_undoStack.empty()) + { + CardMoveRecord moveRecord(m_undoStack.top()); + + CardStack::processCardMoveRecord(CardStack::UndoMove,m_undoStack.top()); + m_undoStack.pop(); + } + + this->clearUndoRedoStacks(); + + // update the screen for the new layout + this->update(); + + // calc the score with the changes + this->calcScore(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::showHint() +{ + unsigned int index; + CardStack * pFromStack=NULL; + CardStack * pToStack=NULL; + + // show hint if we found one. + if (this->getHint(pFromStack,index,pToStack) && pToStack && pFromStack) + { + CardStack::showHint(pFromStack,index,pToStack); + } + else + { + QMessageBox::critical(this,this->gameName(), + tr("No move found involving full sets of movable cards. " + "It might be possible to make a move not using the full set of movable cards.").trimmed()); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::startDemo(GameBoard::DemoCardAniTime demoCardAniTime) +{ + if (!m_demoRunning) + { + m_pDemoSrcPrev=NULL; + m_pDemoDstPrev=NULL; + m_demoCardsPrev.clear(); + + m_demoCardAniTime=demoCardAniTime; + + m_demoRunning=true; + CardAnimationLock::getInst().setDemoMode(true); + emit demoStarted(); + runDemo(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::stopDemo() +{ + if (m_demoRunning) + { + m_demoRunning=false; + CardAnimationLock::getInst().setDemoMode(false); + emit demoStopped(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::newGame() +{ + m_dealAni.stopAni(); + m_sToSAniMove.stopAni(); + + stopDemo(); + + CardStack::clearAllStacks(); + CardStack::updateAllStacks(); + + // clear the undo and redo info + this->clearUndoRedoStacks(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::slotCardsMoved(const CardMoveRecord & moveRecord) +{ + // calc the score with the changes + this->calcScore(); + + // if the move record is not empty add it. + if (!moveRecord.empty()) + { + this->addUndoMove(moveRecord); + } + + if (this->hasDemo()&& this->isDemoRunning()) + { + runDemo(); + } + // if all suits are sent home the game is over. Show a dialog stating that + // and start the game over. + if (this->isGameWon()) + { + QMessageBox::information(this,this->gameName(),tr("Congratulations you won!").trimmed()); + this->newGame(); + } + else if (CardAnimationLock::getInst().animationsEnabled() && + this->hasDemo() && !this->isDemoRunning() && + this->isGameWonNotComplete()) + { + this->startDemo(DemoEndGameCardAniTime); + } + +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void GameBoard::resizeEvent (QResizeEvent * event) +{ + QGraphicsView::resizeEvent(event); + + this->updateCardSize(event->size()); + this->m_scene.setSceneRect(QRectF(QPointF(0,0),event->size())); + + if (!m_stacksCreated) + { + m_stacksCreated=true; + this->createStacks(); + } + + CardStack::updateAllStacks(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +bool GameBoard::runDemo(bool stopWhenNoMore) +{ + bool rc=false; + unsigned int index; + CardStack * pFromStack=NULL; + CardStack * pToStack=NULL; + PlayingCardVector moveCards; + CardMoveRecord moveRecord; + + // here we are looking to stop moving cards back and forth over and over + // between two stacks + if (this->getHint(pFromStack,index,pToStack) && pToStack && pFromStack) + { + rc=true; + if (pFromStack->removeCardsStartingAt(index,moveCards,moveRecord,true)) + { + if (m_pDemoSrcPrev==pToStack && + m_pDemoDstPrev==pFromStack && + m_demoCardsPrev==moveCards) + { + rc=false; + } + } + } + + // if there is a hint perform the move + if (rc) + { + pToStack->addCards(moveCards,moveRecord,true); + + m_pDemoSrcPrev=pFromStack; + m_pDemoDstPrev=pToStack; + m_demoCardsPrev=moveCards; + + this->m_sToSAniMove.moveCards(moveRecord,m_demoCardAniTime); + } + else if (stopWhenNoMore) + { + stopDemo(); + rc=false; + } + else + { + rc=false; + } + + return rc; +} diff --git a/plugins/qsolocards_plugin/GameBoard.h b/plugins/qsolocards_plugin/GameBoard.h new file mode 100644 index 000000000..3b68acb14 --- /dev/null +++ b/plugins/qsolocards_plugin/GameBoard.h @@ -0,0 +1,213 @@ +/* + 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 . +*/ + +#ifndef GAMEBOARD_H +#define GAMEBOARD_H + +#include +#include +#include +#include +#include +#include + +#include + +#include "CardStack.h" +#include "CardMoveRecord.h" +#include "StackToStackAniMove.h" +#include "DealAnimation.h" + +// Generic base class for a games board +class GameBoard : public QGraphicsView +{ + Q_OBJECT + +public: + enum + { + LayoutSpacing=10 + }; + + enum CardResizeType + { + ResizeByWidth=0, + ResizeByHeight=1 + }; + + enum DemoCardAniTime + { + DemoEndGameCardAniTime=100, + DemoNormalCardAniTime=400 + }; + + GameBoard(QWidget * pWidget, + const QString & gameName, + const QString & gameSettingsId); + virtual ~GameBoard(); + + virtual void setGameName(const QString & gameName){m_gameName=gameName;} + virtual void setGameId(const QString & gameId){ m_gameSettingsId=gameId;} + + // this function show be called in the constructor of classes inheriting from this + // class to set the way that cards will be resized. + virtual void setCardResizeAlg(unsigned int colsOrRows,CardResizeType resizeType); + + // this function is called when setCardResizeAlg is called or when the GameBoard is resized. + virtual void updateCardSize(const QSize & newSize); + + // undoMove and redoMove pop items off there respective stacks + // and process the move. They also call calcScore to update the + // score. + // signals undoAvail and redoAvail are also emitted if necessary + virtual void undoMove(); + virtual void redoMove(); + + virtual bool canUndoMove() const; + virtual bool canRedoMove() const; + + // addUndoMove will add the move to the undo stack. clear the redo stack + // and call calcScore. + // signals undoAvail and redoAvail are also emitted if necessary + virtual void addUndoMove(const CardMoveRecord &); + + // will clear all contents of both the redo and undo stacks, call calcScore, and + // signals undoAvail and redoAvail are also emitted if necessary + virtual void clearUndoRedoStacks(); + + virtual void restartGame(); + + virtual void showHint(); + + // this function is split into a separate virtual function + // it will allow the function to be used both for showing a + // hint and for demo mode. + virtual bool getHint(CardStack * & pSrcWidget, + unsigned int & srcStackIndex, + CardStack * & pDstWidget)=0; + + virtual void startDemo(DemoCardAniTime demoCardAniTime=DemoNormalCardAniTime); + virtual void stopDemo(); + inline bool isDemoRunning() const { return m_demoRunning;} + + inline DemoCardAniTime getDemoCardAniTime()const{return m_demoCardAniTime;} + + // override this function if the game is implementing demo mode. + // The runDemo() function will need to be called after + // each move. Bestway would be to add something at the end of the slot + // that catches the cardsMoved signal from the move animations. + // By default runDemo will call getHint and if a move is returned it will + // perform the move. If something else is desired the function can be overridden. + // it also returns a bool. So, if it is overridden the base class can be called + // first to see if there is a basic move. If not something else can be done. + virtual bool hasDemo() const {return false;} + + virtual void newGame(); + + virtual bool isCheating() const=0; + + virtual void setCheat(bool cheat)=0; + + virtual void addGameMenuItems(QMenu &)=0; + + virtual void loadSettings(const QSettings & settings)=0; + virtual void saveSettings(QSettings & settings)=0; + + virtual bool supportsScore() const=0; + + virtual const QString & helpFile() const { return m_helpFile;} + + const QPixmap & getGamePixmap() const{return m_gamePixmap;} + + const QString & gameName() const{return m_gameName;} + + const QString & gameSettingsId() const {return m_gameSettingsId;} + +public slots: + virtual void slotCardsMoved(const CardMoveRecord &); + +signals: + // this signal should be emitted on a state change of undo from available + // to unavailable or unavailable to available by sub classes + void undoAvail(bool avail); + + // this signal should be emitted on a state change of redo from available + // to unavailable or unavailable to available by sub classes + void redoAvail(bool avail); + + // signal emitted by a game when its score changed. + // The string is extra info the game can pass to show + // additional info. + void scoreChanged(int score,const QString &); + + + void demoStarted(); + void demoStopped(); + +protected: + virtual void calcScore()=0; // called when the score is changed by add to rewinding the undo and redo stacks + // subclasses should override for customizing score calculations + + virtual void setHelpFile(const QString & helpFile){m_helpFile=helpFile;} + + virtual void resizeEvent (QResizeEvent * event); + + // called to create the CardStacks for the game. + virtual void createStacks()=0; + + // this function can be overloaded for more complex behavior for the demo. By default it + // will just peform the hint returned if it found one. + virtual bool runDemo(bool stopWhenNoMore=true); + + // implement in subclasses to determine if the game is won. + virtual bool isGameWon()const=0; + + // implement in subclasses when cards are in position that the + // game will be won. When this function returns true the demo + // will be started if it is available to move the remaining cards + virtual bool isGameWonNotComplete()const=0; + + + QGraphicsScene m_scene; + StackToStackAniMove m_sToSAniMove; + DealAnimation m_dealAni; + +private: + QString m_gameName; + QString m_gameSettingsId; + QPixmap m_gamePixmap; + + std::stack m_undoStack; // stack to keep track of moves + std::stack m_redoStack; // stack to keep track of moves + + QString m_helpFile; + + unsigned int m_numColsOrRows; + CardResizeType m_resizeType; + + bool m_demoRunning; + + CardStack * m_pDemoSrcPrev; + CardStack * m_pDemoDstPrev; + PlayingCardVector m_demoCardsPrev; + DemoCardAniTime m_demoCardAniTime; + + bool m_stacksCreated; // variable to keep track if we have called createStacks +}; + +#endif // GAMEBOARD_H diff --git a/plugins/qsolocards_plugin/GameMgr.cpp b/plugins/qsolocards_plugin/GameMgr.cpp new file mode 100644 index 000000000..aedd5b183 --- /dev/null +++ b/plugins/qsolocards_plugin/GameMgr.cpp @@ -0,0 +1,107 @@ +/* + 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 "GameMgr.h" +#include "SpiderBoard.h" +#include "Spider3DeckBoard.h" +#include "SpideretteBoard.h" +#include "KlondikeBoard.h" +#include "FreeCellBoard.h" +#include "YukonBoard.h" +#include + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +GameMgr::GameMgr() + :m_lastGameId(GameMgr::NoGame) +{ + // build the list of games + m_gameDspNameList<m_gameDspNameList.at(i),pGameGroup); + pCurrAction->setData(QVariant(i)); + pCurrAction->setCheckable(true); + if (i==this->m_lastGameId) + { + pCurrAction->setChecked(true); + } + menu.addAction(pCurrAction); + } +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +GameBoard * GameMgr::getGame(GameId gameId) +{ + GameBoard * pGame=NULL; + + switch(gameId) + { + case GameMgr::Spider: + pGame=new SpiderBoard(NULL); + break; + case GameMgr::Klondike: + pGame=new KlondikeBoard(NULL); + break; + case GameMgr::FreeCell: + pGame=new FreeCellBoard; + break; + case GameMgr::ThreeDeckSpider: + pGame=new Spider3DeckBoard; + break; + case GameMgr::Spiderette: + pGame=new SpideretteBoard; + break; + case GameMgr::Yukon: + pGame=new YukonBoard; + break; + case GameMgr::NoGame: + default: + pGame=NULL; + break; + }; + + // if we were able to create a valid game board. Set the last + // game id + if (NULL!=pGame) + { + this->m_lastGameId=gameId; + } + + return pGame; +} diff --git a/plugins/qsolocards_plugin/GameMgr.h b/plugins/qsolocards_plugin/GameMgr.h new file mode 100644 index 000000000..a2d408148 --- /dev/null +++ b/plugins/qsolocards_plugin/GameMgr.h @@ -0,0 +1,62 @@ +/* + 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 . +*/ + +#ifndef GAMEMGR_H +#define GAMEMGR_H + +#include "GameBoard.h" +#include +#include + +class GameMgr +{ +public: + enum GameId + { + Spider=0, + Klondike=1, + FreeCell=2, + ThreeDeckSpider=3, + Spiderette=4, + Yukon=5, + NoGame=6, + DefaultGame=Spider + }; + GameMgr(); + virtual ~GameMgr(); + + // Add menu items for the games. A menu item will be created with the data object set + // as an integer with the GameId value. The caller can connect to the menus triggered + // signal and then get the data object from the QAction and call getGame with the id + // to create a game board. + void buildGameListMenu(QMenu & menu) const; + + // get a game based on the gameId. The returned GameBoard ptr + // is the responsibility of the caller to delete. If the game id is not valid + // NULL is returned. + GameBoard * getGame(GameId gameId=DefaultGame); + + GameId getGameId() const {return m_lastGameId;} + +private: + GameId m_lastGameId; // the game id of the game requested at the last call to + // getGame. The default is NoGame. + QStringList m_gameDspNameList; +}; + +#endif // GAMEMGR_H diff --git a/plugins/qsolocards_plugin/Help.cpp b/plugins/qsolocards_plugin/Help.cpp new file mode 100644 index 000000000..77675f838 --- /dev/null +++ b/plugins/qsolocards_plugin/Help.cpp @@ -0,0 +1,76 @@ +/* + 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 "Help.h" + +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +Help::Help(QWidget * pParent,const QString & helpFile) + :QDialog(pParent), + m_pBrowser(NULL) +{ + this->setWindowTitle(tr("QSoloCards: Game Help").trimmed()); + + this->setAttribute(Qt::WA_DeleteOnClose,true); + + m_pBrowser=new QTextBrowser; + + QHBoxLayout * pLayout=new QHBoxLayout; + + pLayout->addWidget(m_pBrowser,20); + + this->setLayout(pLayout); + + this->setHelpFile(helpFile); +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +Help::~Help() +{ +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +void Help::setHelpFile(const QString & helpFile) +{ + QFile file(helpFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + return; + } + + QTextStream in(&file); + QString line = in.readLine(); + + QString text; + + while (!line.isNull()) + { + text.append(line); + text.append(" "); + line = in.readLine(); + } + + m_pBrowser->setHtml(text); +} + diff --git a/plugins/qsolocards_plugin/Help.h b/plugins/qsolocards_plugin/Help.h new file mode 100644 index 000000000..18f349d06 --- /dev/null +++ b/plugins/qsolocards_plugin/Help.h @@ -0,0 +1,40 @@ +/* + 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 . +*/ + +#ifndef HELP_H +#define HELP_H + +#include +#include +#include + +class Help: public QDialog +{ + Q_OBJECT +public: + Help(QWidget * pParent,const QString & helpFile); + ~Help(); + + void setHelpFile(const QString &); + +private: + + QTextBrowser * m_pBrowser; +}; + +#endif // HELP_H diff --git a/plugins/qsolocards_plugin/KlondikeBoard.cpp b/plugins/qsolocards_plugin/KlondikeBoard.cpp new file mode 100644 index 000000000..ef6c7eed3 --- /dev/null +++ b/plugins/qsolocards_plugin/KlondikeBoard.cpp @@ -0,0 +1,770 @@ +/* + 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 "KlondikeBoard.h" +#include + +#include "CardDeck.h" +#include "CardPixmaps.h" +#include "CardAnimationLock.h" + +const QString KlondikeBoard::GameTypeKeyStr("GameType"); + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +KlondikeBoard::KlondikeBoard(QWidget * pWidget) + :GameBoard(pWidget,QString(tr("Klondike Solitaire")).trimmed(),QString("Klondike")), + m_pDeck(NULL), + m_pFlipDeck(NULL), + m_homeVector(), + m_stackVector(), + m_cheat(false), + m_gameType(KlondikeBoard::FlipOne), + m_flipNum(0), + m_sToSFlipAni() +{ + this->setHelpFile(":/help/KlondikeHelp.html"); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +KlondikeBoard::~KlondikeBoard() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::undoMove() +{ + bool emptyBefore=false; + bool emptyAfter=false; + + emptyBefore=m_pDeck->isEmpty(); + + GameBoard::undoMove(); + + emptyAfter=m_pDeck->isEmpty(); + + // if we undone a redeal decrement the flip count + if (!emptyBefore && emptyAfter) + { + this->m_flipNum--; + if (!(KlondikeBoard::FlipOne==this->m_gameType && + this->m_flipNum<2) && + !(KlondikeBoard::FlipThree==this->m_gameType)) + { + this->m_pDeck->setShowRedealCircle(false); + this->m_pDeck->updateStack(); + } + else + { + this->m_pDeck->setShowRedealCircle(true); + this->m_pDeck->updateStack(); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::redoMove() +{ + bool emptyBefore=false; + bool emptyAfter=false; + + emptyBefore=m_pDeck->isEmpty(); + + GameBoard::redoMove(); + + emptyAfter=m_pDeck->isEmpty(); + + // if we are redoing a redeal increment the flip count + if (emptyBefore && !emptyAfter) + { + this->m_flipNum++; + + if (!(KlondikeBoard::FlipOne==this->m_gameType && + this->m_flipNum<2) && + !(KlondikeBoard::FlipThree==this->m_gameType)) + { + this->m_pDeck->setShowRedealCircle(false); + this->m_pDeck->updateStack(); + } + else + { + this->m_pDeck->setShowRedealCircle(true); + this->m_pDeck->updateStack(); + } + } + +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::restartGame() +{ + // call the base class to rewind the undo stack + GameBoard::restartGame(); + + // reset the flip count + this->m_flipNum=0; + // and set the redeal circle depending on game type + if (KlondikeBoard::NoRedeals==this->m_gameType) + { + this->m_pDeck->setShowRedealCircle(false); + } + else + { + this->m_pDeck->setShowRedealCircle(true); + } + +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +bool KlondikeBoard::getHint(CardStack * & pFromStack, + unsigned int & index, + CardStack * & pToStack) +{ + // first see if we can move anything to one of the home stacks. + PlayingCardVector moveCards; + unsigned int i; + bool matchFound=false; + + + // ok check to see if we have a card from the stacks that can + // be added to a home stack + for (i=0;im_stackVector.size() && !matchFound;i++) + { + if (!this->m_stackVector[i]->isEmpty()) + { + const PlayingCardVector & currCards=this->m_stackVector[i]->getCardVector(); + moveCards.clear(); + moveCards.push_back(currCards[currCards.size()-1]); // just get the last card since we are moving to the home stack + index=currCards.size()-1; + + for (unsigned int j=0;jm_homeVector.size();j++) + { + if (this->m_homeVector[j]->canAddCards(moveCards)) + { + pToStack=this->m_homeVector[j]; + pFromStack=this->m_stackVector[i]; + matchFound=true; + break; + } + } + } + } + + // next check for stack to stack moves. + if (!matchFound) + { + moveCards.clear(); + pToStack=NULL; + pFromStack=NULL; + + for (i=0;im_stackVector.size() && !matchFound;i++) + { + moveCards.clear(); + if (!this->m_stackVector[i]->isEmpty() && + this->m_stackVector[i]->getMovableCards(moveCards,index)) + { + // we want to eliminate a move that starts with a stack that + // has a faceup king as the first card. We will just end up + // suggesting to move it to another empty row. Which is not + // really a move. + if (PlayingCard::King==moveCards[0].getIndex() && + moveCards.size()== this->m_stackVector[i]->getCardVector().size()) + { + continue; + } + for (unsigned int j=0;jm_stackVector.size();j++) + { + if (this->m_stackVector[i]!=this->m_stackVector[j] && + this->m_stackVector[j]->canAddCards(moveCards)) + { + pToStack=this->m_stackVector[j]; + pFromStack=this->m_stackVector[i]; + matchFound=true; + break; + } + } + } + } + } + + + // check the flip deck. We can just call getMovableCards for it + // since, it will always be just one card. + if (!matchFound) + { + moveCards.clear(); + pToStack=NULL; + pFromStack=NULL; + + if (!this->m_pFlipDeck->isEmpty() && + this->m_pFlipDeck->getMovableCards(moveCards,index)) + { + // first see if we can send a card to one of the home + // stacks + for(i=0;im_homeVector.size();i++) + { + if (this->m_homeVector[i]->canAddCards(moveCards)) + { + pToStack=this->m_homeVector[i]; + pFromStack=this->m_pFlipDeck; + matchFound=true; + break; + } + } + + // if no match now check to see if we can add the card to the + // normal stacks + if (!matchFound) + { + for(i=0;im_stackVector.size();i++) + { + if (this->m_stackVector[i]->canAddCards(moveCards)) + { + pToStack=this->m_stackVector[i]; + pFromStack=this->m_pFlipDeck; + matchFound=true; + break; + } + } + } + } + } + + + return matchFound; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::newGame() +{ + // stop any animation of flipping cards + m_sToSFlipAni.stopAni(); + // call the base class + GameBoard::newGame(); + + CardDeck deck; + unsigned int i; + + this->m_flipNum=0; + + // only show the redeal circle in the cases that we can redeal + if (KlondikeBoard::NoRedeals==this->m_gameType) + { + this->m_pDeck->setShowRedealCircle(false); + } + else + { + this->m_pDeck->setShowRedealCircle(true); + } + + + this->m_pFlipDeck->cardsToShow(((KlondikeBoard::FlipThree==this->m_gameType)?3:1)); + + + + while(!deck.isEmpty()) + { + this->m_pDeck->addCard(deck.next()); + } + + + DealItemVector dealItemVector; + + + // Create the dealItemVector to direct the DealAnimation object on + // how to deal the cards. + for (i=0;im_stackVector.size();i++) + { + dealItemVector.push_back(DealItem(this->m_stackVector[i],m_pDeck)); + + unsigned int j; + + for (j=0;jsetShortcut(QKeySequence(Qt::CTRL + Qt::Key_1)); + pFlipOneAction->setCheckable(true); + connect(pFlipOneAction,SIGNAL(triggered()), + this,SLOT(slotSetFlipOne())); + + QAction * pFlipThreeAction=new QAction(tr("Flip three").trimmed(),pFlipCardsGroup); + pFlipThreeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_3)); + pFlipThreeAction->setCheckable(true); + connect(pFlipThreeAction,SIGNAL(triggered()), + this,SLOT(slotSetFlipThree())); + + QAction * pNoRedealsAction=new QAction(tr("No redeals (flip one)").trimmed(),pFlipCardsGroup); + pNoRedealsAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_0)); + pNoRedealsAction->setCheckable(true); + connect(pNoRedealsAction,SIGNAL(triggered()), + this,SLOT(slotSetNoRedeals())); + + // select the correct item in the list + switch (this->m_gameType) + { + case KlondikeBoard::FlipOne: + pFlipOneAction->setChecked(true); + break; + + case KlondikeBoard::FlipThree: + pFlipThreeAction->setChecked(true); + break; + + case KlondikeBoard::NoRedeals: + pNoRedealsAction->setChecked(true); + break; + }; + + + menu.addAction(pFlipOneAction); + menu.addAction(pFlipThreeAction); + menu.addAction(pNoRedealsAction); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::loadSettings(const QSettings & settings) +{ + int gameType=settings.value(this->GameTypeKeyStr,KlondikeBoard::FlipOne).toInt(); + + switch (gameType) + { + case KlondikeBoard::NoRedeals: + this->m_gameType=KlondikeBoard::NoRedeals; + break; + + case KlondikeBoard::FlipThree: + this->m_gameType=KlondikeBoard::FlipThree; + break; + + case KlondikeBoard::FlipOne: + default: + this->m_gameType=KlondikeBoard::FlipOne; + break; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::saveSettings(QSettings & settings) +{ + settings.setValue(this->GameTypeKeyStr,this->m_gameType); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::setCheat(bool cheat) +{ + this->m_cheat=cheat; + + for(unsigned int i=0;im_stackVector.size();i++) + { + m_stackVector[i]->setCheat(cheat); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::slotFlipCards(CardStack * pCardStack, + unsigned int index) +{ + Q_UNUSED(pCardStack); + Q_UNUSED(index); + // just use the game type to indicate the number of flip cards + // the enum is assigned the number of cards that will be flipped + // the exception is the NoRedeals in that case we are just flipping + // one card. + unsigned int numFlipCards=this->m_gameType; + if (KlondikeBoard::NoRedeals==this->m_gameType) + { + numFlipCards=KlondikeBoard::FlipOne; + } + + + m_sToSFlipAni.moveCards(m_pFlipDeck,m_pDeck,numFlipCards); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::slotRedealCards(CardStack * pCardStack) +{ + Q_UNUSED(pCardStack); + // ignore an attempt to redeal if the game type is NoRedeals. + // otherwise take all the cards from the Flip stack and put them back + // in the deal stack + if (KlondikeBoard::NoRedeals!=this->m_gameType && + ((KlondikeBoard::FlipOne==this->m_gameType && + this->m_flipNum<2) || + KlondikeBoard::FlipThree==this->m_gameType)) + { + unsigned int numFlipCards=this->m_gameType; + if (KlondikeBoard::NoRedeals==this->m_gameType) + { + numFlipCards=KlondikeBoard::FlipOne; + } + + // flip the cards back. Flip the cards back over. Show the bottom 3 if in FlipThree mode. Otherwise + // just show one. + m_sToSFlipAni.moveCards(m_pDeck,m_pFlipDeck,this->m_pFlipDeck->getCardVector().size(),numFlipCards); + + this->m_flipNum++; + + if (!(KlondikeBoard::FlipOne==this->m_gameType && + this->m_flipNum<2) && + !(KlondikeBoard::FlipThree==this->m_gameType)) + { + this->m_pDeck->setShowRedealCircle(false); + } + } + else + { + // if a demo is running stop it. Can't redeal any more. + this->stopDemo(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::slotStackCardsClicked(CardStack * pCardStack, + const PlayingCardVector & cardVector, + const CardMoveRecord & startMoveRecord) +{ + unsigned int i=0; + CardStack * pFoundStack=NULL; + + if (NULL==pCardStack) + { + return; + } + + // first see if the card can be added to the sent home stack + if (cardVector.size()==1) + { + for(i=0;im_homeVector.size();i++) + { + if (pCardStack!=this->m_homeVector[i] && + this->m_homeVector[i]->canAddCards(cardVector)) + { + pFoundStack=this->m_homeVector[i]; + break; + } + } + } + + // if we did not find a match look at the stacks. + // the home will use the same logic so just call that slot + if (NULL==pFoundStack) + { + this->slotHomeCardsClicked(pCardStack,cardVector,startMoveRecord); + } + + if (pFoundStack) + { + CardMoveRecord moveRecord(startMoveRecord); + pFoundStack->addCards(cardVector,moveRecord,true); + + // perform the move of the cards and animate it if animations + // are enabled + m_sToSAniMove.moveCards(moveRecord); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::slotHomeCardsClicked(CardStack * pCardStack, + const PlayingCardVector & cardVector, + const CardMoveRecord & startMoveRecord) +{ + unsigned int i=0; + CardStack * pFoundStack=NULL; + + if (NULL==pCardStack) + { + return; + } + + for(i=0;im_stackVector.size();i++) + { + if (pCardStack!=this->m_stackVector[i] && + this->m_stackVector[i]->canAddCards(cardVector)) + { + pFoundStack=this->m_stackVector[i]; + break; + } + } + + if (pFoundStack) + { + CardMoveRecord moveRecord(startMoveRecord); + pFoundStack->addCards(cardVector,moveRecord,true); + + // perform the move of the cards and animate it if animations + // are enabled + m_sToSAniMove.moveCards(moveRecord); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::slotSetNoRedeals() +{ + this->m_gameType=KlondikeBoard::NoRedeals; + this->newGame(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::slotSetFlipOne() +{ + this->m_gameType=KlondikeBoard::FlipOne; + this->newGame(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::slotSetFlipThree() +{ + this->m_gameType=KlondikeBoard::FlipThree; + this->newGame(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::calcScore() +{ + int score=0; + + for(unsigned int i=0;im_homeVector.size();i++) + { + score+=this->m_homeVector[i]->score(); + } + + emit scoreChanged(score,""); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::resizeEvent (QResizeEvent * event) +{ + unsigned int i; + + GameBoard::resizeEvent(event); + + + QSize cardSize(CardPixmaps::getInst().getCardSize()); + + QPointF currPos(GameBoard::LayoutSpacing,GameBoard::LayoutSpacing); + + m_pDeck->setPos(currPos); + + currPos.rx()+=GameBoard::LayoutSpacing + cardSize.width(); + + m_pFlipDeck->setPos(currPos); + + currPos.rx()+=GameBoard::LayoutSpacing*3 + cardSize.width()*3; + + + for (i=0;isetPos(currPos); + currPos.rx()+=cardSize.width()+GameBoard::LayoutSpacing; + } + + currPos.setY(GameBoard::LayoutSpacing*2+cardSize.height()); + currPos.setX(GameBoard::LayoutSpacing*2+cardSize.width()); + for (i=0;isetPos(currPos); + currPos.rx()+=cardSize.width()+GameBoard::LayoutSpacing; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +bool KlondikeBoard::runDemo(bool stopWhenNoMore) +{ + bool rc=true; + + if (!GameBoard::runDemo(false)) + { + if (!m_pDeck->isEmpty()) + { + this->slotFlipCards(); + } + else if (!m_pFlipDeck->isEmpty()) + { + this->slotRedealCards(); + } + else if (stopWhenNoMore) + { + stopDemo(); + rc=false; + } + else + { + rc=false; + } + } + + return rc; + +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void KlondikeBoard::createStacks() +{ + setCardResizeAlg(8,ResizeByWidth); + + + unsigned int i; + + // first create the home widgets where the cards need to be eventually stacked to + // win the game. + for(i=0;i<4;i++) + { + this->m_homeVector.push_back(new KlondikeHomeStack); + this->m_scene.addItem(m_homeVector[i]); + this->connect(this->m_homeVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + this->connect(this->m_homeVector[i],SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotHomeCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord))); + } + + // now create the 7 rows for the stacks. + for (i=0;i<7;i++) + { + this->m_stackVector.push_back(new KlondikeStack); + this->m_scene.addItem(m_stackVector[i]); + this->connect(this->m_stackVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + this->connect(this->m_stackVector[i],SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotStackCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord))); + } + + this->m_pDeck=new CardStack; + this->m_scene.addItem(this->m_pDeck); + + this->m_pDeck->setShowRedealCircle(); + + + // if a card is double clicked that means we need to flip over the next set of cards + this->connect(this->m_pDeck,SIGNAL(cardClicked(CardStack*,uint)), + this,SLOT(slotFlipCards(CardStack*,uint))); + + // if there are no cards in the deck and the pad is clicked that means we need + // to flip the deck back over. If the version of the game is not No redeals. + this->connect(this->m_pDeck,SIGNAL(padClicked(CardStack*)), + this,SLOT(slotRedealCards(CardStack*))); + + this->m_pFlipDeck=new KlondikeFlipStack; + this->m_scene.addItem(this->m_pFlipDeck); + + this->connect(this->m_pFlipDeck,SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + this->connect(this->m_pFlipDeck,SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotStackCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord))); + + + + // hook up the animation signal for flipping cards over from the deck to the flip + // stack. And then back. + this->connect(&m_sToSFlipAni,SIGNAL(cardsMoved(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +bool KlondikeBoard::isGameWon()const +{ + bool rc=true; + + for (unsigned int i=0;im_homeVector.size();i++) + { + if (!this->m_homeVector[i]->isStackComplete()) + { + rc=false; + break; + } + } + + return rc; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +bool KlondikeBoard::isGameWonNotComplete()const +{ + bool rc=false; + + rc=m_pDeck->isEmpty(); + + if (rc) + { + rc=this->m_pFlipDeck->cardsAscendingTopToBottom(); + } + + if (rc) + { + for (unsigned int i=0;im_stackVector.size();i++) + { + if (!(this->m_stackVector[i]->cardsAscendingTopToBottom() && + this->m_stackVector[i]->allCardsFaceUp())) + { + rc=false; + break; + } + } + } + + return rc; + +} diff --git a/plugins/qsolocards_plugin/KlondikeBoard.h b/plugins/qsolocards_plugin/KlondikeBoard.h new file mode 100644 index 000000000..016871466 --- /dev/null +++ b/plugins/qsolocards_plugin/KlondikeBoard.h @@ -0,0 +1,115 @@ +/* + 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 . +*/ + +#ifndef KLONDIKEBOARD_H +#define KLONDIKEBOARD_H + +#include "GameBoard.h" +#include "KlondikeStack.h" +#include "KlondikeHomeStack.h" +#include "KlondikeFlipStack.h" +#include "CardStack.h" +#include "StackToStackFlipAni.h" + +#include + + +class KlondikeBoard : public GameBoard +{ + Q_OBJECT +public: + enum GameType + { + NoRedeals=0, + FlipOne=1, + FlipThree=3 + }; + + static const QString GameTypeKeyStr; + + KlondikeBoard(QWidget * pParent=NULL); + ~KlondikeBoard(); + + virtual void undoMove(); + virtual void redoMove(); + + void restartGame(); + + bool getHint(CardStack * & pSrcWidget, + unsigned int & srcStackIndex, + CardStack * & pDstWidget); + + inline bool hasDemo() const {return true;} + + void newGame(); + + void addGameMenuItems(QMenu & menu); + + void loadSettings(const QSettings & settings); + void saveSettings(QSettings & settings); + + inline bool isCheating() const {return m_cheat;} + + void setCheat(bool cheat); + + inline bool supportsScore() const{return true;} + +public slots: + void slotFlipCards(CardStack * pCardStackWidget=NULL,unsigned int index=0); + void slotRedealCards(CardStack * pCardStackWidget=NULL); + + void slotStackCardsClicked(CardStack * pCardStackWidget, + const PlayingCardVector & cardVector, + const CardMoveRecord &); + void slotHomeCardsClicked(CardStack * pCardStackWidget, + const PlayingCardVector & cardVector, + const CardMoveRecord &); + + void slotSetNoRedeals(); + void slotSetFlipOne(); + void slotSetFlipThree(); + +protected: + void calcScore(); + + virtual void resizeEvent (QResizeEvent * event); + + bool runDemo(bool stopWhenNoMore=true); + + virtual void createStacks(); + + bool isGameWon()const; + bool isGameWonNotComplete()const; + +private: + + CardStack * m_pDeck; + KlondikeFlipStack * m_pFlipDeck; + + std::vector m_homeVector; // we will have 4 items in this vector one for each suit + std::vector m_stackVector; // we will have 7 items in this vector + + bool m_cheat; + + GameType m_gameType; + unsigned int m_flipNum; + + StackToStackFlipAni m_sToSFlipAni; +}; + +#endif // KLONDIKEBOARD_H diff --git a/plugins/qsolocards_plugin/KlondikeFlipStack.cpp b/plugins/qsolocards_plugin/KlondikeFlipStack.cpp new file mode 100644 index 000000000..3db1d2a8c --- /dev/null +++ b/plugins/qsolocards_plugin/KlondikeFlipStack.cpp @@ -0,0 +1,259 @@ +/* + 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 "KlondikeFlipStack.h" +#include "CardPixmaps.h" + +#include +#include + +const qreal KlondikeFlipStack::ExposedPrecent=.18; + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +KlondikeFlipStack::KlondikeFlipStack() + :CardStack(), + m_bRectVector(), + m_cardsShown(1), + m_firstShowCard(0) +{ +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +KlondikeFlipStack::~KlondikeFlipStack() +{ +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +QPointF KlondikeFlipStack::getGlobalCardAddPt() const +{ + QPointF pt(0,0); + + const PlayingCardVector & cardVector=this->getCardVector(); + + // We are going to do this by the bounding rects and not by actual cards + // in the stacks. That way we can add something before doing animations + // and then update the display when the animation is complete + if (m_bRectVector.size()>0 && cardVector.size()>=m_bRectVector.size()) + { + pt=m_bRectVector[m_bRectVector.size()-1].topLeft(); + + pt.rx()+=this->getOverlapIncrement(cardVector,m_bRectVector.size()-1,m_firstShowCard); + } + + return mapToScene(pt); +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +QPointF KlondikeFlipStack::getGlobalLastCardPt() const +{ + QPointF pt(0,0); + + const PlayingCardVector & cardVector=this->getCardVector(); + + // We are going to do this by the bounding rects and not by actual cards + // in the stacks. That way we can add something before doing animations + // and then update the display when the animation is complete + if (m_bRectVector.size()>0 && cardVector.size()>=m_bRectVector.size()) + { + pt=m_bRectVector[m_bRectVector.size()-1].topLeft(); + } + + return mapToScene(pt); +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +QPointF KlondikeFlipStack::getGlobalCardPt(int index) const +{ + QPointF pt(0,0); + + if (index>=0 && index<(int)m_bRectVector.size()) + { + pt=m_bRectVector[index].topLeft(); + } + + return mapToScene(pt); +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +void KlondikeFlipStack::updateStack() +{ + PlayingCardVector cardVector=this->getCardVector(); + m_bRectVector.clear(); + + // if the stack has no cards in it just call the base + // class to render the empty stack. + if (0==cardVector.size()) + { + CardStack::updateStack(); + return; + } + + // figure out the index of the first card to show + if (m_cardsShown>=cardVector.size()) + { + m_firstShowCard=0; + } + else + { + m_firstShowCard=cardVector.size()-m_cardsShown; + } + + // now calc the size of the pixmap we will need + QSize pixmapSize; + + this->calcPixmapSize(cardVector,pixmapSize,m_firstShowCard); + + QPixmap pixmap(pixmapSize); + // for linux the transparent fill must be done before + // we associate the pixmap with the painter + pixmap.fill(Qt::transparent); + + QPainter painter; + + painter.begin(&pixmap); + + QPoint pt(0,0); + QSize cardSize(CardPixmaps::getInst().getCardSize()); + unsigned int i; + + for (i=0;i=m_firstShowCard) + { + bool hl=((hintHighlightIndex()>=0 && hintHighlightIndex()<=(int)i) || + ((cardVector.size()-1==i) && isHighlighted())); + + if (cardVector[i].isFaceUp()) + { + painter.drawPixmap(pt,CardPixmaps::getInst().getCardPixmap(cardVector[i],hl)); + } + else + { + painter.drawPixmap(pt,CardPixmaps::getInst().getCardBackPixmap(hl)); + } + } + + if (cardVector.size()-1==i) + { + m_bRectVector.push_back(QRectF(QPoint(pt.x(),0), + cardSize)); + } + else + { + m_bRectVector.push_back(QRectF(QPoint(pt.x(),0), + QSize(incrementValue,cardSize.height()))); + } + + // increment the point that we are going to paint the + // card pixmap onto this pixmap + pt.rx()+=incrementValue; + } + + painter.end(); + + this->setPixmap(pixmap); +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +bool KlondikeFlipStack::getCardIndex(const QPointF & pos,unsigned int & index) +{ + bool rc=false; + unsigned int i; + + // go through the bounding rect backwards. The ones lower for cards that are + // not visible are just place holders. + for(i=m_bRectVector.size();i>0;i--) + { + if (m_bRectVector[i-1].contains(pos)) + { + index=i-1; + rc=true; + break; + } + } + + return rc; +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +void KlondikeFlipStack::calcPixmapSize(const PlayingCardVector & cardVector, + QSize & size,unsigned int showIndex) +{ + QSize cardSize(CardPixmaps::getInst().getCardSize()); + unsigned int i; + + size.setWidth(0); + size.setHeight(cardSize.height()); + + for(i=0;igetOverlapIncrement(cardVector,i,showIndex); + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +int KlondikeFlipStack::getOverlapIncrement(const PlayingCardVector & cardVector, + unsigned int index,unsigned int showIndex) const +{ + int increment=0; + + if (index=showIndex) + { + increment=CardPixmaps::getInst().getCardSize().width()*ExposedPrecent; + } + } + + return increment; +} + + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +bool KlondikeFlipStack::canMoveCard(unsigned int index) const +{ + bool rc=false; + + // ok the only time a card can be moved is if the card is the last in the stack. + if (!this->isEmpty() && (index==(this->getCardVector().size()-1))) + { + rc=true; + } + + return rc; +} diff --git a/plugins/qsolocards_plugin/KlondikeFlipStack.h b/plugins/qsolocards_plugin/KlondikeFlipStack.h new file mode 100644 index 000000000..43035f46a --- /dev/null +++ b/plugins/qsolocards_plugin/KlondikeFlipStack.h @@ -0,0 +1,62 @@ +/* + 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 . +*/ + +#ifndef KLONDIKEFLIPSTACK_H +#define KLONDIKEFLIPSTACK_H + +#include "CardStack.h" +#include +#include + +class KlondikeFlipStack : public CardStack +{ + Q_OBJECT +public: + static const qreal ExposedPrecent; + + KlondikeFlipStack(); + virtual ~KlondikeFlipStack(); + + inline void cardsToShow(unsigned int cardsToShow=1){m_cardsShown=((0==cardsToShow)?1:cardsToShow);} + + // this function gets the point in the scene that a card would be added to this stack. + virtual QPointF getGlobalCardAddPt() const; + virtual QPointF getGlobalLastCardPt() const; + virtual QPointF getGlobalCardPt(int index) const; + + virtual void updateStack(); + +protected: + virtual bool getCardIndex(const QPointF & pos,unsigned int & index); + + void calcPixmapSize(const PlayingCardVector & cardVector, + QSize & size,unsigned int showIndex); + + int getOverlapIncrement(const PlayingCardVector & cardVector, + unsigned int index, + unsigned int showIndex) const; + + bool canMoveCard(unsigned int index) const; + +private: + std::vector m_bRectVector; + unsigned int m_cardsShown; + unsigned int m_firstShowCard; +}; + +#endif // KLONDIKEFLIPSTACK_H diff --git a/plugins/qsolocards_plugin/KlondikeHomeStack.cpp b/plugins/qsolocards_plugin/KlondikeHomeStack.cpp new file mode 100644 index 000000000..acca976a2 --- /dev/null +++ b/plugins/qsolocards_plugin/KlondikeHomeStack.cpp @@ -0,0 +1,75 @@ +/* + 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 "KlondikeHomeStack.h" + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +KlondikeHomeStack::KlondikeHomeStack() + :CardStack() +{ +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +KlondikeHomeStack::~KlondikeHomeStack() +{ +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +bool KlondikeHomeStack::canAddCards(const PlayingCardVector & newCardVector) +{ + bool rc=false; + const PlayingCardVector & cardVector=this->getCardVector(); + + if (1==newCardVector.size()) + { + + if (this->isEmpty() && PlayingCard::Ace==newCardVector[0].getIndex()) + { + rc=true; + } + else if (!this->isEmpty() && + cardVector[cardVector.size()-1].isSameSuit(newCardVector[0]) && + cardVector[cardVector.size()-1].isNextCardIndex(newCardVector[0])) + { + rc=true; + } + } + + return rc; +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// +bool KlondikeHomeStack::canMoveCard(unsigned int index) const +{ + bool rc=false; + + if (!this->isEmpty()) + { + const PlayingCardVector & cardVector=this->getCardVector(); + + if ((cardVector.size()-1)==index) + { + rc=true; + } + } + return rc; +} diff --git a/plugins/qsolocards_plugin/KlondikeHomeStack.h b/plugins/qsolocards_plugin/KlondikeHomeStack.h new file mode 100644 index 000000000..4d4d0f307 --- /dev/null +++ b/plugins/qsolocards_plugin/KlondikeHomeStack.h @@ -0,0 +1,40 @@ +/* + 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 . +*/ + +#ifndef KLONDIKEHOMESTACK_H +#define KLONDIKEHOMESTACK_H + +#include "CardStack.h" + +class KlondikeHomeStack : public CardStack +{ + Q_OBJECT +public: + KlondikeHomeStack(); + ~KlondikeHomeStack(); + + inline bool isStackComplete(){return getCardVector().size()==PlayingCard::MaxCardIndex;} + + inline int score() const {return getCardVector().size();} + bool canAddCards(const PlayingCardVector &); +protected: + bool canMoveCard(unsigned int index) const; + +}; + +#endif // KLONDIKEHOMESTACK_H diff --git a/plugins/qsolocards_plugin/KlondikeStack.cpp b/plugins/qsolocards_plugin/KlondikeStack.cpp new file mode 100644 index 000000000..ee95fea99 --- /dev/null +++ b/plugins/qsolocards_plugin/KlondikeStack.cpp @@ -0,0 +1,91 @@ +/* + 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 "KlondikeStack.h" + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +KlondikeStack::KlondikeStack() + :VCardStack(), + m_cheat(false) +{ + this->setAutoTopCardUp(); +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +KlondikeStack::~KlondikeStack() +{ +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +bool KlondikeStack::canAddCards(const PlayingCardVector & newCardVector) +{ + if (m_cheat) + { + return true; + } + + bool rc=false; + const PlayingCardVector & cardVector=this->getCardVector(); + + if (newCardVector.size()>0) + { + // if there are no cards in the stack then the first card + // must be a king. + if (0==cardVector.size() && + PlayingCard::King==newCardVector[0].getIndex()) + { + rc=true; + } + else if (cardVector.size()>0 && + (cardVector[cardVector.size()-1].isRed() ^ newCardVector[0].isRed()) && + cardVector[cardVector.size()-1].isPrevCardIndex(newCardVector[0]) && + cardVector[cardVector.size()-1].isFaceUp()) + { + rc=true; + } + } + + return rc; +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +bool KlondikeStack::canMoveCard(unsigned int index) const +{ + if (m_cheat) + { + return true; + } + + bool rc=false; + const PlayingCardVector & cardVector=this->getCardVector(); + + // ok if we have cards in the stack and the index is valid + // see if we can move it. + // For klondike as long as the card is faceup we should be able to move the + // card and all cards after it in the stack. + if (cardVector.size()>0 && index. +*/ + +#ifndef KLONDIKESTACK_H +#define KLONDIKESTACK_H + +#include "VCardStack.h" + +class KlondikeStack : public VCardStack +{ + Q_OBJECT +public: + KlondikeStack(); + ~KlondikeStack(); + inline bool isCheating() const{return m_cheat;} + + inline void setCheat(bool cheat=true){m_cheat=cheat;} + + bool canAddCards(const PlayingCardVector &); + +protected: + bool canMoveCard(unsigned int index) const; + +private: + bool m_cheat; + +}; + +#endif // KLONDIKESTACK_H diff --git a/plugins/qsolocards_plugin/Makefile b/plugins/qsolocards_plugin/Makefile new file mode 100644 index 000000000..f1b3f1738 --- /dev/null +++ b/plugins/qsolocards_plugin/Makefile @@ -0,0 +1,142 @@ +############################################################################# +# Makefile for building: qsolocards_plugin +# Generated by qmake (2.01a) (Qt 4.6.1) on: Mo 15. Feb 12:18:27 2010 +# Project: qsolocards_plugin.pro +# Template: lib +# Command: d:\qt\2010.01\qt\bin\qmake.exe -win32 -o Makefile qsolocards_plugin.pro +############################################################################# + +first: release +install: release-install +uninstall: release-uninstall +MAKEFILE = Makefile +QMAKE = d:\qt\2010.01\qt\bin\qmake.exe +DEL_FILE = del +CHK_DIR_EXISTS= if not exist +MKDIR = mkdir +COPY = copy /y +COPY_FILE = $(COPY) +COPY_DIR = xcopy /s /q /y /i +INSTALL_FILE = $(COPY_FILE) +INSTALL_PROGRAM = $(COPY_FILE) +INSTALL_DIR = $(COPY_DIR) +DEL_FILE = del +SYMLINK = +DEL_DIR = rmdir +MOVE = move +CHK_DIR_EXISTS= if not exist +MKDIR = mkdir +SUBTARGETS = \ + release \ + debug + +release: $(MAKEFILE).Release FORCE + $(MAKE) -f $(MAKEFILE).Release +release-make_default: $(MAKEFILE).Release FORCE + $(MAKE) -f $(MAKEFILE).Release +release-make_first: $(MAKEFILE).Release FORCE + $(MAKE) -f $(MAKEFILE).Release first +release-all: $(MAKEFILE).Release FORCE + $(MAKE) -f $(MAKEFILE).Release all +release-clean: $(MAKEFILE).Release FORCE + $(MAKE) -f $(MAKEFILE).Release clean +release-distclean: $(MAKEFILE).Release FORCE + $(MAKE) -f $(MAKEFILE).Release distclean +release-install: $(MAKEFILE).Release FORCE + $(MAKE) -f $(MAKEFILE).Release install +release-uninstall: $(MAKEFILE).Release FORCE + $(MAKE) -f $(MAKEFILE).Release uninstall +debug: $(MAKEFILE).Debug FORCE + $(MAKE) -f $(MAKEFILE).Debug +debug-make_default: $(MAKEFILE).Debug FORCE + $(MAKE) -f $(MAKEFILE).Debug +debug-make_first: $(MAKEFILE).Debug FORCE + $(MAKE) -f $(MAKEFILE).Debug first +debug-all: $(MAKEFILE).Debug FORCE + $(MAKE) -f $(MAKEFILE).Debug all +debug-clean: $(MAKEFILE).Debug FORCE + $(MAKE) -f $(MAKEFILE).Debug clean +debug-distclean: $(MAKEFILE).Debug FORCE + $(MAKE) -f $(MAKEFILE).Debug distclean +debug-install: $(MAKEFILE).Debug FORCE + $(MAKE) -f $(MAKEFILE).Debug install +debug-uninstall: $(MAKEFILE).Debug FORCE + $(MAKE) -f $(MAKEFILE).Debug uninstall + +Makefile: qsolocards_plugin.pro d:/Qt/2010.01/qt/mkspecs/default/qmake.conf d:/Qt/2010.01/qt/mkspecs/qconfig.pri \ + d:/Qt/2010.01/qt/mkspecs/features/qt_functions.prf \ + d:/Qt/2010.01/qt/mkspecs/features/qt_config.prf \ + d:/Qt/2010.01/qt/mkspecs/features/exclusive_builds.prf \ + d:/Qt/2010.01/qt/mkspecs/features/default_pre.prf \ + d:/Qt/2010.01/qt/mkspecs/features/win32/default_pre.prf \ + d:/Qt/2010.01/qt/mkspecs/features/release.prf \ + d:/Qt/2010.01/qt/mkspecs/features/debug_and_release.prf \ + d:/Qt/2010.01/qt/mkspecs/features/default_post.prf \ + d:/Qt/2010.01/qt/mkspecs/features/win32/default_post.prf \ + d:/Qt/2010.01/qt/mkspecs/features/win32/rtti.prf \ + d:/Qt/2010.01/qt/mkspecs/features/win32/exceptions.prf \ + d:/Qt/2010.01/qt/mkspecs/features/win32/stl.prf \ + d:/Qt/2010.01/qt/mkspecs/features/shared.prf \ + d:/Qt/2010.01/qt/mkspecs/features/dll.prf \ + d:/Qt/2010.01/qt/mkspecs/features/warn_on.prf \ + d:/Qt/2010.01/qt/mkspecs/features/qt.prf \ + d:/Qt/2010.01/qt/mkspecs/features/win32/thread.prf \ + d:/Qt/2010.01/qt/mkspecs/features/moc.prf \ + d:/Qt/2010.01/qt/mkspecs/features/win32/windows.prf \ + d:/Qt/2010.01/qt/mkspecs/features/resources.prf \ + d:/Qt/2010.01/qt/mkspecs/features/uic.prf \ + d:/Qt/2010.01/qt/mkspecs/features/yacc.prf \ + d:/Qt/2010.01/qt/mkspecs/features/lex.prf + $(QMAKE) -win32 -o Makefile qsolocards_plugin.pro +d:\Qt\2010.01\qt\mkspecs\qconfig.pri: +d:\Qt\2010.01\qt\mkspecs\features\qt_functions.prf: +d:\Qt\2010.01\qt\mkspecs\features\qt_config.prf: +d:\Qt\2010.01\qt\mkspecs\features\exclusive_builds.prf: +d:\Qt\2010.01\qt\mkspecs\features\default_pre.prf: +d:\Qt\2010.01\qt\mkspecs\features\win32\default_pre.prf: +d:\Qt\2010.01\qt\mkspecs\features\release.prf: +d:\Qt\2010.01\qt\mkspecs\features\debug_and_release.prf: +d:\Qt\2010.01\qt\mkspecs\features\default_post.prf: +d:\Qt\2010.01\qt\mkspecs\features\win32\default_post.prf: +d:\Qt\2010.01\qt\mkspecs\features\win32\rtti.prf: +d:\Qt\2010.01\qt\mkspecs\features\win32\exceptions.prf: +d:\Qt\2010.01\qt\mkspecs\features\win32\stl.prf: +d:\Qt\2010.01\qt\mkspecs\features\shared.prf: +d:\Qt\2010.01\qt\mkspecs\features\dll.prf: +d:\Qt\2010.01\qt\mkspecs\features\warn_on.prf: +d:\Qt\2010.01\qt\mkspecs\features\qt.prf: +d:\Qt\2010.01\qt\mkspecs\features\win32\thread.prf: +d:\Qt\2010.01\qt\mkspecs\features\moc.prf: +d:\Qt\2010.01\qt\mkspecs\features\win32\windows.prf: +d:\Qt\2010.01\qt\mkspecs\features\resources.prf: +d:\Qt\2010.01\qt\mkspecs\features\uic.prf: +d:\Qt\2010.01\qt\mkspecs\features\yacc.prf: +d:\Qt\2010.01\qt\mkspecs\features\lex.prf: +qmake: qmake_all FORCE + @$(QMAKE) -win32 -o Makefile qsolocards_plugin.pro + +qmake_all: FORCE + +make_default: release-make_default debug-make_default FORCE +make_first: release-make_first debug-make_first FORCE +all: release-all debug-all FORCE +clean: release-clean debug-clean FORCE + -$(DEL_FILE) ..\..\bin\libqsolocards_plugin0.a +distclean: release-distclean debug-distclean FORCE + -$(DEL_FILE) Makefile + +release-mocclean: $(MAKEFILE).Release + $(MAKE) -f $(MAKEFILE).Release mocclean +debug-mocclean: $(MAKEFILE).Debug + $(MAKE) -f $(MAKEFILE).Debug mocclean +mocclean: release-mocclean debug-mocclean + +release-mocables: $(MAKEFILE).Release + $(MAKE) -f $(MAKEFILE).Release mocables +debug-mocables: $(MAKEFILE).Debug + $(MAKE) -f $(MAKEFILE).Debug mocables +mocables: release-mocables debug-mocables +FORCE: + +$(MAKEFILE).Release: Makefile +$(MAKEFILE).Debug: Makefile diff --git a/plugins/qsolocards_plugin/Makefile.Debug b/plugins/qsolocards_plugin/Makefile.Debug new file mode 100644 index 000000000..4f842faa9 --- /dev/null +++ b/plugins/qsolocards_plugin/Makefile.Debug @@ -0,0 +1,991 @@ +############################################################################# +# Makefile for building: qsolocards_plugin +# Generated by qmake (2.01a) (Qt 4.6.1) on: Mo 15. Feb 12:18:27 2010 +# Project: qsolocards_plugin.pro +# Template: lib +############################################################################# + +####### Compiler, tools and options + +CC = gcc +CXX = g++ +DEFINES = -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_PLUGIN -DQT_SVG_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT +CFLAGS = -g -Wall $(DEFINES) +CXXFLAGS = -DVER_MAJ=0 -DVER_MIN=99 -DVER_PAT=1 -frtti -fexceptions -mthreads -Wall $(DEFINES) +INCPATH = -I"d:\Qt\2010.01\qt\include\QtCore" -I"d:\Qt\2010.01\qt\include\QtGui" -I"d:\Qt\2010.01\qt\include\QtSvg" -I"d:\Qt\2010.01\qt\include" -I".." -I"d:\Qt\2010.01\qt\include\ActiveQt" -I"temp\moc" -I"d:\Qt\2010.01\qt\mkspecs\default" +LINK = g++ +LFLAGS = -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc -mthreads -Wl -shared -Wl,--out-implib,..\..\bin\libqsolocards_plugin0.a +LIBS = -L"d:\Qt\2010.01\qt\lib" -lQtSvgd4 -lQtGuid4 -lQtCored4 +QMAKE = d:\qt\2010.01\qt\bin\qmake.exe +IDC = d:\Qt\2010.01\qt\bin\idc.exe +IDL = midl +ZIP = zip -r -9 +DEF_FILE = +RES_FILE = +COPY = copy /y +COPY_FILE = $(COPY) +COPY_DIR = xcopy /s /q /y /i +DEL_FILE = del +DEL_DIR = rmdir +MOVE = move +CHK_DIR_EXISTS= if not exist +MKDIR = mkdir +INSTALL_FILE = $(COPY_FILE) +INSTALL_PROGRAM = $(COPY_FILE) +INSTALL_DIR = $(COPY_DIR) + +####### Output directory + +OBJECTS_DIR = temp\obj + +####### Files + +SOURCES = QSoloCardsPlugin.cpp \ + main.cpp \ + mainwindow.cpp \ + PlayingCard.cpp \ + CardDeck.cpp \ + CardPixmaps.cpp \ + CardStack.cpp \ + DragCardStack.cpp \ + VCardStack.cpp \ + CardAnimationLock.cpp \ + StackToStackAniMove.cpp \ + DealAnimation.cpp \ + FlipAnimation.cpp \ + StackToStackFlipAni.cpp \ + GameBoard.cpp \ + CardMoveRecord.cpp \ + About.cpp \ + Help.cpp \ + GameMgr.cpp \ + SpiderBoard.cpp \ + SpiderHomeStack.cpp \ + SpiderStack.cpp \ + KlondikeStack.cpp \ + KlondikeFlipStack.cpp \ + KlondikeHomeStack.cpp \ + KlondikeBoard.cpp \ + FreeCellBoard.cpp \ + FreeCellDeck.cpp \ + FreeCellStack.cpp \ + FreeCellHome.cpp \ + FreeCellFree.cpp \ + Spider3DeckBoard.cpp \ + SpideretteBoard.cpp \ + YukonBoard.cpp temp\moc\moc_QSoloCardsPlugin.cpp \ + temp\moc\moc_mainwindow.cpp \ + temp\moc\moc_CardStack.cpp \ + temp\moc\moc_DragCardStack.cpp \ + temp\moc\moc_VCardStack.cpp \ + temp\moc\moc_CardAnimationLock.cpp \ + temp\moc\moc_StackToStackAniMove.cpp \ + temp\moc\moc_DealAnimation.cpp \ + temp\moc\moc_FlipAnimation.cpp \ + temp\moc\moc_StackToStackFlipAni.cpp \ + temp\moc\moc_GameBoard.cpp \ + temp\moc\moc_About.cpp \ + temp\moc\moc_Help.cpp \ + temp\moc\moc_SpiderBoard.cpp \ + temp\moc\moc_SpiderStack.cpp \ + temp\moc\moc_KlondikeStack.cpp \ + temp\moc\moc_KlondikeFlipStack.cpp \ + temp\moc\moc_KlondikeHomeStack.cpp \ + temp\moc\moc_KlondikeBoard.cpp \ + temp\moc\moc_FreeCellBoard.cpp \ + temp\moc\moc_FreeCellDeck.cpp \ + temp\moc\moc_FreeCellStack.cpp \ + temp\moc\moc_FreeCellHome.cpp \ + temp\moc\moc_FreeCellFree.cpp \ + temp\moc\moc_Spider3DeckBoard.cpp \ + temp\moc\moc_SpideretteBoard.cpp \ + temp\moc\moc_YukonBoard.cpp \ + temp\qrc\qrc_QSoloCards.cpp +OBJECTS = temp/obj/QSoloCardsPlugin.o \ + temp/obj/main.o \ + temp/obj/mainwindow.o \ + temp/obj/PlayingCard.o \ + temp/obj/CardDeck.o \ + temp/obj/CardPixmaps.o \ + temp/obj/CardStack.o \ + temp/obj/DragCardStack.o \ + temp/obj/VCardStack.o \ + temp/obj/CardAnimationLock.o \ + temp/obj/StackToStackAniMove.o \ + temp/obj/DealAnimation.o \ + temp/obj/FlipAnimation.o \ + temp/obj/StackToStackFlipAni.o \ + temp/obj/GameBoard.o \ + temp/obj/CardMoveRecord.o \ + temp/obj/About.o \ + temp/obj/Help.o \ + temp/obj/GameMgr.o \ + temp/obj/SpiderBoard.o \ + temp/obj/SpiderHomeStack.o \ + temp/obj/SpiderStack.o \ + temp/obj/KlondikeStack.o \ + temp/obj/KlondikeFlipStack.o \ + temp/obj/KlondikeHomeStack.o \ + temp/obj/KlondikeBoard.o \ + temp/obj/FreeCellBoard.o \ + temp/obj/FreeCellDeck.o \ + temp/obj/FreeCellStack.o \ + temp/obj/FreeCellHome.o \ + temp/obj/FreeCellFree.o \ + temp/obj/Spider3DeckBoard.o \ + temp/obj/SpideretteBoard.o \ + temp/obj/YukonBoard.o \ + temp/obj/moc_QSoloCardsPlugin.o \ + temp/obj/moc_mainwindow.o \ + temp/obj/moc_CardStack.o \ + temp/obj/moc_DragCardStack.o \ + temp/obj/moc_VCardStack.o \ + temp/obj/moc_CardAnimationLock.o \ + temp/obj/moc_StackToStackAniMove.o \ + temp/obj/moc_DealAnimation.o \ + temp/obj/moc_FlipAnimation.o \ + temp/obj/moc_StackToStackFlipAni.o \ + temp/obj/moc_GameBoard.o \ + temp/obj/moc_About.o \ + temp/obj/moc_Help.o \ + temp/obj/moc_SpiderBoard.o \ + temp/obj/moc_SpiderStack.o \ + temp/obj/moc_KlondikeStack.o \ + temp/obj/moc_KlondikeFlipStack.o \ + temp/obj/moc_KlondikeHomeStack.o \ + temp/obj/moc_KlondikeBoard.o \ + temp/obj/moc_FreeCellBoard.o \ + temp/obj/moc_FreeCellDeck.o \ + temp/obj/moc_FreeCellStack.o \ + temp/obj/moc_FreeCellHome.o \ + temp/obj/moc_FreeCellFree.o \ + temp/obj/moc_Spider3DeckBoard.o \ + temp/obj/moc_SpideretteBoard.o \ + temp/obj/moc_YukonBoard.o \ + temp/obj/qrc_QSoloCards.o +DIST = +QMAKE_TARGET = qsolocards_plugin +DESTDIR = ..\..\bin\ #avoid trailing-slash linebreak +TARGET = qsolocards_plugin0.dll +DESTDIR_TARGET = ..\..\bin\qsolocards_plugin0.dll + +####### Implicit rules + +.SUFFIXES: .cpp .cc .cxx .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + +first: all +all: Makefile.Debug $(DESTDIR_TARGET) + +$(DESTDIR_TARGET): $(OBJECTS) + $(LINK) $(LFLAGS) -o $(DESTDIR_TARGET) object_script.qsolocards_plugin.Debug $(LIBS) + + +qmake: FORCE + @$(QMAKE) -win32 -o Makefile.Debug qsolocards_plugin.pro + +dist: + $(ZIP) qsolocards_plugin.zip $(SOURCES) $(DIST) qsolocards_plugin.pro d:\Qt\2010.01\qt\mkspecs\qconfig.pri d:\Qt\2010.01\qt\mkspecs\features\qt_functions.prf d:\Qt\2010.01\qt\mkspecs\features\qt_config.prf d:\Qt\2010.01\qt\mkspecs\features\exclusive_builds.prf d:\Qt\2010.01\qt\mkspecs\features\default_pre.prf d:\Qt\2010.01\qt\mkspecs\features\win32\default_pre.prf d:\Qt\2010.01\qt\mkspecs\features\debug.prf d:\Qt\2010.01\qt\mkspecs\features\debug_and_release.prf d:\Qt\2010.01\qt\mkspecs\features\default_post.prf d:\Qt\2010.01\qt\mkspecs\features\win32\default_post.prf d:\Qt\2010.01\qt\mkspecs\features\build_pass.prf d:\Qt\2010.01\qt\mkspecs\features\win32\rtti.prf d:\Qt\2010.01\qt\mkspecs\features\win32\exceptions.prf d:\Qt\2010.01\qt\mkspecs\features\win32\stl.prf d:\Qt\2010.01\qt\mkspecs\features\shared.prf d:\Qt\2010.01\qt\mkspecs\features\dll.prf d:\Qt\2010.01\qt\mkspecs\features\warn_on.prf d:\Qt\2010.01\qt\mkspecs\features\qt.prf d:\Qt\2010.01\qt\mkspecs\features\win32\thread.prf d:\Qt\2010.01\qt\mkspecs\features\moc.prf d:\Qt\2010.01\qt\mkspecs\features\win32\windows.prf d:\Qt\2010.01\qt\mkspecs\features\resources.prf d:\Qt\2010.01\qt\mkspecs\features\uic.prf d:\Qt\2010.01\qt\mkspecs\features\yacc.prf d:\Qt\2010.01\qt\mkspecs\features\lex.prf HEADERS RESOURCES IMAGES SOURCES OBJECTIVE_SOURCES FORMS YACCSOURCES YACCSOURCES LEXSOURCES + +clean: compiler_clean + -$(DEL_FILE) temp\obj\QSoloCardsPlugin.o temp\obj\main.o temp\obj\mainwindow.o temp\obj\PlayingCard.o temp\obj\CardDeck.o temp\obj\CardPixmaps.o temp\obj\CardStack.o temp\obj\DragCardStack.o temp\obj\VCardStack.o temp\obj\CardAnimationLock.o temp\obj\StackToStackAniMove.o temp\obj\DealAnimation.o temp\obj\FlipAnimation.o temp\obj\StackToStackFlipAni.o temp\obj\GameBoard.o temp\obj\CardMoveRecord.o temp\obj\About.o temp\obj\Help.o temp\obj\GameMgr.o temp\obj\SpiderBoard.o temp\obj\SpiderHomeStack.o temp\obj\SpiderStack.o temp\obj\KlondikeStack.o temp\obj\KlondikeFlipStack.o temp\obj\KlondikeHomeStack.o temp\obj\KlondikeBoard.o temp\obj\FreeCellBoard.o temp\obj\FreeCellDeck.o temp\obj\FreeCellStack.o temp\obj\FreeCellHome.o temp\obj\FreeCellFree.o temp\obj\Spider3DeckBoard.o temp\obj\SpideretteBoard.o temp\obj\YukonBoard.o temp\obj\moc_QSoloCardsPlugin.o temp\obj\moc_mainwindow.o temp\obj\moc_CardStack.o temp\obj\moc_DragCardStack.o temp\obj\moc_VCardStack.o temp\obj\moc_CardAnimationLock.o temp\obj\moc_StackToStackAniMove.o temp\obj\moc_DealAnimation.o temp\obj\moc_FlipAnimation.o temp\obj\moc_StackToStackFlipAni.o temp\obj\moc_GameBoard.o temp\obj\moc_About.o temp\obj\moc_Help.o temp\obj\moc_SpiderBoard.o temp\obj\moc_SpiderStack.o temp\obj\moc_KlondikeStack.o temp\obj\moc_KlondikeFlipStack.o temp\obj\moc_KlondikeHomeStack.o temp\obj\moc_KlondikeBoard.o temp\obj\moc_FreeCellBoard.o temp\obj\moc_FreeCellDeck.o temp\obj\moc_FreeCellStack.o temp\obj\moc_FreeCellHome.o temp\obj\moc_FreeCellFree.o temp\obj\moc_Spider3DeckBoard.o temp\obj\moc_SpideretteBoard.o temp\obj\moc_YukonBoard.o temp\obj\qrc_QSoloCards.o + -$(DEL_FILE) ..\..\bin\libqsolocards_plugin0.a + +distclean: clean + -$(DEL_FILE) $(DESTDIR_TARGET) + -$(DEL_FILE) Makefile.Debug + +mocclean: compiler_moc_header_clean compiler_moc_source_clean + +mocables: compiler_moc_header_make_all compiler_moc_source_make_all + +compiler_moc_header_make_all: temp/moc/moc_QSoloCardsPlugin.cpp temp/moc/moc_mainwindow.cpp temp/moc/moc_CardStack.cpp temp/moc/moc_DragCardStack.cpp temp/moc/moc_VCardStack.cpp temp/moc/moc_CardAnimationLock.cpp temp/moc/moc_StackToStackAniMove.cpp temp/moc/moc_DealAnimation.cpp temp/moc/moc_FlipAnimation.cpp temp/moc/moc_StackToStackFlipAni.cpp temp/moc/moc_GameBoard.cpp temp/moc/moc_About.cpp temp/moc/moc_Help.cpp temp/moc/moc_SpiderBoard.cpp temp/moc/moc_SpiderStack.cpp temp/moc/moc_KlondikeStack.cpp temp/moc/moc_KlondikeFlipStack.cpp temp/moc/moc_KlondikeHomeStack.cpp temp/moc/moc_KlondikeBoard.cpp temp/moc/moc_FreeCellBoard.cpp temp/moc/moc_FreeCellDeck.cpp temp/moc/moc_FreeCellStack.cpp temp/moc/moc_FreeCellHome.cpp temp/moc/moc_FreeCellFree.cpp temp/moc/moc_Spider3DeckBoard.cpp temp/moc/moc_SpideretteBoard.cpp temp/moc/moc_YukonBoard.cpp +compiler_moc_header_clean: + -$(DEL_FILE) temp\moc\moc_QSoloCardsPlugin.cpp temp\moc\moc_mainwindow.cpp temp\moc\moc_CardStack.cpp temp\moc\moc_DragCardStack.cpp temp\moc\moc_VCardStack.cpp temp\moc\moc_CardAnimationLock.cpp temp\moc\moc_StackToStackAniMove.cpp temp\moc\moc_DealAnimation.cpp temp\moc\moc_FlipAnimation.cpp temp\moc\moc_StackToStackFlipAni.cpp temp\moc\moc_GameBoard.cpp temp\moc\moc_About.cpp temp\moc\moc_Help.cpp temp\moc\moc_SpiderBoard.cpp temp\moc\moc_SpiderStack.cpp temp\moc\moc_KlondikeStack.cpp temp\moc\moc_KlondikeFlipStack.cpp temp\moc\moc_KlondikeHomeStack.cpp temp\moc\moc_KlondikeBoard.cpp temp\moc\moc_FreeCellBoard.cpp temp\moc\moc_FreeCellDeck.cpp temp\moc\moc_FreeCellStack.cpp temp\moc\moc_FreeCellHome.cpp temp\moc\moc_FreeCellFree.cpp temp\moc\moc_Spider3DeckBoard.cpp temp\moc\moc_SpideretteBoard.cpp temp\moc\moc_YukonBoard.cpp +temp/moc/moc_QSoloCardsPlugin.cpp: QSoloCardsPlugin.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 QSoloCardsPlugin.h -o temp\moc\moc_QSoloCardsPlugin.cpp + +temp/moc/moc_mainwindow.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + Help.h \ + About.h \ + GameMgr.h \ + mainwindow.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 mainwindow.h -o temp\moc\moc_mainwindow.cpp + +temp/moc/moc_CardStack.cpp: CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 CardStack.h -o temp\moc\moc_CardStack.cpp + +temp/moc/moc_DragCardStack.cpp: CardDeck.h \ + PlayingCard.h \ + CardMoveRecord.h \ + DragCardStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 DragCardStack.h -o temp\moc\moc_DragCardStack.cpp + +temp/moc/moc_VCardStack.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + VCardStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 VCardStack.h -o temp\moc\moc_VCardStack.cpp + +temp/moc/moc_CardAnimationLock.cpp: CardAnimationLock.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 CardAnimationLock.h -o temp\moc\moc_CardAnimationLock.cpp + +temp/moc/moc_StackToStackAniMove.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 StackToStackAniMove.h -o temp\moc\moc_StackToStackAniMove.cpp + +temp/moc/moc_DealAnimation.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + DealAnimation.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 DealAnimation.h -o temp\moc\moc_DealAnimation.cpp + +temp/moc/moc_FlipAnimation.cpp: CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FlipAnimation.h -o temp\moc\moc_FlipAnimation.cpp + +temp/moc/moc_StackToStackFlipAni.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackFlipAni.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 StackToStackFlipAni.h -o temp\moc\moc_StackToStackFlipAni.cpp + +temp/moc/moc_GameBoard.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + GameBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 GameBoard.h -o temp\moc\moc_GameBoard.cpp + +temp/moc/moc_About.cpp: About.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 About.h -o temp\moc\moc_About.cpp + +temp/moc/moc_Help.cpp: Help.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 Help.h -o temp\moc\moc_Help.cpp + +temp/moc/moc_SpiderBoard.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + SpiderBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 SpiderBoard.h -o temp\moc\moc_SpiderBoard.cpp + +temp/moc/moc_SpiderStack.cpp: VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + SpiderStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 SpiderStack.h -o temp\moc\moc_SpiderStack.cpp + +temp/moc/moc_KlondikeStack.cpp: VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + KlondikeStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 KlondikeStack.h -o temp\moc\moc_KlondikeStack.cpp + +temp/moc/moc_KlondikeFlipStack.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + KlondikeFlipStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 KlondikeFlipStack.h -o temp\moc\moc_KlondikeFlipStack.cpp + +temp/moc/moc_KlondikeHomeStack.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + KlondikeHomeStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 KlondikeHomeStack.h -o temp\moc\moc_KlondikeHomeStack.cpp + +temp/moc/moc_KlondikeBoard.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + KlondikeStack.h \ + VCardStack.h \ + KlondikeHomeStack.h \ + KlondikeFlipStack.h \ + StackToStackFlipAni.h \ + KlondikeBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 KlondikeBoard.h -o temp\moc\moc_KlondikeBoard.cpp + +temp/moc/moc_FreeCellBoard.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + FreeCellDeck.h \ + FreeCellFree.h \ + FreeCellStack.h \ + VCardStack.h \ + FreeCellHome.h \ + FreeCellBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellBoard.h -o temp\moc\moc_FreeCellBoard.cpp + +temp/moc/moc_FreeCellDeck.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + FreeCellDeck.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellDeck.h -o temp\moc\moc_FreeCellDeck.cpp + +temp/moc/moc_FreeCellStack.cpp: VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + FreeCellStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellStack.h -o temp\moc\moc_FreeCellStack.cpp + +temp/moc/moc_FreeCellHome.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + FreeCellHome.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellHome.h -o temp\moc\moc_FreeCellHome.cpp + +temp/moc/moc_FreeCellFree.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + FreeCellFree.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellFree.h -o temp\moc\moc_FreeCellFree.cpp + +temp/moc/moc_Spider3DeckBoard.cpp: SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + Spider3DeckBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 Spider3DeckBoard.h -o temp\moc\moc_Spider3DeckBoard.cpp + +temp/moc/moc_SpideretteBoard.cpp: SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + SpideretteBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 SpideretteBoard.h -o temp\moc\moc_SpideretteBoard.cpp + +temp/moc/moc_YukonBoard.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + FreeCellHome.h \ + FreeCellDeck.h \ + KlondikeStack.h \ + VCardStack.h \ + YukonBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 YukonBoard.h -o temp\moc\moc_YukonBoard.cpp + +compiler_rcc_make_all: temp/qrc/qrc_QSoloCards.cpp +compiler_rcc_clean: + -$(DEL_FILE) temp\qrc\qrc_QSoloCards.cpp +temp/qrc/qrc_QSoloCards.cpp: QSoloCards.qrc \ + images/greenfelt.png \ + images/anglo_bitmap.svg \ + images/sol128x128.png \ + images/sol32x32.png \ + help/FreeCellHelp.html \ + help/SpideretteHelp.html \ + help/YukonHelp.html \ + help/SpiderHelp.html \ + help/Spider3DeckHelp.html \ + help/KlondikeHelp.html \ + help/gpl3.html + d:\Qt\2010.01\qt\bin\rcc.exe -name QSoloCards QSoloCards.qrc -o temp\qrc\qrc_QSoloCards.cpp + +compiler_image_collection_make_all: qmake_image_collection.cpp +compiler_image_collection_clean: + -$(DEL_FILE) qmake_image_collection.cpp +compiler_moc_source_make_all: +compiler_moc_source_clean: +compiler_uic_make_all: +compiler_uic_clean: +compiler_yacc_decl_make_all: +compiler_yacc_decl_clean: +compiler_yacc_impl_make_all: +compiler_yacc_impl_clean: +compiler_lex_make_all: +compiler_lex_clean: +compiler_clean: compiler_moc_header_clean compiler_rcc_clean + + + +####### Compile + +temp/obj/QSoloCardsPlugin.o: QSoloCardsPlugin.cpp QSoloCardsPlugin.h \ + mainwindow.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + Help.h \ + About.h \ + GameMgr.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\QSoloCardsPlugin.o QSoloCardsPlugin.cpp + +temp/obj/main.o: main.cpp mainwindow.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + Help.h \ + About.h \ + GameMgr.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\main.o main.cpp + +temp/obj/mainwindow.o: mainwindow.cpp mainwindow.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + Help.h \ + About.h \ + GameMgr.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\mainwindow.o mainwindow.cpp + +temp/obj/PlayingCard.o: PlayingCard.cpp PlayingCard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\PlayingCard.o PlayingCard.cpp + +temp/obj/CardDeck.o: CardDeck.cpp CardDeck.h \ + PlayingCard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardDeck.o CardDeck.cpp + +temp/obj/CardPixmaps.o: CardPixmaps.cpp CardPixmaps.h \ + PlayingCard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardPixmaps.o CardPixmaps.cpp + +temp/obj/CardStack.o: CardStack.cpp CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardPixmaps.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardStack.o CardStack.cpp + +temp/obj/DragCardStack.o: DragCardStack.cpp DragCardStack.h \ + CardDeck.h \ + PlayingCard.h \ + CardMoveRecord.h \ + CardStack.h \ + FlipAnimation.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\DragCardStack.o DragCardStack.cpp + +temp/obj/VCardStack.o: VCardStack.cpp VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\VCardStack.o VCardStack.cpp + +temp/obj/CardAnimationLock.o: CardAnimationLock.cpp CardAnimationLock.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardAnimationLock.o CardAnimationLock.cpp + +temp/obj/StackToStackAniMove.o: StackToStackAniMove.cpp StackToStackAniMove.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\StackToStackAniMove.o StackToStackAniMove.cpp + +temp/obj/DealAnimation.o: DealAnimation.cpp DealAnimation.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\DealAnimation.o DealAnimation.cpp + +temp/obj/FlipAnimation.o: FlipAnimation.cpp FlipAnimation.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + CardStack.h \ + DragCardStack.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FlipAnimation.o FlipAnimation.cpp + +temp/obj/StackToStackFlipAni.o: StackToStackFlipAni.cpp StackToStackFlipAni.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardAnimationLock.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\StackToStackFlipAni.o StackToStackFlipAni.cpp + +temp/obj/GameBoard.o: GameBoard.cpp GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + CardPixmaps.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\GameBoard.o GameBoard.cpp + +temp/obj/CardMoveRecord.o: CardMoveRecord.cpp CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardMoveRecord.o CardMoveRecord.cpp + +temp/obj/About.o: About.cpp About.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\About.o About.cpp + +temp/obj/Help.o: Help.cpp Help.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\Help.o Help.cpp + +temp/obj/GameMgr.o: GameMgr.cpp GameMgr.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderBoard.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + Spider3DeckBoard.h \ + SpideretteBoard.h \ + KlondikeBoard.h \ + KlondikeStack.h \ + KlondikeHomeStack.h \ + KlondikeFlipStack.h \ + StackToStackFlipAni.h \ + FreeCellBoard.h \ + FreeCellDeck.h \ + FreeCellFree.h \ + FreeCellStack.h \ + FreeCellHome.h \ + YukonBoard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\GameMgr.o GameMgr.cpp + +temp/obj/SpiderBoard.o: SpiderBoard.cpp SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\SpiderBoard.o SpiderBoard.cpp + +temp/obj/SpiderHomeStack.o: SpiderHomeStack.cpp SpiderHomeStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\SpiderHomeStack.o SpiderHomeStack.cpp + +temp/obj/SpiderStack.o: SpiderStack.cpp SpiderStack.h \ + VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + SpiderHomeStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\SpiderStack.o SpiderStack.cpp + +temp/obj/KlondikeStack.o: KlondikeStack.cpp KlondikeStack.h \ + VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\KlondikeStack.o KlondikeStack.cpp + +temp/obj/KlondikeFlipStack.o: KlondikeFlipStack.cpp KlondikeFlipStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\KlondikeFlipStack.o KlondikeFlipStack.cpp + +temp/obj/KlondikeHomeStack.o: KlondikeHomeStack.cpp KlondikeHomeStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\KlondikeHomeStack.o KlondikeHomeStack.cpp + +temp/obj/KlondikeBoard.o: KlondikeBoard.cpp KlondikeBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + KlondikeStack.h \ + VCardStack.h \ + KlondikeHomeStack.h \ + KlondikeFlipStack.h \ + StackToStackFlipAni.h \ + CardPixmaps.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\KlondikeBoard.o KlondikeBoard.cpp + +temp/obj/FreeCellBoard.o: FreeCellBoard.cpp FreeCellBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + FreeCellDeck.h \ + FreeCellFree.h \ + FreeCellStack.h \ + VCardStack.h \ + FreeCellHome.h \ + CardPixmaps.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellBoard.o FreeCellBoard.cpp + +temp/obj/FreeCellDeck.o: FreeCellDeck.cpp FreeCellDeck.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellDeck.o FreeCellDeck.cpp + +temp/obj/FreeCellStack.o: FreeCellStack.cpp FreeCellStack.h \ + VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellStack.o FreeCellStack.cpp + +temp/obj/FreeCellHome.o: FreeCellHome.cpp FreeCellHome.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellHome.o FreeCellHome.cpp + +temp/obj/FreeCellFree.o: FreeCellFree.cpp FreeCellFree.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellFree.o FreeCellFree.cpp + +temp/obj/Spider3DeckBoard.o: Spider3DeckBoard.cpp Spider3DeckBoard.h \ + SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\Spider3DeckBoard.o Spider3DeckBoard.cpp + +temp/obj/SpideretteBoard.o: SpideretteBoard.cpp SpideretteBoard.h \ + SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\SpideretteBoard.o SpideretteBoard.cpp + +temp/obj/YukonBoard.o: YukonBoard.cpp YukonBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + FreeCellHome.h \ + FreeCellDeck.h \ + KlondikeStack.h \ + VCardStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\YukonBoard.o YukonBoard.cpp + +temp/obj/moc_QSoloCardsPlugin.o: temp/moc/moc_QSoloCardsPlugin.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_QSoloCardsPlugin.o temp\moc\moc_QSoloCardsPlugin.cpp + +temp/obj/moc_mainwindow.o: temp/moc/moc_mainwindow.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_mainwindow.o temp\moc\moc_mainwindow.cpp + +temp/obj/moc_CardStack.o: temp/moc/moc_CardStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_CardStack.o temp\moc\moc_CardStack.cpp + +temp/obj/moc_DragCardStack.o: temp/moc/moc_DragCardStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_DragCardStack.o temp\moc\moc_DragCardStack.cpp + +temp/obj/moc_VCardStack.o: temp/moc/moc_VCardStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_VCardStack.o temp\moc\moc_VCardStack.cpp + +temp/obj/moc_CardAnimationLock.o: temp/moc/moc_CardAnimationLock.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_CardAnimationLock.o temp\moc\moc_CardAnimationLock.cpp + +temp/obj/moc_StackToStackAniMove.o: temp/moc/moc_StackToStackAniMove.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_StackToStackAniMove.o temp\moc\moc_StackToStackAniMove.cpp + +temp/obj/moc_DealAnimation.o: temp/moc/moc_DealAnimation.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_DealAnimation.o temp\moc\moc_DealAnimation.cpp + +temp/obj/moc_FlipAnimation.o: temp/moc/moc_FlipAnimation.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FlipAnimation.o temp\moc\moc_FlipAnimation.cpp + +temp/obj/moc_StackToStackFlipAni.o: temp/moc/moc_StackToStackFlipAni.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_StackToStackFlipAni.o temp\moc\moc_StackToStackFlipAni.cpp + +temp/obj/moc_GameBoard.o: temp/moc/moc_GameBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_GameBoard.o temp\moc\moc_GameBoard.cpp + +temp/obj/moc_About.o: temp/moc/moc_About.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_About.o temp\moc\moc_About.cpp + +temp/obj/moc_Help.o: temp/moc/moc_Help.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_Help.o temp\moc\moc_Help.cpp + +temp/obj/moc_SpiderBoard.o: temp/moc/moc_SpiderBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_SpiderBoard.o temp\moc\moc_SpiderBoard.cpp + +temp/obj/moc_SpiderStack.o: temp/moc/moc_SpiderStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_SpiderStack.o temp\moc\moc_SpiderStack.cpp + +temp/obj/moc_KlondikeStack.o: temp/moc/moc_KlondikeStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_KlondikeStack.o temp\moc\moc_KlondikeStack.cpp + +temp/obj/moc_KlondikeFlipStack.o: temp/moc/moc_KlondikeFlipStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_KlondikeFlipStack.o temp\moc\moc_KlondikeFlipStack.cpp + +temp/obj/moc_KlondikeHomeStack.o: temp/moc/moc_KlondikeHomeStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_KlondikeHomeStack.o temp\moc\moc_KlondikeHomeStack.cpp + +temp/obj/moc_KlondikeBoard.o: temp/moc/moc_KlondikeBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_KlondikeBoard.o temp\moc\moc_KlondikeBoard.cpp + +temp/obj/moc_FreeCellBoard.o: temp/moc/moc_FreeCellBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellBoard.o temp\moc\moc_FreeCellBoard.cpp + +temp/obj/moc_FreeCellDeck.o: temp/moc/moc_FreeCellDeck.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellDeck.o temp\moc\moc_FreeCellDeck.cpp + +temp/obj/moc_FreeCellStack.o: temp/moc/moc_FreeCellStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellStack.o temp\moc\moc_FreeCellStack.cpp + +temp/obj/moc_FreeCellHome.o: temp/moc/moc_FreeCellHome.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellHome.o temp\moc\moc_FreeCellHome.cpp + +temp/obj/moc_FreeCellFree.o: temp/moc/moc_FreeCellFree.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellFree.o temp\moc\moc_FreeCellFree.cpp + +temp/obj/moc_Spider3DeckBoard.o: temp/moc/moc_Spider3DeckBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_Spider3DeckBoard.o temp\moc\moc_Spider3DeckBoard.cpp + +temp/obj/moc_SpideretteBoard.o: temp/moc/moc_SpideretteBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_SpideretteBoard.o temp\moc\moc_SpideretteBoard.cpp + +temp/obj/moc_YukonBoard.o: temp/moc/moc_YukonBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_YukonBoard.o temp\moc\moc_YukonBoard.cpp + +temp/obj/qrc_QSoloCards.o: temp/qrc/qrc_QSoloCards.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\qrc_QSoloCards.o temp\qrc\qrc_QSoloCards.cpp + +####### Install + +install: FORCE + +uninstall: FORCE + +FORCE: + diff --git a/plugins/qsolocards_plugin/Makefile.Release b/plugins/qsolocards_plugin/Makefile.Release new file mode 100644 index 000000000..df4410744 --- /dev/null +++ b/plugins/qsolocards_plugin/Makefile.Release @@ -0,0 +1,991 @@ +############################################################################# +# Makefile for building: qsolocards_plugin +# Generated by qmake (2.01a) (Qt 4.6.1) on: Mo 15. Feb 12:18:26 2010 +# Project: qsolocards_plugin.pro +# Template: lib +############################################################################# + +####### Compiler, tools and options + +CC = gcc +CXX = g++ +DEFINES = -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_PLUGIN -DQT_SVG_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT +CFLAGS = -O2 -Wall $(DEFINES) +CXXFLAGS = -DVER_MAJ=0 -DVER_MIN=99 -DVER_PAT=1 -frtti -fexceptions -mthreads -Wall $(DEFINES) +INCPATH = -I"d:\Qt\2010.01\qt\include\QtCore" -I"d:\Qt\2010.01\qt\include\QtGui" -I"d:\Qt\2010.01\qt\include\QtSvg" -I"d:\Qt\2010.01\qt\include" -I".." -I"d:\Qt\2010.01\qt\include\ActiveQt" -I"temp\moc" -I"d:\Qt\2010.01\qt\mkspecs\default" +LINK = g++ +LFLAGS = -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc -Wl,-s -mthreads -Wl -shared -Wl,--out-implib,..\..\bin\libqsolocards_plugin0.a +LIBS = -L"d:\Qt\2010.01\qt\lib" -lQtSvg4 -lQtGui4 -lQtCore4 +QMAKE = d:\qt\2010.01\qt\bin\qmake.exe +IDC = d:\Qt\2010.01\qt\bin\idc.exe +IDL = midl +ZIP = zip -r -9 +DEF_FILE = +RES_FILE = +COPY = copy /y +COPY_FILE = $(COPY) +COPY_DIR = xcopy /s /q /y /i +DEL_FILE = del +DEL_DIR = rmdir +MOVE = move +CHK_DIR_EXISTS= if not exist +MKDIR = mkdir +INSTALL_FILE = $(COPY_FILE) +INSTALL_PROGRAM = $(COPY_FILE) +INSTALL_DIR = $(COPY_DIR) + +####### Output directory + +OBJECTS_DIR = temp\obj + +####### Files + +SOURCES = QSoloCardsPlugin.cpp \ + main.cpp \ + mainwindow.cpp \ + PlayingCard.cpp \ + CardDeck.cpp \ + CardPixmaps.cpp \ + CardStack.cpp \ + DragCardStack.cpp \ + VCardStack.cpp \ + CardAnimationLock.cpp \ + StackToStackAniMove.cpp \ + DealAnimation.cpp \ + FlipAnimation.cpp \ + StackToStackFlipAni.cpp \ + GameBoard.cpp \ + CardMoveRecord.cpp \ + About.cpp \ + Help.cpp \ + GameMgr.cpp \ + SpiderBoard.cpp \ + SpiderHomeStack.cpp \ + SpiderStack.cpp \ + KlondikeStack.cpp \ + KlondikeFlipStack.cpp \ + KlondikeHomeStack.cpp \ + KlondikeBoard.cpp \ + FreeCellBoard.cpp \ + FreeCellDeck.cpp \ + FreeCellStack.cpp \ + FreeCellHome.cpp \ + FreeCellFree.cpp \ + Spider3DeckBoard.cpp \ + SpideretteBoard.cpp \ + YukonBoard.cpp temp\moc\moc_QSoloCardsPlugin.cpp \ + temp\moc\moc_mainwindow.cpp \ + temp\moc\moc_CardStack.cpp \ + temp\moc\moc_DragCardStack.cpp \ + temp\moc\moc_VCardStack.cpp \ + temp\moc\moc_CardAnimationLock.cpp \ + temp\moc\moc_StackToStackAniMove.cpp \ + temp\moc\moc_DealAnimation.cpp \ + temp\moc\moc_FlipAnimation.cpp \ + temp\moc\moc_StackToStackFlipAni.cpp \ + temp\moc\moc_GameBoard.cpp \ + temp\moc\moc_About.cpp \ + temp\moc\moc_Help.cpp \ + temp\moc\moc_SpiderBoard.cpp \ + temp\moc\moc_SpiderStack.cpp \ + temp\moc\moc_KlondikeStack.cpp \ + temp\moc\moc_KlondikeFlipStack.cpp \ + temp\moc\moc_KlondikeHomeStack.cpp \ + temp\moc\moc_KlondikeBoard.cpp \ + temp\moc\moc_FreeCellBoard.cpp \ + temp\moc\moc_FreeCellDeck.cpp \ + temp\moc\moc_FreeCellStack.cpp \ + temp\moc\moc_FreeCellHome.cpp \ + temp\moc\moc_FreeCellFree.cpp \ + temp\moc\moc_Spider3DeckBoard.cpp \ + temp\moc\moc_SpideretteBoard.cpp \ + temp\moc\moc_YukonBoard.cpp \ + temp\qrc\qrc_QSoloCards.cpp +OBJECTS = temp/obj/QSoloCardsPlugin.o \ + temp/obj/main.o \ + temp/obj/mainwindow.o \ + temp/obj/PlayingCard.o \ + temp/obj/CardDeck.o \ + temp/obj/CardPixmaps.o \ + temp/obj/CardStack.o \ + temp/obj/DragCardStack.o \ + temp/obj/VCardStack.o \ + temp/obj/CardAnimationLock.o \ + temp/obj/StackToStackAniMove.o \ + temp/obj/DealAnimation.o \ + temp/obj/FlipAnimation.o \ + temp/obj/StackToStackFlipAni.o \ + temp/obj/GameBoard.o \ + temp/obj/CardMoveRecord.o \ + temp/obj/About.o \ + temp/obj/Help.o \ + temp/obj/GameMgr.o \ + temp/obj/SpiderBoard.o \ + temp/obj/SpiderHomeStack.o \ + temp/obj/SpiderStack.o \ + temp/obj/KlondikeStack.o \ + temp/obj/KlondikeFlipStack.o \ + temp/obj/KlondikeHomeStack.o \ + temp/obj/KlondikeBoard.o \ + temp/obj/FreeCellBoard.o \ + temp/obj/FreeCellDeck.o \ + temp/obj/FreeCellStack.o \ + temp/obj/FreeCellHome.o \ + temp/obj/FreeCellFree.o \ + temp/obj/Spider3DeckBoard.o \ + temp/obj/SpideretteBoard.o \ + temp/obj/YukonBoard.o \ + temp/obj/moc_QSoloCardsPlugin.o \ + temp/obj/moc_mainwindow.o \ + temp/obj/moc_CardStack.o \ + temp/obj/moc_DragCardStack.o \ + temp/obj/moc_VCardStack.o \ + temp/obj/moc_CardAnimationLock.o \ + temp/obj/moc_StackToStackAniMove.o \ + temp/obj/moc_DealAnimation.o \ + temp/obj/moc_FlipAnimation.o \ + temp/obj/moc_StackToStackFlipAni.o \ + temp/obj/moc_GameBoard.o \ + temp/obj/moc_About.o \ + temp/obj/moc_Help.o \ + temp/obj/moc_SpiderBoard.o \ + temp/obj/moc_SpiderStack.o \ + temp/obj/moc_KlondikeStack.o \ + temp/obj/moc_KlondikeFlipStack.o \ + temp/obj/moc_KlondikeHomeStack.o \ + temp/obj/moc_KlondikeBoard.o \ + temp/obj/moc_FreeCellBoard.o \ + temp/obj/moc_FreeCellDeck.o \ + temp/obj/moc_FreeCellStack.o \ + temp/obj/moc_FreeCellHome.o \ + temp/obj/moc_FreeCellFree.o \ + temp/obj/moc_Spider3DeckBoard.o \ + temp/obj/moc_SpideretteBoard.o \ + temp/obj/moc_YukonBoard.o \ + temp/obj/qrc_QSoloCards.o +DIST = +QMAKE_TARGET = qsolocards_plugin +DESTDIR = ..\..\bin\ #avoid trailing-slash linebreak +TARGET = qsolocards_plugin0.dll +DESTDIR_TARGET = ..\..\bin\qsolocards_plugin0.dll + +####### Implicit rules + +.SUFFIXES: .cpp .cc .cxx .c + +.cpp.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cc.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.cxx.o: + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< + +.c.o: + $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< + +####### Build rules + +first: all +all: Makefile.Release $(DESTDIR_TARGET) + +$(DESTDIR_TARGET): $(OBJECTS) + $(LINK) $(LFLAGS) -o $(DESTDIR_TARGET) object_script.qsolocards_plugin.Release $(LIBS) + + +qmake: FORCE + @$(QMAKE) -win32 -o Makefile.Release qsolocards_plugin.pro + +dist: + $(ZIP) qsolocards_plugin.zip $(SOURCES) $(DIST) qsolocards_plugin.pro d:\Qt\2010.01\qt\mkspecs\qconfig.pri d:\Qt\2010.01\qt\mkspecs\features\qt_functions.prf d:\Qt\2010.01\qt\mkspecs\features\qt_config.prf d:\Qt\2010.01\qt\mkspecs\features\exclusive_builds.prf d:\Qt\2010.01\qt\mkspecs\features\default_pre.prf d:\Qt\2010.01\qt\mkspecs\features\win32\default_pre.prf d:\Qt\2010.01\qt\mkspecs\features\release.prf d:\Qt\2010.01\qt\mkspecs\features\debug_and_release.prf d:\Qt\2010.01\qt\mkspecs\features\default_post.prf d:\Qt\2010.01\qt\mkspecs\features\win32\default_post.prf d:\Qt\2010.01\qt\mkspecs\features\build_pass.prf d:\Qt\2010.01\qt\mkspecs\features\win32\rtti.prf d:\Qt\2010.01\qt\mkspecs\features\win32\exceptions.prf d:\Qt\2010.01\qt\mkspecs\features\win32\stl.prf d:\Qt\2010.01\qt\mkspecs\features\shared.prf d:\Qt\2010.01\qt\mkspecs\features\dll.prf d:\Qt\2010.01\qt\mkspecs\features\warn_on.prf d:\Qt\2010.01\qt\mkspecs\features\qt.prf d:\Qt\2010.01\qt\mkspecs\features\win32\thread.prf d:\Qt\2010.01\qt\mkspecs\features\moc.prf d:\Qt\2010.01\qt\mkspecs\features\win32\windows.prf d:\Qt\2010.01\qt\mkspecs\features\resources.prf d:\Qt\2010.01\qt\mkspecs\features\uic.prf d:\Qt\2010.01\qt\mkspecs\features\yacc.prf d:\Qt\2010.01\qt\mkspecs\features\lex.prf HEADERS RESOURCES IMAGES SOURCES OBJECTIVE_SOURCES FORMS YACCSOURCES YACCSOURCES LEXSOURCES + +clean: compiler_clean + -$(DEL_FILE) temp\obj\QSoloCardsPlugin.o temp\obj\main.o temp\obj\mainwindow.o temp\obj\PlayingCard.o temp\obj\CardDeck.o temp\obj\CardPixmaps.o temp\obj\CardStack.o temp\obj\DragCardStack.o temp\obj\VCardStack.o temp\obj\CardAnimationLock.o temp\obj\StackToStackAniMove.o temp\obj\DealAnimation.o temp\obj\FlipAnimation.o temp\obj\StackToStackFlipAni.o temp\obj\GameBoard.o temp\obj\CardMoveRecord.o temp\obj\About.o temp\obj\Help.o temp\obj\GameMgr.o temp\obj\SpiderBoard.o temp\obj\SpiderHomeStack.o temp\obj\SpiderStack.o temp\obj\KlondikeStack.o temp\obj\KlondikeFlipStack.o temp\obj\KlondikeHomeStack.o temp\obj\KlondikeBoard.o temp\obj\FreeCellBoard.o temp\obj\FreeCellDeck.o temp\obj\FreeCellStack.o temp\obj\FreeCellHome.o temp\obj\FreeCellFree.o temp\obj\Spider3DeckBoard.o temp\obj\SpideretteBoard.o temp\obj\YukonBoard.o temp\obj\moc_QSoloCardsPlugin.o temp\obj\moc_mainwindow.o temp\obj\moc_CardStack.o temp\obj\moc_DragCardStack.o temp\obj\moc_VCardStack.o temp\obj\moc_CardAnimationLock.o temp\obj\moc_StackToStackAniMove.o temp\obj\moc_DealAnimation.o temp\obj\moc_FlipAnimation.o temp\obj\moc_StackToStackFlipAni.o temp\obj\moc_GameBoard.o temp\obj\moc_About.o temp\obj\moc_Help.o temp\obj\moc_SpiderBoard.o temp\obj\moc_SpiderStack.o temp\obj\moc_KlondikeStack.o temp\obj\moc_KlondikeFlipStack.o temp\obj\moc_KlondikeHomeStack.o temp\obj\moc_KlondikeBoard.o temp\obj\moc_FreeCellBoard.o temp\obj\moc_FreeCellDeck.o temp\obj\moc_FreeCellStack.o temp\obj\moc_FreeCellHome.o temp\obj\moc_FreeCellFree.o temp\obj\moc_Spider3DeckBoard.o temp\obj\moc_SpideretteBoard.o temp\obj\moc_YukonBoard.o temp\obj\qrc_QSoloCards.o + -$(DEL_FILE) ..\..\bin\libqsolocards_plugin0.a + +distclean: clean + -$(DEL_FILE) $(DESTDIR_TARGET) + -$(DEL_FILE) Makefile.Release + +mocclean: compiler_moc_header_clean compiler_moc_source_clean + +mocables: compiler_moc_header_make_all compiler_moc_source_make_all + +compiler_moc_header_make_all: temp/moc/moc_QSoloCardsPlugin.cpp temp/moc/moc_mainwindow.cpp temp/moc/moc_CardStack.cpp temp/moc/moc_DragCardStack.cpp temp/moc/moc_VCardStack.cpp temp/moc/moc_CardAnimationLock.cpp temp/moc/moc_StackToStackAniMove.cpp temp/moc/moc_DealAnimation.cpp temp/moc/moc_FlipAnimation.cpp temp/moc/moc_StackToStackFlipAni.cpp temp/moc/moc_GameBoard.cpp temp/moc/moc_About.cpp temp/moc/moc_Help.cpp temp/moc/moc_SpiderBoard.cpp temp/moc/moc_SpiderStack.cpp temp/moc/moc_KlondikeStack.cpp temp/moc/moc_KlondikeFlipStack.cpp temp/moc/moc_KlondikeHomeStack.cpp temp/moc/moc_KlondikeBoard.cpp temp/moc/moc_FreeCellBoard.cpp temp/moc/moc_FreeCellDeck.cpp temp/moc/moc_FreeCellStack.cpp temp/moc/moc_FreeCellHome.cpp temp/moc/moc_FreeCellFree.cpp temp/moc/moc_Spider3DeckBoard.cpp temp/moc/moc_SpideretteBoard.cpp temp/moc/moc_YukonBoard.cpp +compiler_moc_header_clean: + -$(DEL_FILE) temp\moc\moc_QSoloCardsPlugin.cpp temp\moc\moc_mainwindow.cpp temp\moc\moc_CardStack.cpp temp\moc\moc_DragCardStack.cpp temp\moc\moc_VCardStack.cpp temp\moc\moc_CardAnimationLock.cpp temp\moc\moc_StackToStackAniMove.cpp temp\moc\moc_DealAnimation.cpp temp\moc\moc_FlipAnimation.cpp temp\moc\moc_StackToStackFlipAni.cpp temp\moc\moc_GameBoard.cpp temp\moc\moc_About.cpp temp\moc\moc_Help.cpp temp\moc\moc_SpiderBoard.cpp temp\moc\moc_SpiderStack.cpp temp\moc\moc_KlondikeStack.cpp temp\moc\moc_KlondikeFlipStack.cpp temp\moc\moc_KlondikeHomeStack.cpp temp\moc\moc_KlondikeBoard.cpp temp\moc\moc_FreeCellBoard.cpp temp\moc\moc_FreeCellDeck.cpp temp\moc\moc_FreeCellStack.cpp temp\moc\moc_FreeCellHome.cpp temp\moc\moc_FreeCellFree.cpp temp\moc\moc_Spider3DeckBoard.cpp temp\moc\moc_SpideretteBoard.cpp temp\moc\moc_YukonBoard.cpp +temp/moc/moc_QSoloCardsPlugin.cpp: QSoloCardsPlugin.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 QSoloCardsPlugin.h -o temp\moc\moc_QSoloCardsPlugin.cpp + +temp/moc/moc_mainwindow.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + Help.h \ + About.h \ + GameMgr.h \ + mainwindow.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 mainwindow.h -o temp\moc\moc_mainwindow.cpp + +temp/moc/moc_CardStack.cpp: CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 CardStack.h -o temp\moc\moc_CardStack.cpp + +temp/moc/moc_DragCardStack.cpp: CardDeck.h \ + PlayingCard.h \ + CardMoveRecord.h \ + DragCardStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 DragCardStack.h -o temp\moc\moc_DragCardStack.cpp + +temp/moc/moc_VCardStack.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + VCardStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 VCardStack.h -o temp\moc\moc_VCardStack.cpp + +temp/moc/moc_CardAnimationLock.cpp: CardAnimationLock.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 CardAnimationLock.h -o temp\moc\moc_CardAnimationLock.cpp + +temp/moc/moc_StackToStackAniMove.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 StackToStackAniMove.h -o temp\moc\moc_StackToStackAniMove.cpp + +temp/moc/moc_DealAnimation.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + DealAnimation.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 DealAnimation.h -o temp\moc\moc_DealAnimation.cpp + +temp/moc/moc_FlipAnimation.cpp: CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FlipAnimation.h -o temp\moc\moc_FlipAnimation.cpp + +temp/moc/moc_StackToStackFlipAni.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackFlipAni.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 StackToStackFlipAni.h -o temp\moc\moc_StackToStackFlipAni.cpp + +temp/moc/moc_GameBoard.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + GameBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 GameBoard.h -o temp\moc\moc_GameBoard.cpp + +temp/moc/moc_About.cpp: About.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 About.h -o temp\moc\moc_About.cpp + +temp/moc/moc_Help.cpp: Help.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 Help.h -o temp\moc\moc_Help.cpp + +temp/moc/moc_SpiderBoard.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + SpiderBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 SpiderBoard.h -o temp\moc\moc_SpiderBoard.cpp + +temp/moc/moc_SpiderStack.cpp: VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + SpiderStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 SpiderStack.h -o temp\moc\moc_SpiderStack.cpp + +temp/moc/moc_KlondikeStack.cpp: VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + KlondikeStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 KlondikeStack.h -o temp\moc\moc_KlondikeStack.cpp + +temp/moc/moc_KlondikeFlipStack.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + KlondikeFlipStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 KlondikeFlipStack.h -o temp\moc\moc_KlondikeFlipStack.cpp + +temp/moc/moc_KlondikeHomeStack.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + KlondikeHomeStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 KlondikeHomeStack.h -o temp\moc\moc_KlondikeHomeStack.cpp + +temp/moc/moc_KlondikeBoard.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + KlondikeStack.h \ + VCardStack.h \ + KlondikeHomeStack.h \ + KlondikeFlipStack.h \ + StackToStackFlipAni.h \ + KlondikeBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 KlondikeBoard.h -o temp\moc\moc_KlondikeBoard.cpp + +temp/moc/moc_FreeCellBoard.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + FreeCellDeck.h \ + FreeCellFree.h \ + FreeCellStack.h \ + VCardStack.h \ + FreeCellHome.h \ + FreeCellBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellBoard.h -o temp\moc\moc_FreeCellBoard.cpp + +temp/moc/moc_FreeCellDeck.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + FreeCellDeck.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellDeck.h -o temp\moc\moc_FreeCellDeck.cpp + +temp/moc/moc_FreeCellStack.cpp: VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + FreeCellStack.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellStack.h -o temp\moc\moc_FreeCellStack.cpp + +temp/moc/moc_FreeCellHome.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + FreeCellHome.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellHome.h -o temp\moc\moc_FreeCellHome.cpp + +temp/moc/moc_FreeCellFree.cpp: CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + FreeCellFree.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 FreeCellFree.h -o temp\moc\moc_FreeCellFree.cpp + +temp/moc/moc_Spider3DeckBoard.cpp: SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + Spider3DeckBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 Spider3DeckBoard.h -o temp\moc\moc_Spider3DeckBoard.cpp + +temp/moc/moc_SpideretteBoard.cpp: SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + SpideretteBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 SpideretteBoard.h -o temp\moc\moc_SpideretteBoard.cpp + +temp/moc/moc_YukonBoard.cpp: GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + FreeCellHome.h \ + FreeCellDeck.h \ + KlondikeStack.h \ + VCardStack.h \ + YukonBoard.h + d:/Qt/2010.01/qt/bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 YukonBoard.h -o temp\moc\moc_YukonBoard.cpp + +compiler_rcc_make_all: temp/qrc/qrc_QSoloCards.cpp +compiler_rcc_clean: + -$(DEL_FILE) temp\qrc\qrc_QSoloCards.cpp +temp/qrc/qrc_QSoloCards.cpp: QSoloCards.qrc \ + images/greenfelt.png \ + images/anglo_bitmap.svg \ + images/sol128x128.png \ + images/sol32x32.png \ + help/FreeCellHelp.html \ + help/SpideretteHelp.html \ + help/YukonHelp.html \ + help/SpiderHelp.html \ + help/Spider3DeckHelp.html \ + help/KlondikeHelp.html \ + help/gpl3.html + d:\Qt\2010.01\qt\bin\rcc.exe -name QSoloCards QSoloCards.qrc -o temp\qrc\qrc_QSoloCards.cpp + +compiler_image_collection_make_all: qmake_image_collection.cpp +compiler_image_collection_clean: + -$(DEL_FILE) qmake_image_collection.cpp +compiler_moc_source_make_all: +compiler_moc_source_clean: +compiler_uic_make_all: +compiler_uic_clean: +compiler_yacc_decl_make_all: +compiler_yacc_decl_clean: +compiler_yacc_impl_make_all: +compiler_yacc_impl_clean: +compiler_lex_make_all: +compiler_lex_clean: +compiler_clean: compiler_moc_header_clean compiler_rcc_clean + + + +####### Compile + +temp/obj/QSoloCardsPlugin.o: QSoloCardsPlugin.cpp QSoloCardsPlugin.h \ + mainwindow.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + Help.h \ + About.h \ + GameMgr.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\QSoloCardsPlugin.o QSoloCardsPlugin.cpp + +temp/obj/main.o: main.cpp mainwindow.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + Help.h \ + About.h \ + GameMgr.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\main.o main.cpp + +temp/obj/mainwindow.o: mainwindow.cpp mainwindow.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + Help.h \ + About.h \ + GameMgr.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\mainwindow.o mainwindow.cpp + +temp/obj/PlayingCard.o: PlayingCard.cpp PlayingCard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\PlayingCard.o PlayingCard.cpp + +temp/obj/CardDeck.o: CardDeck.cpp CardDeck.h \ + PlayingCard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardDeck.o CardDeck.cpp + +temp/obj/CardPixmaps.o: CardPixmaps.cpp CardPixmaps.h \ + PlayingCard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardPixmaps.o CardPixmaps.cpp + +temp/obj/CardStack.o: CardStack.cpp CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardPixmaps.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardStack.o CardStack.cpp + +temp/obj/DragCardStack.o: DragCardStack.cpp DragCardStack.h \ + CardDeck.h \ + PlayingCard.h \ + CardMoveRecord.h \ + CardStack.h \ + FlipAnimation.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\DragCardStack.o DragCardStack.cpp + +temp/obj/VCardStack.o: VCardStack.cpp VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\VCardStack.o VCardStack.cpp + +temp/obj/CardAnimationLock.o: CardAnimationLock.cpp CardAnimationLock.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardAnimationLock.o CardAnimationLock.cpp + +temp/obj/StackToStackAniMove.o: StackToStackAniMove.cpp StackToStackAniMove.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\StackToStackAniMove.o StackToStackAniMove.cpp + +temp/obj/DealAnimation.o: DealAnimation.cpp DealAnimation.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\DealAnimation.o DealAnimation.cpp + +temp/obj/FlipAnimation.o: FlipAnimation.cpp FlipAnimation.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + CardStack.h \ + DragCardStack.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FlipAnimation.o FlipAnimation.cpp + +temp/obj/StackToStackFlipAni.o: StackToStackFlipAni.cpp StackToStackFlipAni.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardAnimationLock.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\StackToStackFlipAni.o StackToStackFlipAni.cpp + +temp/obj/GameBoard.o: GameBoard.cpp GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + CardPixmaps.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\GameBoard.o GameBoard.cpp + +temp/obj/CardMoveRecord.o: CardMoveRecord.cpp CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\CardMoveRecord.o CardMoveRecord.cpp + +temp/obj/About.o: About.cpp About.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\About.o About.cpp + +temp/obj/Help.o: Help.cpp Help.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\Help.o Help.cpp + +temp/obj/GameMgr.o: GameMgr.cpp GameMgr.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderBoard.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + Spider3DeckBoard.h \ + SpideretteBoard.h \ + KlondikeBoard.h \ + KlondikeStack.h \ + KlondikeHomeStack.h \ + KlondikeFlipStack.h \ + StackToStackFlipAni.h \ + FreeCellBoard.h \ + FreeCellDeck.h \ + FreeCellFree.h \ + FreeCellStack.h \ + FreeCellHome.h \ + YukonBoard.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\GameMgr.o GameMgr.cpp + +temp/obj/SpiderBoard.o: SpiderBoard.cpp SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\SpiderBoard.o SpiderBoard.cpp + +temp/obj/SpiderHomeStack.o: SpiderHomeStack.cpp SpiderHomeStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\SpiderHomeStack.o SpiderHomeStack.cpp + +temp/obj/SpiderStack.o: SpiderStack.cpp SpiderStack.h \ + VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + SpiderHomeStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\SpiderStack.o SpiderStack.cpp + +temp/obj/KlondikeStack.o: KlondikeStack.cpp KlondikeStack.h \ + VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\KlondikeStack.o KlondikeStack.cpp + +temp/obj/KlondikeFlipStack.o: KlondikeFlipStack.cpp KlondikeFlipStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\KlondikeFlipStack.o KlondikeFlipStack.cpp + +temp/obj/KlondikeHomeStack.o: KlondikeHomeStack.cpp KlondikeHomeStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\KlondikeHomeStack.o KlondikeHomeStack.cpp + +temp/obj/KlondikeBoard.o: KlondikeBoard.cpp KlondikeBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + KlondikeStack.h \ + VCardStack.h \ + KlondikeHomeStack.h \ + KlondikeFlipStack.h \ + StackToStackFlipAni.h \ + CardPixmaps.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\KlondikeBoard.o KlondikeBoard.cpp + +temp/obj/FreeCellBoard.o: FreeCellBoard.cpp FreeCellBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + FreeCellDeck.h \ + FreeCellFree.h \ + FreeCellStack.h \ + VCardStack.h \ + FreeCellHome.h \ + CardPixmaps.h \ + CardAnimationLock.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellBoard.o FreeCellBoard.cpp + +temp/obj/FreeCellDeck.o: FreeCellDeck.cpp FreeCellDeck.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellDeck.o FreeCellDeck.cpp + +temp/obj/FreeCellStack.o: FreeCellStack.cpp FreeCellStack.h \ + VCardStack.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellStack.o FreeCellStack.cpp + +temp/obj/FreeCellHome.o: FreeCellHome.cpp FreeCellHome.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellHome.o FreeCellHome.cpp + +temp/obj/FreeCellFree.o: FreeCellFree.cpp FreeCellFree.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\FreeCellFree.o FreeCellFree.cpp + +temp/obj/Spider3DeckBoard.o: Spider3DeckBoard.cpp Spider3DeckBoard.h \ + SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\Spider3DeckBoard.o Spider3DeckBoard.cpp + +temp/obj/SpideretteBoard.o: SpideretteBoard.cpp SpideretteBoard.h \ + SpiderBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + SpiderStack.h \ + VCardStack.h \ + SpiderHomeStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\SpideretteBoard.o SpideretteBoard.cpp + +temp/obj/YukonBoard.o: YukonBoard.cpp YukonBoard.h \ + GameBoard.h \ + CardStack.h \ + CardMoveRecord.h \ + CardDeck.h \ + PlayingCard.h \ + FlipAnimation.h \ + DragCardStack.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + FreeCellHome.h \ + FreeCellDeck.h \ + KlondikeStack.h \ + VCardStack.h \ + CardPixmaps.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\YukonBoard.o YukonBoard.cpp + +temp/obj/moc_QSoloCardsPlugin.o: temp/moc/moc_QSoloCardsPlugin.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_QSoloCardsPlugin.o temp\moc\moc_QSoloCardsPlugin.cpp + +temp/obj/moc_mainwindow.o: temp/moc/moc_mainwindow.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_mainwindow.o temp\moc\moc_mainwindow.cpp + +temp/obj/moc_CardStack.o: temp/moc/moc_CardStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_CardStack.o temp\moc\moc_CardStack.cpp + +temp/obj/moc_DragCardStack.o: temp/moc/moc_DragCardStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_DragCardStack.o temp\moc\moc_DragCardStack.cpp + +temp/obj/moc_VCardStack.o: temp/moc/moc_VCardStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_VCardStack.o temp\moc\moc_VCardStack.cpp + +temp/obj/moc_CardAnimationLock.o: temp/moc/moc_CardAnimationLock.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_CardAnimationLock.o temp\moc\moc_CardAnimationLock.cpp + +temp/obj/moc_StackToStackAniMove.o: temp/moc/moc_StackToStackAniMove.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_StackToStackAniMove.o temp\moc\moc_StackToStackAniMove.cpp + +temp/obj/moc_DealAnimation.o: temp/moc/moc_DealAnimation.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_DealAnimation.o temp\moc\moc_DealAnimation.cpp + +temp/obj/moc_FlipAnimation.o: temp/moc/moc_FlipAnimation.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FlipAnimation.o temp\moc\moc_FlipAnimation.cpp + +temp/obj/moc_StackToStackFlipAni.o: temp/moc/moc_StackToStackFlipAni.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_StackToStackFlipAni.o temp\moc\moc_StackToStackFlipAni.cpp + +temp/obj/moc_GameBoard.o: temp/moc/moc_GameBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_GameBoard.o temp\moc\moc_GameBoard.cpp + +temp/obj/moc_About.o: temp/moc/moc_About.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_About.o temp\moc\moc_About.cpp + +temp/obj/moc_Help.o: temp/moc/moc_Help.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_Help.o temp\moc\moc_Help.cpp + +temp/obj/moc_SpiderBoard.o: temp/moc/moc_SpiderBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_SpiderBoard.o temp\moc\moc_SpiderBoard.cpp + +temp/obj/moc_SpiderStack.o: temp/moc/moc_SpiderStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_SpiderStack.o temp\moc\moc_SpiderStack.cpp + +temp/obj/moc_KlondikeStack.o: temp/moc/moc_KlondikeStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_KlondikeStack.o temp\moc\moc_KlondikeStack.cpp + +temp/obj/moc_KlondikeFlipStack.o: temp/moc/moc_KlondikeFlipStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_KlondikeFlipStack.o temp\moc\moc_KlondikeFlipStack.cpp + +temp/obj/moc_KlondikeHomeStack.o: temp/moc/moc_KlondikeHomeStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_KlondikeHomeStack.o temp\moc\moc_KlondikeHomeStack.cpp + +temp/obj/moc_KlondikeBoard.o: temp/moc/moc_KlondikeBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_KlondikeBoard.o temp\moc\moc_KlondikeBoard.cpp + +temp/obj/moc_FreeCellBoard.o: temp/moc/moc_FreeCellBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellBoard.o temp\moc\moc_FreeCellBoard.cpp + +temp/obj/moc_FreeCellDeck.o: temp/moc/moc_FreeCellDeck.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellDeck.o temp\moc\moc_FreeCellDeck.cpp + +temp/obj/moc_FreeCellStack.o: temp/moc/moc_FreeCellStack.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellStack.o temp\moc\moc_FreeCellStack.cpp + +temp/obj/moc_FreeCellHome.o: temp/moc/moc_FreeCellHome.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellHome.o temp\moc\moc_FreeCellHome.cpp + +temp/obj/moc_FreeCellFree.o: temp/moc/moc_FreeCellFree.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_FreeCellFree.o temp\moc\moc_FreeCellFree.cpp + +temp/obj/moc_Spider3DeckBoard.o: temp/moc/moc_Spider3DeckBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_Spider3DeckBoard.o temp\moc\moc_Spider3DeckBoard.cpp + +temp/obj/moc_SpideretteBoard.o: temp/moc/moc_SpideretteBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_SpideretteBoard.o temp\moc\moc_SpideretteBoard.cpp + +temp/obj/moc_YukonBoard.o: temp/moc/moc_YukonBoard.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\moc_YukonBoard.o temp\moc\moc_YukonBoard.cpp + +temp/obj/qrc_QSoloCards.o: temp/qrc/qrc_QSoloCards.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o temp\obj\qrc_QSoloCards.o temp\qrc\qrc_QSoloCards.cpp + +####### Install + +install: FORCE + +uninstall: FORCE + +FORCE: + diff --git a/plugins/qsolocards_plugin/PlayingCard.cpp b/plugins/qsolocards_plugin/PlayingCard.cpp new file mode 100644 index 000000000..3528d7f52 --- /dev/null +++ b/plugins/qsolocards_plugin/PlayingCard.cpp @@ -0,0 +1,174 @@ +/* + 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 "PlayingCard.h" + +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +PlayingCard::PlayingCard(PlayingCard::Suit suit, + PlayingCard::CardIndex index, + bool isFaceUp) + :m_suit(suit), + m_index(index), + m_isFaceUp(isFaceUp), + m_textStr(NULL) +{ + this->setTextStr(); +} + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +PlayingCard::PlayingCard(const PlayingCard & playingCard) + :m_textStr(NULL) +{ + *this=playingCard; +} + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +PlayingCard::~PlayingCard() +{ + delete []m_textStr; +} + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +unsigned short PlayingCard::hashValue() const +{ + return m_suit*MaxCardIndex + m_index; +} + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +PlayingCard PlayingCard::cardFromHashValue(unsigned short value) +{ + PlayingCard card(PlayingCard::MaxSuit,PlayingCard::MaxCardIndex); + // if the value is valid set the suit and index + if (value(const PlayingCard & rh) const +{ + return m_index>rh.getIndex(); +} + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +PlayingCard & PlayingCard::operator=(const PlayingCard & rh) +{ + m_suit=rh.getSuit(); + m_index=rh.getIndex(); + this->setFaceUp(rh.isFaceUp()); + setTextStr(); + return *this; +} + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +bool PlayingCard::isNextCardIndex(const PlayingCard & rh) const +{ + return m_index+1==rh.getIndex(); +} + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +bool PlayingCard::isPrevCardIndex(const PlayingCard & rh) const +{ + return m_index-1==rh.getIndex(); +} + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +void PlayingCard::setTextStr() +{ + std::string cardValue; + + switch (m_index) + { + case Ace: + cardValue="1"; + break; + case Jack: + cardValue="jack"; + break; + case Queen: + cardValue="queen"; + break; + case King: + cardValue="king"; + break; + case MaxCardIndex: + cardValue="invalid"; + break; + default: + { + char cardNumStr[20]; + sprintf(cardNumStr,"%i",(int)m_index+1); + cardValue=cardNumStr; + }; + break; + }; + + cardValue+="_"; + + switch (m_suit) + { + case Clubs: + cardValue+="club"; + break; + case Spades: + cardValue+="spade"; + break; + case Hearts: + cardValue+="heart"; + break; + case Diamonds: + cardValue+="diamond"; + break; + default: + cardValue+="Invalid Suit"; + break; + }; + + delete []m_textStr; + + this->m_textStr=new char[cardValue.size()+1]; + + strcpy(this->m_textStr,cardValue.c_str()); +} diff --git a/plugins/qsolocards_plugin/PlayingCard.h b/plugins/qsolocards_plugin/PlayingCard.h new file mode 100644 index 000000000..585460e51 --- /dev/null +++ b/plugins/qsolocards_plugin/PlayingCard.h @@ -0,0 +1,100 @@ +/* + 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 . +*/ + +#ifndef PLAYINGCARD_H +#define PLAYINGCARD_H + +class PlayingCard +{ + public: + enum Suit + { + Clubs=0, + Diamonds=1, + Hearts=2, + Spades=3, + MaxSuit=4 + }; + + + enum CardIndex + { + Ace=0, + Two=1, + Three=2, + Four=3, + Five=4, + Six=5, + Seven=6, + Eight=7, + Nine=8, + Ten=9, + Jack=10, + Queen=11, + King=12, + MaxCardIndex=13 + }; + + PlayingCard(Suit suit=PlayingCard::MaxSuit, + CardIndex index=PlayingCard::MaxCardIndex, + bool isFaceUp=false); + PlayingCard(const PlayingCard & playingCard); + + virtual ~PlayingCard(); + + // a value to uniquely id the card + unsigned short hashValue() const; + static PlayingCard cardFromHashValue(unsigned short value); + + Suit getSuit() const {return m_suit;} + CardIndex getIndex() const {return m_index;} + + inline bool isValid() const{return (MaxSuit!=m_suit && MaxCardIndex!=m_index);} + + inline bool isSameSuit(const PlayingCard & cmp) const{return cmp.getSuit()==m_suit;} + inline bool isSameIndex(const PlayingCard & cmp) const{return cmp.getIndex()==m_index;} + + inline bool isRed() const{return ((PlayingCard::Diamonds==m_suit || PlayingCard::Hearts==m_suit)?true:false);} + inline bool isBlack() const{return ((PlayingCard::Spades==m_suit || PlayingCard::Clubs==m_suit)?true:false);} + + inline bool isFaceUp() const {return m_isFaceUp;} + inline void setFaceUp(bool state=true) {m_isFaceUp=state;} + + + inline bool operator==(const PlayingCard & rh) const {return (isSameSuit(rh) && isSameIndex(rh));} + + PlayingCard & operator=(const PlayingCard & rh); + + virtual bool operator<(const PlayingCard & rh) const; + virtual bool operator>(const PlayingCard & rh) const; + + virtual bool isNextCardIndex(const PlayingCard & rh) const; + virtual bool isPrevCardIndex(const PlayingCard & rh) const; + + inline const char * asString() const{return m_textStr;} + + private: + + void setTextStr(); + + Suit m_suit; + CardIndex m_index; + bool m_isFaceUp; + char * m_textStr; +}; +#endif // PLAYINGCARD_H diff --git a/plugins/qsolocards_plugin/QSoloCards.icns b/plugins/qsolocards_plugin/QSoloCards.icns new file mode 100644 index 0000000000000000000000000000000000000000..e148c0daa683be380685698d651b747778beb076 GIT binary patch literal 129301 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 literal 0 HcmV?d00001 diff --git a/plugins/qsolocards_plugin/QSoloCards.qrc b/plugins/qsolocards_plugin/QSoloCards.qrc new file mode 100644 index 000000000..fe8c2c4c3 --- /dev/null +++ b/plugins/qsolocards_plugin/QSoloCards.qrc @@ -0,0 +1,15 @@ + + + images/greenfelt.png + images/anglo_bitmap.svg + images/sol32x32.png + images/sol128x128.png + help/SpiderHelp.html + help/Spider3DeckHelp.html + help/SpideretteHelp.html + help/KlondikeHelp.html + help/FreeCellHelp.html + help/YukonHelp.html + help/gpl3.html + + diff --git a/plugins/qsolocards_plugin/QSoloCardsPlugin.cpp b/plugins/qsolocards_plugin/QSoloCardsPlugin.cpp new file mode 100644 index 000000000..dcb4d6760 --- /dev/null +++ b/plugins/qsolocards_plugin/QSoloCardsPlugin.cpp @@ -0,0 +1,53 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2010 RetroShare Team + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +//#include +//#include +//#include + +#include "QSoloCardsPlugin.h" +#include "mainwindow.h" + +QString +QSoloCardsPlugin::pluginDescription() const +{ + QString res; + res = "a QSoloCards plugin" ; + + return res; +} + +QString +QSoloCardsPlugin::pluginName() const +{ + return "QSoloCards" ; +} + +QWidget* +QSoloCardsPlugin::pluginWidget(QWidget * parent ) +{ + MainWindow* window = new MainWindow(); + + return window; +} + + +Q_EXPORT_PLUGIN2(qsolocards_plugin, QSoloCardsPlugin) diff --git a/plugins/qsolocards_plugin/QSoloCardsPlugin.h b/plugins/qsolocards_plugin/QSoloCardsPlugin.h new file mode 100644 index 000000000..9537132df --- /dev/null +++ b/plugins/qsolocards_plugin/QSoloCardsPlugin.h @@ -0,0 +1,48 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2010 RetroShare Team + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#ifndef _QSOLOCARDS_PLUGIN_H_ +#define _QSOLOCARDS_PLUGIN_H_ + +#include + +#include +#include + +#include + +#include + +class QSoloCardsPlugin: public QObject, public PluginInterface +{ + Q_OBJECT + Q_INTERFACES(PluginInterface) + + public slots: + + virtual QString pluginDescription() const ; + virtual QString pluginName() const ; + + virtual QWidget* pluginWidget(QWidget * parent = 0) ; + +}; + +#endif diff --git a/plugins/qsolocards_plugin/Spider3DeckBoard.cpp b/plugins/qsolocards_plugin/Spider3DeckBoard.cpp new file mode 100644 index 000000000..1bd4ecc94 --- /dev/null +++ b/plugins/qsolocards_plugin/Spider3DeckBoard.cpp @@ -0,0 +1,181 @@ +/* + 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 "Spider3DeckBoard.h" +#include "CardPixmaps.h" + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +Spider3DeckBoard::Spider3DeckBoard() + :SpiderBoard() +{ + this->setGameName(QString(tr("Three Deck Spider Solitaire")).trimmed()); + this->setGameId("ThreeDeckSpider"); + + this->setHelpFile(":/help/Spider3DeckHelp.html"); +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +Spider3DeckBoard::~Spider3DeckBoard() +{ +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +void Spider3DeckBoard::newGame() +{ + // call the base class to do cleanup for us. + GameBoard::newGame(); + + CardDeck deck(3); + + // Put all cards in the m_pDeck stack. We will deal + // from this stack. + while(!deck.isEmpty()) + { + this->m_pDeck->addCard(deck.next()); + } + + unsigned int i; + unsigned int j; + + DealItemVector dealItemVector; + + // Create the dealItemVector to direct the DealAnimation object on + // how to deal the cards. + for (i=0;im_stackVector.size();i++) + { + unsigned int cardsInStack=((i<6)?5:4); + + dealItemVector.push_back(DealItem(this->m_stackVector[i],m_pDeck)); + + for (j=0;jsetPos(currPos); + + currPos.rx()+=GameBoard::LayoutSpacing+cardSize.width(); + + for (i=0;isetPos(currPos); + currPos.setX(currPos.x()+cardSize.width()+GameBoard::LayoutSpacing); + } + + currPos.setY(GameBoard::LayoutSpacing*2+cardSize.height()); + currPos.setX(GameBoard::LayoutSpacing*2+cardSize.width()); + for (i=0;isetPos(currPos); + currPos.setX(currPos.x()+cardSize.width()+GameBoard::LayoutSpacing); + } + +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +void Spider3DeckBoard::createStacks() +{ + setCardResizeAlg(13,ResizeByWidth); + + unsigned int i; + // create all the widgets for the board + for(i=0;i<12;i++) + { + this->m_homeVector.push_back(new SpiderHomeStack); + this->m_scene.addItem(m_homeVector[i]); + + // get signals when cards are added to the stack. So, we can add undo info and + // see when the game is over. + this->connect(this->m_homeVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + } + + for(i=0;i<12;i++) + { + this->m_stackVector.push_back(new SpiderStack); + this->m_scene.addItem(m_stackVector[i]); + + // get signals when cards are added to the stack. So, we can add undo info and + // see when the game is over. + this->connect(this->m_stackVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + this->connect(this->m_stackVector[i],SIGNAL(sendSuitHome(SpiderStack *,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotSendSuitHome(SpiderStack*,PlayingCardVector,CardMoveRecord))); + this->connect(this->m_stackVector[i],SIGNAL(moveCardsToDiffStack(SpiderStack *,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotMoveCardsToDiffStack(SpiderStack*,PlayingCardVector,CardMoveRecord))); + } + + m_pDeck=new CardStack; + this->m_scene.addItem(m_pDeck); + + // get signals when the deck is clicked on so we can deal the next set of cards + this->connect(this->m_pDeck,SIGNAL(cardClicked(CardStack*,uint)), + this,SLOT(slotDealNextCards(CardStack*,uint))); +} diff --git a/plugins/qsolocards_plugin/Spider3DeckBoard.h b/plugins/qsolocards_plugin/Spider3DeckBoard.h new file mode 100644 index 000000000..3ce28bc07 --- /dev/null +++ b/plugins/qsolocards_plugin/Spider3DeckBoard.h @@ -0,0 +1,43 @@ +/* + 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 . +*/ + +#ifndef __SPIDER3DECKBOARD_H__ +#define __SPIDER3DECKBOARD_H__ + +#include "SpiderBoard.h" + +class Spider3DeckBoard:public SpiderBoard +{ + Q_OBJECT +public: + Spider3DeckBoard(); + virtual ~Spider3DeckBoard(); + + virtual void newGame(); + + virtual void addGameMenuItems(QMenu & menu); + + virtual void loadSettings(const QSettings & settings); + virtual void saveSettings(QSettings & settings); + +protected: + virtual void resizeEvent (QResizeEvent * event); + virtual void createStacks(); +}; + +#endif diff --git a/plugins/qsolocards_plugin/SpiderBoard.cpp b/plugins/qsolocards_plugin/SpiderBoard.cpp new file mode 100644 index 000000000..ae7a58bc4 --- /dev/null +++ b/plugins/qsolocards_plugin/SpiderBoard.cpp @@ -0,0 +1,754 @@ +/* + 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 "SpiderBoard.h" +#include +#include +#include +#include +#include + +#include "CardPixmaps.h" +#include "CardDeck.h" + + +#include + +const QString SpiderBoard::GameTypeKeyStr("GameType"); + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +SpiderBoard::SpiderBoard(QWidget * pWidget) + :GameBoard(pWidget,QString(tr("Spider Solitaire")).trimmed(),QString("Spider")), + m_pDeck(NULL), + m_homeVector(), + m_stackVector(), + m_cheat(false), + m_gameType(SpiderBoard::FourSuits) +{ + this->setHelpFile(":/help/SpiderHelp.html"); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +SpiderBoard::~SpiderBoard() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// ok this is an attempt to offer hint moves. It will prefer same suit moves, then +// consecutive index matches, and then card to empty stack moves. It will try to +// move all cards that are movable in a stack. So, there are possibilities for +// tweaks. +//////////////////////////////////////////////////////////////////////////////// +bool SpiderBoard::getHint(CardStack * & pSrcWidget, + unsigned int & srcStackIndex, + CardStack * & pDstWidget) +{ + bool moveFound=false; + bool sameSuitFound=false; + bool nonSameSuitFound=false; + + CardStack * pCanMoveToEmpty=NULL; + CardStack * pCanMoveTo=NULL; + CardStack * pCanMoveToSameSuit=NULL; + bool newMoveFound=false; + int j; + + qsrand(QDateTime::currentDateTime().toTime_t()); + bool fromZero=((0==qrand()%2 ^ 1==qrand()%3)?true:false); // this introduces some randomness by selecting whether we are going + // to go through the stacks forward or backwards. + + + for ((fromZero?(j=0):(j=this->m_stackVector.size()-1)); + ((fromZero)?(j<(int)this->m_stackVector.size()):(j>=0))&& !sameSuitFound ;((fromZero)?(j++):(j--))) + { + PlayingCardVector cardVector; + unsigned int currSrcStackIndex; + bool fromZeroInner=((0==qrand()%2 ^ 1==qrand()%3)?true:false); // this introduces some randomness by selecting whether we are going + // to go through the stacks forward or backwards. + int i; + + newMoveFound=false; + + if (this->m_stackVector[j]->getMovableCards(cardVector,currSrcStackIndex)) + { + + // first see if the cards can be sent home + // the priority will be the same as a move to + // cards of the same suit + if (SpiderHomeStack::canSendHome(cardVector)) + { + // find an open home widget + for(unsigned int k=0;km_homeVector.size();k++) + { + if (this->m_homeVector[k]->isEmpty()) + { + pDstWidget=this->m_homeVector[k]; + break; + } + } + + if (NULL!=pDstWidget) + { + pSrcWidget=this->m_stackVector[j]; + srcStackIndex=currSrcStackIndex; + moveFound=true; + break; + } + } + + for ((fromZeroInner?(i=0):(i=this->m_stackVector.size()-1)); + ((fromZeroInner)?(i<(int)this->m_stackVector.size()):(i>=0)); + ((fromZeroInner)?(i++):(i--))) + { + + // ok we are only moving the cards if the hit is not on the same + // stack they are already located in + if (this->m_stackVector[i]!=this->m_stackVector[j]) + { + // see if we have a perferred move to a stack that has the same suit + // we will break out if we find a perferred match + if (this->m_stackVector[i]->canAddCardsSameSuit(cardVector)) + { + pCanMoveToSameSuit=this->m_stackVector[i]; + newMoveFound=true; + break; + } + // otherwise see if we can move the cards to the stack at all + else if (this->m_stackVector[i]->canAddCards(cardVector)) + { + if (this->m_stackVector[i]->isEmpty()) + { + pCanMoveToEmpty=this->m_stackVector[i]; + } + else + { + pCanMoveTo=this->m_stackVector[i]; + } + newMoveFound=true; + } + } + } + + if (newMoveFound) + { + // ok the best move is to a matching suit and consecutive + // next best is to a consecutive + // and lastly to an empty stack. + if (NULL!=pCanMoveToSameSuit) + { + pDstWidget=pCanMoveToSameSuit; + pSrcWidget=this->m_stackVector[j]; + srcStackIndex=currSrcStackIndex; + sameSuitFound=true; + } + else if (NULL!=pCanMoveTo && !nonSameSuitFound) + { + pDstWidget=pCanMoveTo; + pSrcWidget=this->m_stackVector[j]; + srcStackIndex=currSrcStackIndex; + nonSameSuitFound=true; + } + else if (NULL!=pCanMoveToEmpty && !nonSameSuitFound) + { + pDstWidget=pCanMoveToEmpty; + pSrcWidget=this->m_stackVector[j]; + srcStackIndex=currSrcStackIndex; + } + moveFound=true; + } + } + } + + + return moveFound; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::newGame() +{ + // call the base class to do cleanup for us. + GameBoard::newGame(); + + CardDeck * pDeck=NULL; + + unsigned int i; + unsigned int j; + + switch(this->m_gameType) + { + case SpiderBoard::FourSuits: + pDeck=new CardDeck(2); + break; + + case SpiderBoard::TwoSuits: + { + PlayingCardVector cardVector; + // use hearts and spades as the two suits + for (i=PlayingCard::Ace;iisEmpty()) + { + this->m_pDeck->addCard(pDeck->next()); + } + + delete pDeck; + + + DealItemVector dealItemVector; + + + // Create the dealItemVector to direct the DealAnimation object on + // how to deal the cards. + for (i=0;im_stackVector.size();i++) + { + unsigned int cardsInStack=((i<4)?6:5); + + dealItemVector.push_back(DealItem(this->m_stackVector[i],m_pDeck)); + + for (j=0;jsetShortcut(QKeySequence(Qt::CTRL + Qt::Key_4)); + pFourSuitsAction->setCheckable(true); + connect(pFourSuitsAction,SIGNAL(triggered()), + this,SLOT(slotSetFourSuits())); + + QAction * pTwoSuitsAction=new QAction(tr("Two Suits").trimmed(),pNumSuitsGroup); + pTwoSuitsAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_2)); + pTwoSuitsAction->setCheckable(true); + connect(pTwoSuitsAction,SIGNAL(triggered()), + this,SLOT(slotSetTwoSuits())); + + QAction * pOneSuitAction=new QAction(tr("One Suit").trimmed(),pNumSuitsGroup); + pOneSuitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_1)); + pOneSuitAction->setCheckable(true); + connect(pOneSuitAction,SIGNAL(triggered()), + this,SLOT(slotSetOneSuit())); + + // select the correct item in the list + switch (this->m_gameType) + { + case SpiderBoard::FourSuits: + pFourSuitsAction->setChecked(true); + break; + + case SpiderBoard::TwoSuits: + pTwoSuitsAction->setChecked(true); + break; + + case SpiderBoard::OneSuit: + pOneSuitAction->setChecked(true); + break; + }; + + menu.addAction(pFourSuitsAction); + menu.addAction(pTwoSuitsAction); + menu.addAction(pOneSuitAction); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::loadSettings(const QSettings & settings) +{ + int gameType=settings.value(this->GameTypeKeyStr,SpiderBoard::FourSuits).toInt(); + + switch (gameType) + { + case SpiderBoard::OneSuit: + this->m_gameType=SpiderBoard::OneSuit; + break; + + case SpiderBoard::TwoSuits: + this->m_gameType=SpiderBoard::TwoSuits; + break; + + case SpiderBoard::FourSuits: + default: + this->m_gameType=SpiderBoard::FourSuits; + break; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::saveSettings(QSettings & settings) +{ + settings.setValue(this->GameTypeKeyStr,this->m_gameType); +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::setCheat(bool cheat) +{ + this->m_cheat=cheat; + + for(unsigned int i=0;im_stackVector.size();i++) + { + this->m_stackVector[i]->setCheat(cheat); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::slotDealNextCards(CardStack * pCardStackWidget, + unsigned int index) +{ + bool aStackIsEmpty=false; + unsigned int i; + + Q_UNUSED(pCardStackWidget); + Q_UNUSED(index); + + // if the deck has cards to deal make sure all the stacks have cards + // and deal them out + if (!this->m_pDeck->isEmpty()) + { + // first make sure none of the 10 stacks is empty. All must have at least one card. + // to be able to deal the cards. + for(i=0;im_stackVector.size();i++) + { + if (this->m_stackVector[i]->isEmpty()) + { + aStackIsEmpty=true; + break; + } + } + + + if (aStackIsEmpty) + { + QMessageBox::critical(this,this->gameName(), + tr("All stacks must contain at least one card before the next set of cards can be dealt!").trimmed()); + this->stopDemo(); + return; + } + + + DealItemVector dealItemVector; + + + // Create the dealItemVector to direct the DealAnimation object on + // how to deal the cards. + for (i=0;im_stackVector.size();i++) + { + dealItemVector.push_back(DealItem(this->m_stackVector[i],m_pDeck)); + + dealItemVector[i].addCard(true); + } + // ok now start the deal. + m_dealAni.dealCards(dealItemVector); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// ok we need to perform the move from the stackWidget to the sentHome widget +// and create the CardMoveRecord. Then just call slotCardsMoved and let the +// move be processed as if it was a drag and drop +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::slotSendSuitHome(SpiderStack * pStack, + const PlayingCardVector & cardVector, + const CardMoveRecord & startMoveRecord) +{ + if (NULL!=pStack) + { + // ok first find an empty sentHome widget to add the cards too. + SpiderHomeStack * pHome=NULL; + unsigned int i; + for (i=0;im_homeVector.size();i++) + { + if (this->m_homeVector[i]->isEmpty()) + { + pHome=this->m_homeVector[i]; + break; + } + } + + // we should always find an empty home widget. But check just in case + if (pHome) + { + CardMoveRecord moveRecord(startMoveRecord); + // add the cards to the update record. But don't move the + // cards + pHome->addCards(cardVector,moveRecord,true); + + // perform the move of the cards and animate it if animations + // are enabled + m_sToSAniMove.moveCards(moveRecord); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::slotMoveCardsToDiffStack(SpiderStack * pStack, + const PlayingCardVector & cardVector, + const CardMoveRecord & startMoveRecord) +{ + if (NULL!=pStack) + { + SpiderStack * pCanMoveToEmpty=NULL; + SpiderStack * pCanMoveTo=NULL; + SpiderStack * pCanMoveToSameSuit=NULL; + bool cardsWillMove=false; + + for (unsigned int i=0;im_stackVector.size();i++) + { + // ok we are only moving the cards if the hit is not on the same + // stack they are already located in + if (this->m_stackVector[i]!=pStack) + { + // see if we have a perferred move to a stack that has the same suit + // we will break out if we find a perferred match + if (this->m_stackVector[i]->canAddCardsSameSuit(cardVector)) + { + pCanMoveToSameSuit=this->m_stackVector[i]; + cardsWillMove=true; + break; + } + // otherwise see if we can move the cards to the stack at all + else if (this->m_stackVector[i]->canAddCards(cardVector)) + { + if (this->m_stackVector[i]->isEmpty()) + { + pCanMoveToEmpty=this->m_stackVector[i]; + } + else + { + pCanMoveTo=this->m_stackVector[i]; + } + cardsWillMove=true; + } + } + } + + // if we are going to move the cards + if (cardsWillMove) + { + SpiderStack * pNewStack=NULL; + + // ok the best move is to a matching suit and consecutive + // next best is to a consecutive + // and lastly to an empty stack. + if (NULL!=pCanMoveToSameSuit) + { + pNewStack=pCanMoveToSameSuit; + } + else if (NULL!=pCanMoveTo) + { + pNewStack=pCanMoveTo; + } + else + { + pNewStack=pCanMoveToEmpty; + } + + CardMoveRecord moveRecord(startMoveRecord); + pNewStack->addCards(cardVector,moveRecord,true); + + // perform the move of the cards and animate it if animations + // are enabled + m_sToSAniMove.moveCards(moveRecord); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::slotSetFourSuits() +{ + if (SpiderBoard::FourSuits!=this->m_gameType) + { + this->m_gameType=SpiderBoard::FourSuits; + this->newGame(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::slotSetTwoSuits() +{ + if (SpiderBoard::TwoSuits!=this->m_gameType) + { + this->m_gameType=SpiderBoard::TwoSuits; + this->newGame(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::slotSetOneSuit() +{ + if (SpiderBoard::OneSuit!=this->m_gameType) + { + this->m_gameType=SpiderBoard::OneSuit; + this->newGame(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::calcScore() +{ + int score=0; + unsigned int i; + + for(i=0;im_homeVector.size();i++) + { + score+=this->m_homeVector[i]->score(); + } + + for(i=0;im_stackVector.size();i++) + { + score+=this->m_stackVector[i]->score(); + } + + int deals=0; + + // The number of deals left is the number of cards in the deck widget divided by the number of stack widgets + if (!this->m_pDeck->isEmpty() && this->m_stackVector.size()>0) + { + const PlayingCardVector & cardVector=this->m_pDeck->getCardVector(); + + deals=cardVector.size()/this->m_stackVector.size(); + + if (cardVector.size()%this->m_stackVector.size()) + { + deals++; + } + } + + QString dealsLeft(tr("Deals remaining: %1").arg(QString::number(deals)).trimmed()); + + emit scoreChanged(score,dealsLeft); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::resizeEvent (QResizeEvent * event) +{ + unsigned int i; + + GameBoard::resizeEvent(event); + + + QSize cardSize(CardPixmaps::getInst().getCardSize()); + + QPointF currPos(GameBoard::LayoutSpacing,GameBoard::LayoutSpacing); + + m_pDeck->setPos(currPos); + + currPos.setX(GameBoard::LayoutSpacing*3 + cardSize.width()*2); + + for (i=0;isetPos(currPos); + currPos.setX(currPos.x()+cardSize.width()+GameBoard::LayoutSpacing); + } + + currPos.setY(GameBoard::LayoutSpacing*2+cardSize.height()); + currPos.setX(GameBoard::LayoutSpacing); + for (i=0;isetPos(currPos); + currPos.setX(currPos.x()+cardSize.width()+GameBoard::LayoutSpacing); + } + + std::cout<<__FUNCTION__<isEmpty()) + { + slotDealNextCards(); + } + else if (stopWhenNoMore) + { + stopDemo(); + rc=false; + } + else + { + rc=false; + } + } + + return rc; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +void SpiderBoard::createStacks() +{ + setCardResizeAlg(10,ResizeByWidth); + + unsigned int i; + // create all the widgets for the board + for(i=0;i<8;i++) + { + this->m_homeVector.push_back(new SpiderHomeStack); + this->m_scene.addItem(m_homeVector[i]); + + // get signals when cards are added to the stack. So, we can add undo info and + // see when the game is over. + this->connect(this->m_homeVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + } + + for(i=0;i<10;i++) + { + this->m_stackVector.push_back(new SpiderStack); + this->m_scene.addItem(m_stackVector[i]); + + // get signals when cards are added to the stack. So, we can add undo info and + // see when the game is over. + + this->connect(this->m_stackVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + this->connect(this->m_stackVector[i],SIGNAL(sendSuitHome(SpiderStack *,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotSendSuitHome(SpiderStack*,PlayingCardVector,CardMoveRecord))); + this->connect(this->m_stackVector[i],SIGNAL(moveCardsToDiffStack(SpiderStack *,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotMoveCardsToDiffStack(SpiderStack*,PlayingCardVector,CardMoveRecord))); + + + } + + m_pDeck=new CardStack; + this->m_scene.addItem(m_pDeck); + + // get signals when the deck is clicked on so we can deal the next set of cards + this->connect(this->m_pDeck,SIGNAL(cardClicked(CardStack*,uint)), + this,SLOT(slotDealNextCards(CardStack*,uint))); + + std::cout<<__FUNCTION__<<__FILE__<m_homeVector.size();i++) + { + if (this->m_homeVector[i]->isEmpty()) + { + allSuitsSentHome=false; + break; + } + } + + return allSuitsSentHome; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +bool SpiderBoard::isGameWonNotComplete()const +{ + bool rc=m_pDeck->isEmpty(); + + if (rc) + { + for (unsigned int i=0;im_stackVector.size();i++) + { + if (!(this->m_stackVector[i]->cardsAscendingTopToBottom() && + this->m_stackVector[i]->allCardsFaceUp())) + { + rc=false; + break; + } + } + } + + return rc; +} + diff --git a/plugins/qsolocards_plugin/SpiderBoard.h b/plugins/qsolocards_plugin/SpiderBoard.h new file mode 100644 index 000000000..bd0e32a8e --- /dev/null +++ b/plugins/qsolocards_plugin/SpiderBoard.h @@ -0,0 +1,101 @@ +/* + 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 . +*/ + +#ifndef SPIDERBOARD_H +#define SPIDERBOARD_H + +#include "GameBoard.h" +#include "CardStack.h" +#include "SpiderStack.h" +#include "SpiderHomeStack.h" + +#include + +class SpiderBoard : public GameBoard +{ + Q_OBJECT + + public: + enum GameType + { + FourSuits=4, + TwoSuits=2, + OneSuit=1 + }; + + static const QString GameTypeKeyStr; + + SpiderBoard(QWidget * pParent=NULL); + virtual ~SpiderBoard(); + + bool getHint(CardStack * & pSrcWidget, + unsigned int & srcStackIndex, + CardStack * & pDstWidget); + + inline bool hasDemo() const {return true;} + + virtual void newGame(); + + virtual void addGameMenuItems(QMenu & menu); + + virtual void loadSettings(const QSettings & settings); + virtual void saveSettings(QSettings & settings); + + inline bool isCheating() const {return m_cheat;} + + void setCheat(bool cheat); + + inline bool supportsScore() const{return true;} + + public slots: + virtual void slotDealNextCards(CardStack * pCardStackWidget=NULL,unsigned int index=0); + + // these slot catch the signals from the SpiderStacks that are started by + // a click on a card instead of a drag + virtual void slotSendSuitHome(SpiderStack *,const PlayingCardVector &,const CardMoveRecord &); + virtual void slotMoveCardsToDiffStack(SpiderStack *,const PlayingCardVector &,const CardMoveRecord &); + + + void slotSetFourSuits(); + void slotSetTwoSuits(); + void slotSetOneSuit(); + + protected: + void calcScore(); + + virtual void resizeEvent (QResizeEvent * event); + + bool runDemo(bool stopWhenNoMore=true); + + virtual void createStacks(); + + virtual bool isGameWon()const; + virtual bool isGameWonNotComplete()const; + + CardStack * m_pDeck; + std::vector m_homeVector; // we will have 8 items in this + //vector one for each suit (2 decks) + std::vector m_stackVector; // we will have 10 items in this vector + + bool m_cheat; + + + GameType m_gameType; +}; + +#endif // SPIDERBOARD_H diff --git a/plugins/qsolocards_plugin/SpiderHomeStack.cpp b/plugins/qsolocards_plugin/SpiderHomeStack.cpp new file mode 100644 index 000000000..5fb666688 --- /dev/null +++ b/plugins/qsolocards_plugin/SpiderHomeStack.cpp @@ -0,0 +1,70 @@ +/* + 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 "SpiderHomeStack.h" + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +SpiderHomeStack::SpiderHomeStack() + :CardStack() +{ +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +SpiderHomeStack::~SpiderHomeStack() +{ +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +bool SpiderHomeStack::canSendHome(const PlayingCardVector & cardVector) +{ + bool rc=false; + + if (PlayingCard::MaxCardIndex==cardVector.size() && + PlayingCard::King==cardVector[0].getIndex() && + PlayingCard::Ace==cardVector[cardVector.size()-1].getIndex()) + { + rc=true; + for(unsigned int i=1;iisEmpty()) + { + rc=SpiderHomeStack::canSendHome(newCards); + } + + return rc; +} diff --git a/plugins/qsolocards_plugin/SpiderHomeStack.h b/plugins/qsolocards_plugin/SpiderHomeStack.h new file mode 100644 index 000000000..108fb6314 --- /dev/null +++ b/plugins/qsolocards_plugin/SpiderHomeStack.h @@ -0,0 +1,46 @@ +/* + 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 . +*/ + +#ifndef SPIDERHOMESTACK_H +#define SPIDERHOMESTACK_H + +#include "CardStack.h" + +// When a suit is together from King to Ace it can be "sent home" or moved off the +// main board to a separate set stack. When all 8 sets of suits are "sent home" the +// game is won. +class SpiderHomeStack: public CardStack +{ + public: + SpiderHomeStack(); + ~SpiderHomeStack(); + + // this function just tests if the cardVector is complete + // King to Ace of the same suit + static bool canSendHome(const PlayingCardVector &); + + // for this type of stack the score will be 0 or 12 + // or one less than the number of cards in a suit. + // ie we have a sent home suit or nothing. + inline int score() const {return ((isEmpty())?0:PlayingCard::MaxCardIndex-1);} + + bool canAddCards(const PlayingCardVector &); + +}; + +#endif // SPIDERHOMESTACK_H diff --git a/plugins/qsolocards_plugin/SpiderStack.cpp b/plugins/qsolocards_plugin/SpiderStack.cpp new file mode 100644 index 000000000..5ff38576a --- /dev/null +++ b/plugins/qsolocards_plugin/SpiderStack.cpp @@ -0,0 +1,175 @@ +/* + 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 "SpiderStack.h" +#include "SpiderHomeStack.h" + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +SpiderStack::SpiderStack() + :VCardStack(), + m_cheat(false) +{ + this->setAutoTopCardUp(); + + + // connect a slot to get the signal when a movable card is clicked + this->connect(this,SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotMovableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord))); +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +SpiderStack::~SpiderStack() +{ +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +int SpiderStack::score() const +{ + const PlayingCardVector & cardVector=this->getCardVector(); + int score=0; + + for (unsigned int i=1;igetCardVector(); + + if (newCardVector.size()>0) + { + // if there are no cards in the stack then we will accept any cards + if (0==cardVector.size()) + { + rc=true; + } + else if (cardVector[cardVector.size()-1].isPrevCardIndex(newCardVector[0]) && + cardVector[cardVector.size()-1].isFaceUp()) + { + rc=true; + } + } + + return rc; +} + +/////////////////////////////////////////////////////////////////////////////////// +// similar to can Add cards. But in this case the +// suit of the last card in this stack is the same as +// the first suit of the cardVector +/////////////////////////////////////////////////////////////////////////////////// +bool SpiderStack::canAddCardsSameSuit(const PlayingCardVector & newCardVector) +{ + bool rc=false; + + if (this->canAddCards(newCardVector) && !this->isEmpty() && newCardVector.size()>0) + { + const PlayingCardVector & cardVector=this->getCardVector(); + + rc=cardVector[cardVector.size()-1].isSameSuit(newCardVector[0]); + } + + return rc; +} + +/////////////////////////////////////////////////////////////////////////////////// +// if a card is clicked on see if it needs to be sent home or can just be moved +// to another stack. +/////////////////////////////////////////////////////////////////////////////////// +void SpiderStack::slotMovableCardsClicked(CardStack * pCardStack, + const PlayingCardVector & moveCards, + const CardMoveRecord & moveRecord) +{ + bool isSentHome=false; + + Q_UNUSED(pCardStack); + + // first see if the item needs to be sent home + if (SpiderHomeStack::canSendHome(moveCards)) + { + emit sendSuitHome(this,moveCards,moveRecord); + isSentHome=true; + } + + // if this is not a case when the suit can be sent home + // Then we will just emit a signal to try to move the + // set of cards. + if (!isSentHome) + { + emit moveCardsToDiffStack(this,moveCards,moveRecord); + } +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +bool SpiderStack::canMoveCard(unsigned int index) const +{ + if (m_cheat) + { + return true; + } + + bool rc=false; + const PlayingCardVector & cardVector=this->getCardVector(); + + // ok if we have cards in the stack and the index is valid + // see if we can move it. + if (cardVector.size()>0 && index. +*/ + +#ifndef SPIDERSTACK_H +#define SPIDERSTACK_H + +#include "VCardStack.h" + +// This is the stack of cards that are used for the main game play +// There are ten of these stacks. +class SpiderStack: public VCardStack +{ + Q_OBJECT + + public: + SpiderStack(); + ~SpiderStack(); + + inline bool isCheating() const{return m_cheat;} + + inline void setCheat(bool cheat=true){m_cheat=cheat;} + + int score() const; + + bool canAddCards(const PlayingCardVector &); + + // similar to can Add cards. But in this case the + // suit of the last card in this stack is the same as + // the first suit of the cardVector + bool canAddCardsSameSuit(const PlayingCardVector &); + + signals: + // signals that are emitted when a card that can be moved is clicked on + // the move record created will have the Remove and flip actions (if the flip of the + // card before the cards is necessary.) + void sendSuitHome(SpiderStack *,const PlayingCardVector &,const CardMoveRecord &); + void moveCardsToDiffStack(SpiderStack *,const PlayingCardVector &,const CardMoveRecord &); + + public slots: + void slotMovableCardsClicked(CardStack * pCardStack, + const PlayingCardVector &, + const CardMoveRecord &); + + + protected: + bool canMoveCard(unsigned int index) const; + + private: + bool m_cheat; +}; + +#endif // SPIDERSTACK_H diff --git a/plugins/qsolocards_plugin/SpideretteBoard.cpp b/plugins/qsolocards_plugin/SpideretteBoard.cpp new file mode 100644 index 000000000..3106dbbeb --- /dev/null +++ b/plugins/qsolocards_plugin/SpideretteBoard.cpp @@ -0,0 +1,182 @@ +/* + 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 "SpideretteBoard.h" +#include "CardPixmaps.h" + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +SpideretteBoard::SpideretteBoard() +{ + this->setGameName(QString(tr("Spiderette Solitaire")).trimmed()); + this->setGameId("Spiderette"); + + this->setHelpFile(":/help/SpideretteHelp.html"); +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +SpideretteBoard::~SpideretteBoard() +{ +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +void SpideretteBoard::newGame() +{ + // call the base class + GameBoard::newGame(); + + CardDeck deck; + unsigned int i; + + while(!deck.isEmpty()) + { + this->m_pDeck->addCard(deck.next()); + } + + + DealItemVector dealItemVector; + + + // Create the dealItemVector to direct the DealAnimation object on + // how to deal the cards. + for (i=0;im_stackVector.size();i++) + { + dealItemVector.push_back(DealItem(this->m_stackVector[i],m_pDeck)); + + unsigned int j; + + for (j=0;jsetPos(currPos); + + currPos.rx()+=GameBoard::LayoutSpacing*4 + cardSize.width()*4; + + + for (i=0;isetPos(currPos); + currPos.rx()+=cardSize.width()+GameBoard::LayoutSpacing; + } + + currPos.setY(GameBoard::LayoutSpacing*2+cardSize.height()); + currPos.setX(GameBoard::LayoutSpacing*2+cardSize.width()); + for (i=0;isetPos(currPos); + currPos.rx()+=cardSize.width()+GameBoard::LayoutSpacing; + } +} + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// +void SpideretteBoard::createStacks() +{ + setCardResizeAlg(8,ResizeByWidth); + + + unsigned int i; + + // first create the home widgets where the cards need to be eventually stacked to + // win the game. + for(i=0;i<4;i++) + { + this->m_homeVector.push_back(new SpiderHomeStack); + this->m_scene.addItem(m_homeVector[i]); + + // get signals when cards are added to the stack. So, we can add undo info and + // see when the game is over. + this->connect(this->m_homeVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + } + + // now create the 7 rows for the stacks. + for (i=0;i<7;i++) + { + this->m_stackVector.push_back(new SpiderStack); + this->m_scene.addItem(m_stackVector[i]); + + // get signals when cards are added to the stack. So, we can add undo info and + // see when the game is over. + this->connect(this->m_stackVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + this->connect(this->m_stackVector[i],SIGNAL(sendSuitHome(SpiderStack *,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotSendSuitHome(SpiderStack*,PlayingCardVector,CardMoveRecord))); + this->connect(this->m_stackVector[i],SIGNAL(moveCardsToDiffStack(SpiderStack *,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotMoveCardsToDiffStack(SpiderStack*,PlayingCardVector,CardMoveRecord))); + } + + this->m_pDeck=new CardStack; + this->m_scene.addItem(this->m_pDeck); + + // get signals when the deck is clicked on so we can deal the next set of cards + this->connect(this->m_pDeck,SIGNAL(cardClicked(CardStack*,uint)), + this,SLOT(slotDealNextCards(CardStack*,uint))); +} diff --git a/plugins/qsolocards_plugin/SpideretteBoard.h b/plugins/qsolocards_plugin/SpideretteBoard.h new file mode 100644 index 000000000..01be53147 --- /dev/null +++ b/plugins/qsolocards_plugin/SpideretteBoard.h @@ -0,0 +1,43 @@ +/* + 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 . +*/ + +#ifndef __SPIDERETTEBOARD_H__ +#define __SPIDERETTEBOARD_H__ + +#include "SpiderBoard.h" + +class SpideretteBoard:public SpiderBoard +{ + Q_OBJECT +public: + SpideretteBoard(); + virtual ~SpideretteBoard(); + + virtual void newGame(); + + virtual void addGameMenuItems(QMenu & menu); + + virtual void loadSettings(const QSettings & settings); + virtual void saveSettings(QSettings & settings); + +protected: + virtual void resizeEvent (QResizeEvent * event); + virtual void createStacks(); +}; + +#endif diff --git a/plugins/qsolocards_plugin/StackToStackAniMove.cpp b/plugins/qsolocards_plugin/StackToStackAniMove.cpp new file mode 100644 index 000000000..c00049f69 --- /dev/null +++ b/plugins/qsolocards_plugin/StackToStackAniMove.cpp @@ -0,0 +1,290 @@ +/* + 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 "StackToStackAniMove.h" +#include "CardAnimationLock.h" + +#include + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +StackToStackAniMoveItem::StackToStackAniMoveItem(const CardMoveRecord & startMoveRecord,int duration) + :m_pSrc(NULL), + m_pDst(NULL), + m_pFlipStack(NULL), + m_flipIndex(-2), + m_srcTopCardIndex(-1), + m_cardVector(), + m_duration(duration), + m_moveRecord(startMoveRecord) +{ + CardMoveRecord moveRecord(startMoveRecord); + + while(!moveRecord.empty()) + { + CardMoveRecordItem currItem(moveRecord.back()); + CardStack * pStack=CardStack::getStackByName(currItem.stackName()); + const PlayingCardVector & cardVector=currItem.cardVector(); + + CardMoveRecordItem::MoveType moveType=currItem.moveType(); + + switch(moveType) + { + case CardMoveRecordItem::RemoveCards: + { + m_pSrc=pStack; + if (NULL!=m_pSrc) + { + m_srcTopCardIndex=m_pSrc->getCardVector().size()-cardVector.size(); + } + m_cardVector=cardVector; + } + break; + case CardMoveRecordItem::AddCards: + { + m_pDst=pStack; + } + break; + // for this case we are just going to flip the card over + case CardMoveRecordItem::FlipCard: + { + m_flipIndex=currItem.flipIndex(); + m_pFlipStack=pStack; + } + break; + }; + + moveRecord.pop_back(); + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +StackToStackAniMoveItem::StackToStackAniMoveItem(const StackToStackAniMoveItem & rh) + :m_pSrc(NULL), + m_pDst(NULL), + m_pFlipStack(NULL), + m_flipIndex(-1), + m_srcTopCardIndex(-1), + m_cardVector(), + m_duration(0), + m_moveRecord() +{ + *this=rh; +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +StackToStackAniMoveItem::StackToStackAniMoveItem() + :m_pSrc(NULL), + m_pDst(NULL), + m_pFlipStack(NULL), + m_flipIndex(-1), + m_srcTopCardIndex(-1), + m_cardVector(), + m_duration(0), + m_moveRecord() +{ +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +StackToStackAniMoveItem::~StackToStackAniMoveItem() +{ +} + +StackToStackAniMoveItem & StackToStackAniMoveItem::operator=(const StackToStackAniMoveItem & rh) +{ + m_pSrc=rh.m_pSrc; + m_pDst=rh.m_pDst; + m_pFlipStack=rh.m_pFlipStack; + m_flipIndex=rh.m_flipIndex; + m_srcTopCardIndex=rh.m_srcTopCardIndex; + m_cardVector=rh.m_cardVector; + m_duration=rh.m_duration; + m_moveRecord=rh.m_moveRecord; + + return *this; +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +StackToStackAniMove::StackToStackAniMove() + :m_pTimeLine(NULL), + m_flipDelayTimer(), + m_pItemAni(NULL), + m_pPixmapItem(NULL), + m_aniMoveItem(), + m_aniRunning(false) +{ + m_flipDelayTimer.setSingleShot(true); + m_flipDelayTimer.setInterval(250); + this->connect(&m_flipDelayTimer,SIGNAL(timeout()), + this,SLOT(slotWaitForFlipComplete())); +} + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +StackToStackAniMove::~StackToStackAniMove() +{ + delete m_pTimeLine; + delete m_pItemAni; + delete m_pPixmapItem; +} + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +void StackToStackAniMove::moveCards(const CardMoveRecord & moveRecord,int duration) +{ + // if animation is off just process the move record as normal + if (!CardAnimationLock::getInst().animationsEnabled()) + { + CardStack::processCardMoveRecord(CardStack::RedoMove,moveRecord); + emit cardsMoved(moveRecord); + } + else + { + // first if we have an animation running stop it. + slotAniFinished(); + m_aniMoveItem=StackToStackAniMoveItem(moveRecord,duration); + CardAnimationLock::getInst().lock(); + runAnimation(); + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +void StackToStackAniMove::stopAni() +{ + slotAniFinished(false); +} + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +void StackToStackAniMove::slotAniFinished(bool emitSignal) +{ + if (m_aniRunning) + { + m_pItemAni->timeLine()->stop(); + + // add the cards to the destination + m_aniMoveItem.dst()->addCards(m_aniMoveItem.getCardVector()); + + // now update the destination + m_aniMoveItem.dst()->updateStack(); + + // remove the animation object + m_aniMoveItem.dst()->scene()->removeItem(m_pPixmapItem); + + delete m_pPixmapItem; + m_pPixmapItem=NULL; + + + + // use the emit signal to know whether or not to disable the animation. + if (m_aniMoveItem.flipIndex()>-2) + { + m_aniMoveItem.flipStack()->flipCard(m_aniMoveItem.flipIndex(),emitSignal); + } + + CardAnimationLock::getInst().unlock(); + + m_aniRunning=false; + + if (emitSignal) + { + // emit a signal that the move is complete + emit cardsMoved(m_aniMoveItem.moveRecord()); + } + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +void StackToStackAniMove::slotWaitForFlipComplete() +{ + this->runAnimation(); +} + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +void StackToStackAniMove::runAnimation() +{ + m_aniRunning=true; + + // if the flip animation is running for the src or dst + // give it 1/2 a second to complete. + if (m_aniMoveItem.src()->isFlipAniRunning() || + m_aniMoveItem.dst()->isFlipAniRunning()) + { + m_flipDelayTimer.start(); + return; + } + + delete m_pTimeLine; + delete m_pItemAni; + delete m_pPixmapItem; + + + m_pTimeLine=new QTimeLine(m_aniMoveItem.duration()); + m_pItemAni=new QGraphicsItemAnimation; + m_pPixmapItem=new QGraphicsPixmapItem; + + QPixmap * pPixmap=m_aniMoveItem.src()->getStackPixmap(m_aniMoveItem.getCardVector()); + + if (pPixmap) + { + m_pPixmapItem->setPixmap(*pPixmap); + delete pPixmap; + } + + // set the z value to 2 so it will be on top of the + // stacks. + m_pPixmapItem->setZValue(2); + + // add the item to the scene and move it over the stack in the + // place of the cards we are going to move + m_aniMoveItem.src()->scene()->addItem(m_pPixmapItem); + m_pPixmapItem->setPos(m_aniMoveItem.src()->getGlobalCardPt(m_aniMoveItem.srcTopCardIndex())); + + + // setup the animation + m_pItemAni->setItem(m_pPixmapItem); + m_pItemAni->setTimeLine(m_pTimeLine); + + m_pItemAni->setPosAt (0, m_aniMoveItem.src()->getGlobalCardPt(m_aniMoveItem.srcTopCardIndex())); + m_pItemAni->setPosAt (1, m_aniMoveItem.dst()->getGlobalCardAddPt()); + + // connect up the slot so we will know when it is finished. + this->connect(m_pTimeLine,SIGNAL(finished()), + this,SLOT(slotAniFinished())); + + for (unsigned int i=0;iremoveTopCard(); + } + + // redraw the source stack and start the animation. + m_aniMoveItem.src()->updateStack(); + + m_pTimeLine->start(); +} diff --git a/plugins/qsolocards_plugin/StackToStackAniMove.h b/plugins/qsolocards_plugin/StackToStackAniMove.h new file mode 100644 index 000000000..3e6da6894 --- /dev/null +++ b/plugins/qsolocards_plugin/StackToStackAniMove.h @@ -0,0 +1,102 @@ +/* + 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 . +*/ + +#ifndef __STACKTOSTACKANIMOVE_H__ +#define __STACKTOSTACKANIMOVE_H__ + +#include "CardStack.h" +#include "CardMoveRecord.h" + +#include +#include +#include +#include +#include + +/* + StackToStackAniMove is just for moving one set of cards to another stack. Normal usage is + when a card in one stack is clicked on and then it is determined that this should result + in moving the card(s) to a different stack. (Auto)flipping + a card when the move is complete is also done if included in the moveRecord. +*/ + +class StackToStackAniMoveItem +{ +public: + StackToStackAniMoveItem(const CardMoveRecord & startMoveRecord,int duration); + StackToStackAniMoveItem(const StackToStackAniMoveItem & rh); + StackToStackAniMoveItem(); + + virtual ~StackToStackAniMoveItem(); + + inline CardStack * src() {return m_pSrc;} + inline CardStack * dst() {return m_pDst;} + inline CardStack * flipStack() {return m_pFlipStack;} + inline int flipIndex()const{return m_flipIndex;} + inline int srcTopCardIndex()const {return m_srcTopCardIndex;} + inline const PlayingCardVector & getCardVector() const{return m_cardVector;} + inline int duration()const{return m_duration;} + inline const CardMoveRecord & moveRecord(){return m_moveRecord;} + + StackToStackAniMoveItem & operator=(const StackToStackAniMoveItem & rh); + +private: + CardStack * m_pSrc; + CardStack * m_pDst; + CardStack * m_pFlipStack; + int m_flipIndex; + int m_srcTopCardIndex; + PlayingCardVector m_cardVector; + int m_duration; + CardMoveRecord m_moveRecord; +}; + + +class StackToStackAniMove:public QObject +{ + Q_OBJECT +public: + StackToStackAniMove(); + virtual ~StackToStackAniMove(); + + void moveCards(const CardMoveRecord & startMoveRecord,int duration=400); + void stopAni(); + +signals: + void cardsMoved(const CardMoveRecord & moveRecord); + +public slots: + void slotAniFinished(bool emitSignal=true); + void slotWaitForFlipComplete(); + +protected: + + void runAnimation(); + +private: + QTimeLine * m_pTimeLine; + QTimer m_flipDelayTimer; + QGraphicsItemAnimation * m_pItemAni; + QGraphicsPixmapItem * m_pPixmapItem; + StackToStackAniMoveItem m_aniMoveItem; + bool m_aniRunning; +}; + + + +#endif diff --git a/plugins/qsolocards_plugin/StackToStackFlipAni.cpp b/plugins/qsolocards_plugin/StackToStackFlipAni.cpp new file mode 100644 index 000000000..6ec4565d9 --- /dev/null +++ b/plugins/qsolocards_plugin/StackToStackFlipAni.cpp @@ -0,0 +1,334 @@ +/* + 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 "StackToStackFlipAni.h" +#include "CardAnimationLock.h" +#include "CardPixmaps.h" + +#include +#include + +#include + +const qreal StackToStackFlipAni::ExposedPrecentShownCards=.18; +const qreal StackToStackFlipAni::ExposedPrecentHiddenCards=.02; + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +StackToStackFlipAni::StackToStackFlipAni() + :m_pDst(NULL), + m_pSrc(NULL), + m_cardVector(), + m_firstCardToShow(0), + m_flipPtReached(false), + m_moveRecord(), + m_pTimeLine(NULL), + m_pItemAni(NULL), + m_pPixmapItem(NULL), + m_aniRunning(false) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +StackToStackFlipAni::~StackToStackFlipAni() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +void StackToStackFlipAni::moveCards(CardStack * pDst,CardStack * pSrc, + int numCards,int cardsShown, + int duration) +{ + // first if we have an animation running stop it. + this->stopAni(); + + // setup the next animation. + m_pDst=pDst; + m_pSrc=pSrc; + m_cardVector.clear(); + m_moveRecord.clear(); + m_flipPtReached=false; + + while( !m_pSrc->isEmpty() && numCards>0) + { + PlayingCard card(m_pSrc->removeTopCard(m_moveRecord)); + + m_cardVector.insert(m_cardVector.begin(),card); + numCards--; + } + + // by default we will show all cards + m_firstCardToShow=0; + + // if we are not showing all cards starting with index 0 + // then figure out the index of the first card that will + // be shown. + if (m_cardVector.size()>0 && cardsShown>=0 && + cardsShown<(int)m_cardVector.size()) + { + // ok if the value is 0 or 1. We will just show + // the last card. 0 doesn't make any sense if you + // are flipping cards. So, we will assume one for + // that case as well. + if (cardsShown<=1) + { + m_firstCardToShow=m_cardVector.size()-1; + } + else + { + m_firstCardToShow=m_cardVector.size()-cardsShown; + } + } + + + // if animation is off just immediately add the cards to the new + // stack. Call updateStack to redraw the stacks. And emit the + // signal that the cards have been moved. + if (!CardAnimationLock::getInst().animationsEnabled()) + { + this->flipCards(); + m_pSrc->updateStack(); + + m_pDst->addCards(m_cardVector,m_moveRecord); + m_pDst->updateStack(); + emit cardsMoved(m_moveRecord); + } + else + { + CardAnimationLock::getInst().lock(); + runAnimation(duration); + } + +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +void StackToStackFlipAni::slotAniFinished(bool emitSignal) +{ + if (m_aniRunning) + { + m_aniRunning=false; + this->m_pTimeLine->stop(); + + m_pDst->addCards(m_cardVector,m_moveRecord); + m_pDst->updateStack(); + + // remove the animation object + m_pSrc->scene()->removeItem(m_pPixmapItem); + delete m_pPixmapItem; + m_pPixmapItem=NULL; + + CardAnimationLock::getInst().unlock(); + + if (emitSignal) + { + emit cardsMoved(m_moveRecord); + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +void StackToStackFlipAni::slotAniProgress(qreal currProgress) +{ + if (currProgress>=.6 && !m_flipPtReached) + { + m_flipPtReached=true; + + this->flipCards(); + + QPixmap * pPixmap=this->getAniPixmap(); + + if (pPixmap) + { + m_pPixmapItem->setPixmap(*pPixmap); + delete pPixmap; + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +void StackToStackFlipAni::runAnimation(int duration) +{ + m_aniRunning=true; + + delete m_pTimeLine; + delete m_pItemAni; + delete m_pPixmapItem; + + + m_pTimeLine=new QTimeLine(duration); + m_pItemAni=new QGraphicsItemAnimation; + m_pPixmapItem=new QGraphicsPixmapItem; + + + QPixmap * pPixmap=this->getAniPixmap(); + + if (pPixmap) + { + m_pPixmapItem->setPixmap(*pPixmap); + delete pPixmap; + } + + // set the z value to 2 so it will be on top of the + // stacks. + m_pPixmapItem->setZValue(2); + + // add the item to the scene and move it over the stack in the + // place of the cards we are going to move + m_pSrc->scene()->addItem(m_pPixmapItem); + m_pPixmapItem->setPos(m_pSrc->getGlobalLastCardPt()); + + + // setup the animation + m_pItemAni->setItem(m_pPixmapItem); + m_pItemAni->setTimeLine(m_pTimeLine); + + // set the start and end point + m_pItemAni->setPosAt (0, m_pSrc->getGlobalLastCardPt()); + m_pItemAni->setPosAt (1, m_pDst->getGlobalCardAddPt()); + + // set the scaling to give the flipping effect. + m_pItemAni->setScaleAt( 0, 1, 1 ); + m_pItemAni->setScaleAt( 0.6, 0, 1 ); + m_pItemAni->setScaleAt( 1, 1, 1 ); + + // connect up the slot so we will know when it is finished. + this->connect(m_pTimeLine,SIGNAL(finished()), + this,SLOT(slotAniFinished())); + + this->connect(m_pTimeLine,SIGNAL(valueChanged(qreal)), + this,SLOT(slotAniProgress(qreal))); + + // update the src stack behind the flip item we just added + m_pSrc->updateStack(); + + m_pTimeLine->start(); +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +QPixmap * StackToStackFlipAni::getAniPixmap() +{ + QPixmap * pPixmap=NULL; + + if (m_cardVector.size()>0) + { + unsigned int i; + + pPixmap =new QPixmap(this->calcPixmapSize()); + // for linux the transparent fill must be done before + // we associate the pixmap with the painter + pPixmap->fill(Qt::transparent); + + QPainter painter(pPixmap); + + + QPoint pt(0,0); + + for (i=0;i=m_firstCardToShow && m_cardVector[index].isFaceUp()) + { + increment=CardPixmaps::getInst().getCardSize().width()*ExposedPrecentShownCards; + } + else + { + increment=CardPixmaps::getInst().getCardSize().width()*ExposedPrecentHiddenCards; + } + } + + return increment; +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +void StackToStackFlipAni::flipCards() +{ + + if (m_cardVector.size()>0) + { + int i; + + PlayingCardVector flipVector; + + for(i=m_cardVector.size()-1;i>=0;i--) + { + m_cardVector[i].setFaceUp(!m_cardVector[i].isFaceUp()); + flipVector.push_back(m_cardVector[i]); + } + + m_cardVector.clear(); + m_cardVector=flipVector; + } +} diff --git a/plugins/qsolocards_plugin/StackToStackFlipAni.h b/plugins/qsolocards_plugin/StackToStackFlipAni.h new file mode 100644 index 000000000..f4065c894 --- /dev/null +++ b/plugins/qsolocards_plugin/StackToStackFlipAni.h @@ -0,0 +1,80 @@ +/* + 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 . +*/ + +#ifndef __STACKTOSTACKFLIPANI_H__ +#define __STACKTOSTACKFLIPANI_H__ + +#include "CardStack.h" +#include "CardMoveRecord.h" + +#include +#include +#include +#include +#include + +class StackToStackFlipAni: public QObject +{ + Q_OBJECT +public: + static const qreal ExposedPrecentShownCards; + static const qreal ExposedPrecentHiddenCards; + + StackToStackFlipAni(); + virtual ~StackToStackFlipAni(); + + inline bool isAniRunning() const{return m_aniRunning;} + + inline void stopAni(){if (m_aniRunning){slotAniFinished(false);m_aniRunning=false;}} + + void moveCards(CardStack * pDst,CardStack * pSrc, + int numCards=1,int cardsShown=-1, + int duration=500); + +signals: + void cardsMoved(const CardMoveRecord & moveRecord); + +public slots: + void slotAniFinished(bool emitSignal=true); + void slotAniProgress(qreal currProgress); + +protected: + virtual void runAnimation(int duration); + + virtual QPixmap * getAniPixmap(); + + QSize calcPixmapSize(); + int getOverlapIncrement(unsigned int index); + + void flipCards(); + +private: + CardStack * m_pDst; + CardStack * m_pSrc; + PlayingCardVector m_cardVector; + unsigned int m_firstCardToShow; // first index into m_cardVector to show + bool m_flipPtReached; + CardMoveRecord m_moveRecord; + + QTimeLine * m_pTimeLine; + QGraphicsItemAnimation * m_pItemAni; + QGraphicsPixmapItem * m_pPixmapItem; + bool m_aniRunning; +}; + +#endif diff --git a/plugins/qsolocards_plugin/VCardStack.cpp b/plugins/qsolocards_plugin/VCardStack.cpp new file mode 100644 index 000000000..3f4a21c6c --- /dev/null +++ b/plugins/qsolocards_plugin/VCardStack.cpp @@ -0,0 +1,333 @@ +/* + 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 "VCardStack.h" +#include "CardPixmaps.h" +#include +#include + +#include + +const qreal VCardStack::ExposedPrecentFaceUp=.23; +const qreal VCardStack::ExposedPrecentFaceDown=.10; + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +VCardStack::VCardStack() + :m_bRectVector(), + m_compressValue(CompressNormal), + m_percentScene(1) +{ +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +VCardStack::~VCardStack() +{ +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +void VCardStack::setStackBottom(qreal percentScene) +{ + if(percentScene>=0 && percentScene<=1) + { + m_percentScene=percentScene; + } + else + { + m_percentScene=1; + } +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +QPointF VCardStack::getGlobalCardAddPt() const +{ + QPointF pt(0,0); + + const PlayingCardVector & cardVector=this->getCardVector(); + + // We are going to do this by the bounding rects and not by actual cards + // in the stacks. That way we can add something before doing animations + // and then update the display when the animation is complete + if (m_bRectVector.size()>0 && cardVector.size()>=m_bRectVector.size()) + { + pt=m_bRectVector[m_bRectVector.size()-1].topLeft(); + + pt.ry()+=getOverlapIncrement(cardVector[m_bRectVector.size()-1], + m_compressValue); + } + + return mapToScene(pt); +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +QPointF VCardStack::getGlobalLastCardPt() const +{ + QPointF pt(0,0); + + const PlayingCardVector & cardVector=this->getCardVector(); + + // We are going to do this by the bounding rects and not by actual cards + // in the stacks. That way we can add something before doing animations + // and then update the display when the animation is complete + if (m_bRectVector.size()>0 && cardVector.size()>=m_bRectVector.size()) + { + pt=m_bRectVector[m_bRectVector.size()-1].topLeft(); + } + + return mapToScene(pt); +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +QPointF VCardStack::getGlobalCardPt(int index) const +{ + QPointF pt(0,0); + + if (index>=0 && index<(int)m_bRectVector.size()) + { + pt=m_bRectVector[index].topLeft(); + } + + return mapToScene(pt); +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +void VCardStack::updateStack() +{ + QSize size; + const PlayingCardVector & cardVector=this->getCardVector(); + + // the compress value decresses how much of cards are exposed. + // The preferred exposed value is normal. But we will decrease the + // values down to a quarter of the desired to make the stack fit on + // the screen. This function uses the m_precentScene value to determine + // the bottom point of the stack + for(m_compressValue=CompressNormal;m_compressValuescene()->sceneRect().bottom()*m_percentScene)>mapToScene(QPointF(0,size.height())).y()) + { + break; + } + } + + QPixmap * pPixmap=NULL; + + // draw the card and calc the bounding rectangles while we are at it. + if (this->isFlipAniRunning()) + { + PlayingCardVector newCardVector(cardVector); + + // the stack should have at least one card ie the one being flipped + // but make sure. + if (cardVector.size()>0) + { + newCardVector.pop_back(); + } + + // draw the card and calc the bounding rectangles while we are at it. + pPixmap=getStackPixmap(newCardVector,isHighlighted(), + hintHighlightIndex(),m_compressValue, + &m_bRectVector); + } + else + { + // draw the card and calc the bounding rectangles while we are at it. + pPixmap=getStackPixmap(cardVector,isHighlighted(), + hintHighlightIndex(),m_compressValue, + &m_bRectVector); + } + + if (NULL!=pPixmap) + { + this->setPixmap(*pPixmap); + delete pPixmap; + } +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +QPixmap * VCardStack::getStackPixmap(const PlayingCardVector & cardVector, + bool highlighted, + int hintHighlightIndex) +{ + return getStackPixmap(cardVector,highlighted, + hintHighlightIndex,CompressNormal,NULL); +} + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +bool VCardStack::getCardIndex(const QPointF & pos,unsigned int & index) +{ + bool rc=false; + + unsigned int i; + + for(i=0;im_bRectVector.size();i++) + { + if (this->m_bRectVector[i].contains(pos)) + { + index=i; + rc=true; + break; + } + } + + return rc; +} + + +//////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////// +void VCardStack::calcPixmapSize(const PlayingCardVector & cardVector, + QSize & size,qreal compressValue) +{ + unsigned int i; + + if (0==cardVector.size()) + { + size=CardPixmaps::getInst().getCardSize(); + } + else + { + unsigned int sizeY=0; + + for (i=0;iclear(); + } + + // first handle the case that there are no cards in the stack + if (0==cardVector.size()) + { + bool hl=(highlighted || HintHighlightNoCards==hintHighlightIndex); + pPixmap=new QPixmap(CardPixmaps::getInst().getCardNonePixmap(hl,this->showRedealCircle())); + } + else + { + unsigned int i; + QSize cardSize(CardPixmaps::getInst().getCardSize()); + QSize pixmapSize(0,0); + + this->calcPixmapSize(cardVector,pixmapSize,compressValue); + + pPixmap =new QPixmap(pixmapSize); + // for linux the transparent fill must be done before + // we associate the pixmap with the painter + pPixmap->fill(Qt::transparent); + + QPainter painter(pPixmap); + + + QPoint pt(0,0); + + for (i=0;i=0 && hintHighlightIndex<=(int)i) || + ((cardVector.size()-1==i) && highlighted)); + + if (cardVector[i].isFaceUp()) + { + painter.drawPixmap(pt,CardPixmaps::getInst().getCardPixmap(cardVector[i],hl)); + } + else + { + painter.drawPixmap(pt,CardPixmaps::getInst().getCardBackPixmap(hl)); + } + + unsigned int incrementValue=getOverlapIncrement(cardVector[i], + compressValue); + + if (pBRectVector) + { + // if it is the last card we just want the full size + // of the card. + if (cardVector.size()-1==i) + { + pBRectVector->push_back(QRectF(QPointF(0,pt.y()),cardSize)); + } + else + { + pBRectVector->push_back(QRectF(QPointF(0,pt.y()),QSize(cardSize.width(),incrementValue))); + } + } + + // increment the point that we are going to paint the + // card pixmap onto this pixmap + pt.ry()+=incrementValue; + + } + } + return pPixmap; +} diff --git a/plugins/qsolocards_plugin/VCardStack.h b/plugins/qsolocards_plugin/VCardStack.h new file mode 100644 index 000000000..c78a0f8aa --- /dev/null +++ b/plugins/qsolocards_plugin/VCardStack.h @@ -0,0 +1,88 @@ +/* + 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 . +*/ + +#ifndef VCARDSTACK_H +#define VCARDSTACK_H + +#include "CardStack.h" +#include +#include + +typedef std::vector CardBRectVect; + + +// this class will show cards stacked but all cards +// will be partly visible with a card on top of a card revealing +// a portion of the top of the card beneath it. +class VCardStack: public CardStack +{ + Q_OBJECT +public: + static const qreal ExposedPrecentFaceUp; // the precentage show for a face up card will be more than + // that for a card that is face down. Since, we want to be + // able to see the value of the card if it is face up. + static const qreal ExposedPrecentFaceDown; + + enum + { + CompressNormal=1, + CompressMax=4 + }; + + VCardStack(); + virtual ~VCardStack(); + + + // this function allows the caller to set the preportion of the screen that the + // stack can decend too. For example, 1 is the default which means to the bottom + // of the scene. To make the bottom 3/4 of the scene use .75 etc... 1 is the maximum + // value. + void setStackBottom(qreal percentScene); + qreal stackBottom() const{return m_percentScene;} + + // this function gets the point in the scene that a card would be added to this stack. + virtual QPointF getGlobalCardAddPt() const; + virtual QPointF getGlobalLastCardPt() const; + virtual QPointF getGlobalCardPt(int index) const; + + virtual void updateStack(); + + virtual QPixmap * getStackPixmap(const PlayingCardVector & cardVector, + bool highlighted=false, + int hintHighlightIndex=-1); +protected: + virtual bool getCardIndex(const QPointF & pos,unsigned int & index); + + void calcPixmapSize(const PlayingCardVector & cardVector, + QSize & size,qreal compressValue); + + virtual unsigned int getOverlapIncrement(const PlayingCard & card,qreal compressValue) const; + + virtual QPixmap * getStackPixmap(const PlayingCardVector & cardVector, + bool highlighted, + int hintHighlightIndex, + qreal compressValue, + CardBRectVect * pBRectVector); + +private: + CardBRectVect m_bRectVector; + + qreal m_compressValue; + qreal m_percentScene; +}; +#endif diff --git a/plugins/qsolocards_plugin/YukonBoard.cpp b/plugins/qsolocards_plugin/YukonBoard.cpp new file mode 100644 index 000000000..e2865e4e9 --- /dev/null +++ b/plugins/qsolocards_plugin/YukonBoard.cpp @@ -0,0 +1,488 @@ +/* + 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 "YukonBoard.h" +#include "CardPixmaps.h" +#include + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +YukonBoard::YukonBoard() + :GameBoard(NULL,QString(tr("Yukon Solitaire")).trimmed(),QString("Yukon")), + m_pDeck(NULL), + m_homeVector(), + m_stackVector(), + m_cheat(false) +{ + this->setHelpFile(":/help/YukonHelp.html"); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +YukonBoard::~YukonBoard() +{ +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +bool YukonBoard::getHint(CardStack * & pSrc, + unsigned int & srcStackIndex, + CardStack * & pDst) +{ + bool rc=false; + unsigned int i; + + // ok we will look for a move based on trying to move the first faceup + // card in a stack. The basic strategy for this game is to get all cards turned + // over. + if (!rc) + { + for (i=0;im_stackVector.size() && !rc;i++) + { + unsigned int j; + + for (j=0;jm_stackVector.size() && !rc;j++) + { + // can't move a stack to itself + if (i!=j) + { + PlayingCardVector addCardVector(this->m_stackVector[j]->getCardVector()); + unsigned int k=0; + while (!rc && addCardVector.size()>0) + { + // ok find the first card that is faceup. + if (!addCardVector[0].isFaceUp()) + { + addCardVector.erase(addCardVector.begin()); + } + // no need to do this if a king is already face up and the first card in the stack. + else if (!(PlayingCard::King==addCardVector[0].getIndex() && 0==k && + this->m_stackVector[i]->isEmpty()) && + this->m_stackVector[i]->canAddCards(addCardVector)) + { + pDst=this->m_stackVector[i]; + srcStackIndex=k; + pSrc=this->m_stackVector[j]; + + rc=true; + } + else + { + break; + } + k++; + } + } + } + } + } + + // ok let's see if we have an empty stack + // and a face up king. + if (!rc) + { + CardStack * pEmptyStack=NULL; + CardStack * pFaceUpKingStack=NULL; + unsigned int faceUpKingIndex=0; + + for (i=0;im_stackVector.size() && !rc;i++) + { + if (NULL==pEmptyStack && this->m_stackVector[i]->isEmpty()) + { + pEmptyStack=this->m_stackVector[i]; + } + + if (NULL==pFaceUpKingStack) + { + const PlayingCardVector cardVector=this->m_stackVector[i]->getCardVector(); + + unsigned int j; + + for(j=0;jm_homeVector.size() && !rc;i++) + { + unsigned int j; + + for (j=0;jm_stackVector.size() && !rc;j++) + { + const PlayingCardVector cardVector=this->m_stackVector[j]->getCardVector(); + + if (cardVector.size()>0) + { + PlayingCardVector addCardVector; + + addCardVector.push_back(cardVector[cardVector.size()-1]); + + if (this->m_homeVector[i]->canAddCards(addCardVector)) + { + pDst=this->m_homeVector[i]; + srcStackIndex=cardVector.size()-1; + pSrc=this->m_stackVector[j]; + + rc=true; + } + } + } + } + } + + // look at each stack and try to find the first available card that from another + // stack that can be moved to the stack. + if (!rc) + { + for (i=0;im_stackVector.size() && !rc;i++) + { + unsigned int j; + + for (j=0;jm_stackVector.size() && !rc;j++) + { + // can't move a stack to itself + if (i!=j) + { + PlayingCardVector addCardVector(this->m_stackVector[j]->getCardVector()); + unsigned int k=0; + while (!rc && addCardVector.size()>0) + { + // ok find the first card that is faceup. + if (!addCardVector[0].isFaceUp()) + { + addCardVector.erase(addCardVector.begin()); + } + else if (this->m_stackVector[i]->canAddCards(addCardVector)) + { + pDst=this->m_stackVector[i]; + srcStackIndex=k; + pSrc=this->m_stackVector[j]; + + rc=true; + } + else + { + addCardVector.erase(addCardVector.begin()); + } + k++; + } + } + } + } + } + + + + return rc; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void YukonBoard::newGame() +{ + // call the base class + GameBoard::newGame(); + + CardDeck deck; + unsigned int i; + + + while(!deck.isEmpty()) + { + this->m_pDeck->addCard(deck.next()); + } + + + DealItemVector dealItemVector; + + + // Create the dealItemVector to direct the DealAnimation object on + // how to deal the cards. + for (i=0;im_stackVector.size();i++) + { + dealItemVector.push_back(DealItem(this->m_stackVector[i],m_pDeck)); + + unsigned int j; + + for (j=0;j0) + { + for (j=0;j<4;j++) + { + dealItemVector[i].addCard(true); + } + } + } + + // ok now start the deal. We don't need a move record for this item. + m_dealAni.dealCards(dealItemVector,false); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void YukonBoard::addGameMenuItems(QMenu & menu) +{ + Q_UNUSED(menu); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void YukonBoard::loadSettings(const QSettings & settings) +{ + Q_UNUSED(settings); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void YukonBoard::saveSettings(QSettings & settings) +{ + Q_UNUSED(settings); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void YukonBoard::setCheat(bool cheat) +{ + this->m_cheat=cheat; + + for(unsigned int i=0;im_stackVector.size();i++) + { + m_stackVector[i]->setCheat(cheat); + } +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void YukonBoard::slotStackCardsClicked(CardStack * pCardStack, + const PlayingCardVector & cardVector, + const CardMoveRecord & startMoveRecord) +{ + unsigned int i=0; + CardStack * pFoundStack=NULL; + + if (NULL==pCardStack) + { + return; + } + + // first see if the card can be added to the sent home stack + if (cardVector.size()==1) + { + for(i=0;im_homeVector.size();i++) + { + if (pCardStack!=this->m_homeVector[i] && + this->m_homeVector[i]->canAddCards(cardVector)) + { + pFoundStack=this->m_homeVector[i]; + break; + } + } + } + + // if we did not find a match look at the stacks. + if (NULL==pFoundStack) + { + for(i=0;im_stackVector.size();i++) + { + if (pCardStack!=this->m_stackVector[i] && + this->m_stackVector[i]->canAddCards(cardVector)) + { + pFoundStack=this->m_stackVector[i]; + break; + } + } + } + + if (pFoundStack) + { + CardMoveRecord moveRecord(startMoveRecord); + pFoundStack->addCards(cardVector,moveRecord,true); + + // perform the move of the cards and animate it if animations + // are enabled + m_sToSAniMove.moveCards(moveRecord); + } +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void YukonBoard::calcScore() +{ + int score=0; + + for(unsigned int i=0;im_homeVector.size();i++) + { + score+=this->m_homeVector[i]->score(); + } + + emit scoreChanged(score,""); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void YukonBoard::resizeEvent (QResizeEvent * event) +{ + int i; + + this->setCardResizeAlg(8,ResizeByWidth); + + GameBoard::resizeEvent(event); + + QSize cardSize(CardPixmaps::getInst().getCardSize()); + + // ok let's see if it fits when we size things by width + // basically we just need to check if we have room to draw + // 4 cards vertically. If we don't have enough room we + // will try to draw by height. + if (cardSize.height()*4+GameBoard::LayoutSpacing*5>event->size().height()) + { + this->setCardResizeAlg(4,ResizeByHeight); + + GameBoard::resizeEvent(event); + + cardSize=CardPixmaps::getInst().getCardSize(); + } + + + + QPointF currPos(GameBoard::LayoutSpacing,GameBoard::LayoutSpacing); + + + for (i=0;i(m_homeVector.size());i++) + { + m_homeVector[i]->setPos(currPos); + currPos.ry()+=GameBoard::LayoutSpacing+cardSize.height(); + } + + currPos.setX(event->size().width()-GameBoard::LayoutSpacing-cardSize.width()); + currPos.setY(GameBoard::LayoutSpacing); + for (i=m_stackVector.size()-1;i>=0;i--) + { + m_stackVector[i]->setPos(currPos); + currPos.rx()-=cardSize.width()+GameBoard::LayoutSpacing; + } + + + currPos.setX(GameBoard::LayoutSpacing*4+cardSize.width()*4); + currPos.setY(event->size().height()-GameBoard::LayoutSpacing-cardSize.height()); + + m_pDeck->setPos(currPos); + +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void YukonBoard::createStacks() +{ + unsigned int i; + + // first create the home widgets where the cards need to be eventually stacked to + // win the game. + for(i=0;i<4;i++) + { + this->m_homeVector.push_back(new FreeCellHome); + this->m_scene.addItem(m_homeVector[i]); + } + + // now create the 7 rows for the stacks. + for (i=0;i<7;i++) + { + this->m_stackVector.push_back(new KlondikeStack); + this->m_scene.addItem(m_stackVector[i]); + this->connect(this->m_stackVector[i],SIGNAL(cardsMovedByDragDrop(CardMoveRecord)), + this,SLOT(slotCardsMoved(CardMoveRecord))); + this->connect(this->m_stackVector[i],SIGNAL(movableCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord)), + this,SLOT(slotStackCardsClicked(CardStack*,PlayingCardVector,CardMoveRecord))); + } + + this->m_pDeck=new FreeCellDeck; + this->m_scene.addItem(this->m_pDeck); + +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +bool YukonBoard::isGameWon()const +{ + bool rc=true; + + for (unsigned int i=0;im_homeVector.size();i++) + { + if (!this->m_homeVector[i]->isStackComplete()) + { + rc=false; + break; + } + } + + return rc; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +bool YukonBoard::isGameWonNotComplete()const +{ + bool rc=true; + + for (unsigned int i=0;im_stackVector.size();i++) + { + if (!(this->m_stackVector[i]->cardsAscendingTopToBottom() && + this->m_stackVector[i]->allCardsFaceUp())) + { + rc=false; + break; + } + } + + return rc; +} diff --git a/plugins/qsolocards_plugin/YukonBoard.h b/plugins/qsolocards_plugin/YukonBoard.h new file mode 100644 index 000000000..64a38a740 --- /dev/null +++ b/plugins/qsolocards_plugin/YukonBoard.h @@ -0,0 +1,80 @@ +/* + 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 . +*/ + +#ifndef __YUKONBOARD_H__ +#define __YUKONBOARD_H__ + +#include "GameBoard.h" +#include "FreeCellHome.h" +#include "FreeCellDeck.h" +#include "KlondikeStack.h" + +#include + + +class YukonBoard : public GameBoard +{ + Q_OBJECT +public: + YukonBoard(); + ~YukonBoard(); + + bool getHint(CardStack * & pSrc, + unsigned int & srcStackIndex, + CardStack * & pDst); + + inline bool hasDemo() const {return true;} + + void newGame(); + + void addGameMenuItems(QMenu & menu); + + void loadSettings(const QSettings & settings); + void saveSettings(QSettings & settings); + + inline bool isCheating() const {return m_cheat;} + + void setCheat(bool cheat); + + inline bool supportsScore() const{return true;} + +public slots: + void slotStackCardsClicked(CardStack * pCardStack, + const PlayingCardVector & cardVector, + const CardMoveRecord &); + +protected: + void calcScore(); + + virtual void resizeEvent (QResizeEvent * event); + + virtual void createStacks(); + + bool isGameWon()const; + bool isGameWonNotComplete()const; + +private: + FreeCellDeck * m_pDeck; + + std::vector m_homeVector; // we will have 4 items in this vector one for each suit + std::vector m_stackVector; // we will have 7 items in this vector + + bool m_cheat; +}; + +#endif // YUKONBOARD_H diff --git a/plugins/qsolocards_plugin/help/._gpl3.html b/plugins/qsolocards_plugin/help/._gpl3.html new file mode 100644 index 0000000000000000000000000000000000000000..864802133011523c3c9ef704b0fbe864bb6f8be2 GIT binary patch literal 197 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@nj$d@s9#A5x_AdB#1$W^CM6xNXHBy z)9Mr07E1orvLx| literal 0 HcmV?d00001 diff --git a/plugins/qsolocards_plugin/help/FreeCellHelp.html b/plugins/qsolocards_plugin/help/FreeCellHelp.html new file mode 100644 index 000000000..71d1499eb --- /dev/null +++ b/plugins/qsolocards_plugin/help/FreeCellHelp.html @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + +

Freecell +Solitaire

+

Written +by Steve Moore

+

Overview

+

Freecell +Solitaire is a solitaire game played with the standard 52 card deck. +The object is to arrange cards of the same suit from ace to king.

+

Rules

+

The +board is setup with eight stacks of cards, four “freecells”, and +four home stacks. The goal is to move all cards to the home stacks in +ascending order from ace to king of the same suit. Cards are placed +one at a time in order on the home stacks. The eight stacks of cards +are dealt with the first four stacks containing seven cards and the +last four contains size cards. All cards in the eight stacks are +dealt face up. Cards can be moved between the stacks by placing red +cards on black cards in descending order from king to ace. But only +one card can be moved to a stack or freecell at a time. A card can +also be played on the home stack, if it is an ace or the next card in +ascending order of a suit in one of the home stacks. Any card can be +placed in an empty freecell or an empty stack. Play will continue +until all moves are exhausted or until all cards are moved to the +home stacks and the game is won. +

+

Scoring

+

A +point is scored when a card is moved to one of the home stacks. A +total of 52 points can be scored, one for each card in the deck. The +current score is indicated in the status bar at the bottom of the +game window.

+

Game +Play

+

Cards +that are movable will be indicated when the mouse is over them with +the open hand icon. Cards with the open hand icon displayed over them +can be dragged and dropped to another stack or clicked to move them +to another stack. Hints of possible moves are available from the menu +select Control->Hint.

+ + \ No newline at end of file diff --git a/plugins/qsolocards_plugin/help/KlondikeHelp.html b/plugins/qsolocards_plugin/help/KlondikeHelp.html new file mode 100644 index 000000000..1da5ab701 --- /dev/null +++ b/plugins/qsolocards_plugin/help/KlondikeHelp.html @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + +

Klondike +Solitaire

+

Written +by Steve Moore

+

Overview

+

Klondike +Solitaire is a solitaire game played with the standard 52 card deck. +The variations of the game all deal with how many cards are flipped +at once from the deck, and how many times the deck of cards can be +cycled through. The variations are:

+
    +
  • Flip + one – one card is flipped over from the deck at a time, and the + deck can be recycled two times.

    +
  • Flip + three – three cards are flipped over from the deck at a time, and + the there is no limit on the number of times the deck can be + recycled. +

    +
  • No + redeals (flip one) – one card is flipped over from the deck at a + time, and the deck cannot be recycled.

    +
+

Rules

+

The +board is setup with seven stacks of cards, a deck of the remaining +cards, and four home stacks. The goal is to move all cards to the +home stacks in ascending order from ace to king of the same suit. +Cards are placed one at a time in order on the home stacks. The +seven stacks of cards are dealt with each stack containing one more +card than the previous stack. The first stack will contain one card +and the last of the seven will contain seven cards. All cards in the +seven stacks are face down accept the top card. Cards can be moved +between the stacks by placing red cards on black cards in descending +order from king to ace. When a card is moved of a stack with a face +down card being exposed it will be flipped over automatically. A +card can also be played on the home stack, if it is an ace or the +next card in ascending order of a suit in one of the home stacks. +Once moves are exhausted on the board the next set of cards can be +flipped over from the deck. The top card in the flipped over cards +from the deck can be played using the same rules described for the +stacks. Play will continue until all moves are exhausted or until +all cards are moved to the home stacks and the game is won. +

+

Scoring

+

A +point is scored when a card is moved to one of the home stacks. A +total of 52 points can be scored, one for each card in the deck. The +current score is indicated in the status bar at the bottom of the +game window.

+

Game +Play

+

Cards +that are movable will be indicated when the mouse is over them with +the open hand icon. Cards with the open hand icon displayed over them +can be dragged and dropped to another stack or clicked to move +them to another stack. Hints of possible moves are available from the +menu select Control->Hint.

+ + diff --git a/plugins/qsolocards_plugin/help/Spider3DeckHelp.html b/plugins/qsolocards_plugin/help/Spider3DeckHelp.html new file mode 100644 index 000000000..2b81dcb09 --- /dev/null +++ b/plugins/qsolocards_plugin/help/Spider3DeckHelp.html @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + +

Three +Deck Spider Solitaire

+

Written +by Steve Moore

+

Overview

+

Three +Deck Spider Solitaire is a variation of Spider Solitaire played with +156 cards or three full decks of playing cards. +

+

Rules

+

The +cards are dealt into six rows of six cards, and six rows of five +cards. All the cards are face down except the last card in each +stack. A card can be moved from one stack to another if it is the +next card in descending order with King being high and Ace being low +regardless of suit. But a stack of cards can only be moved if they +are in descending order and the same suit. Once moves are exhausted +twelve cards can be dealt one on top of each stack ( The last deal is +an exception cards are only added to the first six stacks. ). Cards +cannot be dealt if there is an empty stack.

+

The +object of the game is to get all twelve suits in descending order +from King to Ace. Once a suit is complete it can be sent home or +moved to one of the twelve empty slots at the top of the board. Once +all twelve suits are sent home the game is over.

+

Scoring

+

A +point is scored when cards in descending order of the same suit are +stacked on one another. So, the total number of points available is +144 or 12 for each suit. The score along with the number of deals +remaining are indicated in the status bar at the bottom of the game +window.

+

Game +Play

+

Cards +that are movable will be indicated when the mouse is over them with +the open hand icon. Cards with the open hand icon displayed over them +can be dragged and dropped to another stack or clicked to move them +to another stack ( For the click case the cards are moved to a +matching suit, non-matching suit, or an empty stack in that order. In +some cases it might be necessary to drag and drop the cards to move +them to the exact stack desired. ). When all moves are exhausted, the +next set of cards can be dealt on top of the current cards by +clicking on the deck in the upper left corner of the board. +

+

Hints +of possible moves are available from the menu select Control->Hint.

+ + \ No newline at end of file diff --git a/plugins/qsolocards_plugin/help/SpiderHelp.html b/plugins/qsolocards_plugin/help/SpiderHelp.html new file mode 100644 index 000000000..8733b68bb --- /dev/null +++ b/plugins/qsolocards_plugin/help/SpiderHelp.html @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + +

Spider +Solitaire

+

Written +by Steve Moore

+

Overview

+

Spider +Solitaire is a solitaire game played with 104 cards. It has three +different variations.

+
    +
  • Four + suits – two complete 52 card decks are used.

    +
  • Two + suits – four sets each of hearts and spades are used.

    +
  • One + suit – eight sets of spades are used.

    +
+

Rules

+

The +game is played the same regardless of the variation. The cards are +dealt into four rows of six cards, and six rows of five cards. All +the cards are face down except the last card in each stack. A card +can be moved from one stack to another if it is the next card in +descending order with King being high and Ace being low regardless of +suit. But a stack of cards can only be moved if they are in +descending order and the same suit. Once moves are exhausted ten +cards can be dealt one on top of each stack. Cards cannot be dealt if +there is an empty stack.

+

The +object of the game is to get all eight sets of suits ( There are +eight sets regardless of the variation. ) in descending order from +King to Ace. Once a suit is complete it can be sent home or moved to +one of the eight empty slots at the top of the board. Once all eight +suits are sent home the game is over.

+

Scoring

+

A +point is scored when cards in descending order of the same suit are +stacked on one another. So, the total number of points available is +96 or 12 for each suit. The score along with the number of deals +remaining are indicated in the status bar at the bottom of the game +window.

+

Game +Play

+

Cards +that are movable will be indicated when the mouse is over them with +the open hand icon. Cards with the open hand icon displayed over them +can be dragged and dropped to another stack or clicked to move them +to another stack ( For the click case the cards are moved to a +matching suit, non-matching suit, or an empty stack in that order. In +some cases it might be necessary to drag and drop the cards to move +them to the exact stack desired. ). When all moves are exhausted, the +next set of cards can be dealt on top of the current cards by +clicking on the deck in the upper left corner of the board. +

+

Hints +of possible moves are available from the menu select Control->Hint.

+ + \ No newline at end of file diff --git a/plugins/qsolocards_plugin/help/SpideretteHelp.html b/plugins/qsolocards_plugin/help/SpideretteHelp.html new file mode 100644 index 000000000..20f7d22bc --- /dev/null +++ b/plugins/qsolocards_plugin/help/SpideretteHelp.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + +

Spiderette +Solitaire

+

Written +by Steve Moore

+

Overview

+

Spiderette +Solitaire is a solitaire game played with a standard 52 card deck. +It is a variation of Spider Solitaire that is played with a board +layout similar to that of Klondike Solitaire.

+

Rules

+

The +cards are dealt into seven stacks. The number of cards increases by +one for each stack. The first stack contains one card and the last +contains seven. All the cards are face down except the last card in +each stack. A card can be moved from one stack to another if it is +the next card in descending order with King being high and Ace being +low regardless of suit. But a stack of cards can only be moved if +they are in descending order and the same suit. Once moves are +exhausted seven cards can be dealt one on top of each stack ( The +last deal is an exception cards are only added to the first three +stacks. ). Cards cannot be dealt if there is an empty stack.

+

The +object of the game is to get all four suits in descending order from +King to Ace. Once a suit is complete it can be sent home or moved to +one of the four empty slots at the top of the board. Once all fourxs +suits are sent home the game is over.

+

Scoring

+

A +point is scored when cards in descending order of the same suit are +stacked on one another. So, the total number of points available is +48 or 12 for each suit. The score along with the number of deals +remaining are indicated in the status bar at the bottom of the game +window.

+

Game +Play

+

Cards +that are movable will be indicated when the mouse is over them with +the open hand icon. Cards with the open hand icon displayed over them +can be dragged and dropped to another stack or clicked to move them +to another stack ( For the click case the cards are moved to a +matching suit, non-matching suit, or an empty stack in that order. In +some cases it might be necessary to drag and drop the cards to move +them to the exact stack desired. ). When all moves are exhausted, the +next set of cards can be dealt on top of the current cards by +clicking on the deck in the upper left corner of the board. +

+

Hints +of possible moves are available from the menu select Control->Hint.

+ + \ No newline at end of file diff --git a/plugins/qsolocards_plugin/help/YukonHelp.html b/plugins/qsolocards_plugin/help/YukonHelp.html new file mode 100644 index 000000000..f56597dbc --- /dev/null +++ b/plugins/qsolocards_plugin/help/YukonHelp.html @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + +

Yukon +Solitaire

+

Written +by Steve Moore

+

Overview

+

Yukon +Solitaire is a solitaire game played with the standard 52 card deck. +The object is to arrange cards of the same suit from ace to king.

+

Rules

+

The +board is setup with seven stacks of cards, and four home stacks. The +goal is to move all cards to the home stacks in ascending order from +ace to king of the same suit. Cards are placed one at a time in order +on the home stacks. The seven stacks of cards are dealt. The first +stack has just one face up card. The remaining have one ( second +stack ) increasing to six ( seventh stack ) cards face down and five +cards face up. Cards can be moved between the stacks by placing red +cards on black cards in ascending order ( You can move cards as deep +in the a stack as you wish. The red to black ascending relationship +only applies to the top card being moved and the last card in the +stack to which it is moved. ). When a card is moved of a stack with +a face down card being exposed it will be flipped over automatically. +A card can also be played on the home stack, if it is an ace or the +next card in ascending order of a suit in one of the home stacks. +Once moves are exhausted on the board the next set of cards can be +flipped over from the deck. The top card in the flipped over cards +from the deck can be played using the same rules described for the +stacks. Play will continue until all moves are exhausted or until all +cards are moved to the home stacks and the game is won. +

+

Scoring

+

A +point is scored when a card is moved to one of the home stacks. A +total of 52 points can be scored, one for each card in the deck. The +current score is indicated in the status bar at the bottom of the +game window.

+

Game +Play

+

Cards +that are movable will be indicated when the mouse is over them with +the open hand icon. Cards with the open hand icon displayed over them +can be dragged and dropped to another stack or clicked to move them +to another stack. Hints of possible moves are available from the menu +select Control->Hint.

+ + \ No newline at end of file diff --git a/plugins/qsolocards_plugin/help/gpl3.html b/plugins/qsolocards_plugin/help/gpl3.html new file mode 100644 index 000000000..d127cadf1 --- /dev/null +++ b/plugins/qsolocards_plugin/help/gpl3.html @@ -0,0 +1,692 @@ + + + + + + GNU General Public License - GNU Project - Free Software Foundation (FSF) + +

GNU GENERAL PUBLIC LICENSE

+

Version 3, 29 June 2007

+ +

Copyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>

+ Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed.

+ +
+ +

The GNU General Public License is a free, copyleft license for +software and other kinds of works.

+ +

The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too.

+ +

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things.

+ +

To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others.

+ +

For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights.

+ +

Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it.

+ +

For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions.

+ +

Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users.

+ +

Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free.

+ +

The precise terms and conditions for copying, distribution and +modification follow.

+ +

TERMS AND CONDITIONS

+ +

0. Definitions.

+ +

“This License” refers to version 3 of the GNU General Public License.

+ +

“Copyright” also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks.

+ +

“The Program” refers to any copyrightable work licensed under this +License. Each licensee is addressed as “you”. “Licensees” and +“recipients” may be individuals or organizations.

+ +

To “modify” a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a “modified version” of the +earlier work or a work “based on” the earlier work.

+ +

A “covered work” means either the unmodified Program or a work based +on the Program.

+ +

To “propagate” a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well.

+ +

To “convey” a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying.

+ +

An interactive user interface displays “Appropriate Legal Notices” +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion.

+ +

1. Source Code.

+ +

The “source code” for a work means the preferred form of the work +for making modifications to it. “Object code” means any non-source +form of a work.

+ +

A “Standard Interface” means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language.

+ +

The “System Libraries” of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +“Major Component”, in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it.

+ +

The “Corresponding Source” for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work.

+ +

The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source.

+ +

The Corresponding Source for a work in source code form is that +same work.

+ +

2. Basic Permissions.

+ +

All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law.

+ +

You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you.

+ +

Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary.

+ +

3. Protecting Users' Legal Rights From Anti-Circumvention Law.

+ +

No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures.

+ +

When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures.

+ +

4. Conveying Verbatim Copies.

+ +

You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program.

+ +

You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee.

+ +

5. Conveying Modified Source Versions.

+ +

You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions:

+ +
    +
  • a) The work must carry prominent notices stating that you modified + it, and giving a relevant date.
  • + +
  • b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + “keep intact all notices”.
  • + +
  • c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it.
  • + +
  • d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so.
  • +
+ +

A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +“aggregate” if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate.

+ +

6. Conveying Non-Source Forms.

+ +

You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways:

+ +
    +
  • a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange.
  • + +
  • b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge.
  • + +
  • c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b.
  • + +
  • d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements.
  • + +
  • e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d.
  • +
+ +

A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work.

+ +

A “User Product” is either (1) a “consumer product”, which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, “normally used” refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product.

+ +

“Installation Information” for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made.

+ +

If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM).

+ +

The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network.

+ +

Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying.

+ +

7. Additional Terms.

+ +

“Additional permissions” are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions.

+ +

When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission.

+ +

Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms:

+ +
    +
  • a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or
  • + +
  • b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or
  • + +
  • c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or
  • + +
  • d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or
  • + +
  • e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or
  • + +
  • f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors.
  • +
+ +

All other non-permissive additional terms are considered “further +restrictions” within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying.

+ +

If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms.

+ +

Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way.

+ +

8. Termination.

+ +

You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11).

+ +

However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation.

+ +

Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice.

+ +

Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10.

+ +

9. Acceptance Not Required for Having Copies.

+ +

You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so.

+ +

10. Automatic Licensing of Downstream Recipients.

+ +

Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License.

+ +

An “entity transaction” is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts.

+ +

You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it.

+ +

11. Patents.

+ +

A “contributor” is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's “contributor version”.

+ +

A contributor's “essential patent claims” are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, “control” includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License.

+ +

Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version.

+ +

In the following three paragraphs, a “patent license” is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To “grant” such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party.

+ +

If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. “Knowingly relying” means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid.

+ +

If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it.

+ +

A patent license is “discriminatory” if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007.

+ +

Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law.

+ +

12. No Surrender of Others' Freedom.

+ +

If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program.

+ +

13. Use with the GNU Affero General Public License.

+ +

Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such.

+ +

14. Revised Versions of this License.

+ +

The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns.

+ +

Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License “or any later version” applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation.

+ +

If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program.

+ +

Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version.

+ +

15. Disclaimer of Warranty.

+ +

THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

+ +

16. Limitation of Liability.

+ +

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES.

+ +

17. Interpretation of Sections 15 and 16.

+ +

If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee.

+ +

END OF TERMS AND CONDITIONS

+ +

How to Apply These Terms to Your New Programs

+ +

If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms.

+ +

To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the “copyright” line and a pointer to where the full notice is found.

+ +
    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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/>.
+
+ +

Also add information on how to contact you by electronic and paper mail.

+ +

If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode:

+ +
    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+ +

The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an “about box”.

+ +

You should also get your employer (if you work as a programmer) or school, +if any, to sign a “copyright disclaimer” for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>.

+ +

The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ + + \ No newline at end of file diff --git a/plugins/qsolocards_plugin/images/anglo_bitmap.svg b/plugins/qsolocards_plugin/images/anglo_bitmap.svg new file mode 100644 index 000000000..e5cdb7fd5 --- /dev/null +++ b/plugins/qsolocards_plugin/images/anglo_bitmap.svg @@ -0,0 +1,10159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/qsolocards_plugin/images/greenfelt.png b/plugins/qsolocards_plugin/images/greenfelt.png new file mode 100644 index 0000000000000000000000000000000000000000..9bed0cb778b3592e0f2172b88ccb75bf378d5382 GIT binary patch literal 1019 zcmVPx#22e~?MF&_O0Z$k8H<9ZA000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXG~ z6BQf;iRya*00VnTL_t(2&jD})kNf}zW0HV?E6)fY4**Z+RwV`w3z`^(04Ke~Nj+$d zOyJJ|gg&D`+Ji{~P744Osk3_xFTi4MJOI>!|D|%S0Oqzh0K@@ZeGSbo{=jMg!~bAE z4a4SxAO!$C^YCvRR{ziLQ~>w;XSv`9=f}L{0LlN@7)Q$eK{LYu+z#x3XLvgO3CI9= z6KDu%5Pw_|$N*4TBm>3aGKq!E0E;gSk260E0D3Y2g~A^TvlpR&Cnf;E;D)=365xk1 zG5{`NNRgZA%^m(O0O*PZQR&F6CO2mQn$j5wbl~Pb6J-Dq^8~_iFx)*jLjW2Y3fNdu zd>}s{04_=-O~?*?Lc-w9tZUZP{i@TgA!7qD{7qbzy< zjgkPf6xD;KBhdFl=m4<#$EWi1*^hp#06h>gdZ1nT1E&N44hjN6y9_b|=3W2;G02g2 zA|Zf7asYjx!OX4qVa(Wq0C?tTnHaL*=dum}xN@FQJ}~Lp#y9}Z{d;~7dD4E*3;?jKr9lGE^#gZ0L%h_qy@-=fhhnY=3Q|x1CDY4006i}|0O|i&-N}T04g|Qv<7h5 zt!VxL3n(7wOc(r*`TqcGWH+%J=TI!(_yAZG{0+mvE#3_S00X?z07bT;$WjRaI8T9q zs2W#5xC;OPJ3%lQIUhjrCIG~kF(3p97-0RM0DxQp)`kgcB43>V&>qCY!(d(>!=eC> zhww%c_b+tA1_0(AydxP*6Szl>00i`DU(VD;q z%=6Eh00i=aP(&cZy^t3GdW2Myg=3wKhf@GU$LRDlAD@I>AOMqxbx0Urjm#bl08Jv} p9ta?*PKi-+Ilymz%DFkCxvf7C2CQxZdeJ5%yhYnt$iy zU~x+36W|wQBgMwJDylco(=(c$oTN*yFQ57MXcyOInLKFATB1`qwdW(!f^uBDHnC2x z`0M?9JD%)K#idDRr&K=2+uXf}OElM;^?nP8svtQo5Y`DijVD{a8iV%P3a!Da-@c88 z+^MryfB;lf)RBB~Q68Sjxw*N~(b1EHFstkHy{Yo@a@O=Xl@g5{K9<+7yT-=G`un40 zzRVxBjn`^(GZ5{S$m68it6dQvQwuCwgf2Yol@<7Sdtcw&94`KL*%`@x5W;hDb~dOn z%T7;61B`w<&or!t4sUx=pQE8(-$BkFCDE}WlcUyQ8_9jL=Wiq5^)17rwUMEr z909k*qmCy8a$CbsrWy%pGJBjgg+yCjZ+?OdH--&0yc-M2J#^@jCo{2I%PM(9zM|=G{5}zC~scnWwv>j-!5eA(F6! z1YDpKhqLuq>>!MXmv`GMz}592421H?1aOh#qM?0aCK>9DB`&}K5UU*ofRdV8u(_+W zfzo7YtMRn|lc(yG?wefcClNam)bOgi3(>I*O9)iqM6Yb>=Jr;Hy3)`1>z_Xg08lUn zsR50{af5hNo*K1n>arh$N}hiJ09uajAU_3VRZ#=Vq@TaBfX>a6d}8_pIl6#Xw>EBA ztQAhCE&RK-?k}zs@z1Hm2ULq9ROK|mj$5Qto(Bb1^T;cQ%A!#KJR2 zh{iYWh@YxZrSZirX&?+LJhSw~{Lv~|D3ykB4PYX~my*w8e_J#%4m0GnsiPf;o?@IU zcF<3YU*d!jLunlktGYB8iEzVK00`vZi-w1kh3z=Ya2XZ|z~IPWn-&2&+i|v?t3&<2 zDVlw3fPRvDc6>K8)NidjHZlyAU0$gBhrV#Lq?ye2_OOE9uo3_&q1`ODsnGOZpm65p z;a3mF=zzbE3Ujoyj~DbgV4`00@vcRa0^!2diA;XZ!uV=+5PODa*7O@) znY?8NAZ(|M70R}6Pw;{E9b%SPyJ$Hf92Di3&xQ_+#Ns^n=gGr8WCL`X&>wh1zl|kJ zxksy9?U(SVs&5(AtuVV5Co8ikM?7X4J0%bMR96EIpGix069gXBi=q{y=ZZcV;E2;C6QL5R?48>VVT; z+DsIHmLl=rW)GF{WXNBthArE;va-Ya!lum+!D3l>)p5E_Gqa|If^2`6Nk%DY>I4Fg zbC*1_@=#w)}V#Y_2s8mcCTg;>> z!?zfAv44{*Anh&UuKSTP{!>8K8Yzq*k>5@JqzMNv3ofpQKSEku0liJ<>B=4)4{h zv)#f1c*saQrT$BoRn;87fC0Oa*2NH;c+)CzLX<~4OI+N)#t=$DV7N5uhZ%F^jN1ZQ z)*nV)M*?sS090kYF4i3s*Du$W;rwbeo|5SRhr=%~*$kuanKUdRa{6Xw z6qIa_$FfF6UD#4#f}&0dlDH9iVq{NKf^r-7Xk+Q^{yMeB`f<$2ytxLxVH*Z5dn~uN zd7W5;-#3gV53hB#7lcyy?x^{judLl&VLaZHJzXAt9)yC*;~Q$tSC6+dNzZn#NG5hb zM!amF)jrgSedDYSiQ8P7rkvza0Riz$=x1hoj1_4rszzxpK@gxY_#8eMg$HM|#b9zNL_@+<2LocruHS)<@; zCX(TjG*alZDChE=g;Kw6O}6O3cNvBE`aWR(>$sNjJTlKzXt0gt;)RmU$D2r7bKTdw zV%=_M)+`ih>2X@%#o>B@@Kpq$90A7VV5O4`*HgrB0 zxbj~uu#2f&YkLv>6PXXXy_w+dX}LPoC`UdFW|`3zzn*V=iJh>PL7@n86u$$hqk$aX zgIY`=SGu|?6WlsgcF|k{4%spx1psYv-LbUieK=s%_>C@T!#t@d8dR#Aca(TI0kN2QluA;(@y)K(cLwWmI$al**UBMxYR!f_SjZ7IU_tCJ% z+sW(s)-O-`*wOk*axKyqE)^}fpnNvN#aVp6bs3(rVTk+kpWL|*w<||6v>b^t&wy)x zE+MrF@mU%LTLyjFHMJ~DLtr{R-SNv%(x--M>KF|N%^cf%C)61dfIP|}=@RF3PqzwX zFPn9Sb*k2k`8&}rtCXtcT(6uQ^}(~XfBI71lVzp#^{V%`w=yA^HeYUTeBNeVTS*Wxhh1qcxgRZwcPvX0HY=%_4(-NP&7d-niLy? zC|ZxEpq($04Az`Mb_SR=f-5KCidf=q0x&K(34`T+XWyx5$!Jp~5q5T+2+L>7hiH}U z-hLDyOIzDkPvXV;&^H4*X$UB!Zo?^!)s*=0pz7?Hyt`GX?oS5Na=EzUNJ9ZK z)Jb{vu1}2&{*vgh6pPxyHkk0iHOVY>k1JIY6%mWgBE(qB#6U<;%LW2`e6I~tqZ;Hj-d=?0^sy%b%1}s;u3qfX8#%KGfJ+CosmjiX^xf2V7 z-s?^?>l3{R7d|=Bx?(`7<2Y{x(T)w4hupc<-LBp3m653vDg+uWWSBC4(Jq`(&axh7 z!o7&a++dw;BIYYU5H=cC~M|bWJ%JvwO_0@ zr;`#-i2@2}jGt8E1|`)%CU>DG@sC9zg96Hg|gZQ|(Yl{2TyX2Gfk=J{RW{ADCph?y#5 z=+UNbo2&6%i7MkV(~pHm$wwjhtxrW$@chc=?btF&Y_2H!J5l;+^?}uRewQjq+G)5) zh5T}(mDa{op=Ba^+y0NaG(+Z`E5zH_Se949KLf7Zp-L||6-2()j^9-`jOSYg1Mu@G z@UBYNFDg9f6BtUR!6(TdybnlrUG+?QhfFRwvSve^%m4#flBAOqPIJe2u3m z1YEiPgv=8FMrDr%>tPVOUt2wO{AN@ZyE)lMwTTp65~iCOX4Sw>wj#-2q+BJ zwi@W7B;B>P)X?_y=$EkE59+k}aWF~!gIkvr;0j5zh~X?#uTgH`4}As&8h!EH%=Vkm z_UkFLgeDrNy93(}7WqF!9>QAWwY8}QJ#y4;3LoyGXJ&4muIcG{h&*zIQujlfjA|y~ zDQ0fyiLJp3I1d}2@XIezqVemx3X?=Zg zE+kwkD}5VTUm4Ss8z2CnYMb3-HR2=WzV%bhVF*=aNnxfD@5TUzSj&RXzs+HKB}@mx zwf4Wr{wYXU?}^^pT{^@17R{B5b1)eZyP+Cc+W|qm`MbpLEAR2<)QMnQ} z!k^g6^{x{Q4U~{uw*~8ShYJ+I#leqahv+M+#H&m7c-MXwK;%d+HoV<*+p?{lUmSKl z6@oDP{@VqMie3Wvqj)Qa?n&wlt4?L4KvT&U9uHkMG&J}sJ6VeomeKR?)N2&V6fzw# zF@Y;V6RLE;<=GfqPBQtg7-ffiBR!?-5 zdBp8}A}|pQ8efuplD8CEoO-{znDhz_@ZQ??NnGwLu^*)X0LT<0TPbOTOt_LNQN$Mr zde~O3$8+V*Y_aUCMVH1mT&z5Q3-#j6A$iGGfz{x60>F^*FrDQK5LS1#jjVeu`@U&M z>Bf$`t@UEUE1ZTy=LcP~b%MCgxc$lEo;|7#Ui}&~E7SOGahKH&KsXIf=K*r`a))MP z@v(b-Q6>(lwLuedn$P+ACl*+MTuBs_q&c@oe!WNca@x^Yw;DI7_SSgPR@qIkNOFVq z`u;aOlM$_;L*GTmp<7{(&-+_?WH-5vQ@$}@PP&8fk013uu_No4yu5dZI5F6piPQ@a!>Qh?tjEN8hh)^)+wxI>qGFK8F?;hC=oz9h_8lYt#LACxm zn3?L|yDiT>(tVn-lPNIlk4}6YgccG}08POcz3>j4+=*2 z%1}glSE5$_KO^;T`CP9gD$*bM3@PxXz*L6B!XwNtuZPe*JwVg!vKVHR4^*pEXOkkf z`0;^Rx|GL&-}Y>8O!)f5hFPVsy~)38QnO%gzu!`+hQhK0tT&_a$tgw-we~_s+54Bw zr1eb^^n;B9AQt6rPJ9UfXcW^e`MW){I4K<=ZLEc)Ol`4XIMJ)W6ueRVUd0PUuC?ah zgO3Y0XW!a|N{F*3h+9456``QJt;GbpREjYvhCYY@VWh-86rveB9_BlH6qMV79=^-X zc5t}mCz`QWk}Iwml`H@W4~w0>P^T8l1W`#IXCl^B9L+ys!rr%4?xtca^AWP&-TpP2 zhqahTmo_(BcReG%Yl+t)_c~{`nXh&Co1NBczouLKfCm&tfBZ-#`In0O12aOk-j%T9 zNuv23Mi^}YfyA1}qHSs?tkG==dbKLJ6U+B_i~?A8M&W%J&HaMtSIp*+_LN0G4!~tk zCwiOGXzaPeiIhZOug1)l;jjL3>8ul*2?fb^cBJx(SLdPMhK5xBB&2-Bb{z0nW{!*F zS(gB$z{bWDl<~gIi)yt7rcI6$P{=)sfG~_Kic-LXLsbc0v5ne;^h0y)XBuPd)PoJH z8S2^AMBg2-r8bl-!kToxz7a_?o~Ri|s-L^H?R9U~o5#(JR-)kb*SD9K6>n6>wY6Xw zZ_+F5FPs?`sAipAbabj<*{PFP)+UKd_1U(jh06JPu;asqfz{EV%R(l_G12|z-R9K5 zgHTUBl{%q-^u>s5QXp)AwgwdCnRgMP1#>7c{w`PU;za1N91{$y*sykyk^Axu+|kb2 zGZEM4lPh4{QMNwJ$xnx50`>bYjM*dC+c8LUlW@?Av{Kb>b}n6_0RiA|HfL`9>FBeg zQIV6(OxjPmw;1@H&OXp>ODB5er)!kM)qYj=7T?$Up4C0efyagC(=5=OIQw)o?>z}# zK#gi=$`7!nZ*|h+0cbnpN9{H%vn$!z`AkV`m^3DTIjB3Y8PoMW+zEU_v)O4lxb;cM z7K5X!gSa~1S=ULycNbqEbXoE$^g`k%w~fg;@qyDb?v;h(8AGG&m?m}JF>9O%c%!Fm zQpK)|TNoPJpO^O7Qs$n-sNuf{L*njph$#nlxpRsuIHzdHEy=NL`yYiq-h9^V%M&$P zI#7ifxvn?dUi#`AzbyS*NWtfJy8&au{_XC_p5de_J^KE%Z;9ku< ze5OmOs!>SFG7ns=uIGf(`oA8Z|I1}#oggZw3v8*tJTln;fQ1)hfo%WS+4_G>M4IB_ z--s41BsU{x{u?=KMhp7JL+SKW&i5m zkjUvDi;tv&Lj&tkV`rVy%TszX$a*)K4SSw8aJrv)(GDE79NnHOb1NopAge@sc~|W- zJma$~9*~HyA!>mS7^RZ`8!BFR4pG+;%0>lqIx<%w7GF}2);Nb&beo@}0Bc0A5Dh+T z+*5~bSK||3>$NSNS>H0p08^BoUU(lD{!S#9Ss>VtcU~02{Z|<)G&Ca@dGZJUWD>qs zhfszhyHrP!Jgp%YCJjj~{+=`#BT4a_kQ4dUmx{iA1j50M-%G_Yu|?hi;AR3N&w=86 zmPjiuQGw1e9NjN(ii*Y4O~I?y6q24dq2NThsGya@6?KB&Z5wobJ@nVdRxyRYrjX76 zlgp*e-lVQXWuoE-^gYA7pUEs}Bs)Rm7GF7S&V7QiLiQiFM?=eUYOzE z8X#obg`D%iE{_^)+3Hgwj@tJHg6b2m`~F}HcnI)%R*U`G4bC=jAQ$arW39^crn0&3 z4Ojgns<*SrG}L!kkJ$-#^q#OVQFyPAsde9=+l9}s!}*s|a;K>;M{yy0=1 z8^LBWo}nXC$G%(}mrp#!U25fM!$Mg(-M;2aWYN9;7PyN_ls$|m?D@=4hgFU-no7cT z&-6fkO0z?UCEZ2l=5skcS_b08`@OLkH!4uOPvu@Dsep~_Q@o^3Jh3;Ck{Vd=Nrq`S z+b59|Cg;S-maMcc#8J%R04l%nh2MJhC4_VEoynRA%PJKm|1Y0de;7_O4EDV_zxLcu zY08^Q)F2QKZJnEHxm9Yl8*bGKfEvWKScZ=U9T`)ad{@5@P&AvNJzL8X&cOg^&)??~ z^)+};GK9N!7q^V`?_X%*o_O=Z z^5{;8F_kV~{X)v%;L0Szu{09ovG)AKx9M@4{*hVBe`#b?8t_3VJoQ2Vxwavd@q!|< z&P$;IJ8qLcBntg~;&2+uz*PhRd-fmrmoJZ!_W+fWp2VukAyvmw`+KY-a74d(O{ttm zSee{O;+w+qw7*lL1QykF4E!j$e6(l?n9CnERO#@b%jB#iiN7<*e&44zsw3a5u(0wg z4Q(i%{}Fu6%7_XovI=l_1q%8d(^!!mA7QT%4jHSl$btQfIbm|_m-F)E_t!;(GIG{G zo=r`1y{gNTecE;tm+ouRO?6i1T^9 z*q*m>sBX>m;S$le9n^^trhrjqmj(iq7~cI-vM!@TGpZJ+6l{LObQkg@?vEd{vG?-$ zZ0ue=7mji=GuG)=kuHwomBHfkAZi~YgC!c0^X}-!XfL>NJc|C~aR|uq>Nbs8LcuUx zT-x8f(c?Yj7WDu5H3nqG&zG8`w8N!aPmQb}IQqoW}x zLc#avWD-ED3>8m&j3Lb#F6GQ8*|0641{n#8Qhn%*T-x}DP=L@g#51A?HMIyeIlTaq zRbo|syFbbEDm-x*c6on+=JujkR;6Wymi!$3FhS!<%1~&Ara^}b6zhB~R(E<+H3Vlh z5?pHHq$dFc4az1UV>dec3J``@Y&2Lh znO}sf+F|D=DJ~-a&Im8k*3Zv}?50@%*+NJKMHXP902ckVnLwKY-B_cYO}TAdWoLhc nut)IopQZxmhCtt$`V&UI&ePGIHG~_vPzWf?Ysl5eSbq2q8dL`` literal 0 HcmV?d00001 diff --git a/plugins/qsolocards_plugin/images/sol16x16.png b/plugins/qsolocards_plugin/images/sol16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..42bf709e0c0989e8628578168f16d54e66bc4c89 GIT binary patch literal 719 zcmV;=0xPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L02-SB02U_CX>@2HM@dakSAh-}0006iNkl$@Pfrt36vfY*8QW6F))tkf3z*Vk)YeE?kTf)g5EBzaOx%^2@EusW?{{Eh)Ex^J z*u;$sXuuR=M4J#u1EHoM6l6;O(N0Te=FL18Q>cxe&AT`E{&MfRdBil$x9>l^c>YWj zMf|0urKMQ%6zIm4! z3wdnBHQ~#j6SF+upfhssO}TtTWKz@W$g^4|m*-^&J@iW7s>sco`im zADjbFbGiJ?j5i*ql}aO(3MP{sfDp#>SKo_=VY1Fm*VbB@OnY~iX&R%nmC1BGoY&Oo z!vO#sAwj?U)7K-*L;vioJrpuqEk^0h@p1R`^dDiK^ncSr6;=QM002ovPDHLkV1mIS BI@bUI literal 0 HcmV?d00001 diff --git a/plugins/qsolocards_plugin/images/sol256x256.png b/plugins/qsolocards_plugin/images/sol256x256.png new file mode 100644 index 0000000000000000000000000000000000000000..9125e38c6f8553a15e1ea6855e53124fec590dbe GIT binary patch literal 14179 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 literal 0 HcmV?d00001 diff --git a/plugins/qsolocards_plugin/images/sol32x32.png b/plugins/qsolocards_plugin/images/sol32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..a145497dce9b867434d25efd79a729309084b45b GIT binary patch literal 2431 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
Xj^1}_I)fp>BB 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%0A(@}d%ua1+fpG=QnWbuSMrVE?2oKpn}KHIk4L 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 PbRVLvt_z$?>(KuJCv5PF literal 0 HcmV?d00001 diff --git a/plugins/qsolocards_plugin/main.cpp b/plugins/qsolocards_plugin/main.cpp new file mode 100644 index 000000000..7746402b0 --- /dev/null +++ b/plugins/qsolocards_plugin/main.cpp @@ -0,0 +1,28 @@ +/* + 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 +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/plugins/qsolocards_plugin/mainwindow.cpp b/plugins/qsolocards_plugin/mainwindow.cpp new file mode 100644 index 000000000..9456b26f4 --- /dev/null +++ b/plugins/qsolocards_plugin/mainwindow.cpp @@ -0,0 +1,653 @@ +/* + 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 "mainwindow.h" + +#include +#include +#include +#include +#include +#include + +#include "CardAnimationLock.h" + +const unsigned int MainWindow::MaxWidth=780; +const unsigned int MainWindow::MaxHeight=900; +const QString MainWindow::SizeStr("size"); +const QString MainWindow::PtStr("point"); +const QString MainWindow::HelpStr("help"); +const QString MainWindow::GameIdStr("LastGame"); +const QString MainWindow::AnimationStr("EnableAnimations"); + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent), + m_pGameBoard(NULL), + m_pMenuBar(NULL), + m_pGameOptionsMenu(NULL), + m_pHelpMenu(NULL), + m_settings("QSoloCards","QSoloCards"), + m_pNewGameAction(NULL), + m_pRestartAction(NULL), + m_pUndoAction(NULL), + m_pRedoAction(NULL), + m_pHintAction(NULL), + m_pAnimationAction(NULL), + m_pDemoAction(NULL), + m_pCheatAction(NULL), + m_pStatusBar(NULL), + m_pStatusBarLabel(NULL), + m_helpWindow(NULL), + m_aboutWindow(NULL), + m_gameMgr(), + m_firstShow(false) +{ + // make the window a nice size and make sure it is on the screen + QSize deskSize(QApplication::desktop()->size()); + + unsigned int width=MaxWidth<(unsigned int)deskSize.width()?MaxWidth:deskSize.width()-100; + unsigned int height=MaxHeight<(unsigned int)deskSize.height()?MaxHeight:deskSize.height()-100; + + int locX=(deskSize.width()-width)/2; + int locY=(deskSize.height()-height)/2; + + this->resize(m_settings.value(SizeStr, QSize(width, height)).toSize()); + this->move(m_settings.value(PtStr, QPoint(locX, locY)).toPoint()); + + // create the status bar we will use to show the score and game info. + this->m_pStatusBar=new QStatusBar; + this->m_pStatusBarLabel=new QLabel; + this->m_pStatusBar->addPermanentWidget(m_pStatusBarLabel); + this->setStatusBar(this->m_pStatusBar); + + // show the last game played or the default game if we don't have a last played. + // we need to create the board before adding the menus. This is done. So, the + // initial check state of the game selected will reflect the initial game. + int gameId=m_settings.value(GameIdStr, GameMgr::DefaultGame).toInt(); + GameBoard * pGameBoard=m_gameMgr.getGame((GameMgr::GameId)gameId); + + // add the menus for the window + this->addMenuItems(); + + // finally setup the board. + this->setupGameBoard(pGameBoard); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +MainWindow::~MainWindow() +{ + // save the current settings for the game + this->m_settings.beginGroup(this->m_pGameBoard->gameSettingsId()); + this->m_pGameBoard->saveSettings(this->m_settings); + this->m_settings.endGroup(); + + // save the position of the game window + this->m_settings.setValue(SizeStr,this->size()); + this->m_settings.setValue(PtStr,this->pos()); + + // save the current game being played + this->m_settings.setValue(GameIdStr,this->m_gameMgr.getGameId()); + + // save if animation is enabled or not + this->m_settings.setValue(AnimationStr,this->m_pAnimationAction->isChecked()); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotNewGame() +{ + if (NULL!=this->m_pGameBoard) + { + this->m_pGameBoard->newGame(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotRestartGame() +{ + if (NULL!=this->m_pGameBoard) + { + this->m_pGameBoard->restartGame(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotSelectGame(QAction * pAction) +{ + if (NULL!=pAction) + { + bool ok=false; + int gameId=pAction->data().toInt(&ok); + + // if we got the gameid and it is not the same as the current game + // set the game as the current. + if (ok && gameId!=this->m_gameMgr.getGameId()) + { + this->setupGameBoard(this->m_gameMgr.getGame((GameMgr::GameId)gameId)); + } + } +} + +void MainWindow::slotAnimation(bool checked) +{ + CardAnimationLock::getInst().enableAnimations(checked); + + if (this->m_pGameBoard->hasDemo() && checked) + { + this->m_pDemoAction->setEnabled(true); + } + else + { + this->m_pDemoAction->setEnabled(false); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotCheat(bool checked) +{ + if (NULL!=this->m_pGameBoard) + { + this->m_pGameBoard->setCheat(checked); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotUndo() +{ + if (NULL!=this->m_pGameBoard) + { + if (this->m_pGameBoard->canUndoMove()) + { + this->m_pGameBoard->undoMove(); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotRedo() +{ + if (NULL!=this->m_pGameBoard) + { + if (this->m_pGameBoard->canRedoMove()) + { + this->m_pGameBoard->redoMove(); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotHint() +{ + if (NULL!=this->m_pGameBoard) + { + this->m_pGameBoard->showHint(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotUndoAvail(bool avail) +{ + if (this->m_pUndoAction && !m_pDemoAction->isChecked()) + { + this->m_pRestartAction->setEnabled(avail); + + this->m_pUndoAction->setEnabled(avail); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotRedoAvail(bool avail) +{ + if (this->m_pRedoAction) + { + this->m_pRedoAction->setEnabled(avail); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotScoreChanged(int score,const QString & info) +{ + if (this->m_pStatusBar && !m_pDemoAction->isChecked()) + { + QString statusMsg(tr("%1 Score: %2").arg(info).arg(QString::number(score)).trimmed()); + + this->m_pStatusBarLabel->setText(statusMsg); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotAbout() +{ + if (NULL==this->m_aboutWindow) + { + this->m_aboutWindow=new About(this); + connect(this->m_aboutWindow.data(),SIGNAL(showLink(QString)), + this,SLOT(slotShowHelp(QString))); + } + this->m_aboutWindow->show(); + this->m_aboutWindow->activateWindow(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotHelp() +{ + if (this->m_pGameBoard) + { + this->slotShowHelp(this->m_pGameBoard->helpFile()); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotHelpClosed(int finishCode) +{ + Q_UNUSED(finishCode); + + this->m_settings.beginGroup(HelpStr); + this->m_settings.setValue(SizeStr,this->m_helpWindow->size()); + this->m_settings.setValue(PtStr,this->m_helpWindow->pos()); + this->m_settings.endGroup(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotShowHelp(const QString & helpFile) +{ + if (NULL==this->m_helpWindow) + { + this->m_helpWindow=new Help(this,helpFile); + this->m_settings.beginGroup(HelpStr); + this->m_helpWindow->resize(this->m_settings.value(SizeStr,QSize(640,480)).toSize()); + this->m_helpWindow->move(this->m_settings.value(PtStr,QPoint(200,200)).toPoint()); + this->m_settings.endGroup(); + this->connect(this->m_helpWindow,SIGNAL(finished(int)),this,SLOT(slotHelpClosed(int))); + this->m_helpWindow->show(); + } + else + { + this->m_helpWindow->setHelpFile(helpFile); + this->m_helpWindow->show(); + this->m_helpWindow->activateWindow(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotAnimationStarted() +{ + m_pRestartAction->setEnabled(false); + m_pDemoAction->setEnabled(false); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotAnimationComplete() +{ + m_pRestartAction->setEnabled(true); + m_pDemoAction->setEnabled(true); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +// this timeout is just to delay slightly calling newGame for a board. So, the +// animation will start with the QGraphicsScene visible and the board will already be +// completely drawn. +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotNewGameTimer() +{ + if (this->m_pGameBoard) + { + this->m_pMenuBar->setEnabled(true); + this->m_pGameBoard->newGame(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotDemoStarted() +{ + m_pNewGameAction->setEnabled(false); + m_pRestartAction->setEnabled(false); + m_pUndoAction->setEnabled(false); + m_pRedoAction->setEnabled(false); + m_pHintAction->setEnabled(false); + m_pAnimationAction->setEnabled(false); + m_pGameSelectMenu->setEnabled(false); + m_pGameOptionsMenu->setEnabled(false); + m_pCheatAction->setEnabled(false); + + m_pDemoAction->setChecked(true); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotDemoStopped() +{ + m_pNewGameAction->setEnabled(true); + m_pRestartAction->setEnabled(true); + m_pHintAction->setEnabled(true); + m_pAnimationAction->setEnabled(true); + m_pGameSelectMenu->setEnabled(true); + m_pGameOptionsMenu->setEnabled(true); + m_pCheatAction->setEnabled(true); + + + if (this->m_pGameBoard->canUndoMove()) + { + m_pUndoAction->setEnabled(true); + } + + if (this->m_pGameBoard->canRedoMove()) + { + m_pRedoAction->setEnabled(true); + } + + m_pDemoAction->setChecked(false); + +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::slotDemoActionItem(bool checked) +{ + if (this->m_pGameBoard) + { + if (checked) + { + this->m_pGameBoard->startDemo(); + } + else + { + this->m_pGameBoard->stopDemo(); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +// we are just using the showEvent to make sure that we don't start the animation of the dealing +// of cards for the game until the window has been shown. +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::showEvent(QShowEvent * pShowEvent) +{ + Q_UNUSED(pShowEvent); + if (!m_firstShow && NULL!=this->m_pGameBoard) + { + this->m_pGameBoard->newGame(); + + m_firstShow=true; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::addMenuItems() +{ + // create the menu for the app. + this->m_pMenuBar=new QMenuBar(this); + + // create a game menu + QMenu * pGameMenu=new QMenu(tr("Game").trimmed(),this->m_pMenuBar); + + m_pNewGameAction=new QAction(tr("New Game").trimmed(),pGameMenu); + m_pNewGameAction->setShortcuts(QKeySequence::New); + this->connect(m_pNewGameAction,SIGNAL(triggered()), + this,SLOT(slotNewGame())); + pGameMenu->addAction(m_pNewGameAction); + + this->m_pRestartAction=new QAction(tr("Restart Game").trimmed(),pGameMenu); + this->m_pRestartAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R)); + this->connect(this->m_pRestartAction,SIGNAL(triggered()), + this,SLOT(slotRestartGame())); + + pGameMenu->addAction(this->m_pRestartAction); + + pGameMenu->addSeparator(); + + this->m_pGameSelectMenu=new QMenu(tr("Select Game").trimmed(),pGameMenu); + // add the available games to the menu. + this->m_gameMgr.buildGameListMenu(*this->m_pGameSelectMenu); + // connecting this one up a little different. Since, we are building + // a generic menu where we don't know what the contents are connect up + // to the menus triggered event. We can then get the action and from it's + // user data the id of the game selected. + this->connect(this->m_pGameSelectMenu,SIGNAL(triggered(QAction*)), + this,SLOT(slotSelectGame(QAction*))); + + pGameMenu->addMenu(this->m_pGameSelectMenu); + +#if !(defined Q_WS_MAC) + pGameMenu->addSeparator(); +#endif + + + QAction * pQuit=new QAction(tr("Quit").trimmed(),pGameMenu); + pQuit->setMenuRole(QAction::QuitRole); + pQuit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); + this->connect(pQuit,SIGNAL(triggered()), + this,SLOT(close())); + pGameMenu->addAction(pQuit); + + this->m_pMenuBar->addMenu(pGameMenu); + + /////////////////////////////////////////////////////////////////////////// + // create a control menu + // for the cheat and undo menu items + /////////////////////////////////////////////////////////////////////////// + QMenu * pCtrlMenu=new QMenu(tr("Control").trimmed(),this->m_pMenuBar); + + m_pUndoAction=new QAction(tr("Undo").trimmed(),pCtrlMenu); + m_pUndoAction->setShortcuts(QKeySequence::Undo); + this->connect(m_pUndoAction,SIGNAL(triggered()), + this,SLOT(slotUndo())); + pCtrlMenu->addAction(m_pUndoAction); + + m_pRedoAction=new QAction(tr("Redo").trimmed(),pCtrlMenu); + m_pRedoAction->setShortcuts(QKeySequence::Redo); + this->connect(m_pRedoAction,SIGNAL(triggered()), + this,SLOT(slotRedo())); + pCtrlMenu->addAction(m_pRedoAction); + + m_pHintAction=new QAction(tr("Hint").trimmed(),pCtrlMenu); + m_pHintAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_H)); + this->connect(m_pHintAction,SIGNAL(triggered()), + this,SLOT(slotHint())); + pCtrlMenu->addAction(m_pHintAction); + + pCtrlMenu->addSeparator(); + + m_pAnimationAction=new QAction(tr("Animation").trimmed(),pCtrlMenu); + m_pAnimationAction->setCheckable(true); + this->connect(m_pAnimationAction,SIGNAL(triggered(bool)), + this,SLOT(slotAnimation(bool))); + pCtrlMenu->addAction(m_pAnimationAction); + + m_pAnimationAction->setChecked(m_settings.value(AnimationStr, true).toBool()); + + CardAnimationLock::getInst().enableAnimations(m_pAnimationAction->isChecked()); + + + m_pDemoAction=new QAction(tr("Demo").trimmed(),pCtrlMenu); + m_pDemoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); + m_pDemoAction->setCheckable(true); + this->connect(m_pDemoAction,SIGNAL(triggered(bool)), + this,SLOT(slotDemoActionItem(bool))); + pCtrlMenu->addAction(m_pDemoAction); + + + pCtrlMenu->addSeparator(); + + m_pCheatAction=new QAction(tr("Cheat").trimmed(),pCtrlMenu); + m_pCheatAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C)); + m_pCheatAction->setCheckable(true); + this->connect(m_pCheatAction,SIGNAL(triggered(bool)), + this,SLOT(slotCheat(bool))); + pCtrlMenu->addAction(m_pCheatAction); + + + this->m_pMenuBar->addMenu(pCtrlMenu); + + + /////////////////////////////////////////////////////////////////////////// + // create a game options menu + // this menu will get the specific game option settings to add to the menu + // from the GameBoard class. We will not add it to the menu at this time. + // It will be added and/or removed when the game board is setup. It will + // only be added if it is needed. + /////////////////////////////////////////////////////////////////////////// + m_pGameOptionsMenu=new QMenu(tr("&Options").trimmed(),this->m_pMenuBar); + + //////////////////////////////////////////////////////////////////////////// + // add the help menu + //////////////////////////////////////////////////////////////////////////// + this->m_pHelpMenu=new QMenu(tr("&Help").trimmed(),this->m_pMenuBar); + + QAction * pHelp=new QAction(tr("Game Help").trimmed(),this->m_pHelpMenu); + pHelp->setShortcut(QKeySequence(Qt::Key_F1)); + this->connect(pHelp,SIGNAL(triggered()), + this,SLOT(slotHelp())); + this->m_pHelpMenu->addAction(pHelp); + +#if !(defined Q_WS_MAC) + this->m_pHelpMenu->addSeparator(); +#endif + + QAction * pAbout=new QAction(tr("&About").trimmed(),this->m_pHelpMenu); + pAbout->setMenuRole(QAction::AboutRole); + this->connect(pAbout,SIGNAL(triggered()), + this,SLOT(slotAbout())); + this->m_pHelpMenu->addAction(pAbout); + + this->m_pMenuBar->addMenu(this->m_pHelpMenu); + + + + this->setMenuBar(this->m_pMenuBar); + + // also go ahead and hook up the slots for the signals that animation is in progress + // now only used by the restart game menu item. Need the undo stack to be updated before + // we can restart a game. + connect(&CardAnimationLock::getInst(),SIGNAL(animationStarted()), + this,SLOT(slotAnimationStarted())); + + connect(&CardAnimationLock::getInst(),SIGNAL(animationComplete()), + this,SLOT(slotAnimationComplete())); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +// Set a gameboard and hook up the menus, set the icon, etc... for the new board +// if there was a previous gameboard. When the QMainWindow::setCentralWidget function is called +// the old game board will be deleted by Qt. +///////////////////////////////////////////////////////////////////////////////////////////// +void MainWindow::setupGameBoard(GameBoard * pGameBoard) +{ + if (pGameBoard) + { + // save settings of the current game if we have one + if (NULL!=this->m_pGameBoard) + { + this->m_settings.beginGroup(this->m_pGameBoard->gameSettingsId()); + this->m_pGameBoard->saveSettings(this->m_settings); + this->m_settings.endGroup(); + } + + this->m_pGameBoard=pGameBoard; + + // connect the gameboards score changed signal to our slot so we + // can get score changes and display them. But first clear the + // current contents of the statusbar to get ride of old info if necessary. + this->m_pStatusBar->showMessage(""); + this->m_pStatusBarLabel->setText(""); + this->connect(this->m_pGameBoard,SIGNAL(scoreChanged(int,QString)), + this,SLOT(slotScoreChanged(int,QString))); + + this->m_settings.beginGroup(this->m_pGameBoard->gameSettingsId()); + this->m_pGameBoard->loadSettings(m_settings); + this->m_settings.endGroup(); + + + this->setCentralWidget(this->m_pGameBoard); + this->setWindowTitle(tr("QSoloCards: %1").arg(this->m_pGameBoard->gameName()).trimmed()); + + // connect up the game board to the menus + m_pUndoAction->setEnabled(this->m_pGameBoard->canUndoMove()); + m_pRedoAction->setEnabled(this->m_pGameBoard->canRedoMove()); + m_pRestartAction->setEnabled(this->m_pGameBoard->canUndoMove()); + + this->m_pMenuBar->removeAction(this->m_pGameOptionsMenu->menuAction()); + + this->m_pGameOptionsMenu->clear(); + this->m_pGameBoard->addGameMenuItems(*this->m_pGameOptionsMenu); + + if (!this->m_pGameOptionsMenu->isEmpty()) + { + this->m_pMenuBar->insertMenu(this->m_pHelpMenu->menuAction(),this->m_pGameOptionsMenu); + } + + // set the window icon for the game. + this->setWindowIcon(this->m_pGameBoard->getGamePixmap()); + + + /////////////////////////////////////////////////////////////////////////// + // connect up the slots so we will know when undo and redo actions are available + /////////////////////////////////////////////////////////////////////////// + this->connect(this->m_pGameBoard,SIGNAL(undoAvail(bool)), + this,SLOT(slotUndoAvail(bool))); + + this->connect(this->m_pGameBoard,SIGNAL(redoAvail(bool)), + this,SLOT(slotRedoAvail(bool))); + + if (this->isVisible()) + { + // disable the menus while we wait for the timer to pop. + this->m_pMenuBar->setEnabled(false); + QTimer::singleShot(100,this,SLOT(slotNewGameTimer())); + } + + this->m_pDemoAction->setChecked(false); + + if (this->m_pGameBoard->hasDemo() && CardAnimationLock::getInst().animationsEnabled()) + { + this->m_pDemoAction->setEnabled(true); + + this->connect(this->m_pGameBoard,SIGNAL(demoStarted()), + this,SLOT(slotDemoStarted())); + + this->connect(this->m_pGameBoard,SIGNAL(demoStopped()), + this,SLOT(slotDemoStopped())); + } + else + { + this->m_pDemoAction->setEnabled(false); + } + + } +} + diff --git a/plugins/qsolocards_plugin/mainwindow.h b/plugins/qsolocards_plugin/mainwindow.h new file mode 100644 index 000000000..9e4d874eb --- /dev/null +++ b/plugins/qsolocards_plugin/mainwindow.h @@ -0,0 +1,117 @@ +/* + 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 . +*/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include + +#include "GameBoard.h" +#include "Help.h" +#include "About.h" +#include "GameMgr.h" + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + static const unsigned int MaxWidth; + static const unsigned int MaxHeight; + static const QString SizeStr; + static const QString PtStr; + static const QString HelpStr; + static const QString GameIdStr; + static const QString AnimationStr; + + MainWindow(QWidget *parent = 0); + ~MainWindow(); + +public slots: + void slotNewGame(); + void slotRestartGame(); + void slotSelectGame(QAction *); + void slotAnimation(bool); + void slotCheat(bool); + void slotUndo(); + void slotRedo(); + void slotHint(); + + void slotUndoAvail(bool avail); + void slotRedoAvail(bool avail); + + void slotScoreChanged(int score,const QString &); + + void slotHelp(); + void slotAbout(); + + void slotHelpClosed(int); + + void slotShowHelp(const QString & helpFile); + + void slotAnimationStarted(); + void slotAnimationComplete(); + + void slotNewGameTimer(); + + void slotDemoStarted(); + void slotDemoStopped(); + + void slotDemoActionItem(bool); +protected: + void showEvent(QShowEvent * pShowEvent); + +private: + void addMenuItems(); + void setupGameBoard(GameBoard * pGameBoard); + + + + GameBoard * m_pGameBoard; + QMenuBar * m_pMenuBar; + QMenu * m_pGameSelectMenu; + QMenu * m_pGameOptionsMenu; + QMenu * m_pHelpMenu; + QSettings m_settings; + + QAction * m_pNewGameAction; + QAction * m_pRestartAction; + QAction * m_pUndoAction; + QAction * m_pRedoAction; + QAction * m_pHintAction; + QAction * m_pAnimationAction; + QAction * m_pDemoAction; + QAction * m_pCheatAction; + + QStatusBar * m_pStatusBar; + QLabel * m_pStatusBarLabel; + QPointer m_helpWindow; // use a QPointer so we don't have to worry about knowing if + // the help window has been deleted. The Window auto deletes + // when closes. + QPointer m_aboutWindow; + GameMgr m_gameMgr; + bool m_firstShow; +}; + +#endif // MAINWINDOW_H diff --git a/plugins/qsolocards_plugin/object_script.qsolocards_plugin.Debug b/plugins/qsolocards_plugin/object_script.qsolocards_plugin.Debug new file mode 100644 index 000000000..cbdb74bc8 --- /dev/null +++ b/plugins/qsolocards_plugin/object_script.qsolocards_plugin.Debug @@ -0,0 +1,64 @@ +INPUT( +./temp\obj\QSoloCardsPlugin.o +./temp\obj\main.o +./temp\obj\mainwindow.o +./temp\obj\PlayingCard.o +./temp\obj\CardDeck.o +./temp\obj\CardPixmaps.o +./temp\obj\CardStack.o +./temp\obj\DragCardStack.o +./temp\obj\VCardStack.o +./temp\obj\CardAnimationLock.o +./temp\obj\StackToStackAniMove.o +./temp\obj\DealAnimation.o +./temp\obj\FlipAnimation.o +./temp\obj\StackToStackFlipAni.o +./temp\obj\GameBoard.o +./temp\obj\CardMoveRecord.o +./temp\obj\About.o +./temp\obj\Help.o +./temp\obj\GameMgr.o +./temp\obj\SpiderBoard.o +./temp\obj\SpiderHomeStack.o +./temp\obj\SpiderStack.o +./temp\obj\KlondikeStack.o +./temp\obj\KlondikeFlipStack.o +./temp\obj\KlondikeHomeStack.o +./temp\obj\KlondikeBoard.o +./temp\obj\FreeCellBoard.o +./temp\obj\FreeCellDeck.o +./temp\obj\FreeCellStack.o +./temp\obj\FreeCellHome.o +./temp\obj\FreeCellFree.o +./temp\obj\Spider3DeckBoard.o +./temp\obj\SpideretteBoard.o +./temp\obj\YukonBoard.o +./temp\obj\moc_QSoloCardsPlugin.o +./temp\obj\moc_mainwindow.o +./temp\obj\moc_CardStack.o +./temp\obj\moc_DragCardStack.o +./temp\obj\moc_VCardStack.o +./temp\obj\moc_CardAnimationLock.o +./temp\obj\moc_StackToStackAniMove.o +./temp\obj\moc_DealAnimation.o +./temp\obj\moc_FlipAnimation.o +./temp\obj\moc_StackToStackFlipAni.o +./temp\obj\moc_GameBoard.o +./temp\obj\moc_About.o +./temp\obj\moc_Help.o +./temp\obj\moc_SpiderBoard.o +./temp\obj\moc_SpiderStack.o +./temp\obj\moc_KlondikeStack.o +./temp\obj\moc_KlondikeFlipStack.o +./temp\obj\moc_KlondikeHomeStack.o +./temp\obj\moc_KlondikeBoard.o +./temp\obj\moc_FreeCellBoard.o +./temp\obj\moc_FreeCellDeck.o +./temp\obj\moc_FreeCellStack.o +./temp\obj\moc_FreeCellHome.o +./temp\obj\moc_FreeCellFree.o +./temp\obj\moc_Spider3DeckBoard.o +./temp\obj\moc_SpideretteBoard.o +./temp\obj\moc_YukonBoard.o +./temp\obj\qrc_QSoloCards.o +); diff --git a/plugins/qsolocards_plugin/object_script.qsolocards_plugin.Release b/plugins/qsolocards_plugin/object_script.qsolocards_plugin.Release new file mode 100644 index 000000000..cbdb74bc8 --- /dev/null +++ b/plugins/qsolocards_plugin/object_script.qsolocards_plugin.Release @@ -0,0 +1,64 @@ +INPUT( +./temp\obj\QSoloCardsPlugin.o +./temp\obj\main.o +./temp\obj\mainwindow.o +./temp\obj\PlayingCard.o +./temp\obj\CardDeck.o +./temp\obj\CardPixmaps.o +./temp\obj\CardStack.o +./temp\obj\DragCardStack.o +./temp\obj\VCardStack.o +./temp\obj\CardAnimationLock.o +./temp\obj\StackToStackAniMove.o +./temp\obj\DealAnimation.o +./temp\obj\FlipAnimation.o +./temp\obj\StackToStackFlipAni.o +./temp\obj\GameBoard.o +./temp\obj\CardMoveRecord.o +./temp\obj\About.o +./temp\obj\Help.o +./temp\obj\GameMgr.o +./temp\obj\SpiderBoard.o +./temp\obj\SpiderHomeStack.o +./temp\obj\SpiderStack.o +./temp\obj\KlondikeStack.o +./temp\obj\KlondikeFlipStack.o +./temp\obj\KlondikeHomeStack.o +./temp\obj\KlondikeBoard.o +./temp\obj\FreeCellBoard.o +./temp\obj\FreeCellDeck.o +./temp\obj\FreeCellStack.o +./temp\obj\FreeCellHome.o +./temp\obj\FreeCellFree.o +./temp\obj\Spider3DeckBoard.o +./temp\obj\SpideretteBoard.o +./temp\obj\YukonBoard.o +./temp\obj\moc_QSoloCardsPlugin.o +./temp\obj\moc_mainwindow.o +./temp\obj\moc_CardStack.o +./temp\obj\moc_DragCardStack.o +./temp\obj\moc_VCardStack.o +./temp\obj\moc_CardAnimationLock.o +./temp\obj\moc_StackToStackAniMove.o +./temp\obj\moc_DealAnimation.o +./temp\obj\moc_FlipAnimation.o +./temp\obj\moc_StackToStackFlipAni.o +./temp\obj\moc_GameBoard.o +./temp\obj\moc_About.o +./temp\obj\moc_Help.o +./temp\obj\moc_SpiderBoard.o +./temp\obj\moc_SpiderStack.o +./temp\obj\moc_KlondikeStack.o +./temp\obj\moc_KlondikeFlipStack.o +./temp\obj\moc_KlondikeHomeStack.o +./temp\obj\moc_KlondikeBoard.o +./temp\obj\moc_FreeCellBoard.o +./temp\obj\moc_FreeCellDeck.o +./temp\obj\moc_FreeCellStack.o +./temp\obj\moc_FreeCellHome.o +./temp\obj\moc_FreeCellFree.o +./temp\obj\moc_Spider3DeckBoard.o +./temp\obj\moc_SpideretteBoard.o +./temp\obj\moc_YukonBoard.o +./temp\obj\qrc_QSoloCards.o +); diff --git a/plugins/qsolocards_plugin/qsolocards_plugin.pro b/plugins/qsolocards_plugin/qsolocards_plugin.pro new file mode 100644 index 000000000..86393617a --- /dev/null +++ b/plugins/qsolocards_plugin/qsolocards_plugin.pro @@ -0,0 +1,106 @@ +# ------------------------------------------------- +# Project created by QtCreator 2009-03-07T14:27:09 +# ------------------------------------------------- +#=== this part is common (similar) for all plugin projects ===================== +TEMPLATE = lib +CONFIG += plugin release + +# this is directory, where PluginInterface.h is located +INCLUDEPATH += ../ + +# and, the result (*.so or *.dll) should appear in this directory +DESTDIR = ../bin +OBJECTS_DIR = temp/obj +RCC_DIR = temp/qrc +UI_DIR = temp/ui +MOC_DIR = temp/moc + + +# the name of the result file; +TARGET = $$qtLibraryTarget(qsolocards_plugin) + +HEADERS += ../PluginInterface.h \ + QSoloCardsPlugin.h +SOURCES += QSoloCardsPlugin.cpp + +#=============================================================================== +SOURCES += main.cpp \ + mainwindow.cpp \ + PlayingCard.cpp \ + CardDeck.cpp \ + CardPixmaps.cpp \ + CardStack.cpp \ + DragCardStack.cpp \ + VCardStack.cpp \ + CardAnimationLock.cpp \ + StackToStackAniMove.cpp \ + DealAnimation.cpp \ + FlipAnimation.cpp \ + StackToStackFlipAni.cpp \ + GameBoard.cpp \ + CardMoveRecord.cpp \ + About.cpp \ + Help.cpp \ + GameMgr.cpp \ + SpiderBoard.cpp \ + SpiderHomeStack.cpp \ + SpiderStack.cpp \ + KlondikeStack.cpp \ + KlondikeFlipStack.cpp \ + KlondikeHomeStack.cpp \ + KlondikeBoard.cpp \ + FreeCellBoard.cpp \ + FreeCellDeck.cpp \ + FreeCellStack.cpp \ + FreeCellHome.cpp \ + FreeCellFree.cpp \ + Spider3DeckBoard.cpp \ + SpideretteBoard.cpp \ + YukonBoard.cpp +HEADERS += mainwindow.h \ + PlayingCard.h \ + CardDeck.h \ + CardPixmaps.h \ + CardStack.h \ + DragCardStack.h \ + VCardStack.h \ + CardAnimationLock.h \ + StackToStackAniMove.h \ + DealAnimation.h \ + FlipAnimation.h \ + StackToStackFlipAni.h \ + GameBoard.h \ + CardMoveRecord.h \ + About.h \ + Help.h \ + GameMgr.h \ + SpiderBoard.h \ + SpiderHomeStack.h \ + SpiderStack.h \ + KlondikeStack.h \ + KlondikeFlipStack.h \ + KlondikeHomeStack.h \ + KlondikeBoard.h \ + FreeCellBoard.h \ + FreeCellDeck.h \ + FreeCellStack.h \ + FreeCellHome.h \ + FreeCellFree.h \ + Spider3DeckBoard.h \ + SpideretteBoard.h \ + YukonBoard.h + +QT += svg +RESOURCES = QSoloCards.qrc + +mac:QMAKE_MAC_SDK=/Developer/SDKs/MacOSX10.4u.sdk +mac:CONFIG+=x86 ppc + +VER_MAJ = 0 +VER_MIN = 99 +VER_PAT = 1 +QMAKE_CXXFLAGS_DEBUG = -DVER_MAJ=$$VER_MAJ \ + -DVER_MIN=$$VER_MIN \ + -DVER_PAT=$$VER_PAT +QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CXXFLAGS_DEBUG +mac:ICON = QSoloCards.icns

Preamble