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