Merge pull request #591 from ispyisail/feature-dynamictext-drag-resize
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 2m32s

Add drag-to-resize for dynamic element text width (#577 phase 1)
This commit is contained in:
Laurent Trinques
2026-09-21 12:19:22 +02:00
committed by GitHub
2 changed files with 171 additions and 5 deletions
@@ -24,6 +24,7 @@
#include "../qetgraphicsitem/terminal.h"
#include "../qetinformation.h"
#include "../utils/qetutils.h"
#include "../QetGraphicsItemModeler/qetgraphicshandleritem.h"
#include "crossrefitem.h"
#include "element.h"
#include "elementtextitemgroup.h"
@@ -67,7 +68,9 @@ DynamicElementTextItem::DynamicElementTextItem(Element *parent_element) :
}
DynamicElementTextItem::~DynamicElementTextItem()
{}
{
removeResizeHandles();
}
/**
@brief DynamicElementTextItem::textFromMetaEnum
@@ -728,7 +731,10 @@ void DynamicElementTextItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
void DynamicElementTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
DiagramTextItem::paint(painter, option, widget);
if (m_left_resize_handle || m_right_resize_handle)
updateResizeHandlesPos();
if (m_frame)
{
painter->save();
@@ -818,15 +824,44 @@ QVariant DynamicElementTextItem::itemChange(QGraphicsItem::GraphicsItemChange ch
updateXref();
updateXref();
}
else if (change == QGraphicsItem::ItemSelectedHasChanged)
{
if (value.toBool())
addResizeHandles();
else
removeResizeHandles();
}
else if (change == QGraphicsItem::ItemSceneHasChanged && !scene())
{
removeResizeHandles();
}
return QGraphicsObject::itemChange(change, value);
}
bool DynamicElementTextItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
{
if (watched == m_left_resize_handle || watched == m_right_resize_handle)
{
auto *handle = static_cast<QetGraphicsHandlerItem *>(watched);
if (event->type() == QEvent::GraphicsSceneMousePress) {
handlerMousePressEvent(handle, static_cast<QGraphicsSceneMouseEvent *>(event));
return true;
}
else if (event->type() == QEvent::GraphicsSceneMouseMove) {
handlerMouseMoveEvent(handle, static_cast<QGraphicsSceneMouseEvent *>(event));
return true;
}
else if (event->type() == QEvent::GraphicsSceneMouseRelease) {
handlerMouseReleaseEvent(handle, static_cast<QGraphicsSceneMouseEvent *>(event));
return true;
}
return false;
}
if(watched != m_slave_Xref_item)
return false;
if(event->type() == QEvent::GraphicsSceneHoverEnter) {
m_slave_Xref_item->setDefaultTextColor(Qt::blue);
return true;
@@ -839,10 +874,129 @@ bool DynamicElementTextItem::sceneEventFilter(QGraphicsItem *watched, QEvent *ev
zoomToLinkedElement();
return true;
}
return false;
}
/**
@brief DynamicElementTextItem::addResizeHandles
Create and show the two width-resize handles (left/right edge of
frameRect()), reusing QetGraphicsHandlerItem the same way QetShapeItem
does for its own resize handles.
*/
void DynamicElementTextItem::addResizeHandles()
{
if (m_left_resize_handle || !scene())
return;
qreal size = QETUtils::graphicsHandlerSize(this);
m_left_resize_handle = new QetGraphicsHandlerItem(size);
m_right_resize_handle = new QetGraphicsHandlerItem(size);
for (QetGraphicsHandlerItem *handle : {m_left_resize_handle, m_right_resize_handle})
{
scene()->addItem(handle);
handle->setColor(Qt::darkGreen);
handle->setZValue(zValue() + 1);
handle->installSceneEventFilter(this);
}
updateResizeHandlesPos();
}
/**
@brief DynamicElementTextItem::removeResizeHandles
*/
void DynamicElementTextItem::removeResizeHandles()
{
delete m_left_resize_handle;
delete m_right_resize_handle;
m_left_resize_handle = nullptr;
m_right_resize_handle = nullptr;
}
/**
@brief DynamicElementTextItem::updateResizeHandlesPos
Keep the two resize handles at the vertical middle of frameRect()'s left
and right edges, in scene coordinates -- called on every paint() so it
stays correct across every kind of change that can move this item or
change its size (position, rotation, font, text, textWidth...) without
needing a dedicated hook for each one.
*/
void DynamicElementTextItem::updateResizeHandlesPos()
{
if (!m_left_resize_handle || !m_right_resize_handle)
return;
QRectF fr = frameRect();
m_left_resize_handle->setPos(mapToScene(QPointF(fr.left(), fr.center().y())));
m_right_resize_handle->setPos(mapToScene(QPointF(fr.right(), fr.center().y())));
}
/**
@brief DynamicElementTextItem::handlerMousePressEvent
@param handle
@param event
*/
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.
m_resize_original_width = textWidth();
//A concrete baseline for the live drag's delta math, which can't
//start from -1.
m_resize_baseline_width = (m_resize_original_width < 0) ? frameRect().width() : m_resize_original_width;
m_resize_start_local_x = mapFromScene(event->scenePos()).x();
}
/**
@brief DynamicElementTextItem::handlerMouseMoveEvent
Live-resize the text while dragging, exactly like the element editor's
resize handles live-update geometry during a drag (undo is only pushed
on release). The drag delta is resolved in this item's own local
coordinates (not scene coordinates) so a rotated text box still resizes
along its own baseline.
@param handle
@param event
*/
void DynamicElementTextItem::handlerMouseMoveEvent(QetGraphicsHandlerItem *handle, QGraphicsSceneMouseEvent *event)
{
qreal local_x = mapFromScene(event->scenePos()).x();
qreal delta = local_x - m_resize_start_local_x;
if (handle == m_left_resize_handle)
delta = -delta;
qreal new_width = qMax(m_resize_baseline_width + delta, qreal(10));
setTextWidth(new_width);
updateResizeHandlesPos();
}
/**
@brief DynamicElementTextItem::handlerMouseReleaseEvent
Push the same QPropertyUndoCommand the properties-panel width spinbox
already pushes (sources/ui/dynamicelementtextmodel.cpp) -- the value is
already applied live from the drag, so this only makes it undoable.
@param handle
@param event
*/
void DynamicElementTextItem::handlerMouseReleaseEvent(QetGraphicsHandlerItem *handle, QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(handle)
Q_UNUSED(event)
qreal new_width = textWidth();
if (!qFuzzyCompare(m_resize_original_width, new_width) && m_parent_element && m_parent_element->diagram())
{
auto *undo = new QPropertyUndoCommand(this, "textWidth", QVariant(m_resize_original_width), QVariant(new_width));
undo->setAnimated(true, false);
undo->setText(tr("Redimensionner un texte d'élément"));
m_parent_element->diagram()->undoStack().push(undo);
}
}
void DynamicElementTextItem::elementInfoChanged()
{
DiagramContext dc;