427 lines
13 KiB
C++
427 lines
13 KiB
C++
#include "ui/ModelBrowser/ModelTreeWidget.h"
|
||
|
||
#include <QResizeEvent>
|
||
#include <QUuid>
|
||
#include <QVariant>
|
||
#include <QMenu>
|
||
|
||
#include <osgEarthUtil/EarthManipulator>
|
||
|
||
#include "common/RecourceHelper.h"
|
||
#include "common/SpdLogger.h"
|
||
#include "entities/EntitiesManager.h"
|
||
#include "entities/ComponentFactory.h"
|
||
#include "viewer/OsgViewer.h"
|
||
#include "viewer/OsgView.h"
|
||
#include "viewer/OsgCameraManipulator.h"
|
||
#include "viewer/CameraControlManipulator.h"
|
||
#include "ui/ModelBrowser/EntityConstent.h"
|
||
#include "workspace/WorkSpaceManager.h"
|
||
|
||
|
||
ModelTreeWidget::ModelTreeWidget(QWidget* parent)
|
||
: QTreeWidget(parent){
|
||
setColumnCount(1);
|
||
connect(this, &QTreeWidget::itemClicked, this, &ModelTreeWidget::OnWorkItemCliecked);
|
||
connect(this, &QTreeWidget::itemDoubleClicked, this, &ModelTreeWidget::OnItemDoubleClicked);
|
||
}
|
||
|
||
ModelTreeWidget::~ModelTreeWidget() {
|
||
}
|
||
|
||
void ModelTreeWidget::OnWorkspaceChange(WorkSpace* workSpace) {
|
||
LOG_INFO("WorkSpace change");
|
||
|
||
clear();
|
||
|
||
currentWorkSpace_ = workSpace;
|
||
if (nullptr == currentWorkSpace_) {
|
||
LOG_WARN("workspace is nullptr");
|
||
return;
|
||
}
|
||
|
||
connect(workSpace, &WorkSpace::EntityAdded, this, &ModelTreeWidget::OnEntityAdded);
|
||
connect(workSpace, &WorkSpace::EntityRemoved, this, &ModelTreeWidget::OnEntityRemoved);
|
||
connect(workSpace, &WorkSpace::FilesChanged, this, &ModelTreeWidget::OnWorkspaceFilesChanged);
|
||
|
||
const QString& name = currentWorkSpace_->GetName();
|
||
root_ = new QTreeWidgetItem(this);
|
||
root_->setText(0, name);
|
||
QVariant root;
|
||
root.setValue(currentWorkSpace_);
|
||
root_->setData(0, E_Workspace, root);
|
||
root_->setData(0, E_UUid, currentWorkSpace_->GetUUid());
|
||
addTopLevelItem(root_);
|
||
|
||
const std::vector<Entity*>& entities = currentWorkSpace_->GetEntities();
|
||
for (const auto& entity : entities) {
|
||
AddEntity(root_, entity);
|
||
}
|
||
|
||
// Create and populate curve entries branch
|
||
curvesRoot_ = new QTreeWidgetItem(root_);
|
||
curvesRoot_->setText(0, tr("Curves"));
|
||
curvesRoot_->setData(0, E_UUid, QString("CurvesRoot"));
|
||
PopulateCurveEntries();
|
||
}
|
||
|
||
void ModelTreeWidget::OnEntityAdded(Entity* entity) {
|
||
if (nullptr == entity) {
|
||
LOG_WARN("entity is nullptr");
|
||
return;
|
||
}
|
||
|
||
const QString& entityName = entity->GetName();
|
||
|
||
QTreeWidgetItem* item = new QTreeWidgetItem;
|
||
connect(entity, &Entity::NameChanged, [item](const QString& name) {
|
||
LOG_WARN("entity name changed: {}", name.toStdString());
|
||
item->setText(0, name);
|
||
}
|
||
);
|
||
item->setText(0, entityName);
|
||
QVariant root;
|
||
root.setValue(entity);
|
||
item->setData(0, E_Entity, root);
|
||
item->setData(0, E_UUid, entity->GetUUid());
|
||
root_->addChild(item);
|
||
}
|
||
|
||
void ModelTreeWidget::OnEntityRemoved(Entity* entity) {
|
||
if (nullptr == entity) {
|
||
LOG_WARN("entity is nullptr");
|
||
return;
|
||
}
|
||
|
||
const QString& uuid = entity->GetUUid();
|
||
FindAndRemoveItem(uuid);
|
||
}
|
||
|
||
void ModelTreeWidget::contextMenuEvent(QContextMenuEvent* event) {
|
||
QTreeWidgetItem* item = itemAt(event->pos());
|
||
if (nullptr != item) {
|
||
QVariant value = item->data(0, E_Entity);
|
||
if (!value.isValid()) {
|
||
LOG_WARN("unknown data E_Entity");
|
||
return;
|
||
}
|
||
|
||
Entity* entity = value.value<Entity*>();
|
||
PopupEntityMenu(event, entity);
|
||
} else {
|
||
return;
|
||
QMenu menu(this);
|
||
|
||
QAction* addEntiy = new QAction(tr("Add boke Entity"), this);
|
||
connect(addEntiy, &QAction::triggered, [this]() {
|
||
OnAddMeshEntity("boke/boke.ive", "boke");
|
||
}
|
||
);
|
||
menu.addAction(addEntiy);
|
||
|
||
addEntiy = new QAction(tr("Add lsjhqt Entity"), this);
|
||
connect(addEntiy, &QAction::triggered, [this]() {
|
||
OnAddMeshEntity("lsjhqt/lsjhqt.flt", "lsjhqt");
|
||
}
|
||
);
|
||
menu.addAction(addEntiy);
|
||
|
||
addEntiy = new QAction(tr("Add nimizi Entity"), this);
|
||
connect(addEntiy, &QAction::triggered, [this]() {
|
||
OnAddMeshEntity("nimizi/nimizi.ive", "nimizi");
|
||
}
|
||
);
|
||
menu.addAction(addEntiy);
|
||
|
||
addEntiy = new QAction(tr("Add tkdlj Entity"), this);
|
||
connect(addEntiy, &QAction::triggered, [this]() {
|
||
OnAddMeshEntity("tkdlj/tkdlj.ive", "tkdlj");
|
||
}
|
||
);
|
||
menu.addAction(addEntiy);
|
||
|
||
addEntiy = new QAction(tr("Add jiaofan Entity"), this);
|
||
connect(addEntiy, &QAction::triggered, [this]() {
|
||
OnAddMeshEntity("jf/decorative-shape-008.obj", "jiaofan");
|
||
}
|
||
);
|
||
menu.addAction(addEntiy);
|
||
|
||
addEntiy = new QAction(tr("Add satellite Entity"), this);
|
||
connect(addEntiy, &QAction::triggered, [this]() {
|
||
OnAddSatelliteEntity();
|
||
}
|
||
);
|
||
menu.addAction(addEntiy);
|
||
|
||
// <20><>ʾ<EFBFBD>˵<EFBFBD>
|
||
menu.exec(event->globalPos());
|
||
}
|
||
|
||
}
|
||
|
||
void ModelTreeWidget::OnWorkItemChanged(WorkSpaceItem* item) {
|
||
LOG_INFO("WorkItemChanged");
|
||
if (nullptr == item) {
|
||
LOG_WARN("item is nullptr");
|
||
return;
|
||
}
|
||
|
||
}
|
||
|
||
void ModelTreeWidget::OnWorkItemCliecked(QTreeWidgetItem* item, int column) {
|
||
// Prefer entity, then file entry, then workspace
|
||
QVariant value = item->data(column, E_Entity);
|
||
if (value.isValid()) { emit EntityChange(value); return; }
|
||
|
||
value = item->data(column, E_FileEntry);
|
||
if (value.isValid()) { emit FileEntryChange(value); return; }
|
||
|
||
value = item->data(column, E_Workspace);
|
||
if (value.isValid()) { emit WorkSpaceChange(value); return; }
|
||
|
||
LOG_WARN("unknown data rol");
|
||
}
|
||
|
||
void ModelTreeWidget::OnItemDoubleClicked(QTreeWidgetItem* item, int column) {
|
||
QVariant value = item->data(column, E_Entity);
|
||
bool isEntity = true;
|
||
if (!value.isValid()) {
|
||
LOG_WARN("unknown data E_Entity");
|
||
return;
|
||
}
|
||
|
||
Entity* entity = value.value<Entity*>();
|
||
if (nullptr == entity) {
|
||
LOG_WARN("entity is nullptr");
|
||
return;
|
||
}
|
||
|
||
OnTrackEntity(entity);
|
||
}
|
||
|
||
void ModelTreeWidget::OnAddMeshEntity(const QString& mesh, const QString& name) {
|
||
if (nullptr == currentWorkSpace_) {
|
||
LOG_WARN("currentWorkSpace_ is nullptr");
|
||
return;
|
||
}
|
||
|
||
Entity* entity = EntitiesManager::Get().CreateMesh(mesh);
|
||
|
||
int count = currentWorkSpace_->GetEntities().size();
|
||
entity->SetName(QString("%1_%2").arg(name).arg(count));
|
||
currentWorkSpace_->AddEntity(entity);
|
||
|
||
OnAddComponent("LabelComponent", entity);
|
||
}
|
||
|
||
SceneComponent* ModelTreeWidget::OnAddComponent(const QString& typeName, Entity* entity) {
|
||
LOG_INFO("enter, typename:{}", typeName.toStdString().c_str());
|
||
if (nullptr == entity) {
|
||
LOG_WARN("entity is nullptr");
|
||
return nullptr;
|
||
}
|
||
|
||
SceneComponent* rootComponent = entity->GetRootComponent();
|
||
SceneComponent* conponent = ComponentFactory::Create(typeName, rootComponent);
|
||
conponent->AttachTo(rootComponent);
|
||
//conponent->AttachEntity(entity);
|
||
|
||
QVariant value;
|
||
value.setValue(entity);
|
||
emit EntityChange(value);
|
||
return conponent;
|
||
}
|
||
|
||
void ModelTreeWidget::OnDeleteEntity(Entity* entity) {
|
||
LOG_INFO("enter");
|
||
if (nullptr == entity) {
|
||
LOG_WARN("entity is nullptr");
|
||
return;
|
||
}
|
||
|
||
entity->Destory();
|
||
}
|
||
|
||
void ModelTreeWidget::PopupEntityMenu(QContextMenuEvent* event, Entity* entity) {
|
||
QMenu menu(this);
|
||
|
||
if (nullptr != entity) {
|
||
auto workspace = entity->GetWorkspace();
|
||
if (nullptr == workspace) {
|
||
LOG_WARN("workspace is nullptr");
|
||
return;
|
||
}
|
||
|
||
if (workspace->GetTrackEntity() == entity) {
|
||
QAction* releaseTrack = new QAction(tr("Release Track"), this);
|
||
connect(releaseTrack, &QAction::triggered, [this]() {
|
||
OnTrackEntity(nullptr);
|
||
}
|
||
);
|
||
menu.addAction(releaseTrack);
|
||
}
|
||
else {
|
||
QAction* addEntiy = new QAction(tr("Track"), this);
|
||
menu.addAction(addEntiy);
|
||
connect(addEntiy, &QAction::triggered, [this, entity]() {
|
||
OnTrackEntity(entity);
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
bool hasLableComponent = entity->HasComponent("LabelComponent");
|
||
if (!hasLableComponent) {
|
||
QAction* addEntiy = new QAction(tr("Add Label Component"), this);
|
||
menu.addAction(addEntiy);
|
||
connect(addEntiy, &QAction::triggered, [this, entity]() {
|
||
OnAddComponent("LabelComponent", entity);
|
||
}
|
||
);
|
||
}
|
||
|
||
bool hasMeshComponent = entity->HasComponent("MeshComponent");
|
||
if (!hasMeshComponent) {
|
||
QAction* addEntiy = new QAction(tr("Add Mesh Component"), this);
|
||
menu.addAction(addEntiy);
|
||
connect(addEntiy, &QAction::triggered, [this, entity]() {
|
||
OnAddComponent("MeshComponent", entity);
|
||
}
|
||
);
|
||
}
|
||
|
||
bool hasPathComponent = entity->HasComponent("PathComponent");
|
||
if (!hasPathComponent) {
|
||
QAction* addEntiy = new QAction(tr("Add Path Component"), this);
|
||
menu.addAction(addEntiy);
|
||
connect(addEntiy, &QAction::triggered, [this, entity]() {
|
||
OnAddComponent("PathComponent", entity);
|
||
}
|
||
);
|
||
}
|
||
|
||
QAction* addEntiy = new QAction(tr("Delete"), this);
|
||
menu.addAction(addEntiy);
|
||
connect(addEntiy, &QAction::triggered, [this, entity]() {
|
||
OnDeleteEntity(entity);
|
||
}
|
||
);
|
||
|
||
menu.exec(event->globalPos());
|
||
}
|
||
|
||
void ModelTreeWidget::FindAndRemoveItem(const QString& itemToRemove) {
|
||
for (int i = 0; i < topLevelItemCount(); ++i) {
|
||
QTreeWidgetItem* topItem = topLevelItem(i);
|
||
if (RemoveItemFromParent(topItem, itemToRemove)) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
bool ModelTreeWidget::RemoveItemFromParent(QTreeWidgetItem* parentItem, const QString& itemToRemove) {
|
||
for (int i = 0; i < parentItem->childCount(); ++i) {
|
||
QTreeWidgetItem* childItem = parentItem->child(i);
|
||
const QString uuid = childItem->data(0, E_UUid).toString();
|
||
if (uuid == itemToRemove) {
|
||
while (childItem->childCount() > 0) {
|
||
QTreeWidgetItem* grandChildItem = childItem->child(0);
|
||
childItem->removeChild(grandChildItem);
|
||
}
|
||
|
||
parentItem->removeChild(childItem);
|
||
return true;
|
||
}
|
||
|
||
if (RemoveItemFromParent(childItem, itemToRemove)) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void ModelTreeWidget::OnAddSatelliteEntity() {
|
||
if (nullptr == currentWorkSpace_) {
|
||
LOG_WARN("currentWorkSpace_ is nullptr");
|
||
return;
|
||
}
|
||
|
||
//const QString mesh("sat/sat.ive");
|
||
const QString mesh("satellite/satellite.ive");
|
||
Entity* entity = EntitiesManager::Get().CreateMesh(mesh);
|
||
int count = currentWorkSpace_->GetEntities().size();
|
||
entity->SetName(QString("%1_%2").arg("satellite").arg(count));
|
||
OnAddComponent("ConeWaveComponent", entity);
|
||
currentWorkSpace_->AddEntity(entity);
|
||
}
|
||
|
||
void ModelTreeWidget::OnTrackEntity(Entity* entity) {
|
||
auto workspace = WorkSpaceManager::Get().GetCurrent();
|
||
if (!workspace){
|
||
LOG_WARN("scene is nullptr");
|
||
return;
|
||
}
|
||
|
||
if (nullptr == entity) {
|
||
LOG_INFO("clear track entity");
|
||
workspace->UntrackEntity();
|
||
return;
|
||
}
|
||
|
||
LOG_INFO("track entity: {}", entity->GetName().toStdString());
|
||
workspace->TrackEntity(entity);
|
||
}
|
||
|
||
void ModelTreeWidget::AddEntity(class QTreeWidgetItem* parent, Entity* entity) {
|
||
const QString& entityName = entity->GetName();
|
||
|
||
QTreeWidgetItem* item = new QTreeWidgetItem;
|
||
connect(entity, &Entity::NameChanged, [item](const QString& name) {
|
||
LOG_WARN("entity name changed: {}", name.toStdString());
|
||
item->setText(0, name);
|
||
}
|
||
);
|
||
item->setText(0, entityName);
|
||
QVariant root;
|
||
root.setValue(entity);
|
||
item->setData(0, E_Entity, root);
|
||
item->setData(0, E_UUid, entity->GetUUid());
|
||
parent->addChild(item);
|
||
|
||
const std::vector<Entity*>& childer = entity->GetChilder();
|
||
for (const auto& child : childer) {
|
||
AddEntity(item, child);
|
||
}
|
||
}
|
||
|
||
void ModelTreeWidget::PopulateCurveEntries() {
|
||
if (!currentWorkSpace_ || !curvesRoot_) return;
|
||
|
||
// Clear existing curve children
|
||
while (curvesRoot_->childCount() > 0) {
|
||
QTreeWidgetItem* child = curvesRoot_->child(0);
|
||
curvesRoot_->removeChild(child);
|
||
delete child;
|
||
}
|
||
|
||
const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Curve);
|
||
for (const auto& entry : entries) {
|
||
if (!entry) continue;
|
||
QTreeWidgetItem* item = new QTreeWidgetItem;
|
||
item->setText(0, entry->GetName());
|
||
QVariant v;
|
||
v.setValue(entry.get());
|
||
item->setData(0, E_FileEntry, v);
|
||
item->setData(0, E_UUid, QString("Curve:%1").arg(entry->GetFileName()));
|
||
curvesRoot_->addChild(item);
|
||
}
|
||
}
|
||
|
||
void ModelTreeWidget::OnWorkspaceFilesChanged(FileEntryType type, std::shared_ptr<FileEntry> /*fileEntry*/) {
|
||
if (type == FileEntryType::Curve) {
|
||
PopulateCurveEntries();
|
||
}
|
||
}
|