1 /*
2  * Copyright (C) 1995 Paul Olav Tvete <paul@troll.no>
3  * Copyright (C) 2000-2009 Stephan Kulow <coolo@kde.org>
4  * Copyright (C) 2010 Parker Coates <coates@kde.org>
5  *
6  * License of original code:
7  * -------------------------------------------------------------------------
8  *   Permission to use, copy, modify, and distribute this software and its
9  *   documentation for any purpose and without fee is hereby granted,
10  *   provided that the above copyright notice appear in all copies and that
11  *   both that copyright notice and this permission notice appear in
12  *   supporting documentation.
13  *
14  *   This file is provided AS IS with no warranties of any kind.  The author
15  *   shall have no liability with respect to the infringement of copyrights,
16  *   trade secrets or any patents by this file or any part thereof.  In no
17  *   event will the author be liable for any lost revenue or profits or
18  *   other special, indirect and consequential damages.
19  * -------------------------------------------------------------------------
20  *
21  * License of modifications/additions made after 2009-01-01:
22  * -------------------------------------------------------------------------
23  *   This program is free software; you can redistribute it and/or
24  *   modify it under the terms of the GNU General Public License as
25  *   published by the Free Software Foundation; either version 2 of
26  *   the License, or (at your option) any later version.
27  *
28  *   This program is distributed in the hope that it will be useful,
29  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
30  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  *   GNU General Public License for more details.
32  *
33  *   You should have received a copy of the GNU General Public License
34  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
35  * -------------------------------------------------------------------------
36  */
37 
38 #include "kcardpile.h"
39 
40 // own
41 #include "kabstractcarddeck.h"
42 #include "kcardscene.h"
43 // Qt
44 #include <QPropertyAnimation>
45 #include <QPainter>
46 // Std
47 #include <cmath>
48 
49 class KCardPilePrivate : public QObject
50 {
51     Q_OBJECT
52 
53     Q_PROPERTY( qreal highlightedness READ highlightedness WRITE setHighlightedness )
54 
55 public:
56     KCardPilePrivate( KCardPile * q );
57 
58     void setHighlightedness( qreal highlightedness );
59     qreal highlightedness() const;
60 
61     KCardPile * q;
62 
63     QList<KCard*> cards;
64 
65     bool autoTurnTop;
66     bool highlighted;
67 
68     QSize graphicSize;
69     QPointF layoutPos;
70     QPointF spread;
71 
72     qreal topPadding;
73     qreal rightPadding;
74     qreal bottomPadding;
75     qreal leftPadding;
76 
77     KCardPile::WidthPolicy widthPolicy;
78     KCardPile::HeightPolicy heightPolicy;
79 
80     KCardPile::KeyboardFocusHint selectHint;
81     KCardPile::KeyboardFocusHint dropHint;
82 
83     qreal highlightValue;
84 
85     QPropertyAnimation * fadeAnimation;
86 };
87 
88 
KCardPilePrivate(KCardPile * q)89 KCardPilePrivate::KCardPilePrivate( KCardPile * q )
90   : QObject( q ),
91     q( q )
92 {
93 }
94 
95 
setHighlightedness(qreal highlightedness)96 void KCardPilePrivate::setHighlightedness( qreal highlightedness )
97 {
98     highlightValue = highlightedness;
99     q->update();
100 }
101 
102 
highlightedness() const103 qreal KCardPilePrivate::highlightedness() const
104 {
105     return highlightValue;
106 }
107 
108 
KCardPile(KCardScene * cardScene)109 KCardPile::KCardPile( KCardScene * cardScene )
110   : QGraphicsObject(),
111     d( new KCardPilePrivate( this ) )
112 {
113     d->autoTurnTop = false;
114     d->highlighted = false;
115     d->highlightValue = 0;
116     d->spread = QPointF( 0, 0 );
117 
118     d->topPadding = 0;
119     d->rightPadding = 0;
120     d->bottomPadding = 0;
121     d->leftPadding = 0;
122 
123     d->widthPolicy = FixedWidth;
124     d->heightPolicy = FixedHeight;
125 
126     d->fadeAnimation = new QPropertyAnimation( d, "highlightedness", d );
127     d->fadeAnimation->setDuration( 150 );
128     d->fadeAnimation->setKeyValueAt( 0, 0 );
129     d->fadeAnimation->setKeyValueAt( 1, 1 );
130 
131     setZValue( 0 );
132     QGraphicsItem::setVisible( true );
133 
134     if ( cardScene )
135         cardScene->addPile( this );
136 }
137 
138 
~KCardPile()139 KCardPile::~KCardPile()
140 {
141     for (KCard * c : qAsConst(d->cards))
142         c->setPile( nullptr );
143 
144     KCardScene * cardScene = dynamic_cast<KCardScene*>( scene() );
145     if ( cardScene )
146         cardScene->removePile( this );
147 }
148 
149 
type() const150 int KCardPile::type() const
151 {
152     return KCardPile::Type;
153 }
154 
155 
boundingRect() const156 QRectF KCardPile::boundingRect() const
157 {
158     return QRectF( QPointF( 0, 0 ), d->graphicSize );
159 }
160 
161 
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)162 void KCardPile::paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget )
163 {
164     Q_UNUSED( option );
165     Q_UNUSED( widget );
166 
167     paintGraphic( painter, d->highlightValue );
168 }
169 
170 
cards() const171 QList<KCard*> KCardPile::cards() const
172 {
173     return d->cards;
174 }
175 
176 
count() const177 int KCardPile::count() const
178 {
179     return d->cards.count();
180 }
181 
182 
isEmpty() const183 bool KCardPile::isEmpty() const
184 {
185     return d->cards.isEmpty();
186 }
187 
188 
indexOf(const KCard * card) const189 int KCardPile::indexOf( const KCard * card ) const
190 {
191     return d->cards.indexOf( const_cast<KCard*>( card ) );
192 }
193 
194 
at(int index) const195 KCard * KCardPile::at( int index ) const
196 {
197     if ( index < 0 || index >= d->cards.size() )
198         return nullptr;
199     return d->cards.at( index );
200 }
201 
202 
topCard() const203 KCard * KCardPile::topCard() const
204 {
205     if ( d->cards.isEmpty() )
206         return nullptr;
207 
208     return d->cards.last();
209 }
210 
211 
topCards(int depth) const212 QList<KCard*> KCardPile::topCards( int depth ) const
213 {
214     if ( depth <= 0 )
215         return QList<KCard*>();
216 
217     if ( depth > count() )
218         return d->cards;
219 
220     return d->cards.mid( count() - depth );
221 }
222 
223 
topCardsDownTo(const KCard * card) const224 QList<KCard*> KCardPile::topCardsDownTo( const KCard * card ) const
225 {
226     int index = d->cards.indexOf( const_cast<KCard*>( card ) );
227     if ( index == -1 )
228         return QList<KCard*>();
229     return d->cards.mid( index );
230 }
231 
232 
setLayoutPos(QPointF pos)233 void KCardPile::setLayoutPos( QPointF pos )
234 {
235     d->layoutPos = pos;
236 }
237 
238 
setLayoutPos(qreal x,qreal y)239 void KCardPile::setLayoutPos( qreal x,  qreal y )
240 {
241     setLayoutPos( QPointF( x, y ) );
242 }
243 
244 
layoutPos() const245 QPointF KCardPile::layoutPos() const
246 {
247     return d->layoutPos;
248 }
249 
250 
setWidthPolicy(WidthPolicy policy)251 void KCardPile::setWidthPolicy( WidthPolicy policy )
252 {
253     d->widthPolicy = policy;
254 }
255 
256 
widthPolicy() const257 KCardPile::WidthPolicy KCardPile::widthPolicy() const
258 {
259     return d->widthPolicy;
260 }
261 
262 
setHeightPolicy(HeightPolicy policy)263 void KCardPile::setHeightPolicy( HeightPolicy policy )
264 {
265     d->heightPolicy = policy;
266 }
267 
268 
heightPolicy() const269 KCardPile::HeightPolicy KCardPile::heightPolicy() const
270 {
271     return d->heightPolicy;
272 }
273 
274 
setPadding(qreal topPadding,qreal rightPadding,qreal bottomPadding,qreal leftPadding)275 void KCardPile::setPadding( qreal topPadding, qreal rightPadding, qreal bottomPadding, qreal leftPadding )
276 {
277     setTopPadding( topPadding );
278     setRightPadding( rightPadding );
279     setBottomPadding( bottomPadding );
280     setLeftPadding( leftPadding);
281 }
282 
283 
setTopPadding(qreal padding)284 void KCardPile::setTopPadding( qreal padding )
285 {
286     d->topPadding = padding;
287 }
288 
289 
topPadding() const290 qreal KCardPile::topPadding() const
291 {
292     return d->topPadding;
293 }
294 
295 
setRightPadding(qreal padding)296 void KCardPile::setRightPadding( qreal padding )
297 {
298     d->rightPadding = padding;
299 }
300 
301 
rightPadding() const302 qreal KCardPile::rightPadding() const
303 {
304     return d->rightPadding;
305 }
306 
307 
setBottomPadding(qreal padding)308 void KCardPile::setBottomPadding( qreal padding )
309 {
310     d->bottomPadding = padding;
311 }
312 
313 
bottomPadding() const314 qreal KCardPile::bottomPadding() const
315 {
316     return d->bottomPadding;
317 }
318 
319 
setLeftPadding(qreal padding)320 void KCardPile::setLeftPadding( qreal padding )
321 {
322     d->leftPadding = padding;
323 }
324 
325 
leftPadding() const326 qreal KCardPile::leftPadding() const
327 {
328     return d->leftPadding;
329 }
330 
331 
setSpread(QPointF spread)332 void KCardPile::setSpread( QPointF spread )
333 {
334     d->spread = spread;
335 }
336 
337 
setSpread(qreal width,qreal height)338 void KCardPile::setSpread( qreal width, qreal height )
339 {
340     setSpread( QPointF( width, height ) );
341 }
342 
343 
spread() const344 QPointF KCardPile::spread() const
345 {
346     return d->spread;
347 }
348 
349 
setAutoTurnTop(bool autoTurnTop)350 void KCardPile::setAutoTurnTop( bool autoTurnTop )
351 {
352     d->autoTurnTop = autoTurnTop;
353 }
354 
355 
autoTurnTop() const356 bool KCardPile::autoTurnTop() const
357 {
358     return d->autoTurnTop;
359 }
360 
361 
setKeyboardSelectHint(KeyboardFocusHint hint)362 void KCardPile::setKeyboardSelectHint( KeyboardFocusHint hint )
363 {
364     d->selectHint = hint;
365 }
366 
367 
keyboardSelectHint() const368 KCardPile::KeyboardFocusHint KCardPile::keyboardSelectHint() const
369 {
370     return d->selectHint;
371 }
372 
373 
setKeyboardDropHint(KeyboardFocusHint hint)374 void KCardPile::setKeyboardDropHint( KeyboardFocusHint hint )
375 {
376     d->dropHint = hint;
377 }
378 
379 
keyboardDropHint() const380 KCardPile::KeyboardFocusHint KCardPile::keyboardDropHint() const
381 {
382     return d->dropHint;
383 }
384 
385 
setVisible(bool visible)386 void KCardPile::setVisible( bool visible )
387 {
388     if ( visible != isVisible() )
389     {
390         QGraphicsItem::setVisible( visible );
391         for (KCard * c : qAsConst(d->cards))
392             c->setVisible( visible );
393     }
394 }
395 
396 
setHighlighted(bool highlighted)397 void KCardPile::setHighlighted( bool highlighted )
398 {
399     if ( highlighted != d->highlighted )
400     {
401         d->highlighted = highlighted;
402         d->fadeAnimation->setDirection( highlighted
403                                        ? QAbstractAnimation::Forward
404                                        : QAbstractAnimation::Backward );
405         if ( d->fadeAnimation->state() != QAbstractAnimation::Running )
406             d->fadeAnimation->start();
407     }
408 }
409 
410 
isHighlighted() const411 bool KCardPile::isHighlighted() const
412 {
413     return d->highlighted;
414 }
415 
416 
add(KCard * card)417 void KCardPile::add( KCard * card )
418 {
419     insert( d->cards.size(), card );
420 }
421 
422 
insert(int index,KCard * card)423 void KCardPile::insert( int index, KCard * card )
424 {
425     if ( card->scene() != scene() )
426         scene()->addItem( card );
427 
428     if ( card->pile() )
429         card->pile()->remove( card );
430 
431     card->setPile( this );
432     card->setVisible( isVisible() );
433 
434     d->cards.insert( index, card );
435 }
436 
437 
remove(KCard * card)438 void KCardPile::remove( KCard * card )
439 {
440     Q_ASSERT( d->cards.contains( card ) );
441     d->cards.removeAll( card );
442     card->setPile( nullptr );
443 }
444 
445 
clear()446 void KCardPile::clear()
447 {
448     const auto currentCards = d->cards;
449     for (KCard *card : currentCards)
450         remove( card );
451     Q_ASSERT(d->cards.isEmpty());
452 }
453 
454 
swapCards(int index1,int index2)455 void KCardPile::swapCards( int index1, int index2 )
456 {
457     if ( index1 == index2 )
458         return;
459 
460     KCard * temp = d->cards.at( index1 );
461     d->cards[ index1 ] = d->cards.at( index2 );
462     d->cards[ index2 ] = temp;
463 }
464 
465 
paintGraphic(QPainter * painter,qreal highlightedness)466 void KCardPile::paintGraphic( QPainter * painter, qreal highlightedness )
467 {
468     int penWidth = boundingRect().width() / 40;
469     int topLeft = penWidth / 2;
470     int bottomRight = topLeft - penWidth;
471     painter->setPen( QPen( Qt::black, penWidth ) );
472     painter->setBrush( QColor( 0, 0, 0, 64 * highlightedness ) );
473     painter->drawRect( boundingRect().adjusted( topLeft, topLeft, bottomRight, bottomRight ) );
474 }
475 
476 
cardPositions() const477 QList<QPointF> KCardPile::cardPositions() const
478 {
479     QList<QPointF> positions;
480     for ( int i = 0; i < count(); ++i )
481         positions << i * spread();
482     return positions;
483 }
484 
485 
setGraphicSize(QSize size)486 void KCardPile::setGraphicSize( QSize size )
487 {
488     if ( size != d->graphicSize )
489     {
490         prepareGeometryChange();
491         d->graphicSize = size;
492         update();
493     }
494 }
495 
496 
497 #include "kcardpile.moc"
498 #include "moc_kcardpile.cpp"
499