From 6e63251b279a49d0dede3e7e783fe1f018b1fd57 Mon Sep 17 00:00:00 2001 From: brige Date: Sun, 9 Nov 2025 13:18:21 +0800 Subject: [PATCH] modify proptry browser --- src/ui/MainWindow.cpp | 1 + src/ui/ModelBrowser.cpp | 1 + src/ui/ModelBrowser.h | 1 + src/ui/ModelBrowser/EntityConstent.h | 3 +- src/ui/ModelBrowser/ModelTreeWidget.cpp | 188 +++++++++++- src/ui/ModelBrowser/ModelTreeWidget.h | 11 + src/ui/PropertyBrowser.cpp | 381 +++++++++++++++++++++++- src/ui/PropertyBrowser.h | 7 + src/workspace/WorkSpace.cpp | 8 +- 9 files changed, 584 insertions(+), 17 deletions(-) diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index 9c6bc50d..570c12a2 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -104,6 +104,7 @@ void MainWindow::InitUI() { connect(modelBrowser_, &ModelBrowser::WorkSpaceChange, propertyBrowser_, &PropertyBrowser::OnWorkSpaceChange); connect(modelBrowser_, &ModelBrowser::EntityChange, propertyBrowser_, &PropertyBrowser::OnEntityChange); connect(modelBrowser_, &ModelBrowser::FileEntryChange, propertyBrowser_, &PropertyBrowser::OnFileEntryChange); + connect(modelBrowser_, &ModelBrowser::GroupChange, propertyBrowser_, &PropertyBrowser::OnGroupChange); qtOsgViewWidget_ = new OsgWidget; qtOsgViewWidget_->Initialize(); diff --git a/src/ui/ModelBrowser.cpp b/src/ui/ModelBrowser.cpp index 8bf5d1b4..3ed28ba8 100644 --- a/src/ui/ModelBrowser.cpp +++ b/src/ui/ModelBrowser.cpp @@ -47,4 +47,5 @@ void ModelBrowser::InitUI() { connect(treeWidget_, &ModelTreeWidget::WorkSpaceChange, this, &ModelBrowser::WorkSpaceChange); connect(treeWidget_, &ModelTreeWidget::EntityChange, this, &ModelBrowser::EntityChange); connect(treeWidget_, &ModelTreeWidget::FileEntryChange, this, &ModelBrowser::FileEntryChange); + connect(treeWidget_, &ModelTreeWidget::GroupChange, this, &ModelBrowser::FileEntryChange); } diff --git a/src/ui/ModelBrowser.h b/src/ui/ModelBrowser.h index 80203b6f..48e9c109 100644 --- a/src/ui/ModelBrowser.h +++ b/src/ui/ModelBrowser.h @@ -15,6 +15,7 @@ Q_SIGNALS: void WorkSpaceChange(const QVariant& workSpace); void EntityChange(const QVariant& workSpace); void FileEntryChange(const QVariant& fileEntry); + void GroupChange(const QVariant& group); private: void InitUI(); diff --git a/src/ui/ModelBrowser/EntityConstent.h b/src/ui/ModelBrowser/EntityConstent.h index ecbc6bda..1478ffc8 100644 --- a/src/ui/ModelBrowser/EntityConstent.h +++ b/src/ui/ModelBrowser/EntityConstent.h @@ -6,5 +6,6 @@ enum ItemRol { E_Workspace = Qt::ItemDataRole::UserRole + 1, E_Entity, E_UUid, - E_FileEntry + E_FileEntry, + E_Group }; diff --git a/src/ui/ModelBrowser/ModelTreeWidget.cpp b/src/ui/ModelBrowser/ModelTreeWidget.cpp index 9841d666..e1d244f0 100644 --- a/src/ui/ModelBrowser/ModelTreeWidget.cpp +++ b/src/ui/ModelBrowser/ModelTreeWidget.cpp @@ -61,8 +61,52 @@ void ModelTreeWidget::OnWorkspaceChange(WorkSpace* workSpace) { // Create and populate curve entries branch curvesRoot_ = new QTreeWidgetItem(root_); curvesRoot_->setText(0, tr("Curves")); + QVariant vCurves; + vCurves.setValue(QString("Curves")); + curvesRoot_->setData(0, E_Group, vCurves); curvesRoot_->setData(0, E_UUid, QString("CurvesRoot")); PopulateCurveEntries(); + + // Create and populate other file type branches + surfacesRoot_ = new QTreeWidgetItem(root_); + surfacesRoot_->setText(0, tr("Surfaces")); + QVariant vSurfaces; + vSurfaces.setValue(QString("Surfaces")); + curvesRoot_->setData(0, E_Group, vSurfaces); + surfacesRoot_->setData(0, E_UUid, QString("SurfacesRoot")); + PopulateSurfaceEntries(); + + tablesRoot_ = new QTreeWidgetItem(root_); + tablesRoot_->setText(0, tr("Tables")); + QVariant vTables; + vTables.setValue(QString("Tables")); + tablesRoot_->setData(0, E_Group, vTables); + tablesRoot_->setData(0, E_UUid, QString("TablesRoot")); + PopulateTableEntries(); + + lightsRoot_ = new QTreeWidgetItem(root_); + lightsRoot_->setText(0, tr("Lights")); + QVariant vLights; + vLights.setValue(QString("Lights")); + lightsRoot_->setData(0, E_Group, vLights); + lightsRoot_->setData(0, E_UUid, QString("LightsRoot")); + PopulateLightEntries(); + + polarsRoot_ = new QTreeWidgetItem(root_); + polarsRoot_->setText(0, tr("Polars")); + QVariant vPolars; + vPolars.setValue(QString("Lights")); + polarsRoot_->setData(0, E_Group, vPolars); + polarsRoot_->setData(0, E_UUid, QString("PolarsRoot")); + PopulatePolarEntries(); + + imagesRoot_ = new QTreeWidgetItem(root_); + imagesRoot_->setText(0, tr("Images")); + QVariant vImages; + vImages.setValue(QString("Images")); + imagesRoot_->setData(0, E_Group, vImages); + imagesRoot_->setData(0, E_UUid, QString("PolarsRoot")); + PopulateImageEntries(); } void ModelTreeWidget::OnEntityAdded(Entity* entity) { @@ -154,7 +198,6 @@ void ModelTreeWidget::contextMenuEvent(QContextMenuEvent* event) { ); menu.addAction(addEntiy); - // ��ʾ�˵� menu.exec(event->globalPos()); } @@ -172,13 +215,28 @@ void ModelTreeWidget::OnWorkItemChanged(WorkSpaceItem* item) { 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; } + if (value.isValid()) { + emit EntityChange(value); + return; + } value = item->data(column, E_FileEntry); - if (value.isValid()) { emit FileEntryChange(value); return; } + if (value.isValid()) { + emit FileEntryChange(value); + return; + } value = item->data(column, E_Workspace); - if (value.isValid()) { emit WorkSpaceChange(value); return; } + if (value.isValid()) { + emit WorkSpaceChange(value); + return; + } + + value = item->data(column, E_Group); + if (value.isValid()) { + emit GroupChange(value); + return; + } LOG_WARN("unknown data rol"); } @@ -419,8 +477,124 @@ void ModelTreeWidget::PopulateCurveEntries() { } } -void ModelTreeWidget::OnWorkspaceFilesChanged(FileEntryType type, std::shared_ptr /*fileEntry*/) { - if (type == FileEntryType::Curve) { - PopulateCurveEntries(); +void ModelTreeWidget::PopulateSurfaceEntries() { + if (!currentWorkSpace_ || !surfacesRoot_) return; + + while (surfacesRoot_->childCount() > 0) { + QTreeWidgetItem* child = surfacesRoot_->child(0); + surfacesRoot_->removeChild(child); + delete child; + } + + const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Surface); + 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("Surface:%1").arg(entry->GetFileName())); + surfacesRoot_->addChild(item); + } +} + +void ModelTreeWidget::PopulateTableEntries() { + if (!currentWorkSpace_ || !tablesRoot_) return; + + while (tablesRoot_->childCount() > 0) { + QTreeWidgetItem* child = tablesRoot_->child(0); + tablesRoot_->removeChild(child); + delete child; + } + + const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Table); + 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("Table:%1").arg(entry->GetFileName())); + tablesRoot_->addChild(item); + } +} + +void ModelTreeWidget::PopulateLightEntries() { + if (!currentWorkSpace_ || !lightsRoot_) return; + + while (lightsRoot_->childCount() > 0) { + QTreeWidgetItem* child = lightsRoot_->child(0); + lightsRoot_->removeChild(child); + delete child; + } + + const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Light); + 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("Light:%1").arg(entry->GetFileName())); + lightsRoot_->addChild(item); + } +} + +void ModelTreeWidget::PopulatePolarEntries() { + if (!currentWorkSpace_ || !polarsRoot_) return; + + while (polarsRoot_->childCount() > 0) { + QTreeWidgetItem* child = polarsRoot_->child(0); + polarsRoot_->removeChild(child); + delete child; + } + + const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Polar); + 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("Polar:%1").arg(entry->GetFileName())); + polarsRoot_->addChild(item); + } +} + +void ModelTreeWidget::PopulateImageEntries() { + if (!currentWorkSpace_ || !imagesRoot_) return; + + while (imagesRoot_->childCount() > 0) { + QTreeWidgetItem* child = imagesRoot_->child(0); + imagesRoot_->removeChild(child); + delete child; + } + + const auto entries = currentWorkSpace_->GetFileEntries(FileEntryType::Image); + 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("Image:%1").arg(entry->GetFileName())); + imagesRoot_->addChild(item); + } +} + +void ModelTreeWidget::OnWorkspaceFilesChanged(FileEntryType type, std::shared_ptr /*fileEntry*/) { + switch (type) { + case FileEntryType::Curve: PopulateCurveEntries(); break; + case FileEntryType::Surface: PopulateSurfaceEntries(); break; + case FileEntryType::Table: PopulateTableEntries(); break; + case FileEntryType::Light: PopulateLightEntries(); break; + case FileEntryType::Polar: PopulatePolarEntries(); break; + case FileEntryType::Image: PopulateImageEntries(); break; + default: break; } } diff --git a/src/ui/ModelBrowser/ModelTreeWidget.h b/src/ui/ModelBrowser/ModelTreeWidget.h index b0618651..753add93 100644 --- a/src/ui/ModelBrowser/ModelTreeWidget.h +++ b/src/ui/ModelBrowser/ModelTreeWidget.h @@ -24,6 +24,7 @@ Q_SIGNALS: void WorkSpaceChange(const QVariant& workSpace); void EntityChange(const QVariant& entity); void FileEntryChange(const QVariant& fileEntry); + void GroupChange(const QVariant& group); protected: void contextMenuEvent(QContextMenuEvent* event) override; @@ -52,9 +53,19 @@ private: //void initUI(); void AddEntity(class QTreeWidgetItem* parent, Entity* entity); void PopulateCurveEntries(); + void PopulateSurfaceEntries(); + void PopulateTableEntries(); + void PopulateLightEntries(); + void PopulatePolarEntries(); + void PopulateImageEntries(); private: WorkSpace* currentWorkSpace_{ nullptr }; QTreeWidgetItem* root_{ nullptr }; QTreeWidgetItem* curvesRoot_{ nullptr }; + QTreeWidgetItem* surfacesRoot_{ nullptr }; + QTreeWidgetItem* tablesRoot_{ nullptr }; + QTreeWidgetItem* lightsRoot_{ nullptr }; + QTreeWidgetItem* polarsRoot_{ nullptr }; + QTreeWidgetItem* imagesRoot_{ nullptr }; }; \ No newline at end of file diff --git a/src/ui/PropertyBrowser.cpp b/src/ui/PropertyBrowser.cpp index f773d71b..64dfbc56 100644 --- a/src/ui/PropertyBrowser.cpp +++ b/src/ui/PropertyBrowser.cpp @@ -11,6 +11,7 @@ #include "DockTitleBar.h" #include "DockWidget.h" #include "workspace/WorkSpace.h" +#include "workspace/WorkSpaceManager.h" #include "entities/Entity.h" #include "entities/MeshComponent.h" @@ -47,14 +48,21 @@ void PropertyBrowser::OnWorkSpaceChange(const QVariant& value) { WorkSpace* workspace = value.value(); if (nullptr == workspace) { LOG_WARN("workspace is nullptr"); + // 如果没有属性对象,清空属性面板 + browser_->clear(); + propertyToId_.clear(); + idToProperty_.clear(); + idToExpanded_.clear(); + colorSetters_.clear(); return; } + // 点击根项目需要清空属性面板,不展示工作区属性 browser_->clear(); - // Reset local mappings when workspace changes propertyToId_.clear(); idToProperty_.clear(); idToExpanded_.clear(); + colorSetters_.clear(); QtProperty* property; @@ -63,7 +71,7 @@ void PropertyBrowser::OnWorkSpaceChange(const QVariant& value) { workSpaceManager_->setValue(property, worksapceAttribute); addProperty(property, tr("WorkSpace")); - // Track and react to runtime workspace changes + // 保持对运行时工作区变更的监听(树刷新所需),但属性面板保持清空 if (currentWorkspace_) { QObject::disconnect(currentWorkspace_, nullptr, this, nullptr); } @@ -71,7 +79,7 @@ void PropertyBrowser::OnWorkSpaceChange(const QVariant& value) { QObject::connect(currentWorkspace_, &WorkSpace::FilesChanged, this, &PropertyBrowser::OnWorkspaceFilesChanged); - // No longer mount file entries under workspace; file entries are handled separately + // 属性面板清空,文件项属性由 FileEntry 点击时单独处理 } void PropertyBrowser::OnEntityChange(const QVariant& value) { @@ -79,6 +87,12 @@ void PropertyBrowser::OnEntityChange(const QVariant& value) { Entity* entity = value.value(); if (nullptr == entity) { LOG_WARN("engity is nullptr"); + // 如果没有属性对象,清空属性面板 + browser_->clear(); + propertyToId_.clear(); + idToProperty_.clear(); + idToExpanded_.clear(); + colorSetters_.clear(); return; } @@ -127,6 +141,13 @@ void PropertyBrowser::OnFileEntryChange(const QVariant& value) { FileEntry* entry = value.value(); if (!entry) { LOG_WARN("file entry is nullptr"); + // 如果没有属性对象,清空属性面板 + inFileEntryView_ = false; + browser_->clear(); + propertyToId_.clear(); + idToProperty_.clear(); + idToExpanded_.clear(); + colorSetters_.clear(); return; } @@ -142,6 +163,345 @@ void PropertyBrowser::OnFileEntryChange(const QVariant& value) { auto curve = entry->AsCurve(); if (!curve) { LOG_WARN("file entry not a curve: %s", entry->GetFileName().toStdString().c_str()); + // 基础信息组 + const QString idBasic = QString("FileEntry:%1").arg(entry->GetFileName()); + const QString titleBasic = QString("File Entry - %1").arg(entry->GetName()); + QtProperty* groupBasic = groupManager_->addProperty(titleBasic); + + QtProperty* typeProp = stringManager_->addProperty(tr("Type")); + stringManager_->setValue(typeProp, QString::fromStdString(FileEntryTypeToString(entry->GetType()))); + groupBasic->addSubProperty(typeProp); + + QtProperty* nameProp = stringManager_->addProperty(tr("Name")); + stringManager_->setValue(nameProp, entry->GetName()); + groupBasic->addSubProperty(nameProp); + + QtProperty* fileProp = stringManager_->addProperty(tr("FileName")); + stringManager_->setValue(fileProp, entry->GetFileName()); + groupBasic->addSubProperty(fileProp); + + QtProperty* pathProp = stringManager_->addProperty(tr("Path")); + stringManager_->setValue(pathProp, entry->GetPath()); + groupBasic->addSubProperty(pathProp); + + addProperty(groupBasic, idBasic); + + // 类型专属属性显示 + switch (entry->GetType()) { + case FileEntryType::Surface: { + auto surf = entry->AsSurface(); + if (surf) { + const QString idChart = QString("SurfaceChart:%1").arg(entry->GetFileName()); + const QString idItems = QString("SurfaceItems:%1").arg(entry->GetFileName()); + const QString titleChart = QString("Surface Chart - %1").arg(entry->GetName()); + const QString titleItems = QString("Surfaces - %1").arg(entry->GetName()); + + // Chart 属性 + QtProperty* chartGroup = groupManager_->addProperty(titleChart); + const auto& chart = surf->GetChartProperties(); + QtProperty* xCountProp = intManager_->addProperty(tr("xCount")); + intManager_->setValue(xCountProp, chart.xCount); + chartGroup->addSubProperty(xCountProp); + QtProperty* yCountProp = intManager_->addProperty(tr("yCount")); + intManager_->setValue(yCountProp, chart.yCount); + chartGroup->addSubProperty(yCountProp); + QtProperty* zCountProp = intManager_->addProperty(tr("zCount")); + intManager_->setValue(zCountProp, chart.zCount); + chartGroup->addSubProperty(zCountProp); + QtProperty* xTitleProp = stringManager_->addProperty(tr("xTitle")); + stringManager_->setValue(xTitleProp, chart.xTitle); + chartGroup->addSubProperty(xTitleProp); + QtProperty* yTitleProp = stringManager_->addProperty(tr("yTitle")); + stringManager_->setValue(yTitleProp, chart.yTitle); + chartGroup->addSubProperty(yTitleProp); + QtProperty* zTitleProp = stringManager_->addProperty(tr("zTitle")); + stringManager_->setValue(zTitleProp, chart.zTitle); + chartGroup->addSubProperty(zTitleProp); + QtProperty* xMinProp = doubleManager_->addProperty(tr("xMin")); + doubleManager_->setValue(xMinProp, chart.xMin); + chartGroup->addSubProperty(xMinProp); + QtProperty* xMaxProp = doubleManager_->addProperty(tr("xMax")); + doubleManager_->setValue(xMaxProp, chart.xMax); + chartGroup->addSubProperty(xMaxProp); + QtProperty* yMinProp = doubleManager_->addProperty(tr("yMin")); + doubleManager_->setValue(yMinProp, chart.yMin); + chartGroup->addSubProperty(yMinProp); + QtProperty* yMaxProp = doubleManager_->addProperty(tr("yMax")); + doubleManager_->setValue(yMaxProp, chart.yMax); + chartGroup->addSubProperty(yMaxProp); + QtProperty* zMinProp = doubleManager_->addProperty(tr("zMin")); + doubleManager_->setValue(zMinProp, chart.zMin); + chartGroup->addSubProperty(zMinProp); + QtProperty* zMaxProp = doubleManager_->addProperty(tr("zMax")); + doubleManager_->setValue(zMaxProp, chart.zMax); + chartGroup->addSubProperty(zMaxProp); + QtProperty* tProp = doubleManager_->addProperty(tr("timeParam")); + doubleManager_->setValue(tProp, chart.timeParam); + chartGroup->addSubProperty(tProp); + addProperty(chartGroup, idChart); + + // Surface 列表 + QtProperty* itemsGroup = groupManager_->addProperty(titleItems); + const auto& items = surf->GetSurfaceProperties(); + for (int i = 0; i < items.size(); ++i) { + const auto& s = items[i]; + QtProperty* itemGroup = groupManager_->addProperty(QString("Surface[%1]").arg(i)); + QtProperty* nm = stringManager_->addProperty(tr("name")); + stringManager_->setValue(nm, s.name); + itemGroup->addSubProperty(nm); + QtProperty* col = colorManager_->addProperty(tr("color")); + colorManager_->setValue(col, s.color); + itemGroup->addSubProperty(col); + // 写回 Surface 条目颜色 + colorSetters_[col] = [surf, entry, i](const QColor& c){ + auto props = surf->GetSurfaceProperties(); + if (i >= 0 && i < props.size()) { + auto item = props[i]; + item.color = c; + surf->SetSurfaceProperty(i, item); + if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType()); + } + }; + QtProperty* st = intManager_->addProperty(tr("start")); + intManager_->setValue(st, s.start); + itemGroup->addSubProperty(st); + QtProperty* sp = intManager_->addProperty(tr("stop")); + intManager_->setValue(sp, s.stop); + itemGroup->addSubProperty(sp); + QtProperty* x = stringManager_->addProperty(tr("x")); + stringManager_->setValue(x, s.x); + itemGroup->addSubProperty(x); + QtProperty* y = stringManager_->addProperty(tr("y")); + stringManager_->setValue(y, s.y); + itemGroup->addSubProperty(y); + QtProperty* z = stringManager_->addProperty(tr("z")); + stringManager_->setValue(z, s.z); + itemGroup->addSubProperty(z); + itemsGroup->addSubProperty(itemGroup); + } + addProperty(itemsGroup, idItems); + } + break; + } + case FileEntryType::Table: { + auto tbl = entry->AsTable(); + if (tbl) { + const QString idChart = QString("TableChart:%1").arg(entry->GetFileName()); + const QString idItems = QString("TableItems:%1").arg(entry->GetFileName()); + const QString titleChart = QString("Table Chart - %1").arg(entry->GetName()); + const QString titleItems = QString("Tables - %1").arg(entry->GetName()); + + QtProperty* chartGroup = groupManager_->addProperty(titleChart); + const auto& chart = tbl->GetChartProperties(); + QtProperty* headerProp = stringManager_->addProperty(tr("headerString")); + stringManager_->setValue(headerProp, chart.headerString); + chartGroup->addSubProperty(headerProp); + QtProperty* tProp = doubleManager_->addProperty(tr("timeParam")); + doubleManager_->setValue(tProp, chart.timeParam); + chartGroup->addSubProperty(tProp); + addProperty(chartGroup, idChart); + + QtProperty* itemsGroup = groupManager_->addProperty(titleItems); + const auto& items = tbl->GetTableProperties(); + for (int i = 0; i < items.size(); ++i) { + const auto& t = items[i]; + QtProperty* itemGroup = groupManager_->addProperty(QString("Table[%1]").arg(i)); + QtProperty* nm = stringManager_->addProperty(tr("name")); + stringManager_->setValue(nm, t.name); + itemGroup->addSubProperty(nm); + QtProperty* col = colorManager_->addProperty(tr("color")); + colorManager_->setValue(col, t.color); + itemGroup->addSubProperty(col); + // 写回 Table 条目颜色 + colorSetters_[col] = [tbl, entry, i](const QColor& c){ + auto props = tbl->GetTableProperties(); + if (i >= 0 && i < props.size()) { + auto item = props[i]; + item.color = c; + tbl->SetTableProperty(i, item); + if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType()); + } + }; + // datas 展示为拼接字符串 + QStringList values; + for (const auto& v : t.datas) values << QString::number(v); + QtProperty* ds = stringManager_->addProperty(tr("datas")); + stringManager_->setValue(ds, values.join(", ")); + itemGroup->addSubProperty(ds); + itemsGroup->addSubProperty(itemGroup); + } + addProperty(itemsGroup, idItems); + } + break; + } + case FileEntryType::Light: { + auto lt = entry->AsLight(); + if (lt) { + const QString idColor = QString("LightColors:%1").arg(entry->GetFileName()); + const QString idRows = QString("LightRows:%1").arg(entry->GetFileName()); + const QString titleColor = QString("Light Colors - %1").arg(entry->GetName()); + const QString titleRows = QString("Light Rows - %1").arg(entry->GetName()); + + // 颜色与时间 + QtProperty* colorGroup = groupManager_->addProperty(titleColor); + const auto& colorProps = lt->GetColorProperties(); + QtProperty* oc = colorManager_->addProperty(tr("openColor")); + colorManager_->setValue(oc, colorProps.openColor); + colorGroup->addSubProperty(oc); + QtProperty* cc = colorManager_->addProperty(tr("closeColor")); + colorManager_->setValue(cc, colorProps.closeColor); + colorGroup->addSubProperty(cc); + QtProperty* tProp = doubleManager_->addProperty(tr("timeParam")); + doubleManager_->setValue(tProp, colorProps.timeParam); + colorGroup->addSubProperty(tProp); + addProperty(colorGroup, idColor); + // 写回处理:颜色变化更新到 FileEntryLight 并通知 Workspace + colorSetters_[oc] = [lt, entry](const QColor& c){ + auto props = lt->GetColorProperties(); + props.openColor = c; + lt->SetColorProperties(props); + if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType()); + }; + colorSetters_[cc] = [lt, entry](const QColor& c){ + auto props = lt->GetColorProperties(); + props.closeColor = c; + lt->SetColorProperties(props); + if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType()); + }; + + // 行数据 + QtProperty* rowsGroup = groupManager_->addProperty(titleRows); + const auto& rows = lt->GetLightProperties(); + for (int i = 0; i < rows.size(); ++i) { + const auto& r = rows[i]; + QtProperty* row = groupManager_->addProperty(QString("Row[%1]").arg(i)); + QtProperty* names = stringManager_->addProperty(tr("names")); + stringManager_->setValue(names, r.name.join(", ")); + row->addSubProperty(names); + QStringList values; + for (const auto& v : r.data) values << QString::number(v); + QtProperty* ds = stringManager_->addProperty(tr("data")); + stringManager_->setValue(ds, values.join(", ")); + row->addSubProperty(ds); + rowsGroup->addSubProperty(row); + } + addProperty(rowsGroup, idRows); + } + break; + } + case FileEntryType::Polar: { + auto pl = entry->AsPolar(); + if (pl) { + const QString idChart = QString("PolarChart:%1").arg(entry->GetFileName()); + const QString idLines = QString("PolarLines:%1").arg(entry->GetFileName()); + const QString titleChart = QString("Polar Chart - %1").arg(entry->GetName()); + const QString titleLines = QString("Lines - %1").arg(entry->GetName()); + + QtProperty* chartGroup = groupManager_->addProperty(titleChart); + const auto& chart = pl->GetChartProperties(); + auto addInt = [&](const QString& label, int v){ QtProperty* p=intManager_->addProperty(label); intManager_->setValue(p, v); chartGroup->addSubProperty(p); }; + auto addStr = [&](const QString& label, const QString& v){ QtProperty* p=stringManager_->addProperty(label); stringManager_->setValue(p, v); chartGroup->addSubProperty(p); }; + auto addDbl = [&](const QString& label, double v){ QtProperty* p=doubleManager_->addProperty(label); doubleManager_->setValue(p, v); chartGroup->addSubProperty(p); }; + addInt(tr("AngularCount"), chart.AngularCount); + addInt(tr("RadialCount"), chart.RadialCount); + addStr(tr("AngularTitle"), chart.AngularTitle); + addStr(tr("RadialTitle"), chart.RadialTitle); + addDbl(tr("AngularMin"), chart.AngularMin); + addDbl(tr("AngularMax"), chart.AngularMax); + addDbl(tr("RadialMin"), chart.RadialMin); + addDbl(tr("RadialMax"), chart.RadialMax); + addStr(tr("AngularUnit"), chart.AngularUnit); + addStr(tr("RadialUnit"), chart.RadialUnit); + addDbl(tr("timeParam"), chart.timeParam); + addProperty(chartGroup, idChart); + + QtProperty* linesGroup = groupManager_->addProperty(titleLines); + const auto& lines = pl->GetLineProperties(); + for (int i = 0; i < lines.size(); ++i) { + const auto& ln = lines[i]; + QtProperty* line = groupManager_->addProperty(QString("Line[%1]").arg(i)); + QtProperty* nm = stringManager_->addProperty(tr("name")); + stringManager_->setValue(nm, ln.name); + line->addSubProperty(nm); + QtProperty* col = colorManager_->addProperty(tr("color")); + colorManager_->setValue(col, ln.color); + line->addSubProperty(col); + // 写回 Polar 线颜色 + colorSetters_[col] = [pl, entry, i](const QColor& c){ + auto props = pl->GetLineProperties(); + if (i >= 0 && i < props.size()) { + auto item = props[i]; + item.color = c; + pl->SetLineProperty(i, item); + if (auto ws = WorkSpaceManager::Get().GetCurrent()) ws->NotifyFileEntryUpdated(entry->GetType()); + } + }; + QtProperty* ag = intManager_->addProperty(tr("Angular")); + intManager_->setValue(ag, ln.Angular); + line->addSubProperty(ag); + QtProperty* rd = intManager_->addProperty(tr("Radial")); + intManager_->setValue(rd, ln.Radial); + line->addSubProperty(rd); + linesGroup->addSubProperty(line); + } + addProperty(linesGroup, idLines); + } + break; + } + case FileEntryType::Image: { + auto img = entry->AsImage(); + if (img) { + const QString idChart = QString("ImageChart:%1").arg(entry->GetFileName()); + const QString idItems = QString("Images:%1").arg(entry->GetFileName()); + const QString titleChart = QString("Image Chart - %1").arg(entry->GetName()); + const QString titleItems = QString("Image Set - %1").arg(entry->GetName()); + + QtProperty* chartGroup = groupManager_->addProperty(titleChart); + const auto& chart = img->GetChartProperties(); + QtProperty* tProp = doubleManager_->addProperty(tr("timeParam")); + doubleManager_->setValue(tProp, chart.timeParam); + chartGroup->addSubProperty(tProp); + addProperty(chartGroup, idChart); + + QtProperty* itemsGroup = groupManager_->addProperty(titleItems); + const auto& items = img->GetImageProperties(); + for (int i = 0; i < items.size(); ++i) { + const auto& im = items[i]; + QtProperty* item = groupManager_->addProperty(QString("Image[%1]").arg(i)); + QtProperty* names = stringManager_->addProperty(tr("names")); + names->setToolTip(tr("File name list")); + stringManager_->setValue(names, im.names.join(", ")); + item->addSubProperty(names); + QStringList values; + for (const auto& v : im.datas) values << QString::number(v); + QtProperty* ds = stringManager_->addProperty(tr("datas")); + ds->setToolTip(tr("Image data per file")); + stringManager_->setValue(ds, values.join(", ")); + item->addSubProperty(ds); + QtProperty* pth = stringManager_->addProperty(tr("path")); + stringManager_->setValue(pth, im.path); + item->addSubProperty(pth); + QtProperty* sfx = stringManager_->addProperty(tr("suffix")); + stringManager_->setValue(sfx, im.suffix); + item->addSubProperty(sfx); + itemsGroup->addSubProperty(item); + } + addProperty(itemsGroup, idItems); + } + break; + } + default: + break; + } + + // 聚焦基础信息组 + if (groupBasic) { + QtBrowserItem* item = browser_->topLevelItem(groupBasic); + if (item) { + browser_->setExpanded(item, true); + browser_->setCurrentItem(item); + } + } return; } const QString title = QString("CurveEntry - %1").arg(entry->GetName()); @@ -160,6 +520,10 @@ void PropertyBrowser::OnFileEntryChange(const QVariant& value) { } } +void PropertyBrowser::OnGroupChange(const QVariant& value) { + browser_->clear(); +} + void PropertyBrowser::InitUI() { QBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -186,6 +550,7 @@ void PropertyBrowser::InitPropertyManager() { workSpaceManager_ = new QtWorkspacePropertyManager(this); entityManager_ = new QtEntityPropertyManager(this); curveEntryManager_ = new QtCurveEntryPropertyManager(this); + groupManager_ = new QtGroupPropertyManager(this); QtDoubleSpinBoxFactory* doubleSpinBoxFactory = new QtDoubleSpinBoxFactory(this); QtCheckBoxFactory* checkBoxFactory = new QtCheckBoxFactory(this); @@ -200,6 +565,8 @@ void PropertyBrowser::InitPropertyManager() { browser_->setFactoryForManager(boolManager_, checkBoxFactory); browser_->setFactoryForManager(doubleManager_, doubleSpinBoxFactory); browser_->setFactoryForManager(stringManager_, lineEditFactory); + // Color properties: use a color dialog editor for the top-level color, keep sub-channel ints editable + browser_->setFactoryForManager(colorManager_, colorFactory); browser_->setFactoryForManager(colorManager_->subIntPropertyManager(), spinBoxFactory); browser_->setFactoryForManager(fontManager_->subIntPropertyManager(), spinBoxFactory); browser_->setFactoryForManager(fontManager_->subBoolPropertyManager(), checkBoxFactory); @@ -228,6 +595,14 @@ void PropertyBrowser::InitPropertyManager() { browser_->setFactoryForManager(curveEntryManager_->subIntProperyManager(), spinBoxFactory); browser_->setFactoryForManager(curveEntryManager_->subDoubleProperyManager(), doubleSpinBoxFactory); browser_->setFactoryForManager(curveEntryManager_->subColorProperyManager(), colorFactory); + + // 颜色属性变更信号:触发对应写回处理器 + connect(colorManager_, &QtColorPropertyManager::valueChanged, this, + [this](QtProperty* prop, const QColor& color){ + if (colorSetters_.contains(prop)) { + colorSetters_[prop](color); + } + }); } void PropertyBrowser::OnWorkspaceFilesChanged(FileEntryType type, std::shared_ptr fileEntry) { diff --git a/src/ui/PropertyBrowser.h b/src/ui/PropertyBrowser.h index f830dc3e..889b4704 100644 --- a/src/ui/PropertyBrowser.h +++ b/src/ui/PropertyBrowser.h @@ -2,6 +2,8 @@ #include #include +#include +#include #include "workspace/FileEntry.h" class QtProperty; @@ -19,6 +21,7 @@ public: void OnWorkSpaceChange(const QVariant& value); void OnEntityChange(const QVariant& value); void OnFileEntryChange(const QVariant& value); + void OnGroupChange(const QVariant& value); void OnWorkspaceFilesChanged(enum class FileEntryType type, std::shared_ptr fileEntry); void Test(); @@ -47,6 +50,7 @@ private: class QtWorkspacePropertyManager* workSpaceManager_{ nullptr }; class QtEntityPropertyManager* entityManager_{ nullptr }; class QtCurveEntryPropertyManager* curveEntryManager_{ nullptr }; + class QtGroupPropertyManager* groupManager_{ nullptr }; QMap propertyToId_; QMap idToProperty_; @@ -59,5 +63,8 @@ private: // When true, we are showing a single FileEntry view (not workspace-wide groups) bool inFileEntryView_{ false }; + + // Write-back hooks for color properties + QMap> colorSetters_; }; diff --git a/src/workspace/WorkSpace.cpp b/src/workspace/WorkSpace.cpp index 1de08c23..33388b03 100644 --- a/src/workspace/WorkSpace.cpp +++ b/src/workspace/WorkSpace.cpp @@ -147,14 +147,10 @@ bool WorkSpace::SetFileEntryCount(FileEntryType type, int count) { fileEntry = std::make_shared(); break; case FileEntryType::Surface: - // TODO: Create FileEntrySurface when implemented - fileEntry = std::make_shared(); - fileEntry->SetType(FileEntryType::Surface); + fileEntry = std::make_shared(); break; case FileEntryType::Table: - // TODO: Create FileEntryTable when implemented - fileEntry = std::make_shared(); - fileEntry->SetType(FileEntryType::Table); + fileEntry = std::make_shared(); break; case FileEntryType::Light: fileEntry = std::make_shared();