feat: 支持多视图标签页、按文件分组的多文件信号管理与网格随勾选自动收敛
数据层与视图配置解耦:新增 DataSet(多文件只读数据层)与 TabConfig(每标签页独立配置),
以 SignalRef{fileIndex,signalIndex} 标识全局信号,替换原有单文件 SignalSet。
- 标签页:新增 TabBar 组件,支持新建/切换/关闭标签页;每页独立保存信号勾选、
颜色/线宽/显示方式、网格划分、视图范围与时间光标,互不影响。
- 网格收敛:可见性变更统一经 TabConfig 的 Set*Visible 接口并同步重算网格,
取消勾选后对应的空网格立即回收(修复此前留下空轨道的问题)。
- 多文件分组:左侧面板改为「文件分组 + 信号」树形列表,分组可折叠、可整组勾选,
分组复选框支持全选/部分/未选三态;新加载文件的信号默认未勾选,由用户自行选择。
- 来源标识:信号行、样式编辑区标题、波形图例与光标读数在跨文件时标注来源文件名。
- 交互补充:面板滚动条支持点击跳转与拖拽,切换标签页自动滚动到已选信号。
- 工具栏精简为「打开 CSV/适应视图/放大/缩小/合并网格/每信号一格/全选信号/清空勾选」,
按钮宽度改为按实际文本像素测量;打开对话框支持多选文件,拖放支持批量载入。
- 新增 TestData/[2].CSV 作为跨文件对比测试数据。
This commit is contained in:
1 parent
132b305544
commit
9c6c374cce
21 files changed
+4086
-1461
No files matched your search
@@ -8,8 +8,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "DataModel.hpp"
|
||||
#include "PaintUtil.hpp"
|
||||
#include "SignalSet.hpp"
|
||||
#include "Theme.hpp"
|
||||
|
||||
namespace jdi
|
||||
@@ -29,6 +29,9 @@ namespace jdi
|
||||
|
||||
/**
|
||||
* @brief 波形绘图区:网格、时间轴、光标、缩放与自适应。
|
||||
*
|
||||
* 绘图区同时依赖数据层(DataSet,只读)与当前标签页配置(TabConfig,可写),
|
||||
* 视图范围、网格滚动与时间光标均保存在标签页配置中,因此各标签页互不干扰。
|
||||
*/
|
||||
class PlotView
|
||||
{
|
||||
@@ -43,10 +46,11 @@ namespace jdi
|
||||
void Setup(const UiFonts* fonts, const Theme* theme);
|
||||
|
||||
/**
|
||||
* @brief 绑定数据集。
|
||||
* @param [IN] document 数据集指针,允许为空。
|
||||
* @brief 绑定数据层与当前标签页配置。
|
||||
* @param [IN] dataSet 数据集合,允许为空。
|
||||
* @param [IN] tab 当前标签页配置,允许为空。
|
||||
*/
|
||||
void SetDocument(SignalSet* document);
|
||||
void SetContext(const DataSet* dataSet, TabConfig* tab);
|
||||
|
||||
/**
|
||||
* @brief 设置 DPI 缩放比例。
|
||||
@@ -149,12 +153,7 @@ namespace jdi
|
||||
HCURSOR QueryCursor(int x, int y) const;
|
||||
|
||||
/**
|
||||
* @brief 时间轴自适应到全部数据范围。
|
||||
*/
|
||||
void FitTime();
|
||||
|
||||
/**
|
||||
* @brief 时间轴与幅值轴同时自适应。
|
||||
* @brief 时间轴与幅值轴同时自适应到可见信号范围。
|
||||
*/
|
||||
void FitAll();
|
||||
|
||||
@@ -180,7 +179,7 @@ namespace jdi
|
||||
* @brief 获取网格当前内容总高度。
|
||||
* @return 内容高度(像素)。
|
||||
*/
|
||||
float LaneContentHeight() const;
|
||||
float LaneContentHeight() const { return m_laneContentHeight; }
|
||||
|
||||
/**
|
||||
* @brief 清除已固定的时间光标。
|
||||
@@ -191,31 +190,30 @@ namespace jdi
|
||||
* @brief 判断当前是否存在激活的时间光标。
|
||||
* @return 存在返回 true。
|
||||
*/
|
||||
bool HasCursor() const { return m_cursorVisible; }
|
||||
bool HasCursor() const;
|
||||
|
||||
/**
|
||||
* @brief 获取当前激活光标对应的时间。
|
||||
* @return 光标时间。
|
||||
*/
|
||||
double CursorTime() const { return m_cursorTime; }
|
||||
double CursorTime() const;
|
||||
|
||||
/**
|
||||
* @brief 获取当前视图左边界时间。
|
||||
* @return 视图左边界时间。
|
||||
*/
|
||||
double ViewMinTime() const { return m_viewMin; }
|
||||
double ViewMinTime() const;
|
||||
|
||||
/**
|
||||
* @brief 获取当前视图右边界时间。
|
||||
* @return 视图右边界时间。
|
||||
*/
|
||||
double ViewMaxTime() const { return m_viewMax; }
|
||||
double ViewMaxTime() const;
|
||||
|
||||
/**
|
||||
* @brief 获取绘图区(波形区域)矩形。
|
||||
* @return 波形区域矩形。
|
||||
* @brief 重新生成网格几何(可见性或网格划分变化后调用)。
|
||||
*/
|
||||
const gd::RectF& WaveformRect() const { return m_plotRect; }
|
||||
void RefreshLanes();
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -226,9 +224,57 @@ namespace jdi
|
||||
gd::RectF rect; /**< 网格波形区域。 */
|
||||
double yMin = 0.0; /**< 幅值下限。 */
|
||||
double yMax = 1.0; /**< 幅值上限。 */
|
||||
bool empty = true; /**< 是否没有可见信号。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 已解析的信号视图:数据与显示配置的组合。
|
||||
*/
|
||||
struct ResolvedSignal
|
||||
{
|
||||
const SignalData* data = nullptr; /**< 信号数据。 */
|
||||
const SignalStyle* style = nullptr; /**< 显示配置。 */
|
||||
const DataFile* file = nullptr; /**< 所属文件。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取当前生效的标签页配置(未绑定时返回内部占位对象)。
|
||||
* @return 标签页配置引用。
|
||||
*/
|
||||
TabConfig& Tab() { return (m_tab != nullptr) ? *m_tab : m_localTab; }
|
||||
|
||||
/**
|
||||
* @brief 获取当前生效的标签页配置(只读)。
|
||||
* @return 标签页配置引用。
|
||||
*/
|
||||
const TabConfig& Tab() const { return (m_tab != nullptr) ? *m_tab : m_localTab; }
|
||||
|
||||
/**
|
||||
* @brief 判断是否存在可绘制内容(已加载数据且至少有一条可见信号)。
|
||||
* @return 可绘制返回 true。
|
||||
*/
|
||||
bool HasDrawableContent() const;
|
||||
|
||||
/**
|
||||
* @brief 计算当前视图应使用的时间范围。
|
||||
* @param [OUT] low 时间下限。
|
||||
* @param [OUT] high 时间上限。
|
||||
*/
|
||||
void TimeBounds(double& low, double& high) const;
|
||||
|
||||
/**
|
||||
* @brief 解析信号引用,得到数据与显示配置。
|
||||
* @param [IN] ref 信号引用。
|
||||
* @return 解析结果,引用无效时各指针为空。
|
||||
*/
|
||||
ResolvedSignal ResolveSignal(const SignalRef& ref) const;
|
||||
|
||||
/**
|
||||
* @brief 判断某网格内的可见信号是否来自多个文件。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
* @return 跨越多个文件返回 true。
|
||||
*/
|
||||
bool LaneSpansMultipleFiles(int laneIndex) const;
|
||||
|
||||
/**
|
||||
* @brief 重新计算各网格的布局与幅值范围。
|
||||
*/
|
||||
@@ -290,13 +336,13 @@ namespace jdi
|
||||
|
||||
/**
|
||||
* @brief 构建单条信号在当前视图下的折线点序列。
|
||||
* @param [IN] signal 目标信号。
|
||||
* @param [IN] resolved 已解析的信号视图。
|
||||
* @param [IN] lane 所属网格绘制信息。
|
||||
* @param [IN] stepMode 是否使用阶梯保持连线。
|
||||
* @param [OUT] points 输出点序列。
|
||||
* @param [OUT] breaks 输出每段折线的起始下标(用于处理缺失值断线)。
|
||||
*/
|
||||
void BuildPolyline(const Signal& signal, const LaneVisual& lane, bool stepMode,
|
||||
void BuildPolyline(const ResolvedSignal& resolved, const LaneVisual& lane, bool stepMode,
|
||||
std::vector<gd::PointF>& points, std::vector<std::size_t>& breaks) const;
|
||||
|
||||
/**
|
||||
@@ -307,8 +353,8 @@ namespace jdi
|
||||
* @param [IN] timeTicks 时间刻度序列。
|
||||
* @param [IN] timeStep 时间刻度步长。
|
||||
*/
|
||||
void PaintLane(gd::Graphics& g, int laneIndex, const LaneVisual& lane, const std::vector<double>& timeTicks,
|
||||
double timeStep);
|
||||
void PaintLane(gd::Graphics& g, int laneIndex, const LaneVisual& lane,
|
||||
const std::vector<double>& timeTicks, double timeStep);
|
||||
|
||||
/**
|
||||
* @brief 绘制底部时间轴。
|
||||
@@ -347,9 +393,17 @@ namespace jdi
|
||||
*/
|
||||
void PaintLaneReadout(gd::Graphics& g, int laneIndex, const LaneVisual& lane);
|
||||
|
||||
/**
|
||||
* @brief 绘制空状态提示文本。
|
||||
* @param [IN,OUT] g 绘图上下文。
|
||||
*/
|
||||
void PaintEmptyState(gd::Graphics& g);
|
||||
|
||||
const UiFonts* m_fonts = nullptr; /**< 字体资源。 */
|
||||
const Theme* m_theme = nullptr; /**< 主题资源。 */
|
||||
SignalSet* m_document = nullptr; /**< 数据集。 */
|
||||
const DataSet* m_dataSet = nullptr; /**< 数据集合。 */
|
||||
TabConfig* m_tab = nullptr; /**< 当前标签页配置。 */
|
||||
TabConfig m_localTab; /**< 未绑定标签页时使用的占位配置。 */
|
||||
float m_scale = 1.0f; /**< DPI 缩放比例。 */
|
||||
|
||||
gd::RectF m_area; /**< 绘图区整体区域。 */
|
||||
@@ -357,21 +411,13 @@ namespace jdi
|
||||
gd::RectF m_timeAxisRect; /**< 时间轴区域。 */
|
||||
gd::RectF m_scrollBarRect; /**< 网格滚动条区域。 */
|
||||
|
||||
float m_yAxisWidth = 64.0f; /**< 纵轴标签列宽度(逻辑像素)。 */
|
||||
float m_timeAxisHeight = 34.0f; /**< 时间轴高度(逻辑像素)。 */
|
||||
float m_yAxisWidth = 74.0f; /**< 纵轴标签列宽度(逻辑像素)。 */
|
||||
float m_timeAxisHeight = 32.0f; /**< 时间轴高度(逻辑像素)。 */
|
||||
float m_laneGap = 6.0f; /**< 网格间距(逻辑像素)。 */
|
||||
float m_minLaneHeight = 46.0f; /**< 网格最小高度(逻辑像素)。 */
|
||||
float m_laneScroll = 0.0f; /**< 网格纵向滚动偏移量。 */
|
||||
float m_laneContentHeight = 0.0f; /**< 网格内容总高度。 */
|
||||
bool m_scrollBarVisible = false; /**< 是否需要显示滚动条。 */
|
||||
|
||||
double m_viewMin = 0.0; /**< 视图左边界时间。 */
|
||||
double m_viewMax = 1.0; /**< 视图右边界时间。 */
|
||||
|
||||
bool m_cursorVisible = false; /**< 是否存在激活光标。 */
|
||||
bool m_cursorPinned = false; /**< 光标是否已被固定。 */
|
||||
double m_cursorTime = 0.0; /**< 光标时间。 */
|
||||
|
||||
PlotDragMode m_dragMode = PlotDragMode::NONE; /**< 当前拖拽模式。 */
|
||||
int m_dragLane = -1; /**< 拖拽所作用的网格下标。 */
|
||||
bool m_dragMoved = false; /**< 拖拽过程中是否发生了位移。 */
|
||||
@@ -379,8 +425,6 @@ namespace jdi
|
||||
int m_dragStartY = 0; /**< 拖拽起点纵坐标。 */
|
||||
int m_dragLastX = 0; /**< 上一次拖拽横坐标。 */
|
||||
int m_dragLastY = 0; /**< 上一次拖拽纵坐标。 */
|
||||
double m_dragStartViewMin = 0.0; /**< 拖拽起始视图左边界。 */
|
||||
double m_dragStartViewMax = 1.0; /**< 拖拽起始视图右边界。 */
|
||||
double m_dragAnchorValue = 0.0; /**< 纵轴缩放锚点幅值。 */
|
||||
double m_dragAnchorRatio = 0.5; /**< 纵轴缩放锚点相对位置。 */
|
||||
double m_dragStartYMin = 0.0; /**< 拖拽起始幅值下限。 */
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user