修复合并网格后的新增信号、适应视图联动、调色面板排版与左右越界三角
1. 合并网格后新增信号不再挤进合并网格
- 分组复选框与「全部显示」按钮此前只更新可见性,没有像单信号勾选那样把划分策略
切到自定义,于是合并网格把新增信号一并吞掉。
- 现在两者在确有信号由不可见变可见时同样切换到自定义划分,
新增信号各自独占一个网格并追加在列表最下方,原合并网格保持不变。
2. 适应视图不再取消「选区放大」模式与「选区 Y 轴自适应」
- 此前适应视图会把缩放模式复位为无,并把全部网格的 autoRange 置真;
而自动适应区间只由 autoRange 决定,置真等于把已经算好的时间段幅值丢掉,
表现为"点一下适应视图,Y 轴自适应就失效了"。
- 现在保留缩放模式;开启了「选区 Y 轴自适应」的网格改为按新的时间视图重新匹配,
其余网格才恢复整段自适应。
3. 「按网格时间轴展开」联动其它网格
- 时间视图是全局的,展开后其余开启了「选区 Y 轴自适应」的网格同样重新匹配 Y 轴,
不再只有被展开的那一个网格量程合适。
4. 自定义颜色面板排版重做
- R/G/B 的标签、滑块与数值改为同属右侧一列并共用同一行,标签紧贴各自的滑块;
预览色块与色号移到左列下方并与色域方块同宽,色号编辑框不再超出面板边界;
面板高度按内容重新计算,底部不再留空。
- 色域方块上的选点去掉外圈深色描边,改为"中心为所选颜色 + 白色描边"。
- 色相指示器由黑色横条改为白色描边的圆角长方条,底色取该位置的颜色;
色相条本身改用分段线性渐变绘制。
5. 修复光标数据点向左/向右越界时的三角
- 三角沿朝向伸出的深度大于贴边时距边界的距离,导致有一大半画在网格绘制区之外,
裁剪后只剩残缺一角、描边也因此不完整。
- 现在左右越界时把锚点向内推一个三角深度,三角完整落在绘制区内;
同时四方向越界都让三角与显示的数值纵向居中对齐。
This commit is contained in:
1 parent
40b12d6e8b
commit
2d029fb09b
3 files changed
+152
-68
No files matched your search
@@ -31,6 +31,9 @@ namespace jdi
|
||||
const float kCursorHandleReserve = 9.0f; /**< 光标顶部三角把手占用的高度(数据点贴边时需避让)。 */
|
||||
const float kMarkerEdgeInset = 7.0f; /**< 数据点越界贴边时距网格可见边界的间距。 */
|
||||
const float kMarkerInsideMargin = 2.0f; /**< 数据点在视界内时允许贴到边界的最小余量。 */
|
||||
const float kMarkerTriangleArm = 5.0f; /**< 越界方向三角"半宽/半高"(垂直于朝向的半边长)。 */
|
||||
/** 越界方向三角沿朝向的深度(与光标把手同比例)。 */
|
||||
const float kMarkerTriangleDepth = kMarkerTriangleArm * 1.4f;
|
||||
const size_t kMaxScatterPoints = 2500; /**< 单条散点最大绘制点数。 */
|
||||
const size_t kPolylineCacheLimit = 64; /**< 折线顶点缓存条目上限。 */
|
||||
const float kMinScatterRadius = 1.6f; /**< 散点最小半径(逻辑像素)。 */
|
||||
@@ -883,21 +886,35 @@ namespace jdi
|
||||
Tab().ViewMax() = high;
|
||||
Tab().ViewInitialized() = true;
|
||||
Tab().LaneScroll() = 0.0f;
|
||||
// 自适应即回到初始状态:退出拖拽缩放模式并放下进行中的选区与拖拽。
|
||||
Tab().ZoomMode() = PlotZoomMode::NONE;
|
||||
// 只放下进行中的选区与拖拽,**不改变「选区放大」等缩放模式的启用状态**
|
||||
// (用户明确要求:点适应视图后仍保持已启用的缩放模式)。
|
||||
m_rubberRect = gd::RectF();
|
||||
m_dragMode = PlotDragMode::NONE;
|
||||
m_dragSignal = SignalRef();
|
||||
m_dragTargetLane = -1;
|
||||
m_hoverSignal = SignalRef();
|
||||
SetHint(Tab().ZoomMode() == PlotZoomMode::NONE
|
||||
? std::wstring()
|
||||
: L"横向或纵向拖动以放大选择区域,ESC退出选区模式");
|
||||
|
||||
if (m_tab != nullptr)
|
||||
{
|
||||
// 适应视图 = 回到初始状态:全部网格恢复整段数据的自动自适应。
|
||||
// 「选区 Y 轴自适应」是用户设置项,这里保持不变。
|
||||
for (Lane& lane : m_tab->Lanes())
|
||||
// 适应视图 = 回到初始状态:恢复整段数据的自动自适应。
|
||||
// 但**开启了「选区 Y 轴自适应」的网格必须继续跟随时间视图**:
|
||||
// 直接置 autoRange 会让 ComputeLaneRange 忽略已经算好的时间段幅值,
|
||||
// 表现为"点一下适应视图就把 Y 轴自适应关掉了"。这里改为按新的
|
||||
// (整段)时间视图重新匹配一次,开关状态与视觉效果都保持。
|
||||
const int laneCount = static_cast<int>(m_tab->Lanes().size());
|
||||
for (int index = 0; index < laneCount; ++index)
|
||||
{
|
||||
lane.autoRange = true;
|
||||
if (m_tab->Lanes()[static_cast<std::size_t>(index)].fitYToSelection)
|
||||
{
|
||||
AutoRangeLaneToView(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tab->Lanes()[static_cast<std::size_t>(index)].autoRange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 适应视图已回到初始状态,这里不再移动光标(光标允许停留在可视区外)。
|
||||
@@ -1152,6 +1169,10 @@ namespace jdi
|
||||
// 否则展开后会看到“时间对了但幅值区间不合适”的波形。
|
||||
AutoRangeLaneToView(laneIndex);
|
||||
|
||||
// 其它开启了「选区 Y 轴自适应」的网格同样要跟新的时间视图重新匹配:
|
||||
// 时间视图变了,只让被展开的那个网格合适、其余网格停留在旧幅值区间并不符合预期。
|
||||
ApplySelectionAutoFit();
|
||||
|
||||
// 注意:不在这里移动光标——光标允许滞留在网格可视区域之外。
|
||||
BuildLaneVisuals();
|
||||
return true;
|
||||
@@ -5787,9 +5808,10 @@ namespace jdi
|
||||
// 依次向下(再向上)避让已占用的标注,保证不会互相覆盖。
|
||||
PlaceCursorLabel(labelRect, labelTop, textHeight, clipTop, clipBottom);
|
||||
|
||||
// 上下越界的方向三角与最终落位的取值标注纵向居中对齐
|
||||
// (用户明确要求“超过上下视界时三角需要与显示的数值居中对齐”)。
|
||||
if (marker.offUp || marker.offDown)
|
||||
// 越界方向三角与最终落位的取值标注纵向居中对齐
|
||||
// (用户明确要求“超过上下视界时三角需要与显示的数值居中对齐”;
|
||||
// 左右越界时同样对齐,避免三角与数值错行、看起来不协调)。
|
||||
if (marker.offUp || marker.offDown || marker.offLeft || marker.offRight)
|
||||
{
|
||||
marker.y = labelRect.Y + labelRect.Height * 0.5f;
|
||||
}
|
||||
@@ -5865,8 +5887,9 @@ namespace jdi
|
||||
std::min(centerTop, clipBottom - textHeight - 1.0f * m_scale));
|
||||
gd::RectF centerRect(centerLeft, centerTop, centerTextWidth, textHeight);
|
||||
PlaceCursorLabel(centerRect, centerTop, textHeight, clipTop, clipBottom);
|
||||
// 与原始信号同一规则:上下越界的方向三角与取值标注纵向居中对齐。
|
||||
if (centerMarker.offUp || centerMarker.offDown)
|
||||
// 与原始信号同一规则:越界方向三角与取值标注纵向居中对齐。
|
||||
if (centerMarker.offUp || centerMarker.offDown || centerMarker.offLeft ||
|
||||
centerMarker.offRight)
|
||||
{
|
||||
centerMarker.y = centerRect.Y + centerRect.Height * 0.5f;
|
||||
}
|
||||
@@ -6084,6 +6107,20 @@ namespace jdi
|
||||
marker.offDown = (rawY > clipBottom);
|
||||
|
||||
marker.x = pinX;
|
||||
// 左右越界时三角沿水平方向**向外**伸出 `kMarkerTriangleDepth`:
|
||||
// 光标贴边时 pinX 只离边界 1px,若直接把锚点放在那里,三角会有一大半画到
|
||||
// 网格绘制区之外(被裁剪后只看到残缺的一角,描边也随之断开)。
|
||||
// 因此把锚点沿水平方向**向内**推 keepIn,保证三角完整落在绘制区内。
|
||||
const float keepIn = (kMarkerTriangleDepth + 1.0f) * m_scale;
|
||||
if (marker.offLeft)
|
||||
{
|
||||
marker.x = std::max(pinX, left + keepIn);
|
||||
}
|
||||
else if (marker.offRight)
|
||||
{
|
||||
marker.x = std::min(pinX, right - keepIn);
|
||||
}
|
||||
|
||||
if (marker.offUp)
|
||||
{
|
||||
// 上越界:为方向三角与顶部把手预留高度,避免压住把手。
|
||||
@@ -6108,8 +6145,8 @@ namespace jdi
|
||||
{
|
||||
gd::SolidBrush ring(ToGdiColor(ringColor));
|
||||
gd::SolidBrush fill(ToGdiColor(fillColor));
|
||||
const float arm = 5.0f * m_scale; /**< 三角“半宽/半高”(垂直于朝向的半边长)。 */
|
||||
const float depth = arm * 1.4f; /**< 三角沿朝向的深度(与光标把手同比例)。 */
|
||||
const float arm = kMarkerTriangleArm * m_scale; /**< 三角“半宽/半高”(垂直于朝向的半边长)。 */
|
||||
const float depth = kMarkerTriangleDepth * m_scale; /**< 三角沿朝向的深度(与光标把手同比例)。 */
|
||||
|
||||
// 越界三角:**尖端朝外**(指向数据点所在的方向,即视界之外),底边在网格内侧;
|
||||
// 三角外接矩形在横/纵两个方向都与锚点**居中**(上下越界时因此与取值标注纵向居中)。
|
||||
|
||||
Reference in new issue
Block a user