refactor(panels): 面板静态特征收敛为唯一登记表 + 标记面板绘制分段(§17.6 第 1/2 项)
- 新增 pvdetail::PanelKindTraits + PanelTraitsOf(唯一 switch):标题 / 排版类别 / 滚动字段 / 面板状态 / 功能开关同表登记;新增面板只改「枚举 + 一行」, -Wswitch 仍在唯一登记点生效。PanelTitle 改为「前缀 + rangeSuffix 标志」, 不再依赖 switch(标题降级为数据,不再需要函数指针)。 - PaintPanelMarkerGroups(约 340 行)拆成 6 个具名函数,主函数只保留绘制顺序 (普通分组栏 -> 条目 -> 表头 -> 吸顶栏 -> 滚动条 -> 透明度行);纯搬移、0 字节变化。 - 顺手修正该函数体遗留的多余缩进。 验证:release/debug/tools 零 warning;UnitTests 260/19;OffscreenChecks -all 7/133; panels -mode compare 7 面板像素哈希逐项不变;rowgeom compare 965+7 / 1268+7 键 0 差异。 产物 781,824 -> 782,336 B(+512,全部来自登记表)。
This commit is contained in:
1 parent
a9f1563896
commit
0c26da07d2
8 files changed
+761
-453
No files matched your search
@@ -1096,99 +1096,21 @@ namespace jdi
|
||||
// ⚠️ 这些 `switch` **不得写 `default:`** —— 让 `-Wswitch` 在新增
|
||||
// `EdgePanelKind` 而漏登记时直接报警(编译期保护,0 运行时代价)。
|
||||
|
||||
/** @brief 取某种面板的 UI 状态(展开/折起/位置)——可写版本。 */
|
||||
inline LanePanelState& LanePanelStateOf(Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case EdgePanelKind::COUNT:
|
||||
return lane.edgePanel;
|
||||
case EdgePanelKind::CENTER:
|
||||
return lane.edgeCenterPanel;
|
||||
case EdgePanelKind::MEAN:
|
||||
return lane.meanFilterPanel;
|
||||
case EdgePanelKind::PEAK:
|
||||
return lane.weakPeakPanel;
|
||||
case EdgePanelKind::MARK:
|
||||
return lane.freeMarkerPanel;
|
||||
case EdgePanelKind::RESAMPLE:
|
||||
return lane.resamplePanel;
|
||||
case EdgePanelKind::CLIP:
|
||||
return lane.clipPanel;
|
||||
}
|
||||
// 枚举值越界(只可能来自非法强制转换):返回一个安全的占位对象。
|
||||
return lane.edgePanel;
|
||||
}
|
||||
|
||||
/** @brief 取某种面板的 UI 状态——只读版本。 */
|
||||
inline const LanePanelState& LanePanelStateOf(const Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
return LanePanelStateOf(const_cast<Lane&>(lane), kind);
|
||||
}
|
||||
|
||||
/** @brief 取某种面板的**内容滚动偏移**(客户区像素)——可写版本。 */
|
||||
inline float& LanePanelScrollOf(Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case EdgePanelKind::COUNT:
|
||||
return lane.edgeCountScroll;
|
||||
case EdgePanelKind::CENTER:
|
||||
return lane.edgeCenterScroll;
|
||||
case EdgePanelKind::MEAN:
|
||||
return lane.meanFilterScroll;
|
||||
case EdgePanelKind::PEAK:
|
||||
return lane.weakPeakScroll;
|
||||
case EdgePanelKind::MARK:
|
||||
return lane.freeMarkerScroll;
|
||||
case EdgePanelKind::RESAMPLE:
|
||||
return lane.resampleScroll;
|
||||
case EdgePanelKind::CLIP:
|
||||
return lane.clipScroll;
|
||||
}
|
||||
return lane.meanFilterScroll;
|
||||
}
|
||||
|
||||
/** @brief 取某种面板的**内容滚动偏移**——只读版本。 */
|
||||
inline const float& LanePanelScrollOf(const Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
return LanePanelScrollOf(const_cast<Lane&>(lane), kind);
|
||||
}
|
||||
|
||||
/** @brief 该面板对应的功能是否已启用(右键菜单里的开关)。 */
|
||||
inline bool LanePanelEnabled(const Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case EdgePanelKind::COUNT:
|
||||
return lane.edgeCount;
|
||||
case EdgePanelKind::CENTER:
|
||||
return lane.edgeCenter;
|
||||
case EdgePanelKind::MEAN:
|
||||
return lane.meanFilter;
|
||||
case EdgePanelKind::PEAK:
|
||||
return lane.weakPeak;
|
||||
case EdgePanelKind::MARK:
|
||||
return lane.freeMarker;
|
||||
case EdgePanelKind::RESAMPLE:
|
||||
return lane.resample;
|
||||
case EdgePanelKind::CLIP:
|
||||
return lane.clip;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---- 面板的「排版类别」与「滚动几何」的唯一来源 --------------------------------
|
||||
// ---- 面板的「排版类别」与「静态特征」的唯一来源 --------------------------------
|
||||
//
|
||||
// ⚠️⚠️ 为什么要有这一层:面板的**分类布尔量**过去在三个地方各写一份
|
||||
// (`EdgePanelWidth` / `EdgePanelLayoutFor` / `PaintEdgeCursor`),
|
||||
// 每份都是 6 个 `kind == XXX` + 3 条组合判断。新增一种面板时若只改其中两处,
|
||||
// 就会出现"宽度按 A 类算、绘制按 B 类画"的错位 —— 这正是历史上
|
||||
// 「元素超出浮动面板」「内容区多出一段空白」「滚动条画在表头上」这类缺陷的共同形态。
|
||||
// 现在只在这里分派一次,三个消费者都读同一份结果。
|
||||
// 现在只在这里登记一次,所有消费者都读同一份结果。
|
||||
//
|
||||
// ⚠️ 同样**不写 `default:`**:新增 `EdgePanelKind` 而未登记时,
|
||||
// ⚠️ `PanelTraitsOf` 的 `switch` **不写 `default:`**:新增 `EdgePanelKind` 而未登记时,
|
||||
// `-Wswitch`(属 `-Wall`)会直接编译报警。
|
||||
//
|
||||
// ⚠️ 标题里只有「边沿计数」「中心轴边沿计数」需要追加运行时后缀(`EdgeRangeSuffix()`
|
||||
// 取决于双光标是否启用),因此表里存的是**标题前缀 + 一个标志**,
|
||||
// 而不是 `std::wstring`(无法 constexpr)或函数指针(会把"数据"重新变成"代码")。
|
||||
|
||||
/**
|
||||
* @brief 一种浮动面板的排版类别(互斥 + 若干可选部件)。
|
||||
@@ -1225,40 +1147,108 @@ namespace jdi
|
||||
bool footerButtons() const { return buildButton || twoButtons; }
|
||||
};
|
||||
|
||||
/** @brief 取某种面板的排版类别(唯一分类来源)。 */
|
||||
inline PanelStyle PanelStyleOf(EdgePanelKind kind)
|
||||
/** @brief `PanelStyle` 的三个具名构造函数(聚合初始化顺序易错,这里给出语义化入口)。 */
|
||||
inline constexpr PanelStyle ListPanelStyle(bool buildButton, bool twoButtons) noexcept
|
||||
{
|
||||
return PanelStyle{true, false, false, buildButton, twoButtons, false};
|
||||
}
|
||||
|
||||
inline constexpr PanelStyle CountTablePanelStyle() noexcept
|
||||
{
|
||||
return PanelStyle{false, true, false, false, false, false};
|
||||
}
|
||||
|
||||
inline constexpr PanelStyle MarkerPanelStyle() noexcept
|
||||
{
|
||||
return PanelStyle{false, false, true, false, false, true};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 一种浮动面板的全部**静态特征**(排版类别 / 标题 / 三个字段偏移)。
|
||||
*
|
||||
* 新增一种面板时**只允许**改三处:`EdgePanelKind` 加一个枚举值、
|
||||
* 本表加一行、`PanelTitle` 不需要动(标题就在这一行里)。
|
||||
* 其余消费者(宽度 / 布局 / 绘制 / 滚动 / 命中 / 调试盒 / 缓存键)全部自动跟上。
|
||||
*/
|
||||
struct PanelKindTraits
|
||||
{
|
||||
PanelStyle style; /**< 排版类别与底部控件。 */
|
||||
const wchar_t* title = L""; /**< 标题前缀(`rangeSuffix` 为真时再追加区间后缀)。 */
|
||||
bool rangeSuffix = false; /**< 标题是否追加 `EdgeRangeSuffix()`(仅两种边沿计数)。 */
|
||||
float Lane::*scroll = nullptr; /**< 内容滚动偏移。 */
|
||||
LanePanelState Lane::*panel = nullptr; /**< 面板 UI 状态(展开/折起/位置)。 */
|
||||
bool Lane::*enabled = nullptr; /**< 功能开关(右键菜单里的勾选项)。 */
|
||||
};
|
||||
|
||||
/** @brief 取某种面板的全部静态特征(**唯一登记点**)。 */
|
||||
inline constexpr PanelKindTraits PanelTraitsOf(EdgePanelKind kind)
|
||||
{
|
||||
PanelStyle style;
|
||||
switch (kind)
|
||||
{
|
||||
case EdgePanelKind::COUNT:
|
||||
style.countTable = true;
|
||||
break;
|
||||
return PanelKindTraits{CountTablePanelStyle(), L"边沿计数", true,
|
||||
&Lane::edgeCountScroll, &Lane::edgePanel, &Lane::edgeCount};
|
||||
case EdgePanelKind::CENTER:
|
||||
style.listRows = true;
|
||||
break;
|
||||
return PanelKindTraits{ListPanelStyle(false, false), L"中心轴边沿计数", true,
|
||||
&Lane::edgeCenterScroll, &Lane::edgeCenterPanel,
|
||||
&Lane::edgeCenter};
|
||||
case EdgePanelKind::MEAN:
|
||||
style.listRows = true;
|
||||
style.buildButton = true;
|
||||
break;
|
||||
return PanelKindTraits{ListPanelStyle(true, false), L"均值滤波", false,
|
||||
&Lane::meanFilterScroll, &Lane::meanFilterPanel,
|
||||
&Lane::meanFilter};
|
||||
case EdgePanelKind::PEAK:
|
||||
style.listRows = true;
|
||||
style.buildButton = true;
|
||||
break;
|
||||
return PanelKindTraits{ListPanelStyle(true, false), kWeakPeakTitle, false,
|
||||
&Lane::weakPeakScroll, &Lane::weakPeakPanel, &Lane::weakPeak};
|
||||
case EdgePanelKind::MARK:
|
||||
style.markerGroups = true;
|
||||
style.markerFooter = true;
|
||||
break;
|
||||
return PanelKindTraits{MarkerPanelStyle(), L"自由标记", false,
|
||||
&Lane::freeMarkerScroll, &Lane::freeMarkerPanel,
|
||||
&Lane::freeMarker};
|
||||
case EdgePanelKind::RESAMPLE:
|
||||
style.listRows = true;
|
||||
style.buildButton = true;
|
||||
break;
|
||||
return PanelKindTraits{ListPanelStyle(true, false), kResampleTitle, false,
|
||||
&Lane::resampleScroll, &Lane::resamplePanel, &Lane::resample};
|
||||
case EdgePanelKind::CLIP:
|
||||
style.listRows = true;
|
||||
style.twoButtons = true;
|
||||
break;
|
||||
return PanelKindTraits{ListPanelStyle(false, true), kClipTitle, false,
|
||||
&Lane::clipScroll, &Lane::clipPanel, &Lane::clip};
|
||||
}
|
||||
return style;
|
||||
// 枚举值越界(只可能来自非法强制转换):退到「均值滤波」这份,保证指针非空。
|
||||
return PanelKindTraits{ListPanelStyle(true, false), L"", false, &Lane::meanFilterScroll,
|
||||
&Lane::meanFilterPanel, &Lane::meanFilter};
|
||||
}
|
||||
|
||||
/** @brief 取某种面板的排版类别(唯一分类来源)。 */
|
||||
inline PanelStyle PanelStyleOf(EdgePanelKind kind)
|
||||
{
|
||||
return PanelTraitsOf(kind).style;
|
||||
}
|
||||
|
||||
/** @brief 取某种面板的 UI 状态(展开/折起/位置)——可写版本。 */
|
||||
inline LanePanelState& LanePanelStateOf(Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
return lane.*(PanelTraitsOf(kind).panel);
|
||||
}
|
||||
|
||||
/** @brief 取某种面板的 UI 状态——只读版本。 */
|
||||
inline const LanePanelState& LanePanelStateOf(const Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
return LanePanelStateOf(const_cast<Lane&>(lane), kind);
|
||||
}
|
||||
|
||||
/** @brief 取某种面板的**内容滚动偏移**(客户区像素)——可写版本。 */
|
||||
inline float& LanePanelScrollOf(Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
return lane.*(PanelTraitsOf(kind).scroll);
|
||||
}
|
||||
|
||||
/** @brief 取某种面板的**内容滚动偏移**——只读版本。 */
|
||||
inline const float& LanePanelScrollOf(const Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
return LanePanelScrollOf(const_cast<Lane&>(lane), kind);
|
||||
}
|
||||
|
||||
/** @brief 该面板对应的功能是否已启用(右键菜单里的开关)。 */
|
||||
inline bool LanePanelEnabled(const Lane& lane, EdgePanelKind kind)
|
||||
{
|
||||
return lane.*(PanelTraitsOf(kind).enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user