Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
7a11c1d
fix multilang dialog height
sshane Sep 24, 2025
6d4f568
split to file
sshane Sep 24, 2025
deb4239
stash
sshane Sep 25, 2025
4bae426
Revert "stash"
sshane Oct 20, 2025
eb0cd5c
Merge remote-tracking branch 'upstream/master' into rl-multilang
sshane Oct 20, 2025
a16adfb
add updater
sshane Oct 20, 2025
5f8b0e6
add files
sshane Oct 20, 2025
e1db692
stuff
sshane Oct 20, 2025
1c047cd
Merge remote-tracking branch 'upstream/master' into rl-multilang
sshane Oct 20, 2025
f64a5bd
try
sshane Oct 20, 2025
473370e
stash
sshane Oct 20, 2025
61ae519
works!
sshane Oct 20, 2025
c32ef45
works!
sshane Oct 20, 2025
45c4ffb
this should be the flow?
sshane Oct 20, 2025
16fe347
cursor wrapping -- it missed entire sections, changed formatting, and…
sshane Oct 21, 2025
f77676a
update translations
sshane Oct 21, 2025
3a0be67
learned my lesson
sshane Oct 21, 2025
8acd9f4
this should be the one thing it's good at
sshane Oct 21, 2025
d9b59f4
update trans
sshane Oct 21, 2025
d5e6c03
onroad wrap
sshane Oct 21, 2025
49bc4b5
spanish
sshane Oct 21, 2025
455fd2c
rename
sshane Oct 21, 2025
a7bd407
Merge remote-tracking branch 'upstream/master' into rl-multilang
sshane Oct 21, 2025
aef9f0f
clean up
sshane Oct 21, 2025
6f2a458
load all
sshane Oct 21, 2025
74762c8
Revert "load all"
sshane Oct 21, 2025
73da4c2
jp translations
sshane Oct 21, 2025
d0524b1
try jp
sshane Oct 21, 2025
80b516c
Revert "try jp"
sshane Oct 21, 2025
73dc75f
remove languages we can't add rn
sshane Oct 21, 2025
b6cba26
tr
sshane Oct 21, 2025
1106e47
pt and fr
sshane Oct 21, 2025
c9d4e2a
ai cannot be trusted
sshane Oct 21, 2025
5eee1ad
ai cannot be trusted
sshane Oct 21, 2025
edee342
missing trans
sshane Oct 21, 2025
4e6c359
add fonts
sshane Oct 21, 2025
52cb48f
Revert "remove languages we can't add rn"
sshane Oct 21, 2025
8b95e90
painfully slow to startup
sshane Oct 21, 2025
cf65454
only load what we need
sshane Oct 21, 2025
ee31e87
Reapply "remove languages we can't add rn"
sshane Oct 21, 2025
9710353
Merge remote-tracking branch 'upstream/master' into rl-multilang
sshane Oct 21, 2025
77f99e9
add system
sshane Oct 21, 2025
005cae7
that's sick that this just works (dynamic)
sshane Oct 21, 2025
9fce014
fix description falling back to first str + support callable titles i…
sshane Oct 21, 2025
bb4f792
device is now live!
sshane Oct 21, 2025
d614530
make firehose live
sshane Oct 21, 2025
2b04469
developer
sshane Oct 21, 2025
ed1fbda
network live
sshane Oct 21, 2025
91e3d0d
software live
sshane Oct 21, 2025
99bf10f
and that
sshane Oct 21, 2025
e7c2d43
toggles live
sshane Oct 21, 2025
9ec5b99
regen
sshane Oct 21, 2025
5145177
start to clean up gpt
sshane Oct 22, 2025
07f7dc0
revert op sans
sshane Oct 22, 2025
d7719f4
bruh
sshane Oct 22, 2025
e19455f
update translations
sshane Oct 22, 2025
b2b646c
rm old script
sshane Oct 22, 2025
da51a49
add noops for descriptions to fix translating away from non-english a…
sshane Oct 22, 2025
4b26138
missing de
sshane Oct 22, 2025
bd20908
do filtering in multilang.py
sshane Oct 22, 2025
83c757f
clean up
sshane Oct 22, 2025
e99b41b
codespell: ignore po
sshane Oct 22, 2025
357d5c3
fix update
sshane Oct 22, 2025
bd6ad67
should not depend
sshane Oct 22, 2025
eb32772
more live
sshane Oct 22, 2025
8fbbbb9
sidebar and offroad alert panel live
sshane Oct 22, 2025
a25806d
fix issues with offroad alerts
sshane Oct 22, 2025
04386b7
fix firehose live
sshane Oct 22, 2025
88f84d9
fix weird tr("") behavior
sshane Oct 22, 2025
6ec6086
sh key live bugfix
sshane Oct 22, 2025
32c5860
setup.py live
sshane Oct 22, 2025
60ba5d4
update
sshane Oct 22, 2025
066ccfd
update
sshane Oct 22, 2025
ba37e8b
no fuzzy matching -- breaks dynamic translations
sshane Oct 22, 2025
ac09180
rm this
sshane Oct 22, 2025
5f16bac
fix calib desc live trans
sshane Oct 22, 2025
cee5d84
change onroad
sshane Oct 22, 2025
0a63493
rm dfonts
sshane Oct 22, 2025
19cf297
clean up device
sshane Oct 22, 2025
78100e8
missing live
sshane Oct 22, 2025
be6801d
update
sshane Oct 22, 2025
951823f
op lint
sshane Oct 22, 2025
d080f70
not true
sshane Oct 22, 2025
03dee01
add to gitignore
sshane Oct 22, 2025
342b47c
speed up startup by reducing chars by ~half
sshane Oct 22, 2025
58006ea
fix scons
sshane Oct 22, 2025
2424fc9
fix crash going from qt
sshane Oct 22, 2025
c6986c2
preserve original lang
sshane Oct 22, 2025
52635b4
cancel kb live translate
sshane Oct 22, 2025
c842109
no preserve
sshane Oct 22, 2025
8a7f0d6
fix lint
sshane Oct 22, 2025
b8fc941
Merge remote-tracking branch 'upstream/master' into rl-multilang
sshane Oct 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ a.out
*.pyxbldc
*.vcd
*.qm
*.mo
*_pyx.cpp
config.json
clcache
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ quiet-level = 3
# if you've got a short variable name that's getting flagged, add it here
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl,lite"
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*, tools/plotjuggler/layouts/*"
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, *.po, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*, docs/assets/*, tools/plotjuggler/layouts/*"

[tool.mypy]
python_version = "3.11"
Expand Down
3 changes: 1 addition & 2 deletions selfdrive/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ SConscript(['controls/lib/lateral_mpc_lib/SConscript'])
SConscript(['controls/lib/longitudinal_mpc_lib/SConscript'])
SConscript(['locationd/SConscript'])
SConscript(['modeld/SConscript'])
if GetOption('extras'):
SConscript(['ui/SConscript'])
SConscript(['ui/SConscript'])
197 changes: 105 additions & 92 deletions selfdrive/ui/SConscript
Original file line number Diff line number Diff line change
@@ -1,98 +1,111 @@
import os
import json
Import('env', 'qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations')

base_libs = [common, messaging, visionipc, transformations,
'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"]

if arch == 'larch64':
base_libs.append('EGL')

if arch == "Darwin":
del base_libs[base_libs.index('OpenCL')]
qt_env['FRAMEWORKS'] += ['OpenCL']

# FIXME: remove this once we're on 5.15 (24.04)
qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"]

qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs)
widgets_src = ["qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/prime_state.cc",
"qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc",
"qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc",
"qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc",
"qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"]

widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=base_libs)
Export('widgets')
qt_libs = [widgets, qt_util] + base_libs

qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc",
"qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc",
"qt/offroad/software_settings.cc", "qt/offroad/developer_panel.cc", "qt/offroad/onboarding.cc",
"qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", "qt/offroad/firehose.cc",
"qt/onroad/onroad_home.cc", "qt/onroad/annotated_camera.cc", "qt/onroad/model.cc",
"qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc"]

# build translation files
# compile gettext .po -> .mo translations
with open(File("translations/languages.json").abspath) as f:
languages = json.loads(f.read())
translation_sources = [f"#selfdrive/ui/translations/{l}.ts" for l in languages.values()]
translation_targets = [src.replace(".ts", ".qm") for src in translation_sources]
lrelease_bin = 'third_party/qt5/larch64/bin/lrelease' if arch == 'larch64' else 'lrelease'

lrelease = qt_env.Command(translation_targets, translation_sources, f"{lrelease_bin} $SOURCES")
qt_env.NoClean(translation_sources)
qt_env.Precious(translation_sources)

# create qrc file for compiled translations to include with assets
translations_assets_src = "#selfdrive/assets/translations_assets.qrc"
with open(File(translations_assets_src).abspath, 'w') as f:
f.write('<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n')
f.write('\n'.join([f'<file alias="{l}">../ui/translations/{l}.qm</file>' for l in languages.values()]))
f.write('\n</qresource>\n</RCC>')

# build assets
assets = "#selfdrive/assets/assets.cc"
assets_src = "#selfdrive/assets/assets.qrc"
qt_env.Command(assets, [assets_src, translations_assets_src], f"rcc $SOURCES -o $TARGET")
qt_env.Depends(assets, Glob('#selfdrive/assets/*', exclude=[assets, assets_src, translations_assets_src, "#selfdrive/assets/assets.o"]) + [lrelease])
asset_obj = qt_env.Object("assets", assets)

# build main UI
qt_env.Program("ui", qt_src + [asset_obj], LIBS=qt_libs)

po_sources = [f"#selfdrive/ui/translations/app_{l}.po" for l in languages.values()]
po_sources = [src for src in po_sources if os.path.exists(File(src).abspath)]
mo_targets = [src.replace(".po", ".mo") for src in po_sources]
mo_build = []
for src, tgt in zip(po_sources, mo_targets):
mo_build.append(qt_env.Command(tgt, src, "msgfmt -o $TARGET $SOURCE"))
mo_alias = qt_env.Alias('mo', mo_build)
qt_env.AlwaysBuild(mo_alias)

if GetOption('extras'):
qt_src.remove("main.cc") # replaced by test_runner
qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs)

# build installers
if arch != "Darwin":
raylib_env = env.Clone()
raylib_env['LIBPATH'] += [f'#third_party/raylib/{arch}/']
raylib_env['LINKFLAGS'].append('-Wl,-strip-debug')

raylib_libs = common + ["raylib"]
if arch == "larch64":
raylib_libs += ["GLESv2", "EGL", "gbm", "drm"]
else:
raylib_libs += ["GL"]

release = "release3"
installers = [
("openpilot", release),
("openpilot_test", f"{release}-staging"),
("openpilot_nightly", "nightly"),
("openpilot_internal", "nightly-dev"),
]

cont = raylib_env.Command("installer/continue_openpilot.o", "installer/continue_openpilot.sh",
"ld -r -b binary -o $TARGET $SOURCE")
inter = raylib_env.Command("installer/inter_ttf.o", "installer/inter-ascii.ttf",
"ld -r -b binary -o $TARGET $SOURCE")
for name, branch in installers:
d = {'BRANCH': f"'\"{branch}\"'"}
if "internal" in name:
d['INTERNAL'] = "1"

obj = raylib_env.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d)
f = raylib_env.Program(f"installer/installers/installer_{name}", [obj, cont, inter], LIBS=raylib_libs)
# keep installers small
assert f[0].get_size() < 1900*1e3, f[0].get_size()
base_libs = [common, messaging, visionipc, transformations,
'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"]

if arch == 'larch64':
base_libs.append('EGL')

if arch == "Darwin":
del base_libs[base_libs.index('OpenCL')]
qt_env['FRAMEWORKS'] += ['OpenCL']

# FIXME: remove this once we're on 5.15 (24.04)
qt_env['CXXFLAGS'] += ["-Wno-deprecated-declarations"]

qt_util = qt_env.Library("qt_util", ["#selfdrive/ui/qt/api.cc", "#selfdrive/ui/qt/util.cc"], LIBS=base_libs)
widgets_src = ["qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/prime_state.cc",
"qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc",
"qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc",
"qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc",
"qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc"]

widgets = qt_env.Library("qt_widgets", widgets_src, LIBS=base_libs)
Export('widgets')
qt_libs = [widgets, qt_util] + base_libs

qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc",
"qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc",
"qt/offroad/software_settings.cc", "qt/offroad/developer_panel.cc", "qt/offroad/onboarding.cc",
"qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", "qt/offroad/firehose.cc",
"qt/onroad/onroad_home.cc", "qt/onroad/annotated_camera.cc", "qt/onroad/model.cc",
"qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc"]

# build translation files
translation_sources = [f"#selfdrive/ui/translations/{l}.ts" for l in languages.values()]
translation_targets = [src.replace(".ts", ".qm") for src in translation_sources]
lrelease_bin = 'third_party/qt5/larch64/bin/lrelease' if arch == 'larch64' else 'lrelease'

lrelease = qt_env.Command(translation_targets, translation_sources, f"{lrelease_bin} $SOURCES")
qt_env.NoClean(translation_sources)
qt_env.Precious(translation_sources)

# create qrc file for compiled translations to include with assets
translations_assets_src = "#selfdrive/assets/translations_assets.qrc"
with open(File(translations_assets_src).abspath, 'w') as f:
f.write('<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n')
f.write('\n'.join([f'<file alias="{l}">../ui/translations/{l}.qm</file>' for l in languages.values()]))
f.write('\n</qresource>\n</RCC>')

# build assets
assets = "#selfdrive/assets/assets.cc"
assets_src = "#selfdrive/assets/assets.qrc"
qt_env.Command(assets, [assets_src, translations_assets_src], f"rcc $SOURCES -o $TARGET")
qt_env.Depends(assets, Glob('#selfdrive/assets/*', exclude=[assets, assets_src, translations_assets_src, "#selfdrive/assets/assets.o"]) + [lrelease])
asset_obj = qt_env.Object("assets", assets)

# build main UI
qt_env.Program("ui", qt_src + [asset_obj], LIBS=qt_libs)
if GetOption('extras'):
qt_src.remove("main.cc") # replaced by test_runner
qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs)

# build installers
if arch != "Darwin":
raylib_env = env.Clone()
raylib_env['LIBPATH'] += [f'#third_party/raylib/{arch}/']
raylib_env['LINKFLAGS'].append('-Wl,-strip-debug')

raylib_libs = common + ["raylib"]
if arch == "larch64":
raylib_libs += ["GLESv2", "EGL", "gbm", "drm"]
else:
raylib_libs += ["GL"]

release = "release3"
installers = [
("openpilot", release),
("openpilot_test", f"{release}-staging"),
("openpilot_nightly", "nightly"),
("openpilot_internal", "nightly-dev"),
]

cont = raylib_env.Command("installer/continue_openpilot.o", "installer/continue_openpilot.sh",
"ld -r -b binary -o $TARGET $SOURCE")
inter = raylib_env.Command("installer/inter_ttf.o", "installer/inter-ascii.ttf",
"ld -r -b binary -o $TARGET $SOURCE")
for name, branch in installers:
d = {'BRANCH': f"'\"{branch}\"'"}
if "internal" in name:
d['INTERNAL'] = "1"

obj = raylib_env.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d)
f = raylib_env.Program(f"installer/installers/installer_{name}", [obj, cont, inter], LIBS=raylib_libs)
# keep installers small
assert f[0].get_size() < 1900*1e3, f[0].get_size()
29 changes: 14 additions & 15 deletions selfdrive/ui/layouts/settings/developer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,24 @@
from openpilot.system.ui.widgets.scroller import Scroller
from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.lib.multilang import tr, tr_noop
from openpilot.system.ui.widgets import DialogResult

# Description constants
DESCRIPTIONS = {
'enable_adb': tr(
'enable_adb': tr_noop(
"ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. " +
"See https://docs.comma.ai/how-to/connect-to-comma for more info."
),
'ssh_key': tr(
'ssh_key': tr_noop(
"Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username " +
"other than your own. A comma employee will NEVER ask you to add their GitHub username."
),
'alpha_longitudinal': tr(
'alpha_longitudinal': tr_noop(
"<b>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</b><br><br>" +
"On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. " +
"Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha."
"Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. " +
"Changing this setting will restart openpilot if the car is powered on."
),
}

Expand All @@ -35,47 +36,45 @@ def __init__(self):

# Build items and keep references for callbacks/state updates
self._adb_toggle = toggle_item(
tr("Enable ADB"),
description=DESCRIPTIONS["enable_adb"],
lambda: tr("Enable ADB"),
description=lambda: DESCRIPTIONS["enable_adb"],
initial_state=self._params.get_bool("AdbEnabled"),
callback=self._on_enable_adb,
enabled=ui_state.is_offroad,
)

# SSH enable toggle + SSH key management
self._ssh_toggle = toggle_item(
tr("Enable SSH"),
lambda: tr("Enable SSH"),
description="",
initial_state=self._params.get_bool("SshEnabled"),
callback=self._on_enable_ssh,
)
self._ssh_keys = ssh_key_item("SSH Keys", description=DESCRIPTIONS["ssh_key"])
self._ssh_keys = ssh_key_item(lambda: tr("SSH Keys"), description=lambda: DESCRIPTIONS["ssh_key"])

self._joystick_toggle = toggle_item(
tr("Joystick Debug Mode"),
lambda: tr("Joystick Debug Mode"),
description="",
initial_state=self._params.get_bool("JoystickDebugMode"),
callback=self._on_joystick_debug_mode,
enabled=ui_state.is_offroad,
)

self._long_maneuver_toggle = toggle_item(
tr("Longitudinal Maneuver Mode"),
lambda: tr("Longitudinal Maneuver Mode"),
description="",
initial_state=self._params.get_bool("LongitudinalManeuverMode"),
callback=self._on_long_maneuver_mode,
)

self._alpha_long_toggle = toggle_item(
tr("openpilot Longitudinal Control (Alpha)"),
description=DESCRIPTIONS["alpha_longitudinal"],
lambda: tr("openpilot Longitudinal Control (Alpha)"),
description=lambda: DESCRIPTIONS["alpha_longitudinal"],
initial_state=self._params.get_bool("AlphaLongitudinalEnabled"),
callback=self._on_alpha_long_enabled,
enabled=lambda: not ui_state.engaged,
)

self._alpha_long_toggle.set_description(self._alpha_long_toggle.description + " Changing this setting will restart openpilot if the car is powered on.")

items = [
self._adb_toggle,
self._ssh_toggle,
Expand Down
Loading
Loading