WsParser_VS/StoryPresent/dag_present.cpp

364 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "dag_present.h"
#include <QDebug>
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);
rect.moveTo(0, 0);
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);
painter->drawText(outline - QMarginsF(5, 5, 0, 0), this->node_name);
painter->restore();
}
PenetrateNode::PenetrateNode(double width, const QString& towards, const QString& to)
: __GraphNodeBase(GraphNodeType::PenetrateNode),
outline(QSizeF(20, 8)), from_name(towards), to_name(to) {
}
void PenetrateNode::resizeOutline(double w, double h) {
this->outline = QSizeF(w, h);
this->update();
}
QString PenetrateNode::nodeFrom() const {
return from_name;
}
QString PenetrateNode::nodeTo() const {
return to_name;
}
QRectF PenetrateNode::boundingRect() const {
return QRectF(QPointF(), this->outline);
}
void PenetrateNode::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
auto outline = this->boundingRect();
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
auto ypos = outline.height() / 2 - 3;
if (this->isHighlighted())
painter->fillRect(QRectF(0, ypos, outline.width(), 4), Qt::red);
else
painter->fillRect(QRectF(0, ypos, outline.width(), 4), Qt::black);
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();
auto xpos = this->start_node->pos().x() + orect.width();
auto ypos = std::min(this->start_node->pos().y(), this->end_node->pos().y());
auto width_value = this->end_node->pos().x() - xpos;
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();
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();
auto line_span = this->prev_layer_w - start_rect.width();
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
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);
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), _layout_engine(new DAGGraph){
this->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
this->setScene(&this->scene_bind);
auto f = this->font();
f.setPixelSize(25);
this->setFont(f);
}
QList<IGraphNode*> DAGActiveView::layer_nodes_construction(const QHash<IGraphNode*, std::shared_ptr<DAGOrderHelper>>& prev_layer_helper,
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()) {
auto from = data_node->tailsNode()->bindPoint().name();
auto to = data_node->headsNode()->bindPoint().name();
auto curr_gnode = new PenetrateNode(20, from, to);
this->scene_bind.addItem(curr_gnode);
curr_gnode->setPos(prev_layer_end, data_node->sortNumber().toDouble() * (this->node_span + this->font().pointSizeF()) * 7);
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());
this->scene_bind.addItem(curr_gnode);
curr_gnode->setPos(prev_layer_end, data_node->sortNumber().toDouble() * (this->node_span + this->font().pointSizeF()) * 7);
current_nodes_helper[curr_gnode] = data_node;
}
}
// <20><><EFBFBD>䵱ǰ<E4B5B1><C7B0><EFBFBD>νڵ<CEBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
double curr_layer_width = 0, prev_node_height = 20;
for (auto n : current_nodes_helper.keys()) {
curr_layer_width = std::max(curr_layer_width, n->boundingRect().width());
}
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);
}
}
}
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);
this->scene_bind.addItem(line_cmbn);
line_cmbn->layoutRefresh();
next_nodes << line_cmbn;
}
}
}
}
next_nodes.append(current_nodes_helper.keys());
return next_nodes;
}
#include <QTextEdit>
void DAGActiveView::updateWithEdges(QList<graph_data::Arrow> arrows) {
_layout_engine->rebuildFromEdges(arrows);
_layout_engine->primitiveGraphLayout();
this->refreshGraph();
}
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();
}
DAGGraph* dags::DAGActiveView::layoutEngine() const
{
return this->_layout_engine;
}
void dags::DAGActiveView::refreshGraph()
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0>ͼ
this->scene_bind.clear();
this->total_graph_nodes.clear();
auto total_nodes = _layout_engine->nodeWithLayout();
total_graph_nodes = this->layer_nodes_construction(QHash<IGraphNode*, std::shared_ptr<DAGOrderHelper>>(), total_nodes);
auto rect = this->scene()->itemsBoundingRect();
this->scene()->setSceneRect(rect);
}
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);
}