dsh UI improvement
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Render the customer UI offscreen to PNG files for visual review.
|
||||
|
||||
The tool never opens a camera and never starts acquisition: it builds the real
|
||||
main window, optionally injects deterministic demo data, then grabs the window.
|
||||
|
||||
Examples
|
||||
--------
|
||||
python tools/ui_snapshot.py --theme dark --out out_dark.png
|
||||
python tools/ui_snapshot.py --theme light --sensor finger \
|
||||
--panels cal,3d --demo --size 1600x900 --out out_light.png
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
APP_ROOT = Path(__file__).resolve().parents[1]
|
||||
REPO_ROOT = APP_ROOT.parents[1]
|
||||
for _path in (APP_ROOT / "src", REPO_ROOT / "shared" / "src"):
|
||||
if _path.is_dir() and str(_path) not in sys.path:
|
||||
sys.path.insert(0, str(_path))
|
||||
|
||||
# Silent platform must be selected before QApplication exists.
|
||||
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||
if sys.platform == "win32" and "QT_QPA_FONTDIR" not in os.environ:
|
||||
fonts = Path(os.environ.get("WINDIR", r"C:\Windows")) / "Fonts"
|
||||
if fonts.is_dir():
|
||||
os.environ["QT_QPA_FONTDIR"] = str(fonts)
|
||||
os.chdir(APP_ROOT)
|
||||
|
||||
|
||||
def _demo_data(window) -> None:
|
||||
"""Fill the plots and the calibration table with deterministic samples."""
|
||||
plots = window.force_plots
|
||||
for i in range(240):
|
||||
t = i / 30.0
|
||||
fn = 6.0 + 5.0 * math.sin(t * 1.4)
|
||||
fx = 4.0 * math.sin(t * 2.1 + 0.4)
|
||||
fy = -3.0 + 2.5 * math.cos(t * 1.1)
|
||||
plots.push(t, fn, fx, fy, unit="N")
|
||||
|
||||
cal = window.cal_panel
|
||||
cal.set_running(True)
|
||||
cal.push_raw(9.81, -0.42, 0.10)
|
||||
for weight, raw, std in ((1.0, 9.72, 0.031), (2.0, 19.51, 0.044), (5.0, 48.90, 0.061)):
|
||||
from orisys_app_shared.force.calibration_io import CalSample
|
||||
|
||||
cal._store.upsert("fn", CalSample(weight_n=weight, raw_mean=raw, n=180, std=std))
|
||||
cal._refresh_table()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--theme", choices=("dark", "light"), default="dark")
|
||||
parser.add_argument("--lang", choices=("zh_CN", "en_US"), default="zh_CN")
|
||||
parser.add_argument("--sensor", choices=("box", "mini", "finger"), default="box")
|
||||
parser.add_argument(
|
||||
"--panels",
|
||||
default="",
|
||||
help="comma list of optional panels to show: cal,3d",
|
||||
)
|
||||
parser.add_argument("--size", default="1440x880", help="WxH window size")
|
||||
parser.add_argument("--view", default="arrows_pure")
|
||||
parser.add_argument("--demo", action="store_true", help="inject demo plot/table data")
|
||||
parser.add_argument("--out", required=True, help="output PNG path")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
width, height = (int(part) for part in args.size.lower().split("x", 1))
|
||||
except ValueError:
|
||||
parser.error("--size must look like 1440x880")
|
||||
|
||||
panels = {part.strip().lower() for part in args.panels.split(",") if part.strip()}
|
||||
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
from orisys_app_shared.i18n import set_locale
|
||||
from orisys_app_shared.theme import build_qss
|
||||
from orisys_customer.app_window import CustomerMainWindow
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
set_locale(args.lang)
|
||||
app.setStyleSheet(build_qss(args.theme))
|
||||
|
||||
prefs = {
|
||||
"language": args.lang,
|
||||
"theme": args.theme,
|
||||
"sensor_type": args.sensor,
|
||||
"show_cal_panel": "cal" in panels,
|
||||
"show_finger_3d": "3d" in panels,
|
||||
"show_fps": True,
|
||||
"image_view_mode": args.view,
|
||||
}
|
||||
window = CustomerMainWindow(prefs=prefs)
|
||||
window.resize(width, height)
|
||||
window.show()
|
||||
app.processEvents()
|
||||
|
||||
if args.demo:
|
||||
_demo_data(window)
|
||||
for _ in range(4):
|
||||
app.processEvents()
|
||||
|
||||
out = Path(args.out)
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
ok = window.grab().save(str(out))
|
||||
print(f"{'saved' if ok else 'FAILED'} {out} ({width}x{height}, theme={args.theme})")
|
||||
window.close()
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user