Techdraw: Undo/redo when dragging views and rework projection group drag (#22875)

* TechDraw: create a transaction when finished dragging a view

* TechDraw: drag projection group when dragging a subview in AutoDistribute is enabled

* TechDraw: avoid creating 'Drag View' transaction if the document is already in a transaction

* TechDraw: Apply suggestions from code review

---------

Co-authored-by: Benjamin Nauck <benjamin@nauck.se>
This commit is contained in:
theo-vt
2025-08-24 02:36:41 -04:00
committed by GitHub
parent cf951bae6b
commit c61ad05789
5 changed files with 103 additions and 39 deletions

View File

@@ -55,6 +55,10 @@ TechDraw::DrawProjGroup * QGIProjGroup::getDrawView() const
App::DocumentObject *obj = getViewObject();
return dynamic_cast<TechDraw::DrawProjGroup *>(obj);
}
bool QGIProjGroup::autoDistributeEnabled() const
{
return getDrawView() && getDrawView()->AutoDistribute.getValue();
}
bool QGIProjGroup::sceneEventFilter(QGraphicsItem* watched, QEvent *event)
{
@@ -64,27 +68,34 @@ bool QGIProjGroup::sceneEventFilter(QGraphicsItem* watched, QEvent *event)
event->type() == QEvent::GraphicsSceneMouseRelease) {
QGIView *qAnchor = getAnchorQItem();
if(qAnchor && watched == qAnchor) {
QGIView* qWatched = dynamic_cast<QGIView*>(watched);
// If AutoDistribute is enabled, catch events and move the anchor directly
if(qAnchor && (watched == qAnchor || (autoDistributeEnabled() && qWatched != nullptr))) {
auto *mEvent = dynamic_cast<QGraphicsSceneMouseEvent*>(event);
switch(event->type()) {
case QEvent::GraphicsSceneMousePress:
// TODO - Perhaps just pass the mouse event on to the anchor somehow?
if (scene() && !qAnchor->isSelected()) {
scene()->clearSelection();
qAnchor->setSelected(true);
}
mousePressEvent(mEvent);
break;
case QEvent::GraphicsSceneMouseMove:
mouseMoveEvent(mEvent);
break;
case QEvent::GraphicsSceneMouseRelease:
mouseReleaseEvent(mEvent);
break;
default:
break;
// Disable moves on the view to prevent double drag
bool initCanMove = qWatched->flags() & QGraphicsItem::ItemIsMovable;
qWatched->setFlag(QGraphicsItem::ItemIsMovable, false);
switch (event->type()) {
case QEvent::GraphicsSceneMousePress:
// TODO - Perhaps just pass the mouse event on to the watched item somehow?
if (scene() && !qWatched->isSelected()) {
scene()->clearSelection();
qWatched->setSelected(true);
}
mousePressEvent(mEvent);
break;
case QEvent::GraphicsSceneMouseMove:
mouseMoveEvent(mEvent);
break;
case QEvent::GraphicsSceneMouseRelease:
mouseReleaseEvent(qWatched, mEvent);
break;
default:
break;
}
// Restore flag
qWatched->setFlag(QGraphicsItem::ItemIsMovable, initCanMove);
return true;
}
}
@@ -134,7 +145,7 @@ void QGIProjGroup::mousePressEvent(QGraphicsSceneMouseEvent * event)
QGIView *qAnchor = getAnchorQItem();
if(qAnchor) {
QPointF transPos = qAnchor->mapFromScene(event->scenePos());
if(qAnchor->shape().contains(transPos)) {
if(qAnchor->shape().contains(transPos) || autoDistributeEnabled()) {
mousePos = event->screenPos();
}
}
@@ -144,28 +155,29 @@ void QGIProjGroup::mousePressEvent(QGraphicsSceneMouseEvent * event)
void QGIProjGroup::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
{
QGIView *qAnchor = getAnchorQItem();
if(scene() && qAnchor && (qAnchor == scene()->mouseGrabberItem())) {
if(scene() && qAnchor && (qAnchor == scene()->mouseGrabberItem() || autoDistributeEnabled())) {
if((mousePos - event->screenPos()).manhattanLength() > 5) { //if the mouse has moved more than 5, process the mouse event
QGIViewCollection::mouseMoveEvent(event);
}
}
event->accept();
}
void QGIProjGroup::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
if(scene()) {
QGIView *qAnchor = getAnchorQItem();
mouseReleaseEvent(getAnchorQItem(), event);
}
void QGIProjGroup::mouseReleaseEvent(QGIView* originator, QGraphicsSceneMouseEvent* event)
{
if(scene()) {
if((mousePos - event->screenPos()).manhattanLength() < 5) {
if(qAnchor && qAnchor->shape().contains(event->pos())) {
if(originator && originator->shape().contains(event->pos())) {
event->ignore();
qAnchor->mouseReleaseEvent(event);
originator->mouseReleaseEvent(event);
}
}
else if(scene() && qAnchor) {
// End of Drag
getViewObject()->setPosition(Rez::appX(x()), Rez::appX(getY()));
else if(scene() && originator) {
dragFinished();
}
}
QGIViewCollection::mouseReleaseEvent(event);

View File

@@ -66,11 +66,14 @@ protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent * event ) override;
void mousePressEvent(QGraphicsSceneMouseEvent * event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent * event) override;
QGIView * getAnchorQItem() const;
void mouseReleaseEvent(QGIView* originator, QGraphicsSceneMouseEvent* event);
QGIView* getAnchorQItem() const;
private:
/// Convenience function
TechDraw::DrawProjGroup* getDrawView() const;
bool autoDistributeEnabled() const;
QGraphicsItem* m_origin;
QPoint mousePos;

View File

@@ -32,10 +32,12 @@
#endif
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObject.h>
#include <Base/Console.h>
#include <Base/Tools.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/Selection/Selection.h>
@@ -91,6 +93,7 @@ QGIView::QGIView()
setCacheMode(QGraphicsItem::NoCache);
setHandlesChildEvents(false);
setAcceptHoverEvents(true);
setFlag(QGraphicsItem::ItemIsSelectable, true);
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
@@ -168,8 +171,7 @@ QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value)
// Base::Console().message("QGIV::itemChange(%d)\n", change);
if(change == ItemPositionChange && scene()) {
QPointF newPos = value.toPointF(); //position within parent!
TechDraw::DrawView *viewObj = getViewObject();
TechDraw::DrawView* viewObj = getViewObject();
auto* dpgi = dynamic_cast<TechDraw::DrawProjGroupItem*>(viewObj);
if (dpgi && dpgi->getPGroup()) {
// restrict movements of secondary views.
@@ -191,14 +193,6 @@ QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value)
}
}
// tell the feature that we have moved
Gui::ViewProvider *vp = getViewProvider(viewObj);
if (vp && !vp->isRestoring()) {
snapping = true; // avoid triggering updateView by the VP updateData
viewObj->setPosition(Rez::appX(newPos.x()), Rez::appX(-newPos.y()));
snapping = false;
}
return newPos;
}
@@ -217,6 +211,8 @@ QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value)
m_label->show();
m_lock->setVisible(getViewObject()->isLocked() && getViewObject()->showLock());
} else {
dragFinished();
if (!m_isHovered) {
m_colCurrent = PreferencesGui::getAccessibleQColor(PreferencesGui::normalQColor());
m_border->hide();
@@ -232,6 +228,55 @@ QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value)
return QGraphicsItemGroup::itemChange(change, value);
}
void QGIView::dragFinished()
{
if (!viewObj) {
return;
}
double currX = viewObj->X.getValue();
double currY = viewObj->Y.getValue();
double candidateX = Rez::appX(pos().x());
double candidateY = Rez::appX(-pos().y());
bool setX = false;
bool setY = false;
const double tolerance = 0.001; // mm
if (!DrawUtil::fpCompare(currX, candidateX, tolerance)) {
setX = true;
}
if (!DrawUtil::fpCompare(currY, candidateY, tolerance)) {
setY = true;
}
if (!setX && !setY) {
return;
}
bool ownTransaction = (viewObj->getDocument()->getTransactionID(true) == 0);
if (ownTransaction) {
Gui::Command::openCommand("Drag view");
}
// tell the feature that we have moved
Gui::ViewProvider *vp = getViewProvider(viewObj);
if (vp && !vp->isRestoring()) {
snapping = true; // avoid triggering updateView by the VP updateData
if (setX) {
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.X = %f",
viewObj->getNameInDocument(), candidateX);
}
if (setY) {
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.Y = %f",
viewObj->getNameInDocument(), candidateY);
}
snapping = false;
}
if (ownTransaction) {
Gui::Command::commitCommand();
}
}
//! align this view with others. newPosition is in this view's parent's coord
//! system. if this view is not in a ProjectionGroup, then this is the scene
@@ -463,6 +508,7 @@ void QGIView::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
m_multiselectActivated = false;
}
dragFinished();
QGraphicsItemGroup::mouseReleaseEvent(event);
event->setModifiers(originalModifiers);

View File

@@ -176,6 +176,8 @@ protected:
QGIView* getQGIVByName(std::string name);
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
void dragFinished();
// Preselection events:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;

View File

@@ -33,6 +33,7 @@
#include <Mod/TechDraw/App/DrawProjGroup.h>
#include <Mod/TechDraw/App/DrawProjGroupItem.h>
#include "QGIView.h"
#include "ViewProviderProjGroupItem.h"
using namespace TechDrawGui;