From be67b5ef031b09cc1174835059c2078e136b1e5b Mon Sep 17 00:00:00 2001 From: codeboss <2422523675@qq.com> Date: Thu, 3 Jul 2025 17:37:20 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=98=E5=88=B6=E8=8A=82=E7=82=B9=E8=81=94?= =?UTF-8?q?=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SimsWorld/BehaviorEditor.cpp | 144 ++++++++++++++++++++++++++++++----- SimsWorld/BehaviorEditor.h | 34 ++++++++- 2 files changed, 155 insertions(+), 23 deletions(-) diff --git a/SimsWorld/BehaviorEditor.cpp b/SimsWorld/BehaviorEditor.cpp index e00b80f..c4668fd 100644 --- a/SimsWorld/BehaviorEditor.cpp +++ b/SimsWorld/BehaviorEditor.cpp @@ -8,7 +8,9 @@ NodePresent::NodePresent(BehaviorsPresent* pwidget, double& width_bind, std::sha QRectF NodePresent::contentMeasure() const { auto metrics = this->_widget_p->fontMetrics(); - return metrics.boundingRect(this->_node_bind->rtName()); + auto rect = metrics.boundingRect(this->_node_bind->rtName()); + rect.moveTopLeft(QPoint(0, 0)); + return rect; } #include @@ -21,7 +23,7 @@ AcceptType NodePresent::testAccept(const QPointF& local_pos, const QString& kind auto left_rect = QRectF(origin + QPointF(0, 0), QSizeF(width / 3, outline.height())); auto right_rect = QRectF(origin + QPointF(width * 2 / 3, 0), QSizeF(width / 3, outline.height())); auto top_rect = QRectF(origin + QPointF(width / 3, outline.height() / 2), QSizeF(width / 3, outline.height() / 2)); - auto bottom_rect = QRectF(origin + QPointF(width / 3, 0), QSizeF(width / 3, outline.height() / 2)); + auto bottom_rect = QRectF(origin + QPointF(width / 3, 0), QSizeF(width / 3, outline.height() / 2)); QList no_child{ NodeKind::ACTIONNODE, NodeKind::COMPARENODE }; auto pnode = this->_node_bind->parent().lock(); @@ -111,7 +113,7 @@ void NodePresent::dropEvent(QGraphicsSceneDragDropEvent* e) auto this_node = this->_node_bind; auto appoint_index = 0; - if(parent_node) + if (parent_node) appoint_index = parent_node->children().indexOf(this_node); switch (_drop_target) { @@ -153,7 +155,7 @@ void NodePresent::paint(QPainter* painter, const QStyleOptionGraphicsItem* optio painter->save(); painter->drawRect(boundingRect()); - painter->fillRect(option->rect - QMargins(8, 8, 8, 8), Qt::gray); + painter->fillRect(option->rect - QMargins(padding, padding, padding, padding), Qt::gray); auto outline = this->boundingRect(); auto width = outline.width(); @@ -203,38 +205,51 @@ BehaviorsPresent::BehaviorsPresent(QWidget* parent /*= nullptr*/) void BehaviorsPresent::setRoot(std::shared_ptr root) { + this->_bind_maproot = root; + + // 清除显示节点 qDeleteAll(_present_peers); _present_peers.clear(); - this->_bind_maproot = root; + // 清空分支 + qDeleteAll(this->_branch_list); + this->_branch_list.clear(); + relayout(); } -void BehaviorsPresent::presentAllocate(std::shared_ptr ins) +NodePresent* BehaviorsPresent::presentAllocate(std::shared_ptr ins) { - switch (ins->nodeKind()) - { + for (auto idx = _column_aligns.size(); idx < ins->depth() + 1; ++idx) + _column_aligns.append(0); + + auto& current_width = _column_aligns[ins->depth()]; + QList _children_set; + switch (ins->nodeKind()) { case NodeKind::MAPNODE: case NodeKind::PARALLELNODE: case NodeKind::SEQUENCENODE: case NodeKind::SELECTORNODE: if (ins->nodeKind() != NodeKind::MAPNODE || !ins->bindMap()) { - auto type = ins->nodeKind(); - for (auto it : ins->children()) - presentAllocate(it); + for (auto it : ins->children()) { + auto child_graph = presentAllocate(it); + if (child_graph) _children_set << child_graph; + } } default: - if (_present_peers.contains(ins)) - return; + if (_present_peers.contains(ins)) { + for (auto child : _children_set) { + _branch_list << new BranchPresent(_present_peers[ins], current_width, child); + this->_bind_scene.addItem(_branch_list.last()); + } + return nullptr; + } - for (auto idx = _column_aligns.size(); idx < ins->depth() + 1; ++idx) - _column_aligns.append(0); - - auto& current_width = _column_aligns[ins->depth()]; _present_peers[ins] = new NodePresent(this, current_width, ins); this->_bind_scene.addItem(_present_peers[ins]); - break; + + return _present_peers[ins]; } } @@ -258,6 +273,7 @@ void BehaviorsPresent::presentRelease(std::shared_ptr ins) } } +const double NodePresent::padding = 8; void BehaviorsPresent::relayout() { if (!_bind_maproot) @@ -269,8 +285,26 @@ void BehaviorsPresent::relayout() QHash, std::pair> results; // 尺寸测量 outlineMeasure(_bind_maproot, results); + // 元素排布 nodeRelayout(results, _bind_maproot, QPointF()); + + // 调整分支图形位置 + for (auto ins : this->_branch_list) { + auto rect_s = ins->startNodeOutline(); + auto rect_e = ins->endNodeOutline(); + + qDebug() << __FILE__ << __LINE__ << rect_s << rect_e; + + auto start_pos = rect_s.bottomRight() - QPoint(NodePresent::padding, rect_s.height() / 2); + auto end_pos = rect_e.topLeft() + QPoint(NodePresent::padding, rect_e.height() / 2); + + auto left_val = std::min(start_pos.x(), end_pos.x()); + auto top_val = std::min(start_pos.y(), end_pos.y()); + + ins->setPos(left_val, top_val); + ins->resetArrow(start_pos, end_pos); + } } QSizeF BehaviorsPresent::outlineMeasure(std::shared_ptr ins, QHash, std::pair>& _outline_occupy) @@ -357,7 +391,6 @@ void BehaviorEditor::open_behavior_map() if (!url.isValid()) return; - qDebug() << url; } BehaviorEditor::BehaviorEditor(QWidget* parent /*= nullptr*/) @@ -448,3 +481,76 @@ void NodeTypesView::startDrag(Qt::DropActions supported) } } } + +BranchPresent::BranchPresent(NodePresent* a, double& a_width, NodePresent* b) + :_start_node(a), _start_node_width(a_width), _end_node(b) { +} + +QRectF BranchPresent::startNodeOutline() const +{ + auto _start_pos = _start_node->pos(); + auto _s_rect = _start_node->boundingRect(); + _s_rect.moveTopLeft(_start_pos); + + return _s_rect; +} + +QRectF BranchPresent::endNodeOutline() const +{ + auto _end_pos = _end_node->pos(); + auto _e_rect = _end_node->boundingRect(); + _e_rect.moveTopLeft(_end_pos); + + return _e_rect; +} + +void BranchPresent::resetArrow(const QPointF& start, const QPointF& end) +{ + this->_arrow_start = start; + this->_arrow_end = end; + qDebug() << __FILE__ << __LINE__ << _arrow_start << _arrow_end; + this->update(); +} + +QRectF BranchPresent::boundingRect() const +{ + auto leftv = std::min(_arrow_start.x(), _arrow_end.x()); + auto topv = std::min(_arrow_start.y(), _arrow_end.y()); + auto width = std::abs(_arrow_start.x() - _arrow_end.x()); + auto height = std::abs(_arrow_start.y() - _arrow_end.y()); + + return QRectF(0, 0, width, height); +} + +void BranchPresent::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + painter->save(); + painter->setRenderHint(QPainter::Antialiasing, true); + + QPointF start(0, 0); + auto vtarget = _arrow_end - _arrow_start; + if (vtarget.y() < 0) { + start -= QPointF(0, vtarget.y()); + vtarget -= QPointF(0, vtarget.y()); + } + + auto pt1 = start + QPointF(vtarget.x() / 2, 0); + auto pt2 = vtarget - QPointF(vtarget.x() / 2, 0); + + QPainterPath bezier_curve; + bezier_curve.moveTo(start); + bezier_curve.cubicTo(pt1, pt2, vtarget); + + QPen p(Qt::black); + p.setWidth(2); + painter->setPen(p); + + painter->drawPath(bezier_curve); + //p.setColor(Qt::red); + //painter->setPen(p); + //painter->drawLine(start, pt1); + //painter->drawLine(pt1, pt2); + //painter->drawLine(pt1, vtarget); + + painter->restore(); +} diff --git a/SimsWorld/BehaviorEditor.h b/SimsWorld/BehaviorEditor.h index eee81e0..a36931d 100644 --- a/SimsWorld/BehaviorEditor.h +++ b/SimsWorld/BehaviorEditor.h @@ -17,16 +17,17 @@ class BehaviorsPresent; class NodePresent : public QGraphicsItem { private: BehaviorsPresent* const _widget_p; - std::shared_ptr _node_bind; double& _column_width; AcceptType _drop_target = AcceptType::NONE; public: + std::shared_ptr _node_bind; + static const double padding; NodePresent(BehaviorsPresent* pwidget, double& width_bind, std::shared_ptr bind); QRectF contentMeasure() const; - AcceptType testAccept(const QPointF& local_pos, const QString &kind_str) const; + AcceptType testAccept(const QPointF& local_pos, const QString& kind_str) const; // 通过 QGraphicsItem 继承 QRectF boundingRect() const override; @@ -39,6 +40,30 @@ protected: virtual void dropEvent(QGraphicsSceneDragDropEvent* event); }; +/// +/// 分支图形代理 +/// +class BranchPresent : public QGraphicsItem { +private: + NodePresent* const _start_node; + double& _start_node_width; + NodePresent* const _end_node; + + QPointF _arrow_start, _arrow_end; + +public: + BranchPresent(NodePresent* a, double& a_width, NodePresent* b); + + QRectF startNodeOutline() const; + QRectF endNodeOutline() const; + void resetArrow(const QPointF& start, const QPointF& end); + + // 通过 QGraphicsItem 继承 + QRectF boundingRect() const override; + void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; + +}; + /// /// 行为树编辑展示 @@ -48,9 +73,10 @@ class BehaviorsPresent : public QGraphicsView private: QGraphicsScene _bind_scene; - const double _space_h = 120; + const double _space_h = 30; QVector _column_aligns; QHash, NodePresent*> _present_peers; + QList _branch_list; /// /// 绑定行为树节点 @@ -72,7 +98,7 @@ public: /// /// /// - void presentAllocate(std::shared_ptr ins); + NodePresent* presentAllocate(std::shared_ptr ins); /// /// 递归释放显示节点 ///