288 信号卡顿根治 + 中心轴面板重做 + 标签页默认状态
一、卡顿真因(实测 29.8ms/帧 → 6.6ms/帧) 1. 中心轴面板高度没有上限:288 个信号时面板高 9996px(绘图区只有 1141px) ⇒ PanelRectInsideLayer 恒为假 ⇒ 面板像素缓存一次都存不进去 ⇒ 每帧全量重画。 2. PanelGlobalKey 混入鼠标驱动状态(m_hoverSignal / m_hoverLane / m_hoverCursor / CursorTime / EdgeRangeMin/Max)⇒ 鼠标一动键就变 ⇒ 所有面板每帧重画; PanelSlotKey 里还会为每个信号调一次 EdgeCenterCountsFor(单帧 288 次查询)。 3. 缓存命中路径的投影(与面板同大的半透明抗锯齿圆角矩形)每帧重画,GDI+ 实测 > 20ms。 修法: * 新增 PlotView::InputIsInteractive()(拖拽中 / 鼠标 140ms 内移动过)。交互期间冻结 全部鼠标驱动项与统计数字、跳过投影、统计预算降到 8 万(静止时 40 万)。 m_meanRowHoverLane/Ref 例外 —— 它直接改面板像素且只在进出某行时变化。 * kEdgeScanPairsPerFrame 由 1,200,000 降为 400,000。 * 中心轴面板重做为可滚动列表 ⇒ 面板高度被绘图区夹住、缓存可用、只画可见行。 二、「中心轴边沿计数」面板重做(与「均值滤波」同风格) 条目栏为信号色叠底的可折叠栏 + 右端复选框;栏下同一行显示「上升沿 / 下降沿」; 再下面两行滑块(均值点数 / 迭代次数,标签不带 X/N),数值可点击输入上限、 右侧复位按钮;整个面板可滚动;未勾选时条目栏不可展开。 新增 Lane::edgeCenterScroll + SetLaneEdgeCenterScroll;交互复用 MEAN_* 拖拽模式 + m_meanDragCenter / m_editMeanCenter 标志分派;光标形状与均值滤波一致。 三、标签页 * 唯一标签页点 ✕ 不再弹警告:直接 erase 后 NewTab(true),名字必然为「视图 1」。 * 新建标签页(含手动新建)默认:组全部折起、无选中信号(清空全局 Selected)、 样式区无目标。 四、验证 .preflight/bugcheck.exe 59/59(A1 空闲 0.7ms、A2 平移 2.5ms、A3 双光标 2.4ms、 A4 自由标记 5.2ms、A5 中心轴拖动 6.6ms;B3 真实 WM_TIMER+WM_PAINT 路径; B5 快速连点与动画反向;C 中心轴面板交互;D 标签页默认状态) panelcheck 71/71、markercheck 13/13、ringcheck 6/6 make release / make debug 零 warning
This commit is contained in:
1 parent
8271879ede
commit
944c074ab3
11 files changed
+618
-122
No files matched your search
@@ -28,8 +28,10 @@ namespace jdi
|
||||
const bool centerAxis = (kind == EdgePanelKind::CENTER);
|
||||
const bool meanFilter = (kind == EdgePanelKind::MEAN);
|
||||
const bool weakPeak = (kind == EdgePanelKind::PEAK);
|
||||
// 「均值滤波」「中心轴边沿计数」「弱峰调整」都是逐条目面板(名称 + 复选框)。
|
||||
const bool itemized = (centerAxis || meanFilter || weakPeak);
|
||||
// 「弱峰调整」仍是旧式逐条目面板(名称 + 复选框 + 两行滑块)。
|
||||
// ⚠️ 「均值滤波」与「中心轴边沿计数」已改为**可滚动的分组列表**(信号色叠底条目栏),
|
||||
// 它们的宽度由下面的 `groupWidth` / 滑块行分支确定。
|
||||
const bool itemized = weakPeak;
|
||||
|
||||
// 标题行 = “GX” 徽标 + 标题(“边沿计数” / “中心轴边沿计数” / “均值滤波” / “弱峰调整”
|
||||
// + 光标区间尾缀)。
|
||||
@@ -69,10 +71,10 @@ namespace jdi
|
||||
width = std::max(width, kEdgePanelPad * 2.0f * m_scale + nameWidth +
|
||||
kEdgePanelMeanCheckSize * m_scale + 6.0f * m_scale);
|
||||
}
|
||||
if (meanFilter)
|
||||
if (meanFilter || centerAxis)
|
||||
{
|
||||
// 「均值滤波」的条目 = **信号色叠底标题栏**(三角 + 名称 + 复选框)
|
||||
// 与两行滑块(标签 + 轨道 + 数值 + 复位按钮),右侧还要给滚动条留位。
|
||||
// 「均值滤波 / 中心轴边沿计数」的条目 = **信号色叠底条目栏**(三角 + 名称 + 复选框)
|
||||
// 与参数行(标签 + 轨道 + 数值 + 复位按钮),右侧还要给滚动条留位。
|
||||
const float groupWidth = kEdgePanelPad * 2.0f * m_scale +
|
||||
kEdgePanelDisclosureWidth * m_scale + 6.0f * m_scale +
|
||||
nameWidth + 6.0f * m_scale +
|
||||
@@ -124,21 +126,7 @@ namespace jdi
|
||||
std::max(nameColumnWidth, countsWidth));
|
||||
}
|
||||
|
||||
if (centerAxis || meanFilter)
|
||||
{
|
||||
// 参数行 = 两个「说明文字 + 数值框」,必须保证文字不被数值框压住。
|
||||
// (CENTER:「均值点数 X」+「迭代次数 N」。MEAN 已改为滑块,见下面单独的分支。)
|
||||
const float labelXWidth = UiMeasureTextWidth(m_fonts->uiSmall, L"均值点数 X");
|
||||
const float labelN = UiMeasureTextWidth(m_fonts->uiSmall, L"迭代次数 N");
|
||||
const float fieldWidth =
|
||||
std::max(kEdgePanelEditFieldWidth * m_scale * 0.75f,
|
||||
UiMeasureTextWidth(m_fonts->monoSmall, L"1000000") + 18.0f * m_scale);
|
||||
const float halfWidth = std::max(labelXWidth, labelN) + 6.0f * m_scale + fieldWidth;
|
||||
const float rowWidth = halfWidth * 2.0f + 8.0f * m_scale;
|
||||
width = std::max(width, kEdgePanelPad * 2.0f * m_scale + rowWidth);
|
||||
}
|
||||
|
||||
if (meanFilter)
|
||||
if (meanFilter || centerAxis)
|
||||
{
|
||||
// 两行滑块 = 「标签列 + 轨道(最小宽度)+ 数值列 + 复位按钮」(两行共用同一列宽),
|
||||
// 右侧再给滚动条留位(上百个信号时内容必然超高)。
|
||||
@@ -263,7 +251,11 @@ namespace jdi
|
||||
// 「均值滤波」与「弱峰调整」共用同一套「逐条目 + 底部按钮」排布。
|
||||
// ⚠️ 「均值滤波」从 2026-10-30 起改为**可滚动的分组列表**(信号色叠底标题栏 +
|
||||
// 展开后的两行滑块),与「自由标记」同一套浏览方式 ⇒ 不再走这里的 `itemized` 分支。
|
||||
const bool itemized = (centerAxis || weakPeak);
|
||||
// ⚠️ 「中心轴边沿计数」从 2026-11-02 起同样改为**可滚动的分组列表**(用户明确要求
|
||||
// “改造为与均值滤波相同的风格”)⇒ 也不走 `itemized`。它没有「构建为新信号」按钮,
|
||||
// 但内容多一行「上升沿 / 下降沿」统计。
|
||||
const bool listStyle = (meanFilter || centerAxis);
|
||||
const bool itemized = weakPeak;
|
||||
const bool hasButton = (meanFilter || weakPeak);
|
||||
const bool enabled = meanFilter ? lane.meanFilter
|
||||
: (weakPeak ? lane.weakPeak
|
||||
@@ -322,11 +314,12 @@ namespace jdi
|
||||
float itemsHeight = 0.0f;
|
||||
float meanContentHeight = 0.0f;
|
||||
float height = 0.0f;
|
||||
if (meanFilter)
|
||||
if (listStyle)
|
||||
{
|
||||
// 「均值滤波」:内容区 = 逐信号的**信号色叠底标题栏**(内容总是显示,
|
||||
// 用于勾选/取消预览)+(勾选且未收起时)两行参数滑块。
|
||||
// 内容超高时出现滚动条;底部「构建为新信号」按钮固定不滚动。
|
||||
// 「均值滤波 / 中心轴边沿计数」:内容区 = 逐信号的**信号色叠底条目栏**
|
||||
//(内容总是显示,用于勾选/取消)+(勾选且未收起时)参数行。
|
||||
// 「中心轴」的参数行 = 一行「上升沿 / 下降沿」统计 + 两行滑块;
|
||||
// 「均值滤波」= 两行滑块。内容超高时出现滚动条;底部「构建为新信号」按钮固定不滚动。
|
||||
const float groupRow = kEdgePanelMeanRowHeight * m_scale;
|
||||
const float sliderRow = weakPeakSliderRow;
|
||||
float content = 0.0f;
|
||||
@@ -338,10 +331,15 @@ namespace jdi
|
||||
continue;
|
||||
}
|
||||
content += groupRow;
|
||||
const Lane::MeanFilterItem* item = lane.FindMeanFilterItem(ref);
|
||||
const Lane::MeanFilterItem* item = meanFilter ? lane.FindMeanFilterItem(ref)
|
||||
: lane.FindEdgeCenterItem(ref);
|
||||
if (item != nullptr && !item->collapsed)
|
||||
{
|
||||
content += sliderRow * 2.0f;
|
||||
if (centerAxis)
|
||||
{
|
||||
content += groupRow; // 统计行(上升沿 / 下降沿)
|
||||
}
|
||||
}
|
||||
}
|
||||
meanContentHeight = content;
|
||||
@@ -562,12 +560,16 @@ namespace jdi
|
||||
{
|
||||
return layout;
|
||||
}
|
||||
if (meanFilter)
|
||||
if (listStyle)
|
||||
{
|
||||
// 「均值滤波」:可滚动内容区(逐信号的信号色叠底标题栏 + 展开后的两行滑块)+ 底部按钮。
|
||||
// 「均值滤波 / 中心轴边沿计数」:可滚动内容区
|
||||
//(逐信号的信号色叠底条目栏 + 展开后的统计行与两行滑块)+(均值滤波)底部按钮。
|
||||
const float buttonRowHeight = kEdgePanelButtonHeight * m_scale;
|
||||
layout.button = gd::RectF(left + pad, top + height - pad - buttonRowHeight,
|
||||
std::max(0.0f, width - pad * 2.0f), buttonRowHeight);
|
||||
if (hasButton)
|
||||
{
|
||||
layout.button = gd::RectF(left + pad, top + height - pad - buttonRowHeight,
|
||||
std::max(0.0f, width - pad * 2.0f), buttonRowHeight);
|
||||
}
|
||||
|
||||
const float groupRow = kEdgePanelMeanRowHeight * m_scale;
|
||||
const float sliderRow = kWeakPeakSliderRowHeight * m_scale;
|
||||
@@ -576,7 +578,8 @@ namespace jdi
|
||||
std::max(0.0f, height - titleHeight - pad * 3.0f - buttonRowHeight);
|
||||
const bool scrollable = meanContentHeight > viewHeight + 0.5f;
|
||||
const float maxScroll = std::max(0.0f, meanContentHeight - viewHeight);
|
||||
const float scroll = std::max(0.0f, std::min(lane.meanFilterScroll, maxScroll));
|
||||
const float storedScroll = meanFilter ? lane.meanFilterScroll : lane.edgeCenterScroll;
|
||||
const float scroll = std::max(0.0f, std::min(storedScroll, maxScroll));
|
||||
const float innerWidth =
|
||||
std::max(0.0f, width - pad * 2.0f - (scrollable ? (scrollW + 4.0f * m_scale) : 0.0f));
|
||||
layout.content = gd::RectF(left + pad, top + titleHeight + pad, innerWidth, viewHeight);
|
||||
@@ -621,7 +624,8 @@ namespace jdi
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const Lane::MeanFilterItem* item = lane.FindMeanFilterItem(ref);
|
||||
const Lane::MeanFilterItem* item = meanFilter ? lane.FindMeanFilterItem(ref)
|
||||
: lane.FindEdgeCenterItem(ref);
|
||||
const bool checked = (item != nullptr);
|
||||
layout.rowRefs.push_back(ref);
|
||||
// 组头(信号色叠底):整行宽度,左侧三角(仅勾选时)+ 名称,右端复选框。
|
||||
@@ -653,6 +657,12 @@ namespace jdi
|
||||
layout.rowIterResets.push_back(gd::RectF());
|
||||
continue;
|
||||
}
|
||||
// 「中心轴边沿计数」:参数行最上面是**同一行**的「上升沿 / 下降沿」统计。
|
||||
if (centerAxis && !layout.rowStats.empty())
|
||||
{
|
||||
layout.rowStats.back() = gd::RectF(contentLeft, rowY, innerWidth, groupRow);
|
||||
rowY += groupRow;
|
||||
}
|
||||
const gd::RectF pointsTrack(trackLeft, rowY + (sliderRow - trackHeight) * 0.5f,
|
||||
trackWidth, trackHeight);
|
||||
layout.rowLevelTracks.push_back(pointsTrack);
|
||||
|
||||
Reference in new issue
Block a user