Add "Scale element..." to the element editor, keeping terminals on the grid

Edit > Scale element... scales the whole element about its hotspot by a
factor picked from x0.5, x1.5, x2, x2.5, x3, x4. Only the factors that
leave every terminal on the 10 px folio grid are offered, so wires to a
scaled element stay straight. An element whose terminals are off the grid
today is offered only the factors that bring them on to it; if none does,
the dialog says so and OK is disabled.

Drawn parts are scaled with their existing handleUserTransformation(), as
the resize handles do. Texts, dynamic text fields and terminals are set
directly so that font sizes (whole points, 4 pt minimum), terminal name
offsets and line end sizes scale too, which the resize handles do not do.
One undo step restores the element.

Unlike "Import an element to resize", this needs no external program and
works on the element being edited.

Grew out of issue #1338.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-08 07:11:58 +13:00
parent 06083c455d
commit 35162b6731
10 changed files with 502 additions and 1 deletions
+31 -1
View File
@@ -54,6 +54,7 @@
#include "../../dxf/dxftoelmt.h"
#include "../../qet_elementscaler/qet_elementscaler.h"
#include "../UndoCommand/openelmtcommand.h"
#include "scaleelementdialog.h"
#include "../../toolbarsettings.h"
#include <QSettings>
@@ -1154,6 +1155,12 @@ void QETElementEditor::setupActions()
ShortcutManager::instance().registerAction(ui->m_mirror_action, "elementeditor.mirror", tr("Éditeur d'élément"), Qt::Key_M);
connect(ui->m_mirror_action, &QAction::triggered, [this]() {this -> elementScene() -> undoStack().push(new MirrorElementsCommand(this->elementScene()));});
//Scale the whole element by a factor that keeps its terminals on the grid
m_scale_element_action = new QAction(tr("Mettre l'élément à l'échelle..."), this);
ui->m_edit_menu->addAction(m_scale_element_action);
ShortcutManager::instance().registerAction(m_scale_element_action, "elementeditor.scale_element", tr("Éditeur d'élément"), QKeySequence());
connect(m_scale_element_action, &QAction::triggered, this, &QETElementEditor::scaleElement);
//Zoom action
ShortcutManager::instance().registerAction(ui->m_zoom_in_action, "elementeditor.zoom_in", tr("Éditeur d'élément"), QKeySequence::ZoomIn);
@@ -1247,7 +1254,8 @@ void QETElementEditor::updateAction()
//Action disabled if read only
auto ro_list = m_add_part_action_grp->actions();
ro_list << ui->m_paste_from_file_action
<< ui->m_paste_from_element_action;
<< ui->m_paste_from_element_action
<< m_scale_element_action;
for (auto action : std::as_const(ro_list)) {
action->setDisabled(m_read_only);
}
@@ -1803,6 +1811,28 @@ void QETElementEditor::on_m_import_dxf_triggered()
}
}
/**
@brief QETElementEditor::scaleElement
Ask for a factor that keeps the terminals on the grid,
then scale the whole element by it.
*/
void QETElementEditor::scaleElement()
{
QList<QPointF> terminals;
for (CustomElementPart *part : m_elmt_scene->primitives()) {
if (auto terminal = qgraphicsitem_cast<PartTerminal *>(part->toItem())) {
terminals << terminal->scenePos();
}
}
ScaleElementDialog dialog(terminals, this);
if (dialog.exec() != QDialog::Accepted || dialog.factor() == 1.0) {
return;
}
m_elmt_scene->undoStack().push(
new ScaleElementCommand(m_elmt_scene, dialog.factor(), dialog.scaleText()));
}
void QETElementEditor::on_m_import_scaled_element_triggered()
{
if (ElementScalerIsPresent(true, this))