1) 打开「选区 Y 轴自适应」时立即自适应一次
- 之前打开开关(单个网格的菜单项或全局项/工具栏按钮)不会真的改变量程,
只有当用户再次做时间轴选区放大时才生效,观感上就是"点了没反应"
- ToggleLaneAutoFitToSelection / SetAllLanesAutoFitToSelection(enable, applyNow=true)
在打开时按当前视图立刻执行一次 AutoRangeLaneToView
- 新增 ApplyAutoFitToSelectionNow / ApplyAllAutoFitToSelectionNow
2) 「按网格时间轴展开」同时对该网格做一次 Y 轴自适应
- FitTimeToLane 在把时间轴展开到本网格信号范围后调用 AutoRangeLaneToView,
避免出现"时间对了但幅值区间不合适"的波形
3) 修复时间光标在大幅放大后丢失、无法拖动的问题
- 根因:缩放/平移改变 ViewMin/ViewMax 后,光标时间可能落到新视野之外,
PaintCursor 直接 return → 光标消失,用户报告为"放大到 10ms 一格后拖动光标会直接丢失"
- 新增 ClampCursorToView(),在 ApplyTimeSelection / FitAll / FitTimeToLane /
平移(PAN) 后把两条光标夹回可见区间;CURSOR_MOVE 也把目标时间夹在 [ViewMin, ViewMax]
- IsOnCursorLine 改为输出命中的光标序号,为双光标拖动做准备
4) 工具栏「时间轴选区」+「Y 轴选区」合并为「选区放大」,并支持右键放弃选区
- 单一 toggle(ToolbarAction::ZOOM_SELECT / PlotZoomMode::SELECT);
按下后按首次明显位移方向决定轴向:横向=时间轴选区,纵向=该网格 Y 轴选区,
轴向固定不变,轴向未定时不画选区(避免闪烁)
- 框选过程中按右键 = 放弃当前选区并显示提示浮层;与 Esc 不同,**不退出**选区放大模式
- 为此 WM_RBUTTONUP 在左键仍按下时不 ReleaseCapture / 不清 m_activeTarget,
否则松左键收不到 OnLButtonUp,m_dragMode 会永远停在 RUBBER_SELECT
- 新增 PlotView 内的提示浮层(m_hintText + PaintHint):切换模式/放弃选区时显示一行说明,
在网格内再次移动鼠标自动清除,无需定时器
- Esc 语义保持原样:放弃拖拽 + 退出选区放大模式
5) 光标功能改为三态:常态 → 单光标 → 双光标 → 常态
- TabConfig 用 PlotCursorMode{NONE,SINGLE,DOUBLE} + CursorTime/CursorTimeAlt 两个时间;
CursorEnabled() 变成只读派生;ToggleCursor 删除,改为 CycleCursorMode()
- 单 → 双时第二条光标落在第一条附近(+12% 视图跨度,越界反向)并保证在可见范围内
- 两条光标颜色区分且同族:光标 1 = Solarized 橙 #CB4B16(theme.cursor),
光标 2 = 青 #2AA198(新增 theme.cursorAlt),光标 2 的顶部把手画成朝上的三角
- 时间读数从绘图区顶部移到**底部**,单/双光标都始终显示(不必悬停才可见)
6) 取消原有的光标数值读数框,改为直接在数据点位置标注取值
- 删除 PaintLaneReadout/PaintLaneReadouts(网格右上角的读数框)
- PaintCursor 在光标与每条可见信号曲线的交点处绘制信号色圆角胶囊(底色=信号色,
文字按 IsDarkColor 自动取深/浅色),一条信号一个标注,颜色与信号一一对应;
右侧空间不足时自动标到左侧
- 双光标时以时间较小者为左;**右侧光标**显示"当前值 , ±增量"(增量 = 右 − 左),
增量为负时用负号前缀,避免出现 "±-" 双符号
验证([1].CSV 11 信号 / VERY_BIG_DATA 1.77GB,窗口 1725x996,125% DPI):
- 三态循环:点 1 次出现单光标、2 次双光标、3 次回到无光标
- 双光标读数:左"426.316 / 427.749",右"538.583 , ±112.267 / 513.726 , ±85.9769"
- 时间读数在底部显示(橙 0.63 / 青 0.7812);第二条光标出现在第一条右侧同一视野内
- 超大文件:放大两次后开启光标仍然可见,拖动从 68.2343 变为 68.1911(原先直接消失)
- 「Y 轴自适应」在放大后的视图中点击立即把量程收到可见区间(300~520)
- 「选区 Y 轴自适应」菜单项点击后立即生效并被勾选,全局项同步勾选
- 「按网格时间轴展开」把时间轴展开回全范围并重新自适应 Y 轴
- 选区放大:横向拖拽只放大时间轴、纵向拖拽只放大 Y 轴;右键放弃后视图不变、提示出现、
模式仍保持选中;Esc 则同时放弃并退出模式
- 回归:空闲 CPU 0.00%;make clean; make all 无警告无错误
161 lines
4.9 KiB
C++
161 lines
4.9 KiB
C++
#ifndef __TOOLBAR_HPP__
|
|
#define __TOOLBAR_HPP__
|
|
|
|
#include <windows.h>
|
|
#include <objidl.h>
|
|
#include <gdiplus.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "PaintUtil.hpp"
|
|
#include "Theme.hpp"
|
|
|
|
namespace jdi
|
|
{
|
|
|
|
/**
|
|
* @brief 工具栏按钮触发的动作。
|
|
*/
|
|
enum class ToolbarAction : int
|
|
{
|
|
NONE = 0, /**< 未触发任何动作。 */
|
|
OPEN_FILE, /**< 打开 CSV 文件。 */
|
|
FIT_ALL, /**< 视图自适应到可见信号范围(同时退出缩放模式)。 */
|
|
AUTO_FIT_Y, /**< 切换「选区 Y 轴自适应」全局开关:时间轴选区放大后自动匹配各网格 Y 轴。 */
|
|
ZOOM_SELECT, /**< 切换「选区放大」模式(横向拖拽放大时间轴,纵向拖拽放大该网格幅值)。 */
|
|
CURSOR, /**< 三态循环切换时间光标:无 → 单光标 → 双光标。 */
|
|
MERGE_LANES, /**< 合并为单一网格。 */
|
|
SPLIT_LANES, /**< 按信号拆分为多网格。 */
|
|
CLEAR_ALL /**< 清空当前标签页的全部网格与信号勾选。 */
|
|
};
|
|
|
|
/**
|
|
* @brief 顶部工具栏:文件操作与视图控制的入口。
|
|
*/
|
|
class Toolbar
|
|
{
|
|
public:
|
|
Toolbar();
|
|
|
|
/**
|
|
* @brief 绑定字体与主题资源。
|
|
* @param [IN] fonts 字体集合,需在工具栏生命周期内保持有效。
|
|
* @param [IN] theme 主题配色,需在工具栏生命周期内保持有效。
|
|
*/
|
|
void Setup(const UiFonts* fonts, const Theme* theme);
|
|
|
|
/**
|
|
* @brief 设置 DPI 缩放比例。
|
|
* @param [IN] scale 缩放比例(1.0 对应 96 DPI)。
|
|
*/
|
|
void SetScale(float scale);
|
|
|
|
/**
|
|
* @brief 设置是否已加载数据(未加载时大部分按钮被禁用)。
|
|
* @param [IN] hasDocument 是否已加载数据。
|
|
*/
|
|
void SetDocumentLoaded(bool hasDocument);
|
|
|
|
/**
|
|
* @brief 设置可切换按钮的选中状态。
|
|
* @param [IN] action 目标按钮动作。
|
|
* @param [IN] checked 是否处于选中(生效)状态。
|
|
*/
|
|
void SetToggleState(ToolbarAction action, bool checked);
|
|
|
|
/**
|
|
* @brief 计算工具栏在指定缩放下的期望高度。
|
|
* @return 期望高度(像素)。
|
|
*/
|
|
float DesiredHeight() const;
|
|
|
|
/**
|
|
* @brief 按给定区域重新排布按钮。
|
|
* @param [IN] area 工具栏可用区域。
|
|
*/
|
|
void Layout(const gd::RectF& area);
|
|
|
|
/**
|
|
* @brief 绘制工具栏。
|
|
* @param [IN,OUT] g 绘图上下文。
|
|
*/
|
|
void Paint(gd::Graphics& g);
|
|
|
|
/**
|
|
* @brief 处理鼠标移动,更新悬停状态。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 悬停状态发生变化返回 true。
|
|
*/
|
|
bool OnMouseMove(int x, int y);
|
|
|
|
/**
|
|
* @brief 处理鼠标左键按下。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @param [OUT] action 命中的按钮动作。
|
|
* @return 命中按钮返回 true。
|
|
*/
|
|
bool OnLButtonDown(int x, int y, ToolbarAction& action);
|
|
|
|
/**
|
|
* @brief 处理鼠标左键抬起。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @param [OUT] action 抬起时命中的按钮动作(仅在按钮上抬起时有效)。
|
|
* @return 视觉状态发生变化返回 true。
|
|
*/
|
|
bool OnLButtonUp(int x, int y, ToolbarAction& action);
|
|
|
|
/**
|
|
* @brief 处理鼠标离开工具栏。
|
|
* @return 视觉状态发生变化返回 true。
|
|
*/
|
|
bool OnMouseLeave();
|
|
|
|
/**
|
|
* @brief 判断坐标是否落在工具栏区域内。
|
|
* @param [IN] x 客户区横坐标。
|
|
* @param [IN] y 客户区纵坐标。
|
|
* @return 落在区域内返回 true。
|
|
*/
|
|
bool HitTest(int x, int y) const;
|
|
|
|
private:
|
|
/**
|
|
* @brief 单个工具栏按钮的运行时状态。
|
|
*/
|
|
struct Button
|
|
{
|
|
ToolbarAction action = ToolbarAction::NONE; /**< 按钮动作。 */
|
|
std::wstring label; /**< 按钮文本。 */
|
|
gd::RectF rect; /**< 按钮矩形。 */
|
|
float width = 0.0f; /**< 按钮宽度。 */
|
|
bool primary = false; /**< 是否为主按钮(强调色填充)。 */
|
|
bool needsDocument = true; /**< 是否依赖已加载数据。 */ bool toggle = false; /**< 是否为可切换按钮。 */
|
|
bool checked = false; /**< 可切换按钮的选中状态。 */ bool hover = false; /**< 悬停状态。 */
|
|
bool pressed = false; /**< 按下状态。 */
|
|
};
|
|
|
|
/**
|
|
* @brief 判断按钮当前是否可用。
|
|
* @param [IN] button 目标按钮。
|
|
* @return 可用返回 true。
|
|
*/
|
|
bool IsEnabled(const Button& button) const;
|
|
|
|
const UiFonts* m_fonts = nullptr; /**< 字体资源。 */
|
|
const Theme* m_theme = nullptr; /**< 主题资源。 */
|
|
float m_scale = 1.0f; /**< DPI 缩放比例。 */
|
|
bool m_documentLoaded = false; /**< 是否已加载数据。 */
|
|
std::vector<Button> m_buttons; /**< 按钮集合。 */
|
|
gd::RectF m_area; /**< 工具栏整体区域。 */
|
|
int m_hoverIndex = -1; /**< 当前悬停按钮下标。 */
|
|
int m_pressedIndex = -1; /**< 当前按下按钮下标。 */
|
|
};
|
|
|
|
} // namespace jdi
|
|
|
|
#endif // __TOOLBAR_HPP__
|