在单位回退时就近提示缺少可用标定

让实时和回放的原始单位回退原因出现在力曲线单位按钮旁。相关定向测试与 lint gate 通过。
This commit is contained in:
ykcheungab
2026-10-10 15:05:09 +08:00
parent cf86bd0702
commit 48de5b74e6
7 changed files with 42 additions and 3 deletions
+1 -1
View File
@@ -504,7 +504,7 @@
"finger_run_unavailable": "Run is not available for this sensor type",
"video_required": "Select a video file first",
"config_missing": "Sensor config not found for {type}",
"units_raw_fallback": "Calibration unavailable — showing raw units",
"units_raw_fallback": "No usable calibration; showing raw for now",
"reveal_failed": "Could not reveal config: {error}"
},
"scene3d": {
+1 -1
View File
@@ -504,7 +504,7 @@
"finger_run_unavailable": "此传感器类型暂不支持运行",
"video_required": "请先选择视频文件",
"config_missing": "未找到传感器配置: {type}",
"units_raw_fallback": "无标定数据 — 显示原始单位",
"units_raw_fallback": "无可用标定,暂显示原始单位",
"reveal_failed": "无法打开配置位置: {error}"
},
"scene3d": {
@@ -152,6 +152,7 @@ class AcquirePresenter(QObject):
if not self._host.session.raw_fallback_notified:
self._host.session.raw_fallback_notified = True
self._host.notify(t("status.units_raw_fallback"))
self._charts.show_unit_fallback()
else:
self._host.session.raw_fallback_notified = False
self._host.session.last_sample_valid = True
@@ -1411,6 +1411,7 @@ class ReplayController(QObject):
self._host.set_display_unit(unit)
if unit != wanted:
self._host.notify(t("status.units_raw_fallback"))
self._charts.show_unit_fallback()
self._charts.show_all()
self._image_panel.set_source_kind("replay")
return
@@ -1483,6 +1484,7 @@ class ReplayController(QObject):
wanted = "N" if self._charts.unit() == "N" else "raw"
if wanted == "N" and not source.unit_available("N"):
self._host.notify(t("status.units_raw_fallback"))
self._charts.show_unit_fallback()
return "raw"
return wanted
@@ -16,7 +16,7 @@ from orisys_app_shared.force.source import StoreCurveSource
from orisys_app_shared.i18n import t
from orisys_app_shared.record.sample import plottable_axis_mask
from orisys_app_shared.theme import color
from PySide6.QtCore import QSize, Qt, Signal
from PySide6.QtCore import QSize, Qt, QTimer, Signal
from PySide6.QtGui import QColor, QFont, QFontDatabase, QFontMetrics
from PySide6.QtWidgets import (
QFrame,
@@ -252,6 +252,13 @@ class ForcePlotsPanel(QFrame):
self.btn_settings = self._header_button("settings")
self.btn_settings.clicked.connect(self.plot_settings_requested.emit)
header.addWidget(self.btn_settings)
self.unit_notice = QLabel()
self.unit_notice.setObjectName("hintText")
self.unit_notice.hide()
header.addWidget(self.unit_notice)
self._unit_notice_timer = QTimer(self)
self._unit_notice_timer.setSingleShot(True)
self._unit_notice_timer.timeout.connect(self.unit_notice.hide)
# The unit chip is a button: switching between newton and raw is a chart
# concern, so it lives on the chart.
self.unit_badge = QPushButton()
@@ -733,6 +740,12 @@ class ForcePlotsPanel(QFrame):
self._last_overview_at = now
self._sync_overview()
def show_unit_fallback(self) -> None:
"""Explain a failed Newton switch beside the unit control."""
self.unit_notice.setText(t("status.units_raw_fallback"))
self.unit_notice.show()
self._unit_notice_timer.start(6000)
def set_units(self, unit: str) -> None:
"""Switch display units without mixing units in the curve buffer.
@@ -742,6 +755,9 @@ class ForcePlotsPanel(QFrame):
cleared rather than reinterpreted.
"""
unit = "N" if str(unit).upper().startswith("N") else "raw"
if unit == "N":
self._unit_notice_timer.stop()
self.unit_notice.hide()
if unit == self._unit:
return
self._unit = unit
@@ -1450,6 +1466,7 @@ class ForcePlotsPanel(QFrame):
self.btn_settings.setAccessibleName(t("chart.settings"))
self.unit_badge.setToolTip(t("chart.unit_toggle_tip"))
self.unit_badge.setAccessibleName(t("chart.unit_toggle"))
self.unit_notice.setText(t("status.units_raw_fallback"))
self.window_caption.setText(t("chart.overview"))
self.window_caption.setToolTip(t("chart.window_tip"))
self._refresh_mode_label()
@@ -3,6 +3,7 @@
from __future__ import annotations
import numpy as np
from orisys_app_shared.i18n import t
from orisys_studio.ui.force_plots import ForcePlotsPanel, _nice_ticks
@@ -28,6 +29,19 @@ def _curve(panel: ForcePlotsPanel, channel: int) -> np.ndarray:
# ------------------------------------------------------------- force output
def test_missing_calibration_notice_sits_beside_unit_button(qt_app):
panel = _panel("raw")
assert not panel.unit_notice.isVisible()
panel.show_unit_fallback()
assert panel.unit_notice.text() == t("status.units_raw_fallback")
assert not panel.unit_notice.isHidden()
header = panel.layout().itemAt(0).layout()
assert header.itemAt(header.count() - 2).widget() is panel.unit_notice
assert header.itemAt(header.count() - 1).widget() is panel.unit_badge
panel.set_units("N")
assert panel.unit_notice.isHidden()
def test_raw_threshold_and_precision_match_cards_and_curve(qt_app):
panel = _panel("raw")
panel.set_deadband_floors(raw=50.0)
@@ -111,6 +111,7 @@ class _Charts:
self.followed = 0
self.shown = 0
self.cleared = 0
self.unit_fallbacks = 0
def unit(self) -> str:
return self._unit
@@ -134,6 +135,9 @@ class _Charts:
def show_all(self) -> None:
self.shown += 1
def show_unit_fallback(self) -> None:
self.unit_fallbacks += 1
class _ImagePanel:
def __init__(self) -> None:
@@ -584,6 +588,7 @@ def test_the_charts_fall_back_to_raw_when_a_recording_has_no_newtons(qt_app):
assert engine.units[-1] == "raw"
assert host.units[-1] == "raw"
assert t("status.units_raw_fallback") in host.notes
assert parts[1].unit_fallbacks == 1
engine._reader = _Reader(newtons=[1.0, 2.0, 3.0])
controller.apply_source(True)