[TD]fix balloon drag on rotated view (fix #15726)

This commit is contained in:
wandererfan
2024-08-26 10:34:07 -04:00
committed by Yorik van Havre
parent 1be41b68a2
commit e88b1b49c9
3 changed files with 108 additions and 47 deletions

View File

@@ -96,6 +96,7 @@ public:
virtual bool checkFit() const;
virtual bool checkFit(DrawPage*) const;
virtual void setPosition(double x, double y, bool force = false);
virtual Base::Vector3d getPosition() const { return Base::Vector3d(X.getValue(), Y.getValue(), 0.0); }
virtual bool keepUpdated(void);
boost::signals2::signal<void (const DrawView*)> signalGuiPaint;

View File

@@ -36,6 +36,7 @@
#include <App/Application.h>
#include <Base/Parameter.h>
#include <Base/Tools.h>
#include <Gui/Command.h>
#include <Gui/Tools.h>
#include <Mod/TechDraw/App/ArrowPropEnum.h>
@@ -205,6 +206,11 @@ void QGIBalloonLabel::setLabelCenter()
posY = y() + m_labelText->boundingRect().height() / 2.;
}
Base::Vector3d QGIBalloonLabel::getLabelCenter() const
{
return Base::Vector3d(posX, posY, 0.0);
}
void QGIBalloonLabel::setFont(QFont font) { m_labelText->setFont(font); }
void QGIBalloonLabel::setDimString(QString text)
@@ -381,7 +387,6 @@ void QGIViewBalloon::setViewPartFeature(TechDraw::DrawViewBalloon* balloonFeat)
void QGIViewBalloon::updateView(bool update)
{
// Base::Console().Message("QGIVB::updateView()\n");
Q_UNUSED(update);
auto balloon(dynamic_cast<TechDraw::DrawViewBalloon*>(getViewObject()));
if (!balloon) {
@@ -406,7 +411,6 @@ void QGIViewBalloon::updateView(bool update)
//update the bubble contents
void QGIViewBalloon::updateBalloon(bool obtuse)
{
// Base::Console().Message("QGIVB::updateBalloon()\n");
(void)obtuse;
const auto balloon(dynamic_cast<TechDraw::DrawViewBalloon*>(getViewObject()));
if (!balloon) {
@@ -459,7 +463,9 @@ void QGIViewBalloon::balloonLabelDragged(bool ctrl)
if (!m_dragInProgress) {//first drag movement
m_dragInProgress = true;
if (ctrl) {//moving whole thing, remember Origin offset from Bubble
m_saveOffset = dvb->getOriginOffset();
m_saveOriginOffset = dvb->getOriginOffset();
m_saveOrigin = DU::toVector3d(arrow->pos());
m_savePosition = DU::toVector3d(balloonLabel->pos());
}
}
@@ -473,6 +479,10 @@ void QGIViewBalloon::balloonLabelDragged(bool ctrl)
// redraw the balloon at the new position
// note that we don't store the new position to the X/Y properties
// since the dragging is not yet finished
// TODO: we don't need to redraw if the graphic is not changing (other than location).
// all of the balloon components (box, text, line, arrow, etc) would have to be placed
// into a QGraphicsItemGroup (or made children of a single QGI) in order to move them in
// sync
drawBalloon(true);
}
}
@@ -488,12 +498,14 @@ void QGIViewBalloon::balloonLabelDragFinished()
double scale = 1.0;
DrawView* balloonParent = getSourceView();
if (balloonParent) {
scale = balloonParent->getScale();
if (!balloonParent) {
return;
}
scale = balloonParent->getScale();
//set feature position (x, y) from graphic position
double x = Rez::appX(balloonLabel->X() / scale), y = Rez::appX(balloonLabel->Y() / scale);
double x = Rez::appX(balloonLabel->X() / scale);
double y = Rez::appX(balloonLabel->Y() / scale);
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Drag Balloon"));
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.X = %f",
dvb->getNameInDocument(), x);
@@ -502,18 +514,27 @@ void QGIViewBalloon::balloonLabelDragFinished()
// for the case that origin was also dragged, calc new origin and update feature
if (m_originDragged) {
Base::Vector3d pos(x, -y, 0.0);
Base::Vector3d newOrg = pos - m_saveOffset;
auto originGui = arrowPosInDrag(); // Qt rotated
auto originApp = originGui / scale; // Qt rotated unscaled
originApp = Rez::appX(DU::invertY(originApp)); // App rotated
auto originAppUnrotated = originApp;
auto rotationDeg = balloonParent->Rotation.getValue();
if (rotationDeg != 0) {
originAppUnrotated.RotateZ(Base::toRadians(-rotationDeg));
}
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.OriginX = %f",
dvb->getNameInDocument(), newOrg.x);
dvb->getNameInDocument(), originAppUnrotated.x);
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.OriginY = %f",
dvb->getNameInDocument(), newOrg.y);
dvb->getNameInDocument(), originAppUnrotated.y);
}
Gui::Command::commitCommand();
m_dragInProgress = false;
m_originDragged = false;
drawBalloon(false);
}
//from QGVP::mouseReleaseEvent - pos = eventPos in scene coords?
@@ -579,14 +600,18 @@ void QGIViewBalloon::placeBalloon(QPointF pos)
void QGIViewBalloon::draw()
{
// Base::Console().Message("QGIVB::draw()\n");
// just redirect
drawBalloon(false);
}
void QGIViewBalloon::drawBalloon(bool dragged)
{
// Base::Console().Message("QGIVB::drawBalloon(%d)\n", dragged);
if ((!dragged) && m_dragInProgress) {
// TODO there are 2 drag status variables. m_dragInProgress appears to be the one to use?
// dragged shows false while drag is still in progress.
return;
}
prepareGeometryChange();
TechDraw::DrawViewBalloon* balloon = dynamic_cast<TechDraw::DrawViewBalloon*>(getViewObject());
@@ -595,6 +620,10 @@ void QGIViewBalloon::drawBalloon(bool dragged)
//nothing to draw, don't try
return;
}
if (balloon->isRestoring()) {
// don't try to draw yet
return;
}
TechDraw::DrawView* refObj = balloon->getParentView();
auto vp = static_cast<ViewProviderBalloon*>(getViewProvider(getViewObject()));
@@ -607,32 +636,14 @@ void QGIViewBalloon::drawBalloon(bool dragged)
double textWidth = balloonLabel->getDimText()->boundingRect().width();
double textHeight = balloonLabel->getDimText()->boundingRect().height();
float x, y, arrowTipX, arrowTipY;
Base::Vector3d arrowTip{balloon->OriginX.getValue(), balloon->OriginY.getValue(), 0.0};
// when not dragging take the X/Y properties otherwise the current label position
if (!dragged) {
x = Rez::guiX(balloon->X.getValue() * refObj->getScale());
y = Rez::guiX(balloon->Y.getValue() * refObj->getScale());
arrowTipX = Rez::guiX(balloon->OriginX.getValue() * refObj->getScale());
arrowTipY = -Rez::guiX(balloon->OriginY.getValue() * refObj->getScale());
}
else {
x = balloonLabel->X();
y = -balloonLabel->Y();
if (m_originDragged) {
double scale = Rez::guiX(refObj->getScale());
Base::Vector3d pos(x / scale, y / scale, 0.0);
Base::Vector3d newOrg = pos - m_saveOffset;
arrowTip = newOrg;
arrowTipX = newOrg.x * scale;
arrowTipY = -newOrg.y * scale;
}
else {
arrowTipX = Rez::guiX(balloon->OriginX.getValue() * refObj->getScale());
arrowTipY = -Rez::guiX(balloon->OriginY.getValue() * refObj->getScale());
}
}
Base::Vector3d lblCenter(x, -y, 0.0);
float arrowTipX;
Base::Vector3d arrowTipPosInParent;
bool isDragging = dragged || m_dragInProgress;
Base::Vector3d labelPos;
getBalloonPoints(balloon, refObj, isDragging, labelPos, arrowTipPosInParent);
arrowTipX = arrowTipPosInParent.x;
Base::Vector3d lblCenter(labelPos.x, -labelPos.y, 0.0);
if (balloon->isLocked()) {
balloonLabel->setFlag(QGraphicsItem::ItemIsMovable, false);
@@ -782,24 +793,20 @@ void QGIViewBalloon::drawBalloon(bool dragged)
}
else {
arrow->setStyle(endType);
arrow->setSize(balloon->EndTypeScale.getValue() * QGIArrow::getPrefArrowSize());
arrow->draw();
arrow->setPos(DU::toQPointF(arrowTipPosInParent));
Base::Vector3d arrowTipPos(arrowTipX, arrowTipY, 0.0);
// arrowTip set above is unscaled, uninverted, unrotated and unRez'd.
arrowTip = DGU::toGuiPoint(refObj, arrowTip);
Base::Vector3d dirballoonLinesLine;
if (!DrawUtil::fpCompare(kinkLength, 0.0)) {
dirballoonLinesLine = (arrowTip - kinkPoint).Normalize();
dirballoonLinesLine = (arrowTipPosInParent - kinkPoint).Normalize();
}
else {
dirballoonLinesLine = (arrowTip - dLineStart).Normalize();
dirballoonLinesLine = (arrowTipPosInParent - dLineStart).Normalize();
}
float arAngle = atan2(dirballoonLinesLine.y, dirballoonLinesLine.x) * 180 / M_PI;
arrow->setPos(DU::toQPointF(arrowTip));
if ((endType == ArrowType::FILLED_TRIANGLE) && (prefOrthoPyramid())) {
if (arAngle < 0.0) {
arAngle += 360.0;
@@ -826,7 +833,7 @@ void QGIViewBalloon::drawBalloon(bool dragged)
arrow->setRotation(arAngle);
arrow->show();
}
dLinePath.lineTo(arrowTip.x - xAdj, arrowTip.y - yAdj);
dLinePath.lineTo(arrowTipPosInParent.x - xAdj, arrowTipPosInParent.y - yAdj);
balloonLines->setPath(dLinePath);
// This overwrites the previously created QPainterPath with empty one, in case it should be hidden. Should be refactored.
@@ -967,4 +974,47 @@ DrawView* QGIViewBalloon::getSourceView() const
return balloonParent;
}
//! Calculate the required position of the arrow tip during drag operations. Uses the current
//! label position and relative positions of the label and tip at the start of the drag.
//! Note this returns the Gui position of the arrow, not the App position.
Base::Vector3d QGIViewBalloon::arrowPosInDrag()
{
auto offsetGui = m_savePosition - m_saveOrigin;
auto arrowPosGui = DU::toVector3d(balloonLabel->pos()) - offsetGui;
return arrowPosGui;
}
//! retrieves the appropriate label position and origin (arrow) point
void QGIViewBalloon::getBalloonPoints(TechDraw::DrawViewBalloon* balloon, DrawView *refObj,
bool isDragging,
Base::Vector3d& labelPos,
Base::Vector3d& arrowPos)
{
float x, y;
Base::Vector3d originApp{balloon->OriginX.getValue(), balloon->OriginY.getValue(), 0.0};
Base::Vector3d arrowTipPosInParent;
// when not dragging take the X/Y properties otherwise the current label position
if (!isDragging) {
x = Rez::guiX(balloon->X.getValue() * refObj->getScale());
y = Rez::guiX(balloon->Y.getValue() * refObj->getScale());
arrowTipPosInParent = DGU::toGuiPoint(refObj, originApp);
}
else {
x = balloonLabel->X();
y = -balloonLabel->Y(); // invert from Qt scene units to R2 mm
if (m_originDragged) {
// moving the whole bubble object. do not adjust origin point.
arrowTipPosInParent = arrowPosInDrag();
} else {
// this is a bubble drag, so the origin must remain in the same position on the view.
// if the parent view is rotated, the origin scene position must be rotated to match
arrowTipPosInParent = DGU::toGuiPoint(refObj, originApp);
}
}
labelPos = Base::Vector3d(x, y, 0.0);
arrowPos = arrowTipPosInParent;
}
#include <Mod/TechDraw/Gui/moc_QGIViewBalloon.cpp>

View File

@@ -78,6 +78,7 @@ public:
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
QWidget* widget = nullptr) override;
void setLabelCenter();
Base::Vector3d getLabelCenter() const;
void setPosFromCenter(const double& xCenter, const double& yCenter);
double X() const
{
@@ -226,6 +227,13 @@ protected:
QString getPrecision();
void parentViewMousePressed(QGIView* view, QPointF pos);
TechDraw::DrawView* getSourceView() const;
Base::Vector3d arrowPosInDrag();
void getBalloonPoints(TechDraw::DrawViewBalloon* balloon,
TechDraw::DrawView* refObj,
bool isDragging,
Base::Vector3d& labelPos,
Base::Vector3d& arrowPos);
private:
TechDraw::DrawViewBalloon* dvBalloon;
@@ -241,7 +249,9 @@ private:
bool m_dragInProgress;
bool m_originDragged = false;
bool m_ctrl;
Base::Vector3d m_saveOffset;
Base::Vector3d m_saveOriginOffset;
Base::Vector3d m_saveOrigin;
Base::Vector3d m_savePosition;
};
}// namespace TechDrawGui