命名审查与垃圾代码清理(纯重命名 / 死代码删除,无行为变更)

前提:加载完成后全部采样都已驻留内存,程序此后与源文件再无联系。
据此修正了一批会让人误以为"仍在读写文件"的命名:

- SampleFileAt → SampleSignalAt(取的是内存信号在给定时刻的采样值)。
- DataSet::AddPreparedFile → AddDataFile。
- PlotView::InvalidatePolylineCache → InvalidateDerivedCaches
  (它同时清空折线、边沿统计、中心平均值曲线、静态场景缓存与悬停引用)。
- PlotView::CursorColor(int which) → CursorColor()(两条光标同色,参数从未使用)。
- UiEllipsize(g,…) → UiEllipsize(…):纯测量不绘制,删掉被忽略的绘图上下文参数;
  同时删除与 UiMeasureTextWidth 完全重复的 UiTextWidth,调用点统一到 UiMeasureTextWidth。

清理残留参数((void)xxx;):
- TabConfig 的可见性/网格族(SetVisible / ToggleVisible / SetFileVisible / SetAllVisible /
  SoloSignal / SetMode / SyncLanes / FileHasVisible / FileAllVisible)去掉从未使用的
  const DataSet& 参数(仅 SyncToDataSet 真正需要数据层,保留)。
- PlotView::OnLButtonUp(int y)、OnMouseWheel(int delta, bool shift);PainterSignalHalo 去掉未用的 ref。
- BuildDataFile 中未使用的局部 rowCount。

删除无人调用的死函数:
  DataSet::Clear / AddFromTable;SignalColorCount;WideToUtf8 / StartsWith;
  PlotView::ViewMinTime / ViewMaxTime / EdgePanelRect / EdgePanelCloseRect /
  EdgeCenterPanelRect / ScaleLaneRange / BeginLaneValueEdit / LaneContentHeight;
  SignalPanel::NeedsScrollBar / IsFilterEditing / FilterText / ContentHeight;
  PopupMenu::EditingItemId;TabBar::IsDragging;TextEdit::PlaceCaret。

删除只写不读的死字段:CsvTable::sourceRowCount(与 rowCount 等义)与 skippedRowCount。

以 VERY_BIG_DATA.CSV 回归验证:加载与勾选、筛选框(含"无匹配的筛选信号")、
样式区线宽文案省略、选区放大(横向与纵向)、双光标读数与 Δt、右键菜单(Y 轴数值与
实验性功能子菜单)、合并/拆分网格、标签与信号重命名省略号,行为均与改动前一致;
make clean && make all 无任何警告。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-09 21:52:46 +08:00
1 parent f5028b1e18
commit 350538c634
21 files changed
+118 -456

No files matched your search

+12 -12
View File
@@ -547,8 +547,8 @@ namespace jdi
m_dataSet.ValidateSelection(); m_dataSet.ValidateSelection();
m_panel.InvalidateRows(); m_panel.InvalidateRows();
// 文件/信号结构变化会让信号引用与文件地址改变,折线顶点缓存必须作废。 // 文件/信号结构变化会让信号引用与文件地址改变,派生缓存必须整体作废。
m_plot.InvalidatePolylineCache(); m_plot.InvalidateDerivedCaches();
// 强制下一次同步重新计算视图状态。 // 强制下一次同步重新计算视图状态。
m_cachedVisibleCount = -1; m_cachedVisibleCount = -1;
@@ -892,7 +892,7 @@ namespace jdi
int fileIndex = -1; int fileIndex = -1;
// 此处只做一次指针/缓冲移动,不拷贝任何采样数据,因此不会造成可见卡顿。 // 此处只做一次指针/缓冲移动,不拷贝任何采样数据,因此不会造成可见卡顿。
if (!m_dataSet.AddPreparedFile(std::move(file), fileIndex)) if (!m_dataSet.AddDataFile(std::move(file), fileIndex))
{ {
SetStatusMessage(L"解析失败:数据为空。", true); SetStatusMessage(L"解析失败:数据为空。", true);
InvalidateRect(m_hwnd, nullptr, FALSE); InvalidateRect(m_hwnd, nullptr, FALSE);
@@ -1033,7 +1033,7 @@ namespace jdi
// 超长文件名用省略号截断,避免撑破卡片。 // 超长文件名用省略号截断,避免撑破卡片。
const std::wstring nameText = const std::wstring nameText =
UiEllipsize(g, m_loadingText, m_fonts.uiSmall, textWidth); UiEllipsize(m_loadingText, m_fonts.uiSmall, textWidth);
UiText(g, nameText, m_fonts.uiSmall, UiText(g, nameText, m_fonts.uiSmall,
gd::RectF(textLeft, card.Y + 42.0f * m_scale, textWidth, 20.0f * m_scale), gd::RectF(textLeft, card.Y + 42.0f * m_scale, textWidth, 20.0f * m_scale),
m_theme.textMuted, TextAlign::LEFT); m_theme.textMuted, TextAlign::LEFT);
@@ -1125,21 +1125,21 @@ namespace jdi
case ToolbarAction::MERGE_LANES: case ToolbarAction::MERGE_LANES:
if (!m_dataSet.Empty()) if (!m_dataSet.Empty())
{ {
ActiveTab().SetMode(m_dataSet, LaneMode::MERGED); ActiveTab().SetMode(LaneMode::MERGED);
SetStatusMessage(L"已将当前标签页的全部可见信号合并到同一网格。", false); SetStatusMessage(L"已将当前标签页的全部可见信号合并到同一网格。", false);
} }
break; break;
case ToolbarAction::SPLIT_LANES: case ToolbarAction::SPLIT_LANES:
if (!m_dataSet.Empty()) if (!m_dataSet.Empty())
{ {
ActiveTab().SetMode(m_dataSet, LaneMode::PER_SIGNAL); ActiveTab().SetMode(LaneMode::PER_SIGNAL);
SetStatusMessage(L"当前标签页已切换为「每信号一格」。", false); SetStatusMessage(L"当前标签页已切换为「每信号一格」。", false);
} }
break; break;
case ToolbarAction::CLEAR_ALL: case ToolbarAction::CLEAR_ALL:
if (!m_dataSet.Empty()) if (!m_dataSet.Empty())
{ {
ActiveTab().SetAllVisible(m_dataSet, false); ActiveTab().SetAllVisible(false);
m_panel.InvalidateRows(); m_panel.InvalidateRows();
SetStatusMessage(L"已清空当前标签页的全部网格。", false); SetStatusMessage(L"已清空当前标签页的全部网格。", false);
} }
@@ -1436,7 +1436,7 @@ namespace jdi
SignalRef derivedRef; SignalRef derivedRef;
derivedRef.fileIndex = fileIndex; derivedRef.fileIndex = fileIndex;
derivedRef.signalIndex = newIndex; derivedRef.signalIndex = newIndex;
ActiveTab().SetVisible(m_dataSet, derivedRef, true); ActiveTab().SetVisible(derivedRef, true);
SignalRef sourceRef; SignalRef sourceRef;
sourceRef.fileIndex = fileIndex; sourceRef.fileIndex = fileIndex;
@@ -1812,7 +1812,7 @@ namespace jdi
m_activeTarget = Target::NONE; m_activeTarget = Target::NONE;
m_draggingSplitter = false; m_draggingSplitter = false;
m_panel.OnLButtonUp(0, 0); m_panel.OnLButtonUp(0, 0);
m_plot.OnLButtonUp(0, 0); m_plot.OnLButtonUp(0);
} }
switch (message) switch (message)
@@ -1937,7 +1937,7 @@ namespace jdi
// 拾色器接管输入后,取消底层组件可能仍在进行的拖拽。 // 拾色器接管输入后,取消底层组件可能仍在进行的拖拽。
m_panel.OnLButtonUp(0, 0); m_panel.OnLButtonUp(0, 0);
m_plot.OnLButtonUp(0, 0); m_plot.OnLButtonUp(0);
m_activeTarget = Target::NONE; m_activeTarget = Target::NONE;
m_draggingSplitter = false; m_draggingSplitter = false;
@@ -2295,7 +2295,7 @@ namespace jdi
m_panel.OnLButtonUp(x, y); m_panel.OnLButtonUp(x, y);
break; break;
case Target::PLOT: case Target::PLOT:
m_plot.OnLButtonUp(x, y); m_plot.OnLButtonUp(y);
break; break;
case Target::NONE: case Target::NONE:
default: default:
@@ -2469,7 +2469,7 @@ namespace jdi
} }
else if (m_plot.HitTest(point.x, point.y)) else if (m_plot.HitTest(point.x, point.y))
{ {
changed = m_plot.OnMouseWheel(point.x, point.y, delta, shift); changed = m_plot.OnMouseWheel(delta, shift);
} }
if (changed) if (changed)
{ {
+9 -63
View File
@@ -160,7 +160,7 @@ namespace jdi
* @param [IN] y 客户区纵坐标。 * @param [IN] y 客户区纵坐标。
* @return 需要重绘返回 true。 * @return 需要重绘返回 true。
*/ */
bool OnLButtonUp(int x, int y); bool OnLButtonUp(int y);
/** /**
* @brief 处理鼠标中键按下:与左键在常规模式下一致,进入自由平移(水平平移时间轴 + * @brief 处理鼠标中键按下:与左键在常规模式下一致,进入自由平移(水平平移时间轴 +
@@ -186,7 +186,7 @@ namespace jdi
* @param [IN] shift 是否按下 Shift(水平平移时间轴)。 * @param [IN] shift 是否按下 Shift(水平平移时间轴)。
* @return 需要重绘返回 true。 * @return 需要重绘返回 true。
*/ */
bool OnMouseWheel(int x, int y, int delta, bool shift); bool OnMouseWheel(int delta, bool shift);
/** /**
* @brief 处理鼠标双击(命中时间光标时进入精确时间输入)。 * @brief 处理鼠标双击(命中时间光标时进入精确时间输入)。
@@ -301,12 +301,6 @@ namespace jdi
*/ */
void ScrollLanesByFraction(double fraction); void ScrollLanesByFraction(double fraction);
/**
* @brief 获取网格当前内容总高度。
* @return 内容高度(像素)。
*/
float LaneContentHeight() const { return m_laneContentHeight; }
/** /**
* @brief 提示浮层是否仍在显示(含淡出阶段)。 * @brief 提示浮层是否仍在显示(含淡出阶段)。
* *
@@ -341,12 +335,14 @@ namespace jdi
bool ExitZoomModes(); bool ExitZoomModes();
/** /**
* @brief 清空折线顶点缓存。 * @brief 使全部派生结果失效:折线顶点、边沿统计、中心平均值曲线与静态场景缓存。
* *
* 数据层结构变化(加载/移除文件、信号增删)后信号引用与文件地址都可能改变, * 数据层结构变化(加载/移除文件、信号增删)后信号引用与文件地址都可能改变,
* 必须清空缓存,避免旧几何键与新的信号意外重合而取到过期顶点。 * 必须整体失效,避免旧几何键与新的信号意外重合而取到过期结果。
*/ */
void InvalidatePolylineCache(); /** void InvalidateDerivedCaches();
/**
* @brief 三态循环切换时间光标:无 → 单光标 → 双光标 → 无。 * @brief 三态循环切换时间光标:无 → 单光标 → 双光标 → 无。
* @return 状态发生变化返回 true。 * @return 状态发生变化返回 true。
*/ */
@@ -508,14 +504,6 @@ namespace jdi
*/ */
bool TakePendingMeanFilterBuild(int& laneIndex, int& radius); bool TakePendingMeanFilterBuild(int& laneIndex, int& radius);
/**
* @brief 进入某网格 Y 轴上限/下限的内联输入状态。
* @param [IN] laneIndex 网格下标。
* @param [IN] editMax 为 true 编辑上限,为 false 编辑下限。
* @return 进入成功返回 true。
*/
bool BeginLaneValueEdit(int laneIndex, bool editMax, const gd::RectF& anchorRect);
/** /**
* @brief 直接把文本解析为网格 Y 轴上限/下限并应用(供菜单内联输入框提交使用)。 * @brief 直接把文本解析为网格 Y 轴上限/下限并应用(供菜单内联输入框提交使用)。
* @param [IN] laneIndex 网格下标。 * @param [IN] laneIndex 网格下标。
@@ -590,18 +578,6 @@ namespace jdi
*/ */
bool OnEditMouseUp(); bool OnEditMouseUp();
/**
* @brief 获取当前视图左边界时间。
* @return 视图左边界时间。
*/
double ViewMinTime() const;
/**
* @brief 获取当前视图右边界时间。
* @return 视图右边界时间。
*/
double ViewMaxTime() const;
/** /**
* @brief 重新生成网格几何(可见性或网格划分变化后调用)。 * @brief 重新生成网格几何(可见性或网格划分变化后调用)。
*/ */
@@ -756,14 +732,6 @@ namespace jdi
*/ */
bool ApplyValueSelection(int laneIndex, float y0, float y1); bool ApplyValueSelection(int laneIndex, float y0, float y1);
/**
* @brief 以指定倍率缩放某网格的幅值轴(保持锚点幅值不动)。
* @param [IN] laneIndex 目标网格下标。
* @param [IN] factor 缩放倍率,大于 1 表示放大。
* @param [IN] anchorValue 锚点幅值。
*/
void ScaleLaneRange(int laneIndex, double factor, double anchorValue);
/** /**
* @brief 平移某网格的幅值轴(偏移波形显示位置)。 * @brief 平移某网格的幅值轴(偏移波形显示位置)。
* @param [IN] laneIndex 目标网格下标。 * @param [IN] laneIndex 目标网格下标。
@@ -827,7 +795,7 @@ namespace jdi
* @param [IN] which 光标序号(1 或 2)。 * @param [IN] which 光标序号(1 或 2)。
* @return 颜色。 * @return 颜色。
*/ */
std::uint32_t CursorColor(int which) const; std::uint32_t CursorColor() const;
/** /**
* @brief 设置并显示一条临时提示(在绘图区底部以浮层方式绘制,短暂停留后淡出)。 * @brief 设置并显示一条临时提示(在绘图区底部以浮层方式绘制,短暂停留后淡出)。
@@ -979,13 +947,6 @@ namespace jdi
*/ */
EdgePanelLayout EdgePanelLayoutFor(int laneIndex, EdgePanelKind kind) const; EdgePanelLayout EdgePanelLayoutFor(int laneIndex, EdgePanelKind kind) const;
/**
* @brief 获取「边沿计数(中心轴)」浮动面板的矩形。
* @param [IN] laneIndex 网格下标。
* @return 面板矩形(未展开时为空矩形)。
*/
gd::RectF EdgeCenterPanelRect(int laneIndex) const;
/** /**
* @brief 获取中心平均值曲线(每个数据点 = 自身与左右各 N 点的平均值),结果带缓存。 * @brief 获取中心平均值曲线(每个数据点 = 自身与左右各 N 点的平均值),结果带缓存。
* @param [IN] signal 目标信号。 * @param [IN] signal 目标信号。
@@ -1103,20 +1064,6 @@ namespace jdi
void PlaceCursorLabel(gd::RectF& rect, float preferredTop, float textHeight, float clipTop, void PlaceCursorLabel(gd::RectF& rect, float preferredTop, float textHeight, float clipTop,
float clipBottom); float clipBottom);
/**
* @brief 获取边沿统计面板的矩形(未展开时返回空矩形)。
* @param [IN] laneIndex 网格下标。
* @return 面板矩形。
*/
gd::RectF EdgePanelRect(int laneIndex) const;
/**
* @brief 获取边沿统计面板上关闭按钮的矩形。
* @param [IN] laneIndex 网格下标。
* @return 关闭按钮矩形。
*/
gd::RectF EdgePanelCloseRect(int laneIndex) const;
/** /**
* @brief 统计某信号穿越横向光标幅值的上/下边沿数量,结果带缓存。 * @brief 统计某信号穿越横向光标幅值的上/下边沿数量,结果带缓存。
* @param [IN] file 信号所属文件。 * @param [IN] file 信号所属文件。
@@ -1466,12 +1413,11 @@ namespace jdi
/** /**
* @brief 绘制某条信号的悬停/拖拽光晕。 * @brief 绘制某条信号的悬停/拖拽光晕。
* @param [IN,OUT] g 绘图上下文。 * @param [IN,OUT] g 绘图上下文。
* @param [IN] ref 信号引用。
* @param [IN] resolved 已解析的信号。 * @param [IN] resolved 已解析的信号。
* @param [IN] points 折线顶点。 * @param [IN] points 折线顶点。
* @param [IN] breaks 每段折线的起始下标。 * @param [IN] breaks 每段折线的起始下标。
*/ */
void PaintSignalHalo(gd::Graphics& g, const SignalRef& ref, const ResolvedSignal& resolved, void PaintSignalHalo(gd::Graphics& g, const ResolvedSignal& resolved,
const std::vector<gd::PointF>& points, const std::vector<std::size_t>& breaks); const std::vector<gd::PointF>& points, const std::vector<std::size_t>& breaks);
/** /**
+29 -111
View File
@@ -363,7 +363,7 @@ namespace jdi
m_hoverLane = -1; m_hoverLane = -1;
m_dragMode = PlotDragMode::NONE; m_dragMode = PlotDragMode::NONE;
// 重新绑定数据源后旧的几何键不再有意义,必须清空折线缓存。 // 重新绑定数据源后旧的几何键不再有意义,必须清空折线缓存。
InvalidatePolylineCache(); InvalidateDerivedCaches();
InvalidateSceneCache(); InvalidateSceneCache();
RefreshLanes(); RefreshLanes();
} }
@@ -389,16 +389,6 @@ namespace jdi
return Tab().CursorMode(); return Tab().CursorMode();
} }
double PlotView::ViewMinTime() const
{
return Tab().ViewMin();
}
double PlotView::ViewMaxTime() const
{
return Tab().ViewMax();
}
bool PlotView::HasDrawableContent() const bool PlotView::HasDrawableContent() const
{ {
return (m_dataSet != nullptr) && !m_dataSet->Empty() && (m_tab != nullptr) && m_tab->AnyVisible(); return (m_dataSet != nullptr) && !m_dataSet->Empty() && (m_tab != nullptr) && m_tab->AnyVisible();
@@ -899,10 +889,9 @@ namespace jdi
} }
} }
std::uint32_t PlotView::CursorColor(int which) const std::uint32_t PlotView::CursorColor() const
{ {
// 两条光标统一使用同一样式与颜色(与光标 1 一致),不再按序号区分配色。 // 两条光标统一使用同一样式与颜色,不按序号区分配色。
(void)which;
if (m_theme == nullptr) if (m_theme == nullptr)
{ {
return 0xFF000000u; return 0xFF000000u;
@@ -952,7 +941,7 @@ namespace jdi
return true; return true;
} }
void PlotView::InvalidatePolylineCache() void PlotView::InvalidateDerivedCaches()
{ {
m_polylineCache.clear(); m_polylineCache.clear();
// 数据层结构变化后边沿统计与中心平均值曲线的派生结果都会失效。 // 数据层结构变化后边沿统计与中心平均值曲线的派生结果都会失效。
@@ -2080,37 +2069,6 @@ namespace jdi
} }
} }
void PlotView::ScaleLaneRange(int laneIndex, double factor, double anchorValue)
{
if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_lanes.size()))
{
return;
}
if (!(factor > 0.0) || !std::isfinite(anchorValue))
{
return;
}
const LaneVisual& visual = m_lanes[static_cast<std::size_t>(laneIndex)];
const double span = visual.yMax - visual.yMin;
if (!(span > 0.0))
{
return;
}
const double magnitude = std::max(std::fabs(visual.yMax), std::fabs(visual.yMin));
const double minSpan = std::max(magnitude * 1.0e-9, 1.0e-12);
const double newSpan = ClampDouble(span / factor, minSpan, magnitude * 100.0 + 1.0);
const double ratio = (visual.yMax - anchorValue) / span;
Lane& lane = m_tab->Lanes()[static_cast<std::size_t>(laneIndex)];
lane.autoRange = false;
lane.fitYToSelection = false;
lane.yMin = anchorValue - ratio * newSpan;
lane.yMax = lane.yMin + newSpan;
BuildLaneVisuals();
}
void PlotView::ShiftLaneRange(int laneIndex, double deltaValue) void PlotView::ShiftLaneRange(int laneIndex, double deltaValue)
{ {
if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_lanes.size()) || if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_lanes.size()) ||
@@ -2135,27 +2093,6 @@ namespace jdi
BuildLaneVisuals(); BuildLaneVisuals();
} }
bool PlotView::BeginLaneValueEdit(int laneIndex, bool editMax, const gd::RectF& anchorRect)
{
if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_tab->Lanes().size()))
{
return false;
}
if (m_lanes.empty())
{
BuildLaneVisuals();
}
if (laneIndex >= static_cast<int>(m_lanes.size()))
{
return false;
}
const LaneVisual& visual = m_lanes[static_cast<std::size_t>(laneIndex)];
const double current = editMax ? visual.yMax : visual.yMin;
return BeginEdit(editMax ? PlotEditTarget::LANE_Y_MAX : PlotEditTarget::LANE_Y_MIN, laneIndex,
FormatValue(current), anchorRect);
}
bool PlotView::ApplyLaneValueText(int laneIndex, bool editMax, const std::wstring& text) bool PlotView::ApplyLaneValueText(int laneIndex, bool editMax, const std::wstring& text)
{ {
if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_tab->Lanes().size())) if (m_tab == nullptr || laneIndex < 0 || laneIndex >= static_cast<int>(m_tab->Lanes().size()))
@@ -3468,8 +3405,9 @@ namespace jdi
return changed; return changed;
} }
bool PlotView::OnLButtonUp(int x, int y) bool PlotView::OnLButtonUp(int y)
{ bool changed = (m_dragMode != PlotDragMode::NONE); {
bool changed = (m_dragMode != PlotDragMode::NONE);
switch (m_dragMode) switch (m_dragMode)
{ {
@@ -3528,11 +3466,10 @@ namespace jdi
m_edgePanelDragKind = EdgePanelKind::COUNT; m_edgePanelDragKind = EdgePanelKind::COUNT;
// 松开左键:粘滞提示结束计时,开始"停留后淡出"。 // 松开左键:粘滞提示结束计时,开始"停留后淡出"。
ReleaseHint(); ReleaseHint();
(void)x;
return changed; return changed;
} }
bool PlotView::OnMouseWheel(int x, int y, int delta, bool shift) bool PlotView::OnMouseWheel(int delta, bool shift)
{ {
if (!HasDrawableContent() || delta == 0) if (!HasDrawableContent() || delta == 0)
{ {
@@ -3559,8 +3496,6 @@ namespace jdi
Tab().LaneScroll() -= static_cast<float>(notches * 48.0 * m_scale); Tab().LaneScroll() -= static_cast<float>(notches * 48.0 * m_scale);
BuildLaneVisuals(); BuildLaneVisuals();
(void)x;
(void)y;
return true; return true;
} }
@@ -4125,7 +4060,7 @@ namespace jdi
g.DrawRectangle(&borderPen, m_plotRect.X, m_plotRect.Y, m_plotRect.Width, m_plotRect.Height); g.DrawRectangle(&borderPen, m_plotRect.X, m_plotRect.Y, m_plotRect.Width, m_plotRect.Height);
} }
void PlotView::PaintSignalHalo(gd::Graphics& g, const SignalRef& ref, const ResolvedSignal& resolved, void PlotView::PaintSignalHalo(gd::Graphics& g, const ResolvedSignal& resolved,
const std::vector<gd::PointF>& points, const std::vector<gd::PointF>& points,
const std::vector<std::size_t>& breaks) const std::vector<std::size_t>& breaks)
{ {
@@ -4133,8 +4068,6 @@ namespace jdi
if (!drawLine || breaks.empty()) if (!drawLine || breaks.empty())
{ {
// 散点模式没有光晕(原实现同样只对折线绘制光晕)。 // 散点模式没有光晕(原实现同样只对折线绘制光晕)。
(void)g;
(void)ref;
return; return;
} }
@@ -4194,7 +4127,7 @@ namespace jdi
const PolylineCacheEntry* cached = AcquirePolyline(m_hoverSignal, resolved, lane); const PolylineCacheEntry* cached = AcquirePolyline(m_hoverSignal, resolved, lane);
if (cached != nullptr) if (cached != nullptr)
{ {
PaintSignalHalo(g, m_hoverSignal, resolved, cached->points, cached->breaks); PaintSignalHalo(g, resolved, cached->points, cached->breaks);
} }
} }
} }
@@ -4534,7 +4467,7 @@ namespace jdi
return; return;
} }
const float textWidth = UiTextWidth(g, text, m_fonts->monoSmall) + 12.0f * m_scale; const float textWidth = UiMeasureTextWidth(m_fonts->monoSmall, text) + 12.0f * m_scale;
const float textHeight = 18.0f * m_scale; const float textHeight = 18.0f * m_scale;
float labelX = m_rubberRect.X + m_rubberRect.Width * 0.5f - textWidth * 0.5f; float labelX = m_rubberRect.X + m_rubberRect.Width * 0.5f - textWidth * 0.5f;
labelX = std::max(m_plotRect.X, std::min(labelX, m_plotRect.X + m_plotRect.Width - textWidth)); labelX = std::max(m_plotRect.X, std::min(labelX, m_plotRect.X + m_plotRect.Width - textWidth));
@@ -4568,7 +4501,7 @@ namespace jdi
// 提示条贴在绘图区底部居中;时间光标的时间读数也在底部, // 提示条贴在绘图区底部居中;时间光标的时间读数也在底部,
// 因此光标启用时把提示条上移一行,避免两者互相遮挡。 // 因此光标启用时把提示条上移一行,避免两者互相遮挡。
const float reserved = (m_tab != nullptr && Tab().CursorEnabled()) ? 26.0f * m_scale : 0.0f; const float reserved = (m_tab != nullptr && Tab().CursorEnabled()) ? 26.0f * m_scale : 0.0f;
const float width = UiTextWidth(g, m_hintText, m_fonts->ui) + 30.0f * m_scale; const float width = UiMeasureTextWidth(m_fonts->ui, m_hintText) + 30.0f * m_scale;
const float height = 30.0f * m_scale; const float height = 30.0f * m_scale;
float left = m_plotRect.X + (m_plotRect.Width - width) * 0.5f; float left = m_plotRect.X + (m_plotRect.Width - width) * 0.5f;
left = std::max(m_plotRect.X + 2.0f * m_scale, left = std::max(m_plotRect.X + 2.0f * m_scale,
@@ -4731,7 +4664,7 @@ namespace jdi
const bool highlighted = (ref == haloRef); const bool highlighted = (ref == haloRef);
if (highlighted) if (highlighted)
{ {
PaintSignalHalo(g, ref, resolved, points, breaks); PaintSignalHalo(g, resolved, points, breaks);
} }
if (drawLine && !breaks.empty()) if (drawLine && !breaks.empty())
@@ -4892,7 +4825,7 @@ namespace jdi
} }
UiFillRoundRect(g, pill, 3.0f * m_scale, WithAlpha(m_theme->cardBg, 0xF0)); UiFillRoundRect(g, pill, 3.0f * m_scale, WithAlpha(m_theme->cardBg, 0xF0));
const std::wstring text = UiEllipsize(g, raw, m_fonts->monoSmall, pill.Width - 6.0f * m_scale); const std::wstring text = UiEllipsize(raw, m_fonts->monoSmall, pill.Width - 6.0f * m_scale);
UiText(g, text, m_fonts->monoSmall, UiText(g, text, m_fonts->monoSmall,
gd::RectF(pill.X + 4.0f * m_scale, pill.Y, pill.Width - 8.0f * m_scale, pill.Height), gd::RectF(pill.X + 4.0f * m_scale, pill.Y, pill.Width - 8.0f * m_scale, pill.Height),
(tick == 0.0) ? m_theme->text : m_theme->textMuted, TextAlign::LEFT); (tick == 0.0) ? m_theme->text : m_theme->textMuted, TextAlign::LEFT);
@@ -4972,7 +4905,7 @@ namespace jdi
label += L" · " + resolved.file->Title(); label += L" · " + resolved.file->Title();
} }
const float itemWidth = kLegendSwatchSize * m_scale + 5.0f * m_scale + const float itemWidth = kLegendSwatchSize * m_scale + 5.0f * m_scale +
std::min(UiTextWidth(g, label, m_fonts->uiSmall), std::min(UiMeasureTextWidth(m_fonts->uiSmall, label),
kLegendMaxTextWidth * m_scale) + kLegendMaxTextWidth * m_scale) +
kLegendItemGap * m_scale; kLegendItemGap * m_scale;
if (cursorX + legendWidth + itemWidth > maxX) if (cursorX + legendWidth + itemWidth > maxX)
@@ -5027,10 +4960,10 @@ namespace jdi
} }
// 文本宽度按上限夹取,超出部分用省略号(与测量阶段保持一致)。 // 文本宽度按上限夹取,超出部分用省略号(与测量阶段保持一致)。
const float maxTextWidth = kLegendMaxTextWidth * m_scale; const float maxTextWidth = kLegendMaxTextWidth * m_scale;
const float fullTextWidth = UiTextWidth(g, label, m_fonts->uiSmall); const float fullTextWidth = UiMeasureTextWidth(m_fonts->uiSmall, label);
const float textWidth = std::min(fullTextWidth, maxTextWidth); const float textWidth = std::min(fullTextWidth, maxTextWidth);
const std::wstring drawLabel = const std::wstring drawLabel =
(fullTextWidth > maxTextWidth) ? UiEllipsize(g, label, m_fonts->uiSmall, maxTextWidth) : label; (fullTextWidth > maxTextWidth) ? UiEllipsize(label, m_fonts->uiSmall, maxTextWidth) : label;
const float itemWidth = kLegendSwatchSize * m_scale + 5.0f * m_scale + textWidth + const float itemWidth = kLegendSwatchSize * m_scale + 5.0f * m_scale + textWidth +
kLegendItemGap * m_scale; kLegendItemGap * m_scale;
if (drawnWidth + itemWidth > legendWidth + 0.5f) if (drawnWidth + itemWidth > legendWidth + 0.5f)
@@ -5114,7 +5047,7 @@ namespace jdi
{ {
for (std::size_t fileIndex = 0; fileIndex < m_dataSet->FileCount(); ++fileIndex) for (std::size_t fileIndex = 0; fileIndex < m_dataSet->FileCount(); ++fileIndex)
{ {
if (!m_tab->FileHasVisible(*m_dataSet, static_cast<int>(fileIndex))) if (!m_tab->FileHasVisible(static_cast<int>(fileIndex)))
{ {
continue; continue;
} }
@@ -5138,7 +5071,7 @@ namespace jdi
m_plotRect.Width * 0.4f); m_plotRect.Width * 0.4f);
const gd::RectF nameRect(m_plotRect.X + 2.0f * m_scale, axisY + 3.0f * m_scale, nameWidth, const gd::RectF nameRect(m_plotRect.X + 2.0f * m_scale, axisY + 3.0f * m_scale, nameWidth,
std::max(0.0f, m_timeAxisRect.Height - 5.0f * m_scale)); std::max(0.0f, m_timeAxisRect.Height - 5.0f * m_scale));
UiText(g, UiEllipsize(g, axisName, m_fonts->monoSmall, nameWidth), m_fonts->monoSmall, nameRect, UiText(g, UiEllipsize(axisName, m_fonts->monoSmall, nameWidth), m_fonts->monoSmall, nameRect,
m_theme->textMuted, TextAlign::LEFT); m_theme->textMuted, TextAlign::LEFT);
const float labelWidth = 96.0f * m_scale; const float labelWidth = 96.0f * m_scale;
@@ -5295,7 +5228,7 @@ namespace jdi
} }
const bool hot = (m_hoverCursor == which); const bool hot = (m_hoverCursor == which);
const std::uint32_t color = CursorColor(which); const std::uint32_t color = CursorColor();
const float lineTop = m_plotRect.Y; const float lineTop = m_plotRect.Y;
const float lineBottom = m_timeAxisRect.Y + m_timeAxisRect.Height; const float lineBottom = m_timeAxisRect.Y + m_timeAxisRect.Height;
UiDrawLine(g, x, lineTop, x, lineBottom, color, (hot ? 2.0f : 1.4f) * m_scale); UiDrawLine(g, x, lineTop, x, lineBottom, color, (hot ? 2.0f : 1.4f) * m_scale);
@@ -5346,7 +5279,7 @@ namespace jdi
const bool interpolate = (resolved.style->mode != DrawMode::SCATTER); const bool interpolate = (resolved.style->mode != DrawMode::SCATTER);
double value = 0.0; double value = 0.0;
if (!SampleFileAt(*resolved.file, *resolved.data, time, interpolate, value)) if (!SampleSignalAt(*resolved.file, *resolved.data, time, interpolate, value))
{ {
continue; continue;
} }
@@ -5368,7 +5301,7 @@ namespace jdi
if (showDelta) if (showDelta)
{ {
double otherValue = 0.0; double otherValue = 0.0;
if (SampleFileAt(*resolved.file, *resolved.data, otherTime, interpolate, otherValue)) if (SampleSignalAt(*resolved.file, *resolved.data, otherTime, interpolate, otherValue))
{ {
const double delta = value - otherValue; const double delta = value - otherValue;
// 增量 = 右侧光标取值 − 左侧光标取值,包在圆括号里并按差值显式给出正负号。 // 增量 = 右侧光标取值 − 左侧光标取值,包在圆括号里并按差值显式给出正负号。
@@ -5379,7 +5312,7 @@ namespace jdi
} }
} }
const float textWidth = UiTextWidth(g, text, m_fonts->monoSmall) + 10.0f * m_scale; const float textWidth = UiMeasureTextWidth(m_fonts->monoSmall, text) + 10.0f * m_scale;
const float textHeight = 17.0f * m_scale; const float textHeight = 17.0f * m_scale;
float labelLeft = pinX + radius + 4.0f * m_scale; float labelLeft = pinX + radius + 4.0f * m_scale;
if (labelLeft + textWidth > m_plotRect.X + m_plotRect.Width - 2.0f * m_scale) if (labelLeft + textWidth > m_plotRect.X + m_plotRect.Width - 2.0f * m_scale)
@@ -5454,7 +5387,7 @@ namespace jdi
centerText += L")"; centerText += L")";
const float centerTextWidth = const float centerTextWidth =
UiTextWidth(g, centerText, m_fonts->monoSmall) + 10.0f * m_scale; UiMeasureTextWidth(m_fonts->monoSmall, centerText) + 10.0f * m_scale;
float centerLeft = pinX + radius + 4.0f * m_scale; float centerLeft = pinX + radius + 4.0f * m_scale;
if (centerLeft + centerTextWidth > if (centerLeft + centerTextWidth >
m_plotRect.X + m_plotRect.Width - 2.0f * m_scale) m_plotRect.X + m_plotRect.Width - 2.0f * m_scale)
@@ -5507,7 +5440,7 @@ namespace jdi
continue; continue;
} }
const bool highlighted = (m_cursorHover && m_hoverCursor == which); const bool highlighted = (m_cursorHover && m_hoverCursor == which);
const std::uint32_t color = CursorColor(which); const std::uint32_t color = CursorColor();
UiFillRoundRect(g, labelRect, 3.0f * m_scale, UiFillRoundRect(g, labelRect, 3.0f * m_scale,
highlighted ? color : WithAlpha(color, 0xE0)); highlighted ? color : WithAlpha(color, 0xE0));
const bool dark = IsDarkColor(color); const bool dark = IsDarkColor(color);
@@ -5526,7 +5459,7 @@ namespace jdi
if (spanRect.Width > 0.0f && spanRect.Height > 0.0f) if (spanRect.Width > 0.0f && spanRect.Height > 0.0f)
{ {
// 样式与光标时间读数完全一致(同底色/同描边/同文字配色)。 // 样式与光标时间读数完全一致(同底色/同描边/同文字配色)。
const std::uint32_t color = CursorColor(1); const std::uint32_t color = CursorColor();
UiFillRoundRect(g, spanRect, 3.0f * m_scale, UiFillRoundRect(g, spanRect, 3.0f * m_scale,
m_spanHover ? color : WithAlpha(color, 0xE0)); m_spanHover ? color : WithAlpha(color, 0xE0));
const bool dark = IsDarkColor(color); const bool dark = IsDarkColor(color);
@@ -5628,21 +5561,6 @@ namespace jdi
return layout; return layout;
} }
gd::RectF PlotView::EdgePanelRect(int laneIndex) const
{
return EdgePanelLayoutFor(laneIndex, EdgePanelKind::COUNT).panel;
}
gd::RectF PlotView::EdgePanelCloseRect(int laneIndex) const
{
return EdgePanelLayoutFor(laneIndex, EdgePanelKind::COUNT).close;
}
gd::RectF PlotView::EdgeCenterPanelRect(int laneIndex) const
{
return EdgePanelLayoutFor(laneIndex, EdgePanelKind::CENTER).panel;
}
bool PlotView::IsOnEdgeCursorLine(int x, int y, int& laneIndex) const bool PlotView::IsOnEdgeCursorLine(int x, int y, int& laneIndex) const
{ {
laneIndex = -1; laneIndex = -1;
@@ -5934,7 +5852,7 @@ namespace jdi
std::vector<Lane>& tabLanes = m_tab->Lanes(); std::vector<Lane>& tabLanes = m_tab->Lanes();
const std::size_t count = std::min(lanes.size(), tabLanes.size()); const std::size_t count = std::min(lanes.size(), tabLanes.size());
const std::uint32_t color = CursorColor(1); const std::uint32_t color = CursorColor();
const bool dark = IsDarkColor(color); const bool dark = IsDarkColor(color);
// ---- 横向光标(线与两端把手 + 左侧幅值读数)---- // ---- 横向光标(线与两端把手 + 左侧幅值读数)----
@@ -6334,7 +6252,7 @@ namespace jdi
? std::wstring(L"松开左键放回本网格") ? std::wstring(L"松开左键放回本网格")
: (L"移动到网格 " + std::to_wstring(target + 1) + : (L"移动到网格 " + std::to_wstring(target + 1) +
L":松开左键确认"); L":松开左键确认");
const float textWidth = UiTextWidth(g, hint, m_fonts->uiSmall) + 16.0f * m_scale; const float textWidth = UiMeasureTextWidth(m_fonts->uiSmall, hint) + 16.0f * m_scale;
const float height = 20.0f * m_scale; const float height = 20.0f * m_scale;
float left = targetRect.X + (targetRect.Width - textWidth) * 0.5f; float left = targetRect.X + (targetRect.Width - textWidth) * 0.5f;
left = std::max(m_plotRect.X, std::min(left, m_plotRect.X + m_plotRect.Width - textWidth)); left = std::max(m_plotRect.X, std::min(left, m_plotRect.X + m_plotRect.Width - textWidth));
@@ -6373,7 +6291,7 @@ namespace jdi
const std::wstring text = resolved.data->Title() + L" · 按住拖拽可移入其它网格"; const std::wstring text = resolved.data->Title() + L" · 按住拖拽可移入其它网格";
// 提示跟随鼠标:在可拖拽区域内持续移动时,提示条也要跟着走。 // 提示跟随鼠标:在可拖拽区域内持续移动时,提示条也要跟着走。
const float textWidth = UiTextWidth(g, text, m_fonts->uiSmall) + 16.0f * m_scale; const float textWidth = UiMeasureTextWidth(m_fonts->uiSmall, text) + 16.0f * m_scale;
const float height = 20.0f * m_scale; const float height = 20.0f * m_scale;
float left = static_cast<float>(m_mouseX) + 12.0f * m_scale; float left = static_cast<float>(m_mouseX) + 12.0f * m_scale;
if (left + textWidth > m_plotRect.X + m_plotRect.Width) if (left + textWidth > m_plotRect.X + m_plotRect.Width)
@@ -78,12 +78,6 @@ namespace jdi
*/ */
void InvalidateRows() { m_rowsDirty = true; } void InvalidateRows() { m_rowsDirty = true; }
/**
* @brief 判断列表内容是否需要纵向滚动。
* @return 内容超出可视区域返回 true。
*/
bool NeedsScrollBar() const { return m_contentHeight > m_listRect.Height + 0.5f; }
/** /**
* @brief 设置 DPI 缩放比例。 * @brief 设置 DPI 缩放比例。
* @param [IN] scale 缩放比例(1.0 对应 96 DPI)。 * @param [IN] scale 缩放比例(1.0 对应 96 DPI)。
@@ -187,18 +181,6 @@ namespace jdi
*/ */
bool EndFilterEdit(); bool EndFilterEdit();
/**
* @brief 筛选框是否处于编辑状态。
* @return 编辑中返回 true。
*/
bool IsFilterEditing() const { return m_filterEditing; }
/**
* @brief 获取当前筛选文本。
* @return 筛选文本(未输入时为空串)。
*/
const std::wstring& FilterText() const { return m_filterText; }
/** /**
* @brief 向当前输入框送入一个字符。 * @brief 向当前输入框送入一个字符。
* @param [IN] character 输入字符('\r' 提交、'\b' 退格、0x03 复制)。 * @param [IN] character 输入字符('\r' 提交、'\b' 退格、0x03 复制)。
@@ -385,12 +367,6 @@ namespace jdi
*/ */
void RefreshScrollBar(); void RefreshScrollBar();
/**
* @brief 计算列表内容总高度。
* @return 内容高度(像素)。
*/
float ContentHeight() const;
/** /**
* @brief 限制滚动偏移量到合法范围。 * @brief 限制滚动偏移量到合法范围。
*/ */
+18 -22
View File
@@ -419,11 +419,6 @@ namespace jdi
ClampScroll(); ClampScroll();
} }
float SignalPanel::ContentHeight() const
{
return m_contentHeight;
}
void SignalPanel::ClampScroll() void SignalPanel::ClampScroll()
{ {
const float maxOffset = std::max(0.0f, m_contentHeight - m_listRect.Height); const float maxOffset = std::max(0.0f, m_contentHeight - m_listRect.Height);
@@ -732,7 +727,7 @@ namespace jdi
std::max(20.0f, m_headerRect.Width - kPadding * 2.0f * m_scale - std::max(20.0f, m_headerRect.Width - kPadding * 2.0f * m_scale -
m_toggleAllRect.Width - 8.0f * m_scale), m_toggleAllRect.Width - 8.0f * m_scale),
m_headerRect.Height); m_headerRect.Height);
UiText(g, UiEllipsize(g, title, m_fonts->uiBold, titleRect.Width), m_fonts->uiBold, titleRect, UiText(g, UiEllipsize(title, m_fonts->uiBold, titleRect.Width), m_fonts->uiBold, titleRect,
m_theme->textStrong, TextAlign::LEFT); m_theme->textStrong, TextAlign::LEFT);
const bool allVisible = AreAllSignalsVisible(); const bool allVisible = AreAllSignalsVisible();
@@ -775,7 +770,7 @@ namespace jdi
} }
else else
{ {
UiText(g, UiEllipsize(g, m_filterText, m_fonts->uiSmall, textWidth), m_fonts->uiSmall, UiText(g, UiEllipsize(m_filterText, m_fonts->uiSmall, textWidth), m_fonts->uiSmall,
textRect, m_theme->text, TextAlign::LEFT); textRect, m_theme->text, TextAlign::LEFT);
} }
@@ -894,8 +889,8 @@ namespace jdi
// 分组复选框(三态:全选 / 部分 / 未选)。 // 分组复选框(三态:全选 / 部分 / 未选)。
const gd::RectF checkRect(baseX + kDisclosureWidth * m_scale, centerY - kCheckSize * m_scale * 0.5f, const gd::RectF checkRect(baseX + kDisclosureWidth * m_scale, centerY - kCheckSize * m_scale * 0.5f,
kCheckSize * m_scale, kCheckSize * m_scale); kCheckSize * m_scale, kCheckSize * m_scale);
const bool allVisible = m_tab->FileAllVisible(*m_dataSet, item.fileIndex); const bool allVisible = m_tab->FileAllVisible(item.fileIndex);
const bool anyVisible = m_tab->FileHasVisible(*m_dataSet, item.fileIndex); const bool anyVisible = m_tab->FileHasVisible(item.fileIndex);
UiDrawCheckBox(g, checkRect, allVisible ? 1 : (anyVisible ? 2 : 0), 3.0f * m_scale); UiDrawCheckBox(g, checkRect, allVisible ? 1 : (anyVisible ? 2 : 0), 3.0f * m_scale);
const gd::RectF closeRect = FileCloseRect(row); const gd::RectF closeRect = FileCloseRect(row);
@@ -928,7 +923,7 @@ namespace jdi
} }
else else
{ {
UiText(g, UiEllipsize(g, file->Title(), m_fonts->uiBold, nameWidth), m_fonts->uiBold, UiText(g, UiEllipsize(file->Title(), m_fonts->uiBold, nameWidth), m_fonts->uiBold,
gd::RectF(nameAreaLeft, rect.Y, nameWidth, rect.Height), m_theme->textStrong, gd::RectF(nameAreaLeft, rect.Y, nameWidth, rect.Height), m_theme->textStrong,
TextAlign::LEFT); TextAlign::LEFT);
} }
@@ -1013,7 +1008,7 @@ namespace jdi
{ {
const float nameWidth = std::max(16.0f, nameRightLimit - nameLeft); const float nameWidth = std::max(16.0f, nameRightLimit - nameLeft);
const std::uint32_t nameColor = visible ? m_theme->text : m_theme->textMuted; const std::uint32_t nameColor = visible ? m_theme->text : m_theme->textMuted;
UiText(g, UiEllipsize(g, signal->Title(), m_fonts->ui, nameWidth), m_fonts->ui, UiText(g, UiEllipsize(signal->Title(), m_fonts->ui, nameWidth), m_fonts->ui,
gd::RectF(nameLeft, rect.Y, nameWidth, rect.Height), nameColor, TextAlign::LEFT); gd::RectF(nameLeft, rect.Y, nameWidth, rect.Height), nameColor, TextAlign::LEFT);
} }
@@ -1201,7 +1196,8 @@ namespace jdi
const std::wstring fullText = numberText + L" px"; const std::wstring fullText = numberText + L" px";
// 空间不足时省略单位,保证数值本身完整可读。 // 空间不足时省略单位,保证数值本身完整可读。
const std::wstring shown = const std::wstring shown =
(UiTextWidth(g, fullText, m_fonts->monoSmall) > m_widthValueRect.Width - 6.0f * m_scale) (UiMeasureTextWidth(m_fonts->monoSmall, fullText) >
m_widthValueRect.Width - 6.0f * m_scale)
? numberText ? numberText
: fullText; : fullText;
UiText(g, shown, m_fonts->monoSmall, m_widthValueRect, m_theme->textStrong, TextAlign::RIGHT); UiText(g, shown, m_fonts->monoSmall, m_widthValueRect, m_theme->textStrong, TextAlign::RIGHT);
@@ -1996,7 +1992,7 @@ namespace jdi
// 全部显示/隐藏。 // 全部显示/隐藏。
if (UiPointInRect(m_toggleAllRect, fx, fy)) if (UiPointInRect(m_toggleAllRect, fx, fy))
{ {
m_tab->SetAllVisible(*m_dataSet, !AreAllSignalsVisible()); m_tab->SetAllVisible(!AreAllSignalsVisible());
m_rowsDirty = true; m_rowsDirty = true;
return true; return true;
} }
@@ -2066,8 +2062,8 @@ namespace jdi
{ {
if (part == RowPart::CHECK) if (part == RowPart::CHECK)
{ {
const bool allVisible = m_tab->FileAllVisible(*m_dataSet, item.fileIndex); const bool allVisible = m_tab->FileAllVisible(item.fileIndex);
m_tab->SetFileVisible(*m_dataSet, item.fileIndex, !allVisible); m_tab->SetFileVisible(item.fileIndex, !allVisible);
m_rowsDirty = true; m_rowsDirty = true;
return true; return true;
} }
@@ -2091,7 +2087,7 @@ namespace jdi
if (part == RowPart::CHECK) if (part == RowPart::CHECK)
{ {
// 勾选/取消勾选会立即触发网格重新划分(取消后空网格随之消失)。 // 勾选/取消勾选会立即触发网格重新划分(取消后空网格随之消失)。
m_tab->ToggleVisible(*m_dataSet, ref); m_tab->ToggleVisible(ref);
m_rowsDirty = true; m_rowsDirty = true;
} }
else if (part == RowPart::LANE_BADGE) else if (part == RowPart::LANE_BADGE)
@@ -2462,7 +2458,7 @@ namespace jdi
case CMD_SIGNAL_TOGGLE: case CMD_SIGNAL_TOGGLE:
if (m_menuTargetSignal.IsValid()) if (m_menuTargetSignal.IsValid())
{ {
m_tab->ToggleVisible(*m_dataSet, m_menuTargetSignal); m_tab->ToggleVisible(m_menuTargetSignal);
m_rowsDirty = true; m_rowsDirty = true;
needRelayout = true; needRelayout = true;
} }
@@ -2470,25 +2466,25 @@ namespace jdi
case CMD_SIGNAL_SOLO: case CMD_SIGNAL_SOLO:
if (m_menuTargetSignal.IsValid()) if (m_menuTargetSignal.IsValid())
{ {
m_tab->SoloSignal(*m_dataSet, m_menuTargetSignal); m_tab->SoloSignal(m_menuTargetSignal);
m_rowsDirty = true; m_rowsDirty = true;
needRelayout = true; needRelayout = true;
} }
break; break;
case CMD_SIGNAL_SHOW_ALL: case CMD_SIGNAL_SHOW_ALL:
m_tab->SetAllVisible(*m_dataSet, true); m_tab->SetAllVisible(true);
m_rowsDirty = true; m_rowsDirty = true;
needRelayout = true; needRelayout = true;
break; break;
case CMD_SIGNAL_HIDE_ALL: case CMD_SIGNAL_HIDE_ALL:
m_tab->SetAllVisible(*m_dataSet, false); m_tab->SetAllVisible(false);
m_rowsDirty = true; m_rowsDirty = true;
needRelayout = true; needRelayout = true;
break; break;
case CMD_FILE_SHOW_ALL: case CMD_FILE_SHOW_ALL:
if (m_menuTargetFile >= 0) if (m_menuTargetFile >= 0)
{ {
m_tab->SetFileVisible(*m_dataSet, m_menuTargetFile, true); m_tab->SetFileVisible(m_menuTargetFile, true);
m_rowsDirty = true; m_rowsDirty = true;
needRelayout = true; needRelayout = true;
} }
@@ -2496,7 +2492,7 @@ namespace jdi
case CMD_FILE_HIDE_ALL: case CMD_FILE_HIDE_ALL:
if (m_menuTargetFile >= 0) if (m_menuTargetFile >= 0)
{ {
m_tab->SetFileVisible(*m_dataSet, m_menuTargetFile, false); m_tab->SetFileVisible(m_menuTargetFile, false);
m_rowsDirty = true; m_rowsDirty = true;
needRelayout = true; needRelayout = true;
} }
-6
View File
@@ -197,12 +197,6 @@ namespace jdi
*/ */
int DropIndexAt(int x) const; int DropIndexAt(int x) const;
/**
* @brief 判断是否正在拖动标签页。
* @return 正在拖动返回 true。
*/
bool IsDragging() const { return m_dragIndex >= 0; }
/** /**
* @brief 处理鼠标离开标签栏。 * @brief 处理鼠标离开标签栏。
* @return 视觉状态发生变化返回 true。 * @return 视觉状态发生变化返回 true。
+1 -1
View File
@@ -180,7 +180,7 @@ namespace jdi
} }
else else
{ {
const std::wstring label = UiEllipsize(g, tab.name, m_fonts->ui, std::max(8.0f, textWidth)); const std::wstring label = UiEllipsize(tab.name, m_fonts->ui, std::max(8.0f, textWidth));
UiText(g, label, active ? m_fonts->uiBold : m_fonts->ui, UiText(g, label, active ? m_fonts->uiBold : m_fonts->ui,
gd::RectF(textLeft, tab.rect.Y, std::max(8.0f, textWidth), tab.rect.Height), gd::RectF(textLeft, tab.rect.Y, std::max(8.0f, textWidth), tab.rect.Height),
active ? m_theme->textStrong : m_theme->text, TextAlign::LEFT); active ? m_theme->textStrong : m_theme->text, TextAlign::LEFT);
+1 -3
View File
@@ -23,9 +23,7 @@ namespace jdi
std::vector<std::vector<double>> columns; /**< 列优先数值矩阵:columns[列][行],缺失处为 NaN。 */ std::vector<std::vector<double>> columns; /**< 列优先数值矩阵:columns[列][行],缺失处为 NaN。 */
std::size_t rowCount = 0; /**< 有效数据行数。 */ std::size_t rowCount = 0; /**< 有效数据行数。 */
wchar_t delimiter = L','; /**< 实际使用的分隔符。 */ wchar_t delimiter = L','; /**< 实际使用的分隔符。 */
std::size_t sourceRowCount = 0; /**< 文件中有效数据行数(不含空行与注释行)。 */ unsigned long long fileBytes = 0; /**< 源文件字节数(用于按比例预留容量)。 */
std::size_t skippedRowCount = 0; /**< 因格式异常被置为缺失值的行数。 */
unsigned long long fileBytes = 0; /**< 源文件字节数(用于按比例预留容量与进度显示)。 */
/** /**
* @brief 判断解析结果是否包含可用的表格数据。 * @brief 判断解析结果是否包含可用的表格数据。
+17 -37
View File
@@ -189,28 +189,13 @@ namespace jdi
class DataSet class DataSet
{ {
public: public:
/**
* @brief 清空全部已加载文件。
*/
void Clear();
/**
* @brief 依据 CSV 解析结果追加一个数据文件。
* @param [IN] table CSV 解析结果。
* @param [IN] filePath 源文件路径。
* @param [OUT] error 失败原因描述(成功时清空)。
* @param [OUT] fileIndex 新文件下标,失败时为 -1。
* @return 追加成功返回 true。
*/
bool AddFromTable(const CsvTable& table, const std::wstring& filePath, std::wstring& error, int& fileIndex);
/** /**
* @brief 追加一个已构建好的数据文件(仅做一次移动,不拷贝采样数据)。 * @brief 追加一个已构建好的数据文件(仅做一次移动,不拷贝采样数据)。
* @param [IN,OUT] file 数据文件(内部缓冲会被移走)。 * @param [IN,OUT] file 数据文件(内部缓冲会被移走)。
* @param [OUT] fileIndex 新文件下标。 * @param [OUT] fileIndex 新文件下标。
* @return 追加成功返回 true。 * @return 追加成功返回 true。
*/ */
bool AddPreparedFile(DataFile&& file, int& fileIndex); bool AddDataFile(DataFile&& file, int& fileIndex);
/** /**
* @brief 在指定文件的指定信号**下方**插入一条新信号(派生信号)。 * @brief 在指定文件的指定信号**下方**插入一条新信号(派生信号)。
@@ -431,15 +416,19 @@ namespace jdi
}; };
/** /**
* @brief 计算某条信号在给定时刻的取值。 * @brief 从内存中的信号采样点取某一时刻的取值。
* @param [IN] file 信号所属文件。 *
* 加载完成后全部采样值已在内存中,本函数只查询内存数据,与源文件无关。
*
* @param [IN] file 信号所属的已加载数据分组(提供时间轴)。
* @param [IN] signal 目标信号。 * @param [IN] signal 目标信号。
* @param [IN] time 采样时刻。 * @param [IN] time 采样时刻。
* @param [IN] interpolate 是否在相邻采样点之间做线性插值。 * @param [IN] interpolate 是否在相邻采样点之间做线性插值。
* @param [OUT] value 输出采样值,缺失时为 NaN。 * @param [OUT] value 输出采样值,缺失时为 NaN。
* @return 时间点落在数据范围内且取到有效值返回 true。 * @return 时间点落在数据范围内且取到有效值返回 true。
*/ */
bool SampleFileAt(const DataFile& file, const SignalData& signal, double time, bool interpolate, double& value); bool SampleSignalAt(const DataFile& file, const SignalData& signal, double time, bool interpolate,
double& value);
/** /**
* @brief 计算 N 点滑动平均(窗口 = [i-N, i+N],边界按实际窗口长度)。 * @brief 计算 N 点滑动平均(窗口 = [i-N, i+N],边界按实际窗口长度)。
@@ -506,56 +495,49 @@ namespace jdi
/** /**
* @brief 设置指定信号的可见性,并同步网格划分。 * @brief 设置指定信号的可见性,并同步网格划分。
* @param [IN] dataSet 数据集合。
* @param [IN] ref 信号引用。 * @param [IN] ref 信号引用。
* @param [IN] visible 目标可见状态。 * @param [IN] visible 目标可见状态。
*/ */
void SetVisible(const DataSet& dataSet, const SignalRef& ref, bool visible); void SetVisible(const SignalRef& ref, bool visible);
/** /**
* @brief 切换指定信号的可见性,并同步网格划分。 * @brief 切换指定信号的可见性,并同步网格划分。
* @param [IN] dataSet 数据集合。
* @param [IN] ref 信号引用。 * @param [IN] ref 信号引用。
*/ */
void ToggleVisible(const DataSet& dataSet, const SignalRef& ref); void ToggleVisible(const SignalRef& ref);
/** /**
* @brief 设置某个文件全部信号的可见性,并同步网格划分。 * @brief 设置某个文件全部信号的可见性,并同步网格划分。
* @param [IN] dataSet 数据集合。
* @param [IN] fileIndex 文件下标。 * @param [IN] fileIndex 文件下标。
* @param [IN] visible 目标可见状态。 * @param [IN] visible 目标可见状态。
*/ */
void SetFileVisible(const DataSet& dataSet, int fileIndex, bool visible); void SetFileVisible(int fileIndex, bool visible);
/** /**
* @brief 设置全部信号可见性,并同步网格划分。 * @brief 设置全部信号可见性,并同步网格划分。
* @param [IN] dataSet 数据集合。
* @param [IN] visible 目标可见状态。 * @param [IN] visible 目标可见状态。
*/ */
void SetAllVisible(const DataSet& dataSet, bool visible); void SetAllVisible(bool visible);
/** /**
* @brief 仅显示指定信号,其余全部隐藏。 * @brief 仅显示指定信号,其余全部隐藏。
* @param [IN] dataSet 数据集合。
* @param [IN] ref 需要保持可见的信号。 * @param [IN] ref 需要保持可见的信号。
*/ */
void SoloSignal(const DataSet& dataSet, const SignalRef& ref); void SoloSignal(const SignalRef& ref);
/** /**
* @brief 判断某文件是否存在可见信号。 * @brief 判断某文件是否存在可见信号。
* @param [IN] dataSet 数据集合。
* @param [IN] fileIndex 文件下标。 * @param [IN] fileIndex 文件下标。
* @return 存在可见信号返回 true。 * @return 存在可见信号返回 true。
*/ */
bool FileHasVisible(const DataSet& dataSet, int fileIndex) const; bool FileHasVisible(int fileIndex) const;
/** /**
* @brief 判断某文件是否全部信号可见。 * @brief 判断某文件是否全部信号可见。
* @param [IN] dataSet 数据集合。
* @param [IN] fileIndex 文件下标。 * @param [IN] fileIndex 文件下标。
* @return 全部可见且至少有一条信号返回 true。 * @return 全部可见且至少有一条信号返回 true。
*/ */
bool FileAllVisible(const DataSet& dataSet, int fileIndex) const; bool FileAllVisible(int fileIndex) const;
/** /**
* @brief 判断是否存在任何可见信号。 * @brief 判断是否存在任何可见信号。
@@ -577,16 +559,14 @@ namespace jdi
/** /**
* @brief 设置网格划分策略并同步网格。 * @brief 设置网格划分策略并同步网格。
* @param [IN] dataSet 数据集合。
* @param [IN] mode 目标策略。 * @param [IN] mode 目标策略。
*/ */
void SetMode(const DataSet& dataSet, LaneMode mode); void SetMode(LaneMode mode);
/** /**
* @brief 依据当前可见性与策略重新生成网格划分。 * @brief 依据当前可见性与策略重新生成网格划分。
* @param [IN] dataSet 数据集合。
*/ */
void SyncLanes(const DataSet& dataSet); void SyncLanes();
/** /**
* @brief 获取网格集合(只读)。 * @brief 获取网格集合(只读)。
+2 -12
View File
@@ -137,15 +137,6 @@ namespace jdi
void UiText(gd::Graphics& g, const std::wstring& text, HFONT font, const gd::RectF& rect, std::uint32_t argb, void UiText(gd::Graphics& g, const std::wstring& text, HFONT font, const gd::RectF& rect, std::uint32_t argb,
TextAlign align = TextAlign::LEFT); TextAlign align = TextAlign::LEFT);
/**
* @brief 测量单行文本的像素宽度。
* @param [IN,OUT] g 绘图上下文。
* @param [IN] text 文本内容。
* @param [IN] font 字体句柄。
* @return 文本像素宽度。
*/
float UiTextWidth(gd::Graphics& g, const std::wstring& text, HFONT font);
/** /**
* @brief 测量单行文本的像素宽度(无需 GDI+ 上下文,可在布局阶段调用)。 * @brief 测量单行文本的像素宽度(无需 GDI+ 上下文,可在布局阶段调用)。
* @param [IN] font 字体句柄。 * @param [IN] font 字体句柄。
@@ -193,14 +184,13 @@ namespace jdi
std::size_t UiEditOffsetAt(HFONT font, const std::wstring& text, float localX); std::size_t UiEditOffsetAt(HFONT font, const std::wstring& text, float localX);
/** /**
* @brief 在超出可用宽度时对文本做尾部省略截断。 * @brief 在超出可用宽度时对文本做尾部省略截断(不绘制任何内容)。
* @param [IN,OUT] g 绘图上下文。
* @param [IN] text 原始文本。 * @param [IN] text 原始文本。
* @param [IN] font 字体句柄。 * @param [IN] font 字体句柄。
* @param [IN] maxWidth 允许的最大像素宽度。 * @param [IN] maxWidth 允许的最大像素宽度。
* @return 截断后的文本。 * @return 截断后的文本。
*/ */
std::wstring UiEllipsize(gd::Graphics& g, const std::wstring& text, HFONT font, float maxWidth); std::wstring UiEllipsize(const std::wstring& text, HFONT font, float maxWidth);
/** /**
* @brief 处理输入框内的鼠标按下:命中则把插入符定位到最近的字符边界并开始拖拽框选。 * @brief 处理输入框内的鼠标按下:命中则把插入符定位到最近的字符边界并开始拖拽框选。
-6
View File
@@ -183,12 +183,6 @@ namespace jdi
*/ */
bool IsEditing() const { return m_editIndex >= 0; } bool IsEditing() const { return m_editIndex >= 0; }
/**
* @brief 获取当前正在编辑的菜单项命令标识。
* @return 命令标识,未编辑时返回 0。
*/
int EditingItemId() const;
/** /**
* @brief 判断坐标是否落在当前正在编辑的输入框内。 * @brief 判断坐标是否落在当前正在编辑的输入框内。
* @param [IN] x 客户区横坐标。 * @param [IN] x 客户区横坐标。
-7
View File
@@ -144,13 +144,6 @@ namespace jdi
*/ */
bool DeselectToEnd(); bool DeselectToEnd();
/**
* @brief 把插入符定位到指定偏移(单击输入框内时使用),并清除选区。
* @param [IN] offset 目标偏移(内部会夹到合法范围)。
* @return 光标或选区发生变化返回 true。
*/
bool PlaceCaret(std::size_t offset);
/** /**
* @brief 开始鼠标拖拽框选:把锚点与插入符都放在给定偏移。 * @brief 开始鼠标拖拽框选:把锚点与插入符都放在给定偏移。
* @param [IN] offset 起始偏移。 * @param [IN] offset 起始偏移。
-6
View File
@@ -121,12 +121,6 @@ namespace jdi
*/ */
const std::uint32_t* SignalPalette(int& count); const std::uint32_t* SignalPalette(int& count);
/**
* @brief 获取波形默认配色数量。
* @return 配色数量。
*/
int SignalColorCount();
} // namespace jdi } // namespace jdi
#endif // __THEME_HPP__ #endif // __THEME_HPP__
-15
View File
@@ -18,13 +18,6 @@ namespace jdi
*/ */
std::wstring Utf8ToWide(const char* text, int length = -1); std::wstring Utf8ToWide(const char* text, int length = -1);
/**
* @brief 将宽字符串(UTF-16LE)转换为 UTF-8 编码的字节序列。
* @param [IN] text 宽字符文本起始地址。
* @return 转换后的 UTF-8 字符串,输入非法时返回空字符串。
*/
std::string WideToUtf8(const wchar_t* text);
/** /**
* @brief 去除字符串首尾的空白字符(含制表、换行与不间断空格)。 * @brief 去除字符串首尾的空白字符(含制表、换行与不间断空格)。
* @param [IN] text 待处理文本。 * @param [IN] text 待处理文本。
@@ -46,14 +39,6 @@ namespace jdi
*/ */
std::wstring ToLowerAscii(const std::wstring& text); std::wstring ToLowerAscii(const std::wstring& text);
/**
* @brief 判断字符串是否以指定前缀开头。
* @param [IN] text 被检索文本。
* @param [IN] prefix 前缀文本。
* @return 以该前缀开头返回 true,否则返回 false。
*/
bool StartsWith(const std::wstring& text, const std::wstring& prefix);
/** /**
* @brief 判断字符串是否包含指定子串(ASCII 大小写不敏感)。 * @brief 判断字符串是否包含指定子串(ASCII 大小写不敏感)。
* @param [IN] text 被检索文本。 * @param [IN] text 被检索文本。
-6
View File
@@ -303,11 +303,6 @@ namespace jdi
return true; return true;
} }
if (state.fields.size() != table.headers.size())
{
++table.skippedRowCount;
}
bool rowHasValue = false; bool rowHasValue = false;
for (std::size_t column = 0; column < state.rowValues.size(); ++column) for (std::size_t column = 0; column < state.rowValues.size(); ++column)
{ {
@@ -332,7 +327,6 @@ namespace jdi
table.columns[column].push_back(state.rowValues[column]); table.columns[column].push_back(state.rowValues[column]);
} }
++table.rowCount; ++table.rowCount;
++table.sourceRowCount;
return true; return true;
} }
} }
+19 -43
View File
@@ -464,7 +464,6 @@ namespace jdi
} }
const std::size_t columnCount = table.headers.size(); const std::size_t columnCount = table.headers.size();
const std::size_t rowCount = table.rowCount;
if (table.columns.size() < columnCount) if (table.columns.size() < columnCount)
{ {
error = L"数据表列结构不完整。"; error = L"数据表列结构不完整。";
@@ -599,18 +598,12 @@ namespace jdi
} }
file.minTime = tMin; file.minTime = tMin;
file.maxTime = tMax; file.maxTime = tMax;
(void)rowCount;
return true; return true;
} }
// ============================ DataSet ============================ // ============================ DataSet ============================
void DataSet::Clear() bool DataSet::AddDataFile(DataFile&& file, int& fileIndex)
{
m_files.clear();
}
bool DataSet::AddPreparedFile(DataFile&& file, int& fileIndex)
{ {
fileIndex = -1; fileIndex = -1;
if (file.signals.empty()) if (file.signals.empty())
@@ -622,21 +615,6 @@ namespace jdi
return true; return true;
} }
bool DataSet::AddFromTable(const CsvTable& table, const std::wstring& filePath, std::wstring& error,
int& fileIndex)
{
fileIndex = -1;
// 兼容入口:复制一份表格后走与后台加载完全一致的构建流程。
CsvTable local = table;
DataFile file;
if (!BuildDataFile(std::move(local), filePath, SignalCount(), file, error))
{
return false;
}
return AddPreparedFile(std::move(file), fileIndex);
}
bool DataSet::InsertDerivedSignal(int fileIndex, int afterSignalIndex, SignalData&& signal, bool DataSet::InsertDerivedSignal(int fileIndex, int afterSignalIndex, SignalData&& signal,
int& newSignalIndex) int& newSignalIndex)
{ {
@@ -992,7 +970,8 @@ namespace jdi
return best; return best;
} }
bool SampleFileAt(const DataFile& file, const SignalData& signal, double time, bool interpolate, double& value) bool SampleSignalAt(const DataFile& file, const SignalData& signal, double time, bool interpolate,
double& value)
{ {
value = kMissing; value = kMissing;
@@ -1093,7 +1072,7 @@ namespace jdi
[](const Lane& lane) { return lane.signals.empty(); }), [](const Lane& lane) { return lane.signals.empty(); }),
m_lanes.end()); m_lanes.end());
SyncLanes(dataSet); SyncLanes();
} }
void TabConfig::RemapAfterFileRemoval(int fileIndex) void TabConfig::RemapAfterFileRemoval(int fileIndex)
@@ -1147,7 +1126,7 @@ namespace jdi
return fileVisible[static_cast<std::size_t>(ref.signalIndex)]; return fileVisible[static_cast<std::size_t>(ref.signalIndex)];
} }
void TabConfig::SetVisible(const DataSet& dataSet, const SignalRef& ref, bool visible) void TabConfig::SetVisible(const SignalRef& ref, bool visible)
{ {
if (ref.fileIndex < 0 || static_cast<std::size_t>(ref.fileIndex) >= m_visible.size()) if (ref.fileIndex < 0 || static_cast<std::size_t>(ref.fileIndex) >= m_visible.size())
{ {
@@ -1171,15 +1150,15 @@ namespace jdi
m_laneMode = LaneMode::CUSTOM; m_laneMode = LaneMode::CUSTOM;
} }
SyncLanes(dataSet); SyncLanes();
} }
void TabConfig::ToggleVisible(const DataSet& dataSet, const SignalRef& ref) void TabConfig::ToggleVisible(const SignalRef& ref)
{ {
SetVisible(dataSet, ref, !IsVisible(ref)); SetVisible(ref, !IsVisible(ref));
} }
void TabConfig::SetFileVisible(const DataSet& dataSet, int fileIndex, bool visible) void TabConfig::SetFileVisible(int fileIndex, bool visible)
{ {
if (fileIndex < 0 || static_cast<std::size_t>(fileIndex) >= m_visible.size()) if (fileIndex < 0 || static_cast<std::size_t>(fileIndex) >= m_visible.size())
{ {
@@ -1187,30 +1166,29 @@ namespace jdi
} }
std::vector<bool>& fileVisible = m_visible[static_cast<std::size_t>(fileIndex)]; std::vector<bool>& fileVisible = m_visible[static_cast<std::size_t>(fileIndex)];
std::fill(fileVisible.begin(), fileVisible.end(), visible); std::fill(fileVisible.begin(), fileVisible.end(), visible);
SyncLanes(dataSet); SyncLanes();
} }
void TabConfig::SetAllVisible(const DataSet& dataSet, bool visible) void TabConfig::SetAllVisible(bool visible)
{ {
for (std::vector<bool>& fileVisible : m_visible) for (std::vector<bool>& fileVisible : m_visible)
{ {
std::fill(fileVisible.begin(), fileVisible.end(), visible); std::fill(fileVisible.begin(), fileVisible.end(), visible);
} }
SyncLanes(dataSet); SyncLanes();
} }
void TabConfig::SoloSignal(const DataSet& dataSet, const SignalRef& ref) void TabConfig::SoloSignal(const SignalRef& ref)
{ {
for (std::vector<bool>& fileVisible : m_visible) for (std::vector<bool>& fileVisible : m_visible)
{ {
std::fill(fileVisible.begin(), fileVisible.end(), false); std::fill(fileVisible.begin(), fileVisible.end(), false);
} }
SetVisible(dataSet, ref, true); SetVisible(ref, true);
} }
bool TabConfig::FileHasVisible(const DataSet& dataSet, int fileIndex) const bool TabConfig::FileHasVisible(int fileIndex) const
{ {
(void)dataSet;
if (fileIndex < 0 || static_cast<std::size_t>(fileIndex) >= m_visible.size()) if (fileIndex < 0 || static_cast<std::size_t>(fileIndex) >= m_visible.size())
{ {
return false; return false;
@@ -1219,9 +1197,8 @@ namespace jdi
return std::find(fileVisible.begin(), fileVisible.end(), true) != fileVisible.end(); return std::find(fileVisible.begin(), fileVisible.end(), true) != fileVisible.end();
} }
bool TabConfig::FileAllVisible(const DataSet& dataSet, int fileIndex) const bool TabConfig::FileAllVisible(int fileIndex) const
{ {
(void)dataSet;
if (fileIndex < 0 || static_cast<std::size_t>(fileIndex) >= m_visible.size()) if (fileIndex < 0 || static_cast<std::size_t>(fileIndex) >= m_visible.size())
{ {
return false; return false;
@@ -1256,15 +1233,14 @@ namespace jdi
return count; return count;
} }
void TabConfig::SetMode(const DataSet& dataSet, LaneMode mode) void TabConfig::SetMode(LaneMode mode)
{ {
m_laneMode = mode; m_laneMode = mode;
SyncLanes(dataSet); SyncLanes();
} }
void TabConfig::SyncLanes(const DataSet& dataSet) void TabConfig::SyncLanes()
{ {
(void)dataSet;
RebuildLanes(m_visible, m_lanes, m_laneMode); RebuildLanes(m_visible, m_lanes, m_laneMode);
} }
+4 -14
View File
@@ -249,16 +249,6 @@ namespace jdi
g.ReleaseHDC(hdc); g.ReleaseHDC(hdc);
} }
float UiTextWidth(gd::Graphics& g, const std::wstring& text, HFONT font)
{
// 直接复用 UiMeasureTextWidth:后者用 GetDC(nullptr) 取度量 HDC,
// 不会触发 **Graphics::GetHDC() 的 GDI+ 批次刷新**(实测每次约 5µs)。
// UiEllipsize 会反复调用本函数(逐字符回退时每步一次),
// 若走 GetHDC 路线,一个长名称就要刷新十几次,是拖拽掉帧的隐性来源之一。
(void)g;
return UiMeasureTextWidth(font, text);
}
float UiMeasureTextWidth(HFONT font, const std::wstring& text) float UiMeasureTextWidth(HFONT font, const std::wstring& text)
{ {
if (text.empty() || font == nullptr) if (text.empty() || font == nullptr)
@@ -281,19 +271,19 @@ namespace jdi
return static_cast<float>(size.cx); return static_cast<float>(size.cx);
} }
std::wstring UiEllipsize(gd::Graphics& g, const std::wstring& text, HFONT font, float maxWidth) std::wstring UiEllipsize(const std::wstring& text, HFONT font, float maxWidth)
{ {
if (text.empty() || font == nullptr || maxWidth <= 0.0f) if (text.empty() || font == nullptr || maxWidth <= 0.0f)
{ {
return std::wstring(); return std::wstring();
} }
if (UiTextWidth(g, text, font) <= maxWidth) if (UiMeasureTextWidth(font, text) <= maxWidth)
{ {
return text; return text;
} }
const std::wstring ellipsis = L"…"; const std::wstring ellipsis = L"…";
const float ellipsisWidth = UiTextWidth(g, ellipsis, font); const float ellipsisWidth = UiMeasureTextWidth(font, ellipsis);
if (ellipsisWidth > maxWidth) if (ellipsisWidth > maxWidth)
{ {
return std::wstring(); return std::wstring();
@@ -303,7 +293,7 @@ namespace jdi
while (!result.empty()) while (!result.empty())
{ {
result.pop_back(); result.pop_back();
if (UiTextWidth(g, result, font) + ellipsisWidth <= maxWidth) if (UiMeasureTextWidth(font, result) + ellipsisWidth <= maxWidth)
{ {
return result + ellipsis; return result + ellipsis;
} }
+6 -15
View File
@@ -318,15 +318,6 @@ namespace jdi
rect.Y + (rect.Height - height) * 0.5f, width, height); rect.Y + (rect.Height - height) * 0.5f, width, height);
} }
int PopupMenu::EditingItemId() const
{
if (m_editIndex < 0 || m_editIndex >= static_cast<int>(m_items.size()))
{
return 0;
}
return m_items[static_cast<std::size_t>(m_editIndex)].id;
}
bool PopupMenu::IsOnEditField(int x, int y) const bool PopupMenu::IsOnEditField(int x, int y) const
{ {
if (m_editIndex < 0) if (m_editIndex < 0)
@@ -1050,7 +1041,7 @@ namespace jdi
const float labelLeft = rect.X + kItemPad * m_scale; const float labelLeft = rect.X + kItemPad * m_scale;
const gd::RectF fieldRect = EditFieldRect(static_cast<int>(index)); const gd::RectF fieldRect = EditFieldRect(static_cast<int>(index));
const float labelWidth = std::max(8.0f, fieldRect.X - labelLeft - kEditFieldGap * m_scale); const float labelWidth = std::max(8.0f, fieldRect.X - labelLeft - kEditFieldGap * m_scale);
UiText(g, UiEllipsize(g, item.label, m_fonts->uiSmall, labelWidth), m_fonts->uiSmall, UiText(g, UiEllipsize(item.label, m_fonts->uiSmall, labelWidth), m_fonts->uiSmall,
gd::RectF(labelLeft, rect.Y, labelWidth, rect.Height), labelColor, TextAlign::LEFT); gd::RectF(labelLeft, rect.Y, labelWidth, rect.Height), labelColor, TextAlign::LEFT);
if (static_cast<int>(index) == m_editIndex) if (static_cast<int>(index) == m_editIndex)
@@ -1062,7 +1053,7 @@ namespace jdi
UiFillRoundRect(g, fieldRect, 3.0f * m_scale, m_theme->pressed); UiFillRoundRect(g, fieldRect, 3.0f * m_scale, m_theme->pressed);
UiDrawRoundRect(g, fieldRect, 3.0f * m_scale, m_theme->border, 1.0f); UiDrawRoundRect(g, fieldRect, 3.0f * m_scale, m_theme->border, 1.0f);
const std::wstring text = const std::wstring text =
UiEllipsize(g, item.value, m_fonts->uiSmall, fieldRect.Width - 12.0f * m_scale); UiEllipsize(item.value, m_fonts->uiSmall, fieldRect.Width - 12.0f * m_scale);
UiText(g, text, m_fonts->uiSmall, UiText(g, text, m_fonts->uiSmall,
gd::RectF(fieldRect.X + 6.0f * m_scale, fieldRect.Y, gd::RectF(fieldRect.X + 6.0f * m_scale, fieldRect.Y,
std::max(8.0f, fieldRect.Width - 12.0f * m_scale), fieldRect.Height), std::max(8.0f, fieldRect.Width - 12.0f * m_scale), fieldRect.Height),
@@ -1146,7 +1137,7 @@ namespace jdi
const float textLeft = rect.X + kItemPad * m_scale; const float textLeft = rect.X + kItemPad * m_scale;
const float textWidth = const float textWidth =
rect.Width - 2.0f * kItemPad * m_scale - kMarkerColumn * m_scale - kMarkerGap * m_scale; rect.Width - 2.0f * kItemPad * m_scale - kMarkerColumn * m_scale - kMarkerGap * m_scale;
UiText(g, UiEllipsize(g, item.label, m_fonts->uiSmall, textWidth), m_fonts->uiSmall, UiText(g, UiEllipsize(item.label, m_fonts->uiSmall, textWidth), m_fonts->uiSmall,
gd::RectF(textLeft, rect.Y, std::max(8.0f, textWidth), rect.Height), textColor, gd::RectF(textLeft, rect.Y, std::max(8.0f, textWidth), rect.Height), textColor,
TextAlign::LEFT); TextAlign::LEFT);
} }
@@ -1206,12 +1197,12 @@ namespace jdi
const float labelLeft = rect.X + kItemPad * m_scale; const float labelLeft = rect.X + kItemPad * m_scale;
const gd::RectF fieldRect = EditFieldRect(static_cast<int>(index)); const gd::RectF fieldRect = EditFieldRect(static_cast<int>(index));
const float labelWidth = std::max(8.0f, fieldRect.X - labelLeft - kEditFieldGap * m_scale); const float labelWidth = std::max(8.0f, fieldRect.X - labelLeft - kEditFieldGap * m_scale);
UiText(g, UiEllipsize(g, item.label, m_fonts->uiSmall, labelWidth), m_fonts->uiSmall, UiText(g, UiEllipsize(item.label, m_fonts->uiSmall, labelWidth), m_fonts->uiSmall,
gd::RectF(labelLeft, rect.Y, labelWidth, rect.Height), labelColor, TextAlign::LEFT); gd::RectF(labelLeft, rect.Y, labelWidth, rect.Height), labelColor, TextAlign::LEFT);
UiFillRoundRect(g, fieldRect, 3.0f * m_scale, m_theme->pressed); UiFillRoundRect(g, fieldRect, 3.0f * m_scale, m_theme->pressed);
UiDrawRoundRect(g, fieldRect, 3.0f * m_scale, m_theme->border, 1.0f); UiDrawRoundRect(g, fieldRect, 3.0f * m_scale, m_theme->border, 1.0f);
const std::wstring text = const std::wstring text =
UiEllipsize(g, item.value, m_fonts->uiSmall, fieldRect.Width - 12.0f * m_scale); UiEllipsize(item.value, m_fonts->uiSmall, fieldRect.Width - 12.0f * m_scale);
UiText(g, text, m_fonts->uiSmall, UiText(g, text, m_fonts->uiSmall,
gd::RectF(fieldRect.X + 6.0f * m_scale, fieldRect.Y, gd::RectF(fieldRect.X + 6.0f * m_scale, fieldRect.Y,
std::max(8.0f, fieldRect.Width - 12.0f * m_scale), fieldRect.Height), std::max(8.0f, fieldRect.Width - 12.0f * m_scale), fieldRect.Height),
@@ -1258,7 +1249,7 @@ namespace jdi
const float textLeft = rect.X + kItemPad * m_scale; const float textLeft = rect.X + kItemPad * m_scale;
const float textWidth = const float textWidth =
rect.Width - 2.0f * kItemPad * m_scale - kMarkerColumn * m_scale - kMarkerGap * m_scale; rect.Width - 2.0f * kItemPad * m_scale - kMarkerColumn * m_scale - kMarkerGap * m_scale;
UiText(g, UiEllipsize(g, item.label, m_fonts->uiSmall, textWidth), m_fonts->uiSmall, UiText(g, UiEllipsize(item.label, m_fonts->uiSmall, textWidth), m_fonts->uiSmall,
gd::RectF(textLeft, rect.Y, std::max(8.0f, textWidth), rect.Height), textColor, gd::RectF(textLeft, rect.Y, std::max(8.0f, textWidth), rect.Height), textColor,
TextAlign::LEFT); TextAlign::LEFT);
} }
-15
View File
@@ -322,21 +322,6 @@ namespace jdi
return changed; return changed;
} }
bool TextEdit::PlaceCaret(std::size_t offset)
{
if (!m_active)
{
return false;
}
const std::size_t target = ClampOffset(offset);
const bool changed = HasSelection() || (m_caret != target);
m_caret = target;
m_anchor = target;
m_fresh = false;
return changed;
}
void TextEdit::BeginDrag(std::size_t offset) void TextEdit::BeginDrag(std::size_t offset)
{ {
if (!m_active) if (!m_active)
-5
View File
@@ -80,9 +80,4 @@ namespace jdi
return kSignalPalette; return kSignalPalette;
} }
int SignalColorCount()
{
return static_cast<int>(sizeof(kSignalPalette) / sizeof(kSignalPalette[0]));
}
} // namespace jdi } // namespace jdi
-33
View File
@@ -50,30 +50,6 @@ namespace jdi
return result; return result;
} }
std::string WideToUtf8(const wchar_t* text)
{
if (text == nullptr)
{
return std::string();
}
int wideCount = static_cast<int>(std::wcslen(text));
if (wideCount <= 0)
{
return std::string();
}
int byteCount = WideCharToMultiByte(CP_UTF8, 0, text, wideCount, nullptr, 0, nullptr, nullptr);
if (byteCount <= 0)
{
return std::string();
}
std::string result(static_cast<size_t>(byteCount), '\0');
WideCharToMultiByte(CP_UTF8, 0, text, wideCount, &result[0], byteCount, nullptr, nullptr);
return result;
}
std::wstring Trim(const std::wstring& text) std::wstring Trim(const std::wstring& text)
{ {
size_t begin = 0; size_t begin = 0;
@@ -117,15 +93,6 @@ namespace jdi
return result; return result;
} }
bool StartsWith(const std::wstring& text, const std::wstring& prefix)
{
if (prefix.size() > text.size())
{
return false;
}
return text.compare(0, prefix.size(), prefix) == 0;
}
bool ContainsInsensitive(const std::wstring& text, const std::wstring& needle) bool ContainsInsensitive(const std::wstring& text, const std::wstring& needle)
{ {
if (needle.empty()) if (needle.empty())