File indexing completed on 2024-05-19 04:04:54

0001 /*
0002     This file is part of the game 'KJumpingCube'
0003 
0004     SPDX-FileCopyrightText: 1998-2000 Matthias Kiefer <matthias.kiefer@gmx.de>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "kcubewidget.h"
0010 
0011 #include <QPainter>
0012 #include <QMouseEvent>
0013 #include <QPaintEvent>
0014 #include <QPixmap>
0015 
0016 /* ****************************************************** **
0017 **                 static elements                        **
0018 ** ****************************************************** */
0019 bool KCubeWidget::_clicksAllowed=true;
0020 
0021 void KCubeWidget::enableClicks(bool flag)
0022 {
0023    _clicksAllowed=flag;
0024 }
0025 
0026 /* ****************************************************** **
0027 **                 public functions                       **
0028 ** ****************************************************** */
0029 
0030 KCubeWidget::KCubeWidget (QWidget* parent)
0031               : QFrame(parent)
0032 {
0033   setMinimumSize (20,20);
0034   setFrameStyle(QFrame::Panel | QFrame::Raised);
0035   int h = height();
0036   int w = width();
0037   setLineWidth ((h<w?h:w) / 14); // Make QFrame::Raised width proportional.
0038 
0039   setCoordinates (0, 0, 2);
0040 
0041   migrating = 0;
0042   m_scale = 1.0;
0043   m_row = 0;
0044   m_col = 0;
0045   m_owner = Nobody;
0046   m_value = 1;
0047 
0048   pixmaps = nullptr;
0049   blinking = None;
0050 
0051   // show values
0052   update();
0053 }
0054 
0055 KCubeWidget::~KCubeWidget()
0056 {
0057 }
0058 
0059 void KCubeWidget::setPixmaps (QList<QPixmap> * ptr)
0060 {
0061    pixmaps = ptr;
0062 }
0063 
0064 void KCubeWidget::setOwner (Player newOwner)
0065 {
0066    if (newOwner != m_owner) {
0067       m_owner = newOwner;
0068       updateColors();
0069    }
0070 }
0071 
0072 void KCubeWidget::setValue(int newValue)
0073 {
0074    if (newValue != m_value) {
0075       m_value = newValue;
0076       update();
0077    }
0078 }
0079 
0080 void KCubeWidget::shrink (qreal scale)
0081 {
0082    migrating = 0;
0083    m_scale = scale;
0084    update();
0085 }
0086 
0087 void KCubeWidget::expand (qreal scale)
0088 {
0089    migrating = 1;
0090    m_scale = scale;
0091    blinking = None;         // Remove overloaded cube's dark color.
0092    update();
0093 }
0094 
0095 void KCubeWidget::migrateDot (int rowDiff, int colDiff, int step, Player player)
0096 {
0097    migrating = 2;
0098    qreal scale = (step < 4) ? 1.0 - 0.3 * step : 0.0;
0099    m_rowDiff = rowDiff * scale;     // Calculate relative position of dot.
0100    m_colDiff = colDiff * scale;
0101    // If owner changes, fade in new color as dot approaches centre of cube.
0102    m_player  = player;
0103    m_opacity = (step < 4) ? 0.2 * (step + 1) : 1.0;
0104    update();
0105 }
0106 
0107 void KCubeWidget::setCoordinates (int row, int col, int limit)
0108 {
0109    m_row = row;
0110    m_col = col;
0111    m_limit = limit;
0112 }
0113 
0114 /* ****************************************************** **
0115 **                   public slots                         **
0116 ** ****************************************************** */
0117 
0118 void KCubeWidget::reset()
0119 {
0120   blinking = None;
0121   setValue (1);
0122   setOwner (Nobody);
0123   update();
0124 }
0125 
0126 
0127 void KCubeWidget::updateColors()
0128 {
0129   update();
0130 }
0131 
0132 /* ****************************************************** **
0133 **                   Event handler                        **
0134 ** ****************************************************** */
0135 
0136 void KCubeWidget::mouseReleaseEvent(QMouseEvent *e)
0137 {
0138   // only accept click if it was inside this cube
0139   const QPoint mousePos = e->position().toPoint();
0140   if (mousePos.x() < 0 || mousePos.x() > width() || mousePos.y() < 0 || mousePos.y() > height())
0141     return;
0142 
0143   if(e->button() == Qt::LeftButton && _clicksAllowed) {
0144     e->accept();
0145     Q_EMIT clicked (m_row, m_col);
0146   }
0147 }
0148 
0149 void KCubeWidget::paintEvent(QPaintEvent * /* ev unused */)
0150 {
0151   if ((pixmaps == nullptr) || (pixmaps->isEmpty()))
0152       return;
0153 
0154   int width  = this->width();
0155   int height = this->height();
0156 
0157   QPainter p(this);
0158 
0159   SVGElement el = Neutral;
0160   if (owner() == One)
0161     el = Player1;
0162   else if (owner() == Two)
0163     el = Player2;
0164 
0165   // if ((migrating == 2) && (m_player != owner())) // && (m_scale < 0.5))
0166     // el = m_element;
0167 
0168   int pmw = pixmaps->at(el).width();
0169   int pmh = pixmaps->at(el).height();
0170   p.drawPixmap ((width - pmw)/2, (height - pmh)/2, pixmaps->at(el));
0171   if ((migrating == 2) && (m_player != owner())) {
0172       el = (m_player == One) ? Player1 : Player2;
0173       p.setOpacity (m_opacity); // Cube is being captured: fade in new color.
0174       p.drawPixmap ((width - pmw)/2, (height - pmh)/2, pixmaps->at(el));
0175       p.setOpacity (1.0);
0176   }
0177 
0178   QPixmap pip = pixmaps->at(Pip);
0179   int dia = pip.width();
0180 
0181   // Normally scale = 1.0, but it will be less during the first part of an
0182   // animation that shows a cube taking over its neighboring cubes.
0183 
0184   int w   = m_scale * width;    // The size of the pattern of pips.
0185   int h   = m_scale * height;
0186   int cx  = width/2;        // The center point of the cube face.
0187   int cy  = height/2;
0188   int tlx = (width - w) / 2;    // The top left corner of the pattern of pips.
0189   int tly = (height - h) / 2;
0190 
0191   int points = (migrating == 1) ? 0 : value();
0192   if (migrating == 2) {
0193       int dRow = m_rowDiff * width / 2;
0194       int dCol = m_colDiff * height / 2;
0195       p.drawPixmap (cx + dRow - dia/2, cy + dCol - dia/2, pip);
0196   }
0197 
0198   switch (points) {
0199   case 0:
0200       // Show the pattern of pips migrating to neighboring cubes: 
0201       // one pip in the center and one migrating to each neighbor.
0202       p.drawPixmap    (cx - dia/2,          cy - dia/2,           pip);
0203       if (m_scale > 1.0) {  // The migrating dots have all left this cube.
0204          break;
0205       }
0206       if (m_row > 0)        // Neighbor above, if any.
0207          p.drawPixmap (tlx - dia/2,         cy - dia/2,           pip);
0208       if (m_row < m_limit)  // Neighbor below, if any.
0209          p.drawPixmap (width - tlx - dia/2, cy - dia/2,           pip);
0210       if (m_col > 0)        // Neighbor to left, if any.
0211          p.drawPixmap (cx - dia/2,          tly - dia/2,          pip);
0212       if (m_col < m_limit)  // Neighbor to right, if any.
0213          p.drawPixmap (cx - dia/2,          height - tly - dia/2, pip);
0214       break;
0215 
0216       // Otherwise show a pattern for the current number of pips. It may be
0217       // scaled down during the first part of an animation that shows a cube
0218       // taking over its neighboring cubes.
0219   case 1:
0220       p.drawPixmap (tlx + (w - dia)/2, tly + (h - dia)/2, pip);
0221       break;
0222 
0223   case 3:
0224       p.drawPixmap (tlx + (w - dia)/2, tly + (h - dia)/2, pip);
0225       [[fallthrough]];
0226   case 2:
0227       p.drawPixmap (tlx + (w/2 - dia)/2, tly + (h/2 - dia)/2, pip);
0228       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (3*h/2 - dia)/2, pip);
0229       break;
0230 
0231   case 5:
0232       p.drawPixmap (tlx + (w - dia)/2, tly + (h - dia)/2, pip);
0233       [[fallthrough]];
0234   case 4:
0235       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (h/2 - dia)/2, pip);
0236       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (3*h/2 - dia)/2, pip);
0237       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (h/2 - dia)/2, pip);
0238       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (3*h/2 - dia)/2, pip);
0239       break;
0240 
0241   case 8:
0242       p.drawPixmap (tlx + (w - dia)/2,     tly + 2*h/3 - dia/2, pip);
0243       [[fallthrough]];
0244   case 7:
0245       p.drawPixmap (tlx + (w - dia)/2,     tly + h/3 - dia/2, pip);
0246       [[fallthrough]];
0247   case 6:
0248       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (h/2 - dia)/2, pip);
0249       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (h - dia)/2, pip);
0250       p.drawPixmap (tlx + (w/2 - dia)/2,   tly + (3*h/2 - dia)/2, pip);
0251       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (h/2 - dia)/2, pip);
0252       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (h - dia)/2, pip);
0253       p.drawPixmap (tlx + (3*w/2 - dia)/2, tly + (3*h/2 - dia)/2, pip);
0254       break;
0255 
0256   default:
0257       QString s = QString::asprintf("%d",points);
0258       p.setPen(Qt::black);
0259       p.drawText(tlx + w/2,tly + h/2,s);
0260       break;
0261   }
0262 
0263   // This is used to highlight a cube and also to perform the hint animation.
0264   switch (blinking) {
0265   case Light:
0266       p.drawPixmap ((width - pmw)/2, (height - pmh)/2, pixmaps->at(BlinkLight));
0267       break;
0268   case Dark:
0269       p.drawPixmap ((width - pmw)/2, (height - pmh)/2, pixmaps->at(BlinkDark));
0270       break;
0271   default:
0272       break;
0273   }
0274   migrating = 0;
0275   m_scale = 1.0;
0276 
0277   p.end();
0278 }
0279 
0280 #include "moc_kcubewidget.cpp"