信号 X 按钮移至行尾并统一抬起响应,光标读数补秒单位,图例悬停高亮信号,去除筛选框内圈

1. 信号条目的「移除」X 按钮移到最右端
   - 与分组行关闭 X 同尺寸(18)、同右边距(同一列)、同行内垂直居中,描边宽度也统一。
   - 网格编号 GX 徽标让位到 X 左侧,二者恒在列表最右侧;名称可用宽度改按实际徽标是否显示计算,
     不再白留一段空间。

2. 所有 X 关闭按钮由"按下即响应"改为"左键抬起才响应"
   - 与常见的可取消按钮一致:按下只记录目标,按住后移开鼠标再松开视为放弃。
   - 覆盖文件分组 X、信号 X、筛选框清空 X、标签页 X 与实验性功能面板 X。
   - 筛选框的清空 X 在编辑态下走的是宿主的 EDIT_FIELD 分支(OnEditMouseDown/OnEditMouseUp),
     非编辑态才走面板的按下/抬起分支,两条路径都已改造。
   - 标签页 X 原先只要求"抬起时仍在同一标签内",现收紧为"仍在 X 上"。
   - PlotView::OnLButtonUp 增加横坐标参数以便判定抬起位置。

3. 时间光标读数补上 s 后缀
   - 新增 FormatCursorTime,标签宽度测量与文字绘制同时使用,避免文字被裁掉;
     内联编辑仍使用不带单位的秒值。

4. 鼠标悬停网格图例时高亮对应信号
   - 除图例条目的半高亮外,对命中信号绘制与"鼠标贴近曲线"相同的光晕,
     便于确认该条目对应哪条曲线。

5. 筛选信号输入框编辑态不再出现内圈
   - 把输入框绘制拆分为"底板+边框"与"仅内容"两部分;筛选框外框已自绘,
     编辑态改用仅内容版本,空内容时不再套一层多余的圆角内框;
     有输入时的清空 X 不受影响。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-10 11:30:07 +08:00
1 parent a1e30985b8
commit d3c83237f1
8 files changed
+252 -72

No files matched your search

+70 -19
View File
@@ -364,6 +364,20 @@ namespace jdi
return L"Δt:" + FormatDurationCompound(seconds);
}
/**
* @brief 时间光标的读数文本("数值 + s 后缀")。
*
* 时间轴本身就是秒,但与幅值读数放在一起时没有单位容易误读,
* 因此读数恒带 "s" 后缀;内联编辑仍使用不带单位的纯数值(见 BeginEdit 调用处)。
*
* @param [IN] seconds 光标所在时刻(秒)。
* @return 形如 "1.25s" 的文本。
*/
std::wstring FormatCursorTime(double seconds)
{
return FormatValue(seconds) + L"s";
}
/**
* @brief 把时间间隔格式化为"秒"数值文本(不含单位),用于内联编辑。
*
@@ -1313,7 +1327,7 @@ namespace jdi
const auto rawRect = [this](int index) -> gd::RectF
{
const double time = (index == 2) ? Tab().CursorTimeAlt() : Tab().CursorTime();
const std::wstring text = FormatValue(time);
const std::wstring text = FormatCursorTime(time);
const float width =
std::max(64.0f * m_scale, UiMeasureTextWidth(m_fonts->monoSmall, text) + 16.0f * m_scale);
const float height = 20.0f * m_scale;
@@ -3338,6 +3352,9 @@ namespace jdi
m_cursorGrabOffset = 0;
// 新的交互开始:清掉上一次留下的提示(拖动过程中会重新设置粘滞提示)。
SetHint(std::wstring());
// 上一轮尚未抬起确认的面板关闭请求一律作废。
m_pendingPanelClose = false;
m_pendingPanelCloseLane = -1;
if (m_scrollBarVisible &&
UiPointInRect(m_scrollBarRect, static_cast<float>(x), static_cast<float>(y)))
@@ -3416,22 +3433,11 @@ namespace jdi
if (UiPointInRect(layout.close, fx, fy))
{
// ✕ 关闭面板的同时关闭该网格对应的实验性功能。
switch (kind)
{
case EdgePanelKind::CENTER:
SetLaneEdgeCenterCount(index, false);
break;
case EdgePanelKind::MEAN:
SetLaneMeanFilter(index, false);
break;
case EdgePanelKind::COUNT:
default:
SetLaneEdgeCount(index, false);
break;
}
m_dragMode = PlotDragMode::NONE;
return true;
// ✕:**抬起**时才关闭该网格对应的实验性功能,这里只记录目标;
// 按住后移开再松开视为放弃(与面板/标签栏的关闭 ✕ 语义一致)。
m_pendingPanelClose = true;
m_pendingPanelCloseLane = index;
m_pendingPanelCloseKind = kind;
}
if ((kind == EdgePanelKind::CENTER || kind == EdgePanelKind::MEAN) &&
@@ -3584,10 +3590,42 @@ namespace jdi
return changed;
}
bool PlotView::OnLButtonUp(int y)
bool PlotView::OnLButtonUp(int x, int y)
{
bool changed = (m_dragMode != PlotDragMode::NONE);
// 实验性功能面板的 ✕:只有"按下后仍在同一个 ✕ 上抬起"才真正关闭该功能。
if (m_pendingPanelClose)
{
const int lane = m_pendingPanelCloseLane;
const EdgePanelKind kind = m_pendingPanelCloseKind;
m_pendingPanelClose = false;
m_pendingPanelCloseLane = -1;
if (lane >= 0 && lane < static_cast<int>(m_lanes.size()))
{
const EdgePanelLayout layout = EdgePanelLayoutFor(lane, kind);
if (layout.close.Width > 0.0f &&
UiPointInRect(layout.close, static_cast<float>(x), static_cast<float>(y)))
{
switch (kind)
{
case EdgePanelKind::CENTER:
SetLaneEdgeCenterCount(lane, false);
break;
case EdgePanelKind::MEAN:
SetLaneMeanFilter(lane, false);
break;
case EdgePanelKind::COUNT:
default:
SetLaneEdgeCount(lane, false);
break;
}
changed = true;
}
}
}
switch (m_dragMode)
{
case PlotDragMode::RUBBER_SELECT:
@@ -4370,6 +4408,19 @@ namespace jdi
const int saveState = g.Save();
g.SetClip(m_area, gd::CombineModeIntersect);
// 除了图例条目本身,还要把**对应的信号曲线**一并高亮:用户在网格图例上移动时
// 一眼就能确认这条条目对应哪条曲线(与"鼠标贴近曲线"时的光晕提示一致)。
const ResolvedSignal resolved = ResolveSignal(m_hoverLegend);
if (resolved.data != nullptr && resolved.style != nullptr && resolved.visible)
{
const LaneVisual& lane = m_lanes[static_cast<std::size_t>(laneIndex)];
if (const PolylineCacheEntry* cached = AcquirePolyline(m_hoverLegend, resolved, lane))
{
PaintSignalHalo(g, resolved, cached->points, cached->breaks);
}
}
for (const LegendHit& hit : m_legendHits)
{
if (hit.ref == m_hoverLegend)
@@ -5656,7 +5707,7 @@ namespace jdi
highlighted ? color : WithAlpha(color, 0xE0));
const bool dark = IsDarkColor(color);
DrawLabelOutline(g, labelRect, 3.0f * m_scale, dark);
UiText(g, FormatValue(which == 2 ? Tab().CursorTimeAlt() : Tab().CursorTime()),
UiText(g, FormatCursorTime(which == 2 ? Tab().CursorTimeAlt() : Tab().CursorTime()),
m_fonts->monoSmall, labelRect,
dark ? 0xFFFDF6E3u : 0xFF073642u, TextAlign::CENTER);
}