File indexing completed on 2025-02-16 06:56:36
0001 /* 0002 This file is part of the KDE games kwin4 program 0003 SPDX-FileCopyrightText: 2006 Martin Heni <kde@heni-online.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "displaygame.h" 0009 0010 // own 0011 #include "kwin4doc.h" 0012 #include "kwin4view.h" 0013 #include "piecesprite.h" 0014 #include "pixmapsprite.h" 0015 #include "reflectiongraphicsscene.h" 0016 #include "scoresprite.h" 0017 #include "spritenotify.h" 0018 // KF 0019 #include "kfourinline_debug.h" 0020 // Qt 0021 #include <QColor> 0022 #include <QPixmap> 0023 #include <QPoint> 0024 // Std 0025 #include <cassert> 0026 #include <cmath> 0027 0028 // Constructor for the display 0029 DisplayGame::DisplayGame(ReflectionGraphicsScene *scene, ThemeManager *theme, QGraphicsView *parent) 0030 : Themeable(QStringLiteral("gamedisplay"), theme) 0031 , QObject(parent) 0032 { 0033 // Store arguments as attributes 0034 mScene = scene; 0035 mView = parent; 0036 mTheme = theme; 0037 0038 // Choose a background color 0039 scene->setBackgroundBrush(QColor(0, 0, 128)); 0040 0041 // Clear storage of all sprites 0042 mSprites.clear(); 0043 0044 // Create piece sprites 0045 for (int i = 0; i < 42; i++) { 0046 PieceSprite *sprite = new PieceSprite(QStringLiteral("piece"), mTheme, i, mScene); 0047 if (!sprite) 0048 qCCritical(KFOURINLINE_LOG) << "Cannot load sprite" 0049 << "piece"; 0050 mSprites.append(sprite); 0051 mPieces.append(sprite); 0052 sprite->hide(); 0053 } 0054 0055 // Create stars 0056 for (int i = 0; i < 4; i++) { 0057 PixmapSprite *sprite = new PixmapSprite(QStringLiteral("star"), mTheme, i, mScene); 0058 if (!sprite) 0059 qCCritical(KFOURINLINE_LOG) << "Cannot load sprite" 0060 << "star"; 0061 mSprites.append(sprite); 0062 mStars.append(sprite); 0063 sprite->hide(); 0064 } 0065 0066 // Create board 0067 mBoard = new PixmapSprite(QStringLiteral("board"), mTheme, 0, mScene); 0068 if (!mBoard) 0069 qCCritical(KFOURINLINE_LOG) << "Cannot load sprite" 0070 << "board"; 0071 mSprites.append(mBoard); 0072 mBoard->hide(); 0073 0074 // Create hint 0075 mHint = new PixmapSprite(QStringLiteral("hint"), mTheme, 0, mScene); 0076 if (!mHint) 0077 qCCritical(KFOURINLINE_LOG) << "Cannot load sprite" 0078 << "hint"; 0079 mSprites.append(mHint); 0080 mHint->hide(); 0081 0082 // Create Game Over 0083 // mGameOver = new PixmapSprite("gameover", mTheme, 0, mScene); 0084 // if (!mGameOver) qCCritical(KFOURINLINE_LOG) << "Cannot load sprite" << "gameover"; 0085 // mSprites.append(mGameOver); 0086 // mGameOver->hide(); 0087 0088 // Create score board 0089 mScoreBoard = new ScoreSprite(QStringLiteral("scoreboard"), mTheme, 0, mScene); 0090 if (!mScoreBoard) 0091 qCCritical(KFOURINLINE_LOG) << "Cannot load sprite" 0092 << "scoreboard"; 0093 mSprites.append(mScoreBoard); 0094 mScoreBoard->hide(); 0095 0096 // Create movement indication arrows 0097 for (int i = 0; i < 7; i++) { 0098 PixmapSprite *arrow = new PixmapSprite(QStringLiteral("arrow"), mTheme, i, mScene); 0099 if (!arrow) 0100 qCCritical(KFOURINLINE_LOG) << "Cannot load sprite" 0101 << "arrow"; 0102 mSprites.append(arrow); 0103 mArrows.append(arrow); 0104 arrow->hide(); 0105 } 0106 0107 // Static decoration 0108 KConfigGroup config = thememanager()->config(id()); 0109 QStringList deco = config.readEntry("decoration", QStringList()); 0110 for (int i = 0; i < deco.size(); i++) { 0111 PixmapSprite *sprite = new PixmapSprite(deco.at(i), mTheme, i, mScene); 0112 if (!sprite) 0113 qCCritical(KFOURINLINE_LOG) << "Cannot load sprite" << deco.at(i); 0114 mSprites.append(sprite); 0115 sprite->show(); 0116 } 0117 0118 // Animation timer 0119 mTimer = new QTimer(this); 0120 connect(mTimer, &QTimer::timeout, this, &DisplayGame::advance); 0121 0122 // Redraw 0123 if (theme) 0124 theme->updateTheme(this); 0125 } 0126 0127 // Destructor: clean up 0128 DisplayGame::~DisplayGame() 0129 { 0130 delete mTimer; 0131 qDeleteAll(mSprites); 0132 } 0133 0134 // Called by thememanager when theme or theme geometry changes. Redraw and resize 0135 // this display. 0136 void DisplayGame::changeTheme() 0137 { 0138 // Retrieve theme data 0139 KConfigGroup config = thememanager()->config(id()); 0140 QPointF board_pos = config.readEntry("board-pos", QPointF(1.0, 1.0)); 0141 QPointF arrow_pos = config.readEntry("arrow-pos", QPointF(1.0, 1.0)); 0142 QPointF board_spread = config.readEntry("board-spread", QPointF(1.0, 1.0)); 0143 0144 // Retrieve background pixmap 0145 QString bgsvgid = config.readEntry("background-svgid"); 0146 QPixmap pixmap = thememanager()->getPixmap(bgsvgid, mScene->sceneRect().size().toSize()); 0147 mScene->setBackgroundBrush(pixmap); 0148 QRectF pos = mBoard->sceneBoundingRect(); 0149 0150 // Move movement arrows 0151 for (int i = 0; i < 7; i++) { 0152 PixmapSprite *arrow = mArrows.value(i); 0153 QPointF to = QPointF(board_spread.x() * i + arrow_pos.x(), board_spread.y() * 0 + arrow_pos.y()); 0154 arrow->setPosition(to); 0155 } 0156 0157 // Move piece sprites 0158 for (int i = 0; i < 42; i++) { 0159 PieceSprite *piece = mPieces.value(i); 0160 int x = piece->logicalPos().x(); 0161 int y = piece->logicalPos().y(); 0162 QPointF to = QPointF(board_spread.x() * x + board_pos.x(), board_spread.y() * y + board_pos.y()); 0163 piece->setPosition(to); 0164 } 0165 0166 // Move hint 0167 { 0168 int x = mHint->logicalPos().x(); 0169 int y = mHint->logicalPos().y(); 0170 QPointF to = QPointF(board_spread.x() * x + board_pos.x(), board_spread.y() * y + board_pos.y()); 0171 mHint->setPosition(to); 0172 } 0173 0174 // Move stars 0175 for (int i = 0; i < 4; i++) { 0176 PixmapSprite *star = mStars.value(i); 0177 int x = star->logicalPos().x(); 0178 int y = star->logicalPos().y(); 0179 QPointF to = QPointF(board_spread.x() * x + board_pos.x(), board_spread.y() * y + board_pos.y()); 0180 star->setPosition(to); 0181 } 0182 0183 // Check whether the theme uses reflection handling 0184 if (config.readEntry("use-reflection", false)) { 0185 dynamic_cast<KWin4View *>(mView)->setReflection((int)pos.x(), 0186 (int)(pos.y() + pos.height()), 0187 (int)(mScene->sceneRect().width() - pos.x()), 0188 (int)(pos.height() * 0.3)); 0189 } else { 0190 // Zero width disables the reflections 0191 dynamic_cast<KWin4View *>(mView)->setReflection(0, 0, 0, 0); 0192 } 0193 0194 mView->update(); 0195 } 0196 0197 // Start a new game. Initialize graphics. 0198 void DisplayGame::start() 0199 { 0200 // Run timer (unused) 0201 // mTimer->setSingleShot(true); 0202 // mTimer->start(0); 0203 0204 // Show decoration 0205 mBoard->show(); 0206 mScoreBoard->show(); 0207 0208 // Show movement arrows 0209 for (int i = 0; i < 7; i++) { 0210 mArrows.value(i)->setFrame(0); 0211 mArrows.value(i)->show(); 0212 } 0213 0214 // Hide piece sprites 0215 for (int i = 0; i < 42; i++) { 0216 mPieces.value(i)->hide(); 0217 } 0218 0219 // Hide stars 0220 for (int i = 0; i < 4; i++) { 0221 mStars.value(i)->setAnimation(false); 0222 mStars.value(i)->hide(); 0223 } 0224 } 0225 0226 // Run game animation 0227 void DisplayGame::advance() 0228 { 0229 // Currently unused 0230 } 0231 0232 // Display end game sprite 0233 void DisplayGame::displayEnd() 0234 { 0235 // assert(mGameOver != 0); 0236 // mGameOver->show(); 0237 } 0238 0239 // Set the movement indicator arrows above the game board 0240 void DisplayGame::displayArrow(int x, int color) 0241 { 0242 // Set all arrows back to frame 0 0243 for (int i = 0; i < 7; i++) { 0244 mArrows.value(i)->setFrame(0); 0245 } 0246 0247 // Check for no color 0248 if (color == Nobody) { 0249 return; 0250 } 0251 0252 // Make sure the frames are chosen properly 0253 if (color == Yellow) 0254 mArrows.value(x)->setFrame(1); 0255 else 0256 mArrows.value(x)->setFrame(2); 0257 } 0258 0259 // Set a game HINT sprite 0260 void DisplayGame::displayHint(int x, int y, bool show) 0261 { 0262 // Invert height 0263 y = 5 - y; 0264 0265 // Check for removal of the sprite 0266 if (!show) { 0267 mHint->hide(); 0268 return; 0269 } 0270 0271 // Retrieve theme data 0272 KConfigGroup config = thememanager()->config(id()); 0273 QPointF board_pos = config.readEntry("board-pos", QPointF(1.0, 1.0)); 0274 QPointF board_spread = config.readEntry("board-spread", QPointF(1.0, 1.0)); 0275 0276 QPointF to = QPointF(board_spread.x() * x + board_pos.x(), board_spread.y() * y + board_pos.y()); 0277 mHint->setLogicalPos(QPoint(x, y)); 0278 mHint->setPosition(to); 0279 mHint->show(); 0280 } 0281 0282 // Set a game piece, red or yellow or hidden depending on 'color' 0283 SpriteNotify *DisplayGame::displayPiece(int x, int y, int color, int no, bool animation) 0284 { 0285 // Invert height 0286 y = 5 - y; 0287 0288 // Get piece 0289 PieceSprite *sprite = mPieces.value(no); 0290 assert(sprite != nullptr); 0291 0292 // Check for removal of sprite 0293 if (color == Nobody) { 0294 sprite->hide(); 0295 return nullptr; 0296 } 0297 0298 // Retrieve theme data 0299 KConfigGroup config = thememanager()->config(id()); 0300 QPointF board_pos = config.readEntry("board-pos", QPointF(1.0, 1.0)); 0301 QPointF board_spread = config.readEntry("board-spread", QPointF(1.0, 1.0)); 0302 double velocity = config.readEntry("move-velocity", 0.8); 0303 0304 // Make sure the frames are ok 0305 int frame; 0306 if (color == Yellow) 0307 frame = 0; 0308 else 0309 frame = 1; 0310 0311 // Just draw the sprites or show an movement animation? 0312 if (animation) { 0313 QPointF from = QPointF(board_spread.x() * x + board_pos.x(), board_spread.y() * (-1) + board_pos.y()); 0314 QPointF to = QPointF(board_spread.x() * x + board_pos.x(), board_spread.y() * y + board_pos.y()); 0315 sprite->setFrame(frame); 0316 sprite->startLinear(from, to, velocity); 0317 // For theme store (x,y) board coordinate 0318 sprite->setLogicalPos(QPoint(x, y)); 0319 } else { 0320 QPointF to = QPointF(board_spread.x() * x + board_pos.x(), board_spread.y() * y + board_pos.y()); 0321 sprite->setFrame(frame); 0322 sprite->setPosition(to); 0323 // For theme store (x,y) board coordinate 0324 sprite->setLogicalPos(QPoint(x, y)); 0325 } 0326 0327 sprite->show(); 0328 return sprite->notify(); 0329 } 0330 0331 // Draw Star Sprites as winning indicator 0332 void DisplayGame::displayStar(int x, int y, int no) 0333 { 0334 // Invert height 0335 y = 5 - y; 0336 PixmapSprite *star = mStars.value(no - 1); 0337 assert(star != nullptr); 0338 0339 // Retrieve theme data 0340 KConfigGroup config = thememanager()->config(id()); 0341 QPointF board_pos = config.readEntry("board-pos", QPointF(1.0, 1.0)); 0342 QPointF board_spread = config.readEntry("board-spread", QPointF(1.0, 1.0)); 0343 0344 QPointF pos = QPointF(board_spread.x() * x + board_pos.x(), board_spread.y() * y + board_pos.y()); 0345 star->setAnimation(true); 0346 star->setLogicalPos(QPoint(x, y)); 0347 star->setPosition(pos); 0348 star->show(); 0349 } 0350 0351 // Return the mouse mapped to the board or bar item so that a 0352 // move 0..6 is generated. -1 means an illegal position. 0353 int DisplayGame::mapMouseToMove(const QPoint &pos) 0354 { 0355 // Error? 0356 if (!mBoard) 0357 return -1; 0358 0359 // Find which arrow the mouse is closest to. This way 0360 // all board scaling become irrelevant. An alternative 0361 // would be to calculate the position using board_pos and 0362 // board_spread. 0363 for (int i = 0; i < 7; i++) { 0364 PixmapSprite *arrow = mArrows.value(i); 0365 int width = int(arrow->boundingRect().width()); 0366 int relPos = int(arrow->mapFromParent(QPointF(pos)).x()); 0367 // Found matching arrow 0368 if (relPos > 0 && relPos <= width) { 0369 return i; 0370 } 0371 } 0372 0373 // Nothing found 0374 return -1; 0375 } 0376 0377 // Retrieve the score sprite. 0378 ScoreSprite *DisplayGame::score() 0379 { 0380 return mScoreBoard; 0381 } 0382 0383 #include "moc_displaygame.cpp"