标题栏内存占用 / 样式区增益与取绝对值·中心反转 / 拾色器排版 / 图例去托底与命中优先级

标题栏:
- 应用名称后追加「  |  RAM : <值>」:竖线两侧各留两个空格(与分组标题「组X | 组名」的间距风格一致)。
- 数值按 KB/MB/GB 自适应、保留两位小数(复用 FormatByteSize);用 K32GetProcessMemoryInfo 取本进程
  工作集(与任务管理器「内存」一致,无需新增链接依赖);1 秒定时器刷新,数值未变时不调用 SetWindowTextW。

信号样式自定义栏:
- 线宽与透明度交换上下位置(线宽在上、透明度在下)。
- 新增「系数增益」:输入框(默认 1,只接受数值,范围 ±10000),点击进入编辑、回车/点击别处提交。
- 新增「取绝对值」「中心反转」两个同行的切换按钮。
- 三者作用顺序固定为「系数增益 → 取绝对值 → 中心反转」(中心反转最后结算),实现为
  ApplyDrawTransform(style, value),在 BuildPolyline(逐点描边与像素列包络两条路径,含粗粒度分组层)、
  派生预览曲线与光标取值读数统一调用;样式属于信号本身(跨视图共享)并进入 SceneContentHash /
  SceneStyleEntry / 折线缓存键,改动会立即重绘。
- 非保序变换(取绝对值 / 反转 / 负增益)会回退到逐采样点变换、不再使用粗粒度包络层,保证包络精确。

自定义颜色面板:
- 把底部的「色号 + 预览色块」移到 RGB 滑块上方;右侧一列(预览行 + 三行滑块)与左侧「色域方块 +
  色相条」高度严格相等,两列上下边对齐,面板不再为它单独保留一行。

网格内:
- 去掉图例与 GX 编号下方的整块不透明托底(它会把网格线整片擦掉,看起来像一个"可点击控件",
  而其右侧空白实际并不响应点击)。
- 图例与 GX 徽标改为优先命中:先于时间光标线 / 光标读数 / 边沿计数横向光标 / 选区放大判定,
  因此选区放大模式下也能正常拖拽 GX 标签与点选图例(浮动面板仍然优先,与绘制层序一致)。

验证:离屏 harness(.preflight/uitest,SW_HIDE、不动鼠标键盘屏幕)新增
[AK] 标题栏内存读数(格式与竖线间隙、单位阈值、两位小数、随 256MB 分配增长、定时器刷新);
[AL] 样式区行序与几何、增益输入提交、两个切换按钮的真实点击、ApplyDrawTransform 顺序,以及
BuildPolyline 顶点范围与变换后数据范围逐项对齐(默认 / 增益 2 / 取绝对值 / 中心反转 /
负增益+取绝对值+中心反转叠加);
[AM] 拾色器两列严格等高(140.00 == 140.00);
[AN] 选区放大模式下 GX 拖拽重排 + 图例点选 + 网格线穿过图例带(托底已移除)。
另修正旧用例 [AI](远端已删除"光标跟随视界",改为断言光标时间位置不变、允许滑出视窗)。
合计 530/530 通过;make clean && make all 零警告。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-13 12:06:38 +08:00
1 parent 20b90848fe
commit c3343907ec
8 files changed
+420 -105

No files matched your search

+53 -1
View File
@@ -90,7 +90,7 @@ namespace jdi
};
/**
* @brief 单个信号的显示外观(颜色/透明度/线宽/绘制方式)。
* @brief 单个信号的显示外观(颜色/透明度/线宽/绘制方式/数值变换)。
*
* 外观属于信号自身而非某个标签页——同一信号在所有标签页中必须显示效果一致,
* 因此在任一视图里修改颜色/线宽/透明度/样式,其它视图会自动同步。
@@ -103,8 +103,60 @@ namespace jdi
float opacity = 1.0f; /**< 不透明度,取值 0.0-1.0,默认 1.0。 */
float lineWidth = 1.0f; /**< 线宽(逻辑像素,未乘 DPI 缩放)。 */
DrawMode mode = DrawMode::LINE; /**< 绘制方式。 */
/**
* 绘制前的数值变换(三者**依次**作用,见 `ApplyDrawTransform`):
* 1. `gain` 系数增益:采样值乘以该系数(默认 1,即不改变);
* 2. `absolute` 取绝对值:|value|;
* 3. `inverted` 中心反转:按 Y = 0 上下反向(value → −value)。
*/
float gain = 1.0f; /**< 系数增益,默认 1.0。 */
bool absolute = false; /**< 是否对绘制值取绝对值,默认关闭。 */
bool inverted = false; /**< 是否按 Y=0 中心反转绘制值,默认关闭。 */
};
/**
* @brief 把原始采样值变换为**绘制用值**。
*
* 顺序固定为「系数增益 → 取绝对值 → 中心反转」(用户明确要求中心反转最后结算),
* 例如增益 2、原始值 1.5 → 2×1.5 = 3;再取绝对值仍为 3;再中心反转为 −3。
* NaN 经乘/取绝对值/取反后仍为 NaN(保持断线语义)。
*
* @param [IN] style 信号外观(提供增益与两个开关)。
* @param [IN] value 原始采样值。
* @return 绘制用值。
*/
inline double ApplyDrawTransform(const SignalStyle& style, double value)
{
if (style.gain != 1.0f)
{
value *= static_cast<double>(style.gain);
}
if (style.absolute)
{
value = (value < 0.0) ? -value : value;
}
if (style.inverted)
{
value = -value;
}
return value;
}
/**
* @brief 判断数值变换是否**保持大小顺序**(正增益、且不取绝对值、不反转)。
*
* 只有保序时,粗粒度包络层(每组的 min/max)才能直接按增益缩放后继续使用;
* 取绝对值 / 反转会把最小值与最大值互换,此时必须回退到逐采样点变换。
*
* @param [IN] style 信号外观。
* @return 变换单调递增返回 true。
*/
inline bool DrawTransformOrderPreserving(const SignalStyle& style)
{
return (style.gain > 0.0f) && !style.absolute && !style.inverted;
}
/**
* @brief 单条信号的元数据与采样值(纯数据,不含可见性配置)。
*/
+22 -23
View File
@@ -18,8 +18,7 @@ namespace jdi
const float kTitleGap = 8.0f; /**< 标题与内容区间距。 */
const float kRowHeight = 26.0f; /**< 单个滑块行高度。 */
const float kRowGap = 2.0f; /**< 滑块行间距。 */
const float kPreviewGap = 10.0f; /**< 滑块区与预览区间距。 */
const float kPreviewHeight = 24.0f; /**< 预览行高度。 */
const float kPreviewHeight = 24.0f; /**< 预览行(预览色块 + 色号)高度。 */
const float kLabelWidth = 16.0f; /**< 通道标签宽度。 */
const float kLabelGap = 6.0f; /**< 标签与滑块间距。 */
const float kValueWidth = 40.0f; /**< 数值文本宽度。 */
@@ -220,13 +219,14 @@ namespace jdi
void ColorPickerPopup::BuildLayout(const gd::RectF& bounds, const gd::RectF& anchor)
{
// 布局:左侧一列放"色域方块 + 色相条",右侧一列放 R/G/B 三行
//(每行 = 通道标签 + 滑块 + 数值),两列下方再放"预览色块 + 色号"一行。
// 布局:左侧一列放"色域方块 + 色相条",右侧一列**上方**放"预览色块 + 色号"、
// **下方**放 R/G/B 三行(每行 = 通道标签 + 滑块 + 数值)。
// 右列总高 = 预览行 + 间隙 + 三行滑块,与左侧"色域方块"高度**严格相等**,
// 因此两列上下边对齐、整体版面协调(不再有单起一行的底部预览条)。
// 所有控件都从面板内边距起算,因此不会出现越界。
const float width = kPanelWidth * m_scale;
const float height = (kPadV * 2.0f + kTitleHeight + kTitleGap + kGamutSize + kPreviewGap +
kPreviewHeight) *
m_scale;
const float height =
(kPadV * 2.0f + kTitleHeight + kTitleGap + kGamutSize) * m_scale;
const float gap = 4.0f * m_scale;
@@ -260,22 +260,30 @@ namespace jdi
m_hueRect = gd::RectF(m_gamutRect.X + m_gamutRect.Width + kGamutGap * m_scale, contentTop,
kHueWidth * m_scale, kGamutSize * m_scale);
// 右列:R/G/B 三行。整列在方块高度内纵向居中,与左侧方块视觉平衡。
const float leftColumnWidth =
(kGamutSize + kGamutGap + kHueWidth) * m_scale;
// 右列:预览行在滑块之上,整列高度与左侧方块一致。
const float leftColumnWidth = (kGamutSize + kGamutGap + kHueWidth) * m_scale;
const float columnLeft = m_gamutRect.X + leftColumnWidth + kColumnGap * m_scale;
const float columnWidth = std::max(60.0f * m_scale, contentRight - columnLeft);
const float rowsHeight = (kRowHeight * 3.0f + kRowGap * 2.0f) * m_scale;
const float firstRowTop =
contentTop + std::max(0.0f, (kGamutSize * m_scale - rowsHeight) * 0.5f);
// 预览行与滑块之间的间隙:正好补齐"方块高度 − 预览行高 − 三行滑块高",
// 使右列总高与左侧色域方块严格相等(常量变化时自动适配)。
const float previewRowGap =
std::max(0.0f, kGamutSize - kPreviewHeight - (kRowHeight * 3.0f + kRowGap * 2.0f)) * m_scale;
m_previewRect = gd::RectF(columnLeft, contentTop, kSwatchWidth * m_scale, kPreviewHeight * m_scale);
m_hexRect = gd::RectF(m_previewRect.X + m_previewRect.Width + kSwatchHexGap * m_scale, contentTop,
std::max(40.0f * m_scale,
columnWidth - (kSwatchWidth + kSwatchHexGap) * m_scale),
kPreviewHeight * m_scale);
const float sliderTop = m_previewRect.Y + m_previewRect.Height + previewRowGap;
const float trackLeft = columnLeft + (kLabelWidth + kLabelGap) * m_scale;
const float trackWidth =
std::max(24.0f, columnWidth - (kLabelWidth + kLabelGap + kValueWidth + 6.0f) * m_scale);
for (int index = 0; index < 3; ++index)
{
const float rowTop = firstRowTop + static_cast<float>(index) * (kRowHeight + kRowGap) * m_scale;
const float rowTop = sliderTop + static_cast<float>(index) * (kRowHeight + kRowGap) * m_scale;
m_tracks[static_cast<std::size_t>(index)] =
gd::RectF(trackLeft, rowTop + (kRowHeight * m_scale - kTrackHeight * m_scale) * 0.5f,
trackWidth, kTrackHeight * m_scale);
@@ -283,15 +291,6 @@ namespace jdi
gd::RectF(trackLeft + trackWidth + 6.0f * m_scale, rowTop, kValueWidth * m_scale,
kRowHeight * m_scale);
}
// 下行:预览色块 + 色号,与上方的"方块 + 色相条"同宽。
const float previewTop = contentTop + (kGamutSize + kPreviewGap) * m_scale;
m_previewRect =
gd::RectF(contentLeft, previewTop, kSwatchWidth * m_scale, kPreviewHeight * m_scale);
m_hexRect = gd::RectF(m_previewRect.X + m_previewRect.Width + kSwatchHexGap * m_scale,
previewTop,
std::max(40.0f * m_scale, leftColumnWidth - (kSwatchWidth + kSwatchHexGap) * m_scale),
kPreviewHeight * m_scale);
}
void ColorPickerPopup::Open(const gd::RectF& bounds, const gd::RectF& anchor, std::uint32_t color)