Blob Blame History Raw
From dba803039faae82807b1504f25bd5a8cfa4036d2 Mon Sep 17 00:00:00 2001
From: Albert Astals Cid <aacid@kde.org>
Date: Wed, 13 Aug 2014 10:40:56 +0200
Subject: [PATCH 2/2] Don't use cursor to set the dragged item

On some systems it causes glitches as they don't support complex cursors

BUGS: 237700
---
 action.cpp     | 30 +++++++++++--------
 action.h       |  6 ++--
 main.cpp       |  2 +-
 playground.cpp | 95 +++++++++++++++++++++++++++++++++++++++-------------------
 playground.h   |  7 +++--
 todraw.cpp     | 19 ++++++------
 todraw.h       |  7 +++--
 7 files changed, 105 insertions(+), 61 deletions(-)

diff --git a/action.cpp b/action.cpp
index 50583ba..92675b9 100644
--- a/action.cpp
+++ b/action.cpp
@@ -17,8 +17,10 @@
 #include "todraw.h"
 
 ActionAdd::ActionAdd(ToDraw *item, QGraphicsScene *scene)
- : m_item(item), m_scene(scene), m_done(false)
+ : m_item(item), m_scene(scene), m_done(false), m_shouldAdd(false)
 {
+	// First m_shouldAdd is false since it was already added
+	// in the playground code
 }
 
 ActionAdd::~ActionAdd()
@@ -28,8 +30,11 @@ ActionAdd::~ActionAdd()
 
 void ActionAdd::redo()
 {
-	m_scene->addItem(m_item);
+	if (m_shouldAdd) {
+		m_scene->addItem(m_item);
+	}
 	m_done = true;
+	m_shouldAdd = true;
 }
 
 void ActionAdd::undo()
@@ -52,11 +57,8 @@ ActionRemove::~ActionRemove()
 
 void ActionRemove::redo()
 {
-	if (!m_done)
-	{
-		m_scene->removeItem(m_item);
-		m_done = true;
-	}
+	m_scene->removeItem(m_item);
+	m_done = true;
 }
 
 void ActionRemove::undo()
@@ -67,23 +69,25 @@ void ActionRemove::undo()
 
 
 
-ActionMove::ActionMove(ToDraw *item, const QPointF &pos, int zValue, QGraphicsScene *scene)
+ActionMove::ActionMove(ToDraw *item, const QPointF &oldPos, int zValue, QGraphicsScene *scene)
  : m_item(item), m_zValue(zValue), m_scene(scene)
 {
-	m_pos = QPointF(pos.x() / scene->width(), pos.y() / scene->height());
+	m_oldPos = QPointF(oldPos.x() / scene->width(), oldPos.y() / scene->height());
+	m_newPos = QPointF(m_item->pos().x() / scene->width(), m_item->pos().y() / scene->height());
 }
 
 void ActionMove::redo()
 {
-	QPointF pos = m_item->pos();
 	qreal zValue = m_item->zValue();
-	m_item->setPos(m_pos.x() * m_scene->width(), m_pos.y() * m_scene->height());
+	m_item->setPos(m_newPos.x() * m_scene->width(), m_newPos.y() * m_scene->height());
 	m_item->setZValue(m_zValue);
-	m_pos = QPointF(pos.x() / m_scene->width(), pos.y() / m_scene->height());
 	m_zValue = zValue;
 }
 
 void ActionMove::undo()
 {
-	redo();
+	qreal zValue = m_item->zValue();
+	m_item->setPos(m_oldPos.x() * m_scene->width(), m_oldPos.y() * m_scene->height());
+	m_item->setZValue(m_zValue);
+	m_zValue = zValue;
 }
diff --git a/action.h b/action.h
index 9bdcc55..0d868d2 100644
--- a/action.h
+++ b/action.h
@@ -33,6 +33,7 @@ class ActionAdd : public QUndoCommand
 		ToDraw *m_item;
 		QGraphicsScene *m_scene;
 		bool m_done;
+		bool m_shouldAdd;
 };
 
 
@@ -54,14 +55,15 @@ class ActionRemove : public QUndoCommand
 class ActionMove : public QUndoCommand
 {
 	public:
-		ActionMove(ToDraw *item, const QPointF &pos, int zValue, QGraphicsScene *scene);
+		ActionMove(ToDraw *item, const QPointF &oldPos, int zValue, QGraphicsScene *scene);
 		
 		void redo();
 		void undo();
 	
 	private:
 		ToDraw *m_item;
-		QPointF m_pos;
+		QPointF m_oldPos;
+		QPointF m_newPos;
 		qreal m_zValue;
 		QGraphicsScene *m_scene;
 };
diff --git a/main.cpp b/main.cpp
index 13beec8..1881432 100644
--- a/main.cpp
+++ b/main.cpp
@@ -20,7 +20,7 @@
 static const KLocalizedString description = ki18n("Potato game for kids");
 static const KLocalizedString text = ki18n("A program original by <email address='%1'>√Čric Bischoff</email>\nand John Calhoun.\n\nThis program is dedicated to my daughter Sunniva.").subs(QLatin1String("ebischoff@nerim.net"));
 
-static const char version[] = "0.8.0";
+static const char version[] = "0.9.0";
 
 // Main function
 int main(int argc, char *argv[])
diff --git a/playground.cpp b/playground.cpp
index cea940c..59986bf 100644
--- a/playground.cpp
+++ b/playground.cpp
@@ -43,13 +43,14 @@ static const char *saveGameText = "KTuberlingSaveGameV4";
 
 // Constructor
 PlayGround::PlayGround(TopLevel *parent)
-    : QGraphicsView(parent), m_dragItem(0), m_nextZValue(1), m_lockAspect(false)
+    : QGraphicsView(parent), m_newItem(0), m_dragItem(0), m_nextZValue(1), m_lockAspect(false)
 {
   m_topLevel = parent;
   setFrameStyle(QFrame::NoFrame);
   setOptimizationFlag(QGraphicsView::DontSavePainterState, true); // all items here save the painter state
   setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
   setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+  setMouseTracking(true);
 }
 
 // Destructor
@@ -138,7 +139,7 @@ void PlayGround::mousePressEvent(QMouseEvent *event)
   if (event->button() != Qt::LeftButton) return;
 
   if (m_dragItem) placeDraggedItem(event->pos());
-  else if (!m_pickedElement.isNull()) placeNewItem(event->pos());
+  else if (m_newItem) placeNewItem(event->pos());
   else
   {
     // see if the user clicked on the warehouse of items
@@ -156,14 +157,24 @@ void PlayGround::mousePressEvent(QMouseEvent *event)
 
     if (!foundElem.isNull())
     {
-      bounds = mapFromScene(bounds).boundingRect();
-      double objectScale = m_objectsNameRatio.value(foundElem);
-      int width = qRound(bounds.width() * objectScale);
-      int height = qRound(bounds.height() * objectScale);
+      const double objectScale = m_objectsNameRatio.value(foundElem);
+      const QSizeF elementSize = m_SvgRenderer.boundsOnElement(foundElem).size() * objectScale;
+      QPointF itemPos = mapToScene(event->pos());
+      itemPos -= QPointF(elementSize.width()/2, elementSize.height()/2);
 
       m_topLevel->playSound(m_objectsNameSound.value(foundElem));
-      setCursor(QCursor(toPixmap(foundElem, width, height, &m_SvgRenderer)));
-      m_pickedElement = foundElem;
+
+      m_newItem = new ToDraw;
+      m_newItem->setBeingDragged(true);
+      m_newItem->setPos(clipPos(itemPos, m_newItem));
+      m_newItem->setSharedRenderer(&m_SvgRenderer);
+      m_newItem->setElementId(foundElem);
+      m_newItem->setZValue(m_nextZValue);
+      m_nextZValue++;
+      m_newItem->scale(objectScale, objectScale);
+
+      scene()->addItem(m_newItem);
+      setCursor(Qt::BlankCursor);
     }
     else
     {
@@ -172,25 +183,56 @@ void PlayGround::mousePressEvent(QMouseEvent *event)
       m_dragItem = qgraphicsitem_cast<ToDraw*>(dragItem);
       if (m_dragItem)
       {
-        QRectF rect = m_dragItem->unclippedRect();
-        rect = m_dragItem->transform().mapRect(rect);
-        QPolygon poly = mapFromScene(rect);
-        QSize size = poly.boundingRect().size(); // the polygon should be a rect...
         QString elem = m_dragItem->elementId();
-        setCursor(QCursor(toPixmap(elem, size.width(), size.height(), &m_SvgRenderer)));
 
-        scene()->removeItem(m_dragItem);
         m_topLevel->playSound(m_objectsNameSound.value(elem));
+        setCursor(Qt::BlankCursor);
+        m_dragItem->setBeingDragged(true);
+        m_itemDraggedPos = m_dragItem->pos();
+
+        const QSizeF elementSize = m_dragItem->transform().mapRect(m_dragItem->unclippedRect()).size();
+        QPointF itemPos = mapToScene(event->pos());
+        itemPos -= QPointF(elementSize.width()/2, elementSize.height()/2);
+        m_dragItem->setPos(clipPos(itemPos, m_dragItem));
       }
     }
   }
 }
 
+void PlayGround::mouseMoveEvent(QMouseEvent *event)
+{
+  if (m_newItem) {
+    QPointF itemPos = mapToScene(event->pos());
+    const QSizeF elementSize = m_newItem->transform().mapRect(m_newItem->unclippedRect()).size();
+    itemPos -= QPointF(elementSize.width()/2, elementSize.height()/2);
+
+    m_newItem->setPos(clipPos(itemPos, m_newItem));
+  } else if (m_dragItem) {
+    QPointF itemPos = mapToScene(event->pos());
+    const QSizeF elementSize = m_dragItem->transform().mapRect(m_dragItem->unclippedRect()).size();
+    itemPos -= QPointF(elementSize.width()/2, elementSize.height()/2);
+
+    m_dragItem->setPos(clipPos(itemPos, m_dragItem));
+  }
+}
+
 bool PlayGround::insideBackground(const QSizeF &size, const QPointF &pos) const
 {
   return backgroundRect().intersects(QRectF(pos, size));
 }
 
+QPointF PlayGround::clipPos(const QPointF &p, ToDraw *item) const
+{
+  const double objectScale = m_objectsNameRatio.value(item->elementId());
+
+  QPointF res = p;
+  res.setX(qMax(0., res.x()));
+  res.setY(qMax(0., res.y()));
+  res.setX(qMin(m_SvgRenderer.defaultSize().width() - item->boundingRect().width() * objectScale, res.x()));
+  res.setY(qMin(m_SvgRenderer.defaultSize().height()- item->boundingRect().height() * objectScale, res.y()));
+  return res;
+}
+
 QRectF PlayGround::backgroundRect() const
 {
   return m_SvgRenderer.boundsOnElement(QLatin1String( "background" ));
@@ -204,8 +246,8 @@ void PlayGround::placeDraggedItem(const QPoint &pos)
 
   if (insideBackground(elementSize, itemPos))
   {
-    scene()->addItem(m_dragItem);
-    undoStack()->push(new ActionMove(m_dragItem, itemPos, m_nextZValue, scene()));
+    m_dragItem->setBeingDragged(false);
+    undoStack()->push(new ActionMove(m_dragItem, m_itemDraggedPos, m_nextZValue, scene()));
     m_nextZValue++;
   }
   else
@@ -219,27 +261,18 @@ void PlayGround::placeDraggedItem(const QPoint &pos)
 
 void PlayGround::placeNewItem(const QPoint &pos)
 {
-  double objectScale = m_objectsNameRatio.value(m_pickedElement);
-  QSizeF elementSize = m_SvgRenderer.boundsOnElement(m_pickedElement).size() * objectScale;
+  const QSizeF elementSize = m_newItem->transform().mapRect(m_newItem->unclippedRect()).size();
   QPointF itemPos = mapToScene(pos);
-
   itemPos -= QPointF(elementSize.width()/2, elementSize.height()/2);
-
   if (insideBackground(elementSize, itemPos))
   {
-    ToDraw *item = new ToDraw;
-    item->setElementId(m_pickedElement);
-    item->setPos(itemPos);
-    item->setSharedRenderer(&m_SvgRenderer);
-    item->setZValue(m_nextZValue);
-    m_nextZValue++;
-    item->scale(objectScale, objectScale);
-
-    undoStack()->push(new ActionAdd(item, scene()));
+    m_newItem->setBeingDragged(false);
+    undoStack()->push(new ActionAdd(m_newItem, scene()));
+  } else {
+    m_newItem->deleteLater();
   }
-
+  m_newItem = 0;
   setCursor(QCursor());
-  m_pickedElement.clear();
 }
 
 void PlayGround::recenterView()
diff --git a/playground.h b/playground.h
index 3340118..d0969c4 100644
--- a/playground.h
+++ b/playground.h
@@ -59,9 +59,11 @@ public Q_SLOTS:
 protected:
 
   void mousePressEvent(QMouseEvent *event);
+  void mouseMoveEvent(QMouseEvent *event);
   void resizeEvent(QResizeEvent *event);
 
 private:
+  QPointF clipPos(const QPointF &p, ToDraw *item) const;
   QRectF backgroundRect() const;
   bool insideBackground(const QSizeF &size, const QPointF &pos) const;
   void placeDraggedItem(const QPoint &pos);
@@ -79,8 +81,9 @@ private:
 
   TopLevel *m_topLevel;					// Top-level window
 
-  QString m_pickedElement;				// the SVG element the cursor is
-  ToDraw *m_dragItem;					// the item we are dragging
+  QPointF m_itemDraggedPos;
+  ToDraw *m_newItem;				    // the new item we are moving
+  ToDraw *m_dragItem;					// the existing item we are dragging
   QSvgRenderer m_SvgRenderer;				// the SVG renderer
   int m_nextZValue;					// the next Z value to use
 
diff --git a/todraw.cpp b/todraw.cpp
index 00da46f..136e120 100644
--- a/todraw.cpp
+++ b/todraw.cpp
@@ -30,17 +30,9 @@ static QImage toImage(const QString &element, int width, int height, QSvgRendere
   return img;
 }
 
-QPixmap toPixmap(const QString &element, int width, int height, QSvgRenderer *renderer)
-{
-  QPixmap pix(width, height);
-  pix.fill(Qt::transparent);
-  QPainter p2(&pix);
-  renderer->render(&p2, element);
-  p2.end();
-  return pix;
-}
 
 ToDraw::ToDraw()
+ : m_beingDragged(false)
 {
 }
 
@@ -78,6 +70,9 @@ QRectF ToDraw::unclippedRect() const
 
 QRectF ToDraw::clippedRectAt(const QPointF &somePos) const
 {
+  if (m_beingDragged)
+    return unclippedRect();
+
   QRectF backgroundRect = renderer()->boundsOnElement(QLatin1String( "background" ));
   backgroundRect.translate(-somePos);
   backgroundRect = transform().inverted().map(backgroundRect).boundingRect();
@@ -85,6 +80,12 @@ QRectF ToDraw::clippedRectAt(const QPointF &somePos) const
   return unclippedRect().intersected(backgroundRect);
 }
 
+void ToDraw::setBeingDragged(bool dragged)
+{
+    prepareGeometryChange();
+    m_beingDragged = dragged;
+}
+
 QRectF ToDraw::boundingRect() const
 {
   return clippedRectAt(pos());
diff --git a/todraw.h b/todraw.h
index 6035588..c632318 100644
--- a/todraw.h
+++ b/todraw.h
@@ -15,9 +15,6 @@
 
 #include <QGraphicsSvgItem>
 
-
-QPixmap toPixmap(const QString &element, int width, int height, QSvgRenderer *renderer);
-
 class ToDraw : public QGraphicsSvgItem
 {
   public:
@@ -34,11 +31,15 @@ class ToDraw : public QGraphicsSvgItem
     QRectF boundingRect() const;
     QRectF unclippedRect() const;
 
+    void setBeingDragged(bool dragged);
+
   protected:
     QVariant itemChange(GraphicsItemChange change, const QVariant &value);
   
   private:
     QRectF clippedRectAt(const QPointF &somePos) const;
+
+    bool m_beingDragged;
 };
 
 #endif
-- 
1.9.3