Commit 31b2e13a authored by Denis Kuplyakov's avatar Denis Kuplyakov

Initial porting to QML implementation

Added QML classes with simple realization to /qml folder.
KReversiChip and KReversiScene classes were deleted.
Added import of declarative libraries and /qml folder install code to
CMakeLists.txt.
KReversiView was rewriten completely to be QML container, now implements
simple user interaction.
Some changes to mainwindow.cpp due to absense of scene class, we will
use only KReversiView now.
Added install instruction to /pics/CMakeLists.txt for *.desktop theme
file.
parent 8996c716
......@@ -11,19 +11,19 @@ if(NOT COMPILING_KDEGAMES)
include_directories(${KDEGAMES_INCLUDE_DIRS} ${KDEGAMES_INCLUDE_DIR}/highscore ${KDE4_INCLUDES} ${QDBUS_INCLUDE_DIRS})
endif(NOT COMPILING_KDEGAMES)
find_package(KDeclarative REQUIRED)
add_subdirectory( pics )
add_subdirectory( sounds )
add_subdirectory( icons )
add_subdirectory( doc )
include_directories( ${CMAKE_SOURCE_DIR}/libkdegames/highscore)
include_directories( ${CMAKE_SOURCE_DIR}/libkdegames/highscore )
########### next target ###############
set(kreversi_SRCS
kreversichip.cpp
kreversigame.cpp
kreversiscene.cpp
kreversiview.cpp
Engine.cpp
highscores.cpp
......@@ -35,7 +35,8 @@ kde4_add_kcfg_files(kreversi_SRCS preferences.kcfgc)
kde4_add_app_icon(kreversi_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/hi*-app-kreversi.png")
kde4_add_executable(kreversi ${kreversi_SRCS})
target_link_libraries(kreversi ${KDE4_KDEUI_LIBS} kdegames)
target_link_libraries(kreversi kdegames ${KDE4_KDEUI_LIBS}
${QT_QTXML_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY} ${KDECLARATIVE_LIBRARIES})
install(TARGETS kreversi ${INSTALL_TARGETS_DEFAULT_ARGS} )
########### install files ###############
......@@ -43,3 +44,4 @@ install(TARGETS kreversi ${INSTALL_TARGETS_DEFAULT_ARGS} )
install( PROGRAMS kreversi.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
#install( FILES kreversi.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
install( FILES kreversiui.rc DESTINATION ${DATA_INSTALL_DIR}/kreversi )
install( DIRECTORY qml DESTINATION ${DATA_INSTALL_DIR}/kreversi )
/*******************************************************************
*
* Copyright 2006 Dmitry Suzdalev <dimsuz@gmail.com>
* Copyright 2010 Brian Croom <brian.s.croom@gmail.com>
*
* This file is part of the KDE project "KReversi"
*
* KReversi 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.
*
* KReversi 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 KReversi; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "kreversichip.h"
#include <QPainter>
#include <QPixmap>
#include <QImage>
#include <QGraphicsScene>
#include <kdebug.h>
QPixmap* KReversiChip::s_lastMoveMarker;
KReversiChip::KReversiChip( KGameRenderer* renderer, ChipColor color,
const QString& chipsPrefix, int size, QGraphicsScene* scene )
: KGameRenderedItem( renderer, chipsPrefix ), m_color(color), m_curFrame(0)
{
scene->addItem(this);
setRenderSize( QSize(size, size) );
setColor(m_color);
}
void KReversiChip::setChipPrefix( const QString& chipPrefix )
{
setSpriteKey( chipPrefix );
}
void KReversiChip::setChipSize( int newSize )
{
setRenderSize( QSize(newSize, newSize) );
}
void KReversiChip::setColor( ChipColor color )
{
m_color = color;
setFrame(currentFrameNumber());
}
bool KReversiChip::nextFrame()
{
setFrame(currentFrameNumber());
m_curFrame++;
if(m_curFrame == frameCount())
{
m_curFrame = 0;
return true;
}
return false;
}
void KReversiChip::showLastMoveMarker(bool show)
{
QList<QGraphicsItem*> children = childItems();
qDeleteAll(children);
if(show)
{
QGraphicsItem* marker = new QGraphicsPixmapItem(*s_lastMoveMarker, this);
marker->setFlag(QGraphicsItem::ItemStacksBehindParent);
}
}
void KReversiChip::initLastMoveMarker( int size )
{
if(s_lastMoveMarker != NULL)
delete s_lastMoveMarker;
s_lastMoveMarker = new QPixmap(size, size);
s_lastMoveMarker->fill(Qt::transparent);
QPainter p(s_lastMoveMarker);
qreal offset = size*.02;
p.fillRect(QRectF(offset, offset, size-(offset*4), size-(offset*4)), Qt::gray );
p.end();
}
int KReversiChip::currentFrameNumber() const
{
if( m_color == White )
return frameCount() - m_curFrame;
else if( m_color == Black )
return m_curFrame+1;
else return -1;
}
/*******************************************************************
*
* Copyright 2006 Dmitry Suzdalev <dimsuz@gmail.com>
* Copyright 2010 Brian Croom <brian.s.croom@gmail.com>
*
* This file is part of the KDE project "KReversi"
*
* KReversi 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.
*
* KReversi 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 KReversi; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#ifndef KREVERSI_CHIP_H
#define KREVERSI_CHIP_H
#include <KGameRenderedItem>
#include <KGameRenderer>
#include "commondefs.h"
class QGraphicsScene;
class KReversiChip : public KGameRenderedItem
{
public:
KReversiChip( KGameRenderer* renderer, ChipColor color,
const QString& chipsPrefix, int size, QGraphicsScene* scene );
void setChipPrefix( const QString& chipPrefix );
void setChipSize( int newSize );
void setColor( ChipColor color );
void setRowCol( int row, int col ) { m_row = row; m_col = col; }
int row() const { return m_row; }
int col() const { return m_col; }
ChipColor color() const { return m_color; }
/**
* Called during animation
* NOTE: it doesn't change the color of the chip when
* animation finishes - you've to do it yourself
* @return whether the animation sequence is finished
*/
bool nextFrame();
/**
* Toggles showing of little marker on top of the chip.
* It is used to indicate last-made move
*/
void showLastMoveMarker(bool show);
/**
* Render the pixmap for marking the last move
*/
static void initLastMoveMarker( int size );
enum { Type = UserType + 1 };
virtual int type() const { return Type; }
private:
int currentFrameNumber() const;
ChipColor m_color;
/**
* Current animation frame
*/
int m_curFrame;
int m_row;
int m_col;
static QPixmap* s_lastMoveMarker;
};
#endif
/*******************************************************************
*
* Copyright 2006-2007 Dmitry Suzdalev <dimsuz@gmail.com>
* Copyright 2010 Brian Croom <brian.s.croom@gmail.com>
*
* This file is part of the KDE project "KReversi"
*
* KReversi 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.
*
* KReversi 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 KReversi; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
********************************************************************/
#include "kreversiscene.h"
#include "kreversigame.h"
#include "kreversichip.h"
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QTimer>
#include <kdebug.h>
#include <KLocale>
#include <KStandardDirs>
#include <KGamePopupItem>
#include <KgTheme>
static KgTheme* theme()
{
KgTheme* theme = new KgTheme("pics/default_theme.desktop");
theme->setGraphicsPath(KStandardDirs::locate("appdata", "pics/default_theme.svgz"));
return theme;
}
KReversiScene::KReversiScene( KReversiGame* game , const QString& chipsPrefix )
: m_renderer(theme()), m_game(0),
m_pendingNewGame(0), m_hintChip(0), m_lastMoveChip(0), m_timerDelay(25),
m_showingHint(false), m_demoMode(false), m_showLastMove(false), m_showPossibleMoves(false),
m_showLabels(false)
{
m_messageItem = new KGamePopupItem();
m_messageItem->setMessageOpacity(0.9);
addItem(m_messageItem);
m_renderer.setFrameBaseIndex(1);
m_curCellSize = qMin(width(), height()) / 10;
KReversiChip::initLastMoveMarker(m_curCellSize);
setChipsPrefix(chipsPrefix);
m_animTimer = new QTimer(this);
connect(m_animTimer, SIGNAL(timeout()), SLOT(slotAnimationStep()));
setGame(game);
}
void KReversiScene::resizeScene( int width, int height )
{
kDebug() << "resizeScene" << width << "x" << height;
setSceneRect( 0, 0, width, height );
int size = qMin(width, height);
m_boardRect.setRect( width/2 - size/2, height/2 - size/2, size, size );
m_curCellSize = size / 10.0;
if(m_lastMoveChip)
m_lastMoveChip->showLastMoveMarker(false);
KReversiChip::initLastMoveMarker(m_curCellSize);
if(m_lastMoveChip && m_showLastMove)
m_lastMoveChip->showLastMoveMarker(true);
// adopt new chip size
QList<QGraphicsItem*> allItems = items();
KReversiChip *chip = 0;
foreach( QGraphicsItem* item, allItems )
{
chip = qgraphicsitem_cast<KReversiChip*>(item);
if( chip )
{
// adjust pos to new one
chip->setPos( cellTopLeft( chip->row(), chip->col() ) );
chip->setChipSize( (int)m_curCellSize );
}
}
foreach( KGameRenderedItem* item, m_possibleMovesItems )
item->setRenderSize(QSize(m_curCellSize, m_curCellSize));
displayLastAndPossibleMoves();
}
void KReversiScene::setChipsPrefix( const QString& chipsPrefix )
{
m_chipsPrefix = chipsPrefix;
if(m_game)
{
QList<QGraphicsItem*> allItems = items(m_boardRect);
KReversiChip *chip = 0;
foreach( QGraphicsItem* item, allItems )
{
chip = qgraphicsitem_cast<KReversiChip*>(item);
if( chip )
chip->setChipPrefix( chipsPrefix );
}
if(m_hintChip)
m_hintChip->setChipPrefix( chipsPrefix );
}
}
void KReversiScene::setShowBoardLabels( bool show )
{
m_showLabels = show;
}
void KReversiScene::setGame( KReversiGame* game )
{
// if animation is running or we are thinking save this game in pending var.
// It will be made current animation slot will get called
// @see setNewGameObject and @see slotAnimationStep
//
// NOTE: all this magic is needed for game not to crash while pressing new game:
// if we'd simply set the new object right away and deleted an old one, slotAnimationStep
// might got called *after* this, trying to do smth with already deleted object.
// For example see BUG #154946
// So we postpone the setting && deletion...
if( m_animTimer->isActive() || ( m_game && m_game->isThinking() ) )
m_pendingNewGame = game;
else
setNewGameObject( game );
}
void KReversiScene::setNewGameObject( KReversiGame* game )
{
m_animTimer->stop();
// disconnect signals from previous game if it exists,
// we are not interested in them anymore
if( m_game )
{
disconnect( m_game, SIGNAL(boardChanged()), this, SLOT(updateBoard()) );
disconnect( m_game, SIGNAL(moveFinished()), this, SLOT(slotGameMoveFinished()) );
disconnect( m_game, SIGNAL(gameOver()), this, SLOT(slotGameOver()) );
disconnect( m_game, SIGNAL(computerCantMove()), this, SLOT(slotComputerCantMove()) );
disconnect( m_game, SIGNAL(playerCantMove()), this, SLOT(slotPlayerCantMove()) );
}
// delete old object
delete m_game;
m_game = game;
m_pendingNewGame = 0; // it's made official now ;)
connect( m_game, SIGNAL(boardChanged()), SLOT(updateBoard()) );
connect( m_game, SIGNAL(moveFinished()), SLOT(slotGameMoveFinished()) );
connect( m_game, SIGNAL(gameOver()), SLOT(slotGameOver()) );
connect( m_game, SIGNAL(computerCantMove()), SLOT(slotComputerCantMove()) );
connect( m_game, SIGNAL(playerCantMove()), SLOT(slotPlayerCantMove()) );
// this will remove all chips left from previous game
QList<QGraphicsItem*> allItems = items();
KReversiChip* chip;
foreach( QGraphicsItem* item, allItems )
{
chip = qgraphicsitem_cast<KReversiChip*>(item);
if(chip)
{
removeItem( chip );
delete chip;
}
}
foreach( QGraphicsItem* item, m_possibleMovesItems )
{
removeItem( item );
delete item;
}
m_possibleMovesItems.clear();
m_hintChip = 0; // it was deleted above if it was shown
m_showingHint = false;
m_lastMoveChip = 0;
m_demoMode = false;
updateBoard();
}
void KReversiScene::setShowLastMove( bool show )
{
m_showLastMove = show;
if(show)
displayLastAndPossibleMoves();
else
{
if(m_lastMoveChip)
m_lastMoveChip->showLastMoveMarker(false);
}
}
void KReversiScene::setShowLegalMoves( bool show )
{
m_showPossibleMoves = show;
if(show)
displayLastAndPossibleMoves();
else
{
// NOTE: or delete?
foreach( KGameRenderedItem* item, m_possibleMovesItems )
item->hide();
}
}
void KReversiScene::setAnimationSpeed(int speed)
{
if( speed == 0 ) // slow
m_timerDelay = 40;
else if( speed == 1 ) // normal
m_timerDelay = 25;
else if( speed == 2 ) // fast
m_timerDelay = 15;
}
bool KReversiScene::isBusy() const
{
return m_animTimer->isActive();
}
void KReversiScene::updateBoard()
{
for(int row=0; row<8; ++row)
for(int col=0; col<8; ++col )
{
ChipColor color = m_game->chipColorAt( row, col );
if( color != NoColor )
{
// if there's a chip, just change it color
// otherwise create new
KReversiChip *chip = static_cast<KReversiChip*>(itemAt( cellCenter(row, col) ));
if( chip != 0 )
{
if( chip->color() != color )
{
//kDebug() << "Found item at (" << row << "," << col << "). Setting its color.";
chip->setColor( color );
}
}
else
{
//kDebug() << "No item at (" << row << "," << col << "). Creating.";
chip = new KReversiChip( &m_renderer, color, m_chipsPrefix, m_curCellSize, this );
chip->setPos( cellTopLeft(row, col) );
chip->setRowCol( row, col );
}
}
else
{
// this if-branch happens on undos
// deleting only KReversiChips
// (for other QGItems cast will return 0 causing "delete" to be no-op)
KReversiChip *chip = qgraphicsitem_cast<KReversiChip*>(itemAt( cellCenter(row, col) ));
delete chip;
}
}
m_lastMoveChip = 0;
displayLastAndPossibleMoves();
update();
}
void KReversiScene::toggleDemoMode( bool toggle )
{
if( m_game->isGameOver() )
return;
m_demoMode = toggle;
stopHintAnimation();
// if we are currently waiting for user mouse input and not animating,
// let's do the turn right now!
if( !m_game->isComputersTurn() && !m_animTimer->isActive() )
m_game->startNextTurn(m_demoMode);
}
void KReversiScene::slotGameMoveFinished()
{
// hide shown legal moves
if( m_showPossibleMoves )
{
foreach( KGameRenderedItem* item, m_possibleMovesItems )
item->hide();
}
m_changedChips = m_game->changedChips();
// create an item that was placed by player
// by convention it will be the first in the list of changed items
KReversiPos move = m_changedChips.takeFirst();
KReversiChip *newchip = new KReversiChip( &m_renderer, move.color, m_chipsPrefix, m_curCellSize, this );
newchip->setPos( cellTopLeft( move.row, move.col ) );
newchip->setRowCol( move.row, move.col );
// start animation
if( m_lastMoveChip )
m_lastMoveChip->showLastMoveMarker( false );
m_animTimer->start(m_timerDelay);
}
void KReversiScene::slotAnimationStep()
{
if( m_pendingNewGame != 0 )
{
// aha! we have new game waiting for us
m_animTimer->stop();
setNewGameObject( m_pendingNewGame );
return;
}
if(m_changedChips.isEmpty() && !m_showingHint)
{
m_animTimer->stop();
emit moveFinished();
return;
}
if( !m_showingHint )
{ // we're animating chips move
KReversiPos move = m_changedChips.at(0);
QPointF pos = cellCenter(move.row, move.col);
KReversiChip *chip = qgraphicsitem_cast<KReversiChip*>(itemAt(pos));
if (!chip)
{
kDebug() << "looks like pos" << move.row << "," << move.col << "is hovered by message item, searching below";
QList<QGraphicsItem*> allItemsAtPos = items(pos);
foreach (QGraphicsItem* item, allItemsAtPos)
{
chip = qgraphicsitem_cast<KReversiChip*>(item);
if (chip)
break;
}
kDebug() << (chip ? "found it!" : "not found... skipping all animation frames and hoping for the best");
}
bool animFinished = chip ? chip->nextFrame() : true /* skip frames */;
if(animFinished)
{
chip->setColor( move.color );
m_changedChips.removeFirst(); // we finished animating it
if(m_changedChips.count() == 0)
{
// whole animation sequence finished. On to next turn!
m_animTimer->stop();
emit moveFinished();
displayLastAndPossibleMoves();
m_game->startNextTurn(m_demoMode);
}
}
}
else
{ // we're just showing hint to the user
m_hintChip->setVisible( !m_hintChip->isVisible() );
update(m_hintChip->sceneBoundingRect());
}
}
void KReversiScene::displayLastAndPossibleMoves()
{
// ==== Show What Last Move Was ====
if( m_showLastMove )
{
KReversiPos lastPos = m_game->getLastMove();
m_lastMoveChip = qgraphicsitem_cast<KReversiChip*>(itemAt(cellCenter(lastPos.row, lastPos.col)));
if(m_lastMoveChip)
m_lastMoveChip->showLastMoveMarker(true);
}
// ==== Show Possible Moves ====
if( m_showPossibleMoves && !m_game->isComputersTurn() )
{
//hide currently displayed if any
foreach( KGameRenderedItem* item, m_possibleMovesItems )
item->hide();
PosList l = m_game->possibleMoves();
// if m_possibleMovesItems contains less rects then there are items in l
// lets fill it with additional rects.
// Else we'll just reuse rects that we already have.
// NOTE: maybe make m_possibleMovesItems a QVector and simply do resize()?
while( m_possibleMovesItems.count() < l.count() )
{
KGameRenderedItem *item = new KGameRenderedItem( &m_renderer, QLatin1String( "move_hint" ) );
addItem(item);
item->setRenderSize( QSize(m_curCellSize, m_curCellSize) );
item->setZValue(-1);
m_possibleMovesItems.append( item );
}