Finally got around to learning enough C++ and Qt to implement the svg
changes.

There is one difference from the suggestions though...
I didn't completely abandon the pixmap support, as I'm not sure how to split
a user-selected image into elements in a Plasma::Svg
Basically what it does now is use a Plasma::Svg for drawing pieces in
identical mode, and swap to a pixmap for custom images.
I made sure it actually resizes the whole puzzle and updates the images on
the pieces instead of doing a scale() transform, so there shouldn't be any
chance of ugliness as it scales.

I hope someone has time to look though this, as it is quite a large patch,
and possibly commit it for me.

Thanks,
Anthony.
Index: fifteen.cpp
===================================================================
--- fifteen.cpp	(revision 854665)
+++ fifteen.cpp	(working copy)
@@ -26,13 +26,10 @@
 #include <QGraphicsSceneMouseEvent>
 #include <QPainter>
 
-#include <KSvgRenderer>
 #include <KDebug>
 
 #include "plasma/animator.h"
 
-static const int SIZE = 48;
-
 Fifteen::Fifteen(QGraphicsItem *parent)
     : QGraphicsWidget(parent)
 {
@@ -41,9 +38,24 @@
   m_splitPixmap = false;
   m_numerals = true;
 
+  m_svg = new Plasma::Svg();
+  m_svg->setImagePath(QLatin1String(":/images/greensquare.svgz"));
+
   shuffle();
 }
 
+Fifteen::~Fifteen()
+{
+  clearPieces();
+  delete m_svg;
+}
+
+void Fifteen::updateGraphics()
+{
+  updatePixmaps();
+  drawPieces();
+}
+
 void Fifteen::clearPieces()
 {
   for (int i = 0; i < 16; ++i)
@@ -74,9 +86,9 @@
     }
     //kDebug() << "rand" << randIndex << rand;
 
-    m_pieces[rand] = new Piece(SIZE, i, this);
+    m_pieces[rand] = new Piece(i, this, m_svg, 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 +105,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();
@@ -155,98 +172,117 @@
 
 void Fifteen::setIdentical()
 {
-  KSvgRenderer renderer(QLatin1String(":/images/greensquare.svgz"));
-  QPixmap pixmap(renderer.defaultSize());
-  pixmap.fill(Qt::transparent);
-  QPainter painter(&pixmap);
-  renderer.render(&painter);
-  painter.end();
-
-  m_pixmap = pixmap;
-
   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;
 
+  // identical images
   if (!m_splitPixmap) {
-    pixmap = m_pixmap.scaled(SIZE, SIZE);
-    m_pixmaps.fill(pixmap);
-  }
-  else {
-    pixmap = m_pixmap.scaled(SIZE * 4, SIZE * 4);
-    int x = 0;
-    int y = 0;
+    m_svg->resize(width, height);
 
-    for (int i = 1; i < 16; ++i) {
-      if ((i - 1) % 4 == 0 && i != 1) {
-        x = 0;
-        y = y + SIZE;
+    for (int i = 0; i < 16; i++) {
+      m_pieces[i]->setSize(QSizeF(width, height));
+      if (m_pieces[i]->getId() != 0) {
+        m_pieces[i]->setSplitPixmap(m_splitPixmap);
       }
-      m_pixmaps[i] = pixmap.copy(x, y, SIZE, SIZE);
-      x += SIZE;
     }
+    return;
   }
 
+  // split pixmap
+  QPixmap pixmap = m_pixmap.scaled(width * 4, height * 4);
+  int x = 0;
+  int y = 0;
+  for (int i = 1; i < 16; ++i) {
+    x = ((i - 1) % 4) * width;
+    y = ((i - 1) / 4) * height;
+    m_pixmaps[i] = pixmap.copy(x, y, width, height);
+  }
+
   for (int i = 0; i < 16; ++i) {
+    m_pieces[i]->setSplitPixmap(m_splitPixmap);
+    m_pieces[i]->setSize(QSizeF(width, height));
     m_pieces[i]->setPixmap(m_pixmaps[m_pieces[i]->getId()]);
   }
 }
 
-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)
@@ -22,6 +22,8 @@
 
 #include <QGraphicsWidget>
 
+#include <Plasma/Svg>
+
 #include "piece.h"
 
 class Fifteen : public QGraphicsWidget
@@ -29,9 +31,11 @@
   Q_OBJECT
   public:
     Fifteen(QGraphicsItem *parent = 0);
+    ~Fifteen();
+    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 +43,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,8 +52,9 @@
 
     QVector<Piece *> m_pieces;
     QVector<QPixmap> m_pixmaps;
-    QGraphicsItem *m_blank;
+    Piece *m_blank;
     bool m_splitPixmap;
+    Plasma::Svg *m_svg;
     QPixmap m_pixmap;
     bool m_numerals;
 };
Index: piece.cpp
===================================================================
--- piece.cpp	(revision 854665)
+++ piece.cpp	(working copy)
@@ -29,12 +29,13 @@
 
 #include <KDebug>
 
-Piece::Piece(int size, int id, QGraphicsItem *parent)
-    : QGraphicsPixmapItem(parent)
+Piece::Piece(int id, QGraphicsItem *parent, Plasma::Svg *svg, int gamePos)
+    : QGraphicsItem(parent)
 {
-  m_size = size;
   m_id = id;
   m_numeral = true;
+  m_gamePos = gamePos;
+  m_svg = svg;
 }
 
 int Piece::getId()
@@ -42,6 +43,41 @@
   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::setSize(QSizeF size)
+{
+  m_size = size;
+}
+
+void Piece::setSplitPixmap(bool splitPixmap)
+{
+  m_splitPixmap = splitPixmap;
+}
+
+void Piece::setPixmap(QPixmap pixmap)
+{
+  m_pixmap = pixmap;
+}
+
 void Piece::showNumeral(bool show)
 {
   m_numeral = show;
@@ -50,16 +86,28 @@
 void Piece::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                   QWidget *widget)
 {
+  Q_UNUSED(option);
+  Q_UNUSED(widget);
+
   if (m_id == 0) {
     return;
   }
 
-  QGraphicsPixmapItem::paint(painter, option, widget);
+  if (m_splitPixmap) {
+    painter->drawPixmap(QPoint(0, 0), m_pixmap);
+  }
+  else {
+    // here we assume that the svg has already been resized correctly by Fifteen::updatePixmaps()
+    m_svg->paint(painter, QPointF(0, 0));
+  }
 
   if (!m_numeral) {
     return;
   }
 
+  int width = m_size.width();
+  int height = m_size.height();
+
   QFont font = painter->font();
   font.setBold(true);
   font.setPointSize(14);
@@ -72,17 +120,22 @@
 
   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);
 }
 
+QRectF Piece::boundingRect() const
+{
+  return QRectF(QPointF(0, 0), m_size);
+}
+
 void Piece::mousePressEvent(QGraphicsSceneMouseEvent *event)
 {
   Q_UNUSED(event);
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)
@@ -23,27 +23,40 @@
 #include <QGraphicsItem>
 #include <QObject>
 
+#include <Plasma/Svg>
 
-class Piece : public QObject, public QGraphicsPixmapItem
+class Piece : public QObject, public QGraphicsItem
 {
   Q_OBJECT
 
   public:
-    Piece(int size, int id, QGraphicsItem * parent);
+    Piece(int id, QGraphicsItem * parent, Plasma::Svg *svg, int gamePos);
     int getId();
     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+    QRectF boundingRect() const;
     void showNumeral(bool show);
+    int getGameX();
+    int getGameY();
+    int getGamePos();
+    void setGamePos(int gamePos);
+    void setSize(QSizeF size);
+    void setSplitPixmap(bool splitPixmap);
+    void setPixmap(QPixmap pixmap);
 
   private:
     int m_id;
-    int m_size;
     bool m_numeral;
+    int m_gamePos;
+    bool m_splitPixmap;
+    QSizeF m_size;
+    Plasma::Svg *m_svg;
+    QPixmap m_pixmap;
 
   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

Reply via email to