1 /*
2     This file is part of the game 'KJumpingCube'
3 
4     SPDX-FileCopyrightText: 1998-2000 Matthias Kiefer <matthias.kiefer@gmx.de>
5 
6     SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 
9 #include "kcubewidget.h"
10 
11 #include <QPainter>
12 #include <QMouseEvent>
13 #include <QPaintEvent>
14 #include <QPixmap>
15 
16 /* ****************************************************** **
17 **                 static elements                        **
18 ** ****************************************************** */
19 bool KCubeWidget::_clicksAllowed=true;
20 
enableClicks(bool flag)21 void KCubeWidget::enableClicks(bool flag)
22 {
23    _clicksAllowed=flag;
24 }
25 
26 /* ****************************************************** **
27 **                 public functions                       **
28 ** ****************************************************** */
29 
KCubeWidget(QWidget * parent)30 KCubeWidget::KCubeWidget (QWidget* parent)
31               : QFrame(parent)
32 {
33   setMinimumSize (20,20);
34   setFrameStyle(QFrame::Panel | QFrame::Raised);
35   int h = height();
36   int w = width();
37   setLineWidth ((h<w?h:w) / 14); // Make QFrame::Raised width proportional.
38 
39   setCoordinates (0, 0, 2);
40 
41   migrating = 0;
42   m_scale = 1.0;
43   m_row = 0;
44   m_col = 0;
45   m_owner = Nobody;
46   m_value = 1;
47 
48   pixmaps = nullptr;
49   blinking = None;
50 
51   // show values
52   update();
53 }
54 
~KCubeWidget()55 KCubeWidget::~KCubeWidget()
56 {
57 }
58 
setPixmaps(QList<QPixmap> * ptr)59 void KCubeWidget::setPixmaps (QList<QPixmap> * ptr)
60 {
61    pixmaps = ptr;
62 }
63 
setOwner(Player newOwner)64 void KCubeWidget::setOwner (Player newOwner)
65 {
66    if (newOwner != m_owner) {
67       m_owner = newOwner;
68       updateColors();
69    }
70 }
71 
setValue(int newValue)72 void KCubeWidget::setValue(int newValue)
73 {
74    if (newValue != m_value) {
75       m_value = newValue;
76       update();
77    }
78 }
79 
shrink(qreal scale)80 void KCubeWidget::shrink (qreal scale)
81 {
82    migrating = 0;
83    m_scale = scale;
84    update();
85 }
86 
expand(qreal scale)87 void KCubeWidget::expand (qreal scale)
88 {
89    migrating = 1;
90    m_scale = scale;
91    blinking = None;			// Remove overloaded cube's dark color.
92    update();
93 }
94 
migrateDot(int rowDiff,int colDiff,int step,Player player)95 void KCubeWidget::migrateDot (int rowDiff, int colDiff, int step, Player player)
96 {
97    migrating = 2;
98    qreal scale = (step < 4) ? 1.0 - 0.3 * step : 0.0;
99    m_rowDiff = rowDiff * scale;		// Calculate relative position of dot.
100    m_colDiff = colDiff * scale;
101    // If owner changes, fade in new color as dot approaches centre of cube.
102    m_player  = player;
103    m_opacity = (step < 4) ? 0.2 * (step + 1) : 1.0;
104    update();
105 }
106 
setCoordinates(int row,int col,int limit)107 void KCubeWidget::setCoordinates (int row, int col, int limit)
108 {
109    m_row = row;
110    m_col = col;
111    m_limit = limit;
112 }
113 
114 /* ****************************************************** **
115 **                   public slots                         **
116 ** ****************************************************** */
117 
reset()118 void KCubeWidget::reset()
119 {
120   blinking = None;
121   setValue (1);
122   setOwner (Nobody);
123   update();
124 }
125 
126 
updateColors()127 void KCubeWidget::updateColors()
128 {
129   update();
130 }
131 
132 /* ****************************************************** **
133 **                   Event handler                        **
134 ** ****************************************************** */
135 
mouseReleaseEvent(QMouseEvent * e)136 void KCubeWidget::mouseReleaseEvent(QMouseEvent *e)
137 {
138   // only accept click if it was inside this cube
139   if(e->x()< 0 || e->x() > width() || e->y() < 0 || e->y() > height())
140     return;
141 
142   if(e->button() == Qt::LeftButton && _clicksAllowed) {
143     e->accept();
144     Q_EMIT clicked (m_row, m_col);
145   }
146 }
147 
paintEvent(QPaintEvent *)148 void KCubeWidget::paintEvent(QPaintEvent * /* ev unused */)
149 {
150   if ((pixmaps == nullptr) || (pixmaps->isEmpty()))
151       return;
152 
153   int width  = this->width();
154   int height = this->height();
155 
156   QPainter p(this);
157 
158   SVGElement el = Neutral;
159   if (owner() == One)
160     el = Player1;
161   else if (owner() == Two)
162     el = Player2;
163 
164   // if ((migrating == 2) && (m_player != owner()))	// && (m_scale < 0.5))
165     // el = m_element;
166 
167   int pmw = pixmaps->at(el).width();
168   int pmh = pixmaps->at(el).height();
169   p.drawPixmap ((width - pmw)/2, (height - pmh)/2, pixmaps->at(el));
170   if ((migrating == 2) && (m_player != owner())) {
171       el = (m_player == One) ? Player1 : Player2;
172       p.setOpacity (m_opacity);	// Cube is being captured: fade in new color.
173       p.drawPixmap ((width - pmw)/2, (height - pmh)/2, pixmaps->at(el));
174       p.setOpacity (1.0);
175   }
176 
177   QPixmap pip = pixmaps->at(Pip);
178   int dia = pip.width();
179 
180   // Normally scale = 1.0, but it will be less during the first part of an
181   // animation that shows a cube taking over its neighboring cubes.
182 
183   int w   = m_scale * width;	// The size of the pattern of pips.
184   int h   = m_scale * height;
185   int cx  = width/2;		// The center point of the cube face.
186   int cy  = height/2;
187   int tlx = (width - w) / 2;	// The top left corner of the pattern of pips.
188   int tly = (height - h) / 2;
189 
190   int points = (migrating == 1) ? 0 : value();
191   if (migrating == 2) {
192       int dRow = m_rowDiff * width / 2;
193       int dCol = m_colDiff * height / 2;
194       p.drawPixmap (cx + dRow - dia/2, cy + dCol - dia/2, pip);
195   }
196 
197   switch (points) {
198   case 0:
199       // Show the pattern of pips migrating to neighboring cubes:
200       // one pip in the center and one migrating to each neighbor.
201       p.drawPixmap    (cx - dia/2,          cy - dia/2,           pip);
202       if (m_scale > 1.0) {	// The migrating dots have all left this cube.
203          break;
204       }
205       if (m_row > 0)		// Neighbor above, if any.
206          p.drawPixmap (tlx - dia/2,         cy - dia/2,           pip);
207       if (m_row < m_limit)	// Neighbor below, if any.
208          p.drawPixmap (width - tlx - dia/2, cy - dia/2,           pip);
209       if (m_col > 0)		// Neighbor to left, if any.
210          p.drawPixmap (cx - dia/2,          tly - dia/2,          pip);
211       if (m_col < m_limit)	// Neighbor to right, if any.
212          p.drawPixmap (cx - dia/2,          height - tly - dia/2, pip);
213       break;
214 
215       // Otherwise show a pattern for the current number of pips. It may be
216       // scaled down during the first part of an animation that shows a cube
217       // taking over its neighboring cubes.
218   case 1:
219       p.drawPixmap (tlx + (w - dia)/2, tly + (h - dia)/2, pip);
220       break;
221 
222   case 3:
223       p.drawPixmap (tlx + (w - dia)/2, tly + (h - dia)/2, pip);
224   case 2:
225       p.drawPixmap (tlx + (w/2 - dia)/2, tly + (h/2 - dia)/2, pip);
226       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (3*h/2 - dia)/2, pip);
227       break;
228 
229   case 5:
230       p.drawPixmap (tlx + (w - dia)/2, tly + (h - dia)/2, pip);
231   case 4:
232       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (h/2 - dia)/2, pip);
233       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (3*h/2 - dia)/2, pip);
234       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (h/2 - dia)/2, pip);
235       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (3*h/2 - dia)/2, pip);
236       break;
237 
238   case 8:
239       p.drawPixmap (tlx + (w - dia)/2,     tly + 2*h/3 - dia/2, pip);
240   case 7:
241       p.drawPixmap (tlx + (w - dia)/2,     tly + h/3 - dia/2, pip);
242   case 6:
243       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (h/2 - dia)/2, pip);
244       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (h - dia)/2, pip);
245       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (3*h/2 - dia)/2, pip);
246       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (h/2 - dia)/2, pip);
247       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (h - dia)/2, pip);
248       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (3*h/2 - dia)/2, pip);
249       break;
250 
251   default:
252       QString s = QString::asprintf("%d",points);
253       p.setPen(Qt::black);
254       p.drawText(tlx + w/2,tly + h/2,s);
255       break;
256   }
257 
258   // This is used to highlight a cube and also to perform the hint animation.
259   switch (blinking) {
260   case Light:
261       p.drawPixmap ((width - pmw)/2, (height - pmh)/2, pixmaps->at(BlinkLight));
262       break;
263   case Dark:
264       p.drawPixmap ((width - pmw)/2, (height - pmh)/2, pixmaps->at(BlinkDark));
265       break;
266   default:
267       break;
268   }
269   migrating = 0;
270   m_scale = 1.0;
271 
272   p.end();
273 }
274 
275 
276