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