分组折起热区与改名输入框修正 + 数据模型去冗余(单一名称)+ 新增 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:
DeepSeek V4.1 Flash committed 2026-10-16 03:25:48 +08:00
1 parent 5831a0ea0d
commit 0871eb0cba
22 files changed
+1268 -1010

No files matched your search

+98 -67
View File
@@ -4,6 +4,7 @@
#include <cmath>
#include <cstdlib>
#include "UiControls.hpp"
#include "Utf8Util.hpp"
namespace jdi
@@ -12,7 +13,7 @@ namespace jdi
namespace
{
const float kHeaderHeight = 38.0f; /**< 标题区高度(逻辑像素)。 */
const float kFileRowHeight = 30.0f; /**< 文件分组行高。 */
const float kGroupRowHeight = 30.0f; /**< 分组行高。 */
const float kSignalRowHeight = 27.0f; /**< 信号行高。 */
const float kPadding = 12.0f; /**< 通用内边距。 */
const float kCheckSize = 15.0f; /**< 复选框尺寸。 */
@@ -21,7 +22,7 @@ namespace jdi
const float kBadgeHeight = 17.0f; /**< 网格徽标高度。 */
const float kCorner = 4.0f; /**< 通用圆角半径。 */
const float kDisclosureWidth = 16.0f; /**< 折叠三角占位宽度。 */
const float kIndent = 14.0f; /**< 信号行相对文件行的缩进。 */
const float kIndent = 14.0f; /**< 信号行相对分组行的缩进。 */
const float kScrollBarThickness = 8.0f; /**< 滚动条宽度。 */
const float kCloseButtonSize = 18.0f; /**< 行尾关闭(✕)按钮尺寸(分组行与信号行共用)。 */
const float kGroupSeparatorGap = 7.0f; /**< 分组标签与分隔线/名称的间距。 */
@@ -480,7 +481,7 @@ namespace jdi
std::wstring pattern = L"*";
pattern += m_filterText;
pattern += L'*';
return WildcardMatchNoCase(signal.Title(), pattern);
return WildcardMatchNoCase(signal.name, pattern);
}
bool SignalPanel::IsGroupCollapsed(int groupIndex) const
@@ -829,7 +830,7 @@ namespace jdi
return;
}
const float fileHeight = kFileRowHeight * m_scale;
const float groupHeight = kGroupRowHeight * m_scale;
const float signalHeight = kSignalRowHeight * m_scale;
const bool filtering = !m_filterText.empty();
@@ -856,13 +857,13 @@ namespace jdi
const bool collapsed = IsGroupCollapsed(gi);
const bool animating = (FindGroupAnimation(gi) >= 0);
ListRow fileRow;
fileRow.kind = RowKind::GROUP;
fileRow.groupIndex = gi;
fileRow.height = fileHeight;
ListRow groupRow;
groupRow.kind = RowKind::GROUP;
groupRow.groupIndex = gi;
groupRow.height = groupHeight;
// 「N 项」按当前模式下实际列出的信号数显示:筛选时 = 该组内符合筛选条件的个数。
fileRow.displayCount = static_cast<int>(shown.size());
m_rows.push_back(fileRow);
groupRow.displayCount = static_cast<int>(shown.size());
m_rows.push_back(groupRow);
// 折起且没有动画 ⇒ 该组的信号行完全不占高度(不出现在行集合里)。
// ⚠️ 有动画时必须**保留全部信号行**(含正在折起的):它们整组向上平移,
@@ -1048,7 +1049,7 @@ namespace jdi
// `FillRowRect` 会把矩形夹到列表矩形(GDI 填充不受 GDI+ 裁剪约束)。
SetRowClip(gd::RectF(m_listRect.X, stickyY, m_listRect.Width, height));
FillRowRect(g, gd::RectF(m_listRect.X, stickyY, m_listRect.Width, height), m_theme->panelBg);
PaintFileRow(g, row);
PaintGroupRow(g, row);
ClearRowClip();
// 只有真正“浮”在其它行之上时才补一条底部边界线(否则会与正常绘制有差异)。
if (stickyY > naturalY + 0.5f)
@@ -1059,7 +1060,7 @@ namespace jdi
m_rowYOverrideActive = false;
}
gd::RectF SignalPanel::FileCloseRect(int row) const
gd::RectF SignalPanel::GroupCloseRect(int row) const
{
const gd::RectF rect = RowRect(row);
const float size = kCloseButtonSize * m_scale;
@@ -1103,15 +1104,15 @@ namespace jdi
const ListRow& item = m_rows[static_cast<std::size_t>(row)];
const gd::RectF rect = RowRect(row);
const bool isFile = (item.kind == RowKind::GROUP);
const float baseX = rect.X + kPadding * m_scale + (isFile ? 0.0f : kIndent * m_scale);
const bool isGroup = (item.kind == RowKind::GROUP);
const float baseX = rect.X + kPadding * m_scale + (isGroup ? 0.0f : kIndent * m_scale);
const gd::RectF disclosureRect(baseX, rect.Y, kDisclosureWidth * m_scale, rect.Height);
const gd::RectF checkRect(baseX + kDisclosureWidth * m_scale,
rect.Y + (rect.Height - kCheckSize * m_scale) * 0.5f,
kCheckSize * m_scale, kCheckSize * m_scale);
if (isFile)
if (isGroup)
{
if (UiPointInRect(disclosureRect, fx, fy))
{
@@ -1121,10 +1122,18 @@ namespace jdi
{
return RowPart::CHECK;
}
if (UiPointInRect(FileCloseRect(row), fx, fy))
if (UiPointInRect(GroupCloseRect(row), fx, fy))
{
return RowPart::CLOSE;
}
// 「组X」标签:与折叠三角一样是“折起该分组”的热区
//(用户 2026-10-16 要求:只有点三角或「组X」才折起,点到组名本体不折起)。
const float labelLeft = checkRect.X + checkRect.Width + 8.0f * m_scale;
const gd::RectF labelRect(labelLeft, rect.Y, GroupLabelWidth(row), rect.Height);
if (UiPointInRect(labelRect, fx, fy))
{
return RowPart::GROUP_TITLE;
}
return RowPart::BODY;
}
@@ -1430,7 +1439,7 @@ namespace jdi
const SignalRef& target = SelectedRef();
const SignalData* signal = target.IsValid() ? m_dataSet->Resolve(target) : nullptr;
const std::wstring title = (signal != nullptr) ? signal->Title() : std::wstring();
const std::wstring title = (signal != nullptr) ? signal->name : std::wstring();
const int lane = TargetLaneIndex();
// 缓存键:目标信号 + 它所在网格 + 名称(名称宽度与 GX 标签是否出现都由它们决定)。
@@ -1661,7 +1670,7 @@ namespace jdi
if (m_rows[static_cast<std::size_t>(row)].kind == RowKind::GROUP)
{
PaintFileRow(g, row);
PaintGroupRow(g, row);
}
else
{
@@ -1716,7 +1725,7 @@ namespace jdi
UiFillRect(g, clipped, argb);
}
void SignalPanel::PaintFileRow(gd::Graphics& g, int row)
void SignalPanel::PaintGroupRow(gd::Graphics& g, int row)
{
if (m_dataSet == nullptr || m_tab == nullptr || row < 0 || row >= static_cast<int>(m_rows.size()))
{
@@ -1760,14 +1769,13 @@ namespace jdi
const bool anyVisible = m_tab->GroupHasVisible(item.groupIndex);
UiDrawCheckBox(g, checkRect, allVisible ? 1 : (anyVisible ? 2 : 0), 3.0f * m_scale);
const gd::RectF closeRect = FileCloseRect(row);
const gd::RectF closeRect = GroupCloseRect(row);
// 分组标题:左侧为“组X”标签,右侧以绘制的竖线分隔分组名(不使用字符),再显示可重命名的名称。
const std::wstring groupLabel = L"组" + std::to_wstring(item.groupIndex + 1);
// 项数:普通模式 = 信号总数;筛选模式 = 该组内**符合筛选条件**的信号个数
//(用户 2026-10-16 要求)。两者都在 `BuildRows` 里写入 `displayCount`。
const std::wstring stats = std::to_wstring(item.displayCount) + L" 项";
const float groupWidth = FileGroupLabelWidth(row);
const std::wstring groupLabel = GroupLabelText(item.groupIndex);
// 项数文本与 `RowNameRect`(组名编辑框)共用同一来源,保证名称宽度与绘制不漂移。
const std::wstring stats = GroupStatsText(row);
const float groupWidth = GroupLabelWidth(row);
const float statsWidth = UiMeasureTextWidth(m_fonts->uiSmall, stats);
const float statsRight = closeRect.X - 6.0f * m_scale;
const float nameLeft = checkRect.X + checkRect.Width + 8.0f * m_scale;
@@ -1786,13 +1794,13 @@ namespace jdi
rect.Height - 14.0f * m_scale),
WithAlpha(m_theme->borderStrong, 0xB0));
if (m_editField == StyleEditField::FILE_NAME && m_editRow == row)
if (m_editField == StyleEditField::GROUP_TITLE && m_editRow == row)
{
UiDrawEditField(g, RowNameRect(row), m_edit, m_fonts->uiSmall, m_scale);
}
else
{
PaintRowText(g, UiEllipsize(group->Title(), m_fonts->uiBold, nameWidth), m_fonts->uiBold,
PaintRowText(g, UiEllipsize(group->name, m_fonts->uiBold, nameWidth), m_fonts->uiBold,
gd::RectF(nameAreaLeft, rect.Y, nameWidth, rect.Height), m_theme->textStrong,
TextAlign::LEFT);
}
@@ -1800,7 +1808,7 @@ namespace jdi
PaintRowText(g, stats, m_fonts->uiSmall, gd::RectF(statsRight - statsWidth, rect.Y, statsWidth, rect.Height),
m_theme->textMuted, TextAlign::RIGHT);
// 关闭按钮(从工作区移除该文件)。
// 关闭按钮(从工作区移除该分组)。
const bool closeHot = hovered && (m_hoverPart == RowPart::CLOSE);
if (closeHot)
{
@@ -1878,7 +1886,7 @@ namespace jdi
{
const float nameWidth = std::max(16.0f, nameRightLimit - nameLeft);
const std::uint32_t nameColor = visible ? m_theme->text : m_theme->textMuted;
PaintRowText(g, UiEllipsize(signal->Title(), m_fonts->ui, nameWidth), m_fonts->ui,
PaintRowText(g, UiEllipsize(signal->name, m_fonts->ui, nameWidth), m_fonts->ui,
gd::RectF(nameLeft, rect.Y, nameWidth, rect.Height), nameColor, TextAlign::LEFT);
}
@@ -2164,7 +2172,7 @@ namespace jdi
const std::uint32_t nameColor = (m_targetGeomLane >= 0) ? m_theme->text : m_theme->textMuted;
// ⚠️ 这里**不能**用 `PaintRowText`(它把文本裁到 `m_listRect`,而「目标」行在样式区、
// 列表矩形之外 ⇒ 文本会被完全裁掉,用户报告“信号名与 GX 标签都没正确绘制”)。
UiText(g, UiEllipsize(signal->Title(), m_fonts->ui, m_targetNameRect.Width), m_fonts->ui,
UiText(g, UiEllipsize(signal->name, m_fonts->ui, m_targetNameRect.Width), m_fonts->ui,
m_targetNameRect, nameColor, TextAlign::LEFT);
}
@@ -2328,18 +2336,21 @@ namespace jdi
}
const gd::RectF rect = RowRect(row);
const bool isFile = (m_rows[static_cast<std::size_t>(row)].kind == RowKind::GROUP);
const float baseX = rect.X + kPadding * m_scale + (isFile ? 0.0f : kIndent * m_scale);
const bool isGroup = (m_rows[static_cast<std::size_t>(row)].kind == RowKind::GROUP);
const float baseX = rect.X + kPadding * m_scale + (isGroup ? 0.0f : kIndent * m_scale);
const float checkRight = baseX + kDisclosureWidth * m_scale + kCheckSize * m_scale;
float left = 0.0f;
float right = 0.0f;
if (isFile)
if (isGroup)
{
// 分组名需要跳过左侧的“组X”标签与分隔线。
left = checkRight + 8.0f * m_scale + FileGroupLabelWidth(row) + kGroupSeparatorGap * 2.0f * m_scale +
// 分组名需要跳过左侧的“组X”标签与分隔线,并且**右侧让出“N 项”计数**:
// 双击进入编辑时,输入框不得把组内信号个数包进去(用户 2026-10-16 报告)。
left = checkRight + 8.0f * m_scale + GroupLabelWidth(row) + kGroupSeparatorGap * 2.0f * m_scale +
kGroupSeparatorWidth * m_scale;
right = FileCloseRect(row).X - 6.0f * m_scale;
const float statsRight = GroupCloseRect(row).X - 6.0f * m_scale;
const float statsWidth = UiMeasureTextWidth(m_fonts->uiSmall, GroupStatsText(row));
right = statsRight - statsWidth - 6.0f * m_scale;
}
else
{
@@ -2359,15 +2370,31 @@ namespace jdi
return gd::RectF(left, rect.Y + 3.0f * m_scale, right - left, rect.Height - 6.0f * m_scale);
}
float SignalPanel::FileGroupLabelWidth(int row) const
float SignalPanel::GroupLabelWidth(int row) const
{
if (m_fonts == nullptr || m_fonts->uiBold == nullptr || row < 0 ||
row >= static_cast<int>(m_rows.size()))
{
return 0.0f;
}
const std::wstring label = L"组" + std::to_wstring(m_rows[static_cast<std::size_t>(row)].groupIndex + 1);
return UiMeasureTextWidth(m_fonts->uiBold, label);
return UiMeasureTextWidth(m_fonts->uiBold,
GroupLabelText(m_rows[static_cast<std::size_t>(row)].groupIndex));
}
std::wstring SignalPanel::GroupLabelText(int groupIndex)
{
return L"组" + std::to_wstring(groupIndex + 1);
}
std::wstring SignalPanel::GroupStatsText(int row) const
{
if (row < 0 || row >= static_cast<int>(m_rows.size()))
{
return std::wstring();
}
// 项数:普通模式 = 信号总数;筛选模式 = 该组内**符合筛选条件**的信号个数
//(用户 2026-10-16 要求)。两者都在 `BuildRows` 里写入 `displayCount`。
return std::to_wstring(m_rows[static_cast<std::size_t>(row)].displayCount) + L" 项";
}
bool SignalPanel::BeginEdit(StyleEditField field, int row)
@@ -2414,7 +2441,7 @@ namespace jdi
{
return false;
}
initial = signal->Title();
initial = signal->name;
break;
}
if (row >= static_cast<int>(m_rows.size()))
@@ -2427,10 +2454,10 @@ namespace jdi
{
return false;
}
initial = signal->Title();
initial = signal->name;
break;
}
case StyleEditField::FILE_NAME:
case StyleEditField::GROUP_TITLE:
{
if (row < 0 || row >= static_cast<int>(m_rows.size()))
{
@@ -2441,7 +2468,7 @@ namespace jdi
{
return false;
}
initial = group->Title();
initial = group->name;
break;
}
default:
@@ -2459,7 +2486,7 @@ namespace jdi
// 名称类字段可输入任意字符,数值类字段限制为数字与小数点。
const bool nameField =
(field == StyleEditField::SIGNAL_NAME) || (field == StyleEditField::FILE_NAME);
(field == StyleEditField::SIGNAL_NAME) || (field == StyleEditField::GROUP_TITLE);
// 不限长度:名称与数值都由各自的提交逻辑处理超长内容。
m_edit.Begin(std::move(initial), true, nameField ? EditFilter::ANY : EditFilter::NUMBER, 0u);
return true;
@@ -2537,7 +2564,7 @@ namespace jdi
const SignalRef& target = SelectedRef();
if (target.IsValid())
{
m_dataSetWritable->SetSignalDisplayName(target.groupIndex, target.signalIndex, trimmed);
m_dataSetWritable->RenameSignal(target.groupIndex, target.signalIndex, trimmed);
}
// 名称变化会改变「目标」行的文本宽度 ⇒ 几何缓存作废。
m_targetGeomValid = false;
@@ -2548,16 +2575,16 @@ namespace jdi
break;
}
const ListRow& item = m_rows[static_cast<std::size_t>(row)];
m_dataSetWritable->SetSignalDisplayName(item.groupIndex, item.signalIndex, trimmed);
m_dataSetWritable->RenameSignal(item.groupIndex, item.signalIndex, trimmed);
break;
}
case StyleEditField::FILE_NAME:
case StyleEditField::GROUP_TITLE:
{
if (row < 0 || row >= static_cast<int>(m_rows.size()) || m_dataSetWritable == nullptr)
{
break;
}
m_dataSetWritable->SetGroupDisplayName(m_rows[static_cast<std::size_t>(row)].groupIndex, trimmed);
m_dataSetWritable->RenameGroup(m_rows[static_cast<std::size_t>(row)].groupIndex, trimmed);
break;
}
default:
@@ -2596,7 +2623,7 @@ namespace jdi
case StyleEditField::OPACITY:
return m_opacityValueRect;
case StyleEditField::SIGNAL_NAME:
case StyleEditField::FILE_NAME:
case StyleEditField::GROUP_TITLE:
// `row < 0` = 样式区「目标」行:输入框只覆盖**信号名**那一块,
// 不得把名称后面的 GX 标签也包进去(用户 2026-10-16 报告)。
if (m_editRow < 0)
@@ -3450,14 +3477,18 @@ namespace jdi
}
if (part == RowPart::CLOSE)
{
// 关闭文件属于数据层操作,交由宿主窗口处理;但**抬起时才生效**,
// 关闭分组属于数据层操作,交由宿主窗口处理;但**抬起时才生效**,
// 这里只记录目标(按住后移开再松开视为放弃)。
m_pendingClosePart = RowPart::CLOSE;
m_pendingCloseRow = row;
return true;
}
// 折叠 / 展开分组走「带动画 + 悬浮时先滚动就位」的统一入口
//(用户 2026-10-16 要求)。
// 折叠 / 展开分组:**只有**点到「折叠三角」或「组X」标签才生效
//(用户 2026-10-16 要求:点到分组名本体不折起)。
if (part != RowPart::DISCLOSURE && part != RowPart::GROUP_TITLE)
{
return true;
}
ToggleGroupFromRow(item.groupIndex, row);
return true;
}
@@ -3528,7 +3559,7 @@ namespace jdi
}
else
{
// wParam = 文件下标,lParam = 文件内信号下标(见 Application 的消息处理)。
// wParam = 分组下标,lParam = 组内信号下标(见 Application 的消息处理)。
PostMessageW(m_host, WM_APP + 2, static_cast<WPARAM>(item.groupIndex),
static_cast<LPARAM>(item.signalIndex));
}
@@ -3673,7 +3704,7 @@ namespace jdi
}
// 重命名分组会改变列表行高度以外的展示内容,重建行缓存以保证文字刷新。
m_rowsDirty = true;
return BeginEdit(StyleEditField::FILE_NAME, row);
return BeginEdit(StyleEditField::GROUP_TITLE, row);
}
// 复选框、网格徽标与「移除信号」✕ 各自由单击处理,双击不再切换可见性/进入重命名。
@@ -3705,7 +3736,7 @@ namespace jdi
const ListRow& item = m_rows[static_cast<std::size_t>(row)];
if (item.kind == RowKind::GROUP)
{
OpenFileMenu(item.groupIndex, x, y);
OpenGroupMenu(item.groupIndex, x, y);
return true;
}
@@ -3759,13 +3790,13 @@ namespace jdi
}
m_menuTargetSignal = ref;
m_menuTargetFile = -1;
m_menuTargetGroup = -1;
std::vector<MenuItem> items;
MenuItem header;
header.kind = MenuItemKind::HEADER;
header.label = signal->Title();
header.label = signal->name;
items.push_back(header);
MenuItem toggle;
@@ -3827,7 +3858,7 @@ namespace jdi
m_menu->Open(MenuScope::SIGNAL_PANEL, bounds, x, y, items);
}
void SignalPanel::OpenFileMenu(int groupIndex, int x, int y)
void SignalPanel::OpenGroupMenu(int groupIndex, int x, int y)
{
if (m_menu == nullptr || m_tab == nullptr || m_dataSet == nullptr)
{
@@ -3840,14 +3871,14 @@ namespace jdi
return;
}
m_menuTargetFile = groupIndex;
m_menuTargetGroup = groupIndex;
m_menuTargetSignal = SignalRef();
std::vector<MenuItem> items;
MenuItem header;
header.kind = MenuItemKind::HEADER;
header.label = group->Title();
header.label = group->name;
items.push_back(header);
MenuItem showAll;
@@ -3887,7 +3918,7 @@ namespace jdi
}
m_menuTargetSignal = ref;
m_menuTargetFile = -1;
m_menuTargetGroup = -1;
std::vector<MenuItem> items;
@@ -4089,25 +4120,25 @@ namespace jdi
needRelayout = true;
break;
case CMD_GROUP_SHOW_ALL:
if (m_menuTargetFile >= 0)
if (m_menuTargetGroup >= 0)
{
m_tab->SetGroupVisible(m_menuTargetFile, true);
m_tab->SetGroupVisible(m_menuTargetGroup, true);
m_rowsDirty = true;
needRelayout = true;
}
break;
case CMD_GROUP_HIDE_ALL:
if (m_menuTargetFile >= 0)
if (m_menuTargetGroup >= 0)
{
m_tab->SetGroupVisible(m_menuTargetFile, false);
m_tab->SetGroupVisible(m_menuTargetGroup, false);
m_rowsDirty = true;
needRelayout = true;
}
break;
case CMD_GROUP_REMOVE:
if (m_menuTargetFile >= 0 && m_host != nullptr)
if (m_menuTargetGroup >= 0 && m_host != nullptr)
{
PostMessageW(m_host, WM_APP + 1, static_cast<WPARAM>(m_menuTargetFile), 0);
PostMessageW(m_host, WM_APP + 1, static_cast<WPARAM>(m_menuTargetGroup), 0);
}
break;
case CMD_LANE_NEW: