fix: 修复网格滚动溢出并重构绘图区缩放与时间光标交互

网格滚动:
- 修复纵向滚动时波形与文字溢出到工具栏/时间轴的问题:网格内容裁剪改为与绘图区求交,
  并对网格内的图例、幅值标签与读数框增加显式可见性判定
  (GDI 文本不遵循 GDI+ 裁剪区,仅裁剪矢量绘制不足以阻止溢出)。
- 网格之间改为完整矩形描边并加大间距,边界清晰;时间轴固定预留高度,不再被网格挤压。
- 时间轴刻度标签夹在绘图区横向范围内,避免与左侧时间列名重叠。

缩放交互:
- 取消滚轮缩放:滚轮改为纵向滚动网格,Shift+滚轮水平平移。
- 新增「时间轴缩放」「Y 轴缩放」工具栏切换按钮:选中后在绘图区拖拽选区放大对应轴向,
  拖动过程显示选区与跨度提示(时间用强调色、Y 轴用警示色);再次点击退出该模式。
- 「适应视图」回到初始状态:恢复自适应范围并退出缩放模式。
- 移除右键框选缩放,避免与模式化缩放重复。

时间光标:
- 改为工具栏「光标」按钮切换;启用时置于当前视图中心,再次点击关闭(Esc 亦可关闭)。
- 光标由鼠标靠近后拖拽移动,不再跟随鼠标;纵向贯穿全部网格并延伸到时间轴底部,
  顶部带三角把手提示可拖拽。
- 具体时间读数移至绘图区顶部,仅在鼠标覆盖光标时显示,不再遮挡时间轴刻度尺。
- 双击光标进入精确时间输入,交互与线宽输入一致:整段高亮、首次键入即整体覆盖、
  回车提交、Esc 取消、点击框外提交。
- 光标形态按模式区分:默认与悬停线外为箭头(不再出现十字指针),
  时间轴缩放/光标为水平双向箭头,Y 轴缩放为垂直双向箭头。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-09-29 19:32:37 +08:00
1 parent cba62c8218
commit 17eb03a1b3
6 files changed
+852 -359

No files matched your search

+63 -33
View File
@@ -32,7 +32,8 @@ namespace jdi
const int kMinClientWidth = 860; /**< 窗口最小客户区宽度。 */
const int kMinClientHeight = 540; /**< 窗口最小客户区高度。 */
const UINT kMessageRemoveFile = WM_APP + 1; /**< 面板请求移除文件的自定义消息。 */
const wchar_t* kStatusHint = L"滚轮缩放 · Shift+滚轮平移 · Ctrl+滚轮调幅值 · 右键框选 · 双击自适应";
const wchar_t* kStatusHint =
L"滚轮纵向滚动网格 · Shift+滚轮平移 · 双击绘图区恢复自适应 · Esc 关闭光标";
/** @brief 标签页右键菜单命令 ID。 */
const int kMenuTabNew = 1;
@@ -576,6 +577,13 @@ namespace jdi
m_toolbar.SetStatusText(std::wstring());
}
// 工具栏可切换按钮的选中状态始终与当前标签页配置保持一致。
m_toolbar.SetToggleState(ToolbarAction::ZOOM_TIME,
m_plot.CurrentZoomMode() == PlotZoomMode::TIME);
m_toolbar.SetToggleState(ToolbarAction::ZOOM_VALUE,
m_plot.CurrentZoomMode() == PlotZoomMode::VALUE);
m_toolbar.SetToggleState(ToolbarAction::CURSOR, m_plot.CursorEnabled());
{
gd::Graphics g(m_backDc);
g.SetSmoothingMode(gd::SmoothingModeAntiAlias);
@@ -641,7 +649,7 @@ namespace jdi
rightText = m_statusMessage;
rightColor = m_statusIsError ? m_theme.danger : m_theme.textStrong;
}
else if (m_plot.HasCursor() && !m_dataSet.Empty())
else if (m_plot.CursorEnabled() && !m_dataSet.Empty())
{
rightText = L"光标 · " + FormatValue(m_plot.CursorTime());
rightColor = m_theme.text;
@@ -813,13 +821,36 @@ namespace jdi
OpenFileDialog();
break;
case ToolbarAction::FIT_ALL:
// 自适应同时回到初始状态:退出缩放模式并显示全部信号范围。
m_plot.FitAll();
SetStatusMessage(L"已恢复自适应视图。", false);
break;
case ToolbarAction::ZOOM_IN:
m_plot.ZoomTimeStep(1.4);
case ToolbarAction::ZOOM_TIME:
if (m_plot.ToggleZoomMode(PlotZoomMode::TIME))
{
SetStatusMessage((m_plot.CurrentZoomMode() == PlotZoomMode::TIME)
? L"时间轴缩放:在绘图区横向拖拽选择区间即可放大。"
: L"已退出时间轴缩放模式。",
false);
}
break;
case ToolbarAction::ZOOM_OUT:
m_plot.ZoomTimeStep(1.0 / 1.4);
case ToolbarAction::ZOOM_VALUE:
if (m_plot.ToggleZoomMode(PlotZoomMode::VALUE))
{
SetStatusMessage((m_plot.CurrentZoomMode() == PlotZoomMode::VALUE)
? L"Y 轴缩放:在某个网格内纵向拖拽选择区间即可放大。"
: L"已退出 Y 轴缩放模式。",
false);
}
break;
case ToolbarAction::CURSOR:
if (m_plot.ToggleCursor())
{
SetStatusMessage(m_plot.CursorEnabled()
? L"时间光标已启用:拖动竖线移动,双击竖线可输入精确时间。"
: L"时间光标已关闭。",
false);
}
break;
case ToolbarAction::MERGE_LANES:
if (!m_dataSet.Empty())
@@ -895,7 +926,7 @@ namespace jdi
switch (key)
{
case VK_ESCAPE:
m_plot.ClearCursor();
m_plot.DisableCursor();
return true;
case VK_ADD:
case VK_OEM_PLUS:
@@ -1336,6 +1367,12 @@ namespace jdi
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
// 时间光标处于精确输入态时,点击绘图区之外视为提交(与线宽输入一致)。
if (m_plot.IsEditingCursor() && !m_plot.HitTest(x, y))
{
m_plot.OnEditKey(VK_RETURN);
}
// 点击面板之外的位置时收起面板内展开的自定义颜色面板。
if (!m_panel.HitTest(x, y))
{
@@ -1496,33 +1533,12 @@ namespace jdi
m_activeTarget = Target::NONE;
return 0;
}
if (m_plot.HitTest(x, y))
{
SetCapture(hwnd);
m_activeTarget = Target::PLOT;
if (m_plot.OnRButtonDown(x, y))
{
InvalidateRect(hwnd, nullptr, FALSE);
}
return 0;
}
return 0;
}
case WM_RBUTTONUP:
{
const int x = GET_X_LPARAM(lParam);
const int y = GET_Y_LPARAM(lParam);
bool changed = false;
if (m_activeTarget == Target::PLOT)
{
changed = m_plot.OnRButtonUp(x, y);
}
ReleaseCapture();
m_activeTarget = Target::NONE;
if (changed)
{
InvalidateRect(hwnd, nullptr, FALSE);
}
return 0;
}
case WM_MOUSEWHEEL:
@@ -1531,9 +1547,7 @@ namespace jdi
ScreenToClient(hwnd, &point);
const int delta = GET_WHEEL_DELTA_WPARAM(wParam);
const bool control = (GET_KEYSTATE_WPARAM(wParam) & MK_CONTROL) != 0;
const bool shift = (GET_KEYSTATE_WPARAM(wParam) & MK_SHIFT) != 0;
const bool alt = (GetKeyState(VK_MENU) & 0x8000) != 0;
bool changed = false;
if (m_panel.HitTest(point.x, point.y))
@@ -1542,7 +1556,7 @@ namespace jdi
}
else if (m_plot.HitTest(point.x, point.y))
{
changed = m_plot.OnMouseWheel(point.x, point.y, delta, control, shift, alt);
changed = m_plot.OnMouseWheel(point.x, point.y, delta, shift);
}
if (changed)
{
@@ -1577,7 +1591,7 @@ namespace jdi
break;
}
case WM_KEYDOWN:
// 线宽数值输入状态优先接管按键(回车提交、Esc 取消、退格删除)。
// 数值输入状态优先接管按键(回车提交、Esc 取消、退格删除)。
if (m_panel.IsEditingWidth())
{
if (m_panel.OnEditKey(wParam))
@@ -1586,6 +1600,14 @@ namespace jdi
}
return 0;
}
if (m_plot.IsEditingCursor())
{
if (m_plot.OnEditKey(wParam))
{
InvalidateRect(hwnd, nullptr, FALSE);
}
return 0;
}
if (HandleKeyDown(wParam))
{
InvalidateRect(hwnd, nullptr, TRUE);
@@ -1594,7 +1616,7 @@ namespace jdi
break;
case WM_CHAR:
{
// 线宽数值仅接受数字与小数点,其余字符一律吞掉。
// 数值输入仅接受数字与小数点(或科学计数法符号),其余字符一律吞掉。
if (m_panel.IsEditingWidth())
{
if (m_panel.OnEditChar(static_cast<wchar_t>(wParam)))
@@ -1603,6 +1625,14 @@ namespace jdi
}
return 0;
}
if (m_plot.IsEditingCursor())
{
if (m_plot.OnEditChar(static_cast<wchar_t>(wParam)))
{
InvalidateRect(hwnd, nullptr, FALSE);
}
return 0;
}
break;
}
case WM_KILLFOCUS: