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