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 <noreply@anthropic.com>
This commit is contained in:
DaTweety
2026-10-19 12:19:30 +02:00
parent 74f908aa1e
commit 52adc8b3f8
3 changed files with 41 additions and 11 deletions
@@ -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();
}
@@ -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);
+17 -2
View File
@@ -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 <QApplication>
#include <QFontDatabase>
@@ -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