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