From c884d32dbe6409956e1b5fc9f5ad324b9353f10e Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Thu, 9 Jul 2026 14:02:27 +0200 Subject: [PATCH 1/3] Feature: Add terminal name label display in element editor --- sources/editor/graphicspart/partterminal.cpp | 230 +++++++++++++++- sources/editor/graphicspart/partterminal.h | 51 +++- sources/editor/ui/terminaleditor.cpp | 270 ++++++++++++++----- sources/editor/ui/terminaleditor.h | 19 ++ sources/editor/ui/terminaleditor.ui | 147 +++++++++- sources/properties/terminaldata.cpp | 40 +++ sources/properties/terminaldata.h | 19 ++ sources/qetgraphicsitem/terminal.cpp | 59 +++- 8 files changed, 753 insertions(+), 82 deletions(-) diff --git a/sources/editor/graphicspart/partterminal.cpp b/sources/editor/graphicspart/partterminal.cpp index feb4eca0e..d6ff367d1 100644 --- a/sources/editor/graphicspart/partterminal.cpp +++ b/sources/editor/graphicspart/partterminal.cpp @@ -17,6 +17,8 @@ */ #include "partterminal.h" +#include "../elementscene.h" +#include "../../QPropertyUndoCommand/qpropertyundocommand.h" #include "../../qetgraphicsitem/terminal.h" /** @@ -100,6 +102,60 @@ void PartTerminal::paint( if (m_hovered) drawShadowShape(painter); + + if (d->m_show_name && !d->m_name.isEmpty()) { + painter->save(); + painter->setFont(d->m_label_font); + painter->setPen(d->m_label_color); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->setRenderHint(QPainter::TextAntialiasing, true); + + QPointF label_pos = d->m_label_pos; + QRectF text_rect; + QFontMetrics fm(d->m_label_font); + QSizeF text_size = fm.size(Qt::TextSingleLine, d->m_name); + + auto compute_rect = [&]() { + qreal dx = 0, dy = 0; + if (d->m_label_halignment & Qt::AlignLeft) dx = 0; + else if (d->m_label_halignment & Qt::AlignHCenter) dx = -text_size.width() / 2.0; + else if (d->m_label_halignment & Qt::AlignRight) dx = -text_size.width(); + if (d->m_label_valignment & Qt::AlignTop) dy = 0; + else if (d->m_label_valignment & Qt::AlignVCenter) dy = -text_size.height() / 2.0; + else if (d->m_label_valignment & Qt::AlignBottom) dy = -text_size.height(); + return QRectF(label_pos + QPointF(dx, dy), text_size); + }; + + if (d->m_label_rotation != 0.0) { + painter->translate(label_pos); + painter->rotate(d->m_label_rotation); + text_rect = QRectF(-text_size.width()/2.0, -text_size.height()/2.0, + text_size.width(), text_size.height()); + if (d->m_label_frame) { + painter->drawRect(text_rect.adjusted(-1, -1, 1, 1)); + } + painter->drawText(text_rect, static_cast(d->m_label_halignment | d->m_label_valignment), d->m_name); + } else { + text_rect = compute_rect(); + if (d->m_label_frame) { + painter->drawRect(text_rect.adjusted(-1, -1, 1, 1)); + } + painter->drawText(text_rect, static_cast(Qt::AlignLeft | Qt::AlignTop), d->m_name); + } + + if (isSelected() || m_hovered) { + QPen outline_pen(Qt::darkBlue, 0, Qt::DashLine); + painter->setPen(outline_pen); + painter->setBrush(Qt::NoBrush); + if (d->m_label_rotation != 0.0) { + painter->drawRect(text_rect.adjusted(-1, -1, 1, 1)); + } else { + painter->drawRect(text_rect.adjusted(-1, -1, 1, 1)); + } + } + + painter->restore(); + } } /** @@ -114,7 +170,27 @@ QPainterPath PartTerminal::shape() const QPainterPathStroker pps; pps.setWidth(1); - return (pps.createStroke(shape)); + QPainterPath path = pps.createStroke(shape); + + if (d->m_show_name && !d->m_name.isEmpty()) { + path.addRect(labelRect()); + } + + return path; +} + +/** + @brief PartTerminal::shadowShape + @return the hover outline shape (terminal line only, no label rect) +*/ +QPainterPath PartTerminal::shadowShape() const +{ + QPainterPath shape; + shape.lineTo(d -> m_second_point); + + QPainterPathStroker pps; + pps.setWidth(1); + return pps.createStroke(shape); } /** @@ -128,9 +204,40 @@ QRectF PartTerminal::boundingRect() const qreal adjust = (SHADOWS_HEIGHT + 1) / 2; br.adjust(-adjust, -adjust, adjust, adjust); + + if (d->m_show_name && !d->m_name.isEmpty()) { + br = br.united(labelRect()); + } + return(br); } +/** + @brief PartTerminal::labelRect + @return the rectangle of the label text (in item coordinates), + or an empty rect if the label is not shown +*/ +QRectF PartTerminal::labelRect() const +{ + if (!d->m_show_name || d->m_name.isEmpty()) + return QRectF(); + + QFontMetrics fm(d->m_label_font); + QSizeF text_size = fm.size(Qt::TextSingleLine, d->m_name); + QPointF label_pos = d->m_label_pos; + + qreal dx = 0, dy = 0; + if (d->m_label_halignment & Qt::AlignLeft) dx = 0; + else if (d->m_label_halignment & Qt::AlignHCenter) dx = -text_size.width() / 2.0; + else if (d->m_label_halignment & Qt::AlignRight) dx = -text_size.width(); + + if (d->m_label_valignment & Qt::AlignTop) dy = 0; + else if (d->m_label_valignment & Qt::AlignVCenter) dy = -text_size.height() / 2.0; + else if (d->m_label_valignment & Qt::AlignBottom) dy = -text_size.height(); + + return QRectF(label_pos + QPointF(dx, dy), text_size).adjusted(-3, -3, 3, 3); +} + /** Definit l'orientation de la borne @@ -282,6 +389,77 @@ void PartTerminal::setNewUuid() d -> m_uuid = QUuid::createUuid(); } +void PartTerminal::setShowName(bool show) +{ + if (d->m_show_name == show) return; + prepareGeometryChange(); + d->m_show_name = show; + update(); + emit showNameChanged(); +} + +void PartTerminal::setLabelPos(QPointF pos) +{ + if (d->m_label_pos == pos) return; + prepareGeometryChange(); + d->m_label_pos = pos; + update(); + emit labelPosChanged(); +} + +void PartTerminal::setLabelFont(QFont font) +{ + if (d->m_label_font == font) return; + prepareGeometryChange(); + d->m_label_font = font; + update(); + emit labelFontChanged(); +} + +void PartTerminal::setLabelRotation(qreal rotation) +{ + if (qFuzzyCompare(d->m_label_rotation, rotation)) return; + prepareGeometryChange(); + d->m_label_rotation = rotation; + update(); + emit labelRotationChanged(); +} + +void PartTerminal::setLabelHAlignment(Qt::Alignment align) +{ + if (d->m_label_halignment == align) return; + prepareGeometryChange(); + d->m_label_halignment = align; + update(); + emit labelHAlignmentChanged(); +} + +void PartTerminal::setLabelVAlignment(Qt::Alignment align) +{ + if (d->m_label_valignment == align) return; + prepareGeometryChange(); + d->m_label_valignment = align; + update(); + emit labelVAlignmentChanged(); +} + +void PartTerminal::setLabelFrame(bool frame) +{ + if (d->m_label_frame == frame) return; + prepareGeometryChange(); + d->m_label_frame = frame; + update(); + emit labelFrameChanged(); +} + +void PartTerminal::setLabelColor(QColor color) +{ + if (d->m_label_color == color) return; + d->m_label_color = color; + update(); + emit labelColorChanged(); +} + /** Updates the position of the second point according to the position and orientation of the terminal. @@ -338,3 +516,53 @@ void PartTerminal::handleUserTransformation(const QRectF &initial_selection_rect initial_selection_rect, new_selection_rect, QList() << saved_position_).first(); setPos(mapped_point); } + +void PartTerminal::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (event->button() == Qt::LeftButton && d->m_show_name && !d->m_name.isEmpty()) { + QPointF local_click = event->pos(); + // Only start label drag when click is on label AND NOT on terminal line + if (!shadowShape().contains(local_click) && labelRect().contains(local_click)) { + m_dragging_label = true; + m_original_label_pos = d->m_label_pos; + } + } + CustomElementGraphicPart::mousePressEvent(event); +} + +void PartTerminal::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (m_dragging_label) { + QPointF delta = event->pos() - event->buttonDownPos(Qt::LeftButton); + QPointF new_pos = m_original_label_pos + delta; + if (!(event->modifiers() & Qt::ControlModifier)) { + ElementScene *scene = elementScene(); + if (scene) { + QPointF scene_pos = mapToScene(new_pos); + new_pos = mapFromScene(scene->snapToGrid(scene_pos)); + } + } + setLabelPos(new_pos); + update(); + event->accept(); + return; + } + CustomElementGraphicPart::mouseMoveEvent(event); +} + +void PartTerminal::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if (m_dragging_label) { + m_dragging_label = false; + if (m_original_label_pos != d->m_label_pos) { + auto undo = new QPropertyUndoCommand(this, "label_pos", + QVariant(m_original_label_pos), QVariant(d->m_label_pos)); + undo->setText(tr("Déplacer le label d'une borne")); + undo->enableAnimation(); + elementScene()->undoStack().push(undo); + } + event->accept(); + return; + } + CustomElementGraphicPart::mouseReleaseEvent(event); +} diff --git a/sources/editor/graphicspart/partterminal.h b/sources/editor/graphicspart/partterminal.h index 64462c234..c13db27c5 100644 --- a/sources/editor/graphicspart/partterminal.h +++ b/sources/editor/graphicspart/partterminal.h @@ -34,6 +34,14 @@ class PartTerminal : public CustomElementGraphicPart Q_PROPERTY(Qet::Orientation orientation READ orientation WRITE setOrientation) Q_PROPERTY(QString terminal_name READ terminalName WRITE setTerminalName) Q_PROPERTY(TerminalData::Type terminal_type READ terminalType WRITE setTerminalType) + Q_PROPERTY(bool show_name READ showName WRITE setShowName) + Q_PROPERTY(QPointF label_pos READ labelPos WRITE setLabelPos) + Q_PROPERTY(QFont label_font READ labelFont WRITE setLabelFont) + Q_PROPERTY(qreal label_rotation READ labelRotation WRITE setLabelRotation) + Q_PROPERTY(Qt::Alignment label_halignment READ labelHAlignment WRITE setLabelHAlignment) + Q_PROPERTY(Qt::Alignment label_valignment READ labelVAlignment WRITE setLabelVAlignment) + Q_PROPERTY(bool label_frame READ labelFrame WRITE setLabelFrame) + Q_PROPERTY(QColor label_color READ labelColor WRITE setLabelColor) public: // constructors, destructor @@ -46,6 +54,14 @@ class PartTerminal : public CustomElementGraphicPart void orientationChanged(); void nameChanged(); void terminalTypeChanged(); + void showNameChanged(); + void labelPosChanged(); + void labelFontChanged(); + void labelRotationChanged(); + void labelHAlignmentChanged(); + void labelVAlignmentChanged(); + void labelFrameChanged(); + void labelColorChanged(); // methods public: @@ -64,7 +80,7 @@ class PartTerminal : public CustomElementGraphicPart QWidget *) override; QPainterPath shape() const override; - QPainterPath shadowShape() const override {return shape();} + QPainterPath shadowShape() const override; QRectF boundingRect() const override; bool isUseless() const override; QRectF sceneGeometricRect() const override; @@ -90,13 +106,46 @@ class PartTerminal : public CustomElementGraphicPart TerminalData::Type terminalType() const {return d->m_type;} void setTerminalType(TerminalData::Type type); + bool showName() const { return d->m_show_name; } + void setShowName(bool show); + + QPointF labelPos() const { return d->m_label_pos; } + void setLabelPos(QPointF pos); + + QFont labelFont() const { return d->m_label_font; } + void setLabelFont(QFont font); + + qreal labelRotation() const { return d->m_label_rotation; } + void setLabelRotation(qreal rotation); + + Qt::Alignment labelHAlignment() const { return d->m_label_halignment; } + void setLabelHAlignment(Qt::Alignment align); + + Qt::Alignment labelVAlignment() const { return d->m_label_valignment; } + void setLabelVAlignment(Qt::Alignment align); + + bool labelFrame() const { return d->m_label_frame; } + void setLabelFrame(bool frame); + + QColor labelColor() const { return d->m_label_color; } + void setLabelColor(QColor color); + void setNewUuid(); + QRectF labelRect() const; + + protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + private: void updateSecondPoint(); TerminalData* d; // pointer to the terminal data private: QPointF saved_position_; + bool m_dragging_label = false; + QPointF m_original_label_pos; }; #endif diff --git a/sources/editor/ui/terminaleditor.cpp b/sources/editor/ui/terminaleditor.cpp index 4069dba8c..f34a0f8bc 100644 --- a/sources/editor/ui/terminaleditor.cpp +++ b/sources/editor/ui/terminaleditor.cpp @@ -1,55 +1,43 @@ -/* - Copyright 2006-2026 The QElectroTech Team - This file is part of QElectroTech. - - QElectroTech is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - QElectroTech is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with QElectroTech. If not, see . -*/ #include "terminaleditor.h" #include "ui_terminaleditor.h" #include "../../qeticons.h" #include "../../qet.h" #include "../graphicspart/partterminal.h" #include "../../QPropertyUndoCommand/qpropertyundocommand.h" +#include "../../ui/alignmenttextdialog.h" + +#include +#include -/** - * @brief TerminalEditor::TerminalEditor - * Default constructor - * @param editor : element editor of which this terminal editor belong - * @param parent : parent widget - */ TerminalEditor::TerminalEditor(QETElementEditor *editor, QWidget *parent) : ElementItemEditor(editor, parent), ui(new Ui::TerminalEditor) { ui->setupUi(this); + +#ifdef BUILD_WITHOUT_KF5 + m_color_pb = new QPushButton(this); + m_color_pb->setMinimumSize(40, 24); + connect(m_color_pb, &QPushButton::clicked, this, &TerminalEditor::labelColorClicked); +#else + m_color_pb = new KColorButton(this); + m_color_pb->setMinimumSize(40, 24); + connect(m_color_pb, &KColorButton::changed, this, &TerminalEditor::labelColorClicked); +#endif + + QLayout *layout = ui->m_color_widget->parentWidget()->layout(); + layout->replaceWidget(ui->m_color_widget, m_color_pb); + delete ui->m_color_widget; + ui->m_color_widget = nullptr; + init(); } -/** - * @brief TerminalEditor::~TerminalEditor - * Destructor - */ TerminalEditor::~TerminalEditor() { delete ui; } -/** - * @brief TerminalEditor::updateForm - * Reimplemented from ElementItemEditor - * Update the content of this widget - */ void TerminalEditor::updateForm() { if (!m_part) { @@ -63,16 +51,27 @@ void TerminalEditor::updateForm() ui->m_name_le->setText(m_part->terminalName()); ui->m_type_cb->setCurrentIndex(ui->m_type_cb->findData(m_part->terminalType())); + ui->m_show_name_cb->setChecked(m_part->showName()); + ui->m_label_x_dsb->setValue(m_part->labelPos().x()); + ui->m_label_y_dsb->setValue(m_part->labelPos().y()); + ui->m_font_pb->setText(m_part->labelFont().family()); + ui->m_label_size_sb->setValue(m_part->labelFont().pointSize()); + ui->m_label_rotation_sb->setValue(static_cast(m_part->labelRotation())); + ui->m_label_frame_cb->setChecked(m_part->labelFrame()); + +#ifdef BUILD_WITHOUT_KF5 + QPixmap px(16, 16); + px.fill(m_part->labelColor()); + m_color_pb->setIcon(QIcon(px)); +#else + m_color_pb->setColor(m_part->labelColor()); +#endif + + ui->m_text_props_gb->setEnabled(m_part->showName()); + activeConnections(true); } -/** - * @brief TerminalEditor::setPart - * Set the part to edit. - * The part must be a PartTerminal, in other case return false. - * @param new_part : the part to edit - * @return true if the part can be edited. - */ bool TerminalEditor::setPart(CustomElementPart *new_part) { if (m_part == new_part) { @@ -97,21 +96,11 @@ bool TerminalEditor::setPart(CustomElementPart *new_part) return(false); } -/** - * @brief TerminalEditor::currentPart - * @return the current edited part - * or nullptr if there is no part or several part - * @see QList TerminalEditor::currentParts() const - */ CustomElementPart *TerminalEditor::currentPart() const { return m_part; } -/** - * @brief TerminalEditor::init - * Some init about this class - */ void TerminalEditor::init() { ui->m_orientation_cb->addItem(QET::Icons::North, tr("Nord"), Qet::North); @@ -125,11 +114,10 @@ void TerminalEditor::init() ui->m_type_cb->addItem(tr("NO (contact SW)"), TerminalData::No); ui->m_type_cb->addItem(tr("NC (contact SW)"), TerminalData::Nc); ui->m_type_cb->addItem(tr("Commun (contact SW)"), TerminalData::Common); + + ui->m_text_props_gb->setEnabled(false); } -/** - * @brief TerminalEditor::posEdited - */ void TerminalEditor::posEdited() { if (m_locked) { @@ -151,9 +139,6 @@ void TerminalEditor::posEdited() m_locked = false; } -/** - * @brief TerminalEditor::orientationEdited - */ void TerminalEditor::orientationEdited() { if (m_locked) { @@ -172,9 +157,6 @@ void TerminalEditor::orientationEdited() m_locked = false; } -/** - * @brief TerminalEditor::nameEdited - */ void TerminalEditor::nameEdited() { if (m_locked) { @@ -193,9 +175,6 @@ void TerminalEditor::nameEdited() m_locked=false; } -/** - * @brief TerminalEditor::typeEdited - */ void TerminalEditor::typeEdited() { if (m_locked) { @@ -212,12 +191,145 @@ void TerminalEditor::typeEdited() m_locked = false; } -/** - * @brief TerminalEditor::activeConnections - * Active connection between the widgets used in this editor - * and method of this class. - * @param active - */ +void TerminalEditor::showNameEdited() +{ + if (m_locked) return; + m_locked = true; + + bool show = ui->m_show_name_cb->isChecked(); + if (m_part->showName() != show) { + auto undo = new QPropertyUndoCommand(m_part, "show_name", m_part->showName(), show); + undo->setText(tr("Afficher/cacher le nom du terminal")); + undoStack().push(undo); + } + ui->m_text_props_gb->setEnabled(show); + m_locked = false; +} + +void TerminalEditor::labelPosEdited() +{ + if (m_locked) return; + m_locked = true; + + QPointF new_pos(ui->m_label_x_dsb->value(), ui->m_label_y_dsb->value()); + if (m_part->labelPos() != new_pos) { + auto undo = new QPropertyUndoCommand(m_part, "label_pos", m_part->labelPos(), new_pos); + undo->setText(tr("Modifier la position du label")); + undoStack().push(undo); + } + m_locked = false; +} + +void TerminalEditor::labelFontClicked() +{ + if (m_locked) return; + m_locked = true; + + bool ok; + QFont font = QFontDialog::getFont(&ok, m_part->labelFont(), this); + if (ok && font != m_part->labelFont()) { + ui->m_font_pb->setText(font.family()); + ui->m_label_size_sb->blockSignals(true); + ui->m_label_size_sb->setValue(font.pointSize()); + ui->m_label_size_sb->blockSignals(false); + + auto undo = new QPropertyUndoCommand(m_part, "label_font", m_part->labelFont(), font); + undo->setText(tr("Modifier la police du label")); + undoStack().push(undo); + } + m_locked = false; +} + +void TerminalEditor::labelSizeEdited() +{ + if (m_locked) return; + m_locked = true; + + QFont new_font = m_part->labelFont(); + new_font.setPointSize(ui->m_label_size_sb->value()); + if (m_part->labelFont() != new_font) { + auto undo = new QPropertyUndoCommand(m_part, "label_font", m_part->labelFont(), new_font); + undo->setText(tr("Modifier la taille de police du label")); + undoStack().push(undo); + } + m_locked = false; +} + +void TerminalEditor::labelRotationEdited() +{ + if (m_locked) return; + m_locked = true; + + qreal rot = static_cast(ui->m_label_rotation_sb->value()); + if (!qFuzzyCompare(m_part->labelRotation(), rot)) { + auto undo = new QPropertyUndoCommand(m_part, "label_rotation", m_part->labelRotation(), rot); + undo->setText(tr("Modifier la rotation du label")); + undoStack().push(undo); + } + m_locked = false; +} + +void TerminalEditor::labelAlignClicked() +{ + Qt::Alignment align = m_part->labelHAlignment() | m_part->labelVAlignment(); + AlignmentTextDialog dialog(align, this); + if (dialog.exec() == QDialog::Accepted) { + Qt::Alignment new_align = dialog.alignment(); + Qt::Alignment new_h = new_align & Qt::AlignHorizontal_Mask; + Qt::Alignment new_v = new_align & Qt::AlignVertical_Mask; + + if (new_h != m_part->labelHAlignment()) { + auto undo = new QPropertyUndoCommand(m_part, "label_halignment", + QVariant::fromValue(m_part->labelHAlignment()), QVariant::fromValue(new_h)); + undo->setText(tr("Modifier l'alignement du label")); + undoStack().push(undo); + } + if (new_v != m_part->labelVAlignment()) { + auto undo = new QPropertyUndoCommand(m_part, "label_valignment", + QVariant::fromValue(m_part->labelVAlignment()), QVariant::fromValue(new_v)); + undo->setText(tr("Modifier l'alignement du label")); + undoStack().push(undo); + } + } +} + +void TerminalEditor::labelFrameEdited() +{ + if (m_locked) return; + m_locked = true; + + bool frame = ui->m_label_frame_cb->isChecked(); + if (m_part->labelFrame() != frame) { + auto undo = new QPropertyUndoCommand(m_part, "label_frame", m_part->labelFrame(), frame); + undo->setText(tr("Afficher/cacher le cadre du label")); + undoStack().push(undo); + } + m_locked = false; +} + +void TerminalEditor::labelColorClicked() +{ + if (m_locked) return; + m_locked = true; + +#ifdef BUILD_WITHOUT_KF5 + QColor new_color = QColorDialog::getColor(m_part->labelColor(), this); + if (new_color.isValid() && m_part->labelColor() != new_color) { + auto undo = new QPropertyUndoCommand(m_part, "label_color", m_part->labelColor(), new_color); + undo->setText(tr("Modifier la couleur du label")); + undoStack().push(undo); + } +#else + QColor new_color = m_color_pb->color(); + if (new_color.isValid() && m_part->labelColor() != new_color) { + auto undo = new QPropertyUndoCommand(m_part, "label_color", m_part->labelColor(), new_color); + undo->setText(tr("Modifier la couleur du label")); + undoStack().push(undo); + } +#endif + m_locked = false; +} + void TerminalEditor::activeConnections(bool active) { if (active) { @@ -231,6 +343,22 @@ void TerminalEditor::activeConnections(bool active) this, &TerminalEditor::nameEdited); m_editor_connections << connect(ui->m_type_cb, QOverload::of(&QComboBox::activated), this, &TerminalEditor::typeEdited); + m_editor_connections << connect(ui->m_show_name_cb, &QCheckBox::toggled, + this, &TerminalEditor::showNameEdited); + m_editor_connections << connect(ui->m_label_x_dsb, QOverload::of(&QDoubleSpinBox::valueChanged), + [this]() { TerminalEditor::labelPosEdited(); ui->m_label_x_dsb->setFocus(); }); + m_editor_connections << connect(ui->m_label_y_dsb, QOverload::of(&QDoubleSpinBox::valueChanged), + [this]() { TerminalEditor::labelPosEdited(); ui->m_label_y_dsb->setFocus(); }); + m_editor_connections << connect(ui->m_font_pb, &QPushButton::clicked, + this, &TerminalEditor::labelFontClicked); + m_editor_connections << connect(ui->m_label_size_sb, QOverload::of(&QSpinBox::valueChanged), + [this]() { TerminalEditor::labelSizeEdited(); ui->m_label_size_sb->setFocus(); }); + m_editor_connections << connect(ui->m_label_rotation_sb, QOverload::of(&QDoubleSpinBox::valueChanged), + [this]() { TerminalEditor::labelRotationEdited(); ui->m_label_rotation_sb->setFocus(); }); + m_editor_connections << connect(ui->m_align_pb, &QPushButton::clicked, + this, &TerminalEditor::labelAlignClicked); + m_editor_connections << connect(ui->m_label_frame_cb, &QCheckBox::toggled, + this, &TerminalEditor::labelFrameEdited); } else { for (auto const & con : qAsConst(m_editor_connections)) { QObject::disconnect(con); @@ -248,6 +376,14 @@ void TerminalEditor::activeChangeConnections(bool active) m_change_connections << connect(m_part, &PartTerminal::orientationChanged, this, &TerminalEditor::updateForm); m_change_connections << connect(m_part, &PartTerminal::nameChanged, this, &TerminalEditor::updateForm); m_change_connections << connect(m_part, &PartTerminal::terminalTypeChanged, this, &TerminalEditor::updateForm); + m_change_connections << connect(m_part, &PartTerminal::showNameChanged, this, &TerminalEditor::updateForm); + m_change_connections << connect(m_part, &PartTerminal::labelPosChanged, this, &TerminalEditor::updateForm); + m_change_connections << connect(m_part, &PartTerminal::labelFontChanged, this, &TerminalEditor::updateForm); + m_change_connections << connect(m_part, &PartTerminal::labelRotationChanged, this, &TerminalEditor::updateForm); + m_change_connections << connect(m_part, &PartTerminal::labelHAlignmentChanged, this, &TerminalEditor::updateForm); + m_change_connections << connect(m_part, &PartTerminal::labelVAlignmentChanged, this, &TerminalEditor::updateForm); + m_change_connections << connect(m_part, &PartTerminal::labelFrameChanged, this, &TerminalEditor::updateForm); + m_change_connections << connect(m_part, &PartTerminal::labelColorChanged, this, &TerminalEditor::updateForm); } else { for (auto &con : m_change_connections) { QObject::disconnect(con); diff --git a/sources/editor/ui/terminaleditor.h b/sources/editor/ui/terminaleditor.h index d41ecb04e..4fd1e50bd 100644 --- a/sources/editor/ui/terminaleditor.h +++ b/sources/editor/ui/terminaleditor.h @@ -21,6 +21,12 @@ #include #include "../elementitemeditor.h" +#ifdef BUILD_WITHOUT_KF5 +#include +#else +#include +#endif + namespace Ui { class TerminalEditor; } @@ -50,6 +56,14 @@ class TerminalEditor : public ElementItemEditor void orientationEdited(); void nameEdited(); void typeEdited(); + void showNameEdited(); + void labelPosEdited(); + void labelFontClicked(); + void labelSizeEdited(); + void labelRotationEdited(); + void labelAlignClicked(); + void labelFrameEdited(); + void labelColorClicked(); void activeConnections(bool active); void activeChangeConnections(bool active); @@ -59,6 +73,11 @@ class TerminalEditor : public ElementItemEditor m_change_connections; PartTerminal *m_part = nullptr; bool m_locked = false; +#ifdef BUILD_WITHOUT_KF5 + QPushButton *m_color_pb; +#else + KColorButton *m_color_pb; +#endif }; #endif // TERMINALEDITOR_H diff --git a/sources/editor/ui/terminaleditor.ui b/sources/editor/ui/terminaleditor.ui index 2d423ca77..4d99560bf 100644 --- a/sources/editor/ui/terminaleditor.ui +++ b/sources/editor/ui/terminaleditor.ui @@ -7,7 +7,7 @@ 0 0 511 - 236 + 500 @@ -78,18 +78,141 @@ - - - - Qt::Vertical + + + + Nom de la borne - - - 20 - 40 - - - + + + + + Afficher le nom + + + + + + + Propriétés du texte + + + + + + Police + + + + + + + 4 + + + 50 + + + 9 + + + + + + + X : + + + + + + + -5000.000000000000000 + + + 5000.000000000000000 + + + + + + + Y : + + + + + + + -5000.000000000000000 + + + 5000.000000000000000 + + + + + + + Rotation : + + + + + + + true + + + ° + + + 0 + + + 0.000000000000000 + + + 359.000000000000000 + + + + + + + Alignement + + + + + + + Couleur : + + + + + + + + 40 + 24 + + + + + + + + Encadrer le texte + + + + + + + + diff --git a/sources/properties/terminaldata.cpp b/sources/properties/terminaldata.cpp index cadcebd6d..2bf60d914 100644 --- a/sources/properties/terminaldata.cpp +++ b/sources/properties/terminaldata.cpp @@ -18,6 +18,7 @@ #include "terminaldata.h" #include + #include TerminalData::TerminalData(): @@ -110,6 +111,20 @@ QDomElement TerminalData::toXml(QDomDocument &xml_document) const xml_element.setAttribute("type", typeToString(m_type)); + if (m_show_name) { + xml_element.setAttribute("show_name", "true"); + xml_element.setAttribute("label_x", QString::number(m_label_pos.x())); + xml_element.setAttribute("label_y", QString::number(m_label_pos.y())); + xml_element.setAttribute("label_font", m_label_font.toString()); + xml_element.setAttribute("label_rotation", QString::number(m_label_rotation)); + xml_element.setAttribute("label_halign", static_cast(m_label_halignment)); + xml_element.setAttribute("label_valign", static_cast(m_label_valignment)); + if (m_label_frame) + xml_element.setAttribute("label_frame", "true"); + if (m_label_color != QColor(Qt::black)) + xml_element.setAttribute("label_color", m_label_color.name()); + } + return(xml_element); } @@ -157,6 +172,31 @@ bool TerminalData::fromXml (const QDomElement &xml_element) m_type = typeFromString(xml_element.attribute("type")); + m_show_name = (xml_element.attribute("show_name") == QLatin1String("true")); + if (m_show_name) { + qreal lx = xml_element.attribute("label_x", "0").toDouble(); + qreal ly = xml_element.attribute("label_y", "0").toDouble(); + m_label_pos = QPointF(lx, ly); + + QString font_str = xml_element.attribute("label_font"); + if (!font_str.isEmpty()) + m_label_font.fromString(font_str); + + m_label_rotation = xml_element.attribute("label_rotation", "0").toDouble(); + + int ha = xml_element.attribute("label_halign", "0").toInt(); + m_label_halignment = static_cast(ha); + + int va = xml_element.attribute("label_valign", "0").toInt(); + m_label_valignment = static_cast(va); + + m_label_frame = (xml_element.attribute("label_frame") == QLatin1String("true")); + + QString color_str = xml_element.attribute("label_color"); + if (!color_str.isEmpty()) + m_label_color = QColor(color_str); + } + return true; } diff --git a/sources/properties/terminaldata.h b/sources/properties/terminaldata.h index af60a9f78..145fbc7c1 100644 --- a/sources/properties/terminaldata.h +++ b/sources/properties/terminaldata.h @@ -21,6 +21,8 @@ #include "../qet.h" #include "propertiesinterface.h" +#include +#include #include #include @@ -115,6 +117,23 @@ class TerminalData : public PropertiesInterface TerminalData::Type m_type = TerminalData::Generic; + /// Whether to display the terminal name as a text label + bool m_show_name = false; + /// Position of the text label relative to the terminal + QPointF m_label_pos{0.0, 0.0}; + /// Font used for the text label + QFont m_label_font; + /// Rotation of the text label in degrees + qreal m_label_rotation = 0.0; + /// Horizontal alignment of the text label + Qt::Alignment m_label_halignment = Qt::AlignHCenter; + /// Vertical alignment of the text label + Qt::Alignment m_label_valignment = Qt::AlignVCenter; + /// Whether to draw a frame around the text label + bool m_label_frame = false; + /// Color of the text label + QColor m_label_color = Qt::black; + private: QGraphicsObject* q{nullptr}; }; diff --git a/sources/qetgraphicsitem/terminal.cpp b/sources/qetgraphicsitem/terminal.cpp index 49fb53ad4..661a5bb27 100644 --- a/sources/qetgraphicsitem/terminal.cpp +++ b/sources/qetgraphicsitem/terminal.cpp @@ -273,6 +273,43 @@ void Terminal::paint( m_help_line_a -> setLine(line); } + // Draw label if show_name is enabled + if (d->m_show_name && !d->m_name.isEmpty()) { + painter->setRenderHint(QPainter::Antialiasing, true); + painter->setRenderHint(QPainter::TextAntialiasing, true); + painter->setFont(d->m_label_font); + painter->setPen(d->m_label_color); + + QPointF label_pos = d->m_label_pos; + QFontMetrics fm(d->m_label_font); + QSizeF text_size = fm.size(Qt::TextSingleLine, d->m_name); + + if (!qFuzzyIsNull(d->m_label_rotation)) { + painter->save(); + painter->translate(label_pos); + painter->rotate(d->m_label_rotation); + QRectF text_rect(-text_size.width()/2.0, -text_size.height()/2.0, + text_size.width(), text_size.height()); + painter->drawText(text_rect, static_cast(d->m_label_halignment | d->m_label_valignment), d->m_name); + painter->restore(); + } else { + qreal dx = 0, dy = 0; + if (d->m_label_halignment & Qt::AlignLeft) dx = 0; + else if (d->m_label_halignment & Qt::AlignHCenter) dx = -text_size.width() / 2.0; + else if (d->m_label_halignment & Qt::AlignRight) dx = -text_size.width(); + + if (d->m_label_valignment & Qt::AlignTop) dy = 0; + else if (d->m_label_valignment & Qt::AlignVCenter) dy = -text_size.height() / 2.0; + else if (d->m_label_valignment & Qt::AlignBottom) dy = -text_size.height(); + + QRectF text_rect(label_pos + QPointF(dx, dy), text_size); + if (d->m_label_frame) { + painter->drawRect(text_rect.adjusted(-1, -1, 1, 1)); + } + painter->drawText(text_rect, static_cast(Qt::AlignLeft | Qt::AlignTop), d->m_name); + } + } + painter -> restore(); } @@ -341,7 +378,27 @@ QLineF Terminal::HelpLine() const @return Le rectangle (en precision flottante) delimitant la borne et ses alentours. */ QRectF Terminal::boundingRect() const { - return m_br; + if (!d->m_show_name || d->m_name.isEmpty()) { + return m_br; + } + + QFontMetrics fm(d->m_label_font); + QSizeF text_size = fm.size(Qt::TextSingleLine, d->m_name); + QPointF label_pos = d->m_label_pos; + + qreal dx = 0, dy = 0; + if (d->m_label_halignment & Qt::AlignLeft) dx = 0; + else if (d->m_label_halignment & Qt::AlignHCenter) dx = -text_size.width() / 2.0; + else if (d->m_label_halignment & Qt::AlignRight) dx = -text_size.width(); + + if (d->m_label_valignment & Qt::AlignTop) dy = 0; + else if (d->m_label_valignment & Qt::AlignVCenter) dy = -text_size.height() / 2.0; + else if (d->m_label_valignment & Qt::AlignBottom) dy = -text_size.height(); + + QRectF label_rect(label_pos + QPointF(dx, dy), text_size); + label_rect = label_rect.adjusted(-2, -2, 2, 2); + + return m_br.united(label_rect); } /** From f62ce7e4ca98b076bc776a18d27df5bd528a4544 Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Fri, 10 Jul 2026 14:36:47 +0200 Subject: [PATCH 2/3] Update terminal name --- sources/editor/ui/terminaleditor.cpp | 17 +++++++++++++++++ sources/qetgraphicsitem/terminal.cpp | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/sources/editor/ui/terminaleditor.cpp b/sources/editor/ui/terminaleditor.cpp index f34a0f8bc..45682c1d9 100644 --- a/sources/editor/ui/terminaleditor.cpp +++ b/sources/editor/ui/terminaleditor.cpp @@ -1,3 +1,20 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ #include "terminaleditor.h" #include "ui_terminaleditor.h" #include "../../qeticons.h" diff --git a/sources/qetgraphicsitem/terminal.cpp b/sources/qetgraphicsitem/terminal.cpp index 661a5bb27..7b0f58be3 100644 --- a/sources/qetgraphicsitem/terminal.cpp +++ b/sources/qetgraphicsitem/terminal.cpp @@ -280,7 +280,7 @@ void Terminal::paint( painter->setFont(d->m_label_font); painter->setPen(d->m_label_color); - QPointF label_pos = d->m_label_pos; + QPointF label_pos = d->m_pos + d->m_label_pos; QFontMetrics fm(d->m_label_font); QSizeF text_size = fm.size(Qt::TextSingleLine, d->m_name); @@ -384,7 +384,7 @@ QRectF Terminal::boundingRect() const { QFontMetrics fm(d->m_label_font); QSizeF text_size = fm.size(Qt::TextSingleLine, d->m_name); - QPointF label_pos = d->m_label_pos; + QPointF label_pos = d->m_pos + d->m_label_pos; qreal dx = 0, dy = 0; if (d->m_label_halignment & Qt::AlignLeft) dx = 0; From b543adcb46dbb2d7faa080634c217055492a6e4c Mon Sep 17 00:00:00 2001 From: Kellermorph Date: Fri, 10 Jul 2026 15:04:04 +0200 Subject: [PATCH 3/3] Restore comments --- sources/editor/ui/terminaleditor.cpp | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/sources/editor/ui/terminaleditor.cpp b/sources/editor/ui/terminaleditor.cpp index 45682c1d9..b6feb09f3 100644 --- a/sources/editor/ui/terminaleditor.cpp +++ b/sources/editor/ui/terminaleditor.cpp @@ -26,6 +26,12 @@ #include #include +/** + * @brief TerminalEditor::TerminalEditor + * Default constructor + * @param editor : element editor of which this terminal editor belong + * @param parent : parent widget + */ TerminalEditor::TerminalEditor(QETElementEditor *editor, QWidget *parent) : ElementItemEditor(editor, parent), ui(new Ui::TerminalEditor) @@ -50,11 +56,20 @@ TerminalEditor::TerminalEditor(QETElementEditor *editor, QWidget *parent) : init(); } +/** + * @brief TerminalEditor::~TerminalEditor + * Destructor + */ TerminalEditor::~TerminalEditor() { delete ui; } +/** + * @brief TerminalEditor::updateForm + * Reimplemented from ElementItemEditor + * Update the content of this widget + */ void TerminalEditor::updateForm() { if (!m_part) { @@ -89,6 +104,13 @@ void TerminalEditor::updateForm() activeConnections(true); } +/** + * @brief TerminalEditor::setPart + * Set the part to edit. + * The part must be a PartTerminal, in other case return false. + * @param new_part : the part to edit + * @return true if the part can be edited. + */ bool TerminalEditor::setPart(CustomElementPart *new_part) { if (m_part == new_part) { @@ -113,11 +135,21 @@ bool TerminalEditor::setPart(CustomElementPart *new_part) return(false); } +/** + * @brief TerminalEditor::currentPart + * @return the current edited part + * or nullptr if there is no part or several part + * @see QList TerminalEditor::currentParts() const + */ CustomElementPart *TerminalEditor::currentPart() const { return m_part; } +/** + * @brief TerminalEditor::init + * Some init about this class + */ void TerminalEditor::init() { ui->m_orientation_cb->addItem(QET::Icons::North, tr("Nord"), Qet::North); @@ -135,6 +167,9 @@ void TerminalEditor::init() ui->m_text_props_gb->setEnabled(false); } +/** + * @brief TerminalEditor::posEdited + */ void TerminalEditor::posEdited() { if (m_locked) { @@ -156,6 +191,9 @@ void TerminalEditor::posEdited() m_locked = false; } +/** + * @brief TerminalEditor::orientationEdited + */ void TerminalEditor::orientationEdited() { if (m_locked) { @@ -174,6 +212,9 @@ void TerminalEditor::orientationEdited() m_locked = false; } +/** + * @brief TerminalEditor::nameEdited + */ void TerminalEditor::nameEdited() { if (m_locked) { @@ -192,6 +233,9 @@ void TerminalEditor::nameEdited() m_locked=false; } +/** + * @brief TerminalEditor::typeEdited + */ void TerminalEditor::typeEdited() { if (m_locked) { @@ -208,6 +252,13 @@ void TerminalEditor::typeEdited() m_locked = false; } +/** + * @brief TerminalEditor::activeConnections + * Active connection between the widgets used in this editor + * and method of this class. + * @param active + */ + void TerminalEditor::showNameEdited() { if (m_locked) return;