mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-21 22:04:13 +02:00
Width handles keep the point the text is aligned on
Which point of a symbol's text stays in place while its width is dragged now follows the text's alignment, the nine points of its alignment dialog, rather than the handle: a text aligned top right keeps its top right corner whichever handle is dragged, one centred keeps its middle, and a text that wraps grows away from that point. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1041,6 +1041,8 @@ void DynamicElementTextItem::updateResizeHandlesPos()
|
||||
*/
|
||||
void DynamicElementTextItem::handlerMousePressEvent(QetGraphicsHandlerItem *handle, QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(handle)
|
||||
|
||||
//The actual property value, kept as-is (possibly -1, meaning "auto")
|
||||
//so a later undo restores the exact original state rather than a
|
||||
//synthesized fixed width.
|
||||
@@ -1050,30 +1052,33 @@ void DynamicElementTextItem::handlerMousePressEvent(QetGraphicsHandlerItem *hand
|
||||
m_resize_baseline_width = (m_resize_original_width < 0) ? frameRect().width() : m_resize_original_width;
|
||||
m_resize_start_local_x = mapFromScene(event->scenePos()).x();
|
||||
|
||||
//The edge opposite the dragged handle stays where it is, as in a
|
||||
//drawing program: remember it in the parent's coordinates, which
|
||||
//take the text's rotation into account
|
||||
//The point the text is aligned on stays where it is: 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));
|
||||
m_resize_fixed_parent = mapToParent(resizeAnchor());
|
||||
}
|
||||
|
||||
/**
|
||||
@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.
|
||||
a width handle keeps in place: the point it is aligned on, one of the
|
||||
nine of its alignment (left, centre or right; top, middle or bottom).
|
||||
A text aligned top right keeps its top right corner whichever handle
|
||||
is dragged, and a text that wraps onto more lines while it narrows
|
||||
grows away from that point instead of moving into its neighbours.
|
||||
*/
|
||||
QPointF DynamicElementTextItem::resizeAnchor(bool left_handle) const
|
||||
QPointF DynamicElementTextItem::resizeAnchor() const
|
||||
{
|
||||
const QRectF br = boundingRect();
|
||||
const Qt::Alignment v = alignment() & Qt::AlignVertical_Mask;
|
||||
const qreal y = (v & Qt::AlignBottom) ? br.bottom()
|
||||
: (v & Qt::AlignVCenter) ? br.center().y()
|
||||
const Qt::Alignment a = alignment();
|
||||
const qreal x = (a & Qt::AlignRight) ? br.right()
|
||||
: (a & Qt::AlignHCenter) ? br.center().x()
|
||||
: br.left();
|
||||
const qreal y = (a & Qt::AlignBottom) ? br.bottom()
|
||||
: (a & Qt::AlignVCenter) ? br.center().y()
|
||||
: br.top();
|
||||
return QPointF(left_handle ? br.right() : br.left(), y);
|
||||
return QPointF(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1096,10 +1101,9 @@ void DynamicElementTextItem::handlerMouseMoveEvent(QetGraphicsHandlerItem *handl
|
||||
qreal new_width = qMax(m_resize_baseline_width + delta, qreal(10));
|
||||
setTextWidth(new_width);
|
||||
|
||||
//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)));
|
||||
//Keep the point the text is aligned on in place, whatever the new
|
||||
//width and number of lines
|
||||
setPos(pos() + m_resize_fixed_parent - mapToParent(resizeAnchor()));
|
||||
updateResizeHandlesPos();
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ class DynamicElementTextItem : public DiagramTextItem
|
||||
void addResizeHandles();
|
||||
void removeResizeHandles();
|
||||
void updateResizeHandlesPos();
|
||||
QPointF resizeAnchor(bool left_handle) const;
|
||||
QPointF resizeAnchor() const;
|
||||
void fitAutoTextWidth();
|
||||
void handlerMousePressEvent(QetGraphicsHandlerItem *handle, QGraphicsSceneMouseEvent *event);
|
||||
void handlerMouseMoveEvent(QetGraphicsHandlerItem *handle, QGraphicsSceneMouseEvent *event);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// Width handles of a symbol's text, linked against the application's objects.
|
||||
//
|
||||
// Dragging the left handle of a symbol's text changes its width and keeps
|
||||
// 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. A text narrowed
|
||||
// until it wraps grows downwards from its top corner. Checked for an
|
||||
// upright and a rotated text.
|
||||
// Dragging a width handle of a symbol's text changes its width and keeps
|
||||
// the point the text is aligned on in place, one of the nine of its
|
||||
// alignment: a text aligned top right keeps its top right corner, one
|
||||
// centred its middle. Before, the text always kept its left edge, so a
|
||||
// drag on the left handle moved the right edge and the text jumped. A
|
||||
// text narrowed until it wraps grows away from that point. Undo puts back
|
||||
// the width and the position together. Checked for four alignments, on
|
||||
// an upright and on a rotated text.
|
||||
#include <QApplication>
|
||||
#include <QFontDatabase>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
@@ -57,11 +58,14 @@ 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)
|
||||
/// The point the text is aligned on, one of its nine, in the folio.
|
||||
static QPointF anchor(DynamicElementTextItem *text)
|
||||
{
|
||||
const QRectF br = text->boundingRect();
|
||||
return text->mapToScene(QPointF(left ? br.left() : br.right(), br.top()));
|
||||
const Qt::Alignment a = text->alignment();
|
||||
const qreal x = (a & Qt::AlignRight) ? br.right() : (a & Qt::AlignHCenter) ? br.center().x() : br.left();
|
||||
const qreal y = (a & Qt::AlignBottom) ? br.bottom() : (a & Qt::AlignVCenter) ? br.center().y() : br.top();
|
||||
return text->mapToScene(QPointF(x, y));
|
||||
}
|
||||
|
||||
/// Drag one handle by dx along the text's own baseline.
|
||||
@@ -76,46 +80,55 @@ static void drag(Diagram *scene, DynamicElementTextItem *text, bool left, qreal
|
||||
mouse(scene, h, QEvent::GraphicsSceneMouseRelease, end);
|
||||
}
|
||||
|
||||
static void checkText(Diagram *scene, Element *element, DynamicElementTextItem *text)
|
||||
static void checkText(Diagram *scene, Element *element, DynamicElementTextItem *text, Qt::Alignment alignment)
|
||||
{
|
||||
text->setTextWidth(-1);
|
||||
text->setAlignment(alignment);
|
||||
element->setSelected(true);
|
||||
const QPointF pos = text->pos();
|
||||
const qreal width = text->boundingRect().width();
|
||||
const QPointF right = edge(text, false);
|
||||
const QPointF fixed = anchor(text);
|
||||
|
||||
// Left handle 30 to the left: wider, right edge where it was.
|
||||
// Left handle 30 outwards: wider, the alignment point where it was.
|
||||
drag(scene, text, true, -30);
|
||||
check(text->boundingRect().width() > width + 10, "the left handle widens the text");
|
||||
check(near(edge(text, false), right), "dragging the left handle keeps the right edge in place");
|
||||
|
||||
check(near(anchor(text), fixed), "dragging the left handle keeps the alignment point in place");
|
||||
scene->undoStack().undo();
|
||||
check(near(text->pos(), pos), "undo puts the text back where it was");
|
||||
check(qAbs(text->boundingRect().width() - width) < 0.01, "undo puts the width back");
|
||||
scene->undoStack().redo();
|
||||
check(near(edge(text, false), right), "redo keeps the right edge in place");
|
||||
check(near(anchor(text), fixed), "redo keeps the alignment point in place");
|
||||
scene->undoStack().undo();
|
||||
|
||||
// Right handle 30 to the right: wider, left edge where it was.
|
||||
// Right handle 30 outwards: the same point stays.
|
||||
element->setSelected(true);
|
||||
const QPointF left = edge(text, true);
|
||||
drag(scene, text, false, 30);
|
||||
check(text->boundingRect().width() > width + 10, "the right handle widens the text");
|
||||
check(near(edge(text, true), left), "dragging the right handle keeps the left edge in place");
|
||||
check(near(anchor(text), fixed), "dragging the right handle keeps the alignment point in place");
|
||||
scene->undoStack().undo();
|
||||
check(near(text->pos(), pos), "undo of the right handle leaves the position alone");
|
||||
check(near(text->pos(), pos), "undo of the right handle puts the text back");
|
||||
|
||||
// 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.
|
||||
// Narrowed until it wraps onto more lines: it grows away from the
|
||||
// alignment point, a text aligned at the top downwards, so that it
|
||||
// does not move into what stands above it.
|
||||
element->setSelected(true);
|
||||
const qreal height = text->boundingRect().height();
|
||||
drag(scene, text, true, width - 25);
|
||||
drag(scene, text, false, 25 - width);
|
||||
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");
|
||||
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");
|
||||
element->setSelected(false);
|
||||
}
|
||||
|
||||
static void checkAll(Diagram *scene, Element *element, DynamicElementTextItem *text)
|
||||
{
|
||||
checkText(scene, element, text, Qt::AlignLeft | Qt::AlignTop);
|
||||
checkText(scene, element, text, Qt::AlignRight | Qt::AlignTop);
|
||||
checkText(scene, element, text, Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
checkText(scene, element, text, Qt::AlignRight | Qt::AlignBottom);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
@@ -146,13 +159,13 @@ int main(int argc, char **argv)
|
||||
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
|
||||
checkAll(scene, element, text);
|
||||
// The same on a text turned by 90 degrees: the fixed point is
|
||||
// found along the text's own baseline, not the folio's x axis.
|
||||
text->setRotation(90);
|
||||
checkText(scene, element, text);
|
||||
checkAll(scene, element, text);
|
||||
|
||||
std::puts("PASS: a symbol text's width handles keep the opposite edge in place, undo restores both");
|
||||
std::puts("PASS: a symbol text's width handles keep its alignment point in place, undo restores both");
|
||||
}
|
||||
catch (const std::exception &error)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user