File indexing completed on 2023-05-30 10:40:02
0001 /* 0002 SPDX-FileCopyrightText: 2005-2007 Albert Astals Cid <aacid@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "blinken.h" 0008 0009 #include <QCursor> 0010 #include <QPainter> 0011 #include <QSvgRenderer> 0012 #include <QTimer> 0013 #include <QApplication> 0014 #include <QInputDialog> 0015 #include <QKeySequence> 0016 #include <QMouseEvent> 0017 #include <QAction> 0018 0019 #include <KHelpMenu> 0020 #include <KFontUtils> 0021 #include <KLocalizedString> 0022 #include <KAboutData> 0023 0024 #include "button.h" 0025 #include "counter.h" 0026 #include "number.h" 0027 #include "highscoredialog.h" 0028 #include "settings.h" 0029 0030 static const double centerX = 2.0; 0031 static const double centerY = 2.5; 0032 static const double ellipseSmallAxisX = 3.98; 0033 static const double ellipseSmallAxisY = 3.41; 0034 static const double ellipseBigAxisX = 2.16; 0035 static const double ellipseBigAxisY = 2.74; 0036 static const double nonButtonRibbonX = 150.0; 0037 static const double nonButtonRibbonY = 125.0; 0038 0039 blinken::blinken() : m_overHighscore(false), m_overQuit(false), m_overCentralText(false), m_overMenu(false), m_overAboutKDE(false), m_overAboutBlinken(false), m_overSettings(false), m_overManual(false), m_overCentralLetters(false), m_overCounter(false), m_overFont(false), m_overSound(false), m_showPreferences(false), m_updateButtonHighlighting(false), m_highlighted(blinkenGame::none) 0040 { 0041 m_renderer = new QSvgRenderer(QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("images/blinken.svg"))); 0042 0043 m_buttons[0] = new button(blinkenGame::blue); 0044 m_buttons[1] = new button(blinkenGame::yellow); 0045 m_buttons[2] = new button(blinkenGame::red); 0046 m_buttons[3] = new button(blinkenGame::green); 0047 0048 m_fillColor = QColor(40, 40, 40); 0049 m_fontColor = QColor(126, 126, 126); 0050 m_fontHighlightColor = QColor(230, 230, 230); 0051 m_countDownColor = QColor(55, 55, 55); 0052 0053 setMouseTracking(true); 0054 show(); 0055 0056 m_unhighlighter = new QTimer(this); 0057 connect(m_unhighlighter, &QTimer::timeout, this, &blinken::unhighlight); 0058 0059 connect(&m_game, &blinkenGame::gameEnded, this, &blinken::checkHS); 0060 connect(&m_game, SIGNAL(phaseChanged()), this, SLOT(update())); 0061 connect(&m_game, &blinkenGame::highlight, this, &blinken::highlight); 0062 0063 m_helpMenu = new KHelpMenu(this, KAboutData::applicationData()); 0064 m_helpMenu->menu(); // ensures the actions are created 0065 0066 for (int i = 0; i < 3; i++) m_overLevels[i] = false; 0067 0068 QString aux = i18nc("If the Steve font that is used by Blinken by default to show status messages does not support any of the characters of your language, please translate that message to 1 and KDE standard font will be used to show the texts, if not translate it to 0", "0"); 0069 0070 m_alwaysUseNonCoolFont = aux == QStringLiteral("1"); 0071 setAutoSaveSettings(); 0072 } 0073 0074 blinken::~blinken() 0075 { 0076 delete m_renderer; 0077 for (int i = 0; i < 4; i++) delete m_buttons[i]; 0078 delete m_helpMenu; 0079 } 0080 0081 QSize blinken::sizeHint() const 0082 { 0083 return QSize(600, 490); 0084 } 0085 0086 void blinken::paintEvent(QPaintEvent *) 0087 { 0088 m_centralLettersRect = QRectF((double)width() / 3.35, 0089 (double)height() / 2.68, 0090 (double)width() / 2.54, 0091 (double)height() / 10.0); 0092 m_counterRect = QRectF((double)width() / 2.42, 0093 (double)height() / 4.85, 0094 (double)width() / 6.22, 0095 (double)height() / 9.8); 0096 0097 QPainter p(this); 0098 p.setRenderHint(QPainter::Antialiasing, true); 0099 0100 if (m_lastSize != size()) 0101 { 0102 m_pixmapCache.clear(); 0103 m_lastSize = size(); 0104 } 0105 0106 // Base 0107 // This -1 +1 suck but without them i got blank lines on borders 0108 p.drawPixmap(-1, 0, getPixmap(QStringLiteral("blinkenBase"), size()+QSize(1,1))); 0109 0110 double xScaleButtons = 374.625 / 814.062; 0111 double yScaleButtons = 250.344 / 696.5; 0112 0113 const auto sz = QSize((int)(width() * xScaleButtons), (int)(height() * yScaleButtons)); 0114 0115 auto getPixmapFor = [this, sz](blinkenGame::color color, const QString& pixmapName) -> QPixmap { 0116 return getPixmap( m_highlighted & color ? 0117 QStringLiteral("%1_highlight").arg(pixmapName) : 0118 QStringLiteral("%1_normal").arg(pixmapName), sz); 0119 }; 0120 0121 p.drawPixmap(QPointF(width() / 1.975, height() / 28.0), getPixmapFor(blinkenGame::red, QStringLiteral("red"))); 0122 p.drawPixmap(QPointF(width() / 1.975, height() / 2.45), getPixmapFor(blinkenGame::green, QStringLiteral("green"))); 0123 p.drawPixmap(QPointF(width() / 30.0, height() / 28.0), getPixmapFor(blinkenGame::yellow, QStringLiteral("yellow"))); 0124 p.drawPixmap(QPointF(width() / 30.0, height() / 2.45), getPixmapFor(blinkenGame::blue, QStringLiteral("blue"))); 0125 0126 drawMenuQuit(p); 0127 p.resetTransform(); 0128 0129 // 644 525 are fixed size of preSVG blinken 0130 p.scale((double)width()/644.0, (double)height()/525.0); 0131 if (m_showPreferences) 0132 { 0133 // draw the current keys 0134 drawText(p, m_buttons[0]->shortcut(), QPoint(115, 285), true, 20, 5, nullptr, m_buttons[0]->selected(), false); 0135 drawText(p, m_buttons[1]->shortcut(), QPointF(115, 155), true, 20, 5, nullptr, m_buttons[1]->selected(), false); 0136 drawText(p, m_buttons[2]->shortcut(), QPointF(520, 155), true, 20, 5, nullptr, m_buttons[2]->selected(), false); 0137 drawText(p, m_buttons[3]->shortcut(), QPointF(520, 285), true, 20, 5, nullptr, m_buttons[3]->selected(), false); 0138 0139 const QPen &oPen = p.pen(); 0140 const QBrush &oBrush = p.brush(); 0141 const QFont &oFont = p.font(); 0142 0143 // draw the internal square plus a bit of ellipse on the sides and the 0144 // two delimiter lines 0145 p.setPen(Qt::NoPen); 0146 p.setBrush(m_fillColor); 0147 p.drawPie(173, 180, 6, 58, 1440, 2880); 0148 p.drawPie(470, 180, 6, 58, -1440, 2880); 0149 p.setPen(QPen(Qt::black, 3)); 0150 p.fillRect(175, 180, 299, 58, m_fillColor); 0151 p.drawLine(175, 180, 472, 180); 0152 p.drawLine(175, 238, 472, 238); 0153 0154 // draw the two squares of the options 0155 p.setPen(QPen(m_fontColor, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin)); 0156 0157 m_soundRect = QRect(181, 197, 25, 25); 0158 m_fontRect = QRect(432, 197, 25, 25); 0159 p.drawRect(m_soundRect); 0160 if (blinkenSettings::playSounds()) 0161 { 0162 p.drawLine(186, 202, 201, 217); 0163 p.drawLine(186, 217, 201, 202); 0164 } 0165 if (!m_alwaysUseNonCoolFont) 0166 { 0167 p.drawRect(m_fontRect); 0168 if (blinkenSettings::customFont()) 0169 { 0170 p.drawLine(437, 202, 452, 217); 0171 p.drawLine(437, 217, 452, 202); 0172 } 0173 } 0174 0175 // draw the options' text 0176 QFont f1 = QFont(); 0177 p.setFont(f1); 0178 int size, sizeAux; 0179 QRect area; 0180 QString sounds = i18n("Sounds"); 0181 QString font = i18n("Font"); 0182 size = KFontUtils::adaptFontSize(p, sounds, 95, 20, 28, 1, KFontUtils::DoNotAllowWordWrap); 0183 sizeAux = KFontUtils::adaptFontSize(p, font, 95, 20, 28, 1, KFontUtils::DoNotAllowWordWrap); 0184 if (sizeAux > size) size = sizeAux; 0185 f1.setPointSize(size); 0186 area = p.boundingRect(QRect(), Qt::AlignLeft, sounds); 0187 area.translate(212, 209 - (area.height() / 2)); 0188 p.drawText(area, Qt::AlignCenter, sounds); 0189 m_soundRect = m_soundRect.united(area); 0190 if (!m_alwaysUseNonCoolFont) 0191 { 0192 area = p.boundingRect(QRect(), Qt::AlignLeft, font); 0193 area.translate(426 - area.width(), 209 - (area.height() / 2)); 0194 p.drawText(area, Qt::AlignCenter, font); 0195 m_fontRect = m_fontRect.united(area); 0196 } 0197 0198 p.setFont(oFont); 0199 p.setPen(oPen); 0200 p.setBrush(oBrush); 0201 0202 // store the "real" rect 0203 m_fontRect = p.worldTransform().mapRect(m_fontRect); 0204 m_soundRect = p.worldTransform().mapRect(m_soundRect); 0205 } 0206 0207 drawScoreAndCounter(p); 0208 0209 drawStatusText(p); 0210 0211 p.resetTransform(); 0212 p.setFont(QFont()); //Go back to normal font 0213 // Start / Restart button 0214 // We don't use the scale matrix because this way we get a better font 0215 double aux1, aux2, aux3, aux4; 0216 aux1 = (double)width() / 2.02515723270440251572; 0217 aux2 = (double)height() / 1.66139240506329113924; 0218 aux3 = (double)width() / 64.4; 0219 aux4 = (double)height() / 105.0; 0220 switch (m_game.phase()) 0221 { 0222 case blinkenGame::starting: 0223 drawText(p, i18nc("@action:button Start a new game", "Start"), QPointF(aux1, aux2), true, aux3, aux4, &m_centralTextRect, m_overCentralText, true); 0224 break; 0225 0226 case blinkenGame::choosingLevel: 0227 drawLevel(p); 0228 break; 0229 0230 case blinkenGame::waiting3: 0231 case blinkenGame::waiting2: 0232 case blinkenGame::waiting1: 0233 case blinkenGame::learningTheSequence: 0234 case blinkenGame::typingTheSequence: 0235 drawText(p, i18n("Restart"), QPointF(aux1, aux2), true, aux3, aux4, &m_centralTextRect, m_overCentralText, true); 0236 break; 0237 } 0238 0239 if (m_updateButtonHighlighting) updateButtonHighlighting(mapFromGlobal(QCursor::pos())); 0240 } 0241 0242 void blinken::keyPressEvent(QKeyEvent *e) 0243 { 0244 if (e -> isAutoRepeat()) return; 0245 0246 if (m_showPreferences) 0247 { 0248 int i = 0; 0249 while (i < 4 && !m_buttons[i] -> selected()) i++; 0250 0251 if (i < 4) 0252 { 0253 if (e -> key() == Qt::Key_Escape) 0254 { 0255 m_buttons[i] -> setSelected(false); 0256 update(); 0257 } 0258 else 0259 { 0260 QKeySequence ks(e -> key()); 0261 if (!ks.toString().isEmpty()) 0262 { 0263 bool different = true; 0264 int j = 0; 0265 while (different && j < 4) 0266 { 0267 different = (ks.toString() != m_buttons[j] -> shortcut()); 0268 j++; 0269 } 0270 0271 if (different) 0272 { 0273 m_buttons[i] -> setShortcut(e->key()); 0274 update(); 0275 } 0276 } 0277 } 0278 } 0279 } 0280 else 0281 { 0282 if (m_game.phase() == blinkenGame::starting) 0283 { 0284 if (e -> key() == Qt::Key_Return || e -> key() == Qt::Key_Enter) 0285 { 0286 startGamePressed(); 0287 return; 0288 } 0289 } 0290 else if (m_game.phase() == blinkenGame::choosingLevel) 0291 { 0292 if (e -> key() == Qt::Key_1) 0293 { 0294 startGameAtLevel(1); 0295 return; 0296 } 0297 else if (e -> key() == Qt::Key_2) 0298 { 0299 startGameAtLevel(2); 0300 return; 0301 } 0302 else if (e -> key() == Qt::Key_3) 0303 { 0304 startGameAtLevel(3); 0305 return; 0306 } 0307 } 0308 0309 if (e -> key() == m_buttons[0] -> key()) pressedColor(blinkenGame::color::blue); 0310 else if (e -> key() == m_buttons[1] -> key()) pressedColor(blinkenGame::color::yellow); 0311 else if (e -> key() == m_buttons[2] -> key()) pressedColor(blinkenGame::color::red); 0312 else if (e -> key() == m_buttons[3] -> key()) pressedColor(blinkenGame::color::green); 0313 } 0314 } 0315 0316 void blinken::keyReleaseEvent(QKeyEvent *e) 0317 { 0318 if (e -> isAutoRepeat()) return; 0319 0320 if (e -> key() == Qt::Key_Control) 0321 { 0322 togglePreferences(); 0323 } 0324 } 0325 0326 void blinken::togglePreferences() 0327 { 0328 if (m_game.phase() == blinkenGame::starting || m_game.phase() == blinkenGame::choosingLevel) 0329 { 0330 m_showPreferences = !m_showPreferences; 0331 for (int i = 0; i < 4; i++) m_buttons[i] -> setSelected(false); 0332 updateButtonHighlighting(mapFromGlobal(QCursor::pos())); 0333 update(); 0334 } 0335 } 0336 0337 void blinken::mouseMoveEvent(QMouseEvent *e) 0338 { 0339 updateButtonHighlighting(e->pos()); 0340 } 0341 0342 void blinken::mousePressEvent(QMouseEvent *e) 0343 { 0344 if (m_overHighscore || m_overCounter) 0345 { 0346 highScoreDialog hsd(this, m_renderer); 0347 hsd.showLevel(1); 0348 m_updateButtonHighlighting = true; 0349 } 0350 else if (m_showPreferences && m_fontRect.contains(e -> pos()) && !m_alwaysUseNonCoolFont) 0351 { 0352 blinkenSettings::setCustomFont(!blinkenSettings::customFont()); 0353 blinkenSettings::self()->save(); 0354 update(); 0355 } 0356 else if (m_showPreferences && m_soundRect.contains(e -> pos())) 0357 { 0358 blinkenSettings::setPlaySounds(!blinkenSettings::playSounds()); 0359 blinkenSettings::self()->save(); 0360 update(); 0361 } 0362 else if (m_overQuit) qApp->quit(); 0363 else if (m_overAboutBlinken || m_overCentralLetters) m_helpMenu -> aboutApplication(); 0364 else if (m_overAboutKDE) m_helpMenu -> aboutKDE(); 0365 else if (m_overSettings) togglePreferences(); 0366 else if (m_overManual) m_helpMenu -> appHelpActivated(); 0367 else if (m_game.phase() != blinkenGame::choosingLevel && m_overCentralText) 0368 { 0369 startGamePressed(); 0370 } 0371 else if (m_game.phase() == blinkenGame::choosingLevel) 0372 { 0373 int level = 0; 0374 if (m_levelsRect[1].contains(e -> pos())) level = 1; 0375 else if (m_levelsRect[0].contains(e -> pos())) level = 2; 0376 else if (m_levelsRect[2].contains(e -> pos())) level = 3; 0377 if (level) 0378 { 0379 startGameAtLevel(level); 0380 } 0381 } 0382 0383 QPointF p = e->pos(); 0384 p -= QPointF((double)width() / centerX, (double)height() / centerY); 0385 if (insideGreen(p)) 0386 { 0387 if (m_showPreferences) selectButton(3); 0388 else pressedColor(blinkenGame::color::green); 0389 } 0390 else if (insideBlue(p)) 0391 { 0392 if (m_showPreferences) selectButton(0); 0393 else pressedColor(blinkenGame::color::blue); 0394 } 0395 else if (insideYellow(p)) 0396 { 0397 if (m_showPreferences) selectButton(1); 0398 else pressedColor(blinkenGame::color::yellow); 0399 } 0400 else if (insideRed(p)) 0401 { 0402 if (m_showPreferences) selectButton(2); 0403 else pressedColor(blinkenGame::color::red); 0404 } 0405 } 0406 0407 void blinken::checkHS() 0408 { 0409 highScoreManager hsm; 0410 if (hsm.scoreGoodEnough(m_game.level(), m_game.score())) 0411 { 0412 bool ok; 0413 const QString name = QInputDialog::getText(this, i18n("Enter Your Name"), i18nc("@label:textbox refers to the user's name", "Name:"), QLineEdit::Normal, m_lastName, &ok); 0414 if (!name.isNull() && ok) 0415 { 0416 m_lastName = name; 0417 hsm.addScore(m_game.level(), m_game.score(), name); 0418 } 0419 highScoreDialog hsd(this, m_renderer); 0420 hsd.showLevel(m_game.level()); 0421 } 0422 } 0423 0424 void blinken::highlight(blinkenGame::color c, bool unhighlight) 0425 { 0426 m_highlighted = c; 0427 update(); 0428 if (unhighlight) m_unhighlighter -> start(250); 0429 else if (c == blinkenGame::none) 0430 { 0431 m_unhighlighter -> stop(); 0432 updateCursor(mapFromGlobal(QCursor::pos())); 0433 } 0434 } 0435 0436 void blinken::unhighlight() 0437 { 0438 highlight(blinkenGame::none, false); 0439 } 0440 0441 void blinken::pressedColor(blinkenGame::color color) 0442 { 0443 if (m_game.canType()) 0444 { 0445 highlight(color, true); 0446 m_game.clicked(color); 0447 } 0448 } 0449 0450 void blinken::startGamePressed() 0451 { 0452 highlight(blinkenGame::none, true); 0453 m_overCentralText = false; 0454 for(int i = 0; i < 3; i++) m_overLevels[i] = false; 0455 m_game.setPhase(blinkenGame::choosingLevel); 0456 m_updateButtonHighlighting = true; 0457 } 0458 0459 void blinken::startGameAtLevel(int level) 0460 { 0461 for(int i = 0; i < 3; i++) m_overLevels[i] = false; 0462 m_game.start(level); 0463 if (m_showPreferences) m_showPreferences = false; 0464 m_updateButtonHighlighting = true; 0465 } 0466 0467 void blinken::selectButton(int button) 0468 { 0469 int i = 0; 0470 bool selected = false; 0471 while (i < 4 && !selected) 0472 { 0473 selected = m_buttons[i] -> selected(); 0474 if (!selected) i++; 0475 } 0476 0477 if (selected) 0478 { 0479 if (i == button) 0480 { 0481 m_buttons[button] -> setSelected(false); 0482 update(); 0483 } 0484 } 0485 else 0486 { 0487 m_buttons[button] -> setSelected(true); 0488 update(); 0489 } 0490 } 0491 0492 bool blinken::insideGreen(const QPointF &p) const 0493 { 0494 // nonButtonRibbon is used so that the buttons are not clickable in the gray space that is in between the buttons 0495 return insideButtonsArea(p) && 0496 p.x() > (double)width()/nonButtonRibbonX && 0497 p.y() > (double)height()/nonButtonRibbonY; 0498 } 0499 0500 bool blinken::insideBlue(const QPointF &p) const 0501 { 0502 return insideButtonsArea(p) && 0503 p.x() < -(double)width()/nonButtonRibbonX && 0504 p.y() > (double)height()/nonButtonRibbonY; 0505 } 0506 0507 bool blinken::insideYellow(const QPointF &p) const 0508 { 0509 return insideButtonsArea(p) && 0510 p.x() < -(double)width()/nonButtonRibbonX && 0511 p.y() < -(double)height()/nonButtonRibbonY; 0512 } 0513 0514 bool blinken::insideRed(const QPointF &p) const 0515 { 0516 return insideButtonsArea(p) && 0517 p.x() > (double)width()/nonButtonRibbonX && 0518 p.y() < -(double)height()/nonButtonRibbonY; 0519 } 0520 0521 bool blinken::insideButtonsArea(const QPointF &p) const 0522 { 0523 double x, y, x2, y2; 0524 x = p.x(); 0525 y = p.y(); 0526 x2 = x * x; 0527 y2 = y * y; 0528 double x3, y3; 0529 double smallaxis1 = (double)width() / ellipseSmallAxisX; 0530 double smallaxis2 = (double)height() / ellipseSmallAxisY; 0531 x3 = x2 / (smallaxis1 * smallaxis1); 0532 y3 = y2 / (smallaxis2 * smallaxis2); 0533 if (x3 + y3 > 1) 0534 { 0535 // Outside the inner ellipse 0536 double x4, y4; 0537 double bigaxis1 = (double)width() / ellipseBigAxisX; 0538 double bigaxis2 = (double)height() / ellipseBigAxisY; 0539 x4 = x2 / (bigaxis1 * bigaxis1); 0540 y4 = y2 / (bigaxis2 * bigaxis2); 0541 if (x4 + y4 < 1) return true; 0542 } 0543 return false; 0544 } 0545 0546 void blinken::drawMenuQuit(QPainter &p) 0547 { 0548 double xScaleSquareButtons = 90.0 / 814.062; 0549 double yScaleSquareButtons = 90.0 / 696.5; 0550 0551 // Highscore button 0552 p.resetTransform(); 0553 p.translate( (double)width() / 50.875, (double)height() / 30); 0554 p.scale(xScaleSquareButtons, yScaleSquareButtons); 0555 if (m_overHighscore) 0556 { 0557 m_renderer->render(&p, QStringLiteral("highscore_hover")); 0558 } 0559 else 0560 { 0561 m_renderer->render(&p, QStringLiteral("highscore_normal")); 0562 } 0563 m_highscoreRect = QRect(qRound((double)width() / 50.875), 0564 qRound((double)height() / 30.0), 0565 qRound((double)width() * xScaleSquareButtons), 0566 qRound((double)height() * yScaleSquareButtons)); 0567 0568 // Quit button 0569 p.resetTransform(); 0570 p.translate( (double)width() / 1.15, (double)height() / 30.0); 0571 p.scale(xScaleSquareButtons, yScaleSquareButtons); 0572 if (m_overQuit) 0573 { 0574 m_renderer->render(&p, QStringLiteral("quit_hover")); 0575 } 0576 else 0577 { 0578 m_renderer->render(&p, QStringLiteral("quit_normal")); 0579 } 0580 m_quitRect = QRect(qRound((double)width() / 1.15), 0581 qRound((double)height() / 30.0), 0582 qRound((double)width() * xScaleSquareButtons), 0583 qRound((double)height() * yScaleSquareButtons)); 0584 0585 // Help button 0586 p.resetTransform(); 0587 if (m_overMenu) 0588 { 0589 double xScaleHoverHelpButton = 225.0 / 814.062; 0590 double yScaleHoverHelpButton = 225.0 / 696.5; 0591 p.translate( (double)width() / 1.42, (double)height() / 1.56 ); 0592 p.scale(xScaleHoverHelpButton, yScaleHoverHelpButton); 0593 m_renderer->render(&p, QStringLiteral("help_hover")); 0594 0595 p.resetTransform(); 0596 double xScaleArrowButton1 = 40.0 / 814.062; 0597 double yScaleArrowButton1 = 27.5 / 696.5; 0598 0599 double xScaleArrowButton2 = 27.5 / 814.062; 0600 double yScaleArrowButton2 = 40.0 / 696.5; 0601 if (m_overAboutKDE) 0602 { 0603 p.translate((double)width() / 1.3877, (double)height() / 1.23); 0604 p.scale(xScaleArrowButton1, yScaleArrowButton1); 0605 m_renderer->render(&p, QStringLiteral("arrow_down")); 0606 } 0607 else if (m_overAboutBlinken) 0608 { 0609 p.translate((double)width() / 1.2445, (double)height() / 1.23); 0610 p.scale(xScaleArrowButton1, yScaleArrowButton1); 0611 m_renderer->render(&p, QStringLiteral("arrow_down")); 0612 } 0613 else if (m_overSettings) 0614 { 0615 p.translate((double)width() / 1.174, (double)height() / 1.345); 0616 p.scale(xScaleArrowButton2, yScaleArrowButton2); 0617 m_renderer->render(&p, QStringLiteral("arrow_right")); 0618 } 0619 else if (m_overManual) 0620 { 0621 p.translate((double)width() / 1.174, (double)height() / 1.5); 0622 p.scale(xScaleArrowButton2, yScaleArrowButton2); 0623 m_renderer->render(&p, QStringLiteral("arrow_right")); 0624 } 0625 } 0626 else 0627 { 0628 p.translate( (double)width() / 1.15, (double)height() / 1.2 ); 0629 p.scale(xScaleSquareButtons, yScaleSquareButtons); 0630 m_renderer->render(&p, QStringLiteral("help_normal")); 0631 } 0632 m_menuRect = QRect(qRound((double)width() / 1.15), 0633 qRound((double)height() / 1.2), 0634 qRound((double)width() * xScaleSquareButtons), 0635 qRound((double)height() * yScaleSquareButtons)); 0636 m_aboutBlinkenRect = QRect(QPoint(qRound((double)width() / 1.271), qRound((double)height() / 1.153)), 0637 QPoint(m_menuRect.left(), m_menuRect.bottom())); 0638 m_settingsRect = QRect(QPoint(qRound((double)width() / 1.1146), qRound((double)height() / 1.3667)), 0639 QPoint(m_menuRect.right(), m_menuRect.top())); 0640 m_manualRect = QRect(QPoint(qRound((double)width() / 1.1146), qRound((double)height() / 1.55)), 0641 QPoint(m_menuRect.right(), m_settingsRect.top())); 0642 m_aboutKDERect = QRect(QPoint(qRound((double)width() / 1.421), qRound((double)height() / 1.153)), 0643 QPoint(m_aboutBlinkenRect.left(), m_aboutBlinkenRect.bottom())); 0644 } 0645 0646 void blinken::drawScoreAndCounter(QPainter &p) 0647 { 0648 QColor c1, c2, c3; 0649 p.translate(268, 110); 0650 0651 switch (m_game.phase()) 0652 { 0653 case blinkenGame::waiting3: 0654 c1 = Qt::red; 0655 c2 = Qt::red; 0656 c3 = Qt::red; 0657 break; 0658 0659 case blinkenGame::waiting2: 0660 c1 = m_countDownColor; 0661 c2 = Qt::red; 0662 c3 = Qt::red; 0663 break; 0664 0665 case blinkenGame::waiting1: 0666 c1 = m_countDownColor; 0667 c2 = c1; 0668 c3 = Qt::red; 0669 break; 0670 0671 default: 0672 c1 = m_countDownColor; 0673 c2 = c1; 0674 c3 = c1; 0675 break; 0676 } 0677 0678 counter::paint(p, m_game.phase() != blinkenGame::starting, m_game.score(), true, c1, c2, c3, m_renderer); 0679 0680 p.translate(-268, -110); 0681 } 0682 0683 void blinken::drawStatusText(QPainter &p) 0684 { 0685 p.translate(25, 505); 0686 p.rotate(-3.29); 0687 p.setPen(Qt::blue); 0688 0689 QString restartText = i18n("Restart the game"); 0690 QString text; 0691 if (m_overQuit) text = i18n("Quit Blinken"); 0692 else if (m_overHighscore || m_overCounter) text = i18n("View Highscore Table"); 0693 else if (m_overAboutBlinken || m_overCentralLetters) text = m_helpMenu->action( KHelpMenu::menuAboutApp )->text().remove(QLatin1Char('&')); 0694 else if (m_overAboutKDE) text = m_helpMenu->action( KHelpMenu::menuAboutKDE )->text().remove(QLatin1Char('&')); 0695 else if (m_overSettings) 0696 { 0697 if (!m_showPreferences) text = i18n("Show Settings"); 0698 else text = i18n("Hide Settings"); 0699 } 0700 else if (m_overManual) text = m_helpMenu->action( KHelpMenu::menuHelpContents )->text().remove(QLatin1Char('&')); 0701 else if (m_overLevels[0]) text = i18n("2nd Level"); 0702 else if (m_overLevels[1]) text = i18n("1st Level"); 0703 else if (m_overLevels[2]) text = i18n("Random Level"); 0704 else if (m_buttons[0]->selected() || m_buttons[1]->selected() || m_buttons[2]->selected() || m_buttons[3]->selected()) text = i18n("Press the key for this button"); 0705 else if (m_showPreferences) text = i18n("Click any button to change its key"); 0706 else 0707 { 0708 switch (m_game.phase()) 0709 { 0710 case blinkenGame::starting: 0711 text = i18n("Press Start to begin"); 0712 break; 0713 0714 case blinkenGame::choosingLevel: 0715 text = i18n("Set the Difficulty Level..."); 0716 break; 0717 0718 case blinkenGame::waiting3: 0719 if (m_overCentralText) 0720 { 0721 text = restartText; 0722 } 0723 else 0724 { 0725 text = i18n("Next sequence in 3..."); 0726 } 0727 break; 0728 0729 case blinkenGame::waiting2: 0730 if (m_overCentralText) 0731 { 0732 text = restartText; 0733 } 0734 else 0735 { 0736 if (m_game.level() == 1) 0737 { 0738 text = i18n("Next sequence in 3, 2..."); 0739 } 0740 else 0741 { 0742 text = i18n("Next sequence in 2..."); 0743 } 0744 } 0745 break; 0746 0747 case blinkenGame::waiting1: 0748 if (m_overCentralText) 0749 { 0750 text = restartText; 0751 } 0752 else 0753 { 0754 if (m_game.level() == 1) 0755 { 0756 text = i18n("Next sequence in 3, 2, 1..."); 0757 } 0758 else 0759 { 0760 text = i18n("Next sequence in 2, 1..."); 0761 } 0762 } 0763 break; 0764 0765 case blinkenGame::learningTheSequence: 0766 if (m_overCentralText) 0767 { 0768 text = restartText; 0769 } 0770 else 0771 { 0772 text = i18n("Remember this sequence..."); 0773 } 0774 break; 0775 0776 case blinkenGame::typingTheSequence: 0777 if (m_overCentralText) 0778 { 0779 text = restartText; 0780 } 0781 else 0782 { 0783 text = i18n("Repeat the sequence"); 0784 } 0785 break; 0786 } 0787 } 0788 0789 QFont f; 0790 if (blinkenSettings::customFont() && !m_alwaysUseNonCoolFont) f = QFont(QStringLiteral("Steve")); 0791 p.setFont(f); 0792 f.setPointSize(KFontUtils::adaptFontSize(p, text, 380, 30, 28, 1, KFontUtils::DoNotAllowWordWrap)); 0793 p.setFont(f); 0794 p.drawText(0, 0, text); 0795 } 0796 0797 void blinken::drawLevel(QPainter &p) 0798 { 0799 QString n[3]; 0800 n[0] = i18n("2"); 0801 n[1] = i18n("1"); 0802 n[2] = i18n("?"); 0803 0804 double posX = (double)width() / 2.0; 0805 double posY = (double)height() / 1.868; 0806 drawText(p, i18nc("@label:chooser which level is currently being played", "Level"), QPointF(posX, posY), false, 0, 0, nullptr, false, true); 0807 0808 QPointF cp; 0809 for (int i = 0; i < 3; i++) 0810 { 0811 double posX2 = (double)width() / 2.019; 0812 double posY2 = (double)height() / 1.677; 0813 double xMargin = (double)width() / 32.2; 0814 double yMargin = (double)height() / 105.0; 0815 if (i == 0) cp = QPointF(posX2, posY2); 0816 else if (i == 1) cp = QPointF(m_levelsRect[0].left() - m_levelsRect[0].width(), posY2); 0817 else if (i == 2) cp = QPointF(m_levelsRect[0].right() + m_levelsRect[0].width(), posY2); 0818 drawText(p, n[i], cp, true, xMargin, yMargin, &(m_levelsRect[i]), m_overLevels[i], true); 0819 } 0820 } 0821 0822 void blinken::drawText(QPainter &p, const QString &text, const QPointF ¢er, bool withMargin, double xMargin, double yMargin, QRectF *rect, bool highlight, bool bold) 0823 { 0824 QRectF r; 0825 QFont oldFont, f = p.font(); 0826 oldFont = f; 0827 double aux1 = (double)width() / 3.389; 0828 double aux2 = (double)height() / 17.5; 0829 f.setPointSize(KFontUtils::adaptFontSize(p, text, qRound(aux1), qRound(aux2), 28, 1, KFontUtils::DoNotAllowWordWrap)); 0830 if (bold) f.setBold(true); 0831 p.setFont(f); 0832 0833 r = p.boundingRect(QRectF(), Qt::AlignLeft, text); 0834 r = QRectF(0, 0, r.width() + xMargin, r.height() + yMargin); 0835 r.translate(center.x() - r.width() / 2, center.y() - r.height() / 2); 0836 0837 if (withMargin) 0838 { 0839 p.fillRect(r, m_fillColor); 0840 p.setPen(QPen(Qt::black, 3)); 0841 p.drawRoundedRect(r, 15, 15, Qt::RelativeSize); 0842 } 0843 0844 if (highlight) 0845 { 0846 p.setPen(m_fontHighlightColor); 0847 } 0848 else 0849 { 0850 p.setPen(m_fontColor); 0851 } 0852 p.drawText(r, Qt::AlignCenter, text); 0853 0854 if (rect) *rect = p.worldTransform().mapRect(r); 0855 0856 p.setFont(oldFont); 0857 } 0858 0859 0860 void blinken::updateButtonHighlighting(const QPoint &p) 0861 { 0862 bool haveToUpdate; 0863 m_updateButtonHighlighting = false; 0864 haveToUpdate = false; 0865 0866 if (m_highscoreRect.contains(p)) 0867 { 0868 if (!m_overHighscore) 0869 { 0870 m_overHighscore = true; 0871 haveToUpdate = true; 0872 } 0873 } 0874 else if (m_overHighscore) 0875 { 0876 m_overHighscore = false; 0877 haveToUpdate = true; 0878 } 0879 0880 if (m_menuRect.contains(p)) 0881 { 0882 if (!m_overMenu) 0883 { 0884 m_overMenu = true; 0885 m_overAboutKDE = false; 0886 m_overAboutBlinken = false; 0887 m_overSettings = false; 0888 m_overManual = false; 0889 haveToUpdate = true; 0890 } 0891 else if (m_overAboutKDE || m_overAboutBlinken || m_overManual || m_overSettings) 0892 { 0893 m_overAboutKDE = false; 0894 m_overAboutBlinken = false; 0895 m_overSettings = false; 0896 m_overManual = false; 0897 haveToUpdate = true; 0898 } 0899 } 0900 else if (m_overMenu) 0901 { 0902 if (m_aboutKDERect.contains(p)) 0903 { 0904 if (!m_overAboutKDE) 0905 { 0906 m_overAboutKDE = true; 0907 m_overAboutBlinken = false; 0908 m_overSettings = false; 0909 m_overManual = false; 0910 haveToUpdate = true; 0911 } 0912 } 0913 else if (m_aboutBlinkenRect.contains(p)) 0914 { 0915 if (!m_overAboutBlinken) 0916 { 0917 m_overAboutKDE = false; 0918 m_overAboutBlinken = true; 0919 m_overSettings = false; 0920 m_overManual = false; 0921 haveToUpdate = true; 0922 } 0923 } 0924 else if (m_manualRect.contains(p)) 0925 { 0926 if (!m_overManual) 0927 { 0928 m_overAboutKDE = false; 0929 m_overAboutBlinken = false; 0930 m_overSettings = false; 0931 m_overManual = true; 0932 haveToUpdate = true; 0933 } 0934 } 0935 else if (m_settingsRect.contains(p)) 0936 { 0937 if (!m_overSettings) 0938 { 0939 m_overAboutKDE = false; 0940 m_overAboutBlinken = false; 0941 m_overSettings = true; 0942 m_overManual = false; 0943 haveToUpdate = true; 0944 } 0945 } 0946 else 0947 { 0948 m_overMenu = false; 0949 m_overAboutKDE = false; 0950 m_overAboutBlinken = false; 0951 m_overSettings = false; 0952 m_overManual = false; 0953 haveToUpdate = true; 0954 } 0955 } 0956 0957 if (!m_showPreferences && m_centralLettersRect.contains(p)) 0958 { 0959 m_overCentralLetters = true; 0960 haveToUpdate = true; 0961 } 0962 else if (m_overCentralLetters) 0963 { 0964 m_overCentralLetters = false; 0965 haveToUpdate = true; 0966 } 0967 0968 if (m_showPreferences && m_soundRect.contains(p)) 0969 { 0970 m_overSound = true; 0971 haveToUpdate = true; 0972 } 0973 else if (m_overSound) 0974 { 0975 m_overSound = false; 0976 haveToUpdate = true; 0977 } 0978 0979 if (m_showPreferences && m_fontRect.contains(p) && !m_alwaysUseNonCoolFont) 0980 { 0981 m_overFont = true; 0982 haveToUpdate = true; 0983 } 0984 else if (m_overFont) 0985 { 0986 m_overFont = false; 0987 haveToUpdate = true; 0988 } 0989 0990 if (m_counterRect.contains(p)) 0991 { 0992 m_overCounter = true; 0993 haveToUpdate = true; 0994 } 0995 else if (m_overCounter) 0996 { 0997 m_overCounter = false; 0998 haveToUpdate = true; 0999 } 1000 1001 if (m_quitRect.contains(p)) 1002 { 1003 if (!m_overQuit) 1004 { 1005 m_overQuit = true; 1006 haveToUpdate = true; 1007 } 1008 } 1009 else if (m_overQuit) 1010 { 1011 m_overQuit = false; 1012 haveToUpdate = true; 1013 } 1014 1015 switch (m_game.phase()) 1016 { 1017 case blinkenGame::starting: 1018 case blinkenGame::waiting3: 1019 case blinkenGame::waiting2: 1020 case blinkenGame::waiting1: 1021 case blinkenGame::learningTheSequence: 1022 case blinkenGame::typingTheSequence: 1023 if (m_centralTextRect.contains(p)) 1024 { 1025 if (!m_overCentralText) 1026 { 1027 m_overCentralText = true; 1028 haveToUpdate = true; 1029 } 1030 } 1031 else if (m_overCentralText) 1032 { 1033 m_overCentralText = false; 1034 haveToUpdate = true; 1035 } 1036 break; 1037 1038 case blinkenGame::choosingLevel: 1039 for (int i = 0; i < 3; i++) 1040 { 1041 if (m_levelsRect[i].contains(p)) 1042 { 1043 if (!m_overLevels[i]) 1044 { 1045 m_overLevels[i] = true; 1046 haveToUpdate = true; 1047 } 1048 } 1049 else if (m_overLevels[i]) 1050 { 1051 m_overLevels[i] = false; 1052 haveToUpdate = true; 1053 } 1054 } 1055 break; 1056 } 1057 1058 updateCursor(p); 1059 if (haveToUpdate) update(); 1060 } 1061 1062 void blinken::updateCursor(const QPoint &p) 1063 { 1064 QPointF p2 = p - QPointF((double)width() / centerX, (double)height() / centerY); 1065 1066 if (m_overHighscore || m_overQuit || m_overCentralText || m_overMenu || m_overAboutKDE || m_overAboutBlinken || m_overManual || m_overSettings || m_overLevels[0] || m_overLevels[1] || m_overLevels[2] || m_overCentralLetters || m_overCounter || (m_game.canType() && (insideGreen(p2) || insideRed(p2) || insideBlue(p2) || insideYellow(p2))) || m_overFont || m_overSound) setCursor(Qt::PointingHandCursor); 1067 else setCursor(Qt::ArrowCursor); 1068 } 1069 1070 QPixmap blinken::getPixmap(const QString &element, const QSize &imageSize) 1071 { 1072 QMap<QString, QPixmap>::Iterator it = m_pixmapCache.find(element); 1073 if (it == m_pixmapCache.end()) 1074 { 1075 QPixmap pix(imageSize); 1076 pix.fill(Qt::transparent); 1077 QPainter p(&pix); 1078 m_renderer->render(&p, element); 1079 it = m_pixmapCache.insert(element, pix); 1080 } 1081 return it.value(); 1082 } 1083