Repository: FreeCAD/FreeCAD
Pull request #21169: TechDraw: fix positioning and state handling of dimension
Author: login: benj5378
Labels: name: Mod: TechDraw
description: Related to the TechDraw Workbench
Created: 2025-05-06T17:50:19Z | Merged: 2025-05-26T15:18:05Z

- Positioning was calculated using `boundingRect` while `transformOriginPoint` was set according to `tightBoundingRect`, causing mismatch when `QGIDatumLabel` contains more than text (eg. shapes around text). Now `transformOriginPoint` and positioning calculated according to `tightBoundingRect`, and setting `transformOriginPoint` of `QGIDatumLabel` are handled by itself. This fixes an issue where the gap between dimension lines and text varied depending on dimension's angle.
- `m_lineWidth` was set in multiple locations, causing confusion and bug introduction
- If `X` or `Y` property changed, the remaining changed properties were not handled due to using `if else` rather than `if` for property change checking. This became an issue due the above mentioned simplification of `m_lineWidth` setting: if `X` or `Y` had changed (upon document restore).
- Center position was uneededly saved in variables `posX` and `posY` when it could be calculated on demand using `tightBoundingRect`. Removing this uneeded state simplfies code and lowers the risk of bug introduction due to lack of updating state.

Fixes https://github.com/FreeCAD/FreeCAD/issues/20613


Diff:
diff --git a/src/Mod/TechDraw/Gui/QGIDatumLabel.cpp b/src/Mod/TechDraw/Gui/QGIDatumLabel.cpp
index 811da80a8ff0..c11b05c383b4 100644
--- a/src/Mod/TechDraw/Gui/QGIDatumLabel.cpp
+++ b/src/Mod/TechDraw/Gui/QGIDatumLabel.cpp
@@ -52,8 +52,6 @@ namespace TechDrawGui {
 QGIDatumLabel::QGIDatumLabel() : m_dragState(DragState::NoDrag)
 {
     verticalSep = false;
-    posX = 0;
-    posY = 0;
 
     parent = nullptr;
 
@@ -121,7 +119,6 @@ QVariant QGIDatumLabel::itemChange(GraphicsItemChange change, const QVariant& va
             snapPosition(newPos);
         }
 
-        setLabelCenter();
         m_dragState = DragState::Dragging;
         Q_EMIT dragging(m_ctrl);
     }
@@ -343,6 +340,11 @@ void QGIDatumLabel::updateFrameRect() {
     m_frame->setRect(tightBoundingRect());
 }
 
+void QGIDatumLabel::boundingRectChanged()
+{
+    setTransformOriginPoint(tightBoundingRect().center());
+}
+
 void QGIDatumLabel::setLineWidth(double lineWidth)
 {
     QPen pen = m_frame->pen();
@@ -371,20 +373,17 @@ void QGIDatumLabel::paint(QPainter* painter, const QStyleOptionGraphicsItem* opt
 
 void QGIDatumLabel::setPosFromCenter(const double& xCenter, const double& yCenter)
 {
-    prepareGeometryChange();
-    auto* qgivd = dynamic_cast<QGIViewDimension*>(parentItem());
-    if (!qgivd) {
-        return;
-    }
-    const auto dim(dynamic_cast<TechDraw::DrawViewDimension*>(qgivd->getViewObject()));
-    if (!dim) {
-        return;
-    }
-
     //set label's Qt position(top, left) given boundingRect center point
-    Base::Vector2d vec = getPosToCenterVec();
-    setPos(xCenter - vec.x, yCenter - vec.y);
+    Base::Vector2d centerOffset = getPosToCenterVec();
+    double xTopLeft = xCenter - centerOffset.x;
+    double yTopLeft = yCenter - centerOffset.y;
+    setPos(xTopLeft, yTopLeft);
+    updateChildren();
+}
 
+void QGIDatumLabel::updateChildren()
+{
+    prepareGeometryChange();
     QString uText = m_unitText->toPlainText();
     if ((uText.size() > 0) && (uText.at(0) != QChar::fromLatin1(' '))) {
         QString vText = m_dimText->toPlainText();
@@ -415,18 +414,9 @@ void QGIDatumLabel::setPosFromCenter(const double& xCenter, const double& yCente
     m_tolTextUnder->justifyLeftAt(tolLeft + tol_adj.x(), middle + overBox.height() + tol_adj.y()/2.0, false);
 }
 
-void QGIDatumLabel::setLabelCenter()
-{
-    //save label's bRect center (posX, posY) given Qt position (top, left)
-    Base::Vector2d vec = getPosToCenterVec();
-    posX = x() + vec.x;
-    posY = y() + vec.y;
-}
-
-Base::Vector2d QGIDatumLabel::getPosToCenterVec()
+Base::Vector2d QGIDatumLabel::getPosToCenterVec() const
 {
     QPointF center = tightBoundingRect().center();
-
     return Base::Vector2d(center.x(), center.y());
 }
 
@@ -442,6 +432,7 @@ void QGIDatumLabel::setFont(QFont font)
     m_tolTextOver->setFont(tFont);
     m_tolTextUnder->setFont(tFont);
     updateFrameRect();
+    boundingRectChanged();
 }
 
 void QGIDatumLabel::setDimString(QString text, qreal maxWidth)
@@ -450,6 +441,7 @@ void QGIDatumLabel::setDimString(QString text, qreal maxWidth)
     m_dimText->setPlainText(text);
     m_dimText->setTextWidth(maxWidth);
     updateFrameRect();
+    boundingRectChanged();
 }
 
 void QGIDatumLabel::setToleranceString()
@@ -473,6 +465,7 @@ void QGIDatumLabel::setToleranceString()
         m_tolTextOver->setPlainText(QString());
         m_tolTextUnder->setPlainText(QString());
         updateFrameRect();
+        boundingRectChanged();
         return;
     }
 
@@ -511,6 +504,7 @@ void QGIDatumLabel::setToleranceString()
     }
 
     updateFrameRect();
+    boundingRectChanged();
 }
 
 
diff --git a/src/Mod/TechDraw/Gui/QGIDatumLabel.h b/src/Mod/TechDraw/Gui/QGIDatumLabel.h
index 00ee27777442..24cb494b2630 100644
--- a/src/Mod/TechDraw/Gui/QGIDatumLabel.h
+++ b/src/Mod/TechDraw/Gui/QGIDatumLabel.h
@@ -51,9 +51,9 @@ Q_OBJECT
                         QWidget *widget = nullptr ) override;
     void setLabelCenter();
     void setPosFromCenter(const double &xCenter, const double &yCenter);
-    double X() const { return posX; }
-    double Y() const { return posY; }              //minus posY?
-    Base::Vector2d getPosToCenterVec();
+    double X() const { return x() + getPosToCenterVec().x; }
+    double Y() const { return y() + getPosToCenterVec().y; }
+    Base::Vector2d getPosToCenterVec() const;
 
     void setFont(QFont font);
     QFont getFont() const { return m_dimText->font(); }
@@ -96,6 +96,8 @@ Q_OBJECT
     void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
     void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) override;
     void updateFrameRect();
+    void updateChildren();
+    void boundingRectChanged();
 
     int getPrecision();
 
@@ -121,9 +123,6 @@ Q_OBJECT
     QColor m_colNormal;
     bool m_ctrl;
 
-    double posX;
-    double posY;
-
     DragState m_dragState;
 
 private:
diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp
index 3b77f2cf0617..903e49346658 100644
--- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp
+++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp
@@ -192,12 +192,6 @@ void QGIViewDimension::setViewPartFeature(TechDraw::DrawViewDimension* obj)
     setViewFeature(static_cast<TechDraw::DrawView*>(obj));
     dvDimension = obj;
 
-    // Set the QGIGroup Properties based on the DrawView
-    float x = Rez::guiX(obj->X.getValue());
-    float y = Rez::guiX(-obj->Y.getValue());
-
-    datumLabel->setPosFromCenter(x, y);
-
     setNormalColorAll();
     setPrettyNormal();
 
@@ -248,23 +242,19 @@ void QGIViewDimension::updateView(bool update)
         return;
     }
 
+    updateDim();
+
     if (update || dim->X.isTouched() || dim->Y.isTouched()) {
         float x = Rez::guiX(dim->X.getValue());
         float y = Rez::guiX(dim->Y.getValue());
         datumLabel->setPosFromCenter(x, -y);
-        updateDim();
-    }
-    else if (vp->Fontsize.isTouched() || vp->Font.isTouched()) {
-        updateDim();
     }
-    else if (vp->LineWidth.isTouched()) {
-        m_lineWidth = vp->LineWidth.getValue();
-        updateDim();
-    }
-    else {
-        updateDim();
+    if (vp->LineWidth.isTouched()) {
+        m_lineWidth = Rez::guiX(vp->LineWidth.getValue());
     }
 
+    updateDim();
+
     // needs Phase 2 of autocorrect to be useful
     // if (dim->hasGoodReferences()) {
     //     m_refFlag->hide();
@@ -304,7 +294,6 @@ void QGIViewDimension::updateDim()
     prepareGeometryChange();
     datumLabel->setDimString(labelText);
     datumLabel->setToleranceString();
-    datumLabel->setPosFromCenter(datumLabel->X(), datumLabel->Y());
 
     datumLabel->setFramed(dim->TheoreticalExact.getValue());
     datumLabel->setLineWidth(m_lineWidth);
@@ -380,7 +369,6 @@ void QGIViewDimension::draw()
         return;
     }
 
-    m_lineWidth = Rez::guiX(vp->LineWidth.getValue());
     datumLabel->setRotation(0.0);
     datumLabel->show();
 
@@ -1308,7 +1296,6 @@ void QGIViewDimension::drawDistanceExecutive(const Base::Vector2d& startPoint,
         }
     }
 
-    datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
     datumLabel->setRotation(toQtDeg(labelAngle));
 
     dimLines->setPath(distancePath);
@@ -1521,7 +1508,6 @@ void QGIViewDimension::drawDistanceOverride(const Base::Vector2d& startPoint,
         }
     }
 
-    datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
     datumLabel->setRotation(toQtDeg(labelAngle));
 
     dimLines->setPath(distancePath);
@@ -1733,7 +1719,6 @@ void QGIViewDimension::drawRadiusExecutive(const Base::Vector2d& centerPoint,
             standardStyle);
     }
 
-    datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
     datumLabel->setRotation(toQtDeg(labelAngle));
 
     dimLines->setPath(radiusPath);
@@ -1806,7 +1791,6 @@ void QGIViewDimension::drawAreaExecutive(const Base::Vector2d& centerPoint, doub
             standardStyle);
     }
 
-    datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
     datumLabel->setRotation(toQtDeg(labelAngle));
 
     dimLines->setPath(areaPath);
@@ -2008,7 +1992,6 @@ void QGIViewDimension::drawDiameter(TechDraw::DrawViewDimension* dimension,
                                   standardStyle);
         }
 
-        datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
         datumLabel->setRotation(toQtDeg(labelAngle));
 
         dimLines->setPath(diameterPath);
@@ -2237,7 +2220,6 @@ void QGIViewDimension::drawAngle(TechDraw::DrawViewDimension* dimension,
         }
     }
 
-    datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
     datumLabel->setRotation(toQtDeg(labelAngle));
 
     dimLines->setPath(anglePath);


Reviews:
user: login: benj5378
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T16:39:03Z
user: login: WandererFan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:54:46Z
user: login: WandererFan
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T12:56:14Z

Review comments:
diff_hunk: @@ -248,23 +242,19 @@ void QGIViewDimension::updateView(bool update)
         return;
     }
 
+    updateDim();
+
path: src/Mod/TechDraw/Gui/QGIViewDimension.cpp
user: login: benj5378
body: This should be removed 
created_at: 2025-05-19T16:38:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -248,23 +242,19 @@ void QGIViewDimension::updateView(bool update)
         return;
     }
 
+    updateDim();
+
path: src/Mod/TechDraw/Gui/QGIViewDimension.cpp
user: login: WandererFan
body: Go ahead.
created_at: 2025-05-21T12:54:46Z
author_association: CONTRIBUTOR

PR comments:
user: login: WandererFan
created_at: 2025-05-19T13:35:46Z
body: Is this related to TechDraw: Vertical dimension text has wrong orientation or side #16172?
author_association: CONTRIBUTOR
user: login: benj5378
created_at: 2025-05-19T16:36:36Z
body: > Is this related to TechDraw: Vertical dimension text has wrong orientation or side #16172?

Unsure, but likely not. Most of this is related to the order of function calls
author_association: CONTRIBUTOR
user: login: WandererFan
created_at: 2025-05-21T12:51:26Z
body: Am I right in think there is no visible impact of this change?  

author_association: CONTRIBUTOR
user: login: benj5378
created_at: 2025-05-22T00:09:50Z
body: > Am I right in think there is no visible impact of this change?

Not what I know of... though bugs might be reported. The motivation for doing these changes are to support dimensions with stuff other than frames. Due to the mentioned issues (in PR description), all dimensioning positioning were incorrect when trying do draw frames, circles and other elements in QGIDatumLabel
author_association: CONTRIBUTOR
user: login: benj5378
created_at: 2025-05-22T11:50:32Z
body: Fixes #20613
author_association: CONTRIBUTOR