Hi, I've been using KDE from trunk for a while now, and I thought I would try to fix a few bugs I noticed in the fifteen puzzle applet (and also add a few new features) as my first contribution, if someone would be kind enough to look over and possibly commit it.
Basically I've taken out the size constant and re-worked the interface to use the width and height of the actual applet for positioning the pieces, the main problem this fixes is the one pixel gaps between pieces, but it also allows the resolution of custom images to be changed on the fly when the applet is resized. I also changed the piecePressed() function to allow the user to click on any tile in the same row or column as the blank tile. There are also a few fixes for being able to have a puzzle with identical tiles and no numerals, and for having a blank custom image. Bear in mind I don't have a lot of C++ or Qt experience (mostly use java) so there might be a few bugs I haven't spotted. Thanks, Anthony.
Index: fifteen.cpp =================================================================== --- fifteen.cpp (revision 854665) +++ fifteen.cpp (working copy) @@ -31,8 +31,6 @@ #include "plasma/animator.h" -static const int SIZE = 48; - Fifteen::Fifteen(QGraphicsItem *parent) : QGraphicsWidget(parent) { @@ -44,6 +42,12 @@ shuffle(); } +void Fifteen::updateGraphics() +{ + updatePixmaps(); + drawPieces(); +} + void Fifteen::clearPieces() { for (int i = 0; i < 16; ++i) @@ -74,9 +78,9 @@ } //kDebug() << "rand" << randIndex << rand; - m_pieces[rand] = new Piece(SIZE, i, this); + m_pieces[rand] = new Piece(i, this, rand); m_pieces[rand]->hide(); - QObject::connect(m_pieces[rand], SIGNAL(pressed(QGraphicsItem*)), this, SLOT(piecePressed(QGraphicsItem*))); + QObject::connect(m_pieces[rand], SIGNAL(pressed(Piece*)), this, SLOT(piecePressed(Piece*))); if (i == 0) { m_blank = m_pieces[rand]; @@ -93,6 +97,11 @@ b = 0; } qSwap(m_pieces[a], m_pieces[b]); + + // also swap the gamePos of the pieces + int aPos = m_pieces[a]->getGamePos(); + m_pieces[a]->setGamePos(m_pieces[b]->getGamePos()); + m_pieces[b]->setGamePos(aPos); } updatePixmaps(); @@ -166,28 +175,31 @@ m_splitPixmap = false; updatePixmaps(); + + // if the pieces are identical then numerals are needed + m_numerals = true; + updateNumerals(); } void Fifteen::updatePixmaps() { QPixmap pixmap; + int width = contentsRect().size().width() / 4; + int height = contentsRect().size().height() / 4; if (!m_splitPixmap) { - pixmap = m_pixmap.scaled(SIZE, SIZE); + pixmap = m_pixmap.scaled(width, height); m_pixmaps.fill(pixmap); } else { - pixmap = m_pixmap.scaled(SIZE * 4, SIZE * 4); + pixmap = m_pixmap.scaled(width * 4, height * 4); int x = 0; int y = 0; for (int i = 1; i < 16; ++i) { - if ((i - 1) % 4 == 0 && i != 1) { - x = 0; - y = y + SIZE; - } - m_pixmaps[i] = pixmap.copy(x, y, SIZE, SIZE); - x += SIZE; + x = ((i - 1) % 4) * width; + y = ((i - 1) / 4) * height; + m_pixmaps[i] = pixmap.copy(x, y, width, height); } } @@ -196,57 +208,74 @@ } } -void Fifteen::piecePressed(QGraphicsItem *item) +void Fifteen::piecePressed(Piece *item) { - if (isAdjacent(item, m_blank)) { - QPointF pos = item->pos(); - Plasma::Animator::self()->moveItem(item, Plasma::Animator::SlideInMovement, m_blank->pos().toPoint()); - m_blank->setPos(pos); + int ix = item->getGameX(); + int iy = item->getGameY(); + int bx = m_blank->getGameX(); + int by = m_blank->getGameY(); + + if (ix == bx && iy != by) { + if (iy > by) { + for (; by < iy; by++) { + // swap the piece at ix,by+1 with blank + swapPieceWithBlank(itemAt(ix, by + 1)); + } + } + else if (iy < by) { + for (; by > iy; by--) { + // swap the piece at ix,by-1 with blank + swapPieceWithBlank(itemAt(ix, by - 1)); + } + } } + else if (iy == by && ix != bx) { + if (ix > bx) { + for (; bx < ix; bx++) { + // swap the piece at bx+1,iy with blank + swapPieceWithBlank(itemAt(bx + 1, iy)); + } + } + else if (ix < bx) { + for (; bx > ix; bx--) { + // swap the piece at bx-1,iy with blank + swapPieceWithBlank(itemAt(bx - 1, iy)); + } + } + } } -bool Fifteen::isAdjacent(QGraphicsItem *a, QGraphicsItem *b) +Piece* Fifteen::itemAt(int gameX, int gameY) { - qreal ax = a->pos().x(); - qreal ay = a->pos().y(); + int gamePos = (gameY * 4) + gameX; + for (int i = 0; i < 16; i++) { + if (m_pieces[i]->getGamePos() == gamePos) { + return m_pieces[i]; + } + } + return NULL; +} - qreal bx = b->pos().x(); - qreal by = b->pos().y(); +void Fifteen::swapPieceWithBlank(Piece *item) +{ + // swap widget positions + QPointF pos = item->pos(); + Plasma::Animator::self()->moveItem(item, Plasma::Animator::SlideInMovement, m_blank->pos().toPoint()); + m_blank->setPos(pos); - /* - qDebug() << "ax:" << ax << "ay:" << ay; - qDebug() << "bx:" << bx << "by:" << by; - */ - - // Left - if (ax + SIZE == bx && ay == by) - return true; - // Right - if (ax - SIZE == bx && ay == by) - return true; - // Above - if (ay + SIZE == by && ax == bx) - return true; - // Below - if (ay - SIZE == by && ax == bx) - return true; - - return false; + // swap game positions + int blankPos = m_blank->getGamePos(); + m_blank->setGamePos(item->getGamePos()); + item->setGamePos(blankPos); } void Fifteen::drawPieces() { - int x = 0; - int y = 0; + int width = contentsRect().size().width() / 4; + int height = contentsRect().size().height() / 4; for (int i = 0; i < 16; ++i) { - if (i % 4 == 0 && i != 0) { - x = 0; - y = y + SIZE; - } - - m_pieces.at(i)->setPos(x, y); - m_pieces.at(i)->show(); - x += SIZE; + m_pieces[i]->setPos(m_pieces[i]->getGameX() * width, m_pieces[i]->getGameY() * height); + m_pieces[i]->show(); } } Index: fifteen.h =================================================================== --- fifteen.h (revision 854665) +++ fifteen.h (working copy) @@ -29,9 +29,10 @@ Q_OBJECT public: Fifteen(QGraphicsItem *parent = 0); + void updateGraphics(); public slots: - void piecePressed(QGraphicsItem *item); + void piecePressed(Piece *item); void setSplitPixmap(const QString& path); void setIdentical(); void setNumerals(bool show); @@ -39,7 +40,8 @@ private: void drawPieces(); - bool isAdjacent(QGraphicsItem *a, QGraphicsItem *b); + Piece* itemAt(int gameX, int gameY); + void swapPieceWithBlank(Piece *item); void updatePixmaps(); void clearPieces(); void updateNumerals(); @@ -47,7 +49,7 @@ QVector<Piece *> m_pieces; QVector<QPixmap> m_pixmaps; - QGraphicsItem *m_blank; + Piece *m_blank; bool m_splitPixmap; QPixmap m_pixmap; bool m_numerals; Index: piece.cpp =================================================================== --- piece.cpp (revision 854665) +++ piece.cpp (working copy) @@ -29,12 +29,12 @@ #include <KDebug> -Piece::Piece(int size, int id, QGraphicsItem *parent) +Piece::Piece(int id, QGraphicsItem *parent, int gamePos) : QGraphicsPixmapItem(parent) { - m_size = size; m_id = id; m_numeral = true; + m_gamePos = gamePos; } int Piece::getId() @@ -42,6 +42,26 @@ return m_id; } +int Piece::getGameX() +{ + return m_gamePos % 4; +} + +int Piece::getGameY() +{ + return m_gamePos / 4; +} + +int Piece::getGamePos() +{ + return m_gamePos; +} + +void Piece::setGamePos(int gamePos) +{ + m_gamePos = gamePos; +} + void Piece::showNumeral(bool show) { m_numeral = show; @@ -60,6 +80,9 @@ return; } + int width = pixmap().width(); + int height = pixmap().height(); + QFont font = painter->font(); font.setBold(true); font.setPointSize(14); @@ -72,14 +95,14 @@ pen.setColor(QColor(0, 0, 0, 90)); painter->setPen(pen); - painter->drawText(((m_size / 2) - m.width(text) / 2) + 2, - ((m_size / 2) + m.ascent() / 2) + 2, + painter->drawText(((width / 2) - m.width(text) / 2) + 2, + ((height / 2) + m.ascent() / 2) + 2, text); pen.setColor(QColor(Qt::white)); painter->setPen(pen); - painter->drawText((m_size / 2) - m.width(text) / 2, - (m_size / 2) + m.ascent() / 2, + painter->drawText((width / 2) - m.width(text) / 2, + (height / 2) + m.ascent() / 2, text); } Index: fifteenPuzzle.cpp =================================================================== --- fifteenPuzzle.cpp (revision 854665) +++ fifteenPuzzle.cpp (working copy) @@ -59,14 +59,14 @@ } updateBoard(); + board->updateGraphics(); } void FifteenPuzzle::constraintsEvent(Plasma::Constraints constraints) { if (constraints & Plasma::SizeConstraint) { - QSizeF size = contentsRect().size(); - board->resetTransform(); - board->scale(size.width() / 192, size.height() / 192); + board->resize(contentsRect().size()); + board->updateGraphics(); } } @@ -98,6 +98,11 @@ imagePath = configDialog->ui.urlRequester->url().path(); showNumerals = configDialog->ui.cb_showNumerals->isChecked(); + // make sure the image actually exists, if not then use plain pieces + if (imagePath.isEmpty()) { + usePlainPieces = true; + } + cg.writeEntry("UsePlainPieces", usePlainPieces); cg.writeEntry("ImagePath", imagePath); cg.writeEntry("ShowNumerals", showNumerals); Index: piece.h =================================================================== --- piece.h (revision 854665) +++ piece.h (working copy) @@ -29,21 +29,25 @@ Q_OBJECT public: - Piece(int size, int id, QGraphicsItem * parent); + Piece(int id, QGraphicsItem * parent, int gamePos); int getId(); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void showNumeral(bool show); + int getGameX(); + int getGameY(); + int getGamePos(); + void setGamePos(int gamePos); private: int m_id; - int m_size; bool m_numeral; + int m_gamePos; protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); signals: - void pressed(QGraphicsItem *item); + void pressed(Piece *item); }; #endif
_______________________________________________ Plasma-devel mailing list Plasma-devel@kde.org https://mail.kde.org/mailman/listinfo/plasma-devel