/* 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