Draw bridge pixmap in the tableview (wip)

This commit is contained in:
joshua
2021-12-11 21:25:40 +01:00
parent 291e163ee2
commit beee4a06c8
6 changed files with 400 additions and 34 deletions

View File

@@ -618,6 +618,7 @@ bool TerminalStrip::setOrderTo(const QVector<PhysicalTerminalData> &sorted_vecto
}
m_physical_terminals = new_order;
rebuildRealVector();
emit orderChanged();
return true;
}
@@ -909,12 +910,94 @@ void TerminalStrip::unBridge(const QVector<QUuid> &real_terminals_uuid)
* @param real_terminal_uuid
* @return
*/
QSharedPointer<TerminalStripBridge> TerminalStrip::bridgeFor(const QUuid &real_terminal_uuid) const
const QSharedPointer<TerminalStripBridge> TerminalStrip::bridgeFor(const QUuid &real_terminal_uuid) const
{
auto rt = realTerminalForUuid(real_terminal_uuid);
return bridgeFor(QVector{rt});
}
/**
* @brief TerminalStrip::previousTerminalInLevel
* @param real_terminal_uuid
* @return The previous real terminal at the samne level
* as the real terminal with uuid @a real_terminal_uuid
* If there is not a previous terminal, return a null RealTerminalData
*/
RealTerminalData TerminalStrip::previousTerminalInLevel(const QUuid &real_terminal_uuid) const
{
auto real_t = realTerminalForUuid(real_terminal_uuid);
if (real_t)
{
auto phy_t = physicalTerminal(real_t);
if (phy_t)
{
auto level_ = phy_t->levelOf(real_t);
auto index = m_physical_terminals.indexOf(phy_t);
if (index >= 1)
{
auto t_vector = m_physical_terminals.at(index-1)->terminals();
if (t_vector.size() > level_)
{
return realTerminalData(t_vector.at(level_));
}
}
}
}
return RealTerminalData();
}
/**
* @brief TerminalStrip::nextTerminalInLevel
* @param real_terminal_uuid
* @return The next real terminal at the samne level
* as the real terminal with uuid @a real_terminal_uuid
* If there is not a next terminal, return a null RealTerminalData
*/
RealTerminalData TerminalStrip::nextTerminalInLevel(const QUuid &real_terminal_uuid) const
{
auto real_t = realTerminalForUuid(real_terminal_uuid);
if (real_t)
{
auto phy_t = physicalTerminal(real_t);
if (phy_t)
{
auto level_ = phy_t->levelOf(real_t);
auto index = m_physical_terminals.indexOf(phy_t);
if (index < m_physical_terminals.size()-1)
{
auto t_vector = m_physical_terminals.at(index+1)->terminals();
if (t_vector.size() > level_)
{
return realTerminalData(t_vector.at(level_));
}
}
}
}
return RealTerminalData();
}
RealTerminalData TerminalStrip::previousRealTerminal(const QUuid &real_terminal_uuid) const
{
auto real = realTerminalForUuid(real_terminal_uuid);
auto index = m_real_terminals.indexOf(real);
if (index) {
return realTerminalData(m_real_terminals.at(index-1));
}
return RealTerminalData();
}
RealTerminalData TerminalStrip::nextRealTerminal(const QUuid &real_terminal_uuid) const
{
auto real = realTerminalForUuid(real_terminal_uuid);
auto index = m_real_terminals.indexOf(real);
if (index != m_real_terminals.size()-1) {
return realTerminalData(m_real_terminals.at(index+1));
}
return RealTerminalData();
}
/**
* @brief TerminalStrip::terminalElement
* @return A vector of all terminal element owned by this strip
@@ -1058,6 +1141,14 @@ RealTerminalData TerminalStrip::realTerminalData(const QSharedPointer<RealTermin
rtd.led_ = real_terminal->led();
rtd.is_element = real_terminal->isElement();
rtd.is_bridged = isBridged(real_terminal);
if (rtd.is_bridged) {
for (auto bridge : m_bridge) {
if (bridge->real_terminals.contains(real_terminal)) {
rtd.bridge_uuid = bridge->uuid_;
break;
}
}
}
return rtd;
}
@@ -1166,3 +1257,17 @@ QSharedPointer<TerminalStripBridge> TerminalStrip::bridgeForUuid(const QUuid &br
return QSharedPointer<TerminalStripBridge>();
}
/**
* @brief TerminalStrip::rebuildRealVector
* Rebuild the real terminal vector
* to be ordered
*/
void TerminalStrip::rebuildRealVector()
{
m_real_terminals.clear();
for (const auto phy : m_physical_terminals) {
for (const auto &real : phy->terminals())
m_real_terminals.append(real);
}
}

View File

@@ -37,6 +37,8 @@ class TerminalElement;
* @brief The RealTerminalData struct
* Conveniant struct to quickly get some values
* of a RealTerminal
* A RealTerminalData with level_ = -1
* is considered as a null data
*/
struct RealTerminalData
{
@@ -86,7 +88,7 @@ inline uint qHash(const PhysicalTerminalData &key, uint seed) {
struct TerminalStripBridge
{
QVector<QSharedPointer<RealTerminal>> real_terminals;
QColor color_ = Qt::gray;
QColor color_ = Qt::darkGray;
QUuid uuid_ = QUuid::createUuid();
};
@@ -104,6 +106,8 @@ class TerminalStrip : public QObject
Q_OBJECT
public:
static QVector<QColor> bridgeColor() {return QVector<QColor>{Qt::red, Qt::blue, Qt::white, Qt::darkGray, Qt::black};}
signals:
void orderChanged(); //Emitted when the order of the physical terminal is changed
void bridgeChanged();
@@ -146,7 +150,12 @@ class TerminalStrip : public QObject
bool setBridge(const QVector<QUuid> &real_terminals_uuid);
bool setBridge(const QUuid &bridge_uuid, const QVector<QUuid> &real_terminals_uuid);
void unBridge(const QVector<QUuid> &real_terminals_uuid);
QSharedPointer<TerminalStripBridge> bridgeFor(const QUuid &real_terminal_uuid) const;
const QSharedPointer<TerminalStripBridge> bridgeFor(const QUuid &real_terminal_uuid) const;
RealTerminalData previousTerminalInLevel(const QUuid &real_terminal_uuid) const;
RealTerminalData nextTerminalInLevel(const QUuid &real_terminal_uuid) const;
RealTerminalData previousRealTerminal(const QUuid &real_terminal_uuid) const;
RealTerminalData nextRealTerminal(const QUuid &real_terminal_uuid) const;
QVector<QPointer<Element>> terminalElement() const;
@@ -163,6 +172,7 @@ class TerminalStrip : public QObject
QSharedPointer<TerminalStripBridge> isBridged(const QSharedPointer<RealTerminal> real_terminal) const;
QSharedPointer<TerminalStripBridge> bridgeFor (const QVector<QSharedPointer<RealTerminal>> &terminal_vector) const;
QSharedPointer<TerminalStripBridge> bridgeForUuid (const QUuid &bridge_uuid);
void rebuildRealVector();
private:
TerminalStripData m_data;

View File

@@ -60,8 +60,7 @@ TerminalStripEditor::TerminalStripEditor(QETProject *project, QWidget *parent) :
#endif
//Setup the bridge color
QList<QColor> bridge_color{Qt::red, Qt::blue, Qt::white, Qt::gray, Qt::black};
ui->m_bridge_color_cb->setColors(bridge_color);
ui->m_bridge_color_cb->setColors(TerminalStrip::bridgeColor().toList());
setUpUndoConnections();
@@ -329,7 +328,7 @@ void TerminalStripEditor::setCurrentStrip(TerminalStrip *strip_)
m_model = new TerminalStripModel(strip_, this);
ui->m_table_widget->setModel(m_model);
setUpBridgeCellWidth();
m_model->buildBridgePixmap(setUpBridgeCellWidth());
spanMultiLevelTerminals();
selectionChanged(); //Used to update child widgets
@@ -461,7 +460,7 @@ void TerminalStripEditor::selectionChanged()
ui->m_unbridge_terminals_pb->setEnabled(enable_unbridge);
}
void TerminalStripEditor::setUpBridgeCellWidth()
QSize TerminalStripEditor::setUpBridgeCellWidth()
{
if (ui->m_table_widget->verticalHeader() &&
m_model)
@@ -469,15 +468,15 @@ void TerminalStripEditor::setUpBridgeCellWidth()
auto section_size = ui->m_table_widget->verticalHeader()->defaultSectionSize();
auto h_header = ui->m_table_widget->horizontalHeader();
h_header->setSectionResizeMode(2, QHeaderView::Fixed);
h_header->resizeSection(2, section_size);
h_header->setSectionResizeMode(3, QHeaderView::Fixed);
h_header->resizeSection(3, section_size);
h_header->setSectionResizeMode(4, QHeaderView::Fixed);
h_header->resizeSection(4, section_size);
h_header->setSectionResizeMode(5, QHeaderView::Fixed);
h_header->resizeSection(5, section_size);
for (int i = TerminalStripModel::Level0 ; i<(TerminalStripModel::Level3+1) ; ++i) {
ui->m_table_widget->setColumnWidth(i, section_size);
h_header->setSectionResizeMode(i, QHeaderView::Fixed);
}
return QSize(section_size, section_size);
}
return QSize(0,0);
}
/**

View File

@@ -53,7 +53,7 @@ class TerminalStripEditor : public QDialog
void setCurrentStrip(TerminalStrip *strip_);
void spanMultiLevelTerminals();
void selectionChanged();
void setUpBridgeCellWidth();
QSize setUpBridgeCellWidth();
TerminalStripModel::Column isSingleColumnSelected() const;
private slots:

View File

@@ -24,6 +24,7 @@
#include <QComboBox>
#include <QSpinBox>
#include <QPainter>
#include <QApplication>
/**
* Some const int who describe what a column contain
@@ -143,18 +144,6 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
switch (index.column()) {
case POS_CELL : return physicalDataAtIndex(index.row()).pos_;
case LEVEL_CELL : return rtd.level_;
case LEVEL_0_CELL :
if (rtd.level_ == 0 && rtd.is_bridged) return "0";
break;
case LEVEL_1_CELL :
if (rtd.level_ == 1 && rtd.is_bridged) return "0";
break;
case LEVEL_2_CELL :
if (rtd.level_ == 2 && rtd.is_bridged) return "0";
break;
case LEVEL_3_CELL :
if (rtd.level_ == 3 && rtd.is_bridged) return "0";
break;
case LABEL_CELL : return rtd.label_;
case XREF_CELL : return rtd.Xref_;
case CABLE_CELL : return rtd.cable_;
@@ -186,6 +175,18 @@ QVariant TerminalStripModel::data(const QModelIndex &index, int role) const
return QBrush(Qt::yellow);
}
}
else if (role == Qt::DecorationRole &&
(index.column() == LEVEL_0_CELL ||
index.column() == LEVEL_1_CELL ||
index.column() == LEVEL_2_CELL ||
index.column() == LEVEL_3_CELL))
{
return bridgePixmapFor(index);
auto pixmap_ = bridgePixmapFor(index);
if (!pixmap_.isNull()) {
return pixmap_;
}
}
return QVariant();
}
@@ -403,6 +404,78 @@ RealTerminalData TerminalStripModel::realTerminalDataForIndex(const QModelIndex
}
}
/**
* @brief TerminalStripModel::buildBridgePixmap
* Build the pixmap of bridge.
* You should call this method when you know the
* size to use in the bridge cell of a QTableView.
* @param pixmap_size
*/
void TerminalStripModel::buildBridgePixmap(const QSize &pixmap_size)
{
m_bridges_pixmaps.clear();
for (auto color_ : TerminalStrip::bridgeColor())
{
QPen pen;
pen.setColor(color_);
pen.setWidth(1);
QBrush brush;
brush.setColor(color_);
brush.setStyle(Qt::SolidPattern);
QPixmap top_(pixmap_size);
top_.fill(Qt::lightGray);
QPainter top_p(&top_);
top_p.setPen(pen);
top_p.setBrush(brush);
QPixmap middle_(pixmap_size);
middle_.fill(Qt::lightGray);
QPainter middle_p(&middle_);
middle_p.setPen(pen);
middle_p.setBrush(brush);
QPixmap bottom_(pixmap_size);
bottom_.fill(Qt::lightGray);
QPainter bottom_p(&bottom_);
bottom_p.setPen(pen);
bottom_p.setBrush(brush);
QPixmap none_(pixmap_size);
none_.fill(Qt::lightGray);
QPainter none_p(&none_);
none_p.setPen(pen);
none_p.setBrush(brush);
auto w_ = pixmap_size.width();
auto h_ = pixmap_size.height();
//Draw circle
top_p.drawEllipse(QPoint(w_/2, h_/2), w_/4, h_/4);
middle_p.drawEllipse(QPoint(w_/2, h_/2), w_/4, h_/4);
bottom_p.drawEllipse(QPoint(w_/2, h_/2), w_/4, h_/4);
//Draw top line
middle_p.drawRect((w_/2)-(w_/8), 0, w_/4, h_/2);
bottom_p.drawRect((w_/2)-(w_/8), 0, w_/4, h_/2);
none_p.drawRect((w_/2)-(w_/8), 0, w_/4, h_/2);
//Draw bottom line
top_p.drawRect((w_/2)-(w_/8), h_/2, w_/4, h_/2);
middle_p.drawRect((w_/2)-(w_/8), h_/2, w_/4, h_/2);
none_p.drawRect((w_/2)-(w_/8), h_/2, w_/4, h_/2);
BridgePixmap bpxm;
bpxm.top_ = top_;
bpxm.middle_ = middle_;
bpxm.bottom_ = bottom_;
bpxm.none_ = none_;
m_bridges_pixmaps.insert(color_, bpxm);
}
}
void TerminalStripModel::fillPhysicalTerminalData()
{
//Get all physical terminal
@@ -537,6 +610,127 @@ RealTerminalData TerminalStripModel::realDataAtIndex(int index) const
return RealTerminalData();
}
QPixmap TerminalStripModel::bridgePixmapFor(const QModelIndex &index) const
{
if (!index.isValid() || m_terminal_strip.isNull()) {
return QPixmap();
}
auto level_column = levelForColumn(columnTypeForIndex(index));
if (level_column == -1) {
return QPixmap();
}
auto rtd = realTerminalDataForIndex(index);
//Terminal level correspond to the column level of index
if (level_column == rtd.level_)
{
if (rtd.is_bridged)
{
auto bridge_uuid = rtd.bridge_uuid;
auto previous_bridge_uuid = m_terminal_strip->previousTerminalInLevel(rtd.real_terminal_uuid).bridge_uuid;
auto next_bridge_uuid = m_terminal_strip->nextTerminalInLevel(rtd.real_terminal_uuid).bridge_uuid;
auto color_ = m_terminal_strip->bridgeFor(rtd.real_terminal_uuid)->color_;
auto pixmap_ = m_bridges_pixmaps.value(color_);
//Current real terminal between two bridged terminal
if ((bridge_uuid == previous_bridge_uuid) &&
(bridge_uuid == next_bridge_uuid)) {
return pixmap_.middle_;
} else if (bridge_uuid == previous_bridge_uuid) {
return pixmap_.bottom_;
} else if (bridge_uuid == next_bridge_uuid) {
return pixmap_.top_;
}
}
}
//Terminal level ins't in the same column level of index
//Check if we need to draw a none bridge pixmap
//Check previous
auto physical_data = m_terminal_strip->physicalTerminalData(rtd);
auto current_real_uuid = rtd.real_terminal_uuid;
auto current_phy_uuid = physical_data.uuid_;
bool already_jumped_to_previous = false;
RealTerminalData previous_data;
do {
auto previous_rtd = m_terminal_strip->previousRealTerminal(current_real_uuid);
current_real_uuid = previous_rtd.real_terminal_uuid;
if (previous_rtd.level_ == -1) {
break;
}
//We are in the same physical terminal as previous loop
if (current_phy_uuid == m_terminal_strip->physicalTerminalData(previous_rtd).uuid_)
{
if (previous_rtd.is_bridged &&
previous_rtd.level_ == level_column) {
previous_data = previous_rtd;
break;
}
}
else if (already_jumped_to_previous) { //We are not in same physical terminal as previous loop
break;
} else {
already_jumped_to_previous = true;
current_phy_uuid = m_terminal_strip->physicalTerminalData(previous_rtd).uuid_;
if (previous_rtd.is_bridged &&
previous_rtd.level_ == level_column) {
previous_data = previous_rtd;
break;
}
}
} while(true);
//Check next
current_real_uuid = rtd.real_terminal_uuid;
current_phy_uuid = physical_data.uuid_;
bool already_jumped_to_next = false;
RealTerminalData next_data;
do {
auto next_rtd = m_terminal_strip->nextRealTerminal(current_real_uuid);
current_real_uuid = next_rtd.real_terminal_uuid;
if (next_rtd.level_ == -1) {
break;
}
//We are in the same physical terminal as previous loop
if (current_phy_uuid == m_terminal_strip->physicalTerminalData(next_rtd).uuid_)
{
if (next_rtd.is_bridged &&
next_rtd.level_ == level_column) {
next_data = next_rtd;
break;
}
}
else if (already_jumped_to_next) { //We are not in same physical terminal as previous loop
break;
} else {
already_jumped_to_next = true;
current_phy_uuid = m_terminal_strip->physicalTerminalData(next_rtd).uuid_;
if (next_rtd.is_bridged &&
next_rtd.level_ == level_column) {
next_data = next_rtd;
break;
}
}
} while(true);
if (previous_data.bridge_uuid == next_data.bridge_uuid) {
auto bridge_ = m_terminal_strip->bridgeFor(previous_data.real_terminal_uuid);
if (bridge_) {
return m_bridges_pixmaps.value(bridge_->color_).none_;
}
}
return QPixmap();
}
/***********************************************************
* Alittle delegate for add a combobox to edit type
* and a spinbox to edit the level of a terminal
@@ -593,3 +787,43 @@ void TerminalStripModelDelegate::setModelData(QWidget *editor, QAbstractItemMode
}
}
}
/**
* @brief TerminalStripModelDelegate::paint
* By default on a QTableView, Qt draw pixmap in cell with a little margin at left.
* Override the function to draw the pixmap of bridge without the margin at left.
* @param painter
* @param option
* @param index
*/
void TerminalStripModelDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
auto column = index.column();
if (column == LEVEL_0_CELL ||
column == LEVEL_1_CELL ||
column == LEVEL_2_CELL ||
column == LEVEL_3_CELL)
{
auto variant = index.data(Qt::DecorationRole);
if (variant.isNull()) {
QStyledItemDelegate::paint(painter, option, index);
}
else
{
if (option.state & QStyle::State_Selected)
{
QStyleOptionViewItem opt_ = option;
initStyleOption(&opt_, index);
QStyle *style = QApplication::style();
auto px = style->generatedIconPixmap(QIcon::Selected, variant.value<QPixmap>(), &opt_);
style->drawItemPixmap(painter, option.rect, Qt::AlignLeft, px);
}
else {
painter->drawPixmap(option.rect, variant.value<QPixmap>());
}
}
}
else {
QStyledItemDelegate::paint(painter, option, index);
}
}

View File

@@ -1,4 +1,4 @@
/*
/*
Copyright 2006-2021 The QElectroTech Team
This file is part of QElectroTech.
@@ -22,10 +22,16 @@
#include <QObject>
#include <QPointer>
#include <QStyledItemDelegate>
#include <QPair>
#include <QHash>
#include <QColor>
#include "../terminalstrip.h"
//Code to use QColor as key for QHash
inline uint qHash(const QColor &key, uint seed) {
return qHash(key.name(), seed);
}
class TerminalStrip;
class TerminalStripModel : public QAbstractTableModel
@@ -68,21 +74,31 @@ class TerminalStripModel : public QAbstractTableModel
QVector<RealTerminalData> realTerminalDataForIndex(QModelIndexList index_list) const;
RealTerminalData realTerminalDataForIndex(const QModelIndex &index) const;
void buildBridgePixmap(const QSize &pixmap_size);
private:
void fillPhysicalTerminalData();
RealTerminalData dataAtRow(int row) const;
void replaceDataAtRow(RealTerminalData data, int row);
PhysicalTerminalData physicalDataAtIndex(int index) const;
RealTerminalData realDataAtIndex(int index) const;
QPixmap bridgePixmapFor(const QModelIndex &index) const;
private:
QPointer<TerminalStrip> m_terminal_strip;
QVector<PhysicalTerminalData> m_edited_terminal_data, m_original_terminal_data;
QHash<Element *, QVector<bool>> m_modified_cell;
QPixmap m_bridge_top,
m_bride_bottom,
m_bridge,
m_bride_both;
struct BridgePixmap
{
QPixmap top_,
middle_,
bottom_,
none_;
};
QHash<QColor, BridgePixmap> m_bridges_pixmaps;
};
class TerminalStripModelDelegate : public QStyledItemDelegate
@@ -100,6 +116,8 @@ class TerminalStripModelDelegate : public QStyledItemDelegate
QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index) const override;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
#endif // TERMINALSTRIPMODEL_H