分组折起热区与改名输入框修正 + 数据模型去冗余(单一名称)+ 新增 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
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user