diff --git a/ComponentBasic/BehaviorPerform.cpp b/ComponentBasic/BehaviorPerform.cpp index abbb62f..c137b8b 100644 --- a/ComponentBasic/BehaviorPerform.cpp +++ b/ComponentBasic/BehaviorPerform.cpp @@ -187,7 +187,7 @@ int LogicalNode::depth() const return this->parent().lock()->depth() + 1; } -std::shared_ptr LogicalNode::bindMap() const +std::shared_ptr LogicalNode::bindMap() const { auto node_temp = this->parent().lock(); if (!node_temp) return nullptr; @@ -195,7 +195,8 @@ std::shared_ptr LogicalNode::bindMap() const while (node_temp->nodeKind() != NodeKind::MAPNODE) { node_temp = node_temp->parent().lock(); } - return node_temp; + + return std::dynamic_pointer_cast(node_temp); } void LogicalNode::setID(int unique_id) @@ -222,6 +223,11 @@ BehaviorMapNode::BehaviorMapNode(std::shared_ptr core) :LogicalNode(NodeKind::MAPNODE), _bind_kernal(core) { } +std::shared_ptr BehaviorMapNode::getKernal() const +{ + return _bind_kernal; +} + void BehaviorMapNode::setVariable(const QString& key, IO_TYPE t, std::shared_ptr ins) { if (_variables.contains(key)) diff --git a/ComponentBasic/BehaviorPerform.h b/ComponentBasic/BehaviorPerform.h index cca540b..f29d5c6 100644 --- a/ComponentBasic/BehaviorPerform.h +++ b/ComponentBasic/BehaviorPerform.h @@ -324,6 +324,7 @@ enum class NodeKind { COMPARENODE, // 比较节点 ACTIONNODE, // 动作节点 }; +class BehaviorMapNode; /// /// 所有逻辑节点的基类 /// @@ -360,7 +361,7 @@ public: /// 获取包含树图节点 /// /// - std::shared_ptr bindMap() const; + std::shared_ptr bindMap() const; /// /// 回退节点 @@ -475,6 +476,7 @@ private: public: BehaviorMapNode(std::shared_ptr kernal); + std::shared_ptr getKernal() const; /// /// 设置变量,如果类型错误会抛出UniException异常 diff --git a/SimsWorld/BehaviorEditor.cpp b/SimsWorld/BehaviorEditor.cpp index d83944e..e00b80f 100644 --- a/SimsWorld/BehaviorEditor.cpp +++ b/SimsWorld/BehaviorEditor.cpp @@ -1,6 +1,6 @@ #include "BehaviorEditor.h" -NodePresent::NodePresent(QWidget* pwidget, double& width_bind, std::shared_ptr bind) +NodePresent::NodePresent(BehaviorsPresent* pwidget, double& width_bind, std::shared_ptr bind) : _widget_p(pwidget), _node_bind(bind), _column_width(width_bind) { this->setAcceptDrops(true); } @@ -11,16 +11,63 @@ QRectF NodePresent::contentMeasure() const return metrics.boundingRect(this->_node_bind->rtName()); } -AcceptType NodePresent::testAccept(const QPointF& local_pos) const +#include +AcceptType NodePresent::testAccept(const QPointF& local_pos, const QString& kind_str) const { - return AcceptType::PREV_LEVEL; + auto outline = this->boundingRect(); + auto width = outline.width(); + auto origin = outline.topLeft(); + + 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)); + + QList no_child{ NodeKind::ACTIONNODE, NodeKind::COMPARENODE }; + auto pnode = this->_node_bind->parent().lock(); + decltype(pnode) new_type = nullptr; + if (this->_node_bind->bindMap()) + new_type = this->_node_bind->bindMap()->getKernal()->getNode(kind_str); + else + new_type = std::dynamic_pointer_cast(this->_node_bind)->getKernal()->getNode(kind_str); + + // 当前节点存在父节点且不属于Action和Compare + if (left_rect.contains(local_pos) && pnode && !no_child.contains(new_type->nodeKind())) + return AcceptType::PREV_LEVEL; + + // 当前节点存在父节点且父节点可以存在多个节点 + if (pnode && pnode->nodeKind() != NodeKind::MAPNODE) { + if (top_rect.contains(local_pos)) + return AcceptType::PREV_SIBLING; + + if (bottom_rect.contains(local_pos)) + return AcceptType::NEXT_SIBLING; + } + + // 分辨当前节点的是否可以插入新节点 + if (right_rect.contains(local_pos)) + switch (this->_node_bind->nodeKind()) { + case NodeKind::MAPNODE: // 根节点只能容纳一个节点 + if (!this->_node_bind->children().size() && !this->_node_bind->parent().lock()) + return AcceptType::NEXT_LEVEL; + break; + case NodeKind::PARALLELNODE: + case NodeKind::SELECTORNODE: + case NodeKind::SEQUENCENODE: + return AcceptType::NEXT_LEVEL; + default: // Action和Compare节点不能容纳节点 + break; + } + + + return AcceptType::NONE; } #include #include -#include void NodePresent::dragEnterEvent(QGraphicsSceneDragDropEvent* e) { + QGraphicsItem::dragEnterEvent(e); if (e->mimeData()->hasFormat("application/drag-node")) { e->acceptProposedAction(); } @@ -30,27 +77,65 @@ void NodePresent::dragLeaveEvent(QGraphicsSceneDragDropEvent* event) { QGraphicsItem::dragLeaveEvent(event); this->_drop_target = AcceptType::NONE; + this->update(); } +#include void NodePresent::dragMoveEvent(QGraphicsSceneDragDropEvent* e) { + QGraphicsItem::dragMoveEvent(e); + this->update(); if (e->mimeData()->hasFormat("application/drag-node")) { - auto local_pos = this->mapToItem(this, e->pos()); - this->_drop_target = this->testAccept(local_pos); - if (_drop_target != AcceptType::NONE) + auto kind_string = QString::fromUtf8(e->mimeData()->data("application/drag-node")); + this->_drop_target = this->testAccept(e->pos(), kind_string); + if (_drop_target != AcceptType::NONE) { e->acceptProposedAction(); + return; + } } + + e->ignore(); } void NodePresent::dropEvent(QGraphicsSceneDragDropEvent* e) { - qDebug() << QString::fromUtf8(e->mimeData()->data("application/drag-node")); - - + auto kind_string = QString::fromUtf8(e->mimeData()->data("application/drag-node")); + auto parent_node = this->_node_bind->parent().lock(); + decltype(parent_node) new_type = nullptr; + if (this->_node_bind->bindMap()) + new_type = this->_node_bind->bindMap()->getKernal()->getNode(kind_string); + else + new_type = std::dynamic_pointer_cast(this->_node_bind)->getKernal()->getNode(kind_string); + auto new_node = std::dynamic_pointer_cast(new_type->newDefault()); + new_node->setID(++_widget_p->_node_id_max); + auto this_node = this->_node_bind; + auto appoint_index = 0; + if(parent_node) + appoint_index = parent_node->children().indexOf(this_node); + switch (_drop_target) { + case AcceptType::NONE: + break; + case AcceptType::PREV_LEVEL: { + parent_node->remove(this_node); + parent_node->insert(new_node, appoint_index); + new_node->insert(this_node); + }break; + case AcceptType::NEXT_LEVEL: + this_node->insert(new_node); + break; + case AcceptType::PREV_SIBLING: + parent_node->insert(new_node, appoint_index); + break; + case AcceptType::NEXT_SIBLING: + parent_node->insert(new_node, appoint_index + 1); + break; + } + _widget_p->relayout(); this->_drop_target = AcceptType::NONE; + this->update(); } QRectF NodePresent::boundingRect() const @@ -65,12 +150,44 @@ QRectF NodePresent::boundingRect() const #include void NodePresent::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { + painter->save(); + painter->drawRect(boundingRect()); painter->fillRect(option->rect - QMargins(8, 8, 8, 8), Qt::gray); + auto outline = this->boundingRect(); + auto width = outline.width(); + auto origin = outline.topLeft(); + + painter->save(); + painter->translate(QPointF(15, 15)); auto rect = contentMeasure(); painter->drawText(rect, 0, this->_node_bind->rtName()); + + painter->restore(); + + + QRectF paint_target_rect; + switch (_drop_target) { + case AcceptType::NONE: + break; + case AcceptType::PREV_LEVEL: + paint_target_rect = QRectF(origin + QPointF(0, 0), QSizeF(width / 3, outline.height()));; + break; + case AcceptType::NEXT_LEVEL: + paint_target_rect = QRectF(origin + QPointF(width * 2 / 3, 0), QSizeF(width / 3, outline.height()));; + break; + case AcceptType::PREV_SIBLING: + paint_target_rect = QRectF(origin + QPointF(width / 3, outline.height() / 2), QSizeF(width / 3, outline.height() / 2));; + break; + case AcceptType::NEXT_SIBLING: + paint_target_rect = QRectF(origin + QPointF(width / 3, 0), QSizeF(width / 3, outline.height() / 2));; + break; + } + + painter->fillRect(paint_target_rect, Qt::green); + painter->restore(); } BehaviorsPresent::BehaviorsPresent(QWidget* parent /*= nullptr*/) @@ -209,7 +326,9 @@ QPointF BehaviorsPresent::nodeRelayout(QHash, std:: default: // 布局子节点集合位置,根节点必须是顶端根节点 if (ins->nodeKind() != NodeKind::MAPNODE || !ins->bindMap()) { - for (auto item : ins->children()) { + auto child_list = ins->children(); + for (auto iter = child_list.rbegin(); iter != child_list.rend(); ++iter) { + auto item = *iter; child_origin = nodeRelayout(_outline_occupy, item, child_origin); } }break; @@ -297,7 +416,6 @@ NodeTypesView::NodeTypesView(QWidget* parent /*= nullptr*/) this->setSelectionMode(QAbstractItemView::SingleSelection); } -#include #include #include #include diff --git a/SimsWorld/BehaviorEditor.h b/SimsWorld/BehaviorEditor.h index 607b6f8..eee81e0 100644 --- a/SimsWorld/BehaviorEditor.h +++ b/SimsWorld/BehaviorEditor.h @@ -7,24 +7,26 @@ uint qHash(const std::shared_ptr data, uint seed) noexcept; enum class AcceptType { - NONE, PREV_LEVEL, NEXT_LEVEL, PREV_SIBLING, NEXT_SIBLING + NONE = 0, PREV_LEVEL, NEXT_LEVEL, PREV_SIBLING, NEXT_SIBLING }; + +class BehaviorsPresent; /// /// 节点显示代理 /// class NodePresent : public QGraphicsItem { private: - QWidget* const _widget_p; + BehaviorsPresent* const _widget_p; std::shared_ptr _node_bind; double& _column_width; AcceptType _drop_target = AcceptType::NONE; public: - NodePresent(QWidget* pwidget, double& width_bind, std::shared_ptr bind); + NodePresent(BehaviorsPresent* pwidget, double& width_bind, std::shared_ptr bind); QRectF contentMeasure() const; - AcceptType testAccept(const QPointF& local_pos) const; + AcceptType testAccept(const QPointF& local_pos, const QString &kind_str) const; // 通过 QGraphicsItem 继承 QRectF boundingRect() const override; @@ -56,6 +58,7 @@ private: std::shared_ptr _bind_maproot = nullptr; public: + uint64_t _node_id_max = 0; BehaviorsPresent(QWidget* parent = nullptr); ///