界面改用「精密仪器工作台」布局:顶栏压缩、视图切布局、标定与回放面板不再裁切
- What: 品牌条 40→28px 并加 实时监测/历史回放/标定 导航;导航改为切换主界面三套布局(实时=2D图像+曲线、回放=自动全程浏览、标定=标定面板 880px+曲线,2D 图像整体缩小);传感器选择(传感器 / 传感器配置 两个带 tooltip 的下拉 + 产品徽标)移到状态轨最左侧,记录模式移入设置区;新增 RecordStatusChip(记录中时长、丢帧、写入异常)与「同一时刻只有一个实心按钮」(新增 dangerOutline 描边危险样式);三轴读数移到曲线上方(16pt 等宽)、只保留最下方时间轴、网格淡化、全程浏览条可拖动;三轴配色统一为蓝/橙/绿并把语义色对比度审计扩展到 toolbar_bg;箭头页脚显示放大倍率与有效区域,深度模式才显示色条与范围;左侧面板改名「2D 图像」且固定显示图像宽高比;标定面板加纵向滚动区、九按钮分两行、六列表头 ResizeToContents;PlaybackDialog 补上从未调用的 retranslate;main() 在事件循环结束后 flush 日志并 os._exit,避免设备 SDK 原生线程把进程挂在解释器收尾。 - Why: 评审提出的 7 点:顶部占高与装饰过多、记录状态不突出、配置切换看不懂且藏得太深、切视图应换主界面布局、标定与回放面板文字被裁、关窗后命令行不退出、2D 图像无固定宽高比且名字不符。 - Verification: ui_check.py(430 项,新增 top area / instrument panels / clean shutdown 段,含中英×1280/1440 的轨不挤压检查)、test_ui_smoke.py(57 项,新增视图切换、标定不裁切、2D 宽高比、回放按钮文字、传感器选择器等用例)、drive_shared.py(146 项)、locale_studio.py(261 键齐全、zh==en、prefs 对齐)、reproduce.py、ui_snapshot.py 四张复核图。 - Not in this change: 录制文件格式、CSV/MP4 写入路径与记录通道数据流不变;三维面板仍是占位符;回放对话框(含离线深度重算)本身只修了按钮文字。
This commit is contained in:
@@ -96,6 +96,25 @@ def flow_colormap(theme: str = "dark") -> np.ndarray:
|
||||
return _lut_from_ramp(color(theme, "flow_ramp", FLOW_RAMP_FALLBACK))
|
||||
|
||||
|
||||
def arrow_display_scale(draw_style: str = "box") -> float:
|
||||
"""How much the drawn arrows amplify the measured displacement.
|
||||
|
||||
``orisys.util.draw_arrows`` divides the displacement by ``arrow_scale``, so
|
||||
the effective display magnification is its reciprocal (box ``0.5`` -> ``2x``,
|
||||
finger ``1.0`` -> ``1x``). The drawn length is additionally capped at
|
||||
``grid_spacing * 0.8`` pixels, so the returned factor describes the mapping
|
||||
only while an arrow has not hit that cap — the UI says so in its tooltip.
|
||||
"""
|
||||
draw_kw = _FINGER_ARROW_DRAW_KW if str(draw_style).lower().startswith("f") else _ARROW_DRAW_KW
|
||||
try:
|
||||
scale = float(draw_kw["arrow_scale"])
|
||||
except (KeyError, TypeError, ValueError):
|
||||
return 1.0
|
||||
if scale <= 0:
|
||||
return 1.0
|
||||
return 1.0 / scale
|
||||
|
||||
|
||||
def _ensure_bgr(img: np.ndarray) -> np.ndarray:
|
||||
if img.ndim == 2:
|
||||
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
|
||||
|
||||
@@ -32,6 +32,12 @@ _DEFAULTS: dict[str, Any] = {
|
||||
"image_view_mode": "arrows_pure",
|
||||
"arrow_rotation_deg": 90,
|
||||
"show_fps": False,
|
||||
#: The top rail's settings area (source / camera / config / units) starts
|
||||
#: collapsed: the rail is for state, not configuration.
|
||||
"settings_expanded": False,
|
||||
#: Top-level view: "custom" (a hand-arranged layout), "live", "replay" or
|
||||
#: "calibration". Each view is a layout of the same window.
|
||||
"view_preset": "custom",
|
||||
"splitter_sizes": [340, 480, 400],
|
||||
"window_default_size": [1440, 880],
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
"scrollbar_handle_hover": "#6E7C9E",
|
||||
"plot_bg": "#11161F",
|
||||
"plot_grid": "#28303F",
|
||||
"plot_fn": "#8AA6F2",
|
||||
"plot_fx": "#F45CC0",
|
||||
"plot_fy": "#D8FF00",
|
||||
"plot_fn": "#6FA8FF",
|
||||
"plot_fx": "#FF9A4D",
|
||||
"plot_fy": "#7CE0A0",
|
||||
"text_primary": "#E6EAF2",
|
||||
"text_secondary": "#9AA4B8",
|
||||
"text_muted": "#838FA6",
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
"plot_bg": "#F8FAFD",
|
||||
"plot_grid": "#DFE5EE",
|
||||
"plot_fn": "#003893",
|
||||
"plot_fx": "#B0178C",
|
||||
"plot_fy": "#4E7A00",
|
||||
"plot_fx": "#B45309",
|
||||
"plot_fy": "#2E7D32",
|
||||
"text_primary": "#141A24",
|
||||
"text_secondary": "#4A5566",
|
||||
"text_muted": "#5C6678",
|
||||
|
||||
@@ -175,6 +175,29 @@ QFrame#brandBar QFrame#sectionSeparator {{
|
||||
max-width: 1px;
|
||||
min-width: 1px;
|
||||
}}
|
||||
/* Top-rail navigation: flat items on the brand background, so the product
|
||||
colour stays the only strong colour in the rail. */
|
||||
QFrame#brandBar QPushButton#navButton {{
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
color: {c['brand_bar_fg_muted']};
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
min-height: 18px;
|
||||
padding: 1px 7px;
|
||||
}}
|
||||
QFrame#brandBar QPushButton#navButton:hover {{
|
||||
color: {c['brand_bar_fg']};
|
||||
border-color: {c['brand_bar_fg_muted']};
|
||||
}}
|
||||
QFrame#brandBar QPushButton#navButton[navActive="true"] {{
|
||||
color: {c['brand_bar_fg']};
|
||||
font-weight: 600;
|
||||
}}
|
||||
QFrame#brandBar QPushButton#navButton:focus {{
|
||||
border-color: {c['brand_bar_fg']};
|
||||
}}
|
||||
/* ---------- Buttons ---------- */
|
||||
QPushButton {{
|
||||
background-color: {c['button_bg']};
|
||||
@@ -249,10 +272,63 @@ QPushButton#ghostButton:hover {{
|
||||
background-color: {c['button_hover']};
|
||||
color: {c['text_primary']};
|
||||
}}
|
||||
/* The settings toggle advertises its own state: an open area must look open. */
|
||||
QPushButton#ghostButton[settingsOpen="true"] {{
|
||||
background-color: {c['button_hover']};
|
||||
color: {c['text_primary']};
|
||||
border-color: {c['accent']};
|
||||
}}
|
||||
/* The "outlined danger" affordance: a red action that is *not* the one filled
|
||||
button of the moment. Stop stays red and one click away without competing
|
||||
with the primary record action. */
|
||||
QPushButton#dangerOutline {{
|
||||
background-color: transparent;
|
||||
color: {c['danger']};
|
||||
border: 1px solid {c['danger']};
|
||||
font-weight: 600;
|
||||
padding: 7px 18px;
|
||||
}}
|
||||
QPushButton#dangerOutline:hover {{
|
||||
background-color: {c['danger_fill']};
|
||||
color: {c['danger_text']};
|
||||
border-color: {c['danger_fill']};
|
||||
}}
|
||||
QPushButton#dangerOutline:pressed {{
|
||||
background-color: {c['danger_fill_hover']};
|
||||
color: {c['danger_text']};
|
||||
border-color: {c['danger_fill']};
|
||||
}}
|
||||
/* Checked is the *running* state of Stop, not a press: it stays outlined, or
|
||||
the outline variant would fill in permanently the moment a session runs. */
|
||||
QPushButton#dangerOutline:checked {{
|
||||
background-color: transparent;
|
||||
color: {c['danger']};
|
||||
border-color: {c['danger']};
|
||||
}}
|
||||
QPushButton#dangerOutline:disabled {{
|
||||
color: {c['text_muted']};
|
||||
background-color: {c['window_bg']};
|
||||
border: 1px solid {c['separator']};
|
||||
}}
|
||||
QPushButton[compact="true"] {{
|
||||
padding: 6px 9px;
|
||||
font-size: 12px;
|
||||
}}
|
||||
/* Status-rail controls are one instrument line: they must not carry the
|
||||
padding a dialog button needs, or the top of the window grows to twice the
|
||||
height of the rail's own content. */
|
||||
QPushButton[rail="true"],
|
||||
QPushButton#primaryButton[rail="true"],
|
||||
QPushButton#dangerButton[rail="true"],
|
||||
QPushButton#dangerOutline[rail="true"],
|
||||
QPushButton#ghostButton[rail="true"] {{
|
||||
min-height: 18px;
|
||||
padding: 2px 12px;
|
||||
}}
|
||||
QComboBox[rail="true"] {{
|
||||
min-height: 18px;
|
||||
padding: 2px 8px;
|
||||
}}
|
||||
QToolButton {{
|
||||
background-color: transparent;
|
||||
color: {c['text_secondary']};
|
||||
@@ -507,9 +583,8 @@ QLabel#unitBadge {{
|
||||
letter-spacing: 0.4px;
|
||||
}}
|
||||
QLabel#valueCard {{
|
||||
background-color: {c['card_bg']};
|
||||
border: 1px solid {c['card_border']};
|
||||
border-radius: 8px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}}
|
||||
QLabel#statusChip {{
|
||||
color: {c['status_idle']};
|
||||
@@ -517,6 +592,14 @@ QLabel#statusChip {{
|
||||
font-weight: 600;
|
||||
padding: 0 10px 0 4px;
|
||||
}}
|
||||
/* Record state: colour is written per state by ``RecordStatusChip``; the base
|
||||
rule only fixes the weight and the spacing. */
|
||||
QLabel#recordChip {{
|
||||
color: {c['status_idle']};
|
||||
background: transparent;
|
||||
font-weight: 600;
|
||||
padding: 0 8px 0 2px;
|
||||
}}
|
||||
QLabel#aboutBody {{
|
||||
color: {c['text_secondary']};
|
||||
}}
|
||||
@@ -531,6 +614,12 @@ QFrame#cardPanel {{
|
||||
border: 1px solid {c['card_border']};
|
||||
border-radius: 8px;
|
||||
}}
|
||||
/* The axis readouts are large numbers on the panel, not three boxed cards:
|
||||
three borders side by side is exactly the "fragmented" look to avoid. */
|
||||
QFrame#valueGroup {{
|
||||
background: transparent;
|
||||
border: none;
|
||||
}}
|
||||
QFrame#sectionSeparator {{
|
||||
background-color: {c['separator']};
|
||||
border: none;
|
||||
|
||||
Reference in New Issue
Block a user