2024-09-24 10:43:10 +00:00
|
|
|
|
#include "dag_present.h"
|
2024-10-04 10:58:34 +00:00
|
|
|
|
#include <QDebug>
|
2024-09-24 10:43:10 +00:00
|
|
|
|
|
|
|
|
|
using namespace dags;
|
|
|
|
|
|
|
|
|
|
ActivePresentNode::ActivePresentNode(const QString name, PrsnType type, QFont font)
|
|
|
|
|
: __GraphNodeBase(GraphNodeType::ActivePresentNode),
|
|
|
|
|
node_type(type), node_name(name), measure_base(font) {}
|
|
|
|
|
|
|
|
|
|
QString ActivePresentNode::nodeName() const {
|
|
|
|
|
return this->node_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QRectF ActivePresentNode::boundingRect() const {
|
|
|
|
|
auto rect = this->measure_base.boundingRect(this->node_name);
|
2024-10-04 10:58:34 +00:00
|
|
|
|
rect.moveTo(0, 0);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
return rect += QMarginsF(0, 0, 10, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ActivePresentNode::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
|
|
|
|
auto outline = this->boundingRect();
|
|
|
|
|
painter->save();
|
|
|
|
|
if (this->node_type == PrsnType::NormalNode)
|
|
|
|
|
painter->fillRect(outline, Qt::gray);
|
|
|
|
|
else
|
|
|
|
|
painter->fillRect(outline, Qt::green);
|
|
|
|
|
|
|
|
|
|
if (this->isHighlighted()) {
|
|
|
|
|
painter->setPen(Qt::red);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
painter->drawRect(outline);
|
2024-10-04 10:58:34 +00:00
|
|
|
|
painter->drawText(outline - QMarginsF(5, 5, 0, 0), this->node_name);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
painter->restore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PenetrateNode::PenetrateNode(double width, const QString& towards, const QString& to)
|
|
|
|
|
: __GraphNodeBase(GraphNodeType::PenetrateNode),
|
2024-10-04 12:02:18 +00:00
|
|
|
|
outline(QSizeF(20, 8)), from_name(towards), to_name(to) {
|
2024-09-24 10:43:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-04 12:02:18 +00:00
|
|
|
|
void PenetrateNode::resizeOutline(double w, double h) {
|
|
|
|
|
this->outline = QSizeF(w, h);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
this->update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString PenetrateNode::nodeFrom() const {
|
|
|
|
|
return from_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString PenetrateNode::nodeTo() const {
|
|
|
|
|
return to_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QRectF PenetrateNode::boundingRect() const {
|
2024-10-04 12:02:18 +00:00
|
|
|
|
return QRectF(QPointF(), this->outline);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PenetrateNode::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
|
|
|
|
auto outline = this->boundingRect();
|
|
|
|
|
|
|
|
|
|
painter->save();
|
2024-10-05 09:20:41 +00:00
|
|
|
|
painter->setRenderHint(QPainter::Antialiasing);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
|
2024-10-04 12:02:18 +00:00
|
|
|
|
auto ypos = outline.height() / 2 - 3;
|
2024-09-24 10:43:10 +00:00
|
|
|
|
if (this->isHighlighted())
|
2024-10-04 12:02:18 +00:00
|
|
|
|
painter->fillRect(QRectF(0, ypos, outline.width(), 4), Qt::red);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
else
|
2024-10-04 12:02:18 +00:00
|
|
|
|
painter->fillRect(QRectF(0, ypos, outline.width(), 4), Qt::black);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
|
|
|
|
|
painter->restore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TransitionCurve::TransitionCurve(IGraphNode* start, IGraphNode* end, double prev_layer_width)
|
|
|
|
|
: __GraphNodeBase(GraphNodeType::TransitionCurve),
|
|
|
|
|
start_node(start), end_node(end), prev_layer_w(prev_layer_width) {}
|
|
|
|
|
|
|
|
|
|
void TransitionCurve::layoutRefresh() {
|
|
|
|
|
auto orect = this->start_node->boundingRect();
|
|
|
|
|
auto erect = this->end_node->boundingRect();
|
|
|
|
|
|
2024-10-04 10:58:34 +00:00
|
|
|
|
auto xpos = this->start_node->pos().x() + orect.width();
|
2024-09-24 10:43:10 +00:00
|
|
|
|
auto ypos = std::min(this->start_node->pos().y(), this->end_node->pos().y());
|
2024-10-04 10:58:34 +00:00
|
|
|
|
|
|
|
|
|
auto width_value = this->end_node->pos().x() - xpos;
|
2024-09-24 10:43:10 +00:00
|
|
|
|
auto bottom_y = std::max(this->start_node->pos().y() + orect.height(), this->end_node->pos().y() + erect.height());
|
|
|
|
|
|
|
|
|
|
this->outline = QRectF(0, 0, width_value, bottom_y - ypos);
|
|
|
|
|
this->setPos(xpos, ypos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString TransitionCurve::nodeFrom() const {
|
|
|
|
|
if (start_node->nodeType() == GraphNodeType::ActivePresentNode)
|
|
|
|
|
return static_cast<ActivePresentNode*>(start_node)->nodeName();
|
|
|
|
|
else
|
|
|
|
|
return static_cast<PenetrateNode*>(start_node)->nodeFrom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString TransitionCurve::nodeTo() const {
|
|
|
|
|
if (end_node->nodeType() == GraphNodeType::ActivePresentNode)
|
|
|
|
|
return static_cast<ActivePresentNode*>(end_node)->nodeName();
|
|
|
|
|
else
|
|
|
|
|
return static_cast<PenetrateNode*>(end_node)->nodeTo();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QRectF TransitionCurve::boundingRect() const {
|
|
|
|
|
return this->outline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TransitionCurve::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
|
|
|
|
auto outline = this->boundingRect();
|
|
|
|
|
auto start_rect = this->start_node->boundingRect();
|
|
|
|
|
auto end_rect = this->end_node->boundingRect();
|
2024-10-04 10:58:34 +00:00
|
|
|
|
start_rect.moveTo(this->start_node->pos());
|
|
|
|
|
end_rect.moveTo(this->end_node->pos());
|
|
|
|
|
|
|
|
|
|
auto aj_start_pos = start_rect.topRight();
|
|
|
|
|
auto aj_end_pos = end_rect.topLeft();
|
2024-09-24 10:43:10 +00:00
|
|
|
|
auto line_span = this->prev_layer_w - start_rect.width();
|
|
|
|
|
|
|
|
|
|
painter->save();
|
|
|
|
|
painter->setRenderHint(QPainter::Antialiasing);
|
|
|
|
|
|
2024-10-04 12:02:18 +00:00
|
|
|
|
auto start_pos = aj_start_pos - QGraphicsItem::pos() + QPointF(0, (int) start_rect.height() / 2);
|
|
|
|
|
auto end_pos = aj_end_pos - QGraphicsItem::pos() + QPointF(0, (int) end_rect.height() / 2);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
|
|
|
|
|
auto line_epos = start_pos + QPointF(line_span, 0);
|
|
|
|
|
auto control_pos0 = line_epos + QPointF((outline.width() - line_span) / 3, 0);
|
|
|
|
|
auto control_pos1 = end_pos - QPointF((outline.width() - line_span) / 3, 0);
|
|
|
|
|
|
|
|
|
|
auto npen = QPen(Qt::black);
|
|
|
|
|
if (this->isHighlighted())
|
|
|
|
|
npen = QPen(Qt::red);
|
|
|
|
|
|
|
|
|
|
npen.setWidthF(4);
|
|
|
|
|
painter->setPen(npen);
|
|
|
|
|
painter->drawLine(start_pos, line_epos);
|
|
|
|
|
|
|
|
|
|
auto path0 = QPainterPath();
|
|
|
|
|
path0.moveTo(line_epos);
|
|
|
|
|
path0.cubicTo(control_pos0, control_pos1, end_pos);
|
|
|
|
|
painter->drawPath(path0);
|
|
|
|
|
|
|
|
|
|
painter->restore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DAGActiveView::DAGActiveView(QWidget* parent)
|
|
|
|
|
: QGraphicsView(parent) {
|
|
|
|
|
this->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
|
|
|
|
|
this->setScene(&this->scene_bind);
|
|
|
|
|
|
|
|
|
|
auto f = this->font();
|
|
|
|
|
f.setPixelSize(25);
|
|
|
|
|
this->setFont(f);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-04 10:58:34 +00:00
|
|
|
|
QList<IGraphNode*> DAGActiveView::layer_nodes_construction(const QHash<IGraphNode*, std::shared_ptr<DAGOrderHelper>>& prev_layer_helper,
|
2024-09-24 10:43:10 +00:00
|
|
|
|
const QList<std::shared_ptr<DAGOrderHelper>>& total_datas, int layer_idx, double prev_layer_end) {
|
|
|
|
|
// <20><>ѡ<EFBFBD><D1A1>ǰ<EFBFBD><C7B0><EFBFBD>νڵ<CEBD>
|
|
|
|
|
QList<std::shared_ptr<DAGOrderHelper>> current_layer_datas;
|
|
|
|
|
std::copy_if(total_datas.begin(), total_datas.end(), std::back_inserter(current_layer_datas),
|
|
|
|
|
[&](std::shared_ptr<DAGOrderHelper> ins) { return ins->layerNumber() == layer_idx; });
|
|
|
|
|
std::sort(current_layer_datas.begin(), current_layer_datas.end(),
|
|
|
|
|
[](std::shared_ptr<DAGOrderHelper>a, std::shared_ptr<DAGOrderHelper> b) {
|
|
|
|
|
return a->sortNumber() < b->sortNumber();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
QHash<IGraphNode*, std::shared_ptr<DAGOrderHelper>> current_nodes_helper;
|
|
|
|
|
// <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD>ڵ<DEBD>
|
|
|
|
|
if (!current_layer_datas.size())
|
|
|
|
|
return current_nodes_helper.keys();
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>ͼ<EFBFBD>νڵ<CEBD>
|
|
|
|
|
for (auto& data_node : current_layer_datas) {
|
|
|
|
|
if (data_node->isFakeNode()) {
|
2024-10-05 02:57:49 +00:00
|
|
|
|
auto from = data_node->tailsNode()->bindPoint().name();
|
|
|
|
|
auto to = data_node->headsNode()->bindPoint().name();
|
2024-09-24 10:43:10 +00:00
|
|
|
|
auto curr_gnode = new PenetrateNode(20, from, to);
|
2024-10-04 10:58:34 +00:00
|
|
|
|
this->scene_bind.addItem(curr_gnode);
|
2024-10-05 13:15:07 +00:00
|
|
|
|
curr_gnode->setPos(prev_layer_end, data_node->sortNumber().toDouble() * (this->node_span + this->font().pointSizeF()) * 7);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
|
|
|
|
|
current_nodes_helper[curr_gnode] = data_node;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
auto node_type_vx = PrsnType::NormalNode;
|
|
|
|
|
if (!data_node->layerNode()->inputCount()) {
|
|
|
|
|
node_type_vx = PrsnType::StartNode;
|
|
|
|
|
}
|
|
|
|
|
auto curr_gnode = new ActivePresentNode(data_node->layerNode()->bindPoint().name(), node_type_vx, this->font());
|
2024-10-04 10:58:34 +00:00
|
|
|
|
this->scene_bind.addItem(curr_gnode);
|
2024-10-05 13:15:07 +00:00
|
|
|
|
curr_gnode->setPos(prev_layer_end, data_node->sortNumber().toDouble() * (this->node_span + this->font().pointSizeF()) * 7);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
|
|
|
|
|
current_nodes_helper[curr_gnode] = data_node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>䵱ǰ<E4B5B1><C7B0><EFBFBD>νڵ<CEBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
2024-10-04 12:02:18 +00:00
|
|
|
|
double curr_layer_width = 0, prev_node_height = 20;
|
2024-09-24 10:43:10 +00:00
|
|
|
|
for (auto n : current_nodes_helper.keys()) {
|
|
|
|
|
curr_layer_width = std::max(curr_layer_width, n->boundingRect().width());
|
|
|
|
|
}
|
2024-10-04 12:02:18 +00:00
|
|
|
|
if (prev_layer_helper.size()) {
|
|
|
|
|
prev_node_height = prev_layer_helper.keys().first()->boundingRect().height();
|
|
|
|
|
for (auto n : current_nodes_helper.keys()) {
|
|
|
|
|
if (n->nodeType() == GraphNodeType::PenetrateNode) {
|
|
|
|
|
static_cast<PenetrateNode*>(n)->resizeOutline(curr_layer_width, prev_node_height);
|
|
|
|
|
}
|
2024-09-24 10:43:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto next_nodes = this->layer_nodes_construction(current_nodes_helper,
|
|
|
|
|
total_datas, layer_idx + 1, prev_layer_end + curr_layer_width + this->layer_span);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
if (prev_layer_helper.size()) {
|
|
|
|
|
double prev_layer_width = 0;
|
|
|
|
|
for (auto n : prev_layer_helper.keys()) {
|
|
|
|
|
prev_layer_width = std::max(prev_layer_width, n->boundingRect().width());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto curr_gnode : current_nodes_helper.keys()) {
|
|
|
|
|
auto curr_data = current_nodes_helper[curr_gnode];
|
|
|
|
|
auto upstream_nodes = curr_data->getUpstreamNodes();
|
|
|
|
|
|
|
|
|
|
for (auto prev_gnode : prev_layer_helper.keys()) {
|
|
|
|
|
auto prev_data = prev_layer_helper[prev_gnode];
|
|
|
|
|
if (upstream_nodes.contains(prev_data)) {
|
|
|
|
|
auto line_cmbn = new TransitionCurve(prev_gnode, curr_gnode, prev_layer_width);
|
2024-10-04 10:58:34 +00:00
|
|
|
|
this->scene_bind.addItem(line_cmbn);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
line_cmbn->layoutRefresh();
|
|
|
|
|
next_nodes << line_cmbn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next_nodes.append(current_nodes_helper.keys());
|
|
|
|
|
return next_nodes;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-04 12:02:18 +00:00
|
|
|
|
#include <QTextEdit>
|
2024-09-24 10:43:10 +00:00
|
|
|
|
void DAGActiveView::updateWithEdges(QList<graph_data::Arrow> arrows) {
|
2024-10-04 10:58:34 +00:00
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0>ͼ
|
|
|
|
|
this->scene_bind.clear();
|
|
|
|
|
this->total_graph_nodes.clear();
|
|
|
|
|
|
2024-09-24 10:43:10 +00:00
|
|
|
|
DAGGraph tools;
|
|
|
|
|
tools.rebuildFromEdges(arrows);
|
|
|
|
|
tools.graphLayout();
|
|
|
|
|
|
|
|
|
|
auto total_nodes = tools.nodeWithLayout();
|
2024-10-04 10:58:34 +00:00
|
|
|
|
total_graph_nodes = this->layer_nodes_construction(QHash<IGraphNode*, std::shared_ptr<DAGOrderHelper>>(), total_nodes);
|
2024-09-24 10:43:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DAGActiveView::highlightGraphLink(const QList<graph_data::Arrow> arrows) {
|
|
|
|
|
for (auto& n : this->highlight_nodelist)
|
|
|
|
|
n->highlight(false);
|
|
|
|
|
this->highlight_nodelist.clear();
|
|
|
|
|
|
|
|
|
|
QList<QString> _color_path;
|
|
|
|
|
for (auto& a : arrows) {
|
|
|
|
|
_color_path << a.endPoint().name();
|
|
|
|
|
_color_path << a.startPoint().name();
|
|
|
|
|
}
|
|
|
|
|
auto set = _color_path.toSet();
|
|
|
|
|
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD>·<EFBFBD><C2B7><EFBFBD><EFBFBD>
|
|
|
|
|
for (auto& node : this->total_graph_nodes) {
|
|
|
|
|
if (node->nodeType() == GraphNodeType::ActivePresentNode) {
|
|
|
|
|
auto x_node = static_cast<ActivePresentNode*>(node);
|
|
|
|
|
if (set.contains(x_node->nodeName())) {
|
|
|
|
|
x_node->highlight(true);
|
|
|
|
|
this->highlight_nodelist << x_node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto idx = 0; idx < arrows.size(); ++idx) {
|
|
|
|
|
auto start_name = arrows.at(idx).startPoint().name();
|
|
|
|
|
auto end_name = arrows.at(idx).endPoint().name();
|
|
|
|
|
|
|
|
|
|
for (auto gnode : this->total_graph_nodes) {
|
|
|
|
|
switch (gnode->nodeType()) {
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ռλ<D5BC>ڵ<EFBFBD>
|
|
|
|
|
case GraphNodeType::PenetrateNode:
|
|
|
|
|
{
|
|
|
|
|
auto pinst = dynamic_cast<PenetrateNode*>(gnode);
|
|
|
|
|
if (start_name == pinst->nodeFrom() && end_name == pinst->nodeTo()) {
|
|
|
|
|
gnode->highlight(true);
|
|
|
|
|
this->highlight_nodelist << gnode;
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
case GraphNodeType::TransitionCurve:
|
|
|
|
|
{
|
|
|
|
|
auto pinst = dynamic_cast<TransitionCurve*>(gnode);
|
|
|
|
|
if (start_name == pinst->nodeFrom() && end_name == pinst->nodeTo()) {
|
|
|
|
|
gnode->highlight(true);
|
|
|
|
|
this->highlight_nodelist << gnode;
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->scene_bind.update();
|
|
|
|
|
this->update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DAGActiveView::mousePressEvent(QMouseEvent* ev) {
|
|
|
|
|
QGraphicsView::mousePressEvent(ev);
|
|
|
|
|
|
|
|
|
|
if (ev->buttons().testFlag(Qt::LeftButton)) {
|
|
|
|
|
auto gitems = this->items(ev->pos());
|
|
|
|
|
if (!gitems.size())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (auto& gitem : gitems) {
|
|
|
|
|
auto type_item = dynamic_cast<IGraphNode*>(gitem);
|
|
|
|
|
if (type_item->nodeType() == GraphNodeType::ActivePresentNode) {
|
|
|
|
|
auto node = static_cast<ActivePresentNode*>(type_item);
|
|
|
|
|
emit this->nodeClicked(ev->pos(), QList<QString>() << node->nodeName());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__GraphNodeBase::__GraphNodeBase(GraphNodeType t)
|
|
|
|
|
:_node_type(t), _highlight_mark(false) {}
|
|
|
|
|
|
|
|
|
|
GraphNodeType __GraphNodeBase::nodeType() const {
|
|
|
|
|
return _node_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void __GraphNodeBase::highlight(bool mark) {
|
|
|
|
|
_highlight_mark = mark;
|
|
|
|
|
this->update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool __GraphNodeBase::isHighlighted() const {
|
|
|
|
|
return _highlight_mark;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QPointF __GraphNodeBase::pos() const {
|
|
|
|
|
return QGraphicsItem::pos();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void __GraphNodeBase::setPos(qreal x, qreal y) {
|
|
|
|
|
QGraphicsItem::setPos(x, y);
|
|
|
|
|
}
|