Warning, file /games/kfourinline/src/displayintro.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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 "displayintro.h"
0009 
0010 // own
0011 #include "buttonsprite.h"
0012 #include "introsprite.h"
0013 #include "kfontutils.h"
0014 #include "kfourinline_debug.h"
0015 #include "pixmapsprite.h"
0016 #include "prefs.h"
0017 // KF
0018 #include <KLocalizedString>
0019 // Qt
0020 #include <QColor>
0021 #include <QElapsedTimer>
0022 #include <QFont>
0023 #include <QGraphicsView>
0024 #include <QMouseEvent>
0025 #include <QPixmap>
0026 #include <QPoint>
0027 #include <QStringList>
0028 #include <QTextDocument>
0029 // Std
0030 #include <cmath>
0031 
0032 // Constructor for the intro display
0033 DisplayIntro::DisplayIntro(QGraphicsScene *scene, ThemeManager *theme, QGraphicsView *parent)
0034     : Themeable(QStringLiteral("introdisplay"), theme)
0035     , QObject(parent)
0036 {
0037     // Choose a background color
0038     scene->setBackgroundBrush(QColor(0, 0, 128));
0039 
0040     // Store the theme manager and other attributes
0041     mLastMoveEvent = nullptr;
0042     mTheme = theme;
0043     mScene = scene;
0044     mView = parent;
0045 
0046     // Storage of all sprites
0047     mSprites.clear();
0048 
0049     // Create all sprites used for intro
0050     for (int i = 0; i < 42; i++) {
0051         IntroSprite *sprite = new IntroSprite(QStringLiteral("intro_piece"), mTheme, i, mScene);
0052         mSprites.append(sprite);
0053         if ((i / 1) % 2 == 0)
0054             sprite->setFrame(0);
0055         else
0056             sprite->setFrame(1);
0057         sprite->setZValue(i);
0058         sprite->hide();
0059     }
0060 
0061     // Create board
0062     PixmapSprite *pixmap = new PixmapSprite(QStringLiteral("introboard"), mTheme, 0, mScene);
0063     mSprites.append(pixmap);
0064     pixmap->show();
0065 
0066     // Create quicklaunch. We align text horizontally using QTextDocument
0067     mQuickLaunch = new PixmapSprite(QStringLiteral("quicklaunch"), mTheme, 0, mScene);
0068     mSprites.append(mQuickLaunch);
0069     mQuickLaunch->show();
0070     mTextQuicklaunch = new QGraphicsTextItem(mQuickLaunch);
0071     scene->addItem(mTextQuicklaunch);
0072     mTextQuicklaunch->setPlainText(i18nc("Name of quicklaunch field", "Quick Launch"));
0073     QTextDocument *text_document = mTextQuicklaunch->document();
0074     text_document->setDefaultTextOption(QTextOption(Qt::AlignHCenter));
0075     mTextQuicklaunch->setDocument(text_document);
0076     mTextQuicklaunch->show();
0077     mTextStartplayer = new QGraphicsTextItem(mQuickLaunch);
0078     scene->addItem(mTextStartplayer);
0079     mTextStartplayer->setPlainText(i18nc("Ask player who should start game", "Who starts?"));
0080     mTextStartplayer->show();
0081     mTextColor = new QGraphicsTextItem(mQuickLaunch);
0082     scene->addItem(mTextColor);
0083     mTextColor->setPlainText(i18nc("Ask player which color he wants to play", "Your color?"));
0084     mTextColor->show();
0085 
0086     // Static decoration
0087     KConfigGroup config = thememanager()->config(id());
0088     QStringList deco = config.readEntry("decoration", QStringList());
0089     for (int i = 0; i < deco.size(); i++) {
0090         PixmapSprite *sprite = new PixmapSprite(deco.at(i), mTheme, i, mScene);
0091         mSprites.append(sprite);
0092         sprite->show();
0093     }
0094 
0095     // Color buttons
0096     mStartButton[0] = new ButtonSprite(false, QStringLiteral("button0_start"), mTheme, 0, mScene);
0097     mSprites.append(mStartButton[0]);
0098     mStartButton[0]->show();
0099     connect(mStartButton[0]->notify(), &SpriteNotify::signalNotify, this, &DisplayIntro::buttonPressed);
0100     if (Prefs::startcolouryellow())
0101         mStartButton[0]->setStatus(true);
0102 
0103     mStartButton[1] = new ButtonSprite(false, QStringLiteral("button1_start"), mTheme, 1, mScene);
0104     mSprites.append(mStartButton[1]);
0105     mStartButton[1]->show();
0106     connect(mStartButton[1]->notify(), &SpriteNotify::signalNotify, this, &DisplayIntro::buttonPressed);
0107     if (Prefs::startcolourred())
0108         mStartButton[1]->setStatus(true);
0109 
0110     mPlayerButton[0] = new ButtonSprite(false, QStringLiteral("button0_color"), mTheme, 2, mScene);
0111     mSprites.append(mPlayerButton[0]);
0112     mPlayerButton[0]->show();
0113     connect(mPlayerButton[0]->notify(), &SpriteNotify::signalNotify, this, &DisplayIntro::buttonPressed);
0114     if (Prefs::input0mouse() || Prefs::input0key())
0115         mPlayerButton[0]->setStatus(true);
0116 
0117     mPlayerButton[1] = new ButtonSprite(false, QStringLiteral("button1_color"), mTheme, 3, mScene);
0118     mSprites.append(mPlayerButton[1]);
0119     mPlayerButton[1]->show();
0120     connect(mPlayerButton[1]->notify(), &SpriteNotify::signalNotify, this, &DisplayIntro::buttonPressed);
0121     if ((Prefs::input1mouse() || Prefs::input1key()) && !mPlayerButton[0]->status())
0122         mPlayerButton[0]->setStatus(true);
0123 
0124     // Start game buttons
0125     ButtonSprite *button = new ButtonSprite(true, QStringLiteral("button_aieasy"), mTheme, 10, mScene);
0126     mSprites.append(button);
0127     button->setText(i18nc("quick start button - player versus AI level easy", "Easy Game"));
0128     button->show();
0129     connect(button->notify(), &SpriteNotify::signalNotify, this, &DisplayIntro::buttonPressed);
0130 
0131     button = new ButtonSprite(true, QStringLiteral("button_ainormal"), mTheme, 11, mScene);
0132     mSprites.append(button);
0133     button->setText(i18nc("quick start button - player versus AI level normal", "Normal Game"));
0134     button->show();
0135     connect(button->notify(), &SpriteNotify::signalNotify, this, &DisplayIntro::buttonPressed);
0136 
0137     button = new ButtonSprite(true, QStringLiteral("button_aihard"), mTheme, 12, mScene);
0138     mSprites.append(button);
0139     button->setText(i18nc("quick start button - player versus AI level hard", "Hard Game"));
0140     button->show();
0141     connect(button->notify(), &SpriteNotify::signalNotify, this, &DisplayIntro::buttonPressed);
0142 
0143     button = new ButtonSprite(true, QStringLiteral("button_player"), mTheme, 13, mScene);
0144     mSprites.append(button);
0145     button->setText(i18nc("quick start button - player versus player", "Two Player Game"));
0146     button->show();
0147     connect(button->notify(), &SpriteNotify::signalNotify, this, &DisplayIntro::buttonPressed);
0148 
0149     // Animation timer
0150     mTimer = new QTimer(this);
0151     connect(mTimer, &QTimer::timeout, this, &DisplayIntro::advance);
0152 
0153     // Redraw
0154     if (theme)
0155         theme->updateTheme(this);
0156     qCDebug(KFOURINLINE_LOG) << "CONSTRUCTOR DONE";
0157 }
0158 
0159 // One of the graphical sprite buttons was pressed. Item and its id are delivered
0160 void DisplayIntro::buttonPressed(QGraphicsItem *item, int id)
0161 {
0162     int status = id >> 8;
0163     int no = id & 0xff;
0164     // qCDebug(KFOURINLINE_LOG) << "Button" << no  << "pressed status="<<status;
0165     ButtonSprite *button = dynamic_cast<ButtonSprite *>(item);
0166     Q_ASSERT(button);
0167     if (button == mStartButton[0]) {
0168         mStartButton[1]->setStatus(!button->status());
0169         Prefs::setStartcolouryellow(button->status());
0170         Prefs::setStartcolourred(!button->status());
0171     }
0172     if (button == mStartButton[1]) {
0173         mStartButton[0]->setStatus(!button->status());
0174         Prefs::setStartcolouryellow(!button->status());
0175         Prefs::setStartcolourred(button->status());
0176     }
0177     if (button == mPlayerButton[0]) {
0178         mPlayerButton[1]->setStatus(!button->status());
0179         Prefs::setStartcolouryellow(button->status());
0180         Prefs::setStartcolourred(!button->status());
0181     }
0182     if (button == mPlayerButton[1]) {
0183         mPlayerButton[0]->setStatus(!button->status());
0184         Prefs::setStartcolouryellow(!button->status());
0185         Prefs::setStartcolourred(button->status());
0186     }
0187 
0188     // Start game from button
0189     if (no >= 10 && no <= 13 && status == 1) {
0190         // Emit quick start with status (start player color, player color, AI level, two player?
0191 
0192         // Color
0193         COLOUR startPlayer;
0194         if (mStartButton[0]->status())
0195             startPlayer = Yellow;
0196         else
0197             startPlayer = Red;
0198 
0199         // Inputs
0200         KGameIO::IOMode input0 = KGameIO::ProcessIO;
0201         KGameIO::IOMode input1 = KGameIO::ProcessIO;
0202         if (mPlayerButton[0]->status())
0203             input0 = KGameIO::MouseIO;
0204         if (mPlayerButton[1]->status())
0205             input1 = KGameIO::MouseIO;
0206 
0207         // Level
0208         int level = -1;
0209         if (no == 10)
0210             level = 2;
0211         else if (no == 11)
0212             level = 4;
0213         else if (no == 12)
0214             level = 6;
0215         if (no == 13) {
0216             input0 = KGameIO::MouseIO;
0217             input1 = KGameIO::MouseIO;
0218         }
0219 
0220         // Emit signal
0221         Q_EMIT signalQuickStart(startPlayer, input0, input1, level);
0222     }
0223 }
0224 
0225 // Desctruct the intro and all sprites
0226 DisplayIntro::~DisplayIntro()
0227 {
0228     delete mTimer;
0229     qDeleteAll(mSprites);
0230 }
0231 
0232 // Master theme change function. Redraw the display
0233 void DisplayIntro::changeTheme()
0234 {
0235     qCDebug(KFOURINLINE_LOG) << "THEME CHANGE " << thememanager()->themefileChanged();
0236     // Measure time for resize
0237     QElapsedTimer time;
0238     time.restart();
0239 
0240     // Retrieve theme data
0241     KConfigGroup config = thememanager()->config(id());
0242 
0243     // Retrieve background pixmap
0244     QString bgsvgid = config.readEntry("background-svgid");
0245     QPixmap pixmap = thememanager()->getPixmap(bgsvgid, mScene->sceneRect().size().toSize());
0246     mScene->setBackgroundBrush(pixmap);
0247     mView->update();
0248 
0249     // Process quicklaunch sprite (could be own class...)
0250     double width = mQuickLaunch->boundingRect().width();
0251     double height = mQuickLaunch->boundingRect().height();
0252     // Retrieve theme data
0253     config = thememanager()->config(mQuickLaunch->id());
0254     QPointF posQuickstart = config.readEntry("posQuickstart", QPointF(1.0, 1.0));
0255     QPointF posStartplayer = config.readEntry("posStartplayer", QPointF(1.0, 1.0));
0256     QPointF posColor = config.readEntry("posColor", QPointF(1.0, 1.0));
0257 
0258     // HEADER
0259     // Calculate proper font size
0260     double fontHeight = config.readEntry("fontHeightHeader", 1.0);
0261     fontHeight *= height;
0262     double textHeight = config.readEntry("textHeightHeader", 1.0);
0263     textHeight *= height;
0264     double textWidth = config.readEntry("textWidthHeader", 1.0);
0265     textWidth *= width;
0266 
0267     // Retrieve font color
0268     QColor fontColor;
0269     fontColor = config.readEntry("fontColorHeader", QColor(Qt::white));
0270 
0271     // Create and set current font
0272     QFont font;
0273     fontHeight = KFontUtils::adaptFontSize(mTextQuicklaunch, textWidth, textHeight, fontHeight, 8.0);
0274     font.setPointSizeF(fontHeight);
0275 
0276     // Set font and color for all text items
0277     mTextQuicklaunch->setFont(font);
0278     mTextQuicklaunch->setDefaultTextColor(fontColor);
0279     mTextQuicklaunch->setTextWidth(textWidth);
0280 
0281     // Set position of sub sprites, we centered horizontally at creation time,
0282     // now we center it vertically
0283     QRectF bounding = mTextQuicklaunch->boundingRect();
0284     mTextQuicklaunch->setPos(posQuickstart.x() * width, posQuickstart.y() * height + (textHeight - bounding.height()) / 2);
0285 
0286     // TEXT
0287     // Calculate proper font size
0288     fontHeight = config.readEntry("fontHeight", 1.0);
0289     fontHeight *= height;
0290     textHeight = config.readEntry("textHeight", 1.0);
0291     textHeight *= height;
0292     textWidth = config.readEntry("textWidth", 1.0);
0293     textWidth *= width;
0294 
0295     // Retrieve font color
0296     fontColor = config.readEntry("fontColor", QColor(Qt::white));
0297 
0298     // Create and set current font
0299     // Calculate proper font point size to not wrap translations.
0300     double newFontHeight0 = KFontUtils::adaptFontSize(mTextStartplayer, textWidth, textHeight, fontHeight, 8.0);
0301     double newFontHeight1 = KFontUtils::adaptFontSize(mTextColor, textWidth, textHeight, fontHeight, 8.0);
0302     font.setPointSizeF(qMin(newFontHeight0, newFontHeight1));
0303 
0304     // Set font and color for all text items
0305     mTextStartplayer->setFont(font);
0306     mTextStartplayer->setDefaultTextColor(fontColor);
0307     mTextStartplayer->setTextWidth(textWidth);
0308 
0309     mTextColor->setFont(font);
0310     mTextColor->setDefaultTextColor(fontColor);
0311     mTextColor->setTextWidth(textWidth);
0312 
0313     // Set position of sub sprites, we centered horizontally at creation time,
0314     // now we center it vertically
0315     bounding = mTextStartplayer->boundingRect();
0316     mTextStartplayer->setPos(posStartplayer.x() * width, posStartplayer.y() * height + (textHeight - bounding.height()) / 2);
0317     bounding = mTextColor->boundingRect();
0318     mTextColor->setPos(posColor.x() * width, posColor.y() * height + (textHeight - bounding.height()) / 2);
0319 
0320     int elapsed = time.elapsed();
0321     qCDebug(KFOURINLINE_LOG) << "THEME CHANGE took " << elapsed << " ms";
0322 
0323     // Renew animation on theme change?
0324     if (thememanager()->themefileChanged()) {
0325         start(0);
0326     } else {
0327         delaySprites(elapsed);
0328     }
0329 }
0330 
0331 // Start the animation
0332 void DisplayIntro::start(int delay)
0333 {
0334     qCDebug(KFOURINLINE_LOG) << "START TIMER";
0335     // Do the timer
0336     mTimer->stop();
0337     mTimer->setSingleShot(true);
0338     mTimer->start(delay);
0339 }
0340 
0341 // Delay all sprite animation by the given time
0342 void DisplayIntro::delaySprites(int duration)
0343 {
0344     // Setup sprites
0345     for (int i = 0; i < mSprites.size(); ++i) {
0346         // Use only intro sprites
0347         if (mSprites.at(i)->type() != QGraphicsItem::UserType + 1)
0348             continue;
0349 
0350         IntroSprite *sprite = (IntroSprite *)mSprites.at(i);
0351         sprite->delayAnimation(duration);
0352     }
0353 }
0354 
0355 // Animation main routine to advance the animation. Called
0356 // by a timer
0357 void DisplayIntro::advance()
0358 {
0359     QElapsedTimer time;
0360     time.restart();
0361     int duration = createAnimation(true);
0362 
0363     qCDebug(KFOURINLINE_LOG) << "ADVANCE: Restarting timer in " << (duration + 5000) << " creation time " << time.elapsed();
0364     mTimer->start(duration + 5000); // [ms]
0365 }
0366 
0367 // Animation main routine to advance the animation. Called
0368 // by a timer
0369 int DisplayIntro::createAnimation(bool restartTime)
0370 {
0371     // Columns for the moves in the intro. Results in a drawn game
0372     // Note: Once could load the last played game here or so.
0373     static int moves[] = {3, 4, 4, 3, 3, 4, 4, 1, 3, 5, 3, 3, 6, 6, 6, 6, 6, 0, 6, 4, 5, 5, 2, 2, 5, 5, 1, 4, 5, 0, 0, 1, 1, 1, 2, 2, 2, 2, 1, 0, 0, 0};
0374     // How many moves to perform (size of moves array)
0375     static int maxMoves = 42;
0376 
0377     // Config data
0378     KConfigGroup config = thememanager()->config(id());
0379     QPointF piece0_pos = config.readEntry("piece0-pos", QPointF(1.0, 1.0));
0380     QPointF piece1_pos = config.readEntry("piece1-pos", QPointF(1.0, 1.0));
0381     double piece_spread = config.readEntry("piece-spread", 0.1);
0382     QPointF board_pos = config.readEntry("board-pos", QPointF(1.0, 1.0));
0383     QPointF board_spread = config.readEntry("board-spread", QPointF(1.0, 1.0));
0384     double move_velocity = config.readEntry("move-velocity", 0.1);
0385 
0386     // Local variables
0387     double dura, delay, rad;
0388     QPointF start, end;
0389     int maxDuration = 0;
0390     int addWaitTime = 0;
0391 
0392     // ============================================================================
0393     // Setup sprites
0394     for (int i = 0; i < mSprites.size(); ++i) {
0395         // Use only intro sprites
0396         if (mSprites.at(i)->type() != QGraphicsItem::UserType + 1)
0397             continue;
0398 
0399         IntroSprite *sprite = (IntroSprite *)mSprites.at(i);
0400         int no = sprite->number();
0401         sprite->setZValue(no);
0402         sprite->hide();
0403 
0404         sprite->clearAnimation(restartTime);
0405     }
0406 
0407     // ============================================================================
0408     // First part of intro animation. Move sprites into window
0409     // Loop all sprites
0410     for (int i = 0; i < mSprites.size(); ++i) {
0411         // Move only intro sprites
0412         if (mSprites.at(i)->type() != QGraphicsItem::UserType + 1)
0413             continue;
0414         IntroSprite *sprite = (IntroSprite *)mSprites.at(i);
0415 
0416         int no = sprite->number();
0417         {
0418             if (no % 2 == 0) {
0419                 start = QPointF(1.05, 0.5);
0420                 end = QPointF(piece0_pos.x() + piece_spread * no, piece0_pos.y());
0421                 dura = 3000.0;
0422                 delay = 80.0 * no;
0423                 rad = 0.1;
0424             } else {
0425                 start = QPointF(-0.05, 0.5);
0426                 end = QPointF(piece1_pos.x() + piece_spread * (no - 1), piece1_pos.y());
0427                 dura = 3000.0;
0428                 delay = 80.0 * (no - 1);
0429                 rad = 0.1;
0430             }
0431 
0432             sprite->addPosition(start);
0433             sprite->addShow();
0434             sprite->addPause(int(delay));
0435             sprite->addLinear(start, (start + end) * 0.5, int(dura / 4.0));
0436             sprite->addCircle((start + end) * 0.5, rad, int(dura / 2.0));
0437             sprite->addLinear((start + end) * 0.5, end, int(dura / 4.0));
0438             if (sprite->animationDuration() > maxDuration)
0439                 maxDuration = sprite->animationDuration();
0440         }
0441     } // end list loop
0442     // ============================================================================
0443 
0444     // ============================================================================
0445     // Second part of intro animation. Move sprites inwards
0446     int moveCnt = 0;
0447     delay = 0.0;
0448     // Reset height
0449     int height[7];
0450     addWaitTime = maxDuration;
0451     for (int i = 0; i <= 6; i++)
0452         height[i] = 6;
0453     // Loop all sprites
0454     for (int i = mSprites.size() - 1; i >= 0; --i) {
0455         // Move only intro sprites
0456         if (mSprites.at(i)->type() != QGraphicsItem::UserType + 1)
0457             continue;
0458         IntroSprite *sprite = (IntroSprite *)mSprites.at(i);
0459 
0460         // No more moves left
0461         if (moveCnt >= maxMoves)
0462             continue;
0463         int ix = moves[moveCnt];
0464         moveCnt++;
0465 
0466         int iy = height[ix];
0467         height[ix]--;
0468         double x = board_pos.x() + ix * board_spread.x();
0469         double y = board_pos.y() + iy * board_spread.y();
0470 
0471         sprite->addWait(addWaitTime);
0472         sprite->addPause(3000);
0473         sprite->addPause(int(delay));
0474         AnimationCommand *anim = sprite->addRelativeManhatten(QPointF(x, y), move_velocity);
0475 
0476         delay += sprite->duration(anim);
0477 
0478         if (sprite->animationDuration() > maxDuration)
0479             maxDuration = sprite->animationDuration();
0480     } // end for
0481     // ============================================================================
0482 
0483     // ============================================================================
0484     // Third part of intro animation. Move sprites outwards
0485     addWaitTime = maxDuration;
0486     // Loop all sprites
0487     for (int i = 0; i < mSprites.size(); ++i) {
0488         // Move only intro sprites
0489         if (mSprites.at(i)->type() != QGraphicsItem::UserType + 1)
0490             continue;
0491         IntroSprite *sprite = (IntroSprite *)mSprites.at(i);
0492 
0493         int no = sprite->number();
0494         double xc = board_pos.x() + 3.0 * board_spread.x();
0495         double yc = board_pos.y() + 3.5 * board_spread.y();
0496 
0497         double x = xc + 1.50 * cos(no / 42.0 * 2.0 * M_PI);
0498         double y = yc + 1.50 * sin(no / 42.0 * 2.0 * M_PI);
0499 
0500         sprite->addWait(addWaitTime);
0501         sprite->addPause(8000);
0502         sprite->addRelativeLinear(QPointF(x, y), 800);
0503 
0504         if (sprite->animationDuration() > maxDuration)
0505             maxDuration = sprite->animationDuration();
0506     } // end for
0507     // ============================================================================
0508 
0509     return maxDuration;
0510 }
0511 
0512 // Find the sprite on the given position (buttons)
0513 QGraphicsItem *DisplayIntro::findSprite(QPoint pos)
0514 {
0515     QGraphicsItem *found = nullptr;
0516 
0517     for (int i = 0; i < mSprites.size(); ++i) {
0518         QGraphicsItem *item = mSprites[i];
0519         if (!item)
0520             continue;
0521         if (!item->isVisible())
0522             continue;
0523         // Map position to local
0524         QPointF p = item->mapFromScene(QPointF(pos));
0525         // Take highest zValue item
0526         if (item->contains(p) && (!found || (found->zValue() < item->zValue())))
0527             found = item;
0528     }
0529     return found;
0530 }
0531 
0532 // Handle view events and forward them to the sprites
0533 void DisplayIntro::viewEvent(QEvent *event)
0534 {
0535     // Only process some mouse events
0536     QEvent::Type type = event->type();
0537     if (type != QEvent::MouseButtonPress && type != QEvent::MouseButtonRelease && type != QEvent::MouseMove)
0538         return;
0539 
0540     // Cast items and find right sprite
0541     QMouseEvent *e = dynamic_cast<QMouseEvent *>(event);
0542     QGraphicsItem *item = findSprite(e->pos());
0543 
0544     // Which event type? Forward them to Button sprites only!
0545     switch (event->type()) {
0546     case QEvent::MouseButtonPress:
0547         if (item != nullptr && item->type() == QGraphicsItem::UserType + 100)
0548             (dynamic_cast<ButtonSprite *>(item))->mousePressEvent(e);
0549         break;
0550     case QEvent::MouseButtonRelease:
0551         if (item != nullptr && item->type() == QGraphicsItem::UserType + 100)
0552             (dynamic_cast<ButtonSprite *>(item))->mouseReleaseEvent(e);
0553         break;
0554     case QEvent::MouseMove:
0555         if (item != mLastMoveEvent) {
0556             if (mLastMoveEvent != nullptr && mLastMoveEvent->type() == QGraphicsItem::UserType + 100) {
0557                 (dynamic_cast<ButtonSprite *>(mLastMoveEvent))->hoverLeaveEvent(e);
0558             }
0559             if (item != nullptr && item->type() == QGraphicsItem::UserType + 100) {
0560                 (dynamic_cast<ButtonSprite *>(item))->hoverEnterEvent(e);
0561             }
0562             mLastMoveEvent = item;
0563         }
0564         break;
0565     default:
0566         break;
0567     }
0568     return;
0569 }
0570 
0571 #include "moc_displayintro.cpp"