File indexing completed on 2025-01-26 03:49:00

0001 /*
0002  * Copyright (C) 1995 Paul Olav Tvete <paul@troll.no>
0003  * Copyright (C) 2000-2009 Stephan Kulow <coolo@kde.org>
0004  * Copyright (C) 2010 Parker Coates <coates@kde.org>
0005  *
0006  * License of original code:
0007  * -------------------------------------------------------------------------
0008  *   Permission to use, copy, modify, and distribute this software and its
0009  *   documentation for any purpose and without fee is hereby granted,
0010  *   provided that the above copyright notice appear in all copies and that
0011  *   both that copyright notice and this permission notice appear in
0012  *   supporting documentation.
0013  *
0014  *   This file is provided AS IS with no warranties of any kind.  The author
0015  *   shall have no liability with respect to the infringement of copyrights,
0016  *   trade secrets or any patents by this file or any part thereof.  In no
0017  *   event will the author be liable for any lost revenue or profits or
0018  *   other special, indirect and consequential damages.
0019  * -------------------------------------------------------------------------
0020  *
0021  * License of modifications/additions made after 2009-01-01:
0022  * -------------------------------------------------------------------------
0023  *   This program is free software; you can redistribute it and/or
0024  *   modify it under the terms of the GNU General Public License as
0025  *   published by the Free Software Foundation; either version 2 of
0026  *   the License, or (at your option) any later version.
0027  *
0028  *   This program is distributed in the hope that it will be useful,
0029  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0030  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0031  *   GNU General Public License for more details.
0032  *
0033  *   You should have received a copy of the GNU General Public License
0034  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
0035  * -------------------------------------------------------------------------
0036  */
0037 
0038 #include "kcardpile.h"
0039 
0040 // own
0041 #include "kabstractcarddeck.h"
0042 #include "kcardscene.h"
0043 // Qt
0044 #include <QPainter>
0045 #include <QPropertyAnimation>
0046 // Std
0047 #include <cmath>
0048 
0049 class KCardPilePrivate : public QObject
0050 {
0051     Q_OBJECT
0052 
0053     Q_PROPERTY(qreal highlightedness READ highlightedness WRITE setHighlightedness)
0054 
0055 public:
0056     KCardPilePrivate(KCardPile *q);
0057 
0058     void setHighlightedness(qreal highlightedness);
0059     qreal highlightedness() const;
0060 
0061     KCardPile *q;
0062 
0063     QList<KCard *> cards;
0064 
0065     bool autoTurnTop;
0066     bool highlighted;
0067 
0068     QSize graphicSize;
0069     QPointF layoutPos;
0070     QPointF spread;
0071 
0072     qreal topPadding;
0073     qreal rightPadding;
0074     qreal bottomPadding;
0075     qreal leftPadding;
0076 
0077     KCardPile::WidthPolicy widthPolicy;
0078     KCardPile::HeightPolicy heightPolicy;
0079 
0080     KCardPile::KeyboardFocusHint selectHint;
0081     KCardPile::KeyboardFocusHint dropHint;
0082 
0083     qreal highlightValue;
0084 
0085     QPropertyAnimation *fadeAnimation;
0086 };
0087 
0088 KCardPilePrivate::KCardPilePrivate(KCardPile *q)
0089     : QObject(q)
0090     , q(q)
0091 {
0092 }
0093 
0094 void KCardPilePrivate::setHighlightedness(qreal highlightedness)
0095 {
0096     highlightValue = highlightedness;
0097     q->update();
0098 }
0099 
0100 qreal KCardPilePrivate::highlightedness() const
0101 {
0102     return highlightValue;
0103 }
0104 
0105 KCardPile::KCardPile(KCardScene *cardScene)
0106     : QGraphicsObject()
0107     , d(new KCardPilePrivate(this))
0108 {
0109     d->autoTurnTop = false;
0110     d->highlighted = false;
0111     d->highlightValue = 0;
0112     d->spread = QPointF(0, 0);
0113 
0114     d->topPadding = 0;
0115     d->rightPadding = 0;
0116     d->bottomPadding = 0;
0117     d->leftPadding = 0;
0118 
0119     d->widthPolicy = FixedWidth;
0120     d->heightPolicy = FixedHeight;
0121 
0122     d->fadeAnimation = new QPropertyAnimation(d, "highlightedness", d);
0123     d->fadeAnimation->setDuration(150);
0124     d->fadeAnimation->setKeyValueAt(0, 0);
0125     d->fadeAnimation->setKeyValueAt(1, 1);
0126 
0127     setZValue(0);
0128     QGraphicsItem::setVisible(true);
0129 
0130     if (cardScene)
0131         cardScene->addPile(this);
0132 }
0133 
0134 KCardPile::~KCardPile()
0135 {
0136     for (KCard *c : std::as_const(d->cards))
0137         c->setPile(nullptr);
0138 
0139     KCardScene *cardScene = dynamic_cast<KCardScene *>(scene());
0140     if (cardScene)
0141         cardScene->removePile(this);
0142 }
0143 
0144 int KCardPile::type() const
0145 {
0146     return KCardPile::Type;
0147 }
0148 
0149 QRectF KCardPile::boundingRect() const
0150 {
0151     return QRectF(QPointF(0, 0), d->graphicSize);
0152 }
0153 
0154 void KCardPile::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
0155 {
0156     Q_UNUSED(option);
0157     Q_UNUSED(widget);
0158 
0159     paintGraphic(painter, d->highlightValue);
0160 }
0161 
0162 QList<KCard *> KCardPile::cards() const
0163 {
0164     return d->cards;
0165 }
0166 
0167 int KCardPile::count() const
0168 {
0169     return d->cards.count();
0170 }
0171 
0172 bool KCardPile::isEmpty() const
0173 {
0174     return d->cards.isEmpty();
0175 }
0176 
0177 int KCardPile::indexOf(const KCard *card) const
0178 {
0179     return d->cards.indexOf(const_cast<KCard *>(card));
0180 }
0181 
0182 KCard *KCardPile::at(int index) const
0183 {
0184     if (index < 0 || index >= d->cards.size())
0185         return nullptr;
0186     return d->cards.at(index);
0187 }
0188 
0189 KCard *KCardPile::topCard() const
0190 {
0191     if (d->cards.isEmpty())
0192         return nullptr;
0193 
0194     return d->cards.last();
0195 }
0196 
0197 QList<KCard *> KCardPile::topCards(int depth) const
0198 {
0199     if (depth <= 0)
0200         return QList<KCard *>();
0201 
0202     if (depth > count())
0203         return d->cards;
0204 
0205     return d->cards.mid(count() - depth);
0206 }
0207 
0208 QList<KCard *> KCardPile::topCardsDownTo(const KCard *card) const
0209 {
0210     int index = d->cards.indexOf(const_cast<KCard *>(card));
0211     if (index == -1)
0212         return QList<KCard *>();
0213     return d->cards.mid(index);
0214 }
0215 
0216 void KCardPile::setLayoutPos(QPointF pos)
0217 {
0218     d->layoutPos = pos;
0219 }
0220 
0221 void KCardPile::setLayoutPos(qreal x, qreal y)
0222 {
0223     setLayoutPos(QPointF(x, y));
0224 }
0225 
0226 QPointF KCardPile::layoutPos() const
0227 {
0228     return d->layoutPos;
0229 }
0230 
0231 void KCardPile::setWidthPolicy(WidthPolicy policy)
0232 {
0233     d->widthPolicy = policy;
0234 }
0235 
0236 KCardPile::WidthPolicy KCardPile::widthPolicy() const
0237 {
0238     return d->widthPolicy;
0239 }
0240 
0241 void KCardPile::setHeightPolicy(HeightPolicy policy)
0242 {
0243     d->heightPolicy = policy;
0244 }
0245 
0246 KCardPile::HeightPolicy KCardPile::heightPolicy() const
0247 {
0248     return d->heightPolicy;
0249 }
0250 
0251 void KCardPile::setPadding(qreal topPadding, qreal rightPadding, qreal bottomPadding, qreal leftPadding)
0252 {
0253     setTopPadding(topPadding);
0254     setRightPadding(rightPadding);
0255     setBottomPadding(bottomPadding);
0256     setLeftPadding(leftPadding);
0257 }
0258 
0259 void KCardPile::setTopPadding(qreal padding)
0260 {
0261     d->topPadding = padding;
0262 }
0263 
0264 qreal KCardPile::topPadding() const
0265 {
0266     return d->topPadding;
0267 }
0268 
0269 void KCardPile::setRightPadding(qreal padding)
0270 {
0271     d->rightPadding = padding;
0272 }
0273 
0274 qreal KCardPile::rightPadding() const
0275 {
0276     return d->rightPadding;
0277 }
0278 
0279 void KCardPile::setBottomPadding(qreal padding)
0280 {
0281     d->bottomPadding = padding;
0282 }
0283 
0284 qreal KCardPile::bottomPadding() const
0285 {
0286     return d->bottomPadding;
0287 }
0288 
0289 void KCardPile::setLeftPadding(qreal padding)
0290 {
0291     d->leftPadding = padding;
0292 }
0293 
0294 qreal KCardPile::leftPadding() const
0295 {
0296     return d->leftPadding;
0297 }
0298 
0299 void KCardPile::setSpread(QPointF spread)
0300 {
0301     d->spread = spread;
0302 }
0303 
0304 void KCardPile::setSpread(qreal width, qreal height)
0305 {
0306     setSpread(QPointF(width, height));
0307 }
0308 
0309 QPointF KCardPile::spread() const
0310 {
0311     return d->spread;
0312 }
0313 
0314 void KCardPile::setAutoTurnTop(bool autoTurnTop)
0315 {
0316     d->autoTurnTop = autoTurnTop;
0317 }
0318 
0319 bool KCardPile::autoTurnTop() const
0320 {
0321     return d->autoTurnTop;
0322 }
0323 
0324 void KCardPile::setKeyboardSelectHint(KeyboardFocusHint hint)
0325 {
0326     d->selectHint = hint;
0327 }
0328 
0329 KCardPile::KeyboardFocusHint KCardPile::keyboardSelectHint() const
0330 {
0331     return d->selectHint;
0332 }
0333 
0334 void KCardPile::setKeyboardDropHint(KeyboardFocusHint hint)
0335 {
0336     d->dropHint = hint;
0337 }
0338 
0339 KCardPile::KeyboardFocusHint KCardPile::keyboardDropHint() const
0340 {
0341     return d->dropHint;
0342 }
0343 
0344 void KCardPile::setVisible(bool visible)
0345 {
0346     if (visible != isVisible()) {
0347         QGraphicsItem::setVisible(visible);
0348         for (KCard *c : std::as_const(d->cards))
0349             c->setVisible(visible);
0350     }
0351 }
0352 
0353 void KCardPile::setHighlighted(bool highlighted)
0354 {
0355     if (highlighted != d->highlighted) {
0356         d->highlighted = highlighted;
0357         d->fadeAnimation->setDirection(highlighted ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
0358         if (d->fadeAnimation->state() != QAbstractAnimation::Running)
0359             d->fadeAnimation->start();
0360     }
0361 }
0362 
0363 bool KCardPile::isHighlighted() const
0364 {
0365     return d->highlighted;
0366 }
0367 
0368 void KCardPile::add(KCard *card)
0369 {
0370     insert(d->cards.size(), card);
0371 }
0372 
0373 void KCardPile::insert(int index, KCard *card)
0374 {
0375     if (card->scene() != scene())
0376         scene()->addItem(card);
0377 
0378     if (card->pile())
0379         card->pile()->remove(card);
0380 
0381     card->setPile(this);
0382     card->setVisible(isVisible());
0383 
0384     d->cards.insert(index, card);
0385 }
0386 
0387 void KCardPile::remove(KCard *card)
0388 {
0389     Q_ASSERT(d->cards.contains(card));
0390     d->cards.removeAll(card);
0391     card->setPile(nullptr);
0392 }
0393 
0394 void KCardPile::clear()
0395 {
0396     const auto currentCards = d->cards;
0397     for (KCard *card : currentCards)
0398         remove(card);
0399     Q_ASSERT(d->cards.isEmpty());
0400 }
0401 
0402 void KCardPile::swapCards(int index1, int index2)
0403 {
0404     if (index1 == index2)
0405         return;
0406 
0407     KCard *temp = d->cards.at(index1);
0408     d->cards[index1] = d->cards.at(index2);
0409     d->cards[index2] = temp;
0410 }
0411 
0412 void KCardPile::paintGraphic(QPainter *painter, qreal highlightedness)
0413 {
0414     int penWidth = boundingRect().width() / 40;
0415     int topLeft = penWidth / 2;
0416     int bottomRight = topLeft - penWidth;
0417     painter->setPen(QPen(Qt::black, penWidth));
0418     painter->setBrush(QColor(0, 0, 0, 64 * highlightedness));
0419     painter->drawRect(boundingRect().adjusted(topLeft, topLeft, bottomRight, bottomRight));
0420 }
0421 
0422 QList<QPointF> KCardPile::cardPositions() const
0423 {
0424     QList<QPointF> positions;
0425     for (int i = 0; i < count(); ++i)
0426         positions << i * spread();
0427     return positions;
0428 }
0429 
0430 void KCardPile::setGraphicSize(QSize size)
0431 {
0432     if (size != d->graphicSize) {
0433         prepareGeometryChange();
0434         d->graphicSize = size;
0435         update();
0436     }
0437 }
0438 
0439 #include "kcardpile.moc"
0440 #include "moc_kcardpile.cpp"