分组折起热区与改名输入框修正 + 数据模型去冗余(单一名称)+ 新增 Components/Shared 组件 + 过时注释/命名大清理 + 二进制瘦身 25.6%
## 一、UI 交互修复(用户报告) ① 分组折起热区(用户要求):点分组**名称**不再折起,只有**折叠三角**或**「组X」标签** 才折起。RowPart 新增 GROUP_TITLE;RowHitPart() 为分组行判出三角 / 复选框 / 关闭 ✕ / 「组X」标签矩形 / 其余 BODY;OnLButtonDown 只在这两个热区调用 ToggleGroupFromRow()。 附带:双击「组X」不再进入改名(该区域现为折起热区),双击分组名仍可改名。 ② 分组改名输入框不再吞掉「N 项」:RowNameRect() 对分组行的右边界改为「项数左边缘 − 6*scale」; 新增 GroupLabelText()/GroupStatsText() 作为文本与宽度的唯一来源(PaintGroupRow 与 RowNameRect 共用),避免名称可用宽度与实际绘制文本漂移。 ## 二、数据模型去冗余(用户指出的重点) - SignalData / SignalGroup **只保留一个名称字段** name:删除 displayName、删除 Title() (31 处调用点改为直接用 name);DataSet::SetSignalDisplayName / SetGroupDisplayName → RenameSignal / RenameGroup,且**空串 / 纯空白一律拒绝**(名称不再有回退值)。 依据:信号靠 SignalRef 下标定位、从不按名字匹配 ⇒ 两个字段是同一语义的两份副本。 收益:每条信号 / 每个分组少一个 std::wstring(24B + 堆分配)与一条 Title() 分支。 - 删除 Application::m_loadingBytes(全仓既不读也不写的死成员,注释却称“用于展示体积”)。 ## 三、新增 Components/Shared 组件(通用 UI 控件) - 从 Utilities/PaintUtil.* 迁出全部「控件类」绘制/命中:图标(+ / ✕ / 三角)、复选框、 滑块(UiSliderRatioFromX / UiDrawSlider)、内联输入框(UiDrawEditField / UiDrawEditFieldContent / UiEditTextLeft / UiEditOffsetAt / UiEditFieldMouseDown / UiEditFieldMouseMove)、颜色样块(UiDrawSwatch / UiSwatchNeedsOutline)、 取值胶囊配色(UiInk / UiColorLuminance / UiContrastInk)。 - PaintUtil.* 只保留低层绘制原语(矩形 / 圆角 / 直线 / 批量实线 / 颜色混合 / 文本与测量)。 - 依赖方向固定:Components/* → Components/Shared → Utilities(不得反向,Utilities 不再含控件)。 - Makefile 与 .preflight/perf/build.ps1 已登记新目录;调用方改 include "UiControls.hpp"。 ## 四、过时注释 / 命名批量修正(承接上一轮未做完的部分) - 注释:文件下标→分组下标、文件内信号下标→组内信号下标、所属文件下标→所属分组下标; 措辞统一 文件分组→分组、移除该文件→移除该分组、打开 CSV 文件→打开数据文件 等一批。 - 文不对题的形参名:VisibleIndexRange(const TimeAxis& file,…) → axis; Application::LoadFileAsync(…, SignalGroup& file,…) → group。 - 函数名里的 File 语义(上一轮只改了 RowKind::FILE):PaintFileRow→PaintGroupRow、 FileCloseRect→GroupCloseRect、OpenFileMenu→OpenGroupMenu、FileGroupLabelWidth→GroupLabelWidth、 StyleEditField::FILE_NAME→GROUP_TITLE;局部变量 fileRow/fileHeight/isFile → groupRow/groupHeight/isGroup。 - 修复 DataModel.hpp 两处被压扁的注释块(/**<TAB><TAB>* @brief …)与 Application::NewTab 上方重复的文档块。 - ⚠️ 踩坑:GROUP_NAME 撞上 nb30.h(windows.h 引入)的 #define GROUP_NAME 0x80, 导致枚举编译失败,改名 GROUP_TITLE 解决。 ## 五、二进制瘦身:1 013 248 → 754 176 B(−25.6%,省 259 KB) - 真因不是 PlotView.cpp,而是 Resources/JustDataInspector.ico 里 **256×256@32bpp 以未压缩 BMP 存储的条目(270 376 B,占整包 27%)**。改为 PNG 存储(Vista+ 标准做法,观感零变化) ⇒ 该条目 270 376 → 11 280 B、整个 ico 302 430 → 43 334 B(小尺寸仍保留 BMP)。 - 实测结论:“拆分大文件 ⇒ 瘦身”不成立(同一批机器码仍要进二进制); -ffunction-sections/-fdata-sections/-Wl,--gc-sections 在本工程反而 +9 216 B(已回退)。 - ⚠️ .o 体积受节对齐/重定位表主导,判断“代码搬去哪了”要用 nm,不要看 .o 字节数。 ## 六、验证(全部离屏:SW_HIDE + 不注入真实输入 + 进程/线程 BELOW_NORMAL) - panelanim 156/156(连跑 5 次稳定;新增/更新:点分组名不折起也不滚动、扫掠定位「组X」热区、 筛选态与普通态折叠三角逐像素一致、改名输入框右边界早于项数文本);verify 49/49; datacheck 69/69(含“重命名写入唯一名称字段且空名被拒”);edgecheck 46/46。 - A/B:回退两处 UI 修复 ⇒ 10 项如实失败;恢复后全绿。 - make release / make debug 零警告。 ## 七、本轮未完成(已在报告与 agent_mem.md 中如实记录) - PlotView.cpp(13 695 行 / 544 KB)按功能拆分为多个协作文件:未执行。 前置改造是把第 13–888 行的匿名命名空间(~870 行常量与工具函数)改成具名命名空间并逐个 inline,再逐个文件搬移并反复验证;时间不足以安全完成,故主动不做(附可执行方案)。 - SignalPanel.cpp / Application.cpp / DataModel.cpp 的多文件化、Lane 抽出 LanePanelState、 SetStatusMessage 模态阻塞解耦:均未执行。 ## 八、文档 - 新增 Documents/refactor_report_2026-10-16.md(本轮详细报告); 删除 Documents/refactor_report_2026-10-15.md(有效内容已并入 agent_mem.md 与本报告)。 - Documents/agent_mem.md 新增 §9.37 与 §11.2 第 85–90 条;更新数据层架构摘要(单一名称字段); §12 历史附录加“时效声明”。
This commit is contained in:
1 parent
5831a0ea0d
commit
0871eb0cba
22 files changed
+1268
-1010
No files matched your search
@@ -560,7 +560,7 @@ namespace jdi
|
||||
/**
|
||||
* @brief 使全部派生结果失效:折线顶点、边沿统计、中心平均值曲线与静态场景缓存。
|
||||
*
|
||||
* 数据层结构变化(加载/移除文件、信号增删)后信号引用与文件地址都可能改变,
|
||||
* 数据层结构变化(加载/移除分组、信号增删)后信号引用与分组地址都可能改变,
|
||||
* 必须整体失效,避免旧几何键与新的信号意外重合而取到过期结果。
|
||||
*/
|
||||
void InvalidateDerivedCaches();
|
||||
@@ -568,7 +568,7 @@ namespace jdi
|
||||
/**
|
||||
* @brief 暂停后台派生曲线计算并作废其结果。
|
||||
*
|
||||
* 后台线程会读取采样数据,因此**任何会改变数据层结构(增删文件/信号、插入派生信号,
|
||||
* 后台线程会读取采样数据,因此**任何会改变数据层结构(增删分组/信号、插入派生信号,
|
||||
* 进而移动 `SignalGroup`/`SignalData` 存储)的操作之前**都必须先调用本函数:它会等待正在
|
||||
* 进行的计算结束、清空待算队列与缓存,从而杜绝后台线程读取已释放内存。
|
||||
* 之后的绘制会按需重新启动后台线程(惰性)。
|
||||
@@ -589,7 +589,7 @@ namespace jdi
|
||||
*
|
||||
* ⚠️ 这是"关掉预览后内存不下降"的修复:一条整段(千万级采样)曲线的中间缓冲
|
||||
* 可达数百 MB,而 `thread_local` 只在线程退出时释放 —— 过去只有"
|
||||
* 关闭整个文件分组"(会 `PauseDerivedAsync`)才会真正还内存。
|
||||
* 关闭整个分组"(会 `PauseDerivedAsync`)才会真正还内存。
|
||||
*/
|
||||
void TrimDerivedCurveDataIfIdle();
|
||||
|
||||
@@ -749,7 +749,7 @@ namespace jdi
|
||||
struct MeanFilterBuild
|
||||
{
|
||||
int groupIndex = -1; /**< 信号所属分组下标。 */
|
||||
int signalIndex = -1; /**< 文件内信号下标。 */
|
||||
int signalIndex = -1; /**< 组内信号下标。 */
|
||||
int points = 5; /**< 均值点数 X(滑平半径)。 */
|
||||
int iterations = 1; /**< 迭代次数 N(至少 1)。 */
|
||||
};
|
||||
@@ -773,7 +773,7 @@ namespace jdi
|
||||
struct WeakPeakBuild
|
||||
{
|
||||
int groupIndex = -1; /**< 信号所属分组下标。 */
|
||||
int signalIndex = -1; /**< 文件内信号下标。 */
|
||||
int signalIndex = -1; /**< 组内信号下标。 */
|
||||
int amountPercent = 0; /**< 弱峰调整幅度(-400–400,默认 0 = 不改动)。 */
|
||||
int iterations = 1; /**< 迭代次数 N(1–10)。 */
|
||||
};
|
||||
@@ -1015,9 +1015,9 @@ namespace jdi
|
||||
ResolvedSignal ResolveSignal(const SignalRef& ref) const;
|
||||
|
||||
/**
|
||||
* @brief 判断某网格内的可见信号是否来自多个文件。
|
||||
* @brief 判断某网格内的可见信号是否来自多个分组。
|
||||
* @param [IN] laneIndex 网格下标。
|
||||
* @return 跨越多个文件返回 true。
|
||||
* @return 跨越多个分组返回 true。
|
||||
*/
|
||||
bool LaneSpansMultipleFiles(int laneIndex) const;
|
||||
|
||||
@@ -1605,7 +1605,7 @@ namespace jdi
|
||||
* @brief 派生曲线缓存的键(决定一条派生曲线数值的全部输入)。
|
||||
*
|
||||
* 数据层在两次结构变化之间是只读的,因此 `signal` 指针在此期间稳定;
|
||||
* 任何结构变化(增删文件/信号、插入派生信号、切换标签页)前都会暂停后台线程并清空缓存
|
||||
* 任何结构变化(增删分组/信号、插入派生信号、切换标签页)前都会暂停后台线程并清空缓存
|
||||
*(见 `PauseDerivedAsync`),因此不会出现悬空读取。
|
||||
*/
|
||||
struct CurveKey
|
||||
@@ -1771,7 +1771,7 @@ namespace jdi
|
||||
|
||||
/**
|
||||
* @brief 计算当前视图对应的采样下标区间(时间单调时二分定位,否则为整段)。
|
||||
* @param [IN] file 目标文件。
|
||||
* @param [IN] axis 目标时间轴。
|
||||
* @param [IN] count 可用采样点数。
|
||||
* @param [OUT] begin 区间起点(含)。
|
||||
* @param [OUT] end 区间终点(不含)。
|
||||
@@ -2530,7 +2530,7 @@ namespace jdi
|
||||
int edgeCenter = 0; /**< 中心轴边沿计数开关。 */
|
||||
int meanFilter = 0; /**< 均值滤波开关。 */
|
||||
int weakPeak = 0; /**< 弱峰调整开关。 */
|
||||
/** 各条目展开为 [文件, 信号, 参数…],按原顺序(稳定)。 */
|
||||
/** 各条目展开为 [分组, 信号, 参数…],按原顺序(稳定)。 */
|
||||
std::vector<int> edgeCenterItems;
|
||||
std::vector<int> meanFilterItems;
|
||||
std::vector<int> weakPeakItems;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
#include "UiControls.hpp"
|
||||
#include "Utf8Util.hpp"
|
||||
|
||||
namespace jdi
|
||||
@@ -553,7 +554,7 @@ namespace jdi
|
||||
* 因此这里**不做任何外扩**:只有两端都落在 `[begin, end)` 内的采样对才会被累计
|
||||
*(调用方从 `begin + 1` 开始枚举采样对)。
|
||||
*
|
||||
* @param [IN] file 所属数据分组。
|
||||
* @param [IN] group 所属数据分组。
|
||||
* @param [IN] count 采样点数量。
|
||||
* @param [IN] hasRange 是否限定时间区间。
|
||||
* @param [IN] rangeMin 区间左端点时间。
|
||||
@@ -828,7 +829,7 @@ namespace jdi
|
||||
*/
|
||||
std::wstring BuildLegendText(const SignalData& data)
|
||||
{
|
||||
return data.Title();
|
||||
return data.name;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4322,7 +4323,7 @@ namespace jdi
|
||||
continue;
|
||||
}
|
||||
const float nameWidth =
|
||||
std::min(UiMeasureTextWidth(m_fonts->uiSmall, resolved.data->Title()),
|
||||
std::min(UiMeasureTextWidth(m_fonts->uiSmall, resolved.data->name),
|
||||
kEdgePanelNameMaxWidth * m_scale);
|
||||
nameColumnWidth = std::max(nameColumnWidth, nameWidth);
|
||||
if (itemized)
|
||||
@@ -6929,7 +6930,7 @@ namespace jdi
|
||||
break;
|
||||
}
|
||||
}
|
||||
return BeginEdit(PlotEditTarget::SIGNAL_NAME, -1, resolved.data->Title());
|
||||
return BeginEdit(PlotEditTarget::SIGNAL_NAME, -1, resolved.data->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8196,10 +8197,10 @@ namespace jdi
|
||||
mixFloat(static_cast<float>(resolved.style->offsetTime));
|
||||
}
|
||||
// 图例文案参与绘制,重命名必须让缓存失效。
|
||||
mixText(resolved.data->Title());
|
||||
mixText(resolved.data->name);
|
||||
if (resolved.group != nullptr)
|
||||
{
|
||||
mixText(resolved.group->Title());
|
||||
mixText(resolved.group->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10874,7 +10875,7 @@ namespace jdi
|
||||
std::wstring label = BuildLegendText(*resolved.data);
|
||||
if (multiFile && resolved.group != nullptr)
|
||||
{
|
||||
label += L" · " + resolved.group->Title();
|
||||
label += L" · " + resolved.group->name;
|
||||
}
|
||||
const float maxTextWidth = kLegendMaxTextWidth * m_scale;
|
||||
const float fullTextWidth = UiMeasureTextWidth(m_fonts->uiTiny, label);
|
||||
@@ -13135,7 +13136,7 @@ namespace jdi
|
||||
const float nameWidth =
|
||||
std::min(std::max(20.0f, checkRect.X - (panel.X + pad) - 6.0f * m_scale),
|
||||
kEdgePanelNameMaxWidth * m_scale);
|
||||
UiText(g, UiEllipsize(resolved.data->Title(), m_fonts->uiSmall, nameWidth),
|
||||
UiText(g, UiEllipsize(resolved.data->name, m_fonts->uiSmall, nameWidth),
|
||||
m_fonts->uiSmall,
|
||||
gd::RectF(panel.X + pad, checkRect.Y - 3.0f * m_scale, nameWidth,
|
||||
checkRect.Height + 6.0f * m_scale),
|
||||
@@ -13349,7 +13350,7 @@ namespace jdi
|
||||
const float textWidth = panel.Width - pad * 2.0f;
|
||||
// 名称:超长时省略(面板宽度被 `kEdgePanelNameMaxWidth` 限制,不会把面板顶得很长)。
|
||||
UiText(g,
|
||||
UiEllipsize(resolved.data->Title(), m_fonts->uiSmall,
|
||||
UiEllipsize(resolved.data->name, m_fonts->uiSmall,
|
||||
std::min(textWidth, kEdgePanelNameMaxWidth * m_scale)),
|
||||
m_fonts->uiSmall, gd::RectF(panel.X + pad, rowY, textWidth, rowHeight),
|
||||
signalColor, TextAlign::LEFT);
|
||||
@@ -13651,7 +13652,7 @@ namespace jdi
|
||||
}
|
||||
|
||||
const LaneVisual& lane = m_lanes[static_cast<std::size_t>(laneIndex)];
|
||||
const std::wstring text = resolved.data->Title() + L" · 按住拖拽可移入其它网格";
|
||||
const std::wstring text = resolved.data->name + L" · 按住拖拽可移入其它网格";
|
||||
|
||||
// 提示跟随鼠标:在可拖拽区域内持续移动时,提示条也要跟着走。
|
||||
const float textWidth = UiMeasureTextWidth(m_fonts->uiSmall, text) + 16.0f * m_scale;
|
||||
|
||||
Reference in new issue
Block a user