From 52adc8b3f806f47b0c317b4df661334bb1469d00 Mon Sep 17 00:00:00 2001 From: DaTweety <129504390+DaTweety@users.noreply.github.com> Date: Mon, 19 Oct 2026 12:19:30 +0200 Subject: [PATCH] Width handles: a text that wraps keeps its top corner in place Narrowing a symbol's text with the left handle until it wraps onto more lines moved it up: the point kept in place was the middle of the opposite edge, and the middle moves down as the text grows. Keep the top of the opposite edge instead, or the middle or the bottom for a text aligned that way, for both handles. Co-Authored-By: Claude Opus 5.5 --- .../dynamicelementtextitem.cpp | 32 +++++++++++++------ .../qetgraphicsitem/dynamicelementtextitem.h | 1 + tests/qttest/element_text_resize_probe.cpp | 19 +++++++++-- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/sources/qetgraphicsitem/dynamicelementtextitem.cpp b/sources/qetgraphicsitem/dynamicelementtextitem.cpp index 0a04a63b9..78db79049 100644 --- a/sources/qetgraphicsitem/dynamicelementtextitem.cpp +++ b/sources/qetgraphicsitem/dynamicelementtextitem.cpp @@ -1054,9 +1054,26 @@ void DynamicElementTextItem::handlerMousePressEvent(QetGraphicsHandlerItem *hand //drawing program: remember it in the parent's coordinates, which //take the text's rotation into account m_resize_start_pos = pos(); + m_resize_fixed_parent = mapToParent(resizeAnchor(handle == m_left_resize_handle)); +} + +/** + @brief DynamicElementTextItem::resizeAnchor + @param left_handle : the left width handle is dragged + @return the point of the text, in its own coordinates, that a drag on + a width handle keeps in place: on the opposite edge, and at the top, + the middle or the bottom as the text is aligned. A text that wraps onto + more lines while it narrows then grows away from that point, down for + a text aligned at the top, instead of moving into its neighbours. +*/ +QPointF DynamicElementTextItem::resizeAnchor(bool left_handle) const +{ const QRectF br = boundingRect(); - m_resize_fixed_parent = mapToParent(QPointF(handle == m_left_resize_handle ? br.right() : br.left(), - br.center().y())); + const Qt::Alignment v = alignment() & Qt::AlignVertical_Mask; + const qreal y = (v & Qt::AlignBottom) ? br.bottom() + : (v & Qt::AlignVCenter) ? br.center().y() + : br.top(); + return QPointF(left_handle ? br.right() : br.left(), y); } /** @@ -1079,13 +1096,10 @@ void DynamicElementTextItem::handlerMouseMoveEvent(QetGraphicsHandlerItem *handl qreal new_width = qMax(m_resize_baseline_width + delta, qreal(10)); setTextWidth(new_width); - //The text grows and shrinks on its right side: dragging the left - //handle moves the text so that its right edge stays in place - if (handle == m_left_resize_handle) - { - const QRectF br = boundingRect(); - setPos(pos() + m_resize_fixed_parent - mapToParent(QPointF(br.right(), br.center().y()))); - } + //Keep the opposite edge in place, and the top, middle or bottom + //as the text is aligned, whatever the new number of lines + setPos(pos() + m_resize_fixed_parent + - mapToParent(resizeAnchor(handle == m_left_resize_handle))); updateResizeHandlesPos(); } diff --git a/sources/qetgraphicsitem/dynamicelementtextitem.h b/sources/qetgraphicsitem/dynamicelementtextitem.h index 4fc22b5a8..3077282c7 100644 --- a/sources/qetgraphicsitem/dynamicelementtextitem.h +++ b/sources/qetgraphicsitem/dynamicelementtextitem.h @@ -170,6 +170,7 @@ class DynamicElementTextItem : public DiagramTextItem void addResizeHandles(); void removeResizeHandles(); void updateResizeHandlesPos(); + QPointF resizeAnchor(bool left_handle) const; void fitAutoTextWidth(); void handlerMousePressEvent(QetGraphicsHandlerItem *handle, QGraphicsSceneMouseEvent *event); void handlerMouseMoveEvent(QetGraphicsHandlerItem *handle, QGraphicsSceneMouseEvent *event); diff --git a/tests/qttest/element_text_resize_probe.cpp b/tests/qttest/element_text_resize_probe.cpp index 199c66e8f..ee7d02896 100644 --- a/tests/qttest/element_text_resize_probe.cpp +++ b/tests/qttest/element_text_resize_probe.cpp @@ -5,7 +5,8 @@ // its right edge in place; dragging the right handle keeps its left edge, // as in a drawing program. Before, the text always kept its left edge, so // a drag on the left handle moved the right edge and the text jumped. -// Undo puts back the width and the position together. Checked for an +// Undo puts back the width and the position together. A text narrowed +// until it wraps grows downwards from its top corner. Checked for an // upright and a rotated text. #include #include @@ -56,10 +57,11 @@ static QetGraphicsHandlerItem *handle(DynamicElementTextItem *text, bool left) return found; } +/// The top corner of the text on the left or right, in the folio. static QPointF edge(DynamicElementTextItem *text, bool left) { const QRectF br = text->boundingRect(); - return text->mapToScene(QPointF(left ? br.left() : br.right(), br.center().y())); + return text->mapToScene(QPointF(left ? br.left() : br.right(), br.top())); } /// Drag one handle by dx along the text's own baseline. @@ -101,6 +103,16 @@ static void checkText(Diagram *scene, Element *element, DynamicElementTextItem * check(near(edge(text, true), left), "dragging the right handle keeps the left edge in place"); scene->undoStack().undo(); check(near(text->pos(), pos), "undo of the right handle leaves the position alone"); + + // Narrowed until it wraps onto more lines with the left handle: the + // text grows downwards from its top right corner, it does not move up + // into what stands above it. + const qreal height = text->boundingRect().height(); + drag(scene, text, true, width - 25); + check(text->boundingRect().height() > height + 5, "narrowing the text wraps it onto more lines"); + check(near(edge(text, false), right), "a text that wraps keeps its top right corner in place"); + scene->undoStack().undo(); + check(near(text->pos(), pos), "undo puts the wrapped text back"); element->setSelected(false); } @@ -130,6 +142,9 @@ int main(int argc, char **argv) for (DynamicElementTextItem *t : e->dynamicTextItems()) if (!text) { text = t; element = e; } check(text, "the fixture has a symbol with a text"); + // Several words, so that narrowing it makes it wrap + text->setTextFrom(DynamicElementTextItem::UserText); + text->setText(QStringLiteral("Sockets bathroom first floor, 5")); checkText(scene, element, text); // The same on a text turned by 90 degrees: the fixed edge is