File indexing completed on 2024-04-14 03:39:24

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 &center, 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 
1084 #include "moc_blinken.cpp"