mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-08-06 13:24:14 +02:00
Merge branch 'master' into qt6_cmake_joshua
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
#include "graphicspart/partline.h"
|
||||
#include "graphicspart/partpolygon.h"
|
||||
#include "graphicspart/partrectangle.h"
|
||||
#include "graphicspart/partplctable.h"
|
||||
#include "graphicspart/partterminal.h"
|
||||
#include "graphicspart/parttext.h"
|
||||
#include "ui/qetelementeditor.h"
|
||||
@@ -84,12 +85,15 @@ ElementData ElementScene::elementData() {
|
||||
|
||||
void ElementScene::setElementData(ElementData data)
|
||||
{
|
||||
bool emit_ = m_element_data.m_informations != data.m_informations;
|
||||
bool emit_info = (m_element_data != data);
|
||||
bool type_changed = m_element_data.m_type != data.m_type;
|
||||
|
||||
m_element_data = data;
|
||||
|
||||
if (emit_)
|
||||
if (emit_info)
|
||||
emit elementInfoChanged();
|
||||
if (type_changed)
|
||||
emit elementTypeChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,6 +111,9 @@ ElementScene::~ElementScene()
|
||||
|
||||
if (m_decorator)
|
||||
delete m_decorator;
|
||||
|
||||
if (m_paste_area && !m_paste_area->scene())
|
||||
delete m_paste_area;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -748,7 +755,7 @@ void ElementScene::addItems(QVector<QGraphicsItem *> items)
|
||||
*/
|
||||
void ElementScene::removeItems(QVector<QGraphicsItem *> items)
|
||||
{
|
||||
const int previous_selected_count{selectedItems().size()};
|
||||
const int previous_selected_count = static_cast<int>(selectedItems().size());
|
||||
|
||||
//block signal to avoid multiple emit of selection changed,
|
||||
//we emit this signal only once at the end of this function.
|
||||
@@ -920,9 +927,41 @@ void ElementScene::slot_editProperties()
|
||||
|
||||
if (m_element_data != epew.editedData())
|
||||
{
|
||||
ElementData new_data = epew.editedData();
|
||||
|
||||
// Check PLC state BEFORE pushing (push calls redo which changes m_element_data)
|
||||
bool old_plc = (m_element_data.m_type == ElementData::Master &&
|
||||
m_element_data.m_master_type == ElementData::PLC);
|
||||
bool new_plc = (new_data.m_type == ElementData::Master &&
|
||||
new_data.m_master_type == ElementData::PLC);
|
||||
|
||||
undoStack().push(new changeElementDataCommand(this,
|
||||
m_element_data,
|
||||
epew.editedData()));
|
||||
new_data));
|
||||
|
||||
if (new_plc && !old_plc) {
|
||||
// Switched TO PLC: create table if not present
|
||||
bool has_plc = false;
|
||||
for (QGraphicsItem *item : items()) {
|
||||
if (dynamic_cast<PartPlcTable *>(item)) {
|
||||
has_plc = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_plc) {
|
||||
PartPlcTable *pt = new PartPlcTable(m_element_editor);
|
||||
addItem(pt);
|
||||
}
|
||||
} else if (!new_plc && old_plc) {
|
||||
// Switched FROM PLC: remove table
|
||||
for (QGraphicsItem *item : items()) {
|
||||
if (PartPlcTable *pt = dynamic_cast<PartPlcTable *>(item)) {
|
||||
removeItem(pt);
|
||||
delete pt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1166,15 +1205,16 @@ ElementContent ElementScene::loadContent(const QDomDocument &xml_document)
|
||||
CustomElementPart *cep = nullptr;
|
||||
PartDynamicTextField *pdtf = nullptr;
|
||||
|
||||
if (qde.tagName() == "line") cep = new PartLine (m_element_editor);
|
||||
else if (qde.tagName() == "rect") cep = new PartRectangle(m_element_editor);
|
||||
else if (qde.tagName() == "ellipse") cep = new PartEllipse (m_element_editor);
|
||||
else if (qde.tagName() == "circle") cep = new PartEllipse (m_element_editor);
|
||||
else if (qde.tagName() == "polygon") cep = new PartPolygon (m_element_editor);
|
||||
else if (qde.tagName() == "terminal") cep = new PartTerminal (m_element_editor);
|
||||
else if (qde.tagName() == "text") cep = new PartText (m_element_editor);
|
||||
else if (qde.tagName() == "arc") cep = new PartArc (m_element_editor);
|
||||
if (qde.tagName() == "line") cep = new PartLine (m_element_editor);
|
||||
else if (qde.tagName() == "rect") cep = new PartRectangle (m_element_editor);
|
||||
else if (qde.tagName() == "ellipse") cep = new PartEllipse (m_element_editor);
|
||||
else if (qde.tagName() == "circle") cep = new PartEllipse (m_element_editor);
|
||||
else if (qde.tagName() == "polygon") cep = new PartPolygon (m_element_editor);
|
||||
else if (qde.tagName() == "terminal") cep = new PartTerminal (m_element_editor);
|
||||
else if (qde.tagName() == "text") cep = new PartText (m_element_editor);
|
||||
else if (qde.tagName() == "arc") cep = new PartArc (m_element_editor);
|
||||
else if (qde.tagName() == "dynamic_text") cep = new PartDynamicTextField (m_element_editor);
|
||||
else if (qde.tagName() == "plc_table") cep = new PartPlcTable (m_element_editor);
|
||||
//For the input (aka the old text field) we try to convert it to the new partDynamicTextField
|
||||
else if (qde.tagName() == "input") cep = pdtf = new PartDynamicTextField(m_element_editor);
|
||||
else continue;
|
||||
|
||||
@@ -177,6 +177,8 @@ class ElementScene : public QGraphicsScene
|
||||
/// Signal emitted when need zoomFit
|
||||
void needZoomFit();
|
||||
void elementInfoChanged();
|
||||
/// Signal emitted when the element type changes
|
||||
void elementTypeChanged();
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(ElementScene::ItemOptions)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "../../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include "../elementscene.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QRegularExpression>
|
||||
|
||||
/**
|
||||
@@ -39,7 +40,8 @@ CustomElementGraphicPart::CustomElementGraphicPart(QETElementEditor *editor,
|
||||
_lineweight(NormalWeight),
|
||||
_filling(NoneFilling),
|
||||
_color(BlackColor),
|
||||
_antialiased(false)
|
||||
_antialiased(false),
|
||||
m_first_move (false)
|
||||
{
|
||||
setFlags(QGraphicsItem::ItemIsSelectable
|
||||
| QGraphicsItem::ItemIsMovable
|
||||
@@ -1325,26 +1327,24 @@ void CustomElementGraphicPart::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
||||
void CustomElementGraphicPart::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
//m_first_move is used to avoid an unwanted behavior
|
||||
//when the properties dock widget is displayed :
|
||||
//1 there is no selection
|
||||
//2 the dock widget width is set to minimum
|
||||
//3 select a part, the dock widget gain new widgets used to edit
|
||||
//the current selected part and the width of the dock grow
|
||||
//so the width of the QGraphicsView is reduced and cause a mouse move event.
|
||||
//When this case occur the part is moved but they should not. This bool fix it.
|
||||
if (Q_UNLIKELY(m_first_move)) {
|
||||
if (m_first_move) {
|
||||
// Suppress spurious move events fired when the properties dock
|
||||
// widget expands on first selection of a new item type, causing
|
||||
// the QGraphicsView to shrink and re-map coordinates. Screen
|
||||
// coordinates are stable across viewport changes; scene coords
|
||||
// are not — so use screenPos() for the threshold check.
|
||||
const QPointF d = event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton);
|
||||
if (d.manhattanLength() < QApplication::startDragDistance())
|
||||
return;
|
||||
m_first_move = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if((event->buttons() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable))
|
||||
{
|
||||
if ((event->buttons() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable)) {
|
||||
QPointF pos = event->scenePos() + (m_origin_pos - event->buttonDownScenePos(Qt::LeftButton));
|
||||
event->modifiers() == Qt::ControlModifier ? setPos(pos) : setPos(elementScene()->snapToGrid(pos));
|
||||
}
|
||||
else
|
||||
} else {
|
||||
QGraphicsObject::mouseMoveEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void CustomElementGraphicPart::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "../../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include "../../qetapp.h"
|
||||
#include "../elementscene.h"
|
||||
#include "../../utils/qetutils.h"
|
||||
#include <QApplication>
|
||||
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
@@ -141,7 +143,7 @@ const QDomElement PartDynamicTextField::toXml(QDomDocument &dom_doc) const
|
||||
root_element.setAttribute("y", QString::number(y));
|
||||
root_element.setAttribute("z", QString::number(zValue()));
|
||||
root_element.setAttribute("rotation", QString::number(QET::correctAngle(rot)));
|
||||
root_element.setAttribute("font", font().toString());
|
||||
root_element.setAttribute("font", QETUtils::fontToString(font()));
|
||||
root_element.setAttribute("uuid", m_uuid.toString());
|
||||
root_element.setAttribute("frame", m_frame? "true" : "false");
|
||||
root_element.setAttribute("text_width", QString::number(m_text_width));
|
||||
@@ -213,7 +215,7 @@ void PartDynamicTextField::fromXml(const QDomElement &dom_elmt) {
|
||||
|
||||
if (dom_elmt.hasAttribute("font")) {
|
||||
QFont font_;
|
||||
font_.fromString(dom_elmt.attribute("font"));
|
||||
QETUtils::fontFromString(font_, dom_elmt.attribute("font"));
|
||||
setFont(font_);
|
||||
}
|
||||
else if (dom_elmt.hasAttribute("font_size")) {
|
||||
@@ -495,12 +497,16 @@ bool PartDynamicTextField::keepVisualRotation() const {
|
||||
@param event
|
||||
*/
|
||||
void PartDynamicTextField::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
if((event -> buttons() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable)) {
|
||||
QPointF pos = event -> scenePos() + (m_origin_pos - event -> buttonDownScenePos(Qt::LeftButton));
|
||||
event -> modifiers() == Qt::ControlModifier ? setPos(pos) : setPos(elementScene() -> snapToGrid(pos));
|
||||
}
|
||||
else
|
||||
if ((event->buttons() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable)) {
|
||||
// Suppress spurious moves from the properties dock resizing the viewport.
|
||||
const QPointF d = event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton);
|
||||
if (d.manhattanLength() < QApplication::startDragDistance())
|
||||
return;
|
||||
QPointF pos = event->scenePos() + (m_origin_pos - event->buttonDownScenePos(Qt::LeftButton));
|
||||
event->modifiers() == Qt::ControlModifier ? setPos(pos) : setPos(elementScene()->snapToGrid(pos));
|
||||
} else {
|
||||
QGraphicsObject::mouseMoveEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,696 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "partplctable.h"
|
||||
|
||||
#include "../../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include "../../QetGraphicsItemModeler/qetgraphicshandleritem.h"
|
||||
#include "../../QetGraphicsItemModeler/qetgraphicshandlerutility.h"
|
||||
#include "../../properties/elementdata.h"
|
||||
#include "../elementscene.h"
|
||||
#include "../editorcommands.h"
|
||||
#include "../ui/qetelementeditor.h"
|
||||
|
||||
#include <QPen>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::PartPlcTable
|
||||
Constructor
|
||||
@param editor the QETElementEditor of this item
|
||||
@param parent parent item
|
||||
*/
|
||||
PartPlcTable::PartPlcTable(QETElementEditor *editor, QGraphicsItem *parent) :
|
||||
CustomElementGraphicPart(editor, parent)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::~PartPlcTable
|
||||
*/
|
||||
PartPlcTable::~PartPlcTable()
|
||||
{
|
||||
removeHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::calculateTableSize
|
||||
Calculate the table size from PLC data in the element scene.
|
||||
@return the calculated size in item coordinates
|
||||
*/
|
||||
QSizeF PartPlcTable::calculateTableSize() const
|
||||
{
|
||||
if (!elementEditor() || !elementScene())
|
||||
return QSizeF(100, 50);
|
||||
|
||||
ElementData ed = elementScene()->elementData();
|
||||
if (ed.m_master_type != ElementData::PLC)
|
||||
return QSizeF(100, 50);
|
||||
|
||||
const auto &plc_data = ed.plcMasterData();
|
||||
if (plc_data.ios.isEmpty())
|
||||
return QSizeF(100, 50);
|
||||
|
||||
const int COL_COUNT = 5;
|
||||
|
||||
// Build list of visible columns
|
||||
QList<int> visible_cols;
|
||||
if (!plc_data.columnOrder.isEmpty()) {
|
||||
for (int logical : plc_data.columnOrder) {
|
||||
if (logical >= 0 && logical < COL_COUNT
|
||||
&& plc_data.colVisible.value(logical, true)
|
||||
&& !visible_cols.contains(logical))
|
||||
visible_cols.append(logical);
|
||||
}
|
||||
for (int i = 0; i < COL_COUNT; ++i) {
|
||||
if (plc_data.colVisible.value(i, true) && !visible_cols.contains(i))
|
||||
visible_cols.append(i);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < COL_COUNT; ++i) {
|
||||
if (plc_data.colVisible.value(i, true))
|
||||
visible_cols.append(i);
|
||||
}
|
||||
}
|
||||
if (visible_cols.isEmpty())
|
||||
visible_cols << 0 << 1 << 2; // fallback: Type, Address, Function
|
||||
|
||||
// Default column widths
|
||||
QMap<int, qreal> col_widths;
|
||||
for (int col : visible_cols) {
|
||||
if (plc_data.colWidths.contains(col) && plc_data.colWidths[col] > 0)
|
||||
col_widths[col] = plc_data.colWidths[col];
|
||||
else {
|
||||
switch (col) {
|
||||
case 0: col_widths[col] = 35; break; // Type
|
||||
case 1: col_widths[col] = 25; break; // Address
|
||||
case 2: col_widths[col] = 50; break; // Function
|
||||
case 3: col_widths[col] = 40; break; // Comment
|
||||
case 5: col_widths[col] = 30; break; // CrossRef
|
||||
default: col_widths[col] = 30; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qreal row_h = plc_data.rowHeight > 0 ? plc_data.rowHeight : 8.0;
|
||||
qreal header_h = plc_data.showHeaders ? (row_h + 2.0) : 0;
|
||||
|
||||
qreal total_width = 0;
|
||||
for (int col : visible_cols)
|
||||
total_width += col_widths[col];
|
||||
|
||||
int total_ios = plc_data.ios.size();
|
||||
|
||||
// Collect active break positions (sorted)
|
||||
QList<int> breaks;
|
||||
for (int bp : plc_data.breakPositions) {
|
||||
if (bp > 0 && bp < total_ios && !breaks.contains(bp))
|
||||
breaks.append(bp);
|
||||
}
|
||||
std::sort(breaks.begin(), breaks.end());
|
||||
|
||||
// Build block boundaries
|
||||
QList<int> block_starts;
|
||||
block_starts.append(0);
|
||||
for (int bp : breaks)
|
||||
block_starts.append(bp);
|
||||
|
||||
qreal total_height;
|
||||
int block_count = block_starts.size();
|
||||
|
||||
if (block_count > 1) {
|
||||
// Find the tallest block (most rows)
|
||||
int max_rows = 0;
|
||||
for (int b = 0; b < block_count; ++b) {
|
||||
int start = block_starts.at(b);
|
||||
int end = (b + 1 < block_starts.size()) ? block_starts.at(b + 1) : total_ios;
|
||||
max_rows = qMax(max_rows, end - start);
|
||||
}
|
||||
total_height = header_h + max_rows * row_h;
|
||||
total_width = total_width * block_count + (block_count - 1) * 3;
|
||||
} else {
|
||||
total_height = header_h + total_ios * row_h;
|
||||
}
|
||||
|
||||
return QSizeF(total_width, total_height);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::paint
|
||||
Draw this PLC table
|
||||
@param painter
|
||||
@param options
|
||||
@param widget
|
||||
*/
|
||||
void PartPlcTable::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
Q_UNUSED(options);
|
||||
|
||||
// Auto-size from PLC data
|
||||
QSizeF table_size = calculateTableSize();
|
||||
if (m_rect.size() != table_size) {
|
||||
prepareGeometryChange();
|
||||
QPointF top_left = m_rect.topLeft();
|
||||
m_rect = QRectF(top_left, table_size);
|
||||
}
|
||||
|
||||
applyStylesToQPainter(*painter);
|
||||
QPen t = painter->pen();
|
||||
t.setCosmetic(options && options->levelOfDetailFromTransform(painter->worldTransform()) < 1.0);
|
||||
if (isSelected())
|
||||
t.setColor(Qt::red);
|
||||
t.setJoinStyle(Qt::MiterJoin);
|
||||
if (!m_rect.width() || !m_rect.height())
|
||||
t.setWidth(0);
|
||||
painter->setPen(t);
|
||||
|
||||
// Get PLC data
|
||||
ElementData ed = (elementEditor() && elementScene()) ? elementScene()->elementData() : ElementData();
|
||||
if (ed.m_master_type != ElementData::PLC) {
|
||||
// Draw placeholder
|
||||
painter->setBrush(QColor(255, 255, 200));
|
||||
painter->drawRect(m_rect);
|
||||
painter->drawText(m_rect, Qt::AlignCenter, QObject::tr("Table PLC"));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &plc_data = ed.plcMasterData();
|
||||
if (plc_data.ios.isEmpty()) {
|
||||
painter->setBrush(QColor(255, 255, 200));
|
||||
painter->drawRect(m_rect);
|
||||
painter->drawText(m_rect, Qt::AlignCenter, QObject::tr("Table PLC (vide)"));
|
||||
return;
|
||||
}
|
||||
|
||||
const int COL_TYPE = 0;
|
||||
const int COL_ADDRESS = 1;
|
||||
const int COL_FUNCTION = 2;
|
||||
const int COL_COMMENT = 3;
|
||||
const int COL_CROSSREF = 4;
|
||||
const int COL_COUNT = 5;
|
||||
|
||||
QMap<int, QString> headers;
|
||||
headers[COL_TYPE] = QObject::tr("Type");
|
||||
headers[COL_ADDRESS] = QObject::tr("Adresse");
|
||||
headers[COL_FUNCTION] = QObject::tr("Fonction");
|
||||
headers[COL_COMMENT] = QObject::tr("Commentaire");
|
||||
headers[COL_CROSSREF] = QObject::tr("Réf. croisée");
|
||||
|
||||
// Override with custom column names if set
|
||||
if (!plc_data.columnNames.isEmpty()) {
|
||||
QList<int> all_cols;
|
||||
all_cols << COL_TYPE << COL_ADDRESS << COL_FUNCTION << COL_COMMENT << COL_CROSSREF;
|
||||
for (int i = 0; i < qMin(plc_data.columnNames.size(), all_cols.size()); ++i) {
|
||||
if (!plc_data.columnNames.at(i).isEmpty())
|
||||
headers[all_cols.at(i)] = plc_data.columnNames.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
QList<int> visible_cols;
|
||||
if (!plc_data.columnOrder.isEmpty()) {
|
||||
for (int logical : plc_data.columnOrder) {
|
||||
if (logical >= 0 && logical < COL_COUNT
|
||||
&& plc_data.colVisible.value(logical, true)
|
||||
&& !visible_cols.contains(logical))
|
||||
visible_cols.append(logical);
|
||||
}
|
||||
for (int i = 0; i < COL_COUNT; ++i) {
|
||||
if (plc_data.colVisible.value(i, true) && !visible_cols.contains(i))
|
||||
visible_cols.append(i);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < COL_COUNT; ++i) {
|
||||
if (plc_data.colVisible.value(i, true))
|
||||
visible_cols.append(i);
|
||||
}
|
||||
}
|
||||
if (visible_cols.isEmpty())
|
||||
return;
|
||||
|
||||
QMap<int, qreal> col_widths;
|
||||
for (int col : visible_cols) {
|
||||
if (plc_data.colWidths.contains(col) && plc_data.colWidths[col] > 0)
|
||||
col_widths[col] = plc_data.colWidths[col];
|
||||
else {
|
||||
switch (col) {
|
||||
case COL_TYPE: col_widths[col] = 35; break;
|
||||
case COL_ADDRESS: col_widths[col] = 25; break;
|
||||
case COL_FUNCTION: col_widths[col] = 50; break;
|
||||
case COL_COMMENT: col_widths[col] = 40; break;
|
||||
case COL_CROSSREF: col_widths[col] = 30; break;
|
||||
default: col_widths[col] = 30; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qreal row_h = plc_data.rowHeight > 0 ? plc_data.rowHeight : 8.0;
|
||||
qreal header_h = plc_data.showHeaders ? (row_h + 2.0) : 0;
|
||||
|
||||
int total_ios = plc_data.ios.size();
|
||||
|
||||
// Collect active break positions (sorted)
|
||||
QList<int> breaks;
|
||||
for (int bp : plc_data.breakPositions) {
|
||||
if (bp > 0 && bp < total_ios && !breaks.contains(bp))
|
||||
breaks.append(bp);
|
||||
}
|
||||
std::sort(breaks.begin(), breaks.end());
|
||||
|
||||
// Build block boundaries: start, break1, break2, ..., end
|
||||
QList<int> block_starts;
|
||||
block_starts.append(0);
|
||||
for (int bp : breaks)
|
||||
block_starts.append(bp);
|
||||
int block_count = block_starts.size();
|
||||
|
||||
// Draw background
|
||||
painter->save();
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(Qt::white);
|
||||
painter->drawRect(m_rect);
|
||||
painter->restore();
|
||||
|
||||
// Draw outer border
|
||||
QPen border_pen(Qt::black, 0.5);
|
||||
painter->setPen(border_pen);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(m_rect);
|
||||
|
||||
// Draw each block
|
||||
for (int block = 0; block < block_count; ++block) {
|
||||
qreal block_w = 0;
|
||||
for (int col : visible_cols)
|
||||
block_w += col_widths[col];
|
||||
|
||||
qreal block_x = m_rect.x() + block * (block_w + 3);
|
||||
qreal cx = block_x;
|
||||
|
||||
// Draw column headers
|
||||
QFont header_font = plc_data.headerFont.family().isEmpty()
|
||||
? painter->font() : plc_data.headerFont;
|
||||
header_font.setBold(true);
|
||||
painter->setFont(header_font);
|
||||
|
||||
for (int col : visible_cols) {
|
||||
QRectF header_rect(cx, m_rect.y(), col_widths[col], header_h);
|
||||
painter->fillRect(header_rect, QColor(220, 220, 220));
|
||||
painter->setPen(border_pen);
|
||||
painter->drawRect(header_rect);
|
||||
QString header_text = headers.value(col, QString());
|
||||
painter->drawText(header_rect, Qt::AlignCenter, header_text);
|
||||
cx += col_widths[col];
|
||||
}
|
||||
|
||||
// Draw IO rows
|
||||
QFont cell_font = plc_data.cellFont.family().isEmpty()
|
||||
? painter->font() : plc_data.cellFont;
|
||||
painter->setFont(cell_font);
|
||||
int start_idx = block_starts.at(block);
|
||||
int end_idx = (block + 1 < block_starts.size())
|
||||
? block_starts.at(block + 1) : total_ios;
|
||||
|
||||
for (int row = 0; row < (end_idx - start_idx); ++row) {
|
||||
int io_idx = start_idx + row;
|
||||
const ElementData::PlcIO &io = plc_data.ios.at(io_idx);
|
||||
|
||||
qreal ry = m_rect.y() + header_h + row * row_h;
|
||||
cx = block_x;
|
||||
|
||||
for (int col : visible_cols) {
|
||||
QRectF cell_rect(cx, ry, col_widths[col], row_h);
|
||||
painter->setPen(border_pen);
|
||||
painter->drawRect(cell_rect);
|
||||
|
||||
QString cell_text;
|
||||
switch (col) {
|
||||
case COL_TYPE: cell_text = ElementData::translatedPlcIOType(io.type); break;
|
||||
case COL_ADDRESS: cell_text = io.address; break;
|
||||
case COL_FUNCTION: cell_text = io.functionText; break;
|
||||
case COL_COMMENT: cell_text = io.comment; break;
|
||||
case COL_CROSSREF: cell_text = io.crossRef; break;
|
||||
}
|
||||
|
||||
QRectF text_rect = cell_rect.adjusted(1, 0, -1, 0);
|
||||
painter->drawText(text_rect, Qt::AlignLeft | Qt::AlignVCenter, cell_text);
|
||||
|
||||
cx += col_widths[col];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_hovered)
|
||||
drawShadowShape(painter);
|
||||
|
||||
if (isSelected())
|
||||
drawCross(m_rect.center(), painter);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::toXml
|
||||
Export this PLC table part in xml
|
||||
@param xml_document : Xml document to use for create the xml element.
|
||||
@return an xml element that describe this part
|
||||
*/
|
||||
const QDomElement PartPlcTable::toXml(QDomDocument &xml_document) const
|
||||
{
|
||||
QDomElement xml_element = xml_document.createElement("plc_table");
|
||||
qreal x = qRound(m_rect.x() * 100.0) / 100.0;
|
||||
qreal y = qRound(m_rect.y() * 100.0) / 100.0;
|
||||
|
||||
xml_element.setAttribute("x", QString::number(x));
|
||||
xml_element.setAttribute("y", QString::number(y));
|
||||
|
||||
stylesToXml(xml_element);
|
||||
return xml_element;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::fromXml
|
||||
Import the properties of this PLC table part from a xml element.
|
||||
@param qde : Xml document to use.
|
||||
*/
|
||||
void PartPlcTable::fromXml(const QDomElement &qde)
|
||||
{
|
||||
stylesFromXml(qde);
|
||||
qreal x = qde.attribute("x", "0").toDouble();
|
||||
qreal y = qde.attribute("y", "0").toDouble();
|
||||
setPos(mapFromScene(x, y));
|
||||
|
||||
// Auto-size from PLC data
|
||||
QSizeF table_size = calculateTableSize();
|
||||
prepareGeometryChange();
|
||||
m_rect = QRectF(QPointF(0, 0), table_size);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::rect
|
||||
@return : Returns the item's rectangle.
|
||||
*/
|
||||
QRectF PartPlcTable::rect() const
|
||||
{
|
||||
return m_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::setRect
|
||||
Sets the item's rectangle to be the given rectangle.
|
||||
@param rect
|
||||
*/
|
||||
void PartPlcTable::setRect(const QRectF &rect)
|
||||
{
|
||||
if (rect == m_rect) return;
|
||||
prepareGeometryChange();
|
||||
m_rect = rect;
|
||||
adjustHandlerPos();
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::sceneGeometricRect
|
||||
@return the minimum, margin-less rectangle this part can fit into, in scene
|
||||
coordinates.
|
||||
*/
|
||||
QRectF PartPlcTable::sceneGeometricRect() const
|
||||
{
|
||||
return(mapToScene(m_rect).boundingRect());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::shape
|
||||
@return the shape of this item
|
||||
*/
|
||||
QPainterPath PartPlcTable::shape() const
|
||||
{
|
||||
QPainterPath fill;
|
||||
fill.addRect(m_rect);
|
||||
|
||||
QPainterPath stroke;
|
||||
stroke.addRect(m_rect);
|
||||
|
||||
QPainterPathStroker pps;
|
||||
pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight());
|
||||
stroke = pps.createStroke(stroke);
|
||||
|
||||
return fill.united(stroke);
|
||||
}
|
||||
|
||||
QPainterPath PartPlcTable::shadowShape() const
|
||||
{
|
||||
QPainterPath shape;
|
||||
shape.addRect(m_rect);
|
||||
|
||||
QPainterPathStroker pps;
|
||||
pps.setWidth(penWeight());
|
||||
|
||||
return (pps.createStroke(shape));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::boundingRect
|
||||
@return Bounding rectangle this part can fit into
|
||||
*/
|
||||
QRectF PartPlcTable::boundingRect() const
|
||||
{
|
||||
qreal adjust = (SHADOWS_HEIGHT + penWeight()) / 2;
|
||||
if (penWeight() == 0) adjust += 0.5;
|
||||
|
||||
QRectF r = m_rect.normalized();
|
||||
r.adjust(-adjust, -adjust, adjust, adjust);
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::isUseless
|
||||
@return true if this part is irrelevant and does not deserve to be saved.
|
||||
A PLC table part is always relevant.
|
||||
*/
|
||||
bool PartPlcTable::isUseless() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::startUserTransformation
|
||||
@param initial_selection_rect
|
||||
*/
|
||||
void PartPlcTable::startUserTransformation(const QRectF &initial_selection_rect)
|
||||
{
|
||||
Q_UNUSED(initial_selection_rect)
|
||||
saved_points_.clear();
|
||||
saved_points_ << mapToScene(m_rect.topLeft()) << mapToScene(m_rect.bottomRight());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::handleUserTransformation
|
||||
@param initial_selection_rect
|
||||
@param new_selection_rect
|
||||
*/
|
||||
void PartPlcTable::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect)
|
||||
{
|
||||
QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
|
||||
setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::mouseReleaseEvent
|
||||
*/
|
||||
void PartPlcTable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
CustomElementGraphicPart::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::itemChange
|
||||
@param change
|
||||
@param value
|
||||
@return
|
||||
*/
|
||||
QVariant PartPlcTable::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (change == ItemPositionHasChanged)
|
||||
{
|
||||
adjustHandlerPos();
|
||||
}
|
||||
else if (change == ItemSceneChange)
|
||||
{
|
||||
setSelected(false);
|
||||
}
|
||||
else if (change == ItemSceneHasChanged)
|
||||
{
|
||||
if (ElementScene *es = elementScene()) {
|
||||
connect(es, &ElementScene::elementInfoChanged,
|
||||
this, [this]() {
|
||||
QSizeF table_size = calculateTableSize();
|
||||
if (m_rect.size() != table_size) {
|
||||
QPointF top_left = m_rect.topLeft();
|
||||
setRect(QRectF(top_left, table_size));
|
||||
}
|
||||
update();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return QGraphicsItem::itemChange(change, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::sceneEventFilter
|
||||
@param watched
|
||||
@param event
|
||||
@return
|
||||
*/
|
||||
bool PartPlcTable::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
|
||||
{
|
||||
if(watched->type() == QetGraphicsHandlerItem::Type)
|
||||
{
|
||||
QetGraphicsHandlerItem *qghi = qgraphicsitem_cast<QetGraphicsHandlerItem *>(watched);
|
||||
|
||||
if(m_handler_vector.contains(qghi))
|
||||
{
|
||||
m_vector_index = m_handler_vector.indexOf(qghi);
|
||||
if (m_vector_index != -1)
|
||||
{
|
||||
if(event->type() == QEvent::GraphicsSceneMousePress)
|
||||
{
|
||||
handlerMousePressEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
|
||||
return true;
|
||||
}
|
||||
else if(event->type() == QEvent::GraphicsSceneMouseMove)
|
||||
{
|
||||
handlerMouseMoveEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
|
||||
return true;
|
||||
}
|
||||
else if (event->type() == QEvent::GraphicsSceneMouseRelease)
|
||||
{
|
||||
handlerMouseReleaseEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::switchResizeMode
|
||||
*/
|
||||
void PartPlcTable::switchResizeMode()
|
||||
{
|
||||
if (m_resize_mode == 1)
|
||||
{
|
||||
m_resize_mode = 2;
|
||||
for (QetGraphicsHandlerItem *qghi : m_handler_vector)
|
||||
qghi->setColor(Qt::darkGreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_resize_mode = 1;
|
||||
qDeleteAll(m_handler_vector);
|
||||
m_handler_vector.clear();
|
||||
addHandler();
|
||||
for (QetGraphicsHandlerItem *qghi : m_handler_vector) {
|
||||
qghi->setColor(Qt::blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::adjustHandlerPos
|
||||
*/
|
||||
void PartPlcTable::adjustHandlerPos()
|
||||
{
|
||||
if (m_handler_vector.isEmpty())
|
||||
return;
|
||||
|
||||
QVector<QPointF> points_vector = QetGraphicsHandlerUtility::pointsForRect(m_rect);
|
||||
|
||||
if (m_handler_vector.size() == points_vector.size())
|
||||
{
|
||||
points_vector = mapToScene(points_vector);
|
||||
for (int i = 0 ; i < points_vector.size() ; ++i)
|
||||
m_handler_vector.at(i)->setPos(points_vector.at(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
qDeleteAll(m_handler_vector);
|
||||
m_handler_vector.clear();
|
||||
addHandler();
|
||||
}
|
||||
}
|
||||
|
||||
void PartPlcTable::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(qghi)
|
||||
Q_UNUSED(event)
|
||||
|
||||
m_old_rect = m_rect;
|
||||
}
|
||||
|
||||
void PartPlcTable::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(qghi)
|
||||
|
||||
QPointF new_pos = event->scenePos();
|
||||
if (event->modifiers() != Qt::ControlModifier)
|
||||
new_pos = elementScene()->snapToGrid(event->scenePos());
|
||||
new_pos = mapFromScene(new_pos);
|
||||
|
||||
setRect(QetGraphicsHandlerUtility::rectForPosAtIndex(m_rect, new_pos, m_vector_index));
|
||||
adjustHandlerPos();
|
||||
}
|
||||
|
||||
void PartPlcTable::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(qghi)
|
||||
Q_UNUSED(event)
|
||||
|
||||
QUndoCommand *undo = new QUndoCommand("Modifier une table PLC");
|
||||
if (m_old_rect != m_rect) {
|
||||
QPropertyUndoCommand *u = new QPropertyUndoCommand(this, "rect", QVariant(m_old_rect.normalized()), QVariant(m_rect.normalized()), undo);
|
||||
u->setAnimated(true, false);
|
||||
}
|
||||
|
||||
elementScene()->undoStack().push(undo);
|
||||
m_vector_index = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::addHandler
|
||||
Do not add resize handlers - table size is data-driven.
|
||||
Move is handled by the base class QGraphicsItem drag behavior.
|
||||
*/
|
||||
void PartPlcTable::addHandler()
|
||||
{
|
||||
// No resize handlers - size comes from PLC data
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartPlcTable::removeHandler
|
||||
Remove the handlers of this item
|
||||
*/
|
||||
void PartPlcTable::removeHandler()
|
||||
{
|
||||
if (!m_handler_vector.isEmpty())
|
||||
{
|
||||
qDeleteAll(m_handler_vector);
|
||||
m_handler_vector.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PARTPLCTABLE_H
|
||||
#define PARTPLCTABLE_H
|
||||
|
||||
#include "customelementgraphicpart.h"
|
||||
#include "../../QetGraphicsItemModeler/qetgraphicshandleritem.h"
|
||||
|
||||
#include <QVector>
|
||||
|
||||
/**
|
||||
@brief The PartPlcTable class
|
||||
This class represents a PLC I/O table preview in the element editor.
|
||||
It shows the user where the PLC table will appear at runtime, so they
|
||||
can position other element parts (rectangles, terminals, etc.) around it.
|
||||
The actual PLC data is read from ElementScene::elementData().
|
||||
*/
|
||||
class PartPlcTable : public CustomElementGraphicPart
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QRectF rect READ rect WRITE setRect)
|
||||
|
||||
public:
|
||||
PartPlcTable(QETElementEditor *editor, QGraphicsItem *parent = nullptr);
|
||||
~PartPlcTable() override;
|
||||
|
||||
enum { Type = UserType + 1120 };
|
||||
int type () const override { return Type; }
|
||||
void paint (QPainter *, const QStyleOptionGraphicsItem *, QWidget * = nullptr) override;
|
||||
QString name () const override { return QObject::tr("table PLC", "element part name"); }
|
||||
|
||||
QString xmlName () const override { return QString("plc_table"); }
|
||||
const QDomElement toXml (QDomDocument &) const override;
|
||||
void fromXml (const QDomElement &) override;
|
||||
|
||||
QRectF rect() const;
|
||||
void setRect(const QRectF &rect);
|
||||
|
||||
QRectF sceneGeometricRect() const override;
|
||||
QPainterPath shape () const override;
|
||||
QPainterPath shadowShape() const override;
|
||||
QRectF boundingRect() const override;
|
||||
bool isUseless() const override;
|
||||
|
||||
void startUserTransformation(const QRectF &) override;
|
||||
void handleUserTransformation(const QRectF &, const QRectF &) override;
|
||||
|
||||
void addHandler() override;
|
||||
void removeHandler() override;
|
||||
|
||||
protected:
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override;
|
||||
|
||||
private:
|
||||
void switchResizeMode();
|
||||
void adjustHandlerPos();
|
||||
void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event);
|
||||
void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event);
|
||||
void handlerMouseReleaseEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event);
|
||||
QSizeF calculateTableSize() const;
|
||||
|
||||
private:
|
||||
QRectF m_rect,
|
||||
m_old_rect;
|
||||
QList<QPointF> saved_points_;
|
||||
int m_resize_mode = 1,
|
||||
m_vector_index = -1;
|
||||
QVector<QetGraphicsHandlerItem *> m_handler_vector;
|
||||
};
|
||||
|
||||
#endif // PARTPLCTABLE_H
|
||||
@@ -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<int>(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<int>(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,93 @@ 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();
|
||||
}
|
||||
|
||||
void PartTerminal::setUseMasterLabel(bool use)
|
||||
{
|
||||
if (d->m_use_master_label == use) return;
|
||||
d->m_use_master_label = use;
|
||||
update();
|
||||
emit useMasterLabelChanged();
|
||||
}
|
||||
|
||||
void PartTerminal::setMasterLabelIndex(int index)
|
||||
{
|
||||
if (d->m_master_label_index == index) return;
|
||||
d->m_master_label_index = index;
|
||||
update();
|
||||
emit masterLabelIndexChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
Updates the position of the second point according to the position
|
||||
and orientation of the terminal.
|
||||
@@ -338,3 +532,53 @@ void PartTerminal::handleUserTransformation(const QRectF &initial_selection_rect
|
||||
initial_selection_rect, new_selection_rect, QList<QPointF>() << 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);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,16 @@ 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)
|
||||
Q_PROPERTY(bool use_master_label READ useMasterLabel WRITE setUseMasterLabel)
|
||||
Q_PROPERTY(int master_label_index READ masterLabelIndex WRITE setMasterLabelIndex)
|
||||
|
||||
public:
|
||||
// constructors, destructor
|
||||
@@ -46,6 +56,16 @@ 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();
|
||||
void useMasterLabelChanged();
|
||||
void masterLabelIndexChanged();
|
||||
|
||||
// methods
|
||||
public:
|
||||
@@ -64,7 +84,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 +110,52 @@ 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);
|
||||
|
||||
bool useMasterLabel() const { return d->m_use_master_label; }
|
||||
void setUseMasterLabel(bool use);
|
||||
|
||||
int masterLabelIndex() const { return d->m_master_label_index; }
|
||||
void setMasterLabelIndex(int index);
|
||||
|
||||
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
|
||||
|
||||
@@ -18,10 +18,12 @@
|
||||
#include "parttext.h"
|
||||
|
||||
#include "../../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include <QApplication>
|
||||
#include "../../qetapp.h"
|
||||
#include "../elementprimitivedecorator.h"
|
||||
#include "../elementscene.h"
|
||||
#include "../ui/texteditor.h"
|
||||
#include "../../utils/qetutils.h"
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@@ -124,12 +126,26 @@ void PartText::fromXml(const QDomElement &xml_element) {
|
||||
}
|
||||
else if (xml_element.hasAttribute("font")) {
|
||||
QFont font_;
|
||||
font_.fromString(xml_element.attribute("font"));
|
||||
QETUtils::fontFromString(font_, xml_element.attribute("font"));
|
||||
setFont(font_);
|
||||
}
|
||||
|
||||
setDefaultTextColor(QColor(xml_element.attribute("color", "#000000")));
|
||||
setPlainText(xml_element.attribute("text"));
|
||||
|
||||
// Optional alignment (absent = historical behaviour: top-left anchor,
|
||||
// left-aligned lines), same attributes as the dynamic text fields.
|
||||
Qt::Alignment alignment_ = Qt::AlignTop | Qt::AlignLeft;
|
||||
QMetaEnum me = QMetaEnum::fromType<Qt::Alignment>();
|
||||
if (xml_element.hasAttribute("Halignment"))
|
||||
alignment_ = Qt::Alignment(
|
||||
me.keyToValue(xml_element.attribute("Halignment").toStdString().data()));
|
||||
if (xml_element.hasAttribute("Valignment"))
|
||||
alignment_ = Qt::Alignment(
|
||||
me.keyToValue(xml_element.attribute("Valignment").toStdString().data()))
|
||||
| (alignment_ & Qt::AlignHorizontal_Mask);
|
||||
setAlignment(alignment_);
|
||||
|
||||
setPos(xml_element.attribute("x").toDouble(),
|
||||
xml_element.attribute("y").toDouble());
|
||||
QGraphicsObject::setRotation(QET::correctAngle(xml_element.attribute("rotation", QString::number(0)).toDouble()));
|
||||
@@ -150,10 +166,22 @@ const QDomElement PartText::toXml(QDomDocument &xml_document) const
|
||||
xml_element.setAttribute("x", QString::number(x));
|
||||
xml_element.setAttribute("y", QString::number(y));
|
||||
xml_element.setAttribute("text", toPlainText());
|
||||
xml_element.setAttribute("font", font().toString());
|
||||
xml_element.setAttribute("font", QETUtils::fontToString(font()));
|
||||
xml_element.setAttribute("rotation", QString::number(rot));
|
||||
xml_element.setAttribute("color", defaultTextColor().name());
|
||||
|
||||
// Only written when different from the historical behaviour, so
|
||||
// existing .elmt files round-trip byte-identical.
|
||||
QMetaEnum me = QMetaEnum::fromType<Qt::Alignment>();
|
||||
if (m_alignment & Qt::AlignRight)
|
||||
xml_element.setAttribute("Halignment", me.valueToKey(Qt::AlignRight));
|
||||
else if (m_alignment & Qt::AlignHCenter)
|
||||
xml_element.setAttribute("Halignment", me.valueToKey(Qt::AlignHCenter));
|
||||
if (m_alignment & Qt::AlignBottom)
|
||||
xml_element.setAttribute("Valignment", me.valueToKey(Qt::AlignBottom));
|
||||
else if (m_alignment & Qt::AlignVCenter)
|
||||
xml_element.setAttribute("Valignment", me.valueToKey(Qt::AlignVCenter));
|
||||
|
||||
return(xml_element);
|
||||
}
|
||||
|
||||
@@ -305,24 +333,126 @@ void PartText::setDefaultTextColor(const QColor &color) {
|
||||
|
||||
void PartText::setPlainText(const QString &text) {
|
||||
if (text != this -> toPlainText()) {
|
||||
prepareAlignment();
|
||||
QGraphicsTextItem::setPlainText(text);
|
||||
applyLineAlignment();
|
||||
finishAlignment();
|
||||
emit plainTextChanged(text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartText::setAlignment
|
||||
Set how this text is anchored to its position: when the content later
|
||||
changes, the given corner/center of the bounding rect keeps its place
|
||||
(the historical behaviour, and the default, is top-left). The
|
||||
horizontal part also aligns the lines of a multi-line text relative
|
||||
to each other. Changing the alignment never moves the text itself.
|
||||
@param alignment
|
||||
*/
|
||||
void PartText::setAlignment(const Qt::Alignment &alignment)
|
||||
{
|
||||
if (alignment == m_alignment)
|
||||
return;
|
||||
m_alignment = alignment;
|
||||
applyLineAlignment();
|
||||
emit alignmentChanged(m_alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartText::applyLineAlignment
|
||||
Align the lines of a multi-line text relative to each other according
|
||||
to the horizontal part of the alignment property. QGraphicsTextItem
|
||||
only honors the document text option when a text width is set, hence
|
||||
the idealWidth() dance; -1 restores the free (historical) layout.
|
||||
*/
|
||||
void PartText::applyLineAlignment()
|
||||
{
|
||||
QTextOption option = document()->defaultTextOption();
|
||||
option.setAlignment(m_alignment & Qt::AlignHorizontal_Mask);
|
||||
document()->setDefaultTextOption(option);
|
||||
|
||||
setTextWidth(-1);
|
||||
if (m_alignment & (Qt::AlignHCenter | Qt::AlignRight))
|
||||
setTextWidth(document()->idealWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartText::prepareAlignment
|
||||
Call before a change of the bounding rect (see finishAlignment).
|
||||
*/
|
||||
void PartText::prepareAlignment()
|
||||
{
|
||||
m_alignment_rect = boundingRect();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief PartText::finishAlignment
|
||||
Call after a change of the bounding rect: moves the text so that the
|
||||
point selected by the alignment property stays where it was (same
|
||||
logic as DiagramTextItem::finishAlignment).
|
||||
*/
|
||||
void PartText::finishAlignment()
|
||||
{
|
||||
QTransform transform;
|
||||
transform.rotate(rotation());
|
||||
qreal x, xa, y, ya;
|
||||
x = xa = 0;
|
||||
y = ya = 0;
|
||||
|
||||
if (m_alignment & Qt::AlignRight)
|
||||
{
|
||||
x = m_alignment_rect.right();
|
||||
xa = boundingRect().right();
|
||||
}
|
||||
else if (m_alignment & Qt::AlignHCenter)
|
||||
{
|
||||
x = m_alignment_rect.center().x();
|
||||
xa = boundingRect().center().x();
|
||||
}
|
||||
|
||||
if (m_alignment & Qt::AlignBottom)
|
||||
{
|
||||
y = m_alignment_rect.bottom();
|
||||
ya = boundingRect().bottom();
|
||||
}
|
||||
else if (m_alignment & Qt::AlignVCenter)
|
||||
{
|
||||
y = m_alignment_rect.center().y();
|
||||
ya = boundingRect().center().y();
|
||||
}
|
||||
|
||||
QPointF p = transform.map(QPointF(x, y));
|
||||
QPointF pa = transform.map(QPointF(xa, ya));
|
||||
|
||||
setPos(pos() - (pa - p));
|
||||
}
|
||||
|
||||
void PartText::setFont(const QFont &font) {
|
||||
if (font != this -> font()) {
|
||||
prepareAlignment();
|
||||
QGraphicsTextItem::setFont(font);
|
||||
applyLineAlignment();
|
||||
finishAlignment();
|
||||
// Re-anchor: the item's position transform is -margin(), and margin()
|
||||
// depends on the font ascent. Without re-running this on a font change,
|
||||
// the transform keeps the previous font's ascent — so the text renders
|
||||
// at a different spot after save/reopen (the position recomputes from
|
||||
// the saved font on load). See #158.
|
||||
adjustItemPosition();
|
||||
emit fontChanged(font);
|
||||
}
|
||||
}
|
||||
|
||||
void PartText::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
if((event -> buttons() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable)) {
|
||||
QPointF pos = event -> scenePos() + (m_origin_pos - event -> buttonDownScenePos(Qt::LeftButton));
|
||||
event -> modifiers() == Qt::ControlModifier ? setPos(pos) : setPos(elementScene() -> snapToGrid(pos));
|
||||
}
|
||||
else {
|
||||
if ((event->buttons() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable)) {
|
||||
// Suppress spurious moves from the properties dock resizing the viewport.
|
||||
const QPointF d = event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton);
|
||||
if (d.manhattanLength() < QApplication::startDragDistance())
|
||||
return;
|
||||
QPointF pos = event->scenePos() + (m_origin_pos - event->buttonDownScenePos(Qt::LeftButton));
|
||||
event->modifiers() == Qt::ControlModifier ? setPos(pos) : setPos(elementScene()->snapToGrid(pos));
|
||||
} else {
|
||||
QGraphicsObject::mouseMoveEvent(event);
|
||||
}
|
||||
}
|
||||
@@ -387,6 +517,11 @@ void PartText::startEdition()
|
||||
{
|
||||
// !previous_text.isNull() means the text is being edited
|
||||
previous_text = toPlainText();
|
||||
|
||||
// Anchor the aligned point across the whole inline edition; free the
|
||||
// text width so typing is not wrapped at the previous block width.
|
||||
prepareAlignment();
|
||||
setTextWidth(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,7 +530,8 @@ void PartText::startEdition()
|
||||
*/
|
||||
void PartText::endEdition()
|
||||
{
|
||||
if (!previous_text.isNull()) {
|
||||
const bool was_editing = !previous_text.isNull();
|
||||
if (was_editing) {
|
||||
// the text was being edited
|
||||
QString new_text = toPlainText();
|
||||
if (previous_text != new_text) {
|
||||
@@ -412,4 +548,9 @@ void PartText::endEdition()
|
||||
setTextCursor(qtc);
|
||||
|
||||
setEditable(false);
|
||||
|
||||
if (was_editing) {
|
||||
applyLineAlignment();
|
||||
finishAlignment();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,13 @@ class PartText : public QGraphicsTextItem, public CustomElementPart {
|
||||
Q_PROPERTY(QColor color READ defaultTextColor WRITE setDefaultTextColor NOTIFY colorChanged)
|
||||
Q_PROPERTY(QString text READ toPlainText WRITE setPlainText NOTIFY plainTextChanged)
|
||||
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
|
||||
Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged)
|
||||
|
||||
signals:
|
||||
void fontChanged(const QFont &font);
|
||||
void colorChanged(const QColor &color);
|
||||
void plainTextChanged(const QString &text);
|
||||
void alignmentChanged(Qt::Alignment alignment);
|
||||
|
||||
// constructors, destructor
|
||||
public:
|
||||
@@ -77,6 +79,8 @@ class PartText : public QGraphicsTextItem, public CustomElementPart {
|
||||
void setDefaultTextColor(const QColor &color);
|
||||
void setPlainText(const QString &text);
|
||||
void setFont(const QFont &font);
|
||||
void setAlignment(const Qt::Alignment &alignment);
|
||||
Qt::Alignment alignment() const {return m_alignment;}
|
||||
|
||||
public slots:
|
||||
void adjustItemPosition(int = 0);
|
||||
@@ -97,11 +101,16 @@ class PartText : public QGraphicsTextItem, public CustomElementPart {
|
||||
|
||||
private:
|
||||
QPointF margin() const;
|
||||
void applyLineAlignment();
|
||||
void prepareAlignment();
|
||||
void finishAlignment();
|
||||
QString previous_text;
|
||||
qreal real_font_size_;
|
||||
QPointF saved_point_;
|
||||
qreal saved_font_size_;
|
||||
QGraphicsItem *decorator_;
|
||||
QPointF m_origin_pos;
|
||||
Qt::Alignment m_alignment = (Qt::AlignTop | Qt::AlignLeft);
|
||||
QRectF m_alignment_rect;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -386,7 +386,7 @@ StyleEditor::StyleEditor(QETElementEditor *editor, CustomElementGraphicPart *p,
|
||||
|
||||
outline_color->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
filling_color->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
auto grid_layout = new QGridLayout(this);
|
||||
auto grid_layout = new QGridLayout();
|
||||
grid_layout->addWidget(new QLabel(tr("Contour :")), 0,0, Qt::AlignRight);
|
||||
grid_layout->addWidget(outline_color, 0, 1);
|
||||
grid_layout->addWidget(new QLabel(tr("Remplissage :")), 1, 0, Qt::AlignRight);
|
||||
|
||||
@@ -163,7 +163,7 @@ void DynamicTextFieldEditor::updateForm()
|
||||
}
|
||||
}
|
||||
|
||||
on_m_text_from_cb_activated(ui -> m_text_from_cb -> currentIndex()); //For enable the good widget
|
||||
updateTextFromWidgetsEnabled(ui -> m_text_from_cb -> currentIndex()); //For enable the good widget
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +197,10 @@ void DynamicTextFieldEditor::setUpConnections()
|
||||
m_connection_list << connect(m_text_field.data(), &PartDynamicTextField::textWidthChanged, this, [=](){this -> updateForm();});
|
||||
m_connection_list << connect(m_text_field.data(), &PartDynamicTextField::compositeTextChanged,this, [=](){this -> updateForm();});
|
||||
m_connection_list << connect(m_text_field.data(), &PartDynamicTextField::keepVisualRotationChanged, this, [=](){this -> updateForm();});
|
||||
|
||||
// Refresh info combo when element data changes (e.g. type switched to PLC-Slave)
|
||||
m_connection_list << connect(elementEditor()->elementScene(), &ElementScene::elementInfoChanged,
|
||||
this, &DynamicTextFieldEditor::fillInfoComboBox);
|
||||
}
|
||||
|
||||
void DynamicTextFieldEditor::disconnectConnections()
|
||||
@@ -218,13 +222,34 @@ void DynamicTextFieldEditor::fillInfoComboBox()
|
||||
ui -> m_elmt_info_cb -> clear();
|
||||
|
||||
QStringList strl;
|
||||
auto type = elementEditor()->elementScene()->elementData().m_type;
|
||||
auto ed = elementEditor()->elementScene()->elementData();
|
||||
auto type = ed.m_type;
|
||||
|
||||
if((type & ElementData::AllReport) || (type == ElementData::ConductorDefinition)) {
|
||||
strl = QETInformation::folioReportInfoKeys();
|
||||
}
|
||||
else {
|
||||
strl = QETInformation::elementInfoKeys();
|
||||
|
||||
bool is_plc_slave = (type == ElementData::Slave
|
||||
&& ed.m_slave_type == ElementData::PLCSlave);
|
||||
|
||||
if (is_plc_slave) {
|
||||
QStringList plc_keys = {
|
||||
QETInformation::ELMT_PLC_TYPE,
|
||||
QETInformation::ELMT_PLC_ADDRESS,
|
||||
QETInformation::ELMT_PLC_FUNCTION,
|
||||
QETInformation::ELMT_PLC_COMMENT,
|
||||
QETInformation::ELMT_PLC_CROSSREF
|
||||
};
|
||||
strl = plc_keys + strl;
|
||||
} else {
|
||||
strl.removeAll(QETInformation::ELMT_PLC_TYPE);
|
||||
strl.removeAll(QETInformation::ELMT_PLC_ADDRESS);
|
||||
strl.removeAll(QETInformation::ELMT_PLC_FUNCTION);
|
||||
strl.removeAll(QETInformation::ELMT_PLC_COMMENT);
|
||||
strl.removeAll(QETInformation::ELMT_PLC_CROSSREF);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<strl.size();++i) {
|
||||
@@ -327,7 +352,16 @@ void DynamicTextFieldEditor::on_m_elmt_info_cb_activated(const QString &arg1) {
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicTextFieldEditor::on_m_text_from_cb_activated(int index) {
|
||||
/**
|
||||
@brief DynamicTextFieldEditor::updateTextFromWidgetsEnabled
|
||||
Enable the widget matching @p index (the "text from" combo box's current
|
||||
index) and disable the other two. Purely cosmetic: called both from the
|
||||
real user-activated slot below and from updateForm() when the form is
|
||||
(re)filled for a part/selection, so it must never touch m_parts's data —
|
||||
see on_m_text_from_cb_activated() for the part-mutating counterpart.
|
||||
*/
|
||||
void DynamicTextFieldEditor::updateTextFromWidgetsEnabled(int index)
|
||||
{
|
||||
ui -> m_user_text_le -> setDisabled(true);
|
||||
ui -> m_elmt_info_cb -> setDisabled(true);
|
||||
ui -> m_composite_text_pb -> setDisabled(true);
|
||||
@@ -341,6 +375,10 @@ void DynamicTextFieldEditor::on_m_text_from_cb_activated(int index) {
|
||||
else {
|
||||
ui->m_composite_text_pb->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicTextFieldEditor::on_m_text_from_cb_activated(int index) {
|
||||
updateTextFromWidgetsEnabled(index);
|
||||
|
||||
DynamicElementTextItem::TextFrom tf;
|
||||
if(index == 0) {
|
||||
|
||||
@@ -52,6 +52,7 @@ class DynamicTextFieldEditor : public ElementItemEditor {
|
||||
void fillInfoComboBox();
|
||||
void setUpConnections();
|
||||
void disconnectConnections();
|
||||
void updateTextFromWidgetsEnabled(int index);
|
||||
|
||||
private slots:
|
||||
void on_m_x_sb_editingFinished();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,13 @@
|
||||
#include <QAbstractButton>
|
||||
#include <QDialog>
|
||||
|
||||
class QTableWidget;
|
||||
class QSpinBox;
|
||||
class QCheckBox;
|
||||
class QGroupBox;
|
||||
class QPushButton;
|
||||
class QLineEdit;
|
||||
|
||||
namespace Ui {
|
||||
class ElementPropertiesEditorWidget;
|
||||
}
|
||||
@@ -49,16 +56,45 @@ class ElementPropertiesEditorWidget : public QDialog
|
||||
void setUpInterface();
|
||||
void updateTree();
|
||||
void populateTree();
|
||||
void populateSlaveGroupsTable();
|
||||
void readSlaveGroupsFromTable();
|
||||
void createPlcConfigWidgets();
|
||||
void populatePlcTable();
|
||||
void readPlcTable();
|
||||
|
||||
//SLOTS
|
||||
private slots:
|
||||
void on_m_buttonBox_accepted();
|
||||
void on_m_base_type_cb_currentIndexChanged(int index);
|
||||
void on_m_slave_groups_checkbox_toggled(bool checked);
|
||||
void on_max_slaves_checkbox_toggled(bool checked);
|
||||
void plcAddRow();
|
||||
void plcRemoveRow();
|
||||
void plcPasteFromClipboard();
|
||||
void plcTerminalCountChanged(int row, int count);
|
||||
void plcSelectHeaderFont();
|
||||
void plcSelectCellFont();
|
||||
|
||||
//ATTRIBUTES
|
||||
private:
|
||||
Ui::ElementPropertiesEditorWidget *ui;
|
||||
ElementData m_data;
|
||||
|
||||
// PLC configuration widgets (created programmatically)
|
||||
QGroupBox *m_plc_gb = nullptr;
|
||||
QTableWidget *m_plc_table = nullptr;
|
||||
QTableWidget *m_plc_terminal_table = nullptr;
|
||||
QCheckBox *m_plc_break_checkboxes[4] = {nullptr, nullptr, nullptr, nullptr};
|
||||
QSpinBox *m_plc_break_spinboxes[4] = {nullptr, nullptr, nullptr, nullptr};
|
||||
QSpinBox *m_plc_row_height_spinbox = nullptr;
|
||||
QPushButton *m_plc_header_font_btn = nullptr;
|
||||
QPushButton *m_plc_cell_font_btn = nullptr;
|
||||
QCheckBox *m_plc_show_headers_cb = nullptr;
|
||||
QFont m_plc_header_font;
|
||||
QFont m_plc_cell_font;
|
||||
QList<QCheckBox *> m_plc_col_visibility_checkboxes;
|
||||
QList<QSpinBox *> m_plc_col_width_spinboxes;
|
||||
QList<QLineEdit *> m_plc_col_name_edits;
|
||||
};
|
||||
|
||||
#endif // ELEMENTPROPERTIESEDITORWIDGET_H
|
||||
|
||||
@@ -93,17 +93,17 @@
|
||||
<property name="title">
|
||||
<string>Élément maître</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Type concret</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="m_master_type_cb"/>
|
||||
</item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Type concret</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="m_master_type_cb"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="max_slaves_checkbox">
|
||||
<property name="text">
|
||||
@@ -121,6 +121,55 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="m_slave_groups_checkbox">
|
||||
<property name="text">
|
||||
<string>Définir les éléments esclave</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QTableWidget" name="m_slave_groups_table">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Contact</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Nb. contacts</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Nb. bornes</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -480,15 +480,11 @@ void QETElementEditor::fillPartsList()
|
||||
}
|
||||
}
|
||||
QListWidgetItem *qlwi = new QListWidgetItem(part_desc);
|
||||
QVariant v;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove
|
||||
v.setValue<QGraphicsItem *>(qgi);
|
||||
#else
|
||||
#if TODO_LIST
|
||||
#pragma message("@TODO remove code for QT 6 or later")
|
||||
#endif
|
||||
qDebug()<<"Help code for QT 6 or later";
|
||||
#endif
|
||||
// Qt declares the QGraphicsItem* metatype itself, so this
|
||||
// works on Qt 5 and Qt 6 alike. Without the stored pointer
|
||||
// the parts list loses its item association and selecting
|
||||
// a part no longer selects it on the canvas.
|
||||
QVariant v = QVariant::fromValue(qgi);
|
||||
qlwi -> setData(42, v);
|
||||
m_parts_list -> addItem(qlwi);
|
||||
qlwi -> setSelected(qgi -> isSelected());
|
||||
@@ -736,11 +732,13 @@ bool QETElementEditor::checkElement()
|
||||
QList<QETWarning> warnings;
|
||||
QList<QETWarning> errors;
|
||||
|
||||
// Warning #1: Element haven't got terminal
|
||||
// Warning #1: Element does not have (enough) terminals
|
||||
// (except for report and conductor definition, because they must have one terminal and this checking is done below)
|
||||
// (another exception: "thumbnails" aka "front-views" may/should not have terminals)
|
||||
if (!m_elmt_scene -> containsTerminals() &&
|
||||
!(m_elmt_scene->elementData().m_type & ElementData::AllReport) &&
|
||||
m_elmt_scene->elementData().m_type != ElementData::ConductorDefinition) {
|
||||
m_elmt_scene->elementData().m_type != ElementData::ConductorDefinition &&
|
||||
m_elmt_scene->elementData().m_type != ElementData::Thumbnail) {
|
||||
warnings << qMakePair(
|
||||
tr("Absence de borne", "warning title"),
|
||||
tr(
|
||||
@@ -749,50 +747,50 @@ bool QETElementEditor::checkElement()
|
||||
"warning description"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check folio report element
|
||||
if (m_elmt_scene->elementData().m_type & ElementData::AllReport)
|
||||
{
|
||||
int terminal =0;
|
||||
// Check folio report element
|
||||
if (m_elmt_scene->elementData().m_type & ElementData::AllReport)
|
||||
{
|
||||
int terminal =0;
|
||||
|
||||
for(auto qgi : m_elmt_scene -> items()) {
|
||||
if (qgraphicsitem_cast<PartTerminal *>(qgi)) {
|
||||
terminal ++;
|
||||
}
|
||||
}
|
||||
|
||||
//Error folio report must have only one terminal
|
||||
if (terminal != 1) {
|
||||
errors << qMakePair (tr("Absence de borne"),
|
||||
tr("<br><b>Erreur</b> :"
|
||||
"<br>Les reports de folio doivent posséder une seul borne."
|
||||
"<br><b>Solution</b> :"
|
||||
"<br>Verifier que l'élément ne possède qu'une seul borne"));
|
||||
for(auto qgi : m_elmt_scene -> items()) {
|
||||
if (qgraphicsitem_cast<PartTerminal *>(qgi)) {
|
||||
terminal ++;
|
||||
}
|
||||
}
|
||||
|
||||
// Check conductor definition element
|
||||
if (m_elmt_scene->elementData().m_type == ElementData::ConductorDefinition)
|
||||
{
|
||||
int terminal =0;
|
||||
//Error folio report must have only one terminal
|
||||
if (terminal != 1) {
|
||||
errors << qMakePair (tr("Absence de borne"),
|
||||
tr("<br><b>Erreur</b> :"
|
||||
"<br>Les reports de folio doivent posséder une seul borne."
|
||||
"<br><b>Solution</b> :"
|
||||
"<br>Verifier que l'élément ne possède qu'une seul borne"));
|
||||
}
|
||||
}
|
||||
|
||||
for(auto qgi : m_elmt_scene -> items()) {
|
||||
if (qgraphicsitem_cast<PartTerminal *>(qgi)) {
|
||||
terminal ++;
|
||||
}
|
||||
}
|
||||
// Check conductor definition element
|
||||
if (m_elmt_scene->elementData().m_type == ElementData::ConductorDefinition)
|
||||
{
|
||||
int terminal =0;
|
||||
|
||||
// Error: Conductor definition must have exactly one terminal
|
||||
if (terminal != 1) {
|
||||
errors << qMakePair (tr("Nombre de bornes incorrect"),
|
||||
tr("<br><b>Erreur</b> :"
|
||||
"<br>Les définitions de conducteur ne peuvent posséder qu'une seule borne."
|
||||
"<br><b>Solution</b> :"
|
||||
"<br>Vérifier que l'élément ne possède qu'une seule borne"));
|
||||
for(auto qgi : m_elmt_scene -> items()) {
|
||||
if (qgraphicsitem_cast<PartTerminal *>(qgi)) {
|
||||
terminal ++;
|
||||
}
|
||||
}
|
||||
|
||||
// Error: Conductor definition must have exactly one terminal
|
||||
if (terminal != 1) {
|
||||
errors << qMakePair (tr("Nombre de bornes incorrect"),
|
||||
tr("<br><b>Erreur</b> :"
|
||||
"<br>Les définitions de conducteur ne peuvent posséder qu'une seule borne."
|
||||
"<br><b>Solution</b> :"
|
||||
"<br>Vérifier que l'élément ne possède qu'une seule borne"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!errors.count() && !warnings.count()) {
|
||||
return(true);
|
||||
}
|
||||
@@ -1091,7 +1089,7 @@ void QETElementEditor::updateAction()
|
||||
<< ui->m_revert_selection_action
|
||||
<< ui->m_paste_from_file_action
|
||||
<< ui->m_paste_from_element_action;
|
||||
for (auto action : qAsConst(ro_list)) {
|
||||
for (auto action : std::as_const(ro_list)) {
|
||||
action->setDisabled(m_read_only);
|
||||
}
|
||||
|
||||
@@ -1106,7 +1104,7 @@ void QETElementEditor::updateAction()
|
||||
<< ui->m_flip_action
|
||||
<< ui->m_mirror_action;
|
||||
auto items_selected = !m_read_only && m_elmt_scene->selectedItems().count();
|
||||
for (auto action : qAsConst(select_list)) {
|
||||
for (auto action : std::as_const(select_list)) {
|
||||
action->setEnabled(items_selected);
|
||||
}
|
||||
|
||||
@@ -1190,6 +1188,12 @@ void QETElementEditor::initGui()
|
||||
updateInformations();
|
||||
fillPartsList();
|
||||
|
||||
// When the element type changes, update the terminal editor master label visibility
|
||||
connect(m_elmt_scene, &ElementScene::elementTypeChanged, this, [this]() {
|
||||
auto *te = static_cast<TerminalEditor *>(m_editors["terminal"]);
|
||||
if (te) te->refreshMasterLabelVisibility();
|
||||
});
|
||||
|
||||
statusBar()->showMessage(tr("Éditeur d'éléments", "status bar message"));
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
#include "../../qet.h"
|
||||
#include "../graphicspart/partterminal.h"
|
||||
#include "../../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include "../../ui/alignmenttextdialog.h"
|
||||
|
||||
#include <QColorDialog>
|
||||
#include <QFontDialog>
|
||||
#include "../elementscene.h"
|
||||
#include "qetelementeditor.h"
|
||||
|
||||
/**
|
||||
* @brief TerminalEditor::TerminalEditor
|
||||
@@ -33,6 +39,22 @@ TerminalEditor::TerminalEditor(QETElementEditor *editor, QWidget *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();
|
||||
}
|
||||
|
||||
@@ -63,6 +85,44 @@ 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<int>(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());
|
||||
|
||||
// Update master label fields
|
||||
bool is_slave = updateMasterLabelVisibility();
|
||||
if (is_slave) {
|
||||
PartTerminal *pt = m_part;
|
||||
if (pt) {
|
||||
ui->m_use_master_label_cb->setChecked(pt->useMasterLabel());
|
||||
ui->m_master_label_cb->setEnabled(pt->useMasterLabel());
|
||||
ui->m_name_le->setEnabled(!pt->useMasterLabel());
|
||||
int idx = ui->m_master_label_cb->findData(pt->masterLabelIndex());
|
||||
if (idx >= 0) {
|
||||
ui->m_master_label_cb->setCurrentIndex(idx);
|
||||
}
|
||||
// Show T-label in name field when master label is active
|
||||
if (pt->useMasterLabel()) {
|
||||
int label_idx = pt->masterLabelIndex();
|
||||
ui->m_name_le->setText(tr("T%1").arg(label_idx + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
activeConnections(true);
|
||||
}
|
||||
|
||||
@@ -125,6 +185,16 @@ 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);
|
||||
|
||||
// Populate master label dropdown (T1-T20)
|
||||
for (int i = 1; i <= 20; ++i) {
|
||||
ui->m_master_label_cb->addItem(tr("T%1").arg(i), i - 1);
|
||||
}
|
||||
|
||||
// Check if parent element is a Slave to show/hide master label group
|
||||
updateMasterLabelVisibility();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,6 +288,146 @@ void TerminalEditor::typeEdited()
|
||||
* 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<qreal>(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,8 +441,28 @@ void TerminalEditor::activeConnections(bool active)
|
||||
this, &TerminalEditor::nameEdited);
|
||||
m_editor_connections << connect(ui->m_type_cb, QOverload<int>::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<qreal>::of(&QDoubleSpinBox::valueChanged),
|
||||
[this]() { TerminalEditor::labelPosEdited(); ui->m_label_x_dsb->setFocus(); });
|
||||
m_editor_connections << connect(ui->m_label_y_dsb, QOverload<qreal>::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<int>::of(&QSpinBox::valueChanged),
|
||||
[this]() { TerminalEditor::labelSizeEdited(); ui->m_label_size_sb->setFocus(); });
|
||||
m_editor_connections << connect(ui->m_label_rotation_sb, QOverload<double>::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);
|
||||
m_editor_connections << connect(ui->m_use_master_label_cb, &QCheckBox::toggled,
|
||||
this, &TerminalEditor::useMasterLabelEdited);
|
||||
m_editor_connections << connect(ui->m_master_label_cb, QOverload<int>::of(&QComboBox::activated),
|
||||
this, &TerminalEditor::masterLabelIndexEdited);
|
||||
} else {
|
||||
for (auto const & con : qAsConst(m_editor_connections)) {
|
||||
for (auto const & con : std::as_const(m_editor_connections)) {
|
||||
QObject::disconnect(con);
|
||||
}
|
||||
m_editor_connections.clear();
|
||||
@@ -248,6 +478,16 @@ 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);
|
||||
m_change_connections << connect(m_part, &PartTerminal::useMasterLabelChanged, this, &TerminalEditor::updateForm);
|
||||
m_change_connections << connect(m_part, &PartTerminal::masterLabelIndexChanged, this, &TerminalEditor::updateForm);
|
||||
} else {
|
||||
for (auto &con : m_change_connections) {
|
||||
QObject::disconnect(con);
|
||||
@@ -255,3 +495,95 @@ void TerminalEditor::activeChangeConnections(bool active)
|
||||
m_change_connections.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalEditor::useMasterLabelEdited()
|
||||
{
|
||||
if (m_locked) return;
|
||||
m_locked = true;
|
||||
|
||||
bool use = ui->m_use_master_label_cb->isChecked();
|
||||
ui->m_master_label_cb->setEnabled(use);
|
||||
|
||||
QSignalBlocker name_blocker(ui->m_name_le);
|
||||
|
||||
if (m_part->useMasterLabel() != use) {
|
||||
auto undo = new QPropertyUndoCommand(m_part, "use_master_label",
|
||||
m_part->useMasterLabel(), use);
|
||||
undo->setText(tr("Modifier l'étiquette du maître"));
|
||||
undoStack().push(undo);
|
||||
}
|
||||
|
||||
if (use) {
|
||||
int idx = ui->m_master_label_cb->currentData().toInt();
|
||||
QString t_label = tr("T%1").arg(idx + 1);
|
||||
ui->m_name_le->setText(t_label);
|
||||
ui->m_name_le->setEnabled(false);
|
||||
if (m_part->terminalName() != t_label) {
|
||||
auto undo = new QPropertyUndoCommand(m_part, "terminal_name",
|
||||
m_part->terminalName(), t_label);
|
||||
undo->setText(tr("Modifier le nom de la borne"));
|
||||
undoStack().push(undo);
|
||||
}
|
||||
} else {
|
||||
ui->m_name_le->setEnabled(true);
|
||||
if (!m_part->terminalName().isEmpty()) {
|
||||
auto undo = new QPropertyUndoCommand(m_part, "terminal_name",
|
||||
m_part->terminalName(), QString());
|
||||
undo->setText(tr("Modifier le nom de la borne"));
|
||||
undoStack().push(undo);
|
||||
}
|
||||
ui->m_name_le->clear();
|
||||
}
|
||||
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
void TerminalEditor::masterLabelIndexEdited()
|
||||
{
|
||||
if (m_locked) return;
|
||||
m_locked = true;
|
||||
|
||||
int idx = ui->m_master_label_cb->currentData().toInt();
|
||||
|
||||
if (m_part->masterLabelIndex() != idx) {
|
||||
auto undo = new QPropertyUndoCommand(m_part, "master_label_index",
|
||||
m_part->masterLabelIndex(), idx);
|
||||
undo->setText(tr("Modifier l'index de l'étiquette du maître"));
|
||||
undoStack().push(undo);
|
||||
}
|
||||
|
||||
if (ui->m_use_master_label_cb->isChecked()) {
|
||||
QString t_label = tr("T%1").arg(idx + 1);
|
||||
ui->m_name_le->setText(t_label);
|
||||
if (m_part->terminalName() != t_label) {
|
||||
auto undo = new QPropertyUndoCommand(m_part, "terminal_name",
|
||||
m_part->terminalName(), t_label);
|
||||
undo->setText(tr("Modifier le nom de la borne"));
|
||||
undoStack().push(undo);
|
||||
}
|
||||
}
|
||||
|
||||
m_locked = false;
|
||||
}
|
||||
|
||||
bool TerminalEditor::updateMasterLabelVisibility()
|
||||
{
|
||||
QETElementEditor *editor = elementEditor();
|
||||
if (!editor || !editor->elementScene()) {
|
||||
ui->m_master_label_gb->setVisible(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
ElementData data = editor->elementScene()->elementData();
|
||||
bool is_slave = (data.m_type == ElementData::Slave);
|
||||
ui->m_master_label_gb->setVisible(is_slave);
|
||||
return is_slave;
|
||||
}
|
||||
|
||||
void TerminalEditor::refreshMasterLabelVisibility()
|
||||
{
|
||||
updateMasterLabelVisibility();
|
||||
if (m_part) {
|
||||
updateForm();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
#include <QWidget>
|
||||
#include "../elementitemeditor.h"
|
||||
|
||||
#ifdef BUILD_WITHOUT_KF5
|
||||
#include <QPushButton>
|
||||
#else
|
||||
#include <KColorButton>
|
||||
#endif
|
||||
|
||||
namespace Ui {
|
||||
class TerminalEditor;
|
||||
}
|
||||
@@ -43,6 +49,8 @@ class TerminalEditor : public ElementItemEditor
|
||||
bool setPart(CustomElementPart *new_part) override;
|
||||
CustomElementPart *currentPart() const override;
|
||||
QList<CustomElementPart *> currentParts() const override {return QList<CustomElementPart *>();}
|
||||
public slots:
|
||||
void refreshMasterLabelVisibility();
|
||||
|
||||
private:
|
||||
void init();
|
||||
@@ -50,8 +58,19 @@ class TerminalEditor : public ElementItemEditor
|
||||
void orientationEdited();
|
||||
void nameEdited();
|
||||
void typeEdited();
|
||||
void activeConnections(bool active);
|
||||
void activeChangeConnections(bool active);
|
||||
void showNameEdited();
|
||||
void labelPosEdited();
|
||||
void labelFontClicked();
|
||||
void labelSizeEdited();
|
||||
void labelRotationEdited();
|
||||
void labelAlignClicked();
|
||||
void labelFrameEdited();
|
||||
void labelColorClicked();
|
||||
void activeConnections(bool active);
|
||||
void activeChangeConnections(bool active);
|
||||
void useMasterLabelEdited();
|
||||
void masterLabelIndexEdited();
|
||||
bool updateMasterLabelVisibility();
|
||||
|
||||
private:
|
||||
Ui::TerminalEditor *ui;
|
||||
@@ -59,6 +78,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
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>511</width>
|
||||
<height>236</height>
|
||||
<height>500</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -78,18 +78,167 @@
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="m_type_cb"/>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="m_label_gb">
|
||||
<property name="title">
|
||||
<string>Nom de la borne</string>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_show_name_cb">
|
||||
<property name="text">
|
||||
<string>Afficher le nom</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="m_text_props_gb">
|
||||
<property name="title">
|
||||
<string>Propriétés du texte</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="m_font_pb">
|
||||
<property name="text">
|
||||
<string>Police</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="m_label_size_sb">
|
||||
<property name="minimum">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>X :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_label_x_dsb">
|
||||
<property name="minimum">
|
||||
<double>-5000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Y :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_label_y_dsb">
|
||||
<property name="minimum">
|
||||
<double>-5000.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5000.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Rotation :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="m_label_rotation_sb">
|
||||
<property name="wrapping">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>°</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>359.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="m_align_pb">
|
||||
<property name="text">
|
||||
<string>Alignement</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Couleur :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QWidget" name="m_color_widget" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="m_label_frame_cb">
|
||||
<property name="text">
|
||||
<string>Encadrer le texte</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="m_master_label_gb">
|
||||
<property name="title">
|
||||
<string>Étiquette du maître</string>
|
||||
</property>
|
||||
</spacer>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="m_use_master_label_cb">
|
||||
<property name="text">
|
||||
<string>Reprendre du maître</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="m_master_label_cb">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "texteditor.h"
|
||||
|
||||
#include "../../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include "../../ui/alignmenttextdialog.h"
|
||||
#include "../graphicspart/parttext.h"
|
||||
|
||||
#include <cassert>
|
||||
@@ -84,7 +85,7 @@ void TextEditor::setUpChangeConnection(QPointer<PartText> part)
|
||||
|
||||
void TextEditor::disconnectChangeConnection()
|
||||
{
|
||||
for (const auto &connection : qAsConst(m_change_connection)) {
|
||||
for (const auto &connection : std::as_const(m_change_connection)) {
|
||||
disconnect(connection);
|
||||
}
|
||||
m_change_connection.clear();
|
||||
@@ -371,8 +372,34 @@ void TextEditor::setUpWidget(QWidget *parent)
|
||||
|
||||
gridLayout->addWidget(m_font_pb, 2, 2, 1, 2);
|
||||
|
||||
QPushButton *alignment_pb = new QPushButton(tr("Alignement"), parent);
|
||||
alignment_pb->setToolTip(tr("Point d'ancrage du texte et alignement"
|
||||
" des lignes entre elles"));
|
||||
connect(alignment_pb, &QPushButton::clicked, [this]() {
|
||||
if (m_text.isNull()) {
|
||||
return;
|
||||
}
|
||||
AlignmentTextDialog atd(m_text->alignment(), this);
|
||||
if (atd.exec() != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < m_parts.length(); i++) {
|
||||
PartText *part_text = m_parts[i];
|
||||
if (atd.alignment() != part_text->alignment()) {
|
||||
QPropertyUndoCommand *undo = new QPropertyUndoCommand(
|
||||
part_text, "alignment",
|
||||
QVariant(part_text->alignment()),
|
||||
QVariant(atd.alignment()));
|
||||
undo->setText(tr("Modifier l'alignement d'un champ texte"));
|
||||
undoStack().push(undo);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
gridLayout->addWidget(alignment_pb, 3, 0, 1, 2);
|
||||
|
||||
QSpacerItem *verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
|
||||
gridLayout->addItem(verticalSpacer, 3, 2, 1, 1);
|
||||
gridLayout->addItem(verticalSpacer, 4, 2, 1, 1);
|
||||
setLayout(gridLayout);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user