feat(ui): 修复预设色块误跳自定义色、选区 Y 轴自适应改为切换开关、菜单项改名移位

1) 修复样式区"点预设色块直接跳到自定义色块"
- 根因:加载时 customColor 被赋成信号自身的预设色,而样式区按
  "color == customColor 即视为在用自定义色" 判定高亮,于是点自身的预设色时
  高亮立刻跳到自定义色块上(第 N 个信号点第 N 个预设色必然复现)
- customColor 初值改为调色板中"本信号预设色向后递进一格"的颜色
  (palette[(slot + 1) % count]),自定义色块因此显示与预设色块排布连续的下一色
- 同时收紧高亮判定:仅当当前颜色"不属于任何可见预设色"时才认为在用自定义色。
  这样即使自定义色恰好等于某个预设色,点击该预设色也始终高亮预设色块,
  彻底消除"高亮乱跳";用拾色器选出的非预设色仍正常高亮自定义色块

2)「选区 Y 轴自适应」改为切换开关(原为一次性操作)
- Lane 用单一布尔量 fitYToSelection 表示(删除 viewAutoRange/viewAutoMin/viewAutoMax)
- 开启后每次时间轴选区放大(ApplyTimeSelection → ApplySelectionAutoFit)
  都会把该网格 Y 轴匹配到新的可见时间区间
- 任何手动幅值调整(Y 轴选区放大、纵向平移、缩放、直接输入上下限)都会关闭对应网格的开关
- RebuildLanes 按信号继承该开关:勾选/取消勾选信号不再把用户刚打开的开关悄悄清掉

3) 菜单「恢复 Y 轴自适应」移除,原位置新增「选区 Y 轴自适应(全局)」
- 全局项为切换状态:选中即把全部网格的开关置为开,取消即全部置为关;
  任意网格单独关掉后,全局项立即变为未勾选(= AllLanesAutoFitToSelection)
- 工具栏在「适应视图」之后新增「Y 轴自适应」切换按钮,与全局项是同一个开关,
  每帧同步选中态
- 删除了 PLOT_CMD_LANE_AUTO / PlotView::LaneRangeIsAuto / ResetLaneRange 等已无用的接口

4)「时间轴自适应(匹配本网格)」改名为「按网格时间轴展开」并移到分隔线上方
- 新顺序:网格 N / Y 轴最大值 / Y 轴最小值 / 选区 Y 轴自适应 / 按网格时间轴展开 /
  --- / 选区 Y 轴自适应(全局)/ 全部自适应

验证(TestData/[1].CSV 11 信号,窗口 1725x996,125% DPI):
- 颜色:初始高亮在预设色块 1;点预设 1 与预设 2(等于自定义色初值)均保持点中的色块高亮;
  用拾色器改成非预设色后高亮正确落在自定义色块
- 逐网格:菜单项勾选/取消即时反映;开启的网格做时间轴选区放大后 Y 轴自动匹配
  (仅该网格变化,其它网格保持整段范围)
- 全局:工具栏按钮与菜单全局项互相联动;单独取消一个网格后两者都变为未勾选;
  隐藏/显示信号后开关保持
- 「按网格时间轴展开」能把缩放后的时间轴展开回该网格信号范围;「全部自适应」仍正常
- 超大文件回归(VERY_BIG_DATA 1.77GB)菜单/悬停正常;空闲 CPU 0.00%

构建: make clean; make all 无警告无错误
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-07 13:57:46 +08:00
1 parent dd48cdd2e1
commit 0fffb3ed09
8 files changed
+219 -92

No files matched your search

+39 -27
View File
@@ -677,6 +677,7 @@ namespace jdi
m_toolbar.SetDocumentLoaded(!m_dataSet.Empty());
// 工具栏可切换按钮的选中状态始终与当前标签页配置保持一致。
m_toolbar.SetToggleState(ToolbarAction::AUTO_FIT_Y, m_plot.AllLanesAutoFitToSelection());
m_toolbar.SetToggleState(ToolbarAction::ZOOM_TIME,
m_plot.CurrentZoomMode() == PlotZoomMode::TIME);
m_toolbar.SetToggleState(ToolbarAction::ZOOM_VALUE,
@@ -1024,6 +1025,17 @@ namespace jdi
m_plot.FitAll();
SetStatusMessage(L"已恢复自适应视图。", false);
break;
case ToolbarAction::AUTO_FIT_Y:
{
// 与网格右键菜单中的「选区 Y 轴自适应(全局)」同一开关:
// 打开后每次时间轴选区放大都会自动把各网格 Y 轴匹配到新的可见区间。
const bool enable = !m_plot.AllLanesAutoFitToSelection();
m_plot.SetAllLanesAutoFitToSelection(enable);
SetStatusMessage(enable ? L"已开启选区 Y 轴自适应:时间轴选区放大后自动匹配各网格 Y 轴。"
: L"已关闭选区 Y 轴自适应。",
false);
break;
}
case ToolbarAction::ZOOM_TIME:
if (m_plot.ToggleZoomMode(PlotZoomMode::TIME))
{
@@ -1377,8 +1389,6 @@ namespace jdi
header.label = L"网格 " + std::to_wstring(laneIndex + 1);
items.push_back(header);
const bool isAuto = m_plot.LaneRangeIsAuto(laneIndex);
// 当前网格的 Y 轴上下限值直接在菜单内的输入框里显示,单击即可就地编辑(菜单不关闭)。
double laneYMin = 0.0;
double laneYMax = 1.0;
@@ -1400,29 +1410,29 @@ namespace jdi
minItem.filter = EditFilter::NUMBER;
items.push_back(minItem);
// 选区自适应:只按当前显示时间段内的数据做幅值自适应(放大局部后铺满网格)。
// 选区自适应(切换项):勾选后每次本网格的时间轴选区放大都会自动匹配 Y 轴幅值。
MenuItem autoViewItem;
autoViewItem.label = L"选区 Y 轴自适应";
autoViewItem.id = PLOT_CMD_LANE_AUTO_VIEW;
autoViewItem.checked = m_plot.LaneRangeIsAutoToView(laneIndex);
autoViewItem.checked = m_plot.LaneAutoFitToSelection(laneIndex);
items.push_back(autoViewItem);
// 时间轴自适应到本网格信号范围(原先位于分隔线下方,现移到分隔线上方)。
MenuItem fitLaneTime;
fitLaneTime.label = L"按网格时间轴展开";
fitLaneTime.id = PLOT_CMD_LANE_FIT_TIME;
items.push_back(fitLaneTime);
MenuItem separator;
separator.kind = MenuItemKind::SEPARATOR;
items.push_back(separator);
// 恢复自适应放在分隔线下方、时间轴自适应上方。
MenuItem autoItem;
autoItem.label = isAuto ? L"Y 轴自适应(当前)" : L"恢复 Y 轴自适应";
autoItem.id = PLOT_CMD_LANE_AUTO;
autoItem.checked = isAuto;
autoItem.enabled = !isAuto;
items.push_back(autoItem);
MenuItem fitLaneTime;
fitLaneTime.label = L"时间轴自适应(匹配本网格)";
fitLaneTime.id = PLOT_CMD_LANE_FIT_TIME;
items.push_back(fitLaneTime);
// 全局开关:一次性打开/关闭全部网格各自的「选区 Y 轴自适应」。
MenuItem autoFitAllItem;
autoFitAllItem.label = L"选区 Y 轴自适应(全局)";
autoFitAllItem.id = PLOT_CMD_AUTO_FIT_ALL;
autoFitAllItem.checked = m_plot.AllLanesAutoFitToSelection();
items.push_back(autoFitAllItem);
MenuItem fitItem;
fitItem.label = L"全部自适应";
@@ -1450,14 +1460,11 @@ namespace jdi
m_menu.UpdateItemValue(PLOT_CMD_LANE_Y_MAX, FormatValue(laneYMax));
m_menu.UpdateItemValue(PLOT_CMD_LANE_Y_MIN, FormatValue(laneYMin));
// 手工输入上下限后已不再是自动自适应,同步刷新该项的文字/选中标记/可用状态。
const bool isAuto = m_plot.LaneRangeIsAuto(laneIndex);
m_menu.UpdateItemLabel(PLOT_CMD_LANE_AUTO, isAuto ? L"Y 轴自适应(当前)" : L"恢复 Y 轴自适应",
isAuto, !isAuto);
// “选区 Y 轴自适应”是带状态的操作,同样需要实时反映其“当前生效”标记。
// 「选区 Y 轴自适应」(本网格)与「(全局)」都是切换项,实时反映各自的勾选状态。
m_menu.UpdateItemLabel(PLOT_CMD_LANE_AUTO_VIEW, L"选区 Y 轴自适应",
m_plot.LaneRangeIsAutoToView(laneIndex), true);
m_plot.LaneAutoFitToSelection(laneIndex), true);
m_menu.UpdateItemLabel(PLOT_CMD_AUTO_FIT_ALL, L"选区 Y 轴自适应(全局)",
m_plot.AllLanesAutoFitToSelection(), true);
}
void Application::DispatchMenuResult(const MenuResult& result)
@@ -1500,12 +1507,17 @@ namespace jdi
m_plotMenuLane = -1;
switch (result.id)
{
case PLOT_CMD_LANE_AUTO:
m_plot.ResetLaneRange(laneIndex);
break;
case PLOT_CMD_LANE_AUTO_VIEW:
m_plot.AutoRangeLaneToView(laneIndex);
// 切换本网格的「选区 Y 轴自适应」。
m_plot.ToggleLaneAutoFitToSelection(laneIndex);
break;
case PLOT_CMD_AUTO_FIT_ALL:
{
// 全局切换:一次打开/关闭全部网格各自的开关。
const bool enable = !m_plot.AllLanesAutoFitToSelection();
m_plot.SetAllLanesAutoFitToSelection(enable);
break;
}
case PLOT_CMD_LANE_FIT_TIME:
m_plot.FitTimeToLane(laneIndex);
break;
+26 -17
View File
@@ -47,12 +47,12 @@ namespace jdi
*/
enum PlotMenuCommand : int
{
PLOT_CMD_LANE_AUTO = 1, /**< 该网格恢复 Y 轴自适应。 */
PLOT_CMD_AUTO_FIT_ALL = 1, /**< 全局切换全部网格的「选区 Y 轴自适应」。 */
PLOT_CMD_LANE_Y_MAX = 2, /**< 输入该网格 Y 轴最大值。 */
PLOT_CMD_LANE_Y_MIN = 3, /**< 输入该网格 Y 轴最小值。 */
PLOT_CMD_FIT_ALL = 4, /**< 全部网格与时间轴自适应。 */
PLOT_CMD_LANE_FIT_TIME = 5, /**< 时间轴自适应到本网格信号范围。 */
PLOT_CMD_LANE_AUTO_VIEW = 6 /**< 按当前显示时间段内的数据做 Y 轴自适应。 */
PLOT_CMD_LANE_FIT_TIME = 5, /**< 时间轴自适应到本网格信号范围(按网格时间轴展开)。 */
PLOT_CMD_LANE_AUTO_VIEW = 6 /**< 切换本网格的「选区 Y 轴自适应」开关。 */
};
/**
@@ -175,6 +175,13 @@ namespace jdi
*/
bool AutoRangeLaneToView(int laneIndex);
/**
* @brief 对全部开启了「选区 Y 轴自适应」的网格做一次 Y 轴选区自适应。
*
* 时间轴选区放大后调用:只有开关开启的网格才自动匹配新的可见时间区间。
*/
void ApplySelectionAutoFit();
/**
* @brief 把时间吸附到距今最近的数据采样点。
*
@@ -304,29 +311,31 @@ namespace jdi
int LaneIndexAt(int x, int y) const;
/**
* @brief 判断某网格的 Y 轴是否处于自适应状态。
* @brief 判断某网格是否开启了「选区 Y 轴自适应」开关(菜单勾选标记)。
* @param [IN] laneIndex 网格下标。
* @return 自适应返回 true。
* @return 开启返回 true。
*/
bool LaneRangeIsAuto(int laneIndex) const;
bool LaneAutoFitToSelection(int laneIndex) const;
/**
* @brief 判断某网格当前范围是否正是「选区 Y 轴自适应」的结果(用于菜单勾选标记)。
*
* 只有在该操作之后未发生任何手动幅值改动、且时间选区没有变化时才返回 true,
* 因为一旦时间选区改变,之前的选区自适应结果就不再对应当前视野。
*
* @param [IN] laneIndex 网格下标。
* @return 当前生效返回 true。
* @brief 判断是否全部网格都开启了「选区 Y 轴自适应」(用于全局菜单项与工具栏按钮)。
* @return 存在网格且全部开启返回 true。
*/
bool LaneRangeIsAutoToView(int laneIndex) const;
bool AllLanesAutoFitToSelection() const;
/**
* @brief 让某网格的 Y 轴恢复自适应。
* @brief 切换某网格的「选区 Y 轴自适应」开关。
* @param [IN] laneIndex 网格下标。
* @return 状态发生变化返回 true。
* @return 切换后的状态。
*/
bool ResetLaneRange(int laneIndex);
bool ToggleLaneAutoFitToSelection(int laneIndex);
/**
* @brief 一次性设置全部网格的「选区 Y 轴自适应」开关(全局菜单项 / 工具栏按钮)。
* @param [IN] enabled 目标状态。
* @return 任一网格状态发生变化返回 true。
*/
bool SetAllLanesAutoFitToSelection(bool enabled);
/**
* @brief 进入某网格 Y 轴上限/下限的内联输入状态。
+89 -36
View File
@@ -499,10 +499,11 @@ namespace jdi
if (m_tab != nullptr)
{
// 适应视图 = 回到初始状态:全部网格恢复整段数据的自动自适应。
// 「选区 Y 轴自适应」是用户设置项,这里保持不变。
for (Lane& lane : m_tab->Lanes())
{
lane.autoRange = true;
lane.viewAutoRange = false;
}
}
BuildLaneVisuals();
@@ -788,6 +789,9 @@ namespace jdi
Tab().ViewMin() = timeA;
Tab().ViewMax() = timeB;
ClampTimeView();
// 「选区 Y 轴自适应」开关开启的网格:时间选区放大后自动把 Y 轴匹配到新的可见区间。
ApplySelectionAutoFit();
return true;
}
@@ -822,7 +826,8 @@ namespace jdi
Lane& lane = m_tab->Lanes()[static_cast<std::size_t>(laneIndex)];
lane.autoRange = false;
lane.viewAutoRange = false;
// 手动 Y 轴选区放大:关闭本网格的「选区 Y 轴自适应」。
lane.fitYToSelection = false;
lane.yMin = std::min(valueTop, valueBottom);
lane.yMax = std::max(valueTop, valueBottom);
return true;
@@ -837,47 +842,64 @@ namespace jdi
return LaneAtY(y);
}
bool PlotView::LaneRangeIsAuto(int laneIndex) const
bool PlotView::LaneAutoFitToSelection(int laneIndex) const
{
if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_tab->Lanes().size()))
{
return false;
}
return m_tab->Lanes()[static_cast<std::size_t>(laneIndex)].fitYToSelection;
}
bool PlotView::AllLanesAutoFitToSelection() const
{
if (m_tab == nullptr)
{
return false;
}
const std::vector<Lane>& lanes = m_tab->Lanes();
if (lanes.empty())
{
return false;
}
for (const Lane& lane : lanes)
{
if (!lane.fitYToSelection)
{
// 任一网格未开启 → 全局项就不是勾选状态。
return false;
}
}
return true;
}
return m_tab->Lanes()[static_cast<std::size_t>(laneIndex)].autoRange;
}
bool PlotView::LaneRangeIsAutoToView(int laneIndex) const
{
// “选区 Y 轴自适应”是带状态的操作:只有应用后未被任何手动改动、
// 且时间选区没有变化时,当前范围才仍等于该操作的结果。
if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_tab->Lanes().size()))
{
return false;
}
const Lane& lane = m_tab->Lanes()[static_cast<std::size_t>(laneIndex)];
if (!lane.viewAutoRange || lane.autoRange)
{
return false;
}
return (lane.viewAutoMin == Tab().ViewMin()) && (lane.viewAutoMax == Tab().ViewMax());
}
bool PlotView::ResetLaneRange(int laneIndex)
bool PlotView::ToggleLaneAutoFitToSelection(int laneIndex)
{
if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_tab->Lanes().size()))
{
return false;
}
Lane& lane = m_tab->Lanes()[static_cast<std::size_t>(laneIndex)];
if (lane.autoRange)
lane.fitYToSelection = !lane.fitYToSelection;
return lane.fitYToSelection;
}
bool PlotView::SetAllLanesAutoFitToSelection(bool enabled)
{
if (m_tab == nullptr)
{
return false;
}
lane.autoRange = true;
lane.viewAutoRange = false;
BuildLaneVisuals();
return true;
bool changed = false;
for (Lane& lane : m_tab->Lanes())
{
if (lane.fitYToSelection != enabled)
{
lane.fitYToSelection = enabled;
changed = true;
}
}
return changed;
}
bool PlotView::AutoRangeLaneToView(int laneIndex)
@@ -979,14 +1001,43 @@ namespace jdi
lane.autoRange = false;
lane.yMin = low;
lane.yMax = high;
// 记录应用时的视图时间区间:时间选区一变,本项就不再是“当前生效”状态。
lane.viewAutoRange = true;
lane.viewAutoMin = viewMin;
lane.viewAutoMax = viewMax;
BuildLaneVisuals();
return true;
}
void PlotView::ApplySelectionAutoFit()
{
if (m_tab == nullptr || m_dataSet == nullptr)
{
return;
}
const std::vector<Lane>& lanes = m_tab->Lanes();
bool any = false;
for (const Lane& lane : lanes)
{
if (lane.fitYToSelection)
{
any = true;
break;
}
}
if (!any)
{
return;
}
// 只对开启了「选区 Y 轴自适应」的网格重新匹配 Y 轴;
// 重新匹配依据的是刚刚更新过的时间视图范围。
for (std::size_t index = 0; index < lanes.size(); ++index)
{
if (m_tab->Lanes()[index].fitYToSelection)
{
AutoRangeLaneToView(static_cast<int>(index));
}
}
}
void PlotView::ScaleLaneRange(int laneIndex, double factor, double anchorValue)
{
if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_lanes.size()))
@@ -1012,7 +1063,7 @@ namespace jdi
Lane& lane = m_tab->Lanes()[static_cast<std::size_t>(laneIndex)];
lane.autoRange = false;
lane.viewAutoRange = false;
lane.fitYToSelection = false;
lane.yMin = anchorValue - ratio * newSpan;
lane.yMax = lane.yMin + newSpan;
BuildLaneVisuals();
@@ -1029,7 +1080,8 @@ namespace jdi
// 首次纵向拖动时先把当前自适应范围固化下来,再进行偏移。
const LaneVisual& visual = m_lanes[static_cast<std::size_t>(laneIndex)];
Lane& lane = m_tab->Lanes()[static_cast<std::size_t>(laneIndex)];
lane.viewAutoRange = false;
// 手动纵向平移属于手动调整幅值:关闭本网格的「选区 Y 轴自适应」。
lane.fitYToSelection = false;
if (lane.autoRange)
{
lane.autoRange = false;
@@ -1097,7 +1149,7 @@ namespace jdi
// 手工输入即视为取消自动自适应,与拖拽框选缩放的语义一致。
// 必须先把当前(自适应计算出的)显示范围固化到 lane 里,再只改动被编辑的一端,
// 否则另一端会回退到 Lane 的初始占位值,导致量程被莫名其妙地放大。
lane.viewAutoRange = false;
lane.fitYToSelection = false;
if (lane.autoRange)
{
lane.autoRange = false;
@@ -1437,7 +1489,8 @@ namespace jdi
}
const LaneVisual& visual = m_lanes[static_cast<std::size_t>(laneIndex)];
Lane& lane = m_tab->Lanes()[static_cast<std::size_t>(laneIndex)];
lane.viewAutoRange = false;
// 直接输入上下限属于手动调整幅值:关闭本网格的「选区 Y 轴自适应」。
lane.fitYToSelection = false;
if (lane.autoRange)
{
lane.autoRange = false;
+15 -2
View File
@@ -843,8 +843,21 @@ namespace jdi
int paletteCount = 0;
const std::uint32_t* palette = SignalPalette(paletteCount);
// 当自定义颜色与某个预设色恰好相同时,优先视为自定义颜色,避免两处同时高亮。
const bool customActive = (style->color == style->customColor);
// 判定“当前是否在用自定义色”:必须同时满足
// 1) 显示颜色等于记忆的自定义色;
// 2) 该颜色不是任何一个可见的预设色。
// 否则一旦自定义色与某个预设色相同时,点击那个预设色块会把高亮错误地
// 挪到自定义色块上(用户报告的“点预设色直接跳到自定义色块”)。
bool presetMatches = false;
for (int index = 0; index < m_colorCount; ++index)
{
if (style->color == palette[index % paletteCount])
{
presetMatches = true;
break;
}
}
const bool customActive = (style->color == style->customColor) && !presetMatches;
for (int index = 0; index < m_colorCount; ++index)
{
const gd::RectF& rect = m_colorRects[static_cast<std::size_t>(index)];
+1
View File
@@ -22,6 +22,7 @@ namespace jdi
NONE = 0, /**< 未触发任何动作。 */
OPEN_FILE, /**< 打开 CSV 文件。 */
FIT_ALL, /**< 视图自适应到可见信号范围(同时退出缩放模式)。 */
AUTO_FIT_Y, /**< 切换「选区 Y 轴自适应」全局开关:时间轴选区放大后自动匹配各网格 Y 轴。 */
ZOOM_TIME, /**< 切换「时间轴选区」模式(框选时间区间后放大)。 */
ZOOM_VALUE, /**< 切换「Y 轴选区」模式(框选幅值区间后放大)。 */
CURSOR, /**< 切换时间光标。 */
+1
View File
@@ -68,6 +68,7 @@ namespace jdi
const Spec specs[] = {
{ToolbarAction::OPEN_FILE, L"导入文件", true, false, false},
{ToolbarAction::FIT_ALL, L"适应视图", false, true, false},
{ToolbarAction::AUTO_FIT_Y, L"Y 轴自适应", false, true, true},
{ToolbarAction::ZOOM_TIME, L"时间轴选区", false, true, true},
{ToolbarAction::ZOOM_VALUE, L"Y 轴选区", false, true, true},
{ToolbarAction::CURSOR, L"光标", false, true, true},
+8 -3
View File
@@ -330,9 +330,14 @@ namespace jdi
bool autoRange = true; /**< 是否依据信号取值范围自动计算 Y 轴。 */
double yMin = -1.0; /**< 手动 Y 轴下限。 */
double yMax = 1.0; /**< 手动 Y 轴上限。 */
bool viewAutoRange = false; /**< 是否由「选区 Y 轴自适应」产生且时间选区未再变化。 */
double viewAutoMin = 0.0; /**< 应用「选区 Y 轴自适应」时的视图时间下限。 */
double viewAutoMax = 0.0; /**< 应用「选区 Y 轴自适应」时的视图时间上限。 */
/**
* @brief 「选区 Y 轴自适应」开关。
*
* 开启后每次对该网格做时间轴选区放大,都会自动把本网格的 Y 轴匹配到新的可见时间区间;
* 用户手动调整幅值(拖拽平移、Y 轴选区放大、直接输入上下限)后会自动关闭。
*/
bool fitYToSelection = false;
};
/**
+40 -7
View File
@@ -111,6 +111,28 @@ namespace jdi
void RebuildLanes(const std::vector<std::vector<bool>>& visible, std::vector<Lane>& lanes,
LaneMode mode)
{
// 先记下每个信号原来所在网格的「选区 Y 轴自适应」开关:
// 勾选可见性会重建网格,若不携带,用户刚打开的开关会被悄悄清掉。
std::vector<std::pair<SignalRef, bool>> previousFit;
for (const Lane& lane : lanes)
{
for (const SignalRef& ref : lane.signals)
{
previousFit.emplace_back(ref, lane.fitYToSelection);
}
}
const auto inheritedFit = [&previousFit](const SignalRef& ref)
{
for (const std::pair<SignalRef, bool>& entry : previousFit)
{
if (entry.first == ref)
{
return entry.second;
}
}
return false;
};
// 收集全部可见信号引用。
std::vector<SignalRef> visibleRefs;
for (std::size_t fileIndex = 0; fileIndex < visible.size(); ++fileIndex)
@@ -151,6 +173,7 @@ namespace jdi
{
Lane lane;
lane.autoRange = true;
lane.fitYToSelection = inheritedFit(ref);
lane.signals.push_back(ref);
lanes.push_back(std::move(lane));
}
@@ -175,6 +198,7 @@ namespace jdi
lane.autoRange = previousAutoRange;
lane.yMin = previousYMin;
lane.yMax = previousYMax;
lane.fitYToSelection = inheritedFit(visibleRefs.front());
lane.signals = visibleRefs;
lanes.push_back(std::move(lane));
}
@@ -216,6 +240,7 @@ namespace jdi
Lane lane;
lane.autoRange = true;
lane.fitYToSelection = inheritedFit(ref);
lane.signals.push_back(ref);
lanes.push_back(std::move(lane));
}
@@ -426,11 +451,21 @@ namespace jdi
// 使同一信号在任意标签页中都保持同一默认颜色。
{
const std::size_t globalIndex = paletteBase + file.signals.size();
signal.style.color =
(palette != nullptr && paletteCount > 0)
? palette[globalIndex % static_cast<std::size_t>(paletteCount)]
: 0xFF268BD2u;
signal.style.customColor = signal.style.color;
if (palette != nullptr && paletteCount > 0)
{
const std::size_t count = static_cast<std::size_t>(paletteCount);
const std::size_t slot = globalIndex % count;
signal.style.color = palette[slot];
// 自定义色初值取调色板中「向后递进」的下一个颜色。
// 若初值等于本信号自身的预设色,样式区里点击该预设色块会被判定成
// “当前用的是自定义色”,高亮会直接跳到自定义色块上(此前的缺陷)。
signal.style.customColor = palette[(slot + 1) % count];
}
else
{
signal.style.color = 0xFF268BD2u;
signal.style.customColor = 0xFF859900u;
}
signal.style.opacity = 1.0f;
signal.style.lineWidth = 1.0f;
signal.style.mode = DrawMode::LINE;
@@ -1048,8 +1083,6 @@ namespace jdi
for (Lane& lane : m_lanes)
{
// 网格的信号组成发生变化,“选区 Y 轴自适应”的结果不再对应当前视野。
lane.viewAutoRange = false;
std::vector<SignalRef>& refs = lane.signals;
refs.erase(std::remove(refs.begin(), refs.end(), ref), refs.end());
}