Width handles: a text is not dragged narrower than its widest word

Narrower, a long word ran out of the text's box while the short lines
were still aligned inside the too narrow width: on a right aligned or
centred text a lone "1" stood in the middle under its words, and moved
on every step. Found on a real plan (-XS20, "Steckdosen Windfang, 1").
The probe checks that no line runs out of the text after narrowing, and
also for a text aligned bottom left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DaTweety
2026-10-20 10:53:52 +02:00
parent 8f2cd9f039
commit 1bf076eca8
3 changed files with 37 additions and 1 deletions
@@ -16,6 +16,8 @@
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dynamicelementtextitem.h"
#include <QScopedPointer>
#include <QTextDocument>
#include "../QetGraphicsItemModeler/textresizehandles.h"
#include "../shownkinds.h"
#include "../qetproject.h"
@@ -1063,6 +1065,20 @@ void DynamicElementTextItem::handlerMousePressEvent(QetGraphicsHandlerItem *hand
m_resize_fixed_parent = mapToParent(resizeAnchor());
}
/**
@brief DynamicElementTextItem::minimumTextWidth
@return the narrowest width the text can be dragged to: that of its
widest word. Narrower, a long word runs out of the text's box while
the short lines are still aligned inside it, and a centred or right
aligned text falls apart (a lone "1" in the middle under its words).
*/
qreal DynamicElementTextItem::minimumTextWidth() const
{
QScopedPointer<QTextDocument> narrowest(document()->clone());
narrowest->setTextWidth(0);
return qMax(narrowest->idealWidth(), qreal(10));
}
/**
@brief DynamicElementTextItem::resizeAnchor
@return the point of the text, in its own coordinates, that a drag on
@@ -1102,7 +1118,7 @@ void DynamicElementTextItem::handlerMouseMoveEvent(QetGraphicsHandlerItem *handl
if (handle == m_left_resize_handle)
delta = -delta;
qreal new_width = qMax(m_resize_baseline_width + delta, qreal(10));
qreal new_width = qMax(m_resize_baseline_width + delta, minimumTextWidth());
setTextWidth(new_width);
//Keep the point the text is aligned on in place, whatever the new
@@ -171,6 +171,7 @@ class DynamicElementTextItem : public DiagramTextItem
void removeResizeHandles();
void updateResizeHandlesPos();
QPointF resizeAnchor() const;
qreal minimumTextWidth() const;
void fitAutoTextWidth();
void handlerMousePressEvent(QetGraphicsHandlerItem *handle, QGraphicsSceneMouseEvent *event);
void handlerMouseMoveEvent(QetGraphicsHandlerItem *handle, QGraphicsSceneMouseEvent *event);
@@ -14,6 +14,9 @@
#include <QGraphicsSceneMouseEvent>
#include <QSettings>
#include <QTemporaryDir>
#include <QTextBlock>
#include <QTextDocument>
#include <QTextLayout>
#include <cstdio>
#include <stdexcept>
@@ -82,6 +85,20 @@ static void drag(Diagram *scene, DynamicElementTextItem *text, bool left, qreal
mouse(scene, h, QEvent::GraphicsSceneMouseRelease, end);
}
/// Every line lies inside the text's width: none runs out of it.
static bool linesInside(DynamicElementTextItem *text)
{
QTextDocument *doc = text->document();
const qreal inner = doc->textWidth() - 2 * doc->documentMargin();
for (QTextBlock b = doc->begin(); b.isValid(); b = b.next())
for (int i = 0; i < b.layout()->lineCount(); ++i) {
const QTextLine line = b.layout()->lineAt(i);
if (line.x() < -0.01 || line.x() + line.naturalTextWidth() > inner + 0.01)
return false;
}
return true;
}
/// The width changed by exactly as much as the mouse moved.
static void checkGrowth(DynamicElementTextItem *text, qreal before, qreal moved, const char *message)
{
@@ -124,6 +141,7 @@ static void checkText(Diagram *scene, Element *element, DynamicElementTextItem *
const qreal height = text->boundingRect().height();
drag(scene, text, false, 25 - width);
check(text->boundingRect().height() > height + 5, "narrowing the text wraps it onto more lines");
check(linesInside(text), "a text is not narrower than its widest word: no line runs out of it");
check(near(anchor(text), fixed), "a text that wraps keeps its alignment point in place");
scene->undoStack().undo();
check(near(text->pos(), pos), "undo puts the wrapped text back");
@@ -136,6 +154,7 @@ static void checkAll(Diagram *scene, Element *element, DynamicElementTextItem *t
checkText(scene, element, text, Qt::AlignRight | Qt::AlignTop);
checkText(scene, element, text, Qt::AlignHCenter | Qt::AlignVCenter);
checkText(scene, element, text, Qt::AlignRight | Qt::AlignBottom);
checkText(scene, element, text, Qt::AlignLeft | Qt::AlignBottom);
}
int main(int argc, char **argv)