Make the rail reset zero the sensor in live and the display in replay

The replay view disabled a control whose display reset is exactly what an
operator wants there, and the bare "Reset" hid that the live one zeroes the
sensor tracker; the label, tooltip and status line now name the target, and
Ctrl+R follows the view. Verified with the studio suite, ui_check (628
checks) and real-GL rail snapshots of both views.
This commit is contained in:
ykcheungab
2026-10-04 11:09:22 +08:00
parent aa526c62a9
commit 6fb2f72c6e
9 changed files with 525 additions and 50 deletions
+52 -6
View File
@@ -15,6 +15,11 @@ Everything that is *configuration* rather than state — source, camera number,
video file, units and the sensor/config pickers — lives in the settings area,
collapsed by default. Both live inside one scroll area so a narrow window
scrolls sideways instead of squeezing the controls into an unreadable row.
The reset is the one rail action whose meaning follows the view
(``reset_target``): the live view zeroes the sensor tracker, the replay view —
which owns no device — puts the display back. Its text and tooltip always name
the target that is live *now*, so one control never means two things at once.
"""
from __future__ import annotations
@@ -118,6 +123,9 @@ class ToolbarWidget(QWidget):
self._video_path = ""
#: ``acquire`` while measuring, ``playback`` while replaying a recording.
self._run_role = "acquire"
#: Whether the control's target can be acted on *now* (see
#: ``set_reset_enabled``): it decides which of the two live tooltips is shown.
self._reset_available = False
outer = QVBoxLayout(self)
outer.setContentsMargins(2, 2, 2, 2)
@@ -421,6 +429,9 @@ class ToolbarWidget(QWidget):
self.btn_run.blockSignals(False)
self._refresh_run_label()
self._refresh_stop_label()
# The reset is the one rail control whose *target* moves with the view (see
# ``reset_target``), so its label is refreshed with the other two.
self._refresh_reset_label()
def run_role(self) -> str:
return self._run_role
@@ -490,7 +501,28 @@ class ToolbarWidget(QWidget):
self.btn_stop.setEnabled(bool(enabled))
def set_reset_enabled(self, enabled: bool) -> None:
self.btn_reset.setEnabled(bool(enabled))
"""Offer the reset, and say in its tooltip what it can act on right now.
The button's *target* is the view's (``reset_target``); this is only whether
that target is actionable — a live session for the tracker, always for the
display — so the tip explains a disabled live button rather than leaving the
operator to guess what is missing.
"""
self._reset_available = bool(enabled)
self.btn_reset.setEnabled(self._reset_available)
self._refresh_reset_label()
def reset_target(self) -> str:
"""What the rail's reset control acts on in this view: ``sensor`` or ``display``.
One control, one meaning *per view*, and this is the single place that decides
it: the live view has a device session, so its reset zeroes the tracker; the
replay view has none, so the same button puts the display back instead of being
a dead control ("the reset button cannot be used in replay mode"). The window
routes its click on this answer and ``_refresh_reset_label`` names it, so the
behaviour and the label cannot drift apart.
"""
return "display" if self._run_role == "playback" else "sensor"
def set_camera_controls_enabled(self, enabled: bool) -> None:
live = self._source_view == "live"
@@ -553,6 +585,7 @@ class ToolbarWidget(QWidget):
self._refresh_preview_label()
self._refresh_run_label()
self._refresh_stop_label()
self._refresh_reset_label()
# ------------------------------------------------------------- internals
def _populate_units_combo(self) -> None:
@@ -797,11 +830,24 @@ class ToolbarWidget(QWidget):
self.btn_run.setToolTip(tip)
def _refresh_reset_label(self) -> None:
self.btn_reset.setText(t("toolbar.reset"))
# The button zeroes the *device* tracker; it no longer clears the curves.
# That is now 视图 → 复位视图, because one button doing both meant an
# operator who wanted a fresh baseline also lost the history on screen.
self.btn_reset.setToolTip(t("toolbar.reset_tip"))
"""Say which of the two things this button will do, where it is on screen.
The operator's complaint was that 重置 read as "reset the charts" when it zeroes
the *sensor tracker* — and that in the replay view, where it is the display that
can be reset, it was unavailable. The label therefore names the target and the
tip states the side effect that is real but invisible: zeroing the tracker also
restarts the display baseline (the curve history is kept).
"""
if self.reset_target() == "display":
self.btn_reset.setText(t("toolbar.reset_display"))
self.btn_reset.setToolTip(t("toolbar.reset_display_tip"))
return
self.btn_reset.setText(t("toolbar.reset_sensor"))
self.btn_reset.setToolTip(
t("toolbar.reset_sensor_tip")
if self._reset_available
else t("toolbar.reset_sensor_unavailable")
)
def retranslate(self) -> None:
self.cam_id_label.setText(t("toolbar.cam_id"))