WsParser_VS/StoryPresent/dag_present.cpp

352 lines
11 KiB
C++
Raw Normal View History

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);
}