geopro/src/app/panels/columns/CategorySection.hpp

120 lines
8.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <QStringList>
#include <QWidget>
#include <vector>
#include "interact/SlicePlaneMath.hpp" // geopro::render::interact::SliceAxis
#include "repo/CategoryDescriptor.hpp" // geopro::data::CategoryDescriptor / OpKind / FilterKind
#include "repo/RepoTypes.hpp"
class QTreeWidget;
class QTreeWidgetItem;
class QComboBox;
class QDateEdit;
class QLabel;
class QToolButton;
class QTimer;
class QWidget;
namespace geopro::data {
class DatasetFieldDictionary;
}
namespace geopro::app {
class DateRangeEdit;
class SectionIconBar;
// 单个数据类型大类段spec §7段头标题/折叠 + 段头图标条)+ 段体(折叠筛选行 + 可勾选数据树)。
// 段头图标条由 descriptor.operations(OpKind) 驱动;筛选行由 descriptor.filters(FilterKind) 驱动、默认折叠。
// 勾选数据行 = 渲染(帘面/体素/切片/二维面GenerateVolume 图标据当前勾选源发 generateVolumeRequested。
class CategorySection : public QWidget {
Q_OBJECT
public:
CategorySection(const geopro::data::CategoryDescriptor& desc,
geopro::data::DatasetFieldDictionary* dict, QWidget* parent = nullptr);
// 对象树同源的扁平 GS/TM 节点段体容器分层用Task 12 接入真实结构,当前仅存储)。
void setStructure(const std::vector<geopro::data::StructNode>& nodes);
void setDatasets(const std::vector<geopro::data::DsRow>& rows);
void setChecked(const QString& dsId, bool on); // 按 dsId 勾选/取消(新建切片自动勾选等场景)
// 渲染中:该行复选框替换为等待 spinnerbusy=true/复原false。busy 期间保持勾选、动画由定时器驱动。
void setBusy(const QString& dsId, bool busy);
void clearAllBusy(); // 撤回本段所有 spinner失败兜底
void selectItem(const QString& dsId); // 程序化选中某行(VTK→list 反向联动);空/未找到=清选中
void clearSelection(); // 清本段树选中(信号阻断,不回发 datasetSelected);供跨段全列互斥用
QStringList checkedIds() const { return checkedDsIds(); } // 当前勾选 ds异常显隐同步用
void refreshArrayFilter() { refreshArrayCombo(); } // 装置枚举异步加载后重填下拉
bool isExpanded() const; // 段头展开态(供外层按折叠状态重分配 stretch实现"折叠向上收"
void ensureExpanded(); // 展开本段(折叠则展开):滚动定位前确保目标行可见
QTreeWidget* listWidget() const { return list_; } // 段体树(外层滚动定位用)
QTreeWidgetItem* itemFor(const QString& dsId) const; // 按 dsId 取行(无则 nullptr
// 该 ds 所在层级子树的全部 dsId贴合坐标轴子树盒spec §2/§3.2 决策 3先归一到子树根
// (向上找最高非容器祖先=三维体行),再自根向下收集整棵子树(体+切片+异常)的非空 dsId。
// 故选中体/切片/异常都归到同一个「该体子树」盒。dsId 不在本段则返回空。
QStringList subtreeDsIds(const QString& dsId) const;
bool hasRenderableRows() const; // 段体是否含可渲染数据行(非 container 容器节点),供单列动态显隐
protected:
// 段体树 viewport 事件过滤:在默认处理改选之前记录「按下瞬间该行是否已选中」,供单击已选行的 toggle 取消判定。
bool eventFilter(QObject* obj, QEvent* ev) override;
signals:
void checkedDatasetsChanged(const QStringList& dsIds); // 数据行勾选=渲染
void collapsedChanged(); // 折叠/展开切换 → 外层 CategoryAnalysisTab 重排各段 stretch
void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds); // 段头「+新增三维体」(接收方按 sourceIds 解析类型)
void planeZChanged(const QString& typeId, double z); // PlaneZ 滑块:整体升降该 2D 类型平面z=绝对高程,米)
void basemapKindChanged(const QString& typeId, int kind); // 底图弹窗:矢量平面(0)/无(1)
void basemapOpacityChanged(const QString& typeId, double o); // 底图弹窗透明度滑块[0,1](防抖发射)
void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); // 右键「详情」=属性弹窗
// 双击某行决策6/T4适配相机到该 ds 子树空间范围 + 联动中下方详情面板(无详情页类型静默)。
// 与 detailRequested右键属性弹窗分开使双击「只适配 + 图表联动」,三维体等无图表页时静默。
void datasetActivated(const QString& dsId, const QString& ddCode, const QString& name);
void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除(切片/异常)
// ── 三维体段右键操作(迁自旧 Column3DAnalysis全接──
void sliceRequested(geopro::render::interact::SliceAxis axis, const QString& volumeDsId); // 体→生成切片(轴+目标体)
void colorScaleRequested(const QString& dsId); // 体/切片→色阶
void radarGainModeRequested(const QString& dsId, int mode); // 雷达体→显示增益模式(0关/1AGC/2保幅tpow)
void sliceSaveRequested(const QString& dsId); // 切片→保存位姿
void sliceSaveAsRequested(const QString& dsId); // 切片→另存
void sliceExportImageRequested(const QString& dsId); // 切片→导出图片
void sliceExportDatRequested(const QString& dsId); // 切片→导出 dat
void anomalyVisibilityChanged(const QString& dsId, bool vis); // 异常→显示/隐藏
void datasetSelected(const QString& dsId, const QString& ddCode); // 树选中行→VTK 高亮联动(切片/异常)
private:
void showContextMenu(const QPoint& pos); // 段体树右键菜单(详情 + 删除)
void showPlaneZPopup(QToolButton* host); // PlaneZ 图标:弹 z 值滑块 popup → planeZChanged
void showBasemapPopup(QToolButton* host); // Basemap 图标:弹 矢量平面/无 + 透明度滑块 popup
void rebuildList(); // 据 rows_经装置/日期筛选)重建段体树并复原勾选
void refreshArrayCombo(); // 据当前 rows_ 重填装置类型下拉项(经字典 value→中文
void emitChecked(); // 收集勾选 → checkedDatasetsChanged
QStringList checkedDsIds() const;
bool passesFilters(const geopro::data::DsRow& row) const; // 装置类型 + 采集时间范围
geopro::data::CategoryDescriptor desc_;
geopro::data::DatasetFieldDictionary* dict_ = nullptr;
std::vector<geopro::data::DsRow> rows_;
std::vector<geopro::data::StructNode> structure_;
QToolButton* header_ = nullptr; // 折叠头(标题 + 箭头)
SectionIconBar* iconBar_ = nullptr; // 段头响应式图标条(由 desc_.operations 装配)
QWidget* body_ = nullptr; // 段体容器(折叠时隐藏)
QWidget* filterRow_ = nullptr; // 筛选行容器(默认折叠,由 Filter 图标 toggle
QComboBox* arrayCombo_ = nullptr; // 装置类型筛选(仅 desc_.filters 含 ArrayType
DateRangeEdit* dateRange_ = nullptr; // 采集时间范围筛选(起止双日历,可清空)
QTreeWidget* list_ = nullptr;
QTimer* spinTimer_ = nullptr; // 驱动 busy 行 spinner 旋转(有 busy 行时运行)
int spinAngle_ = 0; // 当前 spinner 角度(度)
double lastPlaneZ_ = 0.0; // 上次 z 值滑块设定的平面高程(重开 popup 时回显,无则 0直接平移故无防抖
int lastBasemapKind_ = 0; // 上次底图选择0=矢量平面/1=无),重开 popup 时回显
int lastBasemapOpacity_ = 50; // 上次底图透明度0100重开 popup 回显;默认 50
QTimer* basemapOpacityTimer_ = nullptr; // 底图透明度滑块发射防抖(透明度改动会触发瓦片重铺,仍需防抖)
double pendingBasemapOpacity_ = 0.5; // 防抖待发的底图透明度[0,1](定时器到点发射 basemapOpacityChanged
// 单击已选行取消选中toggle-offeventFilter 于按下瞬间(默认改选前)记录被按行及其选中态itemClicked 据此取消。
QTreeWidgetItem* pressedItem_ = nullptr; // 本次左键按下的行itemAt(press),与 itemClicked 的行比对)
bool pressedSelected_ = false; // 按下瞬间该行是否已选中true 且非勾选框点击时,单击取消选中)
bool checkToggledThisPress_ = false; // 本次按下是否切换了勾选框(点勾选框只改渲染,不取消选中)
};
} // namespace geopro::app