File indexing completed on 2024-04-28 04:03:10

0001 /***************************************************************************
0002     File                 : board.cpp
0003     Project              : Knights
0004     Description          : Game board (scene)
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2016 Alexander Semke (alexander.semke@web.de)
0007     SPDX-FileCopyrightText: 2009-2011 Miha Čančula (miha@noughmad.eu)
0008 
0009  ***************************************************************************/
0010 
0011 /***************************************************************************
0012  *                                                                         *
0013  *  SPDX-License-Identifier: GPL-2.0-or-later
0014  *                                                                         *
0015  *  This program is distributed in the hope that it will be useful,        *
0016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0018  *  GNU General Public License for more details.                           *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program; if not, write to the Free Software           *
0022  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0023  *   Boston, MA  02110-1301  USA                                           *
0024  *                                                                         *
0025  ***************************************************************************/
0026 
0027 #include "board.h"
0028 #include "gamemanager.h"
0029 #include "settings.h"
0030 #include "core/pos.h"
0031 #include "core/move.h"
0032 #include "core/item.h"
0033 #include "rules/chessrules.h"
0034 #include "ui_promotiondialog.h"
0035 
0036 #include <KGameGraphicsViewRenderer>
0037 
0038 #include <QDialog>
0039 #include <QDialogButtonBox>
0040 #include <QDrag>
0041 #include <QGraphicsSceneMouseEvent>
0042 #include <QMimeData>
0043 #include <QPushButton>
0044 #include <QtMath>
0045 
0046 using namespace Knights;
0047 
0048 const qreal backgroundZValue = -3.0;
0049 const qreal borderZValue = -2.0;
0050 const qreal notationZValue = -1.0;
0051 const qreal tileZValue = 0.0;
0052 const qreal pieceZValue = 1.0;
0053 const qreal legalMarkerZValue = 3.0;
0054 const qreal dragZValue = 4.0;
0055 
0056 const QString backgroundKey = QStringLiteral ( "Background" );
0057 const QString whiteTileKey = QStringLiteral ( "WhiteTile" );
0058 const QString blackTileKey = QStringLiteral ( "BlackTile" );
0059 const QString legalMarkerKey = QStringLiteral ( "Marker" );
0060 const QString motionMarkerKey = QStringLiteral ( "Motion" );
0061 const QString dangerMarkerKey = QStringLiteral ( "Danger" );
0062 
0063 const QString tbBorderKey = QStringLiteral ( "TopBottomBorder" );
0064 const QString lrBorderKey = QStringLiteral ( "LeftRightBorder" );
0065 const QString whiteLettersKey = QStringLiteral ( "WhiteLetters" );
0066 const QString blackLettersKey = QStringLiteral ( "BlackLetters" );
0067 const QString whiteNumbersKey = QStringLiteral ( "WhiteNumbers" );
0068 const QString blackNumbersKey = QStringLiteral ( "BlackNumbers" );
0069 
0070 Board::Board(KGameThemeProvider* provider, QObject* parent) : QGraphicsScene(parent),
0071     m_rules(nullptr),
0072     m_background(nullptr),
0073     m_displayBorders(true),
0074     m_displayNotations(true),
0075     renderer(nullptr),
0076     m_themeProvider(provider),
0077     m_dragActive(false),
0078     draggedPiece(nullptr),
0079     selectedPiece(nullptr),
0080     m_paused(false),
0081     m_animated(true),
0082     m_currentPlayer(White),
0083     m_displayedPlayer(NoColor),
0084     m_drawFrame(true) {
0085 
0086     renderer = new KGameGraphicsViewRenderer(m_themeProvider);
0087     if (!Manager::self()->rules())
0088         Manager::self()->setRules(new ChessRules);
0089     Manager::self()->rules()->setGrid(&m_grid);
0090     updateTheme();
0091 
0092     connect (provider, &KGameThemeProvider::currentThemeChanged, this, &Board::updateTheme);
0093 }
0094 
0095 Board::~Board() {
0096     qDeleteAll(m_grid);
0097     qDeleteAll(m_tiles);
0098     qDeleteAll(markers);
0099     delete renderer;
0100     //TODO: this crashes the application, s.a. BUG 405763
0101     //delete Manager::self()->rules();
0102 }
0103 
0104 void Board::addPiece(PieceType type, Color color, const Pos& pos) {
0105     Piece* t_piece = new Piece ( renderer, type, color, this, pos );
0106     if ( Settings::animationSpeed() != Settings::EnumAnimationSpeed::Instant )
0107         t_piece->setPos ( mapToScene ( Pos ( ( pos.first > 4 ) ? 5 : 4, ( pos.second > 4 ) ? 5 : 4 ) ) );
0108     t_piece->setZValue ( pieceZValue );
0109     m_grid.insert ( pos, t_piece );
0110 }
0111 
0112 void Board::movePiece(const Move& move) {
0113     qCDebug(LOG_KNIGHTS) << move;
0114     Move m = move;
0115     if ( ( m.flag ( Move::Illegal ) && !m.flag ( Move::Forced ) ) ||  m.to() == m.from() || !m_grid.contains ( m.from() ) ) {
0116         qCWarning(LOG_KNIGHTS) << "Invalid move:" << m;
0117         return;
0118     }
0119     if ( !m.flag ( Move::Forced ) &&
0120             ( m_grid[m.from()]->color() != m_currentPlayer || !Manager::self()->rules()->legalMoves(m.from()).contains(m) ) ) {
0121         qCWarning(LOG_KNIGHTS) << "Move not allowed:" << m;
0122         return;
0123     }
0124     qDeleteAll ( markers );
0125     markers.clear();
0126     if ( m.flag(Move::Promote) )
0127         m_grid[m.from() ]->setPieceType ( m.promotedType() ? m.promotedType() : Queen );
0128 
0129     PieceDataMap map = m.removedPieces();
0130     PieceDataMap::const_iterator it = map.constBegin();
0131     PieceDataMap::const_iterator end = map.constEnd();
0132     for ( ; it != end; ++it ) {
0133         delete m_grid.value ( it.key(), nullptr );
0134         m_grid.remove ( it.key() );
0135     }
0136 
0137     centerOnPos ( m_grid.value ( m.from() ), m.to() );
0138     m_grid.insert ( m.to(), m_grid.take ( m.from() ) );
0139 
0140     map = m.addedPieces();
0141     it = map.constBegin();
0142     end = map.constEnd();
0143     for ( ; it != end; ++it )
0144         addPiece ( it.value().second, it.value().first, it.key() );
0145 
0146     if ( m_playerColors & oppositeColor ( m_currentPlayer ) ) {
0147         // We only display motion and danger markers if the next player is a human
0148         if ( Settings::showMotion() ) {
0149             addMarker ( m.from(), Motion );
0150             addMarker ( m.to(), Motion );
0151         }
0152         if ( Settings::showDanger() ) {
0153             bool check = false;
0154             for ( Piece* piece : std::as_const(m_grid) ) {
0155                 if ( piece->color() == m_currentPlayer && Manager::self()->rules()->isAttacking ( piece->boardPos() ) ) {
0156                     check = true;
0157                     addMarker ( piece->boardPos(), Danger );
0158                 }
0159             }
0160             if ( check ) {
0161                 for ( Piece* piece : std::as_const(m_grid) ) {
0162                     if ( piece->color() != m_currentPlayer && piece->pieceType() == King )
0163                         addMarker ( piece->boardPos(), Danger );
0164                 }
0165             }
0166         }
0167     }
0168 
0169     for ( const Move& additionalMove : m.additionalMoves() )
0170         movePiece ( additionalMove );
0171 
0172     updateGraphics();
0173 }
0174 
0175 void Board::populate() {
0176     const PieceDataMap pieces = Manager::self()->rules()->startingPieces();
0177     PieceDataMap::const_iterator it = pieces.constBegin();
0178     PieceDataMap::const_iterator end = pieces.constEnd();
0179     for ( ; it != end; ++it )
0180         addPiece ( it.value().second, it.value().first, it.key() );
0181     updateGraphics();
0182 }
0183 
0184 void Board::addTiles() {
0185     if ( !m_tiles.isEmpty() ) {
0186         qCWarning(LOG_KNIGHTS) << "Tiles are already present, delete them first";
0187         return;
0188     }
0189     for ( int i = 1; i < 9; ++i ) {
0190         for ( int j = 1; j < 9; ++j ) {
0191             QString key = ( ( i + j ) % 2 == 0 ) ? blackTileKey : whiteTileKey;
0192             Item* tile = new Item ( renderer, key, this, Pos ( i, j ) );
0193             tile->setZValue ( tileZValue );
0194             m_tiles.insert ( Pos ( i, j ), tile );
0195         }
0196     }
0197 }
0198 
0199 void Board::mousePressEvent(QGraphicsSceneMouseEvent* e) {
0200     if ( !Manager::self()->canLocalMove() ) {
0201         // It is not the human player's turn
0202         e->ignore();
0203         return;
0204     }
0205 
0206     Piece* d_piece = pieceAt ( e->scenePos() );
0207     if ( !d_piece || d_piece->color() != m_currentPlayer ) {
0208         // The piece doesn't belong to the player whose turn it is, or there is no piece
0209         if ( !selectedPiece ) {
0210             e->ignore();
0211             return;
0212         }
0213         Pos from = selectedPiece->boardPos();
0214         Pos to = mapFromScene ( e->scenePos() );
0215         if ( Manager::self()->rules()->legalMoves ( from ).contains ( Move ( from, to ) ) ) {
0216             Move move ( from, to );
0217             move.setFlag ( Move::Take, m_grid.contains ( to ) );
0218 
0219             if ( m_grid[from]->pieceType() == Pawn && ( to.second == 1 || to.second == 8 ) ) {
0220                 move.setFlag ( Move::Promote, true );
0221                 move.setPromotedType ( getPromotedType() );
0222             }
0223             Q_EMIT pieceMoved(move);
0224             selectedPiece = nullptr;
0225         }
0226     } else {
0227         // The active player clicked on his/her own piece
0228         if (d_piece != selectedPiece) {
0229             qDeleteAll ( markers );
0230             markers.clear();
0231 
0232             selectedPiece = d_piece;
0233 
0234             Pos t_pos = mapFromScene ( e->scenePos() );
0235             QList<Move> t_legalMoves = Manager::self()->rules()->legalMoves ( t_pos );
0236             if ( t_legalMoves.isEmpty() ) {
0237                 e->ignore();
0238                 return;
0239             }
0240             d_piece->setZValue ( dragZValue );
0241             if ( Settings::showMarker() ) {
0242                 for ( const Move& t_move : std::as_const(t_legalMoves) )
0243                     addMarker ( t_move.to(), LegalMove );
0244             }
0245             draggedPiece = d_piece;
0246         }
0247         m_draggedPos = e->scenePos();
0248         dragStartPoint = e->screenPos();
0249     }
0250 }
0251 
0252 void Board::mouseReleaseEvent(QGraphicsSceneMouseEvent* e) {
0253     Q_UNUSED(e);
0254     draggedPiece = nullptr;
0255 }
0256 
0257 void Board::mouseMoveEvent(QGraphicsSceneMouseEvent* e) {
0258     if (!(e->buttons() & Qt::LeftButton) || m_dragActive)
0259         return;
0260     if (draggedPiece && ((e->screenPos() - dragStartPoint).manhattanLength() >= QApplication::startDragDistance()) ) {
0261         //initiate a new drag event
0262         drag = new QDrag ( e->widget() );
0263         drag->setMimeData ( new QMimeData() );
0264         m_dragActive = true;
0265         selectedPiece = nullptr;
0266         drag->exec();
0267     }
0268 }
0269 
0270 void Board::dragLeaveEvent(QGraphicsSceneDragDropEvent* e) {
0271     Q_UNUSED(e);
0272     if ( !m_dragActive )
0273         return;
0274 
0275     qDeleteAll(markers);
0276     markers.clear();
0277     centerOnPos(draggedPiece);
0278     draggedPiece->setZValue(pieceZValue);
0279     draggedPiece = nullptr;
0280     m_dragActive = false;
0281 }
0282 
0283 void Board::dropEvent(QGraphicsSceneDragDropEvent* e) {
0284     qDeleteAll(markers);
0285     markers.clear();
0286 
0287     if (draggedPiece) {
0288         m_dragActive = false;
0289         Pos from = draggedPiece->boardPos();
0290         Pos to = mapFromScene ( e->scenePos() );
0291         Move move ( from, to );
0292         if ( !Manager::self()->rules()->legalMoves ( from ).contains ( move ) )
0293             centerOnPos ( draggedPiece );
0294         else {
0295             if ( m_grid[from]->pieceType() == Pawn && ( to.second == 1 || to.second == 8 ) ) {
0296                 move.setFlag ( Move::Promote, true );
0297                 move.setPromotedType ( getPromotedType() );
0298             }
0299             Q_EMIT pieceMoved(move);
0300         }
0301         draggedPiece->setZValue(pieceZValue);
0302         draggedPiece = nullptr;
0303     }
0304 }
0305 
0306 void Board::dragEnterEvent(QGraphicsSceneDragDropEvent* e) {
0307     e->setAccepted(Manager::self()->canLocalMove());
0308 }
0309 
0310 void Board::dragMoveEvent(QGraphicsSceneDragDropEvent* e) {
0311     if ( !draggedPiece ) {
0312         e->ignore();
0313         return;
0314     }
0315     e->accept();
0316     qreal x = e->scenePos().x() - m_draggedPos.x();
0317     qreal y = e->scenePos().y() - m_draggedPos.y();
0318 
0319     draggedPiece->moveBy ( x, y );
0320     m_draggedPos = e->scenePos();
0321 }
0322 
0323 Piece* Board::pieceAt(const QPointF& point) {
0324     return m_grid.value(mapFromScene(point), nullptr);
0325 }
0326 
0327 Pos Board::mapFromScene(const QPointF& point) {
0328     Pos pos;
0329     pos.first = ( point.x() - m_boardRect.left() ) / m_tileSize + 1;
0330     pos.second = 1 - ( point.y() - m_boardRect.bottom() ) / m_tileSize;
0331     if ( m_displayedPlayer != White )
0332         pos = Pos ( 9, 9 ) - pos;
0333     return pos;
0334 }
0335 
0336 QPointF Board::mapToScene(Pos pos) {
0337     if ( m_displayedPlayer != White )
0338         pos = Pos ( 9, 9 ) - pos;
0339     QPointF point;
0340     point.setX ( m_boardRect.left() + ( pos.first - 1 ) * m_tileSize );
0341     point.setY ( m_boardRect.bottom() - pos.second * m_tileSize );
0342     return point;
0343 }
0344 
0345 void Board::centerOnPos(Item* item, const Pos& pos, bool animated) {
0346     item->setBoardPos(pos);
0347     centerOnPos(item, animated);
0348 }
0349 
0350 void Board::centerOnPos(Item* item, bool animated) {
0351     item->move(mapToScene(item->boardPos()), m_tileSize, animated);
0352 }
0353 
0354 void Board::centerAndResize(Item* item, QSize size, bool animated) {
0355     item->moveAndResize(mapToScene ( item->boardPos() ), m_tileSize, size, animated);
0356 }
0357 
0358 bool Board::isInBoard(const Pos& pos) {
0359     return pos.first > 0 && pos.first < 9 && pos.second > 0 && pos.second < 9;
0360 }
0361 
0362 void Board::setPlayerColors(Colors colors) {
0363     m_playerColors = colors;
0364     if ( m_playerColors & m_currentPlayer )
0365         m_displayedPlayer = m_currentPlayer;
0366     else {
0367         if ( m_playerColors == Black )
0368             m_displayedPlayer = Black;
0369         else
0370             m_displayedPlayer = White;
0371     }
0372     changeDisplayedPlayer();
0373     populate();
0374 }
0375 
0376 void Board::setCurrentColor(Color color) {
0377     m_currentPlayer = color;
0378     Color nextPlayer = m_displayedPlayer;
0379     if ( ( ( m_playerColors & (Black|White) ) == (Black|White) ) && !Settings::flipBoard() )
0380         nextPlayer = White;
0381     else if ( m_playerColors & color )
0382         nextPlayer = color;
0383     if ( m_displayedPlayer != nextPlayer ) {
0384         m_displayedPlayer = nextPlayer;
0385         changeDisplayedPlayer();
0386     }
0387     Q_EMIT activePlayerChanged ( m_currentPlayer );
0388 }
0389 
0390 
0391 void Board::addMarker(const Pos& pos, MarkerType type) {
0392     QString key;
0393     switch ( type ) {
0394     case LegalMove:
0395         key = legalMarkerKey;
0396         break;
0397     case Danger:
0398         key = dangerMarkerKey;
0399         break;
0400     case Motion:
0401         key = motionMarkerKey;
0402         break;
0403     }
0404     addMarker ( pos, key );
0405 }
0406 
0407 void Board::addMarker(const Pos& pos, const QString& spriteKey) {
0408     if ( markers.contains ( pos ) ) {
0409         // Prevent two markers (usually Motion and Danger) from being on the same square
0410         delete markers[pos];
0411     }
0412     Item* marker = new Item ( renderer, spriteKey, this, pos );
0413     centerOnPos ( marker, false );
0414     marker->setRenderSize ( QSizeF ( m_tileSize, m_tileSize ).toSize() );
0415     marker->setZValue ( legalMarkerZValue );
0416     markers.insert ( pos, marker );
0417 }
0418 
0419 void Board::updateTheme() {
0420     delete m_background;
0421     qDebug()<<"background key " << backgroundKey;
0422     if ( renderer->spriteExists ( backgroundKey ) ) {
0423         m_background = new Item ( renderer, backgroundKey, this, Pos() );
0424         m_background->setZValue ( backgroundZValue );
0425     } else
0426         m_background = nullptr;
0427 
0428     qDeleteAll ( m_borders );
0429     m_borders.clear();
0430     qDeleteAll ( m_notations );
0431     m_notations.clear();
0432     m_displayBorders = Settings::borderDisplayType() != Settings::EnumBorderDisplayType::None
0433                        && renderer->spriteExists ( lrBorderKey )
0434                        && renderer->spriteExists ( tbBorderKey );
0435     m_displayNotations = Settings::borderDisplayType() == Settings::EnumBorderDisplayType::Notation
0436                          && renderer->spriteExists ( whiteLettersKey )
0437                          && renderer->spriteExists ( blackLettersKey )
0438                          && renderer->spriteExists ( whiteNumbersKey )
0439                          && renderer->spriteExists ( blackNumbersKey );
0440     if ( m_displayBorders ) {
0441         m_borders << new Item ( renderer, tbBorderKey, this, Pos() );
0442 
0443         Item *tItem = new Item ( renderer, lrBorderKey, this, Pos() );
0444         tItem->setRotation ( 180 );
0445         m_borders << tItem;
0446 
0447         tItem = new Item ( renderer, tbBorderKey, this, Pos() );
0448         tItem->setRotation ( 180 );
0449         m_borders << tItem;
0450 
0451         m_borders << new Item ( renderer, lrBorderKey, this, Pos() );
0452         for ( Item* item : std::as_const(m_borders) )
0453             item->setZValue ( borderZValue );
0454     }
0455     if ( m_displayNotations ) {
0456         QString lettersKey;
0457         QString numbersKey;
0458         if ( m_displayedPlayer == White ) {
0459             lettersKey = whiteLettersKey;
0460             numbersKey = whiteNumbersKey;
0461         } else {
0462             lettersKey = blackLettersKey;
0463             numbersKey = blackNumbersKey;
0464         }
0465         m_notations << new Item ( renderer, lettersKey, this, Pos() );
0466         m_notations << new Item ( renderer, numbersKey, this, Pos() );
0467         m_notations << new Item ( renderer, lettersKey, this, Pos() );
0468         m_notations << new Item ( renderer, numbersKey, this, Pos() );
0469         for ( Item* item : std::as_const(m_notations) )
0470             item->setZValue ( notationZValue );
0471     }
0472     addTiles();
0473     updateGraphics();
0474 }
0475 
0476 void Board::updateGraphics() {
0477     if ( m_background )
0478         m_background->setRenderSize ( sceneRect().size().toSize() );
0479     QSizeF tileSize = renderer->boundsOnSprite ( whiteTileKey ).size();
0480     QSizeF boardSize = 8 * tileSize;
0481     qreal sideMargin;
0482     qreal topMargin;
0483     if ( m_displayBorders ) {
0484         sideMargin = renderer->boundsOnSprite ( lrBorderKey ).width();
0485         topMargin = renderer->boundsOnSprite ( tbBorderKey ).height();
0486     } else {
0487         sideMargin = 0.0;
0488         topMargin = 0.0;
0489     }
0490     boardSize = boardSize + 2 * QSize ( sideMargin, topMargin );
0491     qreal ratio = qMin ( sceneRect().width() / boardSize.width(), sceneRect().height() / boardSize.height() );
0492     sideMargin *= ratio;
0493     topMargin *= ratio;
0494 
0495     QSizeF tpSize = tileSize * ratio;
0496     m_tileSize = qFloor ( qMin ( tpSize.width(), tpSize.height() ) );
0497     /*
0498     if ( m_displayBorders )
0499     {
0500         if (  m_tileSize % 2 )
0501         {
0502             m_tileSize -= 1;
0503         }
0504         sideMargin = m_tileSize / 2;
0505         topMargin = m_tileSize / 2;
0506     }
0507     */
0508 
0509     QSize hBorderSize = QSize ( 8 * m_tileSize + 2 * qRound ( sideMargin ), qRound ( topMargin ) );
0510     QSize vBorderSize = QSize ( qRound ( sideMargin ), 8 * m_tileSize );
0511     int hBorderMargin = qRound ( topMargin );
0512     int vBorderMargin = qRound ( sideMargin );
0513 
0514 
0515     sideMargin = qMax ( sideMargin, ( sceneRect().width() - 8 * m_tileSize ) / 2 );
0516     topMargin = qMax ( topMargin, ( sceneRect().height() - 8 * m_tileSize ) / 2 );
0517     m_boardRect = QRect( sceneRect().topLeft().toPoint() + QPoint( sideMargin, topMargin ),
0518                          QSize( m_tileSize, m_tileSize ) * 8);
0519 
0520     QSize tSize = QSizeF ( m_tileSize, m_tileSize ).toSize();
0521     /*
0522      * For historical reasons, QRect's
0523      */
0524     QPointF topBorderPoint = m_boardRect.topRight() + QPoint ( vBorderMargin, 0 );
0525     QPointF rightBorderPoint = m_boardRect.bottomRight() + QPoint ( vBorderMargin, 0 );
0526     QPointF bottomBorderPoint = m_boardRect.bottomLeft() - QPoint ( vBorderMargin, 0 );
0527     QPointF leftBorderPoint = m_boardRect.topLeft() - QPoint ( vBorderMargin, 0 );
0528 
0529     for ( Piece* p : std::as_const(m_grid) )
0530         centerAndResize ( p, tSize );
0531     for ( Item* t : std::as_const(m_tiles) )
0532         centerAndResize ( t, tSize, Settings::animateBoard() );
0533     for ( Item* t : std::as_const(markers) )
0534         centerAndResize ( t, tSize );
0535     if ( m_displayBorders ) {
0536         m_borders[0]->moveAndResize ( bottomBorderPoint, m_tileSize, hBorderSize, Settings::animateBoard() );
0537         m_borders[1]->moveAndResize ( rightBorderPoint, m_tileSize, vBorderSize, Settings::animateBoard() );
0538         m_borders[2]->moveAndResize ( topBorderPoint, m_tileSize, hBorderSize, Settings::animateBoard() );
0539         m_borders[3]->moveAndResize ( leftBorderPoint, m_tileSize, vBorderSize, Settings::animateBoard() );
0540     }
0541     if ( m_displayNotations ) {
0542         m_notations[0]->moveAndResize ( bottomBorderPoint, m_tileSize, hBorderSize, Settings::animateBoard() );
0543         m_notations[1]->moveAndResize ( m_boardRect.topRight(), m_tileSize, vBorderSize, Settings::animateBoard() );
0544         m_notations[2]->moveAndResize ( m_boardRect.topLeft() - QPointF ( vBorderMargin, hBorderMargin ), m_tileSize, hBorderSize, Settings::animateBoard() );
0545         m_notations[3]->moveAndResize ( leftBorderPoint, m_tileSize, vBorderSize, Settings::animateBoard() );
0546     }
0547 }
0548 
0549 void Board::changeDisplayedPlayer() {
0550     for ( Piece* p : std::as_const(m_grid) )
0551         centerOnPos ( p );
0552     for ( Item* i : std::as_const(markers) )
0553         centerOnPos ( i );
0554     if ( Settings::animateBoard() ) {
0555         for ( Item* i : std::as_const(m_tiles) )
0556             centerOnPos ( i );
0557     }
0558     if ( m_displayNotations ) {
0559         if ( m_displayedPlayer == White ) {
0560             m_notations[0]->setSpriteKey ( whiteLettersKey );
0561             m_notations[1]->setSpriteKey ( whiteNumbersKey );
0562             m_notations[2]->setSpriteKey ( whiteLettersKey );
0563             m_notations[3]->setSpriteKey ( whiteNumbersKey );
0564         } else {
0565             m_notations[0]->setSpriteKey ( blackLettersKey );
0566             m_notations[1]->setSpriteKey ( blackNumbersKey );
0567             m_notations[2]->setSpriteKey ( blackLettersKey );
0568             m_notations[3]->setSpriteKey ( blackNumbersKey );
0569         }
0570     }
0571     Q_EMIT displayedPlayerChanged(m_displayedPlayer);
0572 }
0573 
0574 PieceType Board::getPromotedType() {
0575     PieceType piece = Queen;
0576     QPointer<QDialog> dialog = new QDialog();
0577     dialog->setWindowTitle(i18nc("@title:window", "Promotion"));
0578     QWidget *widget = new QWidget();
0579     QVBoxLayout *layout = new QVBoxLayout();
0580     QDialogButtonBox *bBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0581     bBox->button(QDialogButtonBox::Ok)->setText(i18n("Promote"));
0582     bBox->button(QDialogButtonBox::Ok)->setDefault(true);
0583 
0584     Ui::PromotionWidget ui;
0585     ui.setupUi ( widget );
0586 
0587     layout->addWidget ( widget );
0588     layout->addWidget ( bBox );
0589     dialog->setLayout ( layout );
0590 
0591     connect (bBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
0592     connect (bBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
0593 
0594     if ( dialog->exec() == QDialog::Accepted ) {
0595         if ( ui.radioButtonKnight->isChecked() )
0596             piece = Knight;
0597         else if ( ui.radioButtonBishop->isChecked() )
0598             piece = Bishop;
0599         else if ( ui.radioButtonRook->isChecked() )
0600             piece = Rook;
0601     }
0602     delete dialog;
0603     return piece;
0604 }
0605 
0606 #include "moc_board.cpp"