mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-17 19:34:13 +02:00
Improve terminal_strip
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#include "terminalstripdrawer.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPolygonF>
|
||||
#include <QFontMetricsF>
|
||||
#include <QHash>
|
||||
|
||||
@@ -405,6 +406,105 @@ void drawCables(QPainter *painter, const QVector<CableCell> &cells, const Termin
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Width and color of a terminal.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The width of the terminals of the layout is the width of a terminal
|
||||
* of 5.2 mm (the usual width of the terminals of 2.5 mm2).
|
||||
* The width set by the user, in mm, is converted according to this reference.
|
||||
*/
|
||||
constexpr qreal reference_terminal_width_mm{5.2};
|
||||
|
||||
/**
|
||||
* @brief terminalRect
|
||||
* @param pattern
|
||||
* @param index : level of the terminal (0 to 3)
|
||||
* @param real_t : can be null
|
||||
* @return The rectangle of the terminal : the one of the layout,
|
||||
* with the width adapted to the width (in mm) of @a real_t if it is set.
|
||||
*/
|
||||
QRectF terminalRect(const TerminalStripLayoutPattern &pattern,
|
||||
int index,
|
||||
const QSharedPointer<AbstractRealTerminalInterface> &real_t)
|
||||
{
|
||||
auto rect_{pattern.m_terminal_rect[index]};
|
||||
if (real_t && real_t->widthMm() > 0) {
|
||||
rect_.setWidth(rect_.width() * real_t->widthMm() / reference_terminal_width_mm);
|
||||
}
|
||||
return rect_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The TerminalColors struct
|
||||
* Colors used to fill the rectangle of a terminal.
|
||||
* An invalid fill color means that the rectangle is not filled.
|
||||
* The stripe color (if valid) is drawn as stripes over the fill color.
|
||||
*/
|
||||
struct TerminalColors
|
||||
{
|
||||
QColor fill;
|
||||
QColor stripe;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief terminalColors
|
||||
* @param real_t : can be null
|
||||
* @return The colors of the terminal : the color set by the user,
|
||||
* else the default color of the type of the terminal.
|
||||
*/
|
||||
TerminalColors terminalColors(const QSharedPointer<AbstractRealTerminalInterface> &real_t)
|
||||
{
|
||||
if (!real_t) {
|
||||
return {};
|
||||
}
|
||||
if (real_t->color().isValid()) {
|
||||
return {real_t->color(), real_t->stripeColor()};
|
||||
}
|
||||
switch (real_t->type()) {
|
||||
case ElementData::TTGround: return {QColor(255, 216, 0), QColor(46, 158, 46)}; //Green/Yellow
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief drawStripes
|
||||
* Draw diagonal stripes of @a color inside @a rect.
|
||||
*/
|
||||
void drawStripes(QPainter *painter, const QRectF &rect, const QColor &color)
|
||||
{
|
||||
painter->save();
|
||||
painter->setClipRect(rect);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(color);
|
||||
|
||||
const auto band_{std::max<qreal>(2, rect.width() / 2)};
|
||||
for (auto x = rect.left() - rect.height() ; x < rect.right() ; x += 2 * band_)
|
||||
{
|
||||
QPolygonF polygon_;
|
||||
polygon_ << QPointF(x, rect.bottom())
|
||||
<< QPointF(x + band_, rect.bottom())
|
||||
<< QPointF(x + band_ + rect.height(), rect.top())
|
||||
<< QPointF(x + rect.height(), rect.top());
|
||||
painter->drawPolygon(polygon_);
|
||||
}
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The color (black or white) the more readable on @a background.
|
||||
* If @a background is invalid, return black.
|
||||
*/
|
||||
QColor contrastColor(const QColor &background)
|
||||
{
|
||||
if (!background.isValid()) {
|
||||
return Qt::black;
|
||||
}
|
||||
const auto luminance_{0.299 * background.redF() + 0.587 * background.greenF() + 0.114 * background.blueF()};
|
||||
return luminance_ < 0.5 ? QColor(Qt::white) : QColor(Qt::black);
|
||||
}
|
||||
|
||||
} //End anonymous namespace
|
||||
|
||||
/**
|
||||
@@ -509,7 +609,7 @@ void TerminalStripDrawer::paint(QPainter *painter)
|
||||
break;
|
||||
}
|
||||
|
||||
terminal_rect = m_pattern->m_terminal_rect[index_];
|
||||
terminal_rect = terminalRect(*m_pattern, index_, real_terminal_vector[i]);
|
||||
|
||||
//Cable (hose) of this terminal
|
||||
CableCell cable_cell;
|
||||
@@ -523,17 +623,36 @@ void TerminalStripDrawer::paint(QPainter *painter)
|
||||
}
|
||||
const bool have_cable{m_pattern->m_cable_wire_length > 0 && !cable_cell.cable.isEmpty()};
|
||||
cable_cells.append(cable_cell);
|
||||
//Draw terminal rect
|
||||
//Draw terminal rect, filled with the color of the terminal (if any)
|
||||
const auto colors_{terminalColors(real_terminal_vector[i])};
|
||||
const auto fill_color_{colors_.fill};
|
||||
const auto text_color_{contrastColor(fill_color_)};
|
||||
painter->save();
|
||||
if (fill_color_.isValid()) {
|
||||
painter->setBrush(QBrush(fill_color_));
|
||||
}
|
||||
painter->drawRect(terminal_rect);
|
||||
if (colors_.stripe.isValid())
|
||||
{
|
||||
drawStripes(painter, terminal_rect, colors_.stripe);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(terminal_rect); //Draw again the outline, hidden by stripes
|
||||
}
|
||||
painter->restore();
|
||||
|
||||
//Draw the symbol of the terminal type (fuse, ground, led...)
|
||||
if (m_pattern->m_type_symbol_height > 0 && real_terminal_vector[i])
|
||||
{
|
||||
painter->save();
|
||||
if (fill_color_.isValid()) {
|
||||
painter->setPen(text_color_);
|
||||
}
|
||||
drawTypeSymbol(painter,
|
||||
QRectF{0, m_pattern->m_type_symbol_y,
|
||||
terminal_rect.width(), m_pattern->m_type_symbol_height},
|
||||
real_terminal_vector[i]->type(),
|
||||
real_terminal_vector[i]->isLed());
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
//Draw the connections, above and under the terminal
|
||||
@@ -570,6 +689,9 @@ void TerminalStripDrawer::paint(QPainter *painter)
|
||||
|
||||
//Draw text
|
||||
painter->save();
|
||||
if (fill_color_.isValid()) {
|
||||
painter->setPen(text_color_);
|
||||
}
|
||||
text_rect.setRect(0, terminals_text_y, terminal_rect.width(), terminals_text_height);
|
||||
if (terminals_text_orientation == Qt::Vertical)
|
||||
{
|
||||
@@ -594,6 +716,9 @@ void TerminalStripDrawer::paint(QPainter *painter)
|
||||
//Draw xref
|
||||
xref_rect.setRect(0, xref_text_y, terminal_rect.width(), xref_text_height);
|
||||
painter->save();
|
||||
if (fill_color_.isValid()) {
|
||||
painter->setPen(text_color_);
|
||||
}
|
||||
if (xref_text_orientation == Qt::Vertical)
|
||||
{
|
||||
painter->translate(xref_rect.bottomLeft());
|
||||
@@ -848,7 +973,7 @@ qreal TerminalStripDrawer::width() const
|
||||
break;
|
||||
}
|
||||
|
||||
width_ += m_pattern->m_terminal_rect[index_].width();
|
||||
width_ += terminalRect(*m_pattern, index_, real_terminal_vector[i]).width();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef TERMINALSTRIPDRAWER_H
|
||||
#define TERMINALSTRIPDRAWER_H
|
||||
|
||||
#include <QColor>
|
||||
#include <QPointer>
|
||||
#include <QUuid>
|
||||
|
||||
@@ -77,6 +78,13 @@ namespace TerminalStripDrawer
|
||||
virtual QString cable() const { return QString(); }
|
||||
virtual QString cableWire() const { return QString(); }
|
||||
virtual bool isShield() const { return false; }
|
||||
//Color and width (mm) of the terminal, only used to draw the terminal.
|
||||
//An invalid color means "no override" : the default color of the type is used.
|
||||
//A width <= 0 means "unknown" : the default width of the layout is used.
|
||||
virtual QColor color() const { return QColor(); }
|
||||
//Second color of a two-tone color (like green/yellow), drawn as stripes over color()
|
||||
virtual QColor stripeColor() const { return QColor(); }
|
||||
virtual qreal widthMm() const { return 0; }
|
||||
};
|
||||
|
||||
class AbstractPhysicalTerminalInterface
|
||||
|
||||
@@ -153,6 +153,21 @@ namespace TerminalStripDrawer
|
||||
return m_real ? m_real->isShield() : false;
|
||||
}
|
||||
|
||||
QColor TrueRealTerminal::color() const
|
||||
{
|
||||
return m_real ? m_real->color() : QColor();
|
||||
}
|
||||
|
||||
QColor TrueRealTerminal::stripeColor() const
|
||||
{
|
||||
return m_real ? m_real->stripeColor() : QColor();
|
||||
}
|
||||
|
||||
qreal TrueRealTerminal::widthMm() const
|
||||
{
|
||||
return m_real ? m_real->widthMm() : 0;
|
||||
}
|
||||
|
||||
TrueBridge::TrueBridge(QSharedPointer<TerminalStripBridge> bridge) :
|
||||
m_bridge { bridge }
|
||||
{}
|
||||
|
||||
@@ -64,6 +64,9 @@ namespace TerminalStripDrawer
|
||||
QString cable() const override;
|
||||
QString cableWire() const override;
|
||||
bool isShield() const override;
|
||||
QColor color() const override;
|
||||
QColor stripeColor() const override;
|
||||
qreal widthMm() const override;
|
||||
|
||||
private:
|
||||
QSharedPointer<RealTerminal> m_real;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "terminalstrip.h"
|
||||
#include "../qetgraphicsitem/terminalelement.h"
|
||||
#include "physicalterminal.h"
|
||||
#include "terminalcolor.h"
|
||||
#include "../qetgraphicsitem/conductor.h"
|
||||
|
||||
/**
|
||||
@@ -191,6 +192,78 @@ bool RealTerminal::isShield() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RealTerminal::color
|
||||
* @return The color set by the user for this terminal, drawn in the
|
||||
* terminal strip. An invalid color mean that the user did not set a color.
|
||||
* The value is stored in the informations of the element.
|
||||
* @sa stripeColor
|
||||
*/
|
||||
QColor RealTerminal::color() const
|
||||
{
|
||||
QColor main_, stripe_;
|
||||
if (m_element) {
|
||||
TerminalColor::parse(m_element->elementData().m_informations.value(colorInfoKey()).toString(),
|
||||
&main_, &stripe_);
|
||||
}
|
||||
return main_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RealTerminal::stripeColor
|
||||
* @return The second color of a two-tone color (green/yellow for example)
|
||||
* or an invalid color if the color of this terminal is plain or not set.
|
||||
*/
|
||||
QColor RealTerminal::stripeColor() const
|
||||
{
|
||||
QColor main_, stripe_;
|
||||
if (m_element) {
|
||||
TerminalColor::parse(m_element->elementData().m_informations.value(colorInfoKey()).toString(),
|
||||
&main_, &stripe_);
|
||||
}
|
||||
return stripe_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RealTerminal::section
|
||||
* @return The section in mm2 set by the user for this terminal
|
||||
* or 0 if no section was set.
|
||||
* The value is stored in the informations of the element,
|
||||
* with the dot as decimal separator, whatever the locale.
|
||||
*/
|
||||
qreal RealTerminal::section() const
|
||||
{
|
||||
if (m_element)
|
||||
{
|
||||
bool ok_ = false;
|
||||
const auto section_ = m_element->elementData().m_informations.value(sectionInfoKey()).toString().toDouble(&ok_);
|
||||
if (ok_ && section_ > 0) {
|
||||
return section_;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RealTerminal::widthMm
|
||||
* @return The width in mm of this terminal (the width of the terminal
|
||||
* sold by the manufacturer), set by the user, or 0 if no width was set.
|
||||
* The value is stored in the informations of the element,
|
||||
* with the dot as decimal separator, whatever the locale.
|
||||
*/
|
||||
qreal RealTerminal::widthMm() const
|
||||
{
|
||||
if (m_element)
|
||||
{
|
||||
bool ok_ = false;
|
||||
const auto width_ = m_element->elementData().m_informations.value(widthInfoKey()).toString().toDouble(&ok_);
|
||||
if (ok_ && width_ > 0) {
|
||||
return width_;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RealTerminal::conductor
|
||||
* @return
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define REALTERMINAL_H
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include <QColor>
|
||||
#include <QDomElement>
|
||||
#include "../properties/elementdata.h"
|
||||
|
||||
@@ -66,11 +67,20 @@ class RealTerminal
|
||||
QString cable() const;
|
||||
QString cableWire() const;
|
||||
bool isShield() const;
|
||||
QColor color() const;
|
||||
QColor stripeColor() const;
|
||||
qreal section() const;
|
||||
qreal widthMm() const;
|
||||
|
||||
//Keys used to store the cable data in the element informations
|
||||
static QString cableInfoKey() { return QStringLiteral("terminal_cable"); }
|
||||
static QString cableWireInfoKey() { return QStringLiteral("terminal_cable_wire"); }
|
||||
static QString shieldInfoKey() { return QStringLiteral("terminal_shield"); }
|
||||
//Keys used to store the color and the section (mm2) of the terminal
|
||||
static QString colorInfoKey() { return QStringLiteral("terminal_color"); }
|
||||
static QString sectionInfoKey() { return QStringLiteral("terminal_section"); }
|
||||
//Key used to store the width (mm) of the terminal, drawn in the terminal strip
|
||||
static QString widthInfoKey() { return QStringLiteral("terminal_width"); }
|
||||
|
||||
QString conductor() const;
|
||||
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
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 TERMINALCOLOR_H
|
||||
#define TERMINALCOLOR_H
|
||||
|
||||
#include <QColor>
|
||||
#include <QCoreApplication>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QPolygonF>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
/**
|
||||
* Colors of the terminals of a terminal strip.
|
||||
*
|
||||
* A color is stored as a string : "#rrggbb" for a plain color
|
||||
* or "#rrggbb/#rrggbb" for a two-tone color (the second color is drawn
|
||||
* as stripes over the first one, like the green/yellow of the earth).
|
||||
* An empty string means "no color set".
|
||||
*/
|
||||
namespace TerminalColor
|
||||
{
|
||||
struct Entry
|
||||
{
|
||||
const char *english; //Source text of the translation
|
||||
const char *french; //Also accepted when typed or pasted
|
||||
const char *main;
|
||||
const char *stripe; //nullptr if the color is plain
|
||||
};
|
||||
|
||||
inline const QVector<Entry> &palette()
|
||||
{
|
||||
static const QVector<Entry> palette_ {
|
||||
{"Gray", "gris", "#9e9e9e", nullptr},
|
||||
{"Blue", "bleu", "#4a90d9", nullptr},
|
||||
{"Green/Yellow", "vert/jaune", "#ffd800", "#2e9e2e"},
|
||||
{"Brown", "marron", "#8b5a2b", nullptr},
|
||||
{"Black", "noir", "#303030", nullptr},
|
||||
{"Red", "rouge", "#d32f2f", nullptr},
|
||||
{"Orange", "orange", "#f57c00", nullptr},
|
||||
{"Yellow", "jaune", "#ffd800", nullptr},
|
||||
{"Green", "vert", "#2e9e2e", nullptr},
|
||||
{"Violet", "violet", "#7b3fa0", nullptr},
|
||||
{"White", "blanc", "#ffffff", nullptr}
|
||||
};
|
||||
return palette_;
|
||||
}
|
||||
|
||||
inline QString translatedName(const Entry &entry) {
|
||||
return QCoreApplication::translate("TerminalColor", entry.english);
|
||||
}
|
||||
|
||||
inline QString toSpec(const QColor &main, const QColor &stripe = QColor())
|
||||
{
|
||||
if (!main.isValid()) {
|
||||
return QString();
|
||||
}
|
||||
return stripe.isValid() ? main.name() + QLatin1Char('/') + stripe.name()
|
||||
: main.name();
|
||||
}
|
||||
|
||||
inline QString specOf(const Entry &entry) {
|
||||
return toSpec(QColor(QLatin1String(entry.main)),
|
||||
entry.stripe ? QColor(QLatin1String(entry.stripe)) : QColor());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief parse
|
||||
* Read a color from a text : a name of the palette (in english, in french
|
||||
* or translated), a color "#rrggbb" or "#rrggbb/#rrggbb".
|
||||
* An empty text is valid and gives invalid colors (no color).
|
||||
* @return true if the text was understood
|
||||
*/
|
||||
inline bool parse(const QString &text, QColor *main, QColor *stripe)
|
||||
{
|
||||
*main = QColor();
|
||||
*stripe = QColor();
|
||||
|
||||
const auto text_ = text.trimmed();
|
||||
if (text_.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto &entry : palette())
|
||||
{
|
||||
if (text_.compare(QLatin1String(entry.english), Qt::CaseInsensitive) == 0 ||
|
||||
text_.compare(QLatin1String(entry.french), Qt::CaseInsensitive) == 0 ||
|
||||
text_.compare(translatedName(entry), Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
*main = QColor(QLatin1String(entry.main));
|
||||
if (entry.stripe) {
|
||||
*stripe = QColor(QLatin1String(entry.stripe));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const auto parts_ = text_.split(QLatin1Char('/'));
|
||||
if (parts_.size() == 2)
|
||||
{
|
||||
const QColor c1(parts_.at(0).trimmed());
|
||||
const QColor c2(parts_.at(1).trimmed());
|
||||
if (c1.isValid() && c2.isValid()) {
|
||||
*main = c1;
|
||||
*stripe = c2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const QColor color_(text_);
|
||||
if (color_.isValid()) {
|
||||
*main = color_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name to display for a color : the translated name
|
||||
* if the color is in the palette, else the color as text.
|
||||
*/
|
||||
inline QString displayName(const QColor &main, const QColor &stripe)
|
||||
{
|
||||
const auto spec_ = toSpec(main, stripe);
|
||||
if (spec_.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
for (const auto &entry : palette()) {
|
||||
if (specOf(entry) == spec_) {
|
||||
return translatedName(entry);
|
||||
}
|
||||
}
|
||||
return spec_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A little pixmap of the color (the stripe color
|
||||
* fills the upper right half for a two-tone color)
|
||||
*/
|
||||
inline QPixmap swatch(const QColor &main, const QColor &stripe, int size = 16)
|
||||
{
|
||||
QPixmap pixmap_(size, size);
|
||||
pixmap_.fill(Qt::transparent);
|
||||
if (!main.isValid()) {
|
||||
return pixmap_;
|
||||
}
|
||||
|
||||
QPainter painter_(&pixmap_);
|
||||
painter_.setRenderHint(QPainter::Antialiasing);
|
||||
painter_.setPen(Qt::NoPen);
|
||||
painter_.setBrush(main);
|
||||
painter_.drawRect(0, 0, size, size);
|
||||
if (stripe.isValid())
|
||||
{
|
||||
painter_.setBrush(stripe);
|
||||
QPolygonF polygon_;
|
||||
polygon_ << QPointF(0, 0) << QPointF(size, 0) << QPointF(size, size);
|
||||
painter_.drawPolygon(polygon_);
|
||||
}
|
||||
painter_.setPen(QPen(Qt::gray, 1));
|
||||
painter_.setBrush(Qt::NoBrush);
|
||||
painter_.drawRect(0, 0, size - 1, size - 1);
|
||||
return pixmap_;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TERMINALCOLOR_H
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef MODELTERMINALDATA_H
|
||||
#define MODELTERMINALDATA_H
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
#include "../../qetgraphicsitem/element.h"
|
||||
#include "../realterminal.h"
|
||||
@@ -37,6 +38,10 @@ struct modelRealTerminalData
|
||||
mrtd.conductor_ = real_t->conductor();
|
||||
mrtd.led_ = real_t->isLed();
|
||||
mrtd.shield_ = real_t->isShield();
|
||||
mrtd.color_ = real_t->color();
|
||||
mrtd.stripe_color_ = real_t->stripeColor();
|
||||
mrtd.section_ = real_t->section();
|
||||
mrtd.width_mm_ = real_t->widthMm();
|
||||
mrtd.type_ = real_t->type();
|
||||
mrtd.function_ = real_t->function();
|
||||
mrtd.element_ = real_t->element();
|
||||
@@ -55,6 +60,10 @@ struct modelRealTerminalData
|
||||
QString conductor_;
|
||||
bool led_ = false;
|
||||
bool shield_ = false;
|
||||
QColor color_; //Invalid = no color set by the user
|
||||
QColor stripe_color_; //Second color of a two-tone color, invalid if plain
|
||||
qreal section_ = 0; //In mm2, 0 = no section set by the user
|
||||
qreal width_mm_ = 0; //In mm, 0 = no width set by the user
|
||||
bool bridged_ = false;
|
||||
|
||||
ElementData::TerminalType type_ = ElementData::TerminalType::TTGeneric;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "../UndoCommand/changeterminalstripcolor.h"
|
||||
#include "../physicalterminal.h"
|
||||
#include "../terminalstripbridge.h"
|
||||
#include "../terminalcolor.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
@@ -217,6 +218,10 @@ void TerminalStripEditor::apply()
|
||||
set_info(RealTerminal::cableInfoKey(), data_.cable_);
|
||||
set_info(RealTerminal::cableWireInfoKey(), data_.cable_wire);
|
||||
set_info(RealTerminal::shieldInfoKey(), data_.shield_ ? QStringLiteral("true") : QString());
|
||||
//The color and the section are stored with the dot as decimal separator, whatever the locale
|
||||
set_info(RealTerminal::colorInfoKey(), TerminalColor::toSpec(data_.color_, data_.stripe_color_));
|
||||
set_info(RealTerminal::sectionInfoKey(), data_.section_ > 0 ? QString::number(data_.section_, 'g', 6) : QString());
|
||||
set_info(RealTerminal::widthInfoKey(), data_.width_mm_ > 0 ? QString::number(data_.width_mm_, 'g', 6) : QString());
|
||||
|
||||
if (element->elementData() != current_data)
|
||||
m_project->undoStack()->push(new ChangeElementDataCommand(element, current_data));
|
||||
@@ -639,14 +644,17 @@ void TerminalStripEditor::on_m_led_cb_activated(int index)
|
||||
namespace {
|
||||
/**
|
||||
* @return true if the cell at @a index contain a free text
|
||||
* (label, cable or wire of the cable), so a text can be pasted in it.
|
||||
* (label, cable, wire of the cable, color, section or width), so a text can be pasted in it.
|
||||
*/
|
||||
bool cellAcceptText(const QModelIndex &index)
|
||||
{
|
||||
const auto column_ = TerminalStripModel::columnTypeForIndex(index);
|
||||
return column_ == TerminalStripModel::Label
|
||||
|| column_ == TerminalStripModel::Cable
|
||||
|| column_ == TerminalStripModel::CableWire;
|
||||
|| column_ == TerminalStripModel::CableWire
|
||||
|| column_ == TerminalStripModel::Color
|
||||
|| column_ == TerminalStripModel::Section
|
||||
|| column_ == TerminalStripModel::Width;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,7 +738,7 @@ void TerminalStripEditor::copySelectionToClipboard()
|
||||
* the value is set to every selected cell.
|
||||
* - Otherwise the text is read like a table (tabulation between the columns
|
||||
* and new line between the rows) and written from the top left selected cell.
|
||||
* Only the label, cable and cable wire cells are modified.
|
||||
* Only the label, cable, cable wire, color, section and width cells are modified.
|
||||
*/
|
||||
void TerminalStripEditor::pasteFromClipboard()
|
||||
{
|
||||
|
||||
@@ -20,8 +20,12 @@
|
||||
#include "../../qetgraphicsitem/element.h"
|
||||
#include "../physicalterminal.h"
|
||||
#include "../realterminal.h"
|
||||
#include "../terminalcolor.h"
|
||||
#include "../terminalstripbridge.h"
|
||||
#include <QColor>
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QLocale>
|
||||
#include <QBrush>
|
||||
#include <QVector>
|
||||
#include <QComboBox>
|
||||
@@ -47,10 +51,37 @@ const int TYPE_CELL = 11;
|
||||
const int FUNCTION_CELL = 12;
|
||||
const int LED_CELL = 13;
|
||||
const int SHIELD_CELL = 14;
|
||||
const int COLOR_CELL = 15;
|
||||
const int SECTION_CELL = 16;
|
||||
const int WIDTH_CELL = 17;
|
||||
|
||||
const int COLUMN_COUNT = 15;
|
||||
const int COLUMN_COUNT = 18;
|
||||
|
||||
static QVector<bool> UNMODIFIED_CELL_VECTOR{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false};
|
||||
static QVector<bool> UNMODIFIED_CELL_VECTOR(COLUMN_COUNT, false);
|
||||
|
||||
/**
|
||||
* @brief parsePositiveNumber
|
||||
* Convert the text written by the user to a number >= 0
|
||||
* (a section in mm2 or a width in mm).
|
||||
* The comma and the dot are both accepted as decimal separator.
|
||||
* @param text
|
||||
* @param ok : true if the text is valid (empty text is valid and mean 0)
|
||||
* @return
|
||||
*/
|
||||
static qreal parsePositiveNumber(const QString &text, bool *ok)
|
||||
{
|
||||
auto text_ = text.trimmed();
|
||||
text_.replace(QLatin1Char(','), QLatin1Char('.'));
|
||||
if (text_.isEmpty()) {
|
||||
*ok = true;
|
||||
return 0;
|
||||
}
|
||||
const auto value_ = text_.toDouble(ok);
|
||||
if (*ok && value_ < 0) {
|
||||
*ok = false;
|
||||
}
|
||||
return *ok ? value_ : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalStripModel::levelForColumn
|
||||
@@ -95,6 +126,9 @@ TerminalStripModel::Column TerminalStripModel::columnTypeForIndex(const QModelIn
|
||||
case 12 : return Function;
|
||||
case 13 : return Led;
|
||||
case 14 : return Shield;
|
||||
case 15 : return Color;
|
||||
case 16 : return Section;
|
||||
case 17 : return Width;
|
||||
default : return Invalid;
|
||||
}
|
||||
}
|
||||
@@ -172,6 +206,9 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
|
||||
case CABLE_WIRE_CELL : return mrtd.cable_wire;
|
||||
case TYPE_CELL : return ElementData::translatedTerminalType(mrtd.type_);
|
||||
case FUNCTION_CELL : return ElementData::translatedTerminalFunction(mrtd.function_);
|
||||
case COLOR_CELL : return TerminalColor::displayName(mrtd.color_, mrtd.stripe_color_);
|
||||
case SECTION_CELL : return mrtd.section_ > 0 ? QLocale().toString(mrtd.section_, 'g', 6) : QString();
|
||||
case WIDTH_CELL : return mrtd.width_mm_ > 0 ? QLocale().toString(mrtd.width_mm_, 'g', 6) : QString();
|
||||
default : return QVariant();
|
||||
}
|
||||
}
|
||||
@@ -181,6 +218,9 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
|
||||
case LABEL_CELL : return mrtd.label_;
|
||||
case CABLE_CELL : return mrtd.cable_;
|
||||
case CABLE_WIRE_CELL : return mrtd.cable_wire;
|
||||
case COLOR_CELL : return TerminalColor::toSpec(mrtd.color_, mrtd.stripe_color_);
|
||||
case SECTION_CELL : return mrtd.section_ > 0 ? QLocale().toString(mrtd.section_, 'g', 6) : QString();
|
||||
case WIDTH_CELL : return mrtd.width_mm_ > 0 ? QLocale().toString(mrtd.width_mm_, 'g', 6) : QString();
|
||||
default: return QVariant();
|
||||
|
||||
}
|
||||
@@ -203,6 +243,13 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
|
||||
return QBrush(Qt::yellow);
|
||||
}
|
||||
}
|
||||
else if (role == Qt::DecorationRole &&
|
||||
index.column() == COLOR_CELL)
|
||||
{
|
||||
if (mrtd.color_.isValid()) {
|
||||
return TerminalColor::swatch(mrtd.color_, mrtd.stripe_color_);
|
||||
}
|
||||
}
|
||||
else if (role == Qt::DecorationRole &&
|
||||
(index.column() == LEVEL_0_CELL ||
|
||||
index.column() == LEVEL_1_CELL ||
|
||||
@@ -279,6 +326,46 @@ bool TerminalStripModel::setData(const QModelIndex &index, const QVariant &value
|
||||
modified_ = true;
|
||||
modified_cell = SHIELD_CELL;
|
||||
}
|
||||
else if (column_ == COLOR_CELL &&
|
||||
role == Qt::EditRole)
|
||||
{
|
||||
//An empty text remove the color, an unknown text is ignored.
|
||||
//The text can be a name of the palette (gray, blue, green/yellow...),
|
||||
//or a color "#rrggbb" or "#rrggbb/#rrggbb"
|
||||
QColor color_, stripe_;
|
||||
if (TerminalColor::parse(value.toString(), &color_, &stripe_) &&
|
||||
(mrtd.color_ != color_ || mrtd.stripe_color_ != stripe_))
|
||||
{
|
||||
mrtd.color_ = color_;
|
||||
mrtd.stripe_color_ = stripe_;
|
||||
modified_ = true;
|
||||
modified_cell = COLOR_CELL;
|
||||
}
|
||||
}
|
||||
else if (column_ == SECTION_CELL &&
|
||||
role == Qt::EditRole)
|
||||
{
|
||||
bool ok_ = false;
|
||||
const auto section_ = parsePositiveNumber(value.toString(), &ok_);
|
||||
if (ok_ && !qFuzzyCompare(1 + mrtd.section_, 1 + section_))
|
||||
{
|
||||
mrtd.section_ = section_;
|
||||
modified_ = true;
|
||||
modified_cell = SECTION_CELL;
|
||||
}
|
||||
}
|
||||
else if (column_ == WIDTH_CELL &&
|
||||
role == Qt::EditRole)
|
||||
{
|
||||
bool ok_ = false;
|
||||
const auto width_ = parsePositiveNumber(value.toString(), &ok_);
|
||||
if (ok_ && !qFuzzyCompare(1 + mrtd.width_mm_, 1 + width_))
|
||||
{
|
||||
mrtd.width_mm_ = width_;
|
||||
modified_ = true;
|
||||
modified_cell = WIDTH_CELL;
|
||||
}
|
||||
}
|
||||
|
||||
//Set the modification to the terminal data
|
||||
if (modified_)
|
||||
@@ -326,6 +413,9 @@ QVariant TerminalStripModel::headerData(int section, Qt::Orientation orientation
|
||||
case FUNCTION_CELL : return tr("Function");
|
||||
case LED_CELL: return tr("led");
|
||||
case SHIELD_CELL: return tr("Shield");
|
||||
case COLOR_CELL: return tr("Color");
|
||||
case SECTION_CELL: return tr("Section (mm²)");
|
||||
case WIDTH_CELL: return tr("Width (mm)");
|
||||
default : return QVariant();
|
||||
}
|
||||
}
|
||||
@@ -340,7 +430,8 @@ Qt::ItemFlags TerminalStripModel::flags(const QModelIndex &index) const
|
||||
|
||||
auto c = index.column();
|
||||
if (c == LABEL_CELL || c == TYPE_CELL || c == FUNCTION_CELL
|
||||
|| c == CABLE_CELL || c == CABLE_WIRE_CELL)
|
||||
|| c == CABLE_CELL || c == CABLE_WIRE_CELL
|
||||
|| c == COLOR_CELL || c == SECTION_CELL || c == WIDTH_CELL)
|
||||
flags = flags | Qt::ItemIsEditable;
|
||||
if (c == LED_CELL || c == SHIELD_CELL) {
|
||||
flags = flags | Qt::ItemIsUserCheckable;
|
||||
@@ -819,6 +910,40 @@ QPixmap TerminalStripModel::bridgePixmapFor(const QModelIndex &index) const
|
||||
* and a spinbox to edit the level of a terminal
|
||||
**********************************************************/
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Widths (mm) of terminals sold by the manufacturers.
|
||||
* Only the values found in the catalogs of the manufacturers are listed,
|
||||
* any other width can be typed in the cell.
|
||||
* For ABB Entrelec the value is the spacing (pitch) given by the catalog.
|
||||
*/
|
||||
struct WidthEntry { double mm; const char *label; };
|
||||
const WidthEntry WIDTH_ENTRIES[] {
|
||||
{5.1, "Weidmüller WDU 2.5"},
|
||||
{5.2, "WAGO 2002 (TOPJOB S)"},
|
||||
{6.0, "ABB Entrelec M 4/6"},
|
||||
{6.1, "Weidmüller WDU 4"},
|
||||
{6.2, "Phoenix Contact UT 4"},
|
||||
{8.0, "ABB Entrelec M 6/8, M 4/8"},
|
||||
{8.2, "Phoenix Contact UT 6"},
|
||||
{10.0, "ABB Entrelec M 10/10"},
|
||||
{10.2, "Phoenix Contact UT 10"},
|
||||
{11.9, "Weidmüller WDU 16/ZA"},
|
||||
{12.2, "Phoenix Contact UT 16"},
|
||||
{16.0, "Phoenix Contact UT 35, Weidmüller WDU 35N"},
|
||||
{26.0, "ABB Entrelec M 35/26.FF"},
|
||||
{31.0, "ABB Entrelec M 70/31.AF"},
|
||||
{35.0, "ABB Entrelec M 120/35.F"},
|
||||
{42.0, "ABB Entrelec M 300/42.FF"}
|
||||
};
|
||||
|
||||
QString widthItemText(double mm, const QString &label = QString())
|
||||
{
|
||||
const auto text_ = QCoreApplication::translate("TerminalStripModelDelegate", "%1 mm").arg(QLocale().toString(mm, 'g', 6));
|
||||
return label.isEmpty() ? text_ : text_ + QStringLiteral(" - ") + label;
|
||||
}
|
||||
}
|
||||
|
||||
TerminalStripModelDelegate::TerminalStripModelDelegate(QObject *parent) :
|
||||
QStyledItemDelegate(parent)
|
||||
{}
|
||||
@@ -850,10 +975,125 @@ QWidget *TerminalStripModelDelegate::createEditor(QWidget *parent, const QStyleO
|
||||
|
||||
return qcb;
|
||||
}
|
||||
if (index.column() == SECTION_CELL) {
|
||||
auto qcb = new QComboBox(parent);
|
||||
qcb->setObjectName(QStringLiteral("terminal_section"));
|
||||
qcb->addItem(tr("None (default)"), 0.0);
|
||||
//Usual sections, in mm2
|
||||
static const QVector<double> sections_ {0.5, 0.75, 1, 1.5, 2.5, 4, 6, 10, 16, 25, 35, 50, 70, 95, 120, 150, 185, 240};
|
||||
for (const auto section_ : sections_) {
|
||||
qcb->addItem(tr("%1 mm²").arg(QLocale().toString(section_, 'g', 6)), section_);
|
||||
}
|
||||
|
||||
return qcb;
|
||||
}
|
||||
if (index.column() == WIDTH_CELL) {
|
||||
auto qcb = new QComboBox(parent);
|
||||
qcb->setObjectName(QStringLiteral("terminal_width"));
|
||||
qcb->addItem(tr("None (default)"), 0.0);
|
||||
for (const auto &entry : WIDTH_ENTRIES) {
|
||||
qcb->addItem(widthItemText(entry.mm, QString::fromUtf8(entry.label)), entry.mm);
|
||||
}
|
||||
|
||||
return qcb;
|
||||
}
|
||||
if (index.column() == COLOR_CELL) {
|
||||
auto qcb = new QComboBox(parent);
|
||||
qcb->setObjectName(QStringLiteral("terminal_color"));
|
||||
qcb->addItem(tr("None (default)"), QString());
|
||||
for (const auto &entry : TerminalColor::palette())
|
||||
{
|
||||
const auto spec_ = TerminalColor::specOf(entry);
|
||||
QColor main_, stripe_;
|
||||
TerminalColor::parse(spec_, &main_, &stripe_);
|
||||
qcb->addItem(QIcon(TerminalColor::swatch(main_, stripe_)),
|
||||
TerminalColor::translatedName(entry),
|
||||
spec_);
|
||||
}
|
||||
|
||||
return qcb;
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::createEditor(parent, option, index);
|
||||
}
|
||||
|
||||
void TerminalStripModelDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
if (index.isValid() &&
|
||||
editor->objectName() == QLatin1String("terminal_color"))
|
||||
{
|
||||
if (auto qcb = dynamic_cast<QComboBox *>(editor))
|
||||
{
|
||||
const auto spec_ = index.data(Qt::EditRole).toString();
|
||||
auto pos_ = qcb->findData(spec_);
|
||||
if (pos_ < 0)
|
||||
{
|
||||
//The color is not in the palette (typed or pasted), keep it in the list
|
||||
QColor main_, stripe_;
|
||||
TerminalColor::parse(spec_, &main_, &stripe_);
|
||||
qcb->addItem(QIcon(TerminalColor::swatch(main_, stripe_)), spec_, spec_);
|
||||
pos_ = qcb->count() - 1;
|
||||
}
|
||||
qcb->setCurrentIndex(pos_);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (index.isValid() &&
|
||||
editor->objectName() == QLatin1String("terminal_section"))
|
||||
{
|
||||
if (auto qcb = dynamic_cast<QComboBox *>(editor))
|
||||
{
|
||||
bool ok_ = false;
|
||||
const auto section_ = parsePositiveNumber(index.data(Qt::EditRole).toString(), &ok_);
|
||||
auto pos_ = -1;
|
||||
for (auto i = 0 ; i < qcb->count() ; ++i)
|
||||
{
|
||||
if (qFuzzyCompare(1 + qcb->itemData(i).toDouble(), 1 + section_)) {
|
||||
pos_ = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos_ < 0)
|
||||
{
|
||||
//The section is not in the list (typed or pasted), keep it in the list
|
||||
qcb->addItem(tr("%1 mm²").arg(QLocale().toString(section_, 'g', 6)), section_);
|
||||
pos_ = qcb->count() - 1;
|
||||
}
|
||||
qcb->setCurrentIndex(pos_);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (index.isValid() &&
|
||||
editor->objectName() == QLatin1String("terminal_width"))
|
||||
{
|
||||
if (auto qcb = dynamic_cast<QComboBox *>(editor))
|
||||
{
|
||||
bool ok_ = false;
|
||||
const auto width_ = parsePositiveNumber(index.data(Qt::EditRole).toString(), &ok_);
|
||||
auto pos_ = -1;
|
||||
for (auto i = 0 ; i < qcb->count() ; ++i)
|
||||
{
|
||||
if (qFuzzyCompare(1 + qcb->itemData(i).toDouble(), 1 + width_)) {
|
||||
pos_ = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos_ < 0)
|
||||
{
|
||||
//The width is not in the list (typed or pasted), keep it in the list
|
||||
qcb->addItem(widthItemText(width_), width_);
|
||||
pos_ = qcb->count() - 1;
|
||||
}
|
||||
qcb->setCurrentIndex(pos_);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
|
||||
void TerminalStripModelDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
|
||||
{
|
||||
if (index.isValid())
|
||||
@@ -870,6 +1110,24 @@ void TerminalStripModelDelegate::setModelData(QWidget *editor, QAbstractItemMode
|
||||
model->setData(index, qcb->currentData(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
else if (editor->objectName() == QLatin1String("terminal_section"))
|
||||
{
|
||||
if (auto qcb = dynamic_cast<QComboBox *>(editor)) {
|
||||
model->setData(index, qcb->currentData().toDouble(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
else if (editor->objectName() == QLatin1String("terminal_width"))
|
||||
{
|
||||
if (auto qcb = dynamic_cast<QComboBox *>(editor)) {
|
||||
model->setData(index, qcb->currentData().toDouble(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
else if (editor->objectName() == QLatin1String("terminal_color"))
|
||||
{
|
||||
if (auto qcb = dynamic_cast<QComboBox *>(editor)) {
|
||||
model->setData(index, qcb->currentData(), Qt::EditRole);
|
||||
}
|
||||
}
|
||||
else {
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
|
||||
@@ -62,6 +62,9 @@ class TerminalStripModel : public QAbstractTableModel
|
||||
Function = 12,
|
||||
Led = 13,
|
||||
Shield = 14,
|
||||
Color = 15,
|
||||
Section = 16,
|
||||
Width = 17,
|
||||
Invalid = 99
|
||||
};
|
||||
|
||||
@@ -124,6 +127,9 @@ class TerminalStripModelDelegate : public QStyledItemDelegate
|
||||
QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
void setEditorData(
|
||||
QWidget *editor,
|
||||
const QModelIndex &index) const override;
|
||||
void setModelData(
|
||||
QWidget *editor,
|
||||
QAbstractItemModel *model,
|
||||
|
||||
Reference in New Issue
Block a user