From 3e45ecdc3c923af80578ab75c15fe5921cee66d7 Mon Sep 17 00:00:00 2001 From: ykcheungab Date: Wed, 7 Oct 2026 21:36:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=8A=E5=88=86=E6=9E=90=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E5=92=8C=E5=88=86=E6=9E=90=E8=AE=BE=E7=BD=AE=E6=8C=AA=E5=88=B0?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E7=9A=84=E3=80=8C=E5=88=86=E6=9E=90=E3=80=8D?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 菜单栏为文件 | 采集 | 分析 | 视图 | 帮助。提示里指向这两项的路径已改成「分析」。 --- apps/studio/config/locales/en_US.json | 13 ++++--- apps/studio/config/locales/zh_CN.json | 11 +++--- apps/studio/docs/ui-elements.json | 6 ++- apps/studio/src/orisys_studio/app_window.py | 37 ++++++++++--------- apps/studio/tests/test_bare_video_analysis.py | 2 +- 5 files changed, 38 insertions(+), 31 deletions(-) diff --git a/apps/studio/config/locales/en_US.json b/apps/studio/config/locales/en_US.json index f949403..cd74071 100644 --- a/apps/studio/config/locales/en_US.json +++ b/apps/studio/config/locales/en_US.json @@ -21,6 +21,7 @@ "playback": "Open recording replay…", "playback_latest": "Replay most recent recording", "session": "Session", + "analysis": "Analysis", "view": "View", "theme": "Theme", "theme_dark": "Dark", @@ -37,7 +38,7 @@ "plot_settings": "Plot settings…", "rotate_arrows": "Rotate arrows 90°", "recompute": "Analyze video", - "recompute_tip": "On: serve a stored analysis result for this video, or run the pass if there is none. Off: leave analysis and read the recording’s own forces.csv when it has one. To change profile, calibration or reference frame use View ▸ Analysis setup…", + "recompute_tip": "On: serve a stored analysis result for this video, or run the pass if there is none. Off: leave analysis and read the recording’s own forces.csv when it has one. To change profile, calibration or reference frame use Analysis ▸ Analysis setup…", "analysis_setup": "Analysis setup…", "analysis_setup_tip": "Choose the profile, calibration and reference frame for this video, then run (or re-run) the analysis pass.", "run": "Run / Stop", @@ -115,7 +116,7 @@ "choose_video": "Choose a recorded video…", "choose_video_tip": "Open a recorded video: the 2D panel plays it and the charts read the forces.csv beside it", "recompute": "Analyze video…", - "recompute_tip": "Serve a stored analysis result for this video, or run the pass if there is none. The 2D panel can then draw arrows and depth; the charts may show force from the result. Stop cancels a pass that is still running. To change profile, calibration or reference frame use View ▸ Analysis setup…", + "recompute_tip": "Serve a stored analysis result for this video, or run the pass if there is none. The 2D panel can then draw arrows and depth; the charts may show force from the result. Stop cancels a pass that is still running. To change profile, calibration or reference frame use Analysis ▸ Analysis setup…", "replay_view_only": "Open a recording from the History replay view", "preview": "Preview", "preview_stop": "Stop preview", @@ -134,7 +135,7 @@ "playback_tip": "Play this recording at 1× (space bar does the same); dragging the cursor pauses", "playback_pause_tip": "Pause playback (dragging the cursor, box zoom or the wheel also pauses)", "playback_disabled": "Open a recorded video first (“Choose a recorded video…” at the top left)", - "playback_needs_recording": "This video has no recording beside it (no forces.csv): replay needs a recording; to just watch the video open it as a video, or use View ▸ Analyze video", + "playback_needs_recording": "This video has no recording beside it (no forces.csv): replay needs a recording; to just watch the video open it as a video, or use Analysis ▸ Analyze video", "playback_video_only": "Play this video (no recording beside it: the picture plays, the force charts are empty)", "reset_sensor": "Reset sensor", "reset_sensor_tip": "Reset the sensor tracker and its reference frame. Force thresholds remain as configured; chart history is kept.", @@ -297,10 +298,10 @@ "video_filter": "Recorded video (*.mp4 *.avi *.mov *.mkv);;All files (*)", "no_video": "This recording has no usable video segment", "open_failed": "Could not open that recording: {error}", - "not_a_recording": "“{name}” is not a recording: its folder has no forces.csv (a recording is the video plus forces.csv and session.json). Replay needs a recording; to just watch this video, open it as a video or use View ▸ Analyze video.", + "not_a_recording": "“{name}” is not a recording: its folder has no forces.csv (a recording is the video plus forces.csv and session.json). Replay needs a recording; to just watch this video, open it as a video or use Analysis ▸ Analyze video.", "video_only_opened": "Opened “{name}”; no analysis result yet. Choose Analyze video… above to generate one.", "video_only_notice": "This video has no recording beside it (no forces.csv): it plays, but the force charts and the recording details are empty.", - "video_only_panel": "This is not a recording, and this video cannot be decoded (no forces.csv beside it, and it does not read as playable video)\nYou can still try View ▸ Analyze video", + "video_only_panel": "This is not a recording, and this video cannot be decoded (no forces.csv beside it, and it does not read as playable video)\nYou can still try Analysis ▸ Analyze video", "empty_recording": "This recording has no playable picture (no raw_*.mp4 segment), so it cannot be replayed", "none_found": "No recording found under outputs/recordings", "frame_dropped": "This frame never reached the video (the record queue overflowed)", @@ -320,7 +321,7 @@ "analysis_busy": "an analysis is already running: wait for it, or cancel it", "analysis_grid_mismatch": "the current display settings moved the sample grid ({keys}); the stored candidate locations cannot serve it, so the replay keeps drawing the result's own grid", "analysis_no_chain": "this recording does not say which sensor and configuration produced it ({error}), so no result can be read and no pass can be run", - "analysis_setup_declined": "no analysis was set up for this video: the setup prompt was dismissed, so there is nothing to draw from. Use View ▸ Analysis setup… or open the video again" + "analysis_setup_declined": "no analysis was set up for this video: the setup prompt was dismissed, so there is nothing to draw from. Use Analysis ▸ Analysis setup… or open the video again" }, "video_analysis": { "title": "Analyse this video", diff --git a/apps/studio/config/locales/zh_CN.json b/apps/studio/config/locales/zh_CN.json index 43cac61..62746ab 100644 --- a/apps/studio/config/locales/zh_CN.json +++ b/apps/studio/config/locales/zh_CN.json @@ -21,6 +21,7 @@ "playback": "打开录制回放…", "playback_latest": "回放最近一次录制", "session": "采集", + "analysis": "分析", "view": "视图", "theme": "主题", "theme_dark": "深色", @@ -37,7 +38,7 @@ "plot_settings": "绘图设置…", "rotate_arrows": "旋转箭头图 90°", "recompute": "分析视频", - "recompute_tip": "打开:有兼容的分析结果就直接用,没有就跑一遍分析。关闭:离开分析,有 forces.csv 时曲线读录制值。要改配置、标定或参考帧请用「视图 ▸ 分析设置…」。", + "recompute_tip": "打开:有兼容的分析结果就直接用,没有就跑一遍分析。关闭:离开分析,有 forces.csv 时曲线读录制值。要改配置、标定或参考帧请用「分析 ▸ 分析设置…」。", "analysis_setup": "分析设置…", "analysis_setup_tip": "为这段视频选择配置、标定与参考帧,然后跑(或重跑)分析。", "run": "运行 / 停止", @@ -115,7 +116,7 @@ "choose_video": "选择录制视频…", "choose_video_tip": "打开一段录制的视频:2D 面板放视频,曲线读同目录的 forces.csv(原始记录值)", "recompute": "分析视频…", - "recompute_tip": "有兼容的分析结果就直接用,没有就跑一遍分析:2D 面板可画箭头与深度,曲线可读结果中的力。分析进行中可随时「停止」。要改配置、标定或参考帧请用「视图 ▸ 分析设置…」。", + "recompute_tip": "有兼容的分析结果就直接用,没有就跑一遍分析:2D 面板可画箭头与深度,曲线可读结果中的力。分析进行中可随时「停止」。要改配置、标定或参考帧请用「分析 ▸ 分析设置…」。", "replay_view_only": "请在「历史回放」视图里打开录像", "preview": "预览", "preview_stop": "停止预览", @@ -134,7 +135,7 @@ "playback_tip": "按 1× 播放这段录制(空格键同效);拖动游标即暂停", "playback_pause_tip": "暂停播放(拖动游标、框选或滚轮也会暂停)", "playback_disabled": "先打开一段录制视频(左上「选择录制视频…」)", - "playback_needs_recording": "这段视频旁边没有记录(缺 forces.csv):回放需要一条记录;只想看视频请直接打开视频,或用 视图 ▸ 分析视频", + "playback_needs_recording": "这段视频旁边没有记录(缺 forces.csv):回放需要一条记录;只想看视频请直接打开视频,或用 分析 ▸ 分析视频", "playback_video_only": "播放这段视频(没有配套记录:可以看画面,力曲线为空)", "reset_sensor": "重置传感器", "reset_sensor_tip": "重置传感器追踪器及参考帧;力值阈值保持设定值,曲线历史保留。", @@ -300,7 +301,7 @@ "not_a_recording": "「{name}」不是一条记录:同目录没有 forces.csv(一条记录 = 录像 + forces.csv + session.json)。回放需要记录;只想看这段视频请直接打开视频,或用「分析视频」。", "video_only_opened": "已打开「{name}」;尚无分析结果。点顶部「分析视频…」生成。", "video_only_notice": "这段视频没有配套记录(同目录无 forces.csv):可以播放,但力曲线与记录信息为空。", - "video_only_panel": "这不是一条记录,而且无法解码这段视频(没有 forces.csv,也不像可播放的视频文件)\n可以试试 视图 ▸ 分析视频", + "video_only_panel": "这不是一条记录,而且无法解码这段视频(没有 forces.csv,也不像可播放的视频文件)\n可以试试 分析 ▸ 分析视频", "empty_recording": "这条记录没有可播放的画面(没有 raw_*.mp4 视频分段),因此无法回放", "none_found": "outputs/recordings 下没有找到录制", "frame_dropped": "该帧未被写入视频(记录队列曾溢出)", @@ -320,7 +321,7 @@ "analysis_busy": "分析进行中:先等待或取消当前这一遍", "analysis_grid_mismatch": "当前显示设置改了采样网格({keys}),存下来的候选位置无法服务它:回放仍按结果自己的网格绘制", "analysis_no_chain": "这条录像没有说明用哪套传感器与配置录下来({error}),因此既无法读取结果,也无法重算", - "analysis_setup_declined": "这段视频没有建立分析:设置提示被关掉了,因此没有可画的东西。用「视图 ▸ 分析设置…」或重新打开视频即可分析" + "analysis_setup_declined": "这段视频没有建立分析:设置提示被关掉了,因此没有可画的东西。用「分析 ▸ 分析设置…」或重新打开视频即可分析" }, "video_analysis": { "title": "分析这段视频", diff --git a/apps/studio/docs/ui-elements.json b/apps/studio/docs/ui-elements.json index 5234762..c4c6f75 100644 --- a/apps/studio/docs/ui-elements.json +++ b/apps/studio/docs/ui-elements.json @@ -156,6 +156,8 @@ "purpose": "open a video, reveal the sensor config, open a recording for playback" }, { "id": "session_menu", "path": "session_menu", "objectName": null, "class": "QMenu", "purpose": "acquisition session controls: run, cancel, preview, tracker reset, pause" }, + { "id": "analysis_menu", "path": "analysis_menu", "objectName": null, "class": "QMenu", + "purpose": "offline analysis of a recording: serve or run a pass, and reopen analysis setup" }, { "id": "view_menu", "path": "view_menu", "objectName": null, "class": "QMenu", "purpose": "what is on screen: panels, 3D, display aids, reset views, theme and language" }, { "id": "theme_menu", "path": "theme_menu", "objectName": null, "class": "QMenu", @@ -201,9 +203,9 @@ { "id": "act_rotate_arrows", "path": "act_rotate_arrows", "objectName": null, "class": "QAction", "purpose": "view menu: rotate the 2D arrow field by 90 degrees for the mounted sensors" }, { "id": "act_recompute", "path": "act_recompute", "objectName": null, "class": "QAction", - "purpose": "view menu: analyze video — serve a stored result or run the pass; same state as the rail's button" }, + "purpose": "analysis menu: analyze video — serve a stored result or run the pass; same state as the rail's button" }, { "id": "act_analysis_setup", "path": "act_analysis_setup", "objectName": null, "class": "QAction", - "purpose": "view menu: reopen the analysis setup dialog (profile, calibration, reference frame)" }, + "purpose": "analysis menu: reopen the analysis setup dialog (profile, calibration, reference frame)" }, { "id": "act_reset_view", "path": "act_reset_view", "objectName": null, "class": "QAction", "purpose": "view menu / F8: reset the views (curves, window, cursor, 3D camera) without touching the device" }, { "id": "act_theme_dark", "path": "act_theme_dark", "objectName": null, "class": "QAction", diff --git a/apps/studio/src/orisys_studio/app_window.py b/apps/studio/src/orisys_studio/app_window.py index 94cefa4..f953199 100644 --- a/apps/studio/src/orisys_studio/app_window.py +++ b/apps/studio/src/orisys_studio/app_window.py @@ -171,7 +171,7 @@ class StudioMainWindow(QMainWindow): self._theme = str(self.prefs.get("theme") or "dark") self._language = str(self.prefs.get("language") or "zh_CN") #: Reference-frame override for the next analysis pass on a real recording - #: (from View ▸ Analysis setup…). Bare-video workspaces store this in session.json. + #: (from Analysis ▸ Analysis setup…). Bare-video workspaces store this in session.json. self._analysis_reference_override: int | None = None # The view preset, the calibration panel, the 3D pane's switch and the fps # readout are the controllers' state; the window reads and writes them through @@ -1064,7 +1064,7 @@ class StudioMainWindow(QMainWindow): self.addAction(self.act_play) # Acquisition session controls (run / preview / pause). Order on the bar: - # File | Session | View | Help. + # File | Session | Analysis | View | Help. self.session_menu = menu_bar.addMenu("") self.act_run = QAction(self) @@ -1095,6 +1095,19 @@ class StudioMainWindow(QMainWindow): self.act_pause.toggled.connect(self._on_pause_action_toggled) self.session_menu.addAction(self.act_pause) + # Offline analysis of a recording. Separate from Session: that menu starts + # and stops a live device session. + self.analysis_menu = menu_bar.addMenu("") + # Serve / leave a stored analysis result (or run the pass when there is none). + self.act_recompute = QAction(self) + self.act_recompute.setCheckable(True) + self.act_recompute.setChecked(False) + self.analysis_menu.addAction(self.act_recompute) + # Reopen the setup dialog after the first pass (profile / calibration / reference). + self.act_analysis_setup = QAction(self) + self.act_analysis_setup.triggered.connect(self.replay_ctl.on_analysis_setup) + self.analysis_menu.addAction(self.act_analysis_setup) + self.view_menu = menu_bar.addMenu("") self.act_cal_panel = QAction(self) self.act_cal_panel.setCheckable(True) @@ -1142,17 +1155,6 @@ class StudioMainWindow(QMainWindow): self.act_rotate_arrows = QAction(self) self.act_rotate_arrows.triggered.connect(self.display_ctl.on_rotate_arrows) self.view_menu.addAction(self.act_rotate_arrows) - - # Serve / leave a stored analysis result (or run the pass when there is none). - self.act_recompute = QAction(self) - self.act_recompute.setCheckable(True) - self.act_recompute.setChecked(False) - self.view_menu.addAction(self.act_recompute) - - # Reopen the setup dialog after the first pass (profile / calibration / reference). - self.act_analysis_setup = QAction(self) - self.act_analysis_setup.triggered.connect(self.replay_ctl.on_analysis_setup) - self.view_menu.addAction(self.act_analysis_setup) self.view_menu.addSeparator() # The graphics half of the old 重置: curves, window, cursor and the 3D camera. @@ -1392,6 +1394,11 @@ class StudioMainWindow(QMainWindow): self._sync_reset_action() self.act_pause.setText(t("menu.pause")) self._sync_pause_action() + self.analysis_menu.setTitle(t("menu.analysis")) + self.act_recompute.setText(t("menu.recompute")) + self.act_recompute.setToolTip(t("menu.recompute_tip")) + self.act_analysis_setup.setText(t("menu.analysis_setup")) + self.act_analysis_setup.setToolTip(t("menu.analysis_setup_tip")) self.view_menu.setTitle(t("menu.view")) self.act_cal_panel.setText(t("menu.calibration_panel")) self.act_finger_3d.setText(t("menu.finger_3d")) @@ -1401,10 +1408,6 @@ class StudioMainWindow(QMainWindow): self.act_settings.setText(t("menu.settings")) self.act_plot_settings.setText(t("menu.plot_settings")) self.act_rotate_arrows.setText(t("menu.rotate_arrows")) - self.act_recompute.setText(t("menu.recompute")) - self.act_recompute.setToolTip(t("menu.recompute_tip")) - self.act_analysis_setup.setText(t("menu.analysis_setup")) - self.act_analysis_setup.setToolTip(t("menu.analysis_setup_tip")) self.act_reset_view.setText(t("menu.reset_view")) self.act_reset_view.setToolTip(t("menu.reset_view_tip")) self.theme_menu.setTitle(t("menu.theme")) diff --git a/apps/studio/tests/test_bare_video_analysis.py b/apps/studio/tests/test_bare_video_analysis.py index c648acf..2e15e84 100644 --- a/apps/studio/tests/test_bare_video_analysis.py +++ b/apps/studio/tests/test_bare_video_analysis.py @@ -715,7 +715,7 @@ def test_the_prompt_restores_a_prior_reference_and_no_calibration( def test_analysis_setup_reopens_the_prompt_after_the_first_pass( bare_clip, window, monkeypatch ): - """View ▸ Analysis setup… asks again; a new reference frame starts a new pass.""" + """Analysis ▸ Analysis setup… asks again; a new reference frame starts a new pass.""" open_bare_video(window, bare_clip, monkeypatch, reference=None) settle(window) first = window.replay_ctl.recording_directory()