feat(clip): 新增「选区截取」实验性功能 + 筛选态组复选框只作用于筛选结果 + 重采样统计不被省略
一、重采样面板统计信息不再被省略为 `…`
- 根因:EdgePanelWidth 里数值列按"典型样例"(1h 1min 2s(1.23456 GHz))估宽,
真实文本(16ms 182.614us(61.795 Hz))更长 => 绘制矩形不够宽 => 尾部被裁。
- 新增 FormatIntervalWithFrequency() 作为「间隔(频率)」文本的唯一实现,
宽度计算与绘制共用它;EdgePanelWidth 改为逐信号实测真实文本宽度取最大值。
二、筛选状态下组复选框只作用于「筛选出来的信号」
- TabConfig 新增 SetGroupVisibleSubset / GroupAllVisibleSubset / GroupHasVisibleSubset,
只读写掩码内元素,未通过筛选的信号可见性保持不变。
- SignalPanel::BuildFilterMask 提供逐信号掩码(未筛选时返回 false,走整组语义)。
- 组复选框的点击、绘制、行位图缓存键三处统一改用子集判定
(只改绘制不改缓存键会导致勾选后复选框不刷新)。
三、新增实验性功能「选区截取」(EdgePanelKind::CLIP = 6,PLOT_CMD_LANE_CLIP = 14)
- 菜单位置:实验性功能二级菜单,「重采样」之下、「自由标记」上方,带勾选。
- 面板:逐信号一行(信号色叠底条目栏 + 右侧复选框,不可展开),内容可滚动;
底部两个不滚动的按钮「截取为新信号」与「原始信号截取」;
未启用双光标时两个按钮为空矩形并给出提示。
- 截取为新信号:区间内原始数据(不烘焙)+ 继承源信号整套调整,
名称为 <源信号名> (AAAA - BBBB)(显示时刻、保留三位小数、带 s),插入源信号下方,
使用 AppendGroupAxis 新建的独立时间轴。
- 原始信号截取:DataSet::ClipSignalRange 就地裁剪时间轴与采样,
用新建+swap+shrink_to_fit 真正归还内存,并重算统计与轴的 minTime/maxTime/monotonic。
调用前先 PauseDerivedAsync() 避免后台派生读到已释放采样。
- 时间轴偏移参与区间比较:双光标是显示时刻(time+offsetTime),
BuildClippedSignal 比较时加偏移,ClipSignalInPlace 换算回采样时刻(low-offsetTime)。
- 同步点已全部补齐:LaneCarry(三处)/SplitLane/PruneLaneSignalItems/RemapAfterSignalInsert/
purgeRefs/PanelSlotKey/CollectDebugBoxes/SceneContentHash/kEdgePanelKinds/kOrder/
EdgePanelLayoutFor/EDGE_PANEL_MOVE/m_pendingPanelClose/MEAN_SCROLL/滚轮/悬停/
SetLanePanelCollapsed/LanePanelCollapsed/QueryCursor。
make release 零 warning,产物 860,160 B。
This commit is contained in:
1 parent
5d305cb10f
commit
62220477c0
18 files changed
+1263
-67
No files matched your search
@@ -1486,6 +1486,21 @@ namespace jdi
|
||||
*/
|
||||
bool FilterMatchesSignal(const SignalData& signal) const;
|
||||
|
||||
/**
|
||||
* @brief 取得「筛选状态下该分组中可见(通过筛选)的信号」掩码。
|
||||
*
|
||||
* 用户 2026-11-03 明确要求:筛选时组名前的复选框**只对应组内被筛选出来的信号**。
|
||||
* 因此全选 / 部分选择 / 未选判定,以及点击复选框后的写入范围,
|
||||
* 都以本函数返回的掩码为准(未通过筛选的信号不受影响)。
|
||||
*
|
||||
* 未处于筛选状态时返回**空**掩码(调用方应退回 `GroupAllVisible` 等全组语义)。
|
||||
*
|
||||
* @param [IN] groupIndex 分组下标。
|
||||
* @param [OUT] mask 逐信号掩码(长度 = 该组信号数),true 表示通过筛选。
|
||||
* @return 处于筛选状态返回 true。
|
||||
*/
|
||||
bool BuildFilterMask(int groupIndex, std::vector<bool>& mask) const;
|
||||
|
||||
bool m_pendingLaneMenu = false; /**< 左键抬起时是否弹出网格归属菜单。 */
|
||||
SignalRef m_pendingLaneRef; /**< 待弹出菜单的目标信号。 */
|
||||
bool m_pendingColorPicker = false; /**< 左键抬起时是否弹出拾色器。 */
|
||||
|
||||
@@ -262,6 +262,26 @@ namespace jdi
|
||||
return WildcardMatchNoCase(signal.name, pattern);
|
||||
}
|
||||
|
||||
bool SignalPanel::BuildFilterMask(int groupIndex, std::vector<bool>& mask) const
|
||||
{
|
||||
mask.clear();
|
||||
if (m_filterText.empty() || m_dataSet == nullptr || groupIndex < 0)
|
||||
{
|
||||
return false; // 未筛选:调用方走"整组"语义
|
||||
}
|
||||
const SignalGroup* group = m_dataSet->GroupAt(groupIndex);
|
||||
if (group == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
mask.reserve(group->signals.size());
|
||||
for (const SignalData& signal : group->signals)
|
||||
{
|
||||
mask.push_back(FilterMatchesSignal(signal));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SignalPanel::IsGroupCollapsed(int groupIndex) const
|
||||
{
|
||||
if (groupIndex < 0)
|
||||
|
||||
@@ -485,8 +485,34 @@ namespace jdi
|
||||
{
|
||||
if (part == RowPart::CHECK)
|
||||
{
|
||||
const bool allVisible = m_tab->GroupAllVisible(item.groupIndex);
|
||||
m_tab->SetGroupVisible(item.groupIndex, !allVisible);
|
||||
// ⚠️ 筛选状态下组复选框**只作用于被筛选出来的信号**(用户 2026-11-03 明确要求):
|
||||
// 全选时只勾上筛选结果,取消时也只取消筛选结果,
|
||||
// 不会把未通过筛选的信号一起勾上/取消。
|
||||
std::vector<bool> filterMask;
|
||||
if (BuildFilterMask(item.groupIndex, filterMask))
|
||||
{
|
||||
const bool allVisible = m_tab->GroupAllVisibleSubset(item.groupIndex, filterMask);
|
||||
if (allVisible)
|
||||
{
|
||||
// 取消:只取消筛选结果里的信号(其余保持原状)。
|
||||
for (std::size_t i = 0; i < filterMask.size(); ++i)
|
||||
{
|
||||
if (filterMask[i])
|
||||
{
|
||||
m_tab->SetVisible(SignalRef{item.groupIndex, static_cast<int>(i)}, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tab->SetGroupVisibleSubset(item.groupIndex, filterMask);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool allVisible = m_tab->GroupAllVisible(item.groupIndex);
|
||||
m_tab->SetGroupVisible(item.groupIndex, !allVisible);
|
||||
}
|
||||
m_rowsDirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -341,8 +341,20 @@ namespace jdi
|
||||
mix(static_cast<std::uint64_t>(item.displayCount + 1));
|
||||
if (m_tab != nullptr)
|
||||
{
|
||||
mix(m_tab->GroupAllVisible(item.groupIndex) ? 1ull : 0ull);
|
||||
mix(m_tab->GroupHasVisible(item.groupIndex) ? 2ull : 0ull);
|
||||
// ⚠️ 必须与绘制侧同源:筛选状态下复选框反映的是**筛选子集**的三态,
|
||||
// 若仍用整组的 `GroupAllVisible` 入键,勾选筛选结果后缓存键不变
|
||||
// ⇒ 复选框不会重画(用户 2026-11-03 报告的问题之一)。
|
||||
std::vector<bool> filterMask;
|
||||
if (BuildFilterMask(item.groupIndex, filterMask))
|
||||
{
|
||||
mix(m_tab->GroupAllVisibleSubset(item.groupIndex, filterMask) ? 1ull : 0ull);
|
||||
mix(m_tab->GroupHasVisibleSubset(item.groupIndex, filterMask) ? 2ull : 0ull);
|
||||
}
|
||||
else
|
||||
{
|
||||
mix(m_tab->GroupAllVisible(item.groupIndex) ? 1ull : 0ull);
|
||||
mix(m_tab->GroupHasVisible(item.groupIndex) ? 2ull : 0ull);
|
||||
}
|
||||
}
|
||||
const bool editing = (m_editField == StyleEditField::GROUP_TITLE && m_editRow == row);
|
||||
mix(editing ? 1ull : 0ull);
|
||||
@@ -582,8 +594,21 @@ namespace jdi
|
||||
// 分组复选框(三态:全选 / 部分 / 未选)。
|
||||
const gd::RectF checkRect(baseX + kDisclosureWidth * m_scale, centerY - kCheckSize * m_scale * 0.5f,
|
||||
kCheckSize * m_scale, kCheckSize * m_scale);
|
||||
const bool allVisible = m_tab->GroupAllVisible(item.groupIndex);
|
||||
const bool anyVisible = m_tab->GroupHasVisible(item.groupIndex);
|
||||
// ⚠️ 筛选状态下复选框**只反映组内被筛选出来的信号**(用户 2026-11-03 明确要求):
|
||||
// 「不论是否筛选,这个复选框影响的都只有当前组名下显示的元素」。
|
||||
std::vector<bool> filterMask;
|
||||
bool allVisible = false;
|
||||
bool anyVisible = false;
|
||||
if (BuildFilterMask(item.groupIndex, filterMask))
|
||||
{
|
||||
allVisible = m_tab->GroupAllVisibleSubset(item.groupIndex, filterMask);
|
||||
anyVisible = m_tab->GroupHasVisibleSubset(item.groupIndex, filterMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
allVisible = m_tab->GroupAllVisible(item.groupIndex);
|
||||
anyVisible = m_tab->GroupHasVisible(item.groupIndex);
|
||||
}
|
||||
UiDrawCheckBox(g, checkRect, allVisible ? 1 : (anyVisible ? 2 : 0), 3.0f * m_scale);
|
||||
|
||||
const gd::RectF closeRect = GroupCloseRect(row);
|
||||
|
||||
Reference in new issue
Block a user