在单位回退时就近提示缺少可用标定
让实时和回放的原始单位回退原因出现在力曲线单位按钮旁。相关定向测试与 lint gate 通过。
This commit is contained in:
@@ -504,7 +504,7 @@
|
|||||||
"finger_run_unavailable": "Run is not available for this sensor type",
|
"finger_run_unavailable": "Run is not available for this sensor type",
|
||||||
"video_required": "Select a video file first",
|
"video_required": "Select a video file first",
|
||||||
"config_missing": "Sensor config not found for {type}",
|
"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}"
|
"reveal_failed": "Could not reveal config: {error}"
|
||||||
},
|
},
|
||||||
"scene3d": {
|
"scene3d": {
|
||||||
|
|||||||
@@ -504,7 +504,7 @@
|
|||||||
"finger_run_unavailable": "此传感器类型暂不支持运行",
|
"finger_run_unavailable": "此传感器类型暂不支持运行",
|
||||||
"video_required": "请先选择视频文件",
|
"video_required": "请先选择视频文件",
|
||||||
"config_missing": "未找到传感器配置: {type}",
|
"config_missing": "未找到传感器配置: {type}",
|
||||||
"units_raw_fallback": "无标定数据 — 显示原始单位",
|
"units_raw_fallback": "无可用标定,暂显示原始单位",
|
||||||
"reveal_failed": "无法打开配置位置: {error}"
|
"reveal_failed": "无法打开配置位置: {error}"
|
||||||
},
|
},
|
||||||
"scene3d": {
|
"scene3d": {
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ class AcquirePresenter(QObject):
|
|||||||
if not self._host.session.raw_fallback_notified:
|
if not self._host.session.raw_fallback_notified:
|
||||||
self._host.session.raw_fallback_notified = True
|
self._host.session.raw_fallback_notified = True
|
||||||
self._host.notify(t("status.units_raw_fallback"))
|
self._host.notify(t("status.units_raw_fallback"))
|
||||||
|
self._charts.show_unit_fallback()
|
||||||
else:
|
else:
|
||||||
self._host.session.raw_fallback_notified = False
|
self._host.session.raw_fallback_notified = False
|
||||||
self._host.session.last_sample_valid = True
|
self._host.session.last_sample_valid = True
|
||||||
|
|||||||
@@ -1411,6 +1411,7 @@ class ReplayController(QObject):
|
|||||||
self._host.set_display_unit(unit)
|
self._host.set_display_unit(unit)
|
||||||
if unit != wanted:
|
if unit != wanted:
|
||||||
self._host.notify(t("status.units_raw_fallback"))
|
self._host.notify(t("status.units_raw_fallback"))
|
||||||
|
self._charts.show_unit_fallback()
|
||||||
self._charts.show_all()
|
self._charts.show_all()
|
||||||
self._image_panel.set_source_kind("replay")
|
self._image_panel.set_source_kind("replay")
|
||||||
return
|
return
|
||||||
@@ -1483,6 +1484,7 @@ class ReplayController(QObject):
|
|||||||
wanted = "N" if self._charts.unit() == "N" else "raw"
|
wanted = "N" if self._charts.unit() == "N" else "raw"
|
||||||
if wanted == "N" and not source.unit_available("N"):
|
if wanted == "N" and not source.unit_available("N"):
|
||||||
self._host.notify(t("status.units_raw_fallback"))
|
self._host.notify(t("status.units_raw_fallback"))
|
||||||
|
self._charts.show_unit_fallback()
|
||||||
return "raw"
|
return "raw"
|
||||||
return wanted
|
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.i18n import t
|
||||||
from orisys_app_shared.record.sample import plottable_axis_mask
|
from orisys_app_shared.record.sample import plottable_axis_mask
|
||||||
from orisys_app_shared.theme import color
|
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.QtGui import QColor, QFont, QFontDatabase, QFontMetrics
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QFrame,
|
QFrame,
|
||||||
@@ -252,6 +252,13 @@ class ForcePlotsPanel(QFrame):
|
|||||||
self.btn_settings = self._header_button("settings")
|
self.btn_settings = self._header_button("settings")
|
||||||
self.btn_settings.clicked.connect(self.plot_settings_requested.emit)
|
self.btn_settings.clicked.connect(self.plot_settings_requested.emit)
|
||||||
header.addWidget(self.btn_settings)
|
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
|
# The unit chip is a button: switching between newton and raw is a chart
|
||||||
# concern, so it lives on the chart.
|
# concern, so it lives on the chart.
|
||||||
self.unit_badge = QPushButton()
|
self.unit_badge = QPushButton()
|
||||||
@@ -733,6 +740,12 @@ class ForcePlotsPanel(QFrame):
|
|||||||
self._last_overview_at = now
|
self._last_overview_at = now
|
||||||
self._sync_overview()
|
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:
|
def set_units(self, unit: str) -> None:
|
||||||
"""Switch display units without mixing units in the curve buffer.
|
"""Switch display units without mixing units in the curve buffer.
|
||||||
|
|
||||||
@@ -742,6 +755,9 @@ class ForcePlotsPanel(QFrame):
|
|||||||
cleared rather than reinterpreted.
|
cleared rather than reinterpreted.
|
||||||
"""
|
"""
|
||||||
unit = "N" if str(unit).upper().startswith("N") else "raw"
|
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:
|
if unit == self._unit:
|
||||||
return
|
return
|
||||||
self._unit = unit
|
self._unit = unit
|
||||||
@@ -1450,6 +1466,7 @@ class ForcePlotsPanel(QFrame):
|
|||||||
self.btn_settings.setAccessibleName(t("chart.settings"))
|
self.btn_settings.setAccessibleName(t("chart.settings"))
|
||||||
self.unit_badge.setToolTip(t("chart.unit_toggle_tip"))
|
self.unit_badge.setToolTip(t("chart.unit_toggle_tip"))
|
||||||
self.unit_badge.setAccessibleName(t("chart.unit_toggle"))
|
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.setText(t("chart.overview"))
|
||||||
self.window_caption.setToolTip(t("chart.window_tip"))
|
self.window_caption.setToolTip(t("chart.window_tip"))
|
||||||
self._refresh_mode_label()
|
self._refresh_mode_label()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from orisys_app_shared.i18n import t
|
||||||
from orisys_studio.ui.force_plots import ForcePlotsPanel, _nice_ticks
|
from orisys_studio.ui.force_plots import ForcePlotsPanel, _nice_ticks
|
||||||
|
|
||||||
|
|
||||||
@@ -28,6 +29,19 @@ def _curve(panel: ForcePlotsPanel, channel: int) -> np.ndarray:
|
|||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------- force output
|
# ------------------------------------------------------------- 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):
|
def test_raw_threshold_and_precision_match_cards_and_curve(qt_app):
|
||||||
panel = _panel("raw")
|
panel = _panel("raw")
|
||||||
panel.set_deadband_floors(raw=50.0)
|
panel.set_deadband_floors(raw=50.0)
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ class _Charts:
|
|||||||
self.followed = 0
|
self.followed = 0
|
||||||
self.shown = 0
|
self.shown = 0
|
||||||
self.cleared = 0
|
self.cleared = 0
|
||||||
|
self.unit_fallbacks = 0
|
||||||
|
|
||||||
def unit(self) -> str:
|
def unit(self) -> str:
|
||||||
return self._unit
|
return self._unit
|
||||||
@@ -134,6 +135,9 @@ class _Charts:
|
|||||||
def show_all(self) -> None:
|
def show_all(self) -> None:
|
||||||
self.shown += 1
|
self.shown += 1
|
||||||
|
|
||||||
|
def show_unit_fallback(self) -> None:
|
||||||
|
self.unit_fallbacks += 1
|
||||||
|
|
||||||
|
|
||||||
class _ImagePanel:
|
class _ImagePanel:
|
||||||
def __init__(self) -> None:
|
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 engine.units[-1] == "raw"
|
||||||
assert host.units[-1] == "raw"
|
assert host.units[-1] == "raw"
|
||||||
assert t("status.units_raw_fallback") in host.notes
|
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])
|
engine._reader = _Reader(newtons=[1.0, 2.0, 3.0])
|
||||||
controller.apply_source(True)
|
controller.apply_source(True)
|
||||||
|
|||||||
Reference in New Issue
Block a user