From a5c08988f535162f1404077471b7cd6aa150d2a1 Mon Sep 17 00:00:00 2001 From: MPIBR-kretschmerf Date: Tue, 25 Apr 2017 16:14:46 +0200 Subject: [PATCH] Added roi resize with mouse --- NotifyingQGraphicsRectItem.h | 20 --------- ResizeHelper.cpp | 81 ++++++++++++++++++++++++++++++++++++ ResizeHelper.h | 35 ++++++++++++++++ ResizeTraits.cpp | 39 +++++++++++++++++ ResizeTraits.h | 15 +++++++ 5 files changed, 170 insertions(+), 20 deletions(-) delete mode 100644 NotifyingQGraphicsRectItem.h create mode 100644 ResizeHelper.cpp create mode 100644 ResizeHelper.h create mode 100644 ResizeTraits.cpp create mode 100644 ResizeTraits.h diff --git a/NotifyingQGraphicsRectItem.h b/NotifyingQGraphicsRectItem.h deleted file mode 100644 index 35b9c79..0000000 --- a/NotifyingQGraphicsRectItem.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef NOTIFYINGQGRAPHICSRECTITEM_H -#define NOTIFYINGQGRAPHICSRECTITEM_H - -#include - -class NotifyingQGraphicsRectItem : public QObject, public QGraphicsRectItem -{ - Q_OBJECT -protected: - QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { - if (change == ItemPositionHasChanged){ - emit itemMoved(); - } - return QGraphicsRectItem::itemChange(change, value); - } -signals: - void itemMoved(); -}; - -#endif // NOTIFYINGQGRAPHICSRECTITEM_H diff --git a/ResizeHelper.cpp b/ResizeHelper.cpp new file mode 100644 index 0000000..cea69f7 --- /dev/null +++ b/ResizeHelper.cpp @@ -0,0 +1,81 @@ +#include "ResizeHelper.h" + +/// The set of edges intersecting a rectangle of given pen width +QFlags edgesAt(const QPointF & p, const QRectF & r, qreal w) { + QFlags edges; + auto hw = w / 2.0; + if (QRectF(r.x()-hw, r.y()-hw, w, r.height()+w).contains(p)) edges |= Qt::LeftEdge; + if (QRectF(r.x()+r.width()-hw, r.y()-hw, w, r.height()+w).contains(p)) edges |= Qt::RightEdge; + if (QRectF(r.x()-hw, r.y()-hw, r.width()+w, w).contains(p)) edges |= Qt::TopEdge; + if (QRectF(r.x()-hw, r.y()+r.height()-hw, r.width()+w, w).contains(p)) edges |= Qt::BottomEdge; + return edges; +} + +ResizeHelper::ResizeHelper(QObject *parent) { + setAcceptedMouseButtons(Qt::LeftButton); + m_pen.setColor(QColor(255, 0, 0, 128)); + m_pen.setStyle(Qt::SolidLine); +} + +QRectF ResizeHelper::boundingRect() const { + auto hWidth = m_pen.widthF()/2.0; + return m_rect.adjusted(-hWidth, -hWidth, hWidth, hWidth); +} + +void ResizeHelper::selectionChanged() { + if (!scene()) { setVisible(false); return; } + auto sel = scene()->selectedItems(); + if (sel.isEmpty() || sel.size() > 1) { setVisible(false); return; } + auto item = sel.at(0); + if (! traits.isGraphicsItemResizeable(item)) { setVisible(false); return; } + setParentItem(item); + newGeometry(); + setVisible(true); +} + +void ResizeHelper::paint(QPainter * p, const QStyleOptionGraphicsItem *, QWidget *) { + p->setPen(m_pen); + p->drawRect(m_rect); +} + +void ResizeHelper::mousePressEvent(QGraphicsSceneMouseEvent * ev) { + m_edges = edgesAt(ev->pos(), m_rect, m_pen.widthF()); + if (!m_edges){ /*Moving: Store click location + //ev->ignore(); /*Ignore if moved*/ + clickPos = ev->pos(); + } + ev->accept(); +} + +void ResizeHelper::mouseMoveEvent(QGraphicsSceneMouseEvent * ev) { + auto pos = mapToItem(parentItem(), ev->pos()); + auto rect = traits.rectFor(parentItem()); + + if (m_edges & Qt::LeftEdge) rect.setLeft(pos.x()); + if (m_edges & Qt::TopEdge) rect.setTop(pos.y()); + if (m_edges & Qt::RightEdge) rect.setRight(pos.x()); + if (m_edges & Qt::BottomEdge) rect.setBottom(pos.y()); + if (!!m_edges) { + traits.setRectOn(parentItem(), rect); + newGeometry(); + }else{ /*Moving*/ + QPointF d = clickPos - ev->pos(); + rect.setLeft(rect.left()-d.x()); + rect.setTop(rect.top()-d.y()); + rect.setRight(rect.right()-d.x()); + rect.setBottom(rect.bottom()-d.y()); + traits.setRectOn(parentItem(), rect); + newGeometry(); + clickPos = ev->pos(); + } +} + +void ResizeHelper::newGeometry() { + prepareGeometryChange(); + auto parentRect = traits.rectFor(parentItem()); + m_rect.setTopLeft(mapFromParent(parentRect.topLeft())); + m_rect.setBottomRight(mapFromParent(parentRect.bottomRight())); + m_pen.setWidthF(std::min(m_rect.width(), m_rect.height()) * 0.1); + m_pen.setJoinStyle(Qt::MiterJoin); + emit(itemChanged(parentItem())); +} diff --git a/ResizeHelper.h b/ResizeHelper.h new file mode 100644 index 0000000..195006d --- /dev/null +++ b/ResizeHelper.h @@ -0,0 +1,35 @@ +#ifndef ResizeHelper_H +#define ResizeHelper_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class ResizeHelper : public QGraphicsObject +{ + Q_OBJECT + +public: + ResizeTraits traits; + QRectF m_rect; + QPen m_pen; + QPointF clickPos; + QFlags m_edges; + ResizeHelper(QObject *parent = 0); + QRectF boundingRect() const Q_DECL_OVERRIDE; + void newGeometry(); + void paint(QPainter * p, const QStyleOptionGraphicsItem *, QWidget *); + void mousePressEvent(QGraphicsSceneMouseEvent * ev) Q_DECL_OVERRIDE; + void mouseMoveEvent(QGraphicsSceneMouseEvent * ev) Q_DECL_OVERRIDE; +signals: + void itemChanged(QGraphicsItem* item); +public slots: + void selectionChanged(); +}; + +#endif // ResizeHelper_H diff --git a/ResizeTraits.cpp b/ResizeTraits.cpp new file mode 100644 index 0000000..2123376 --- /dev/null +++ b/ResizeTraits.cpp @@ -0,0 +1,39 @@ +#include "ResizeTraits.h" + +/// Determines whether an item is manually resizeable. +bool ResizeTraits::isGraphicsItemResizeable(QGraphicsItem * item) { + auto resizeableItem1 = dynamic_cast(item); + if(resizeableItem1){ + return resizeableItem1; + } + auto resizeableItem2 = dynamic_cast(item); + if(resizeableItem2){ + return resizeableItem2; + } + return false; +} + +/// Gives the rectangle one can base the resize operations on for an item +QRectF ResizeTraits::rectFor(QGraphicsItem * item) { + auto resizeableItem1 = dynamic_cast(item); + if(resizeableItem1){ + return resizeableItem1->rect(); + } + auto resizeableItem2 = dynamic_cast(item); + if(resizeableItem2){ + return resizeableItem2->rect(); + } + return QRectF(); +} + +/// Sets a new rectangle on the item +void ResizeTraits::setRectOn(QGraphicsItem * item, const QRectF & rect) { + auto resizeableItem1 = dynamic_cast(item); + if (resizeableItem1){ + return resizeableItem1->setRect(rect); + } + auto resizeableItem2 = dynamic_cast(item); + if (resizeableItem2){ + return resizeableItem2->setRect(rect); + } +} diff --git a/ResizeTraits.h b/ResizeTraits.h new file mode 100644 index 0000000..9198db0 --- /dev/null +++ b/ResizeTraits.h @@ -0,0 +1,15 @@ +#ifndef SIMPLETRAITS_H +#define SIMPLETRAITS_H +#include +#include + +class SimpleTraits +{ +public: + static bool isGraphicsItemResizeable(QGraphicsItem * item); + static QRectF rectFor(QGraphicsItem * item); + static void setRectOn(QGraphicsItem * item, const QRectF & rect); + +}; + +#endif // SIMPLETRAITS_H