diff --git a/CMakeLists.txt b/CMakeLists.txt index df06641..1cdee8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,85 +1,86 @@ project(klines) cmake_minimum_required (VERSION 3.5 FATAL_ERROR) set (QT_MIN_VERSION "5.9.0") set (KF5_MIN_VERSION "5.46.0") find_package(ECM ${KF5_MIN_VERSION} REQUIRED CONFIG) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Widgets) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS CoreAddons Config Crash WidgetsAddons Config DBusAddons I18n ConfigWidgets XmlGui DocTools ) find_package(KF5KDEGames 4.9.0 REQUIRED) include(FeatureSummary) include(ECMAddAppIcon) include(ECMInstallIcons) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) +include(ECMQtDeclareLoggingCategory) if (EXISTS "${CMAKE_SOURCE_DIR}/.git") add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x060000) endif() add_subdirectory(themes) add_subdirectory(doc) ########### next target ############### set(klines_SRCS mwidget.cpp klines.cpp main.cpp scene.cpp renderer.cpp ballitem.cpp previewitem.cpp animator.cpp ) - +ecm_qt_declare_logging_category(klines_SRCS HEADER klines_debug.h IDENTIFIER KLINES_LOG CATEGORY_NAME org.kde.kdegames.klines) qt5_add_resources(klines_SRCS klines.qrc) kconfig_add_kcfg_files(klines_SRCS prefs.kcfgc) file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/*-apps-klines.png") ecm_add_app_icon(klines_SRCS ICONS ${ICONS_SRCS}) add_executable(klines ${klines_SRCS}) target_link_libraries(klines KF5KDEGames KF5::Crash KF5::DBusAddons KF5::XmlGui ) install(TARGETS klines ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install(PROGRAMS org.kde.klines.desktop DESTINATION ${KDE_INSTALL_APPDIR}) install(FILES klines.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR}) install(FILES org.kde.klines.appdata.xml DESTINATION ${CMAKE_INSTALL_METAINFODIR}) ecm_install_icons(ICONS 16-apps-klines.png 22-apps-klines.png 32-apps-klines.png 48-apps-klines.png 64-apps-klines.png 128-apps-klines.png DESTINATION ${KDE_INSTALL_ICONDIR} THEME hicolor ) - +install( FILES klines.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} ) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/klines.categories b/klines.categories new file mode 100644 index 0000000..4a501b0 --- /dev/null +++ b/klines.categories @@ -0,0 +1 @@ +org.kde.kdegames.klines (kdegames klines) IDENTIFIER [KLINES_LOG] diff --git a/renderer.cpp b/renderer.cpp index e4c2c44..8142fe4 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1,187 +1,187 @@ /******************************************************************* * * Copyright 2006-2007 Dmitry Suzdalev * * This file is part of the KDE project "KLines" * * KLines is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * KLines is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with KLines; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * ********************************************************************/ #include "renderer.h" - +#include "klines_debug.h" #include #include // note: this should be in sync with svg static inline char color2char(BallColor col) { switch (col) { case Blue: return 'b'; case Brown: return 'e'; case Cyan: return 'c'; case Green: return 'g'; case Red: return 'r'; case Violet: return 'p'; case Yellow: return 'y'; default: return 'x'; // error } } int KLinesRenderer::m_cellSize = 0; KGameRenderer *KLinesRenderer::m_renderer; int KLinesRenderer::m_numBornFrames(0); int KLinesRenderer::m_numSelFrames(0); int KLinesRenderer::m_numDieFrames(0); int KLinesRenderer::m_bornDuration(0); int KLinesRenderer::m_selDuration(0); int KLinesRenderer::m_dieDuration(0); int KLinesRenderer::m_moveDuration(0); KLinesRenderer *g_KLinesRenderer = nullptr; void KLinesRenderer::Init() { g_KLinesRenderer = new KLinesRenderer(); } void KLinesRenderer::UnInit() { delete g_KLinesRenderer; } KLinesRenderer::KLinesRenderer() { KgThemeProvider* provider = new KgThemeProvider; provider->discoverThemes("appdata", QStringLiteral("themes")); //the default theme is marked with a key "Default=true" foreach (const KgTheme* theme, provider->themes()) { if (theme->customData(QStringLiteral("Default")) == QLatin1String("true")) { provider->setDefaultTheme(theme); break; } } m_renderer = new KGameRenderer(provider); loadTheme(); } KLinesRenderer::~KLinesRenderer() { delete m_renderer; } QString KLinesRenderer::ballPixmapId(BallColor color) { return QLatin1Char(color2char(color)) + QLatin1String("_rest"); } QPixmap KLinesRenderer::ballPixmap(BallColor color) { return getPixmap(ballPixmapId(color)); } QString KLinesRenderer::animationFrameId(AnimationType type, BallColor color, int frame) { switch (type) { case BornAnim: return QLatin1Char(color2char(color)) + QLatin1String("_born_") + QString::number(frame + 1); case SelectedAnim: return QLatin1Char(color2char(color)) + QLatin1String("_select_") + QString::number(frame + 1); case DieAnim: return QLatin1Char(color2char(color)) + QLatin1String("_die_") + QString::number(frame + 1); case MoveAnim: - qDebug() << "Move animation type isn't supposed to be handled by KLinesRenderer!"; + qCDebug(KLINES_LOG) << "Move animation type isn't supposed to be handled by KLinesRenderer!"; return QString(); default: - qDebug() << "Warning! Animation type not handled in switch!"; + qCDebug(KLINES_LOG) << "Warning! Animation type not handled in switch!"; return QString(); } } QPixmap KLinesRenderer::backgroundTilePixmap() { return getPixmap(QStringLiteral("field_cell")); } QPixmap KLinesRenderer::backgroundPixmap(const QSize& size) { return getPixmap(QStringLiteral("background"), size); } QPixmap KLinesRenderer::previewPixmap() { return getPixmap(QStringLiteral("preview"), QSize(m_cellSize, m_cellSize * 3)); } bool KLinesRenderer::loadTheme() { const KgTheme* theme = m_renderer->theme(); m_numBornFrames = theme->customData(QStringLiteral("NumBornFrames")).toInt(); m_numSelFrames = theme->customData(QStringLiteral("NumSelectedFrames")).toInt(); m_numDieFrames = theme->customData(QStringLiteral("NumDieFrames")).toInt(); m_bornDuration = theme->customData(QStringLiteral("BornAnimDuration")).toInt(); m_selDuration = theme->customData(QStringLiteral("SelectedAnimDuration")).toInt(); m_dieDuration = theme->customData(QStringLiteral("DieAnimDuration")).toInt(); m_moveDuration = theme->customData(QStringLiteral("MoveAnimDuration")).toInt(); return true; } void KLinesRenderer::setCellSize(int cellSize) { if (m_cellSize == cellSize) return; m_cellSize = cellSize; } QPixmap KLinesRenderer::getPixmap(const QString& svgName, const QSize& customSize) { if (m_cellSize == 0) return QPixmap(); QSize sz = customSize.isValid() ? customSize : cellExtent(); QPixmap pix = m_renderer->spritePixmap(svgName, sz); return pix; } QPixmap KLinesRenderer::backgroundBorderPixmap(const QSize& size) { if (!hasBorderElement()) return QPixmap(); return getPixmap(QStringLiteral("border"), size); } bool KLinesRenderer::hasBorderElement() { return m_renderer->spriteExists(QStringLiteral("border")); } diff --git a/scene.cpp b/scene.cpp index 32266de..1741f96 100644 --- a/scene.cpp +++ b/scene.cpp @@ -1,696 +1,696 @@ /******************************************************************* * * Copyright 2006-2008 Dmitry Suzdalev * * This file is part of the KDE project "KLines" * * KLines is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * KLines is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with KLines; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * ********************************************************************/ #include "scene.h" #include "ballitem.h" #include "previewitem.h" #include "animator.h" #include "renderer.h" #include #include #include -#include +#include "klines_debug.h" #include #include inline uint qHash( const FieldPos& pos ) { return qHash( QPair(pos.x,pos.y) ); } KLinesScene::KLinesScene( QObject* parent ) : QGraphicsScene(parent), m_playFieldBorderSize(0), m_numFreeCells(FIELD_SIZE*FIELD_SIZE), m_score(0), m_bonusScore(0), m_cellSize(32), m_previewZoneVisible(true) { m_animator = new KLinesAnimator(this); connect(m_animator, &KLinesAnimator::moveFinished, this, &KLinesScene::moveAnimFinished); connect(m_animator, &KLinesAnimator::removeFinished, this, &KLinesScene::removeAnimFinished); connect(m_animator, &KLinesAnimator::bornFinished, this, &KLinesScene::bornAnimFinished); m_focusItem = new QGraphicsRectItem( QRectF(0, 0, m_cellSize, m_cellSize), nullptr); m_focusItem->setZValue(1.0); m_focusItem->setPen( Qt::DashLine ); m_previewItem = new PreviewItem(this); m_previewItem->setPos( 0, 0 ); addItem(m_previewItem); m_popupItem = new KGamePopupItem; addItem(m_popupItem); startNewGame(); } void KLinesScene::startNewGame() { if(m_animator->isAnimating()) return; // reset all vars m_selPos = FieldPos(); m_numFreeCells = FIELD_SIZE*FIELD_SIZE; m_score = 0; m_bonusScore = 0; m_placeBalls = true; m_gameOver = false; m_itemsToDelete.clear(); m_nextColors.clear(); m_focusItem->setPos(0, 0); m_focusItem->hide(); m_popupItem->forceHide(); // remove all ball items from the scene leaving other items untouched QList itemlist = items(); foreach( QGraphicsItem* item, itemlist ) { BallItem* ball = qgraphicsitem_cast(item); if( ball ) { removeItem(item); delete item; } } for(int x=0; x(m_randomSeq.getLong(static_cast(NumColors))); m_nextColors.append(c); } emit stateChanged(QStringLiteral( "not_undoable" )); nextThreeBalls(); } KLinesScene::~KLinesScene() { delete m_animator; } void KLinesScene::resizeScene(int width,int height) { // store focus item field pos (calculated using old cellSize) FieldPos focusRectFieldPos = pixToField( m_focusItem->pos() ); bool hasBorder = KLinesRenderer::hasBorderElement(); int minDim = qMin( width, height ); // border width is hardcoded to be half of cell size. // take it into account if it exists m_cellSize = hasBorder ? minDim/(FIELD_SIZE+1) : minDim/FIELD_SIZE; // set it only if current theme supports it m_playFieldBorderSize = hasBorder ? m_cellSize/2 : 0; int boardSize = m_cellSize * FIELD_SIZE; if ( m_previewZoneVisible && boardSize +m_playFieldBorderSize*2 + m_cellSize > width) // No space enough for balls preview { minDim = width; m_cellSize = hasBorder ? (minDim - m_cellSize - m_playFieldBorderSize*2)/FIELD_SIZE : (minDim - m_cellSize)/FIELD_SIZE; boardSize = m_cellSize * FIELD_SIZE; } m_playFieldRect.setX( (width - (m_previewZoneVisible ? m_cellSize : 0))/2 - boardSize/2 - m_playFieldBorderSize ); m_playFieldRect.setY( height/2 - boardSize/2 - m_playFieldBorderSize ); m_playFieldRect.setWidth( boardSize + m_playFieldBorderSize*2 ); m_playFieldRect.setHeight( boardSize + m_playFieldBorderSize*2 ); setSceneRect( 0, 0, width, height ); // sets render sizes for cells KLinesRenderer::setCellSize( m_cellSize ); QSize cellSize(m_cellSize, m_cellSize); // re-render && recalc positions for all balls for( int x=0; xsetRenderSize(cellSize); m_field[x][y]->setPos( fieldToPix( FieldPos(x,y) ) ); m_field[x][y]->setColor( m_field[x][y]->color() ); } } m_focusItem->setRect( QRect(0,0, m_cellSize, m_cellSize) ); m_focusItem->setPos( fieldToPix( focusRectFieldPos ) ); int previewOriginY = height / 2 - (3 * m_cellSize) / 2; int previewOriginX = m_playFieldRect.x() + m_playFieldRect.width(); m_previewItem->setPos( previewOriginX, previewOriginY ); m_previewItem->setPreviewColors( m_nextColors ); - //qDebug() << "resize:" << width << "," << height << "; cellSize:" << m_cellSize; + //qCDebug(KLINES_LOG) << "resize:" << width << "," << height << "; cellSize:" << m_cellSize; } void KLinesScene::endTurn() { if( m_gameOver ) return; saveUndoInfo(); nextThreeBalls(); } void KLinesScene::nextThreeBalls() { if( m_animator->isAnimating() ) return; QList newItems; BallItem* newBall; for(int i=0; i<3; i++) { newBall = randomlyPlaceBall( m_nextColors.at(i) ); if( newBall ) newItems.append(newBall); else break; // the field is filled :). } for(int i=0; i<3; i++) { // random color BallColor c = static_cast(m_randomSeq.getLong(static_cast(NumColors))); m_nextColors[i] = c; } m_previewItem->setPreviewColors( m_nextColors ); m_animator->animateBorn( newItems ); } void KLinesScene::setPreviewZoneVisible( bool visible ) { if (visible == m_previewZoneVisible) return; m_previewZoneVisible = visible; m_previewItem->setVisible( visible ); resizeScene((int) width(), (int) height()); invalidate( sceneRect() ); } BallItem* KLinesScene::randomlyPlaceBall(BallColor c) { m_numFreeCells--; if(m_numFreeCells < 0) { // restore m_numFreeCells value, it will trigger // saveAndErase() after bornAnimFinished to check if // we have 5-in-a-row to erase m_numFreeCells = 0; return nullptr; // game over, we won't create more balls } int posx = -1, posy = -1; // let's find random free cell do { posx = m_randomSeq.getLong(FIELD_SIZE); posy = m_randomSeq.getLong(FIELD_SIZE); } while( m_field[posx][posy] != nullptr ); BallItem* newBall = new BallItem( this); newBall->setColor(c, false); // pixmap will be set by born animation newBall->setPos( fieldToPix( FieldPos(posx,posy) ) ); m_field[posx][posy] = newBall; return newBall; } void KLinesScene::mousePressEvent( QGraphicsSceneMouseEvent* ev ) { QGraphicsScene::mousePressEvent(ev); QRect boardRect = m_playFieldRect.adjusted( m_playFieldBorderSize, m_playFieldBorderSize, -m_playFieldBorderSize, -m_playFieldBorderSize ); if ( !boardRect.contains( ev->scenePos().toPoint() ) ) return; selectOrMove( pixToField(ev->scenePos()) ); } void KLinesScene::selectOrMove( const FieldPos& fpos ) { if (fpos.x < 0 || fpos.y < 0) { return; } if( m_animator->isAnimating() ) return; if( m_field[fpos.x][fpos.y] ) // ball was selected { if( m_selPos.isValid() ) { m_field[m_selPos.x][m_selPos.y]->stopAnimation(); if ( m_selPos == fpos ) { m_selPos.x = m_selPos.y = -1; // invalidate position return; } } m_field[fpos.x][fpos.y]->startSelectedAnimation(); m_selPos = fpos; } else // move selected ball to new location { if( m_selPos.isValid() && m_field[fpos.x][fpos.y] == nullptr ) { saveUndoInfo(); // start move animation // slot moveAnimFinished() will be called when it finishes bool pathExists = m_animator->animateMove(m_selPos, fpos); if(!pathExists) { m_popupItem->setMessageTimeout(2500); m_popupItem->showMessage(i18n("There is no path from the selected piece to this cell"), KGamePopupItem::BottomLeft); } } } } void KLinesScene::moveAnimFinished() { // m_field[m_selPos.x][m_selPos.y] still holds the ball pointer // but animation placed it to new location. // But it updated only pixel position, not the field one // So let's do it here BallItem *movedBall = m_field[m_selPos.x][m_selPos.y]; // movedBall has new pixel position - let's find out corresponding field pos FieldPos newpos = pixToField(movedBall->pos()); m_field[m_selPos.x][m_selPos.y] = nullptr; // no more ball here m_field[newpos.x][newpos.y] = movedBall; m_selPos.x = m_selPos.y = -1; // invalidate position m_placeBalls = true; // after anim finished, slot removeAnimFinished() // will be called searchAndErase(); } void KLinesScene::removeAnimFinished() { if( m_itemsToDelete.isEmpty() && m_numFreeCells == 0 ) { // game over gameOverHandler(); return; } if( m_itemsToDelete.isEmpty() && m_placeBalls) { // slot bornAnimFinished() will be called // when born animation finishes // NOTE: removeAnimFinished() will be called again // after new balls will born (because searchAndErase() will be called) // but other if branch will be taken nextThreeBalls(); } else { // this is kind of 'things to do after one turn is finished' // place in code :) int numBallsErased = m_itemsToDelete.count(); if(numBallsErased) { // expression taked from previous code in klines.cpp m_score += 2*numBallsErased*numBallsErased - 20*numBallsErased + 60 ; m_score += m_bonusScore; } foreach( BallItem* item, m_itemsToDelete ) { removeItem(item); delete item; } m_itemsToDelete.clear(); if(numBallsErased) emit scoreChanged(m_score); } } void KLinesScene::bornAnimFinished() { // note that if m_numFreeCells == 0, we still need to // check for possible 5-in-a-row balls, i.e. call searchAndErase() // So there's another gameOver-check in removeAnimFinished() if( m_numFreeCells < 0 ) { gameOverHandler(); return; } // There's a little trick here: // searchAndErase() will cause m_animator to emit removeFinished() // If there wasn't m_placeBalls var // it would cause an infinite loop like this: // SaE()->removeAnimFinished()->next3Balls()->bornAnimFinished()-> // SaE()->removeAnimFinished()->next3Balls()->... // etc etc m_placeBalls = false; // after placing new balls new 5-in-a-row chunks can occur // so we need to check for them // // And because of that we check for gameOver in removeAnimFinished() // rather than here - there's a chance that searchAndErase() will remove // balls making some free cells to play in searchAndErase(); } void KLinesScene::searchAndErase() { // FIXME dimsuz: put more comments about bounds in for loops // QSet - to exclude adding duplicates QSet positionsToDelete; // horizontal chunks searching for(int x=0; xcolor(); int tmpx = x+1; while(tmpx < FIELD_SIZE && m_field[tmpx][y] && m_field[tmpx][y]->color() == col) tmpx++; // tmpx-x will be: how much balls of the same color we found if(tmpx-x >= 5) { for(int i=x; icolor(); int tmpy = y+1; while(tmpy < FIELD_SIZE && m_field[x][tmpy] && m_field[x][tmpy]->color() == col) tmpy++; // tmpy-y will be: how much balls of the same color we found if(tmpy-y >= 5) { for(int j=y; jcolor(); int tmpx = x+1; int tmpy = y+1; while(tmpx < FIELD_SIZE && tmpy < FIELD_SIZE && m_field[tmpx][tmpy] && m_field[tmpx][tmpy]->color() == col) { tmpx++; tmpy++; } // tmpx-x (and tmpy-y too) will be: how much balls of the same color we found if(tmpx-x >= 5) { for(int i=x,j=y; icolor(); int tmpx = x+1; int tmpy = y-1; while(tmpx < FIELD_SIZE && tmpy >=0 && m_field[tmpx][tmpy] && m_field[tmpx][tmpy]->color() == col) { tmpx++; tmpy--; } // tmpx-x (and tmpy-y too) will be: how much balls of the same color we found if(tmpx-x >= 5) { for(int i=x,j=y; ianimateRemove( m_itemsToDelete ); } void KLinesScene::moveFocusLeft() { if( !m_focusItem->isVisible() ) { m_focusItem->show(); // no action for the first time return; } FieldPos focusPos = pixToField( m_focusItem->pos() ); focusPos.x--; if (focusPos.x < 0) // rotate on the torus focusPos.x = FIELD_SIZE - 1; m_focusItem->setPos ( fieldToPix( focusPos ) ); } void KLinesScene::moveFocusRight() { if( !m_focusItem->isVisible() ) { m_focusItem->show(); // no action for the first time return; } FieldPos focusPos = pixToField( m_focusItem->pos() ); focusPos.x++; if (focusPos.x >= FIELD_SIZE) // rotate on the torus focusPos.x = 0; m_focusItem->setPos ( fieldToPix( focusPos ) ); } void KLinesScene::moveFocusUp() { if( !m_focusItem->isVisible() ) { m_focusItem->show(); // no action for the first time return; } FieldPos focusPos = pixToField( m_focusItem->pos() ); focusPos.y--; if (focusPos.y < 0) // rotate on the torus focusPos.y = FIELD_SIZE - 1; m_focusItem->setPos ( fieldToPix( focusPos ) ); } void KLinesScene::moveFocusDown() { if( !m_focusItem->isVisible() ) { m_focusItem->show(); // no action for the first time return; } FieldPos focusPos = pixToField( m_focusItem->pos() ); focusPos.y++; if (focusPos.y >= FIELD_SIZE) // rotate on the torus focusPos.y = 0; m_focusItem->setPos ( fieldToPix( focusPos ) ); } void KLinesScene::cellSelected() { if( !m_focusItem->isVisible() ) m_focusItem->show(); // we're taking the center of the cell selectOrMove( pixToField( m_focusItem->pos() + QPointF(m_cellSize/2,m_cellSize/2) ) ); } void KLinesScene::saveUndoInfo() { // save field state to undoInfo for(int x=0;xcolor() : NumColors ); m_undoInfo.numFreeCells = m_numFreeCells; m_undoInfo.score = m_score; m_undoInfo.nextColors = m_nextColors; emit stateChanged(QStringLiteral( "undoable" )); } // Brings m_field and some other vars to the state it was before last turn void KLinesScene::undo() { // do not allow undo during animation if(m_animator->isAnimating()) return; if( m_selPos.isValid() ) m_field[m_selPos.x][m_selPos.y]->stopAnimation(); BallColor col; for(int x=0;xcolor() != col ) m_field[x][y]->setColor(col); //else live it as it is } else { BallItem *item = new BallItem(this); item->setColor(col); item->setPos( fieldToPix( FieldPos(x,y) ) ); item->show(); item->setRenderSize(KLinesRenderer::cellExtent()); m_field[x][y] = item; } } m_numFreeCells = m_undoInfo.numFreeCells; m_score = m_undoInfo.score; m_nextColors = m_undoInfo.nextColors; m_selPos = FieldPos(); m_previewItem->setPreviewColors( m_nextColors ); emit scoreChanged(m_score); emit stateChanged(QStringLiteral( "not_undoable" )); } void KLinesScene::drawBackground(QPainter *p, const QRectF&) { QPixmap tile = KLinesRenderer::backgroundTilePixmap(); p->drawPixmap( 0, 0, KLinesRenderer::backgroundPixmap(sceneRect().size().toSize()) ); p->drawPixmap( m_playFieldRect.x(), m_playFieldRect.y(), KLinesRenderer::backgroundBorderPixmap( m_playFieldRect.size() ) ); int startX = m_playFieldRect.x()+m_playFieldBorderSize; int maxX = m_playFieldRect.x()+m_cellSize*FIELD_SIZE; int startY = m_playFieldRect.y()+m_playFieldBorderSize; int maxY = m_playFieldRect.y()+m_cellSize*FIELD_SIZE; for(int x=startX; xdrawPixmap( x, y, tile ); } void KLinesScene::gameOverHandler() { if( m_gameOver ) return; // don't emit twice m_gameOver = true; - qDebug() << "GAME OVER"; + qCDebug(KLINES_LOG) << "GAME OVER"; emit stateChanged(QStringLiteral( "not_undoable" )); //emit enableUndo(false); emit gameOver(m_score); // disable auto-hide m_popupItem->setMessageTimeout(0); m_popupItem->showMessage(i18n("

Game over

"), KGamePopupItem::Center); }