拖动构建行为树
This commit is contained in:
parent
3fcf823369
commit
8a27ca60e5
|
@ -187,7 +187,7 @@ int LogicalNode::depth() const
|
|||
return this->parent().lock()->depth() + 1;
|
||||
}
|
||||
|
||||
std::shared_ptr<LogicalNode> LogicalNode::bindMap() const
|
||||
std::shared_ptr<BehaviorMapNode> LogicalNode::bindMap() const
|
||||
{
|
||||
auto node_temp = this->parent().lock();
|
||||
if (!node_temp) return nullptr;
|
||||
|
@ -195,7 +195,8 @@ std::shared_ptr<LogicalNode> LogicalNode::bindMap() const
|
|||
while (node_temp->nodeKind() != NodeKind::MAPNODE) {
|
||||
node_temp = node_temp->parent().lock();
|
||||
}
|
||||
return node_temp;
|
||||
|
||||
return std::dynamic_pointer_cast<BehaviorMapNode>(node_temp);
|
||||
}
|
||||
|
||||
void LogicalNode::setID(int unique_id)
|
||||
|
@ -222,6 +223,11 @@ BehaviorMapNode::BehaviorMapNode(std::shared_ptr<MapKernal> core)
|
|||
:LogicalNode(NodeKind::MAPNODE), _bind_kernal(core) {
|
||||
}
|
||||
|
||||
std::shared_ptr<MapKernal> BehaviorMapNode::getKernal() const
|
||||
{
|
||||
return _bind_kernal;
|
||||
}
|
||||
|
||||
void BehaviorMapNode::setVariable(const QString& key, IO_TYPE t, std::shared_ptr<TopicData> ins)
|
||||
{
|
||||
if (_variables.contains(key))
|
||||
|
|
|
@ -324,6 +324,7 @@ enum class NodeKind {
|
|||
COMPARENODE, // 比较节点
|
||||
ACTIONNODE, // 动作节点
|
||||
};
|
||||
class BehaviorMapNode;
|
||||
/// <summary>
|
||||
/// 所有逻辑节点的基类
|
||||
/// </summary>
|
||||
|
@ -360,7 +361,7 @@ public:
|
|||
/// 获取包含树图节点
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
std::shared_ptr<LogicalNode> bindMap() const;
|
||||
std::shared_ptr<BehaviorMapNode> bindMap() const;
|
||||
|
||||
/// <summary>
|
||||
/// 回退节点
|
||||
|
@ -475,6 +476,7 @@ private:
|
|||
public:
|
||||
BehaviorMapNode(std::shared_ptr<MapKernal> kernal);
|
||||
|
||||
std::shared_ptr<MapKernal> getKernal() const;
|
||||
|
||||
/// <summary>
|
||||
/// 设置变量,如果类型错误会抛出UniException异常
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "BehaviorEditor.h"
|
||||
|
||||
NodePresent::NodePresent(QWidget* pwidget, double& width_bind, std::shared_ptr<LogicalNode> bind)
|
||||
NodePresent::NodePresent(BehaviorsPresent* pwidget, double& width_bind, std::shared_ptr<LogicalNode> 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 <QDebug>
|
||||
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<NodeKind> 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<BehaviorMapNode>(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 <QGraphicsSceneDragDropEvent>
|
||||
#include <QMimeData>
|
||||
#include <QDebug>
|
||||
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 <QApplication>
|
||||
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<BehaviorMapNode>(this->_node_bind)->getKernal()->getNode(kind_string);
|
||||
auto new_node = std::dynamic_pointer_cast<LogicalNode>(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 <QStyleOptionGraphicsItem>
|
||||
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::shared_ptr<LogicalNode>, 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 <QMimeData>
|
||||
#include <QVariant>
|
||||
#include <QDrag>
|
||||
#include <QPainter>
|
||||
|
|
|
@ -7,24 +7,26 @@
|
|||
uint qHash(const std::shared_ptr<LogicalNode> 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;
|
||||
/// <summary>
|
||||
/// ½ÚµãÏÔʾ´úÀí
|
||||
/// </summary>
|
||||
class NodePresent : public QGraphicsItem {
|
||||
private:
|
||||
QWidget* const _widget_p;
|
||||
BehaviorsPresent* const _widget_p;
|
||||
std::shared_ptr<LogicalNode> _node_bind;
|
||||
double& _column_width;
|
||||
|
||||
AcceptType _drop_target = AcceptType::NONE;
|
||||
|
||||
public:
|
||||
NodePresent(QWidget* pwidget, double& width_bind, std::shared_ptr<LogicalNode> bind);
|
||||
NodePresent(BehaviorsPresent* pwidget, double& width_bind, std::shared_ptr<LogicalNode> 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<BehaviorMapNode> _bind_maproot = nullptr;
|
||||
|
||||
public:
|
||||
uint64_t _node_id_max = 0;
|
||||
BehaviorsPresent(QWidget* parent = nullptr);
|
||||
|
||||
/// <summary>
|
||||
|
|
Loading…
Reference in New Issue