diff --git a/selfdrive/carrot/server/features/settings.py b/selfdrive/carrot/server/features/settings.py
index 0ef09efd4a..1ac42344b1 100644
--- a/selfdrive/carrot/server/features/settings.py
+++ b/selfdrive/carrot/server/features/settings.py
@@ -22,6 +22,7 @@ async def api_settings(request: web.Request) -> web.Response:
"apilot": data.get("apilot"),
"groups": groups_list,
"items_by_group": items_by_group,
+ "categories": settings_cache.get("categories"), # 대>중>소 트리 (없으면 None → 프런트 폴백)
"unit_cycle": UNIT_CYCLE,
"has_params": HAS_PARAMS,
"has_param_type": bool(ParamKeyType is not None and hasattr(Params(), "get_type")) if HAS_PARAMS else False,
diff --git a/selfdrive/carrot/server/services/settings.py b/selfdrive/carrot/server/services/settings.py
index 7441d3e2fb..3a5762df57 100644
--- a/selfdrive/carrot/server/services/settings.py
+++ b/selfdrive/carrot/server/services/settings.py
@@ -15,6 +15,7 @@
"groups": None, # {group: [param,...]}
"by_name": None, # {name: param}
"groups_list": None, # [{group, egroup, count}, ...]
+ "categories": None, # 대>중>소 트리 ([{id,ko,en,zh,groups:[...]}]) or None when no "menu"
}
@@ -56,6 +57,71 @@ def group_index(settings: Dict[str, Any]) -> Tuple[Dict[str, list], Dict[str, Di
return groups, by_name, groups_list
+def _label(node: Dict[str, Any]) -> Dict[str, Any]:
+ return {"ko": node.get("ko"), "en": node.get("en"), "zh": node.get("zh")}
+
+
+def build_menu_categories(data: Dict[str, Any], by_name: Dict[str, Dict[str, Any]]) -> List[Dict[str, Any]] | None:
+ """Build the 대>중>소 tree from the optional top-level "menu" block.
+
+ Returns None when no "menu" is present so the frontend falls back to the
+ flat group_index view. Leaf "items" carry param *names* only; the frontend
+ resolves definitions from items_by_group to avoid duplicating param data.
+
+ Shape:
+ [ {id, ko, en, zh,
+ groups: [ {id, ko, en, zh, count,
+ sections: [ {id, ko, en, zh, items:[name,...]} ]} ]} ]
+
+ A 중-group whose menu node holds params directly (no nested "groups") is
+ normalized to a single label-less section.
+ """
+ menu = data.get("menu")
+ if not menu:
+ return None
+
+ def join_labels(nodes: List[Dict[str, Any]], key: str) -> str | None:
+ parts = [str(n.get(key) or "").strip() for n in nodes]
+ parts = [p for p in parts if p]
+ return " · ".join(parts) if parts else None
+
+ def sections_from(nodes: List[Dict[str, Any]], parents: List[Dict[str, Any]] | None = None) -> List[Dict[str, Any]]:
+ sections: List[Dict[str, Any]] = []
+ parents = parents or []
+ for node in nodes:
+ path = parents + [node]
+ children = node.get("groups") or []
+ if children:
+ sections.extend(sections_from(children, path))
+ continue
+ items = [n for n in node.get("params", []) if n in by_name]
+ if not items:
+ continue
+ sections.append({
+ "id": "__".join(str(n.get("id") or "") for n in path if n.get("id")),
+ "ko": join_labels(path, "ko"),
+ "en": join_labels(path, "en"),
+ "zh": join_labels(path, "zh"),
+ "items": items,
+ })
+ return sections
+
+ cats: List[Dict[str, Any]] = []
+ for cat in menu:
+ groups_out: List[Dict[str, Any]] = []
+ for grp in cat.get("groups", []):
+ if "groups" in grp:
+ sections = sections_from(grp["groups"])
+ else:
+ # params directly under the 중-group → single label-less section
+ sections = [{"id": grp.get("id"), "ko": None, "en": None, "zh": None,
+ "items": [n for n in grp.get("params", []) if n in by_name]}]
+ count = sum(len(s["items"]) for s in sections)
+ groups_out.append({**_label(grp), "id": grp.get("id"), "count": count, "sections": sections})
+ cats.append({**_label(cat), "id": cat.get("id"), "groups": groups_out})
+ return cats
+
+
def get_settings_cached() -> Tuple[Dict[str, Any], Dict[str, list], Dict[str, Dict[str, Any]], List[Dict[str, Any]]]:
path = settings_cache["path"]
st = os.stat(path)
@@ -69,6 +135,7 @@ def get_settings_cached() -> Tuple[Dict[str, Any], Dict[str, list], Dict[str, Di
"groups": groups,
"by_name": by_name,
"groups_list": groups_list,
+ "categories": build_menu_categories(data, by_name),
})
return (
settings_cache["data"],
diff --git a/selfdrive/carrot/web/css/components.css b/selfdrive/carrot/web/css/components.css
index f8c576af42..0cd99e50b2 100644
--- a/selfdrive/carrot/web/css/components.css
+++ b/selfdrive/carrot/web/css/components.css
@@ -62,7 +62,7 @@ body[data-page="terminal"] .app-toast-host {
.app-dialog {
position: fixed;
inset: 0;
- z-index: 160;
+ z-index: var(--z-modal);
display: flex;
align-items: center;
justify-content: center;
@@ -71,7 +71,7 @@ body[data-page="terminal"] .app-toast-host {
}
#appDialog {
- z-index: 180;
+ z-index: calc(var(--z-modal) + 10);
}
.app-dialog[hidden] {
@@ -87,31 +87,36 @@ body[data-page="terminal"] .app-toast-host {
inset: 0;
border: 0;
padding: 0;
- background: color-mix(in srgb, #000 56%, transparent);
+ background: color-mix(in srgb, #000 62%, transparent);
opacity: 0;
- transition: opacity 0.18s ease;
+ backdrop-filter: blur(2px) saturate(106%);
+ -webkit-backdrop-filter: blur(2px) saturate(106%);
+ transition: opacity var(--motion-base) var(--ease-linear);
}
.app-dialog__sheet {
position: relative;
z-index: 1;
- width: min(100%, 420px);
- max-height: calc(100dvh - var(--sp-lg) * 2);
+ width: min(100%, var(--dialog-sheet-width));
+ max-height: var(--dialog-sheet-max-height);
display: flex;
flex-direction: column;
padding: var(--sp-lg);
border: 1px solid color-mix(in srgb, var(--md-stroke-soft) 92%, transparent);
- border-radius: var(--r-lg);
+ border-radius: var(--dialog-sheet-radius);
background: color-mix(in srgb, var(--md-surface-cont) 96%, #000);
+ box-shadow: var(--shadow-4);
opacity: 0;
- transform: translateY(14px);
- transition: opacity 0.18s ease, transform 0.18s ease;
+ transform: translateY(14px) scale(0.985);
+ transition:
+ opacity var(--motion-base) var(--ease-emphasized),
+ transform var(--motion-medium) var(--ease-emphasized);
}
.app-dialog.is-open .app-dialog__backdrop,
.app-dialog.is-open .app-dialog__sheet {
opacity: 1;
- transform: translateY(0);
+ transform: translateY(0) scale(1);
}
.app-dialog__head {
@@ -157,12 +162,12 @@ body[data-page="terminal"] .app-toast-host {
.app-dialog__choices {
display: grid;
- gap: var(--sp-sm);
+ gap: 6px;
margin-top: var(--sp-md);
overflow-y: auto;
min-height: 0;
flex: 1 1 auto;
- padding-right: 4px;
+ padding-right: 2px;
}
.app-dialog__choices[hidden] {
@@ -170,19 +175,109 @@ body[data-page="terminal"] .app-toast-host {
}
.app-dialog__choiceBtn {
- width: 100%;
+ display: inline-flex;
+ align-items: center;
justify-content: center;
+ width: 100%;
+ min-width: 0;
+ padding: 0 12px;
+ border-radius: var(--dialog-choice-radius);
+ overflow: hidden;
+ text-overflow: ellipsis;
min-height: 44px;
+ font-size: var(--fs-label-md);
+ font-weight: 800;
+ letter-spacing: 0;
}
.app-dialog__choiceBtn.is-current {
border-color: color-mix(in srgb, var(--md-primary) 56%, var(--md-stroke-soft));
- background: var(--md-primary-state);
- color: var(--md-primary);
+ background: color-mix(in srgb, var(--md-surface-cont-hh) 74%, var(--md-primary-state));
+ color: var(--md-on-surface);
font-weight: 800;
- display: flex;
- align-items: center;
- gap: 8px;
+}
+
+/* 박스 안 박스 금지 — 다이얼로그 시트 자체가 박스이므로 리스트엔 테두리/배경/라운드를
+ 두지 않는다. 상·하 hairline 으로만 구역을 나누고 항목 사이는 구분선만. */
+.app-dialog__choices--list {
+ gap: 0;
+ padding: 0;
+ border: 0;
+ border-top: 1px solid color-mix(in srgb, var(--md-stroke-soft) 30%, transparent);
+ border-bottom: 1px solid color-mix(in srgb, var(--md-stroke-soft) 30%, transparent);
+ background: transparent;
+}
+
+/* list 항목은 .app-dialog__choices--list 하위로 묶어 우선순위를 .btn(파일 뒤쪽
+ 정의, 알약 라운드+1px 보더)보다 높인다. 그래야 사각·풀폭 행이 확실히 유지돼
+ 선택/포커스 시 둥근 박스가 컨테이너 보더와 겹치지 않는다. */
+.app-dialog__choices--list .app-dialog__choiceBtn--action {
+ justify-content: space-between;
+ text-align: left;
+ white-space: normal;
+ line-height: 1.25;
+ min-height: 48px;
+ padding: 0 14px;
+ border: 0;
+ border-bottom: 1px solid color-mix(in srgb, var(--md-stroke-soft) 40%, transparent);
+ border-radius: 0;
+ background: transparent;
+ box-shadow: none;
+}
+
+.app-dialog__choices--list .app-dialog__choiceBtn--action:last-child {
+ border-bottom: 0;
+}
+
+/* 즉시 동작(Play/Upload/Delete…)에 navigation chevron(›)은 오해를 부른다 → 없음 */
+.app-dialog__choices--list .app-dialog__choiceBtn--action::after {
+ content: "";
+ display: none;
+}
+
+/* 호버/포커스: 둥근 포커스링·보더 대신 풀폭 배경만 (선 겹침 방지) */
+.app-dialog__choices--list .app-dialog__choiceBtn--action:hover,
+.app-dialog__choices--list .app-dialog__choiceBtn--action:focus-visible {
+ background: color-mix(in srgb, var(--md-on-surface) 8%, transparent);
+ border-bottom-color: color-mix(in srgb, var(--md-stroke-soft) 40%, transparent);
+ border-radius: 0;
+ outline: none;
+ box-shadow: none;
+}
+
+.app-dialog__choices--list .app-dialog__choiceBtn--action.is-current {
+ color: var(--md-on-surface);
+ background: color-mix(in srgb, var(--md-primary) 14%, transparent);
+ border-bottom-color: color-mix(in srgb, var(--md-stroke-soft) 40%, transparent);
+}
+
+/* 선택된 항목만 체크(✓) — 자체완결 */
+.app-dialog__choices--list .app-dialog__choiceBtn--action.is-current::after {
+ content: "";
+ display: block;
+ width: 6px;
+ height: 11px;
+ margin-left: 12px;
+ border-right: 2px solid color-mix(in srgb, var(--md-primary) 82%, var(--md-on-surface));
+ border-bottom: 2px solid color-mix(in srgb, var(--md-primary) 82%, var(--md-on-surface));
+ transform: rotate(45deg);
+ flex: 0 0 auto;
+}
+
+.app-dialog__choices--value-grid {
+ grid-template-columns: repeat(var(--app-dialog-choice-columns, 5), minmax(0, 1fr));
+ gap: 6px;
+}
+
+.app-dialog__choiceBtn--value {
+ min-height: 42px;
+ padding: 0 6px;
+ justify-content: center;
+ border-radius: var(--dialog-choice-grid-radius);
+ background: var(--md-surface-cont-h);
+ text-align: center;
+ white-space: nowrap;
+ font-variant-numeric: tabular-nums;
}
.app-dialog__inputWrap {
@@ -201,12 +296,66 @@ body[data-page="terminal"] .app-toast-host {
.app-dialog__actions {
display: flex;
justify-content: flex-end;
- gap: var(--sp-sm);
+ gap: 8px;
flex-wrap: wrap;
- margin-top: var(--sp-lg);
+ margin-top: var(--sp-md);
flex-shrink: 0;
}
+.app-dialog__actions .smallBtn,
+.app-dialog__actions .btn {
+ border-radius: var(--dialog-control-radius);
+}
+
+.app-dialog--choice-grid .app-dialog__sheet,
+.app-dialog--choice-value-grid .app-dialog__sheet {
+ width: min(100%, var(--dialog-sheet-width));
+ max-height: min(82dvh, 640px);
+ padding: var(--sp-lg);
+}
+
+.app-dialog--choice-grid .app-dialog__body,
+.app-dialog--choice-value-grid .app-dialog__body {
+ flex: 0 0 auto;
+ font-size: var(--fs-label-sm);
+ line-height: 1.4;
+}
+
+@media (max-width: 640px) and (orientation: portrait) {
+ .app-dialog {
+ align-items: center;
+ padding: calc(12px + env(safe-area-inset-top, 0px)) 8px calc(12px + env(safe-area-inset-bottom, 0px));
+ }
+
+ .app-dialog__sheet {
+ width: calc(100vw - 16px);
+ max-height: var(--dialog-sheet-mobile-max-height);
+ padding: 14px;
+ border-radius: var(--dialog-sheet-radius-mobile);
+ transform: translateY(10px) scale(0.985);
+ }
+
+ .app-dialog__head {
+ margin-bottom: 6px;
+ }
+
+ .app-dialog__title {
+ font-size: var(--fs-title-xs);
+ }
+
+ .app-dialog__body {
+ font-size: var(--fs-body-sm);
+ }
+
+ .app-dialog__choiceBtn {
+ min-height: 42px;
+ }
+
+ .app-dialog__choiceBtn--value {
+ min-height: 40px;
+ }
+}
+
.app-branch-picker__sheet {
width: min(100%, 500px);
max-height: min(72vh, 560px);
diff --git a/selfdrive/carrot/web/css/hud_card.css b/selfdrive/carrot/web/css/hud_card.css
index 606eb2e033..c82e77ce8e 100644
--- a/selfdrive/carrot/web/css/hud_card.css
+++ b/selfdrive/carrot/web/css/hud_card.css
@@ -734,3 +734,35 @@
width: min(100%, var(--hud-max-width));
}
}
+
+/* ── 기어 띄움(floating) — 설정속도 칼럼 우측 빈 공간(중앙)으로 이동 ──
+ 기존엔 차간거리 막대 옆 디테일 영역에 끼어 어색했음. 절대배치라 다른 요소
+ 레이아웃은 안 건드린다. top/right 값은 실기기 보고 미세조정. */
+.hudSupportColumn {
+ position: relative;
+}
+
+.hudWrap .hudSupportColumn > .hudGearStatus--floating {
+ position: absolute;
+ top: 40%;
+ right: calc(var(--hud-padding) * 0.20);
+ transform: translateY(-50%);
+ min-width: 0;
+ max-width: none;
+ align-items: flex-end;
+ text-align: right;
+ z-index: 1;
+}
+
+.hudWrap .hudSupportColumn > .hudGearStatus--floating .hudGearStep,
+.hudWrap .hudSupportColumn > .hudGearStatus--floating .hudGearLabel,
+.hudWrap .hudSupportColumn > .hudGearStatus--floating .hudGearValue {
+ width: auto;
+ text-align: right;
+}
+
+/* 모든 초록 HUD에서 기어 모양 동일하게 — veryCompact·micro 의 GEAR 라벨 숨김을 덮어
+ 라벨을 항상 노출 (단, 0~7 단수 hudGearStep 의 hidden 동작은 그대로 둠). */
+.hudWrap .hudSupportColumn > .hudGearStatus--floating .hudGearLabel {
+ display: block;
+}
diff --git a/selfdrive/carrot/web/css/pages/settings/base.css b/selfdrive/carrot/web/css/pages/settings/base.css
index de73beb8ec..fc24b6a6db 100644
--- a/selfdrive/carrot/web/css/pages/settings/base.css
+++ b/selfdrive/carrot/web/css/pages/settings/base.css
@@ -24,6 +24,8 @@
}
.page--setting #items > .setting.ui-stagger-item,
+.page--setting #items > .setting-section-block.ui-stagger-item,
+.page--setting #items > .setting-group-card.ui-stagger-item,
.page--setting #items > .setting-profile-section.ui-stagger-item,
.page--setting #deviceItems > .setting.ui-stagger-item {
animation-name: setting-item-stagger-in;
@@ -272,6 +274,11 @@
border-color: #ffab66;
color: #111;
box-shadow: 0 12px 28px rgba(255, 135, 58, 0.22);
+ transition:
+ background 0.18s ease,
+ border-color 0.18s ease,
+ box-shadow 0.2s ease,
+ transform 0.2s cubic-bezier(0.2, 0, 0, 1);
}
.fab--setting-menu.active,
@@ -282,15 +289,48 @@
box-shadow: 0 12px 30px rgba(255, 135, 58, 0.3);
}
+.fab--setting-menu:active {
+ transform: scale(0.94);
+}
+
+.setting-fab-menu.is-open .fab--setting-menu {
+ animation: setting-fab-pop 0.28s cubic-bezier(0.2, 0, 0, 1);
+ box-shadow: 0 16px 34px rgba(255, 135, 58, 0.34);
+}
+
.fab--setting-menu svg {
width: 26px;
height: 26px;
- transition: transform 0.24s cubic-bezier(0.2, 0, 0, 1);
+ transition: transform 0.26s cubic-bezier(0.2, 0, 0, 1);
+}
+
+.fab--setting-menu .setting-fab-menu-icon {
+ fill: none;
+}
+
+.fab--setting-menu .setting-fab-menu-icon path,
+.fab--setting-menu .setting-fab-menu-icon circle {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 2;
+ stroke-linecap: round;
+ stroke-linejoin: round;
}
-/* Rotate the "+" into an "x" when the menu is open */
.fab--setting-menu[aria-expanded="true"] svg {
- transform: rotate(135deg);
+ transform: rotate(90deg) scale(0.92);
+}
+
+@keyframes setting-fab-pop {
+ 0% {
+ transform: scale(0.92);
+ }
+ 58% {
+ transform: scale(1.04);
+ }
+ 100% {
+ transform: scale(1);
+ }
}
@media (prefers-reduced-motion: reduce) {
@@ -299,6 +339,9 @@
.fab--setting-menu svg {
transition: none !important;
}
+ .setting-fab-menu.is-open .fab--setting-menu {
+ animation: none !important;
+ }
.setting-fab-menu.is-open .setting-fab-action {
transition-delay: 0ms !important;
}
diff --git a/selfdrive/carrot/web/css/pages/settings/device.css b/selfdrive/carrot/web/css/pages/settings/device.css
index 1b8de5b42e..59d9201c56 100644
--- a/selfdrive/carrot/web/css/pages/settings/device.css
+++ b/selfdrive/carrot/web/css/pages/settings/device.css
@@ -102,10 +102,8 @@
margin-top: 6px;
color: var(--md-on-surface-var);
font-size: var(--fs-body-sm);
- display: -webkit-box;
- overflow: hidden;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 2;
+ display: block;
+ overflow: visible;
}
.setting-search-result__mark {
@@ -134,7 +132,7 @@
.setting-search-panel {
--setting-search-form-width: clamp(360px, 34vw, 540px);
--setting-search-results-width: min(64vw, 820px);
- --setting-search-results-max-height: min(60dvh, 560px);
+ --setting-search-results-max-height: min(72dvh, 680px);
gap: 14px;
padding-top: calc(22px + env(safe-area-inset-top, 0px));
padding-bottom: calc(var(--nav-bar-height-desktop) + 18px + env(safe-area-inset-bottom, 0px));
@@ -219,7 +217,7 @@
.setting-search-panel {
--setting-search-form-width: calc(100vw - 28px);
--setting-search-results-width: calc(100vw - 28px);
- --setting-search-results-max-height: min(56dvh, 420px);
+ --setting-search-results-max-height: min(68dvh, 560px);
gap: 12px;
padding: calc(14px + env(safe-area-inset-top, 0px)) 12px calc(var(--nav-bar-height) + 14px + env(safe-area-inset-bottom, 0px));
}
@@ -232,7 +230,7 @@
@media (max-width: 640px) and (orientation: portrait) {
.page--setting #settingScreenItems {
- padding-top: calc(var(--setting-fixed-subnav-height, 174px) + 10px);
+ padding-top: 0;
}
.page--setting #settingScreenItems.setting-screen-items--profile {
@@ -286,21 +284,7 @@
}
.page--setting #settingSubnavWrap {
- position: fixed !important;
- top: 0 !important;
- right: 0 !important;
- left: 0 !important;
- z-index: 90;
- width: 100dvw;
- margin: 0 !important;
- padding: calc(8px + env(safe-area-inset-top, 0px)) var(--sp-lg) 12px;
- background: color-mix(in srgb, var(--md-surface) 98%, #000);
- border-bottom: 1px solid color-mix(in srgb, var(--md-primary) 42%, var(--md-outline-var));
- box-shadow:
- 0 10px 22px rgba(0, 0, 0, 0.34),
- inset 0 -1px 0 rgba(255, 255, 255, 0.04);
- transform: none !important;
- will-change: auto !important;
+ display: none !important;
}
.page--setting #settingSubnavWrap::after {
@@ -310,7 +294,7 @@
@media (max-height: 760px) {
.setting-search-panel {
- --setting-search-results-max-height: min(48dvh, 300px);
+ --setting-search-results-max-height: min(64dvh, 520px);
gap: 10px;
padding-top: calc(12px + env(safe-area-inset-top, 0px));
}
@@ -364,6 +348,9 @@
box-sizing: border-box;
scrollbar-gutter: stable;
transition: none;
+ /* One UI 스타일 스크롤 가장자리 페이드 (상 14px / 하 24px) */
+ -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 14px, #000 calc(100% - 24px), transparent 100%);
+ mask-image: linear-gradient(to bottom, transparent 0, #000 14px, #000 calc(100% - 24px), transparent 100%);
}
.page.page--setting > #settingScreenHost > #settingScreenGroups {
@@ -547,7 +534,7 @@
.setting-search-panel {
--setting-search-form-width: min(76vw, 540px);
--setting-search-results-width: min(82vw, 760px);
- --setting-search-results-max-height: min(48dvh, 260px);
+ --setting-search-results-max-height: min(68dvh, 520px);
gap: 10px;
padding: calc(12px + env(safe-area-inset-top, 0px)) 12px calc(var(--nav-bar-height) + 12px + env(safe-area-inset-bottom, 0px));
}
@@ -615,6 +602,275 @@
max-width: var(--setting-control-value);
}
+.page--setting #settingScreenItems .ctrl--toggle,
+.page--setting #settingScreenItems .ctrl--value,
+.page--setting #settingScreenItems .ctrl--segmented,
+.page--setting #settingScreenItems .ctrl--select {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ width: auto;
+}
+
+.page--setting #settingScreenItems .ctrl--value {
+ display: inline-grid;
+ grid-template-columns: 38px minmax(66px, auto) 38px;
+ gap: 0;
+ overflow: hidden;
+ border: 1px solid color-mix(in srgb, var(--md-outline-var) 54%, transparent);
+ border-radius: var(--r-md);
+ background: var(--md-surface-cont-h);
+}
+
+.page--setting #settingScreenItems .ctrl--value > :nth-child(1),
+.page--setting #settingScreenItems .ctrl--value > :nth-child(2),
+.page--setting #settingScreenItems .ctrl--value > :nth-child(3) {
+ grid-row: 1;
+}
+
+.page--setting #settingScreenItems .ctrl--value .val {
+ position: relative;
+ width: auto;
+ min-width: 66px;
+ max-width: min(120px, 34vw);
+ min-height: 32px;
+ padding: 0 10px;
+ border: 0;
+ border-left: 1px solid color-mix(in srgb, var(--md-outline-var) 34%, transparent);
+ border-right: 1px solid color-mix(in srgb, var(--md-outline-var) 34%, transparent);
+ border-radius: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ text-align: center;
+}
+
+.page--setting #settingScreenItems .setting-value-compact {
+ border-color: transparent;
+ background: color-mix(in srgb, var(--md-surface-cont-hh) 72%, var(--md-surface-cont-h));
+ color: var(--md-on-surface);
+ box-shadow: none;
+ font-weight: 900;
+}
+
+.page--setting #settingScreenItems .setting-value-arrow {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 38px;
+ min-width: 38px;
+ min-height: 32px;
+ padding: 0;
+ border: 0;
+ border-radius: 0;
+ background: transparent;
+ color: var(--md-on-surface);
+ font-size: var(--fs-label-sm);
+ font-weight: 900;
+ line-height: 1;
+ touch-action: manipulation;
+}
+
+.page--setting #settingScreenItems .setting-value-arrow:active,
+.page--setting #settingScreenItems .setting-value-arrow.is-holding,
+.page--setting #settingScreenItems .setting-step:active,
+.page--setting #settingScreenItems .setting-step.is-holding {
+ background: color-mix(in srgb, var(--md-surface-cont-hh) 88%, var(--md-on-surface));
+}
+
+.page--setting #settingScreenItems .setting-icon {
+ display: block;
+ width: 18px;
+ height: 18px;
+}
+
+.page--setting #settingScreenItems .setting-icon path {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 2.7;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.page--setting #settingScreenItems .ctrl--toggle .val,
+.page--setting #settingScreenItems .ctrl--segmented .val,
+.page--setting #settingScreenItems .ctrl--select .val {
+ display: none;
+}
+
+.page--setting #settingScreenItems .setting-switch {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ width: 54px;
+ height: 32px;
+ cursor: pointer;
+ -webkit-tap-highlight-color: transparent;
+}
+
+.page--setting #settingScreenItems .setting-switch__input {
+ position: absolute;
+ opacity: 0;
+ pointer-events: none;
+}
+
+.page--setting #settingScreenItems .setting-switch__track {
+ position: relative;
+ display: block;
+ width: 100%;
+ height: 100%;
+ border: 1px solid color-mix(in srgb, var(--md-outline-var) 50%, transparent);
+ border-radius: 999px;
+ background: var(--md-surface-cont-h);
+ transition: background 0.16s ease, border-color 0.16s ease;
+}
+
+.page--setting #settingScreenItems .setting-switch__track::after {
+ content: "";
+ position: absolute;
+ top: 3px;
+ left: 3px;
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ background: var(--md-on-surface-var);
+ box-shadow: var(--shadow-1);
+ transition: transform 0.18s cubic-bezier(.2, 0, 0, 1), background 0.16s ease;
+}
+
+.page--setting #settingScreenItems .setting-switch__input:checked + .setting-switch__track {
+ border-color: color-mix(in srgb, var(--md-primary) 72%, var(--md-outline-var));
+ background: color-mix(in srgb, var(--md-primary) 70%, var(--md-surface-cont-h));
+}
+
+.page--setting #settingScreenItems .setting-switch__input:checked + .setting-switch__track::after {
+ transform: translateX(22px);
+ background: var(--md-on-primary);
+}
+
+.page--setting #settingScreenItems .setting-switch:focus-within .setting-switch__track,
+.page--setting #settingScreenItems .setting-segment:focus-visible,
+.page--setting #settingScreenItems .setting-select:focus-visible,
+.page--setting #settingScreenItems .setting-slider__input:focus-visible {
+ outline: var(--focus-ring-width, 2px) solid var(--focus-ring-color, var(--md-primary));
+ outline-offset: 2px;
+}
+
+.page--setting #settingScreenItems .setting-segments {
+ display: inline-flex;
+ max-width: min(216px, 100%);
+ overflow: hidden;
+ border: 1px solid color-mix(in srgb, var(--md-outline-var) 54%, transparent);
+ border-radius: var(--r-md);
+ background: var(--md-surface-cont-h);
+}
+
+.page--setting #settingScreenItems .setting-segment {
+ min-width: 38px;
+ min-height: 32px;
+ padding: 0 10px;
+ border: 0;
+ border-right: 1px solid color-mix(in srgb, var(--md-outline-var) 34%, transparent);
+ background: transparent;
+ color: var(--md-on-surface-var);
+ font-size: var(--fs-label-sm);
+ font-weight: 800;
+}
+
+.page--setting #settingScreenItems .setting-segment:last-child {
+ border-right: 0;
+}
+
+.page--setting #settingScreenItems .setting-segment.is-active {
+ background: var(--md-primary-state);
+ color: var(--md-primary);
+}
+
+.page--setting #settingScreenItems .setting-select {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 92px;
+ min-height: 32px;
+ padding: 0 14px;
+ border: 1px solid color-mix(in srgb, var(--md-outline-var) 54%, transparent);
+ border-radius: var(--r-md);
+ background: var(--md-surface-cont-h);
+ color: var(--md-on-surface);
+ font-family: inherit;
+ font-size: var(--fs-label-sm);
+ font-weight: 850;
+ line-height: 1;
+ text-align: center;
+ cursor: pointer;
+ touch-action: manipulation;
+ -webkit-tap-highlight-color: transparent;
+ appearance: none;
+}
+
+.page--setting #settingScreenItems .ctrl--slider {
+ grid-template-columns: var(--setting-control-side) var(--setting-control-value) var(--setting-control-side);
+}
+
+.page--setting #settingScreenItems .ctrl--slider .setting-slider {
+ grid-column: 1 / -1;
+ grid-row: 1;
+ width: 100%;
+}
+
+.page--setting #settingScreenItems .ctrl--slider .setting-step--minus {
+ grid-column: 1;
+ grid-row: 2;
+}
+
+.page--setting #settingScreenItems .ctrl--slider .val {
+ grid-column: 2;
+ grid-row: 2;
+}
+
+.page--setting #settingScreenItems .ctrl--slider .setting-step--plus {
+ grid-column: 3;
+ grid-row: 2;
+}
+
+.page--setting #settingScreenItems .setting-slider__input {
+ width: 100%;
+ accent-color: var(--md-primary);
+}
+
+.page--setting #settingScreenItems .setting {
+ position: relative;
+}
+
+.page--setting #settingScreenItems .setting--has-unit-cycle {
+ padding-bottom: var(--sp-md);
+}
+
+.page--setting #settingScreenItems .setting-unit-cycle {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin: 8px 0 0 auto;
+ min-width: 54px;
+ min-height: 32px;
+ padding: 0 12px;
+ border: 1px solid color-mix(in srgb, var(--md-outline-var) 54%, transparent);
+ border-radius: var(--r-md);
+ background: color-mix(in srgb, var(--md-surface-cont-hh) 72%, var(--md-surface-cont-h));
+ color: var(--md-on-surface);
+ font-size: var(--fs-label-sm);
+ font-weight: 900;
+ line-height: 1;
+ letter-spacing: 0;
+ box-shadow: none;
+}
+
+.page--setting #settingScreenItems .setting-unit-cycle:active {
+ border-color: color-mix(in srgb, var(--md-outline-var) 68%, transparent);
+ background: color-mix(in srgb, var(--md-surface-cont-hh) 88%, var(--md-on-surface));
+ color: var(--md-on-surface);
+}
+
.page--setting #settingScreenItems .setting-copy {
min-width: 0;
max-width: 100%;
@@ -655,10 +911,84 @@
fill: currentColor;
}
+.page--setting #settingScreenItems > .row-between.mb-sm {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 8px;
+ align-items: end;
+ min-height: 56px;
+ margin: 0 0 14px;
+ padding: 2px 2px 10px;
+}
+
+.page--setting #settingScreenItems #itemsTitle {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+ color: var(--md-on-surface);
+ font-size: 34px;
+ font-weight: 900;
+ line-height: 1;
+ letter-spacing: 0;
+}
+
+.page--setting #settingScreenItems .setting-title-backIcon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 42px;
+ height: 42px;
+ flex: 0 0 42px;
+ margin-left: -10px;
+ border: 0;
+ border-radius: 999px;
+ background: transparent;
+ color: var(--md-on-surface);
+ transition: background 0.14s ease, color 0.14s ease, transform 0.14s ease;
+}
+
+.page--setting #settingScreenItems #itemsTitle:active .setting-title-backIcon {
+ background: color-mix(in srgb, var(--md-on-surface) 10%, transparent);
+ color: var(--md-on-surface);
+ transform: translateX(-1px);
+}
+
+.page--setting #settingScreenItems .setting-title-backIcon .setting-icon {
+ width: 24px;
+ height: 24px;
+}
+
+.page--setting #settingScreenItems .setting-title-backIcon .setting-icon path {
+ stroke-width: 3.05;
+}
+
+.page--setting #settingScreenItems .setting-title-text {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.page--setting.setting-layout-split #settingScreenItems .setting-title-backIcon {
+ display: none;
+}
+
+.page--setting #settingScreenItems #groupMeta {
+ padding-bottom: 3px;
+ color: var(--md-on-surface-var);
+ font-size: var(--fs-label-sm);
+ font-weight: 800;
+}
+
.page--setting #settingScreenItems .setting.is-longpressing {
background: color-mix(in srgb, #7dd3fc 7%, transparent);
}
+.page--setting #settingScreenItems.setting-screen-items--detail #items::after {
+ display: none;
+}
+
.page--setting #settingScreenItems .setting-favorites-empty {
max-width: min(460px, 100%);
margin: 0 auto;
@@ -740,16 +1070,24 @@
@media (max-width: 640px) and (orientation: portrait) {
.page--setting #settingScreenItems > .row-between.mb-sm {
- min-height: 30px;
- margin-bottom: 8px;
+ min-height: 48px;
+ margin-bottom: 10px;
padding-bottom: 8px;
- border-bottom: 1px solid color-mix(in srgb, var(--md-outline-var) 30%, transparent);
+ }
+
+ .page--setting #settingScreenItems #itemsTitle {
+ font-size: 28px;
}
.page--setting #settingScreenItems .setting {
padding: 18px 0 20px;
}
+ .page--setting #settingScreenItems .setting-group-card__body > .setting {
+ padding-left: var(--sp-lg);
+ padding-right: var(--sp-lg);
+ }
+
.page--setting #settingScreenItems #items::after {
content: "";
display: block;
@@ -773,12 +1111,30 @@
max-width: 100%;
}
+ .page--setting #settingScreenItems .ctrl--toggle,
+ .page--setting #settingScreenItems .ctrl--value,
+ .page--setting #settingScreenItems .ctrl--segmented,
+ .page--setting #settingScreenItems .ctrl--select {
+ width: auto;
+ }
+
.page--setting #settingScreenItems .smallBtn,
.page--setting #settingScreenItems .val {
min-height: 34px;
font-size: 12px;
}
+ .page--setting #settingScreenItems .ctrl--value .val,
+ .page--setting #settingScreenItems .setting-value-arrow {
+ min-height: 36px;
+ font-size: var(--fs-label-sm);
+ }
+
+ .page--setting #settingScreenItems .setting-unit-cycle {
+ min-height: 32px;
+ font-size: var(--fs-label-sm);
+ }
+
.page--setting #settingScreenItems .title,
.page--setting #settingScreenItems .name {
text-align: left;
diff --git a/selfdrive/carrot/web/css/pages/settings/panels.css b/selfdrive/carrot/web/css/pages/settings/panels.css
index 1c32188c57..7fcc29fe5e 100644
--- a/selfdrive/carrot/web/css/pages/settings/panels.css
+++ b/selfdrive/carrot/web/css/pages/settings/panels.css
@@ -2,7 +2,7 @@
.setting-search-panel {
--setting-search-form-width: clamp(320px, 42vw, 520px);
--setting-search-results-width: min(72vw, 760px);
- --setting-search-results-max-height: min(58dvh, 520px);
+ --setting-search-results-max-height: min(72dvh, 680px);
position: fixed;
inset: 0;
z-index: 171;
@@ -525,6 +525,8 @@
@media (prefers-reduced-motion: reduce) {
.setting-profile-panel,
.page--setting #items > .setting.ui-stagger-item,
+ .page--setting #items > .setting-section-block.ui-stagger-item,
+ .page--setting #items > .setting-group-card.ui-stagger-item,
.page--setting #items > .setting-profile-section.ui-stagger-item,
.page--setting #deviceItems > .setting.ui-stagger-item,
.setting-profile-section.is-collapsing .setting-profile-section__body,
@@ -539,3 +541,65 @@
}
}
+/* ── 대(category) 구분 헤더 — carrot_settings.json menu 기반 그룹목록 ── */
+.setting-category-divider {
+ padding-top: var(--sp-lg);
+}
+
+.setting-category-divider strong {
+ color: var(--md-primary);
+ font-size: var(--fs-label-md);
+ font-weight: 900;
+ letter-spacing: 0.01em;
+}
+
+.setting-category-divider span {
+ background: color-mix(in srgb, var(--md-primary) 30%, transparent);
+}
+
+/* ── 소(subgroup) 그룹박스 카드 — Material 3 / One UI ──
+ 항목 화면에서 소-섹션을 둥근 카드로 묶는다. 카드 배경은 페이지(--md-surface)
+ 보다 한 단계 밝은 surface-cont. 행(.setting)은 카드 안에서 hairline 으로 구분되고
+ :last-child 는 자동으로 선이 사라진다. */
+.setting-section-block {
+ display: grid;
+ gap: 8px;
+ margin: 0 0 var(--sp-lg);
+}
+
+.setting-group-card {
+ background: var(--md-surface-cont);
+ border: 1px solid color-mix(in srgb, var(--md-outline-var) 22%, transparent);
+ border-radius: var(--r-xl);
+ padding: 0 var(--sp-lg);
+ margin: 0;
+ box-shadow: var(--shadow-1);
+}
+
+.setting-group-card__title {
+ padding: 0 2px;
+ color: var(--md-primary);
+ font-size: var(--fs-title-sm);
+ font-weight: 900;
+ letter-spacing: 0;
+}
+
+.setting-group-card__body > .setting {
+ margin-left: calc(-1 * var(--sp-lg));
+ margin-right: calc(-1 * var(--sp-lg));
+ border-radius: 0;
+ padding-left: var(--sp-lg);
+ padding-right: var(--sp-lg);
+ border-bottom: 1px solid color-mix(in srgb, var(--md-stroke-soft) 32%, transparent);
+}
+
+.setting-group-card__body > .setting:first-child {
+ border-top-left-radius: calc(var(--r-xl) - 1px);
+ border-top-right-radius: calc(var(--r-xl) - 1px);
+}
+
+.setting-group-card__body > .setting:last-child {
+ border-bottom-left-radius: calc(var(--r-xl) - 1px);
+ border-bottom-right-radius: calc(var(--r-xl) - 1px);
+ border-bottom: none;
+}
diff --git a/selfdrive/carrot/web/css/tokens.css b/selfdrive/carrot/web/css/tokens.css
index 3717d4a14a..6d0d809208 100644
--- a/selfdrive/carrot/web/css/tokens.css
+++ b/selfdrive/carrot/web/css/tokens.css
@@ -84,6 +84,22 @@
--r-2xl: 32px;
--r-pill: 999px;
+ /* Popup UX primitives
+ - Compact sheets for alert / confirm / prompt.
+ - Bottom sheets on narrow portrait screens.
+ - Value grids for short numeric or code choices.
+ - Action lists for commands and destructive choices.
+ - Pill radius is reserved for FABs, switches, and small chips. */
+ --dialog-sheet-radius: 16px;
+ --dialog-sheet-radius-mobile: 18px;
+ --dialog-control-radius: 8px;
+ --dialog-choice-radius: 8px;
+ --dialog-choice-grid-radius: 8px;
+ --dialog-sheet-width: 420px;
+ --dialog-sheet-width-wide: 520px;
+ --dialog-sheet-max-height: calc(100dvh - var(--sp-lg) * 2);
+ --dialog-sheet-mobile-max-height: min(88dvh, 720px);
+
/* ── Elevation ────────────────────────────────────────────────
Material 3 dark elevation. Pick the smallest level that reads
as "raised". Larger = more separation from background.
diff --git a/selfdrive/carrot/web/index.html b/selfdrive/carrot/web/index.html
index c9af3cb7c5..535b6f152e 100644
--- a/selfdrive/carrot/web/index.html
+++ b/selfdrive/carrot/web/index.html
@@ -148,8 +148,11 @@
Mode
@@ -566,11 +569,12 @@ Home
(--)
-
+
+
+
diff --git a/selfdrive/carrot/web/js/app.js b/selfdrive/carrot/web/js/app.js
index 20c383cd5c..72ea86689f 100644
--- a/selfdrive/carrot/web/js/app.js
+++ b/selfdrive/carrot/web/js/app.js
@@ -28,7 +28,16 @@ window.addEventListener("popstate", async (ev) => {
const targetGroup = CURRENT_GROUP || getLandscapeDefaultSettingGroup();
if (targetGroup) {
CURRENT_GROUP = targetGroup;
- await activateSettingGroup(targetGroup, false, { scrollMode: "restore", animateGroups: false, animateItems: false });
+ if (screen === "detail" && st.settingName) {
+ showSettingScreen("items", false);
+ await renderItems(targetGroup, {
+ detailName: st.settingName,
+ scrollMode: "restore",
+ animateItems: false,
+ });
+ } else {
+ await activateSettingGroup(targetGroup, false, { scrollMode: "restore", animateGroups: false, animateItems: false });
+ }
} else {
showSettingScreen("groups", false);
}
@@ -38,7 +47,14 @@ window.addEventListener("popstate", async (ev) => {
return;
}
- if (screen === "items" && CURRENT_GROUP) {
+ if (screen === "detail" && CURRENT_GROUP && st.settingName) {
+ showSettingScreen("items", false);
+ renderItems(CURRENT_GROUP, {
+ detailName: st.settingName,
+ scrollMode: "restore",
+ animateItems: false,
+ });
+ } else if (screen === "items" && CURRENT_GROUP) {
showSettingScreen("items", false);
renderItems(CURRENT_GROUP, { scrollMode: "restore", animateItems: false });
} else {
diff --git a/selfdrive/carrot/web/js/pages/logs/dashcam.js b/selfdrive/carrot/web/js/pages/logs/dashcam.js
index 74d4782717..decb933208 100644
--- a/selfdrive/carrot/web/js/pages/logs/dashcam.js
+++ b/selfdrive/carrot/web/js/pages/logs/dashcam.js
@@ -1268,6 +1268,7 @@ async function showDashcamSegmentMenu(route, segment) {
mode: "choice",
title: `SEG ${dashcamSegmentIndex(segment)}`,
message: segment,
+ choiceLayout: "list",
choices: [
{ label: getUIText("play", "Play"), value: "play" },
{ label: getUIText("log_upload", "Upload Logs"), value: "upload" },
@@ -1497,10 +1498,11 @@ async function showDashcamRouteMenu(route) {
mode: "choice",
title: getUIText("group_menu", "Group menu"),
message: dashcamRouteTitle(route),
+ choiceLayout: "list",
choices: [
{ label: `${getUIText("select_range", "Select range")}…`, value: "range" },
- { label: `${getUIText("sort_ascending", "Sort: ascending")}${sort === "asc" ? " ✓" : ""}`, value: "sort_asc" },
- { label: `${getUIText("sort_descending", "Sort: descending")}${sort === "desc" ? " ✓" : ""}`, value: "sort_desc" },
+ { label: getUIText("sort_ascending", "Sort: ascending"), value: "sort_asc", selected: sort === "asc" },
+ { label: getUIText("sort_descending", "Sort: descending"), value: "sort_desc", selected: sort === "desc" },
],
});
if (selected === "range") await showDashcamRangeSelect(route);
diff --git a/selfdrive/carrot/web/js/pages/setting.js b/selfdrive/carrot/web/js/pages/setting.js
index 54ef9e4edd..8ad65e9616 100644
--- a/selfdrive/carrot/web/js/pages/setting.js
+++ b/selfdrive/carrot/web/js/pages/setting.js
@@ -18,6 +18,7 @@ let settingSubnavFocusTimer = null;
const SETTING_FAVORITES_GROUP = "__setting_favorites__";
const SETTING_PROFILES_DIVIDER = "__setting_profiles_divider__";
const SETTING_PROFILE_GROUP_PREFIX = "__setting_profile__:";
+const SETTING_CATEGORY_DIVIDER_PREFIX = "__setting_category__:";
const SETTING_FAVORITES_LONG_PRESS_MS = 620;
const SETTING_FAVORITES_MOVE_TOLERANCE = 10;
const settingFavoritesState = {
@@ -40,6 +41,52 @@ function isSettingProfilesDivider(entry) {
return entry?.group === SETTING_PROFILES_DIVIDER || entry === SETTING_PROFILES_DIVIDER;
}
+function isSettingCategoryDivider(entry) {
+ return String(entry?.group || "").startsWith(SETTING_CATEGORY_DIVIDER_PREFIX);
+}
+
+function isSettingAnyDivider(entry) {
+ return isSettingProfilesDivider(entry) || isSettingCategoryDivider(entry);
+}
+
+// 대>중>소 노드(카테고리/그룹/섹션)의 현재 언어 라벨. ko/en/zh 직접 보유 노드용.
+function settingNodeLabel(node) {
+ if (!node) return "";
+ if (LANG === "zh") return node.zh || node.en || node.ko || "";
+ if (LANG === "ko") return node.ko || node.en || node.zh || "";
+ return node.en || node.ko || node.zh || "";
+}
+
+// /api/settings 의 categories(대>중>소)가 있으면 groups/items_by_group 를
+// 중-group id 키 기준으로 정규화한다. 각 항목엔 소-섹션 라벨을 __section 으로 부착.
+// categories 가 없으면(구버전) 아무것도 바꾸지 않아 기존 평면 UI 로 폴백.
+function normalizeSettingCategories(j) {
+ if (!j || !Array.isArray(j.categories) || !j.categories.length) return;
+ const idx = {};
+ Object.values(j.items_by_group || {}).forEach((list) => {
+ (list || []).forEach((it) => { if (it && it.name) idx[it.name] = it; });
+ });
+ const flatGroups = [];
+ const newItemsByGroup = {};
+ j.categories.forEach((cat) => {
+ (cat.groups || []).forEach((g) => {
+ flatGroups.push({ group: g.id, ko: g.ko, en: g.en, zh: g.zh, count: g.count, category: cat.id });
+ const items = [];
+ (g.sections || []).forEach((sec) => {
+ // 라벨이 없어도(단일 직속 섹션) 카드는 만들도록 항상 객체로 둔다.
+ const secLabel = { id: sec.id, ko: sec.ko, en: sec.en, zh: sec.zh };
+ (sec.items || []).forEach((name) => {
+ const def = idx[name];
+ if (def) items.push(Object.assign({}, def, { __section: secLabel }));
+ });
+ });
+ newItemsByGroup[g.id] = items;
+ });
+ });
+ j.groups = flatGroups;
+ j.items_by_group = newItemsByGroup;
+}
+
function settingProfileGroup(profileId) {
return SETTING_PROFILE_GROUP_PREFIX + String(profileId || "");
}
@@ -133,15 +180,29 @@ function getSettingProfilesLabel() {
}
function getSettingGroupsForDisplay() {
- const groups = SETTINGS?.groups || [];
const out = [
{
group: SETTING_FAVORITES_GROUP,
count: getFavoriteSettingEntries().length,
virtual: true,
},
- ...groups,
];
+ const cats = SETTINGS?.categories;
+ if (Array.isArray(cats) && cats.length) {
+ cats.forEach((cat) => {
+ out.push({
+ group: SETTING_CATEGORY_DIVIDER_PREFIX + (cat.id || ""),
+ label: settingNodeLabel(cat),
+ divider: true,
+ virtual: true,
+ });
+ (cat.groups || []).forEach((g) => {
+ out.push({ group: g.id, ko: g.ko, en: g.en, zh: g.zh, count: g.count, category: cat.id });
+ });
+ });
+ } else {
+ out.push(...(SETTINGS?.groups || []));
+ }
const profiles = settingProfilesState.profiles || [];
if (profiles.length) {
out.push({
@@ -317,7 +378,7 @@ function applyRestoredSettingValuesToRenderedItems(values) {
if (!name || !(name in values)) return;
const valueButton = row.querySelector(".val");
if (!valueButton) return;
- valueButton.textContent = String(values[name]);
+ syncSettingControlState(row, values[name]);
row.classList.add("is-restored-live");
window.setTimeout(() => row.classList.remove("is-restored-live"), 900);
updated = true;
@@ -496,6 +557,7 @@ async function loadSettings(options = {}) {
settingsLoadPromise = (async () => {
const j = await getJson("/api/settings");
+ normalizeSettingCategories(j);
SETTINGS = j;
UNIT_CYCLE = j.unit_cycle || UNIT_CYCLE;
settingValueCache.clear();
@@ -626,7 +688,7 @@ function renderGroups(options = {}) {
const box = document.getElementById("groupList");
const animateGroups = options.animateGroups !== false;
const groups = getSettingGroupsForDisplay();
- const signature = groups.map((g) => isSettingProfilesDivider(g) ? SETTING_PROFILES_DIVIDER : `${g.group}:${g.count ?? ""}:${g.label || ""}`).join("|");
+ const signature = groups.map((g) => isSettingAnyDivider(g) ? `div:${g.label || ""}` : `${g.group}:${g.count ?? ""}:${g.label || ""}`).join("|");
function setGroupButtonLabel(button, label, count) {
const text = Number.isFinite(Number(count)) ? `${label} (${count})` : label;
@@ -638,8 +700,8 @@ function renderGroups(options = {}) {
if (!animateGroups && box.dataset.groupsSignature === signature && box.children.length === groups.length) {
Array.from(box.children).forEach((button, index) => {
const g = groups[index];
- if (isSettingProfilesDivider(g)) {
- button.className = "setting-profile-divider";
+ if (isSettingAnyDivider(g)) {
+ button.className = isSettingCategoryDivider(g) ? "setting-profile-divider setting-category-divider" : "setting-profile-divider";
button.innerHTML = `${escapeHtml(g.label || getSettingProfilesLabel())}`;
button.removeAttribute("data-group");
button.onclick = null;
@@ -662,9 +724,10 @@ function renderGroups(options = {}) {
box.dataset.groupsSignature = signature;
groups.forEach(g => {
- if (isSettingProfilesDivider(g)) {
+ if (isSettingAnyDivider(g)) {
const divider = document.createElement("div");
- divider.className = animateGroups ? "setting-profile-divider ui-stagger-item" : "setting-profile-divider";
+ const base = animateGroups ? "setting-profile-divider ui-stagger-item" : "setting-profile-divider";
+ divider.className = isSettingCategoryDivider(g) ? base + " setting-category-divider" : base;
if (animateGroups) divider.style.setProperty("--i", String(box.children.length));
divider.innerHTML = `${escapeHtml(g.label || getSettingProfilesLabel())}`;
box.appendChild(divider);
@@ -716,11 +779,178 @@ function getSettingGroupLabel(group) {
if (profile) return profile.name;
const meta = getSettingGroupMeta(group);
if (!meta) return group;
+ if (meta.ko || meta.en || meta.zh) return settingNodeLabel(meta);
if (LANG === "zh") return meta.cgroup || meta.egroup || meta.group;
if (LANG === "ko") return meta.group || meta.egroup || group;
return meta.egroup || meta.group || group;
}
+function getSettingItemContextLabel(group, item) {
+ const groupLabel = getSettingGroupLabel(group);
+ const sectionLabel = item?.__section ? settingNodeLabel(item.__section) : "";
+ if (!sectionLabel || sectionLabel === groupLabel) return groupLabel;
+ return `${groupLabel} > ${sectionLabel}`;
+}
+
+const SETTING_CONTROL_OVERRIDES = {
+ ShowPathMode: { kind: "select" },
+ ShowPathColor: { kind: "select" },
+ ShowPathColorCruiseOff: { kind: "select" },
+ ShowPathModeLane: { kind: "select" },
+ ShowPathColorLane: { kind: "select" },
+ ShowPlotMode: { kind: "select" },
+ ClusterHudScreenMode: { kind: "select" },
+ ClusterHudRadarInfo: { kind: "select" },
+};
+
+function getSettingControlConfig(p) {
+ const override = SETTING_CONTROL_OVERRIDES[p?.name] || {};
+ const min = Number(p?.min);
+ const max = Number(p?.max);
+ const unit = Math.max(1, Number(p?.unit) || 1);
+ const optionCount = Number.isFinite(min) && Number.isFinite(max) ? Math.floor(max - min + 1) : 0;
+ let kind = override.kind || "slider";
+
+ if (!override.kind) {
+ if (min === 0 && max === 1) {
+ kind = "toggle";
+ } else if (Number.isInteger(min) && Number.isInteger(max) && optionCount >= 2 && optionCount <= 4) {
+ kind = "segmented";
+ } else if (Number.isInteger(min) && Number.isInteger(max) && optionCount > 4 && optionCount <= 8) {
+ kind = "select";
+ } else {
+ kind = "slider";
+ }
+ }
+
+ return { kind, min, max, unit, optionCount };
+}
+
+function getSettingDisplayUnit(name) {
+ if (!name) return "";
+ if (/Brightness|Volume/i.test(name)) return "%";
+ if (/Speed/i.test(name)) return "km/h";
+ if (/Dist|Distance|Offset/i.test(name)) return "cm";
+ return "";
+}
+
+function formatSettingDisplayValue(p, value) {
+ const text = String(value);
+ const unit = getSettingDisplayUnit(p?.name);
+ return unit ? `${text}${unit}` : text;
+}
+
+const SETTING_UNIT_STORAGE_KEY = "carrot.settingUnitIndex.v1";
+let settingUnitIndexStore = null;
+
+function getSettingUnitIndexStore() {
+ if (settingUnitIndexStore) return settingUnitIndexStore;
+ try {
+ settingUnitIndexStore = JSON.parse(localStorage.getItem(SETTING_UNIT_STORAGE_KEY) || "{}") || {};
+ } catch (_) {
+ settingUnitIndexStore = {};
+ }
+ return settingUnitIndexStore;
+}
+
+function saveSettingUnitIndex(name, index) {
+ const key = String(name || "").trim();
+ if (!key) return;
+ try {
+ const store = getSettingUnitIndexStore();
+ store[key] = index;
+ localStorage.setItem(SETTING_UNIT_STORAGE_KEY, JSON.stringify(store));
+ } catch (_) {}
+}
+
+function getSettingUnitIndex(name) {
+ const key = String(name || "").trim();
+ if (!key) return 0;
+ if (!(key in UNIT_INDEX)) {
+ const saved = Number(getSettingUnitIndexStore()[key]);
+ UNIT_INDEX[key] = Number.isInteger(saved) && saved >= 0 && saved < UNIT_CYCLE.length ? saved : 0;
+ }
+ if (!Number.isInteger(UNIT_INDEX[key]) || UNIT_INDEX[key] < 0 || UNIT_INDEX[key] >= UNIT_CYCLE.length) {
+ UNIT_INDEX[key] = 0;
+ }
+ return UNIT_INDEX[key];
+}
+
+function getSettingUnitValue(name) {
+ return UNIT_CYCLE[getSettingUnitIndex(name)] || UNIT_CYCLE[0] || 1;
+}
+
+function setSettingUnitButtonLabel(button, name) {
+ if (button) button.textContent = "x" + getSettingUnitValue(name);
+}
+
+function cycleSettingUnitValue(name) {
+ const key = String(name || "").trim();
+ if (!key) return;
+ UNIT_INDEX[key] = (getSettingUnitIndex(key) + 1) % UNIT_CYCLE.length;
+ saveSettingUnitIndex(key, UNIT_INDEX[key]);
+}
+
+function settingChevronSvg(direction = "left") {
+ const path = direction === "right" ? "M8.75 4.75 16 12l-7.25 7.25" : "M15.25 4.75 8 12l7.25 7.25";
+ return `
+
+ `;
+}
+
+function setSettingItemsTitle(label) {
+ if (!itemsTitle) return;
+ const safeLabel = escapeHtml(label || "");
+ itemsTitle.innerHTML = `
+ ${settingChevronSvg("left")}
+ ${safeLabel}
+ `;
+}
+
+function getSettingOptionValues(config) {
+ if (!config || !Number.isInteger(config.min) || !Number.isInteger(config.max)) return [];
+ const out = [];
+ for (let value = config.min; value <= config.max; value += 1) out.push(value);
+ return out;
+}
+
+function getSettingOptionLabel(name, value) {
+ return String(value);
+}
+
+function syncSettingControlState(row, value) {
+ if (!row) return;
+ const text = String(value);
+ const valueButton = row.querySelector(".val");
+ if (valueButton) {
+ const displayText = formatSettingDisplayValue({ name: row.dataset.settingName || "" }, value);
+ valueButton.textContent = displayText;
+ valueButton.dataset.rawValue = text;
+ }
+
+ const toggle = row.querySelector(".setting-switch__input");
+ if (toggle) toggle.checked = Number(value) === 1;
+
+ const slider = row.querySelector(".setting-slider__input");
+ if (slider) slider.value = text;
+
+ row.querySelectorAll(".setting-segment").forEach((button) => {
+ button.classList.toggle("is-active", String(button.dataset.value) === text);
+ button.setAttribute("aria-pressed", String(button.dataset.value) === text ? "true" : "false");
+ });
+
+ const select = row.querySelector(".setting-select");
+ if (select) {
+ select.value = text;
+ if (select.tagName === "BUTTON") {
+ select.dataset.value = text;
+ select.textContent = getSettingOptionLabel(row.dataset.settingName || "", value);
+ }
+ }
+}
+
const SETTING_SUBNAV_PAGE_STEP = 1;
let settingGroupTransitionLock = false;
let settingRenderToken = 0;
@@ -731,6 +961,7 @@ let settingSearchEntries = [];
let settingSearchScope = { type: "all", profileId: "" };
const settingPageRoot = document.getElementById("pageSetting");
let settingFabMenuOpen = false;
+let CURRENT_SETTING_DETAIL = null;
function isCompactLandscapeMode() {
return window.matchMedia("(orientation: landscape)").matches;
@@ -1191,6 +1422,7 @@ function mountSettingSearchOverlay() {
function makeSettingSearchEntry({ source, profile = null, group, item }) {
const groupLabel = getSettingGroupLabel(group);
+ const contextGroupLabel = getSettingItemContextLabel(group, item);
const title = formatItemText(item, "title", "etitle", "");
const descr = formatItemText(item, "descr", "edescr", "");
const isProfile = source === "profile" && profile?.id;
@@ -1199,8 +1431,8 @@ function makeSettingSearchEntry({ source, profile = null, group, item }) {
? getUIText("setting_search_source_profile", "Profile")
: getUIText("setting_search_source_carrot", "CarrotPilot");
const contextLabel = isProfile
- ? `${profileName} / ${groupLabel}`
- : groupLabel;
+ ? `${profileName} / ${contextGroupLabel}`
+ : contextGroupLabel;
return {
source: isProfile ? "profile" : "carrot",
@@ -1210,11 +1442,12 @@ function makeSettingSearchEntry({ source, profile = null, group, item }) {
group: isProfile ? settingProfileGroup(profile.id) : group,
originalGroup: group,
groupLabel,
+ contextGroupLabel,
contextLabel,
name: item.name,
title,
descr,
- haystack: [sourceLabel, profileName, groupLabel, item.name, title, descr].join("\n").toLowerCase(),
+ haystack: [sourceLabel, profileName, groupLabel, contextGroupLabel, item.name, title, descr].join("\n").toLowerCase(),
};
}
@@ -1363,7 +1596,7 @@ function resetSettingItemsViewport() {
function hasRenderedSettingItems(group = CURRENT_GROUP) {
const itemsBox = document.getElementById("items");
if (!itemsBox || !group) return false;
- return itemsBox.dataset.renderedGroup === group && itemsBox.childElementCount > 0;
+ return itemsBox.dataset.renderedGroup === group && !itemsBox.dataset.renderedDetail && itemsBox.childElementCount > 0;
}
function isCarrotSettingTabActive() {
@@ -1373,12 +1606,62 @@ function isCarrotSettingTabActive() {
function syncSettingGroupChrome(group = CURRENT_GROUP) {
const meta = document.getElementById("groupMeta");
const list = getSettingItemEntriesForGroup(group);
- if (meta && group) meta.textContent = `${group} / ${list.length}`;
const groupLabel = group ? getSettingGroupLabel(group) : "";
+ if (CURRENT_SETTING_DETAIL) {
+ const detailEntry = getSettingDetailEntry(group, CURRENT_SETTING_DETAIL);
+ const detailTitle = detailEntry?.item ? getSettingDetailTitle(detailEntry.item) : CURRENT_SETTING_DETAIL;
+ if (meta && group) meta.textContent = `${group} / 1`;
+ if (group) {
+ settingTitle.textContent = (UI_STRINGS[LANG].setting || "Setting") + " - " + detailTitle;
+ setSettingItemsTitle(detailTitle);
+ }
+ return;
+ }
+ if (meta && group) meta.textContent = `${group} / ${list.length}`;
if (group) {
settingTitle.textContent = (UI_STRINGS[LANG].setting || "Setting") + " - " + groupLabel;
- if (itemsTitle) itemsTitle.textContent = groupLabel;
+ setSettingItemsTitle(groupLabel);
+ }
+}
+
+function getSettingDetailEntry(group, name) {
+ const target = String(name || "").trim();
+ if (!target) return null;
+ const entries = getSettingItemEntriesForGroup(group);
+ return entries.find((entry) => entry?.item?.name === target) || null;
+}
+
+function getSettingDetailTitle(item) {
+ return formatItemText(item, "title", "etitle", item?.name || "");
+}
+
+function isSettingInlineControlTarget(target) {
+ return Boolean(target?.closest?.(".ctrl, button, input, select, textarea, a"));
+}
+
+async function selectSettingDetail(group, name, pushHistory = true) {
+ const targetGroup = group || CURRENT_GROUP;
+ const targetName = String(name || "").trim();
+ if (!targetGroup || !targetName) return;
+
+ saveCurrentSettingScrollPosition(targetGroup);
+ CURRENT_GROUP = targetGroup;
+ CURRENT_SETTING_DETAIL = targetName;
+ showSettingScreen("items", false);
+ if (pushHistory) {
+ history.pushState({
+ page: "setting",
+ screen: "detail",
+ group: targetGroup,
+ settingName: targetName,
+ }, "");
}
+ await renderItems(targetGroup, {
+ detailName: targetName,
+ scrollMode: "top",
+ animateItems: true,
+ forceValues: true,
+ });
}
function settingMarqueeHtml(text, className) {
@@ -1545,8 +1828,8 @@ function renderSettingSearchResults(query = "") {
button.type = "button";
button.className = "setting-search-result";
const metaLabel = entry.source === "profile"
- ? `${entry.profileName} / ${entry.groupLabel}`
- : entry.groupLabel;
+ ? `${entry.profileName} / ${entry.contextGroupLabel || entry.groupLabel}`
+ : entry.contextGroupLabel || entry.groupLabel;
button.innerHTML = `
${highlightSettingSearchText(metaLabel, trimmed)}
${highlightSettingSearchText(entry.title || entry.name, trimmed)}
@@ -1560,7 +1843,7 @@ function renderSettingSearchResults(query = "") {
settingProfileSectionExpandedState.set(`${entry.profileId}:${entry.originalGroup}`, true);
}
closeSettingSearchPanel({ syncHistory: false });
- if (CURRENT_GROUP === entry.group && screenItems && screenItems.style.display !== "none") {
+ if (CURRENT_GROUP === entry.group && !CURRENT_SETTING_DETAIL && screenItems && screenItems.style.display !== "none") {
focusSettingItem(entry.name);
return;
}
@@ -1603,8 +1886,9 @@ async function openSettingSearchPanel(options = {}) {
if (pushHistory && !(state.page === "setting" && state.search)) {
history.pushState({
page: "setting",
- screen: (screenItems && screenItems.style.display !== "none") ? "items" : "groups",
+ screen: CURRENT_SETTING_DETAIL ? "detail" : ((screenItems && screenItems.style.display !== "none") ? "items" : "groups"),
group: CURRENT_GROUP || null,
+ settingName: CURRENT_SETTING_DETAIL || null,
search: true,
searchScope: settingSearchScope.type,
profileId: settingSearchScope.profileId || null,
@@ -1624,14 +1908,6 @@ async function openSettingSearchPanel(options = {}) {
});
}
-function toggleSettingSearchPanel() {
- if (!settingSearchPanel) return;
- if (settingSearchPanel.hidden) {
- openSettingSearchPanel().catch(() => {});
- }
- else closeSettingSearchPanel({ syncHistory: true });
-}
-
if (btnSettingSearch) {
btnSettingSearch.onclick = () => toggleSettingFabMenu();
}
@@ -1752,12 +2028,27 @@ function updateSettingSubnavLayoutState() {
syncSettingSubnavFixedOffset();
}
+function getCurrentSettingCategoryId() {
+ if (!Array.isArray(SETTINGS?.categories) || !SETTINGS.categories.length) return null;
+ const meta = (SETTINGS?.groups || []).find((g) => g.group === CURRENT_GROUP);
+ return meta?.category || null;
+}
+
function getSettingSubnavGroups() {
- return getSettingGroupsForDisplay().filter((entry) =>
+ const all = getSettingGroupsForDisplay().filter((entry) =>
!isSettingProfilesDivider(entry) &&
+ !isSettingCategoryDivider(entry) &&
!isSettingFavoritesGroup(entry.group) &&
!isSettingProfileGroup(entry.group)
);
+ // 카테고리 모드: 서브내비(퀵링크)를 현재 카테고리의 그룹만으로 한정 → footprint 축소.
+ // 다른 카테고리는 뒤로가기(그룹목록)로 전환. CURRENT_GROUP 이 가상/없으면 전체 유지.
+ const catId = getCurrentSettingCategoryId();
+ if (catId) {
+ const scoped = all.filter((entry) => entry.category === catId);
+ if (scoped.length) return scoped;
+ }
+ return all;
}
function getSettingSubnavGroupIndex(group = CURRENT_GROUP) {
@@ -1791,6 +2082,7 @@ async function activateSettingGroup(group, pushHistory = true, options = {}) {
if (!isCarrotSettingTabActive()) return;
const nextGroup = group || CURRENT_GROUP;
const previousGroup = CURRENT_GROUP;
+ CURRENT_SETTING_DETAIL = null;
const scrollMode = options.scrollMode || "top";
const animateItems = options.animateItems !== false;
const animateGroups = options.animateGroups !== false;
@@ -2167,21 +2459,29 @@ async function renderItems(group, options = {}) {
const meta = document.getElementById("groupMeta");
const itemsBox = document.getElementById("items");
const renderToken = ++settingRenderToken;
+ const detailName = String(options.detailName || "").trim();
+ const detailMode = Boolean(detailName);
const scrollMode = options.scrollMode || "top";
const animateItems = options.animateItems !== false;
const requestedScrollTop = Number.isFinite(options.scrollTop) ? options.scrollTop : null;
itemsBox.innerHTML = "";
delete itemsBox.dataset.renderedGroup;
+ delete itemsBox.dataset.renderedDetail;
renderSettingSubnav();
- const entries = getSettingItemEntriesForGroup(group);
+ const allEntries = getSettingItemEntriesForGroup(group);
+ const detailEntry = detailMode ? getSettingDetailEntry(group, detailName) : null;
+ const entries = detailMode ? (detailEntry ? [detailEntry] : []) : allEntries;
const list = entries.map((entry) => entry.item);
const profile = getSettingProfileByGroup(group);
if (screenItems) screenItems.classList.toggle("setting-screen-items--profile", Boolean(profile));
- if (meta) meta.textContent = `${group} / ${list.length}`;
+ if (screenItems) screenItems.classList.toggle("setting-screen-items--detail", detailMode);
+ CURRENT_SETTING_DETAIL = detailMode ? detailName : null;
+ if (meta) meta.textContent = `${group} / ${detailMode ? "1" : list.length}`;
const groupLabel = getSettingGroupLabel(group);
- settingTitle.textContent = (UI_STRINGS[LANG].setting || "Setting") + " - " + groupLabel;
- if (itemsTitle) itemsTitle.textContent = groupLabel;
+ const detailTitle = detailMode && list[0] ? getSettingDetailTitle(list[0]) : "";
+ settingTitle.textContent = (UI_STRINGS[LANG].setting || "Setting") + " - " + (detailTitle || groupLabel);
+ setSettingItemsTitle(detailTitle || groupLabel);
let values = {};
try {
@@ -2197,6 +2497,24 @@ async function renderItems(group, options = {}) {
return;
}
+ if (!list.length && detailMode) {
+ const empty = document.createElement("div");
+ empty.className = "setting-favorites-empty";
+ const emptyTitle = document.createElement("div");
+ emptyTitle.className = "setting-favorites-empty__title";
+ emptyTitle.textContent = getUIText("setting_not_found", "Setting not found");
+ const emptyDesc = document.createElement("div");
+ emptyDesc.className = "setting-favorites-empty__desc";
+ emptyDesc.textContent = detailName;
+ empty.appendChild(emptyTitle);
+ empty.appendChild(emptyDesc);
+ itemsBox.appendChild(empty);
+ itemsBox.dataset.renderedGroup = group;
+ itemsBox.dataset.renderedDetail = detailName;
+ requestAnimationFrame(resetSettingItemsViewport);
+ return;
+ }
+
if (!list.length && isSettingFavoritesGroup(group)) {
const empty = document.createElement("div");
empty.className = "setting-favorites-empty";
@@ -2217,7 +2535,7 @@ async function renderItems(group, options = {}) {
return;
}
- if (profile) appendSettingProfileHeader(profile, itemsBox);
+ if (profile && !detailMode) appendSettingProfileHeader(profile, itemsBox);
const profileSectionCounts = new Map();
if (profile) {
@@ -2227,12 +2545,58 @@ async function renderItems(group, options = {}) {
}
let lastProfileGroup = "";
let currentProfileSectionBody = null;
+ let lastCategorySectionKey = null;
+ let currentCategoryCardBody = null;
+
+ // 즐겨찾기도 다른 하위메뉴와 같은 카드 박스(공통분모: setting-section-block +
+ // setting-group-card)에 담는다. 즐겨찾기는 소-섹션이 섞여 있으므로 단일 카드 1개로.
+ if (!detailMode && isSettingFavoritesGroup(group) && list.length) {
+ const favBlock = document.createElement("section");
+ favBlock.className = animateItems ? "setting-section-block ui-stagger-item" : "setting-section-block";
+ if (animateItems) favBlock.style.setProperty("--i", "1");
+ const favCard = document.createElement("div");
+ favCard.className = "setting-group-card";
+ const favBody = document.createElement("div");
+ favBody.className = "setting-group-card__body";
+ favCard.appendChild(favBody);
+ favBlock.appendChild(favCard);
+ itemsBox.appendChild(favBlock);
+ currentCategoryCardBody = favBody;
+ }
+
list.forEach((p, index) => {
const name = p.name;
const originGroup = entries[index]?.group || group;
- if (!(name in UNIT_INDEX)) UNIT_INDEX[name] = 0;
+ getSettingUnitIndex(name);
+
+ // 카테고리 모드: 소-섹션마다 카드(그룹박스) 생성 (프로필/즐겨찾기 뷰 제외).
+ // 라벨이 있으면 카드 제목으로, 없으면(단일 직속 섹션) 제목 없는 카드.
+ if (!detailMode && !profile && !isSettingFavoritesGroup(group) && p.__section) {
+ const secKey = p.__section.id || "";
+ if (secKey !== lastCategorySectionKey) {
+ lastCategorySectionKey = secKey;
+ const sectionBlock = document.createElement("section");
+ sectionBlock.className = animateItems ? "setting-section-block ui-stagger-item" : "setting-section-block";
+ if (animateItems) sectionBlock.style.setProperty("--i", String(Math.min(index + 1, 14)));
+ const cardLabel = settingNodeLabel(p.__section);
+ if (cardLabel) {
+ const cardTitle = document.createElement("div");
+ cardTitle.className = "setting-group-card__title";
+ cardTitle.textContent = cardLabel;
+ sectionBlock.appendChild(cardTitle);
+ }
+ const card = document.createElement("div");
+ card.className = "setting-group-card";
+ const cardBody = document.createElement("div");
+ cardBody.className = "setting-group-card__body";
+ card.appendChild(cardBody);
+ sectionBlock.appendChild(card);
+ itemsBox.appendChild(sectionBlock);
+ currentCategoryCardBody = cardBody;
+ }
+ }
- if (profile && originGroup !== lastProfileGroup) {
+ if (!detailMode && profile && originGroup !== lastProfileGroup) {
lastProfileGroup = originGroup;
const section = document.createElement("div");
section.className = animateItems ? "setting-profile-section ui-stagger-item" : "setting-profile-section";
@@ -2310,38 +2674,115 @@ async function renderItems(group, options = {}) {
`;
+ const controlConfig = getSettingControlConfig(p);
+ const compactNumeric = !detailMode && controlConfig.kind === "slider";
const ctrl = document.createElement("div");
- ctrl.className = "ctrl";
-
- const btnMinus = document.createElement("button");
- btnMinus.type = "button";
- btnMinus.className = "smallBtn";
- btnMinus.textContent = "-";
+ ctrl.className = `ctrl ctrl--${compactNumeric ? "value" : controlConfig.kind}`;
const val = document.createElement("button");
val.type = "button";
- val.className = "pill val";
- val.setAttribute("aria-label", getUIText("setting_value_edit", "Edit value"));
-
- const btnPlus = document.createElement("button");
- btnPlus.type = "button";
- btnPlus.className = "smallBtn";
- btnPlus.textContent = "+";
-
- const unitBtn = document.createElement("button");
- unitBtn.type = "button";
- unitBtn.className = "smallBtn";
- unitBtn.textContent = "x" + UNIT_CYCLE[UNIT_INDEX[name]];
-
- unitBtn.onclick = () => {
- UNIT_INDEX[name] = (UNIT_INDEX[name] + 1) % UNIT_CYCLE.length;
- unitBtn.textContent = "x" + UNIT_CYCLE[UNIT_INDEX[name]];
- };
-
- ctrl.appendChild(btnMinus);
- ctrl.appendChild(val);
- ctrl.appendChild(btnPlus);
- ctrl.appendChild(unitBtn);
+ val.className = compactNumeric ? "pill val setting-value-compact" : "pill val";
+ val.setAttribute("aria-label", compactNumeric
+ ? getUIText("setting_value_detail", "Open detail")
+ : getUIText("setting_value_edit", "Edit value"));
+
+ let btnMinus = null;
+ let btnPlus = null;
+ let unitBtn = null;
+ let sliderInput = null;
+ let toggleInput = null;
+ let selectInput = null;
+ const segmentButtons = [];
+
+ if (controlConfig.kind === "toggle") {
+ const switchLabel = document.createElement("label");
+ switchLabel.className = "setting-switch";
+ toggleInput = document.createElement("input");
+ toggleInput.type = "checkbox";
+ toggleInput.className = "setting-switch__input";
+ toggleInput.setAttribute("aria-label", title || name);
+ const switchTrack = document.createElement("span");
+ switchTrack.className = "setting-switch__track";
+ switchLabel.appendChild(toggleInput);
+ switchLabel.appendChild(switchTrack);
+ ctrl.appendChild(switchLabel);
+ ctrl.appendChild(val);
+ } else if (controlConfig.kind === "segmented") {
+ const segmentWrap = document.createElement("div");
+ segmentWrap.className = "setting-segments";
+ getSettingOptionValues(controlConfig).forEach((optionValue) => {
+ const button = document.createElement("button");
+ button.type = "button";
+ button.className = "setting-segment";
+ button.dataset.value = String(optionValue);
+ button.textContent = getSettingOptionLabel(name, optionValue);
+ button.setAttribute("aria-pressed", "false");
+ segmentButtons.push(button);
+ segmentWrap.appendChild(button);
+ });
+ ctrl.appendChild(segmentWrap);
+ ctrl.appendChild(val);
+ } else if (controlConfig.kind === "select") {
+ selectInput = document.createElement("button");
+ selectInput.type = "button";
+ selectInput.className = "setting-select setting-select--button";
+ selectInput.setAttribute("aria-label", title || name);
+ selectInput.setAttribute("aria-haspopup", "dialog");
+ ctrl.appendChild(selectInput);
+ ctrl.appendChild(val);
+ } else if (compactNumeric) {
+ btnMinus = document.createElement("button");
+ btnMinus.type = "button";
+ btnMinus.className = "smallBtn setting-value-arrow setting-value-arrow--prev";
+ btnMinus.textContent = "-";
+ btnMinus.setAttribute("aria-label", getUIText("setting_value_previous", "Previous value"));
+
+ btnPlus = document.createElement("button");
+ btnPlus.type = "button";
+ btnPlus.className = "smallBtn setting-value-arrow setting-value-arrow--next";
+ btnPlus.textContent = "+";
+ btnPlus.setAttribute("aria-label", getUIText("setting_value_next", "Next value"));
+
+ unitBtn = document.createElement("button");
+ unitBtn.type = "button";
+ unitBtn.className = "setting-unit-cycle";
+ setSettingUnitButtonLabel(unitBtn, name);
+
+ ctrl.appendChild(btnMinus);
+ ctrl.appendChild(val);
+ ctrl.appendChild(btnPlus);
+ } else {
+ const sliderWrap = document.createElement("div");
+ sliderWrap.className = "setting-slider";
+ sliderInput = document.createElement("input");
+ sliderInput.type = "range";
+ sliderInput.className = "setting-slider__input";
+ sliderInput.min = String(controlConfig.min);
+ sliderInput.max = String(controlConfig.max);
+ sliderInput.step = String(controlConfig.unit);
+ sliderInput.setAttribute("aria-label", title || name);
+ sliderWrap.appendChild(sliderInput);
+
+ btnMinus = document.createElement("button");
+ btnMinus.type = "button";
+ btnMinus.className = "smallBtn setting-step setting-step--minus";
+ btnMinus.textContent = "-";
+
+ btnPlus = document.createElement("button");
+ btnPlus.type = "button";
+ btnPlus.className = "smallBtn setting-step setting-step--plus";
+ btnPlus.textContent = "+";
+
+ unitBtn = document.createElement("button");
+ unitBtn.type = "button";
+ unitBtn.className = "setting-unit-cycle";
+ setSettingUnitButtonLabel(unitBtn, name);
+
+ ctrl.appendChild(sliderWrap);
+ ctrl.appendChild(btnMinus);
+ ctrl.appendChild(val);
+ ctrl.appendChild(btnPlus);
+ }
top.appendChild(left);
top.appendChild(ctrl);
@@ -2352,10 +2793,15 @@ async function renderItems(group, options = {}) {
el.appendChild(top);
el.appendChild(d);
- (currentProfileSectionBody || itemsBox).appendChild(el);
+ if (unitBtn) {
+ el.classList.add("setting--has-unit-cycle");
+ el.appendChild(unitBtn);
+ }
+ (currentProfileSectionBody || currentCategoryCardBody || itemsBox).appendChild(el);
const cur = (name in values) ? values[name] : p.default;
- val.textContent = String(cur);
+ syncSettingControlState(el, cur);
+ val.dataset.committedValue = String(cur);
function normalizeSettingValue(raw) {
const text = String(raw).trim();
@@ -2386,7 +2832,8 @@ async function renderItems(group, options = {}) {
} else {
await setParam(name, next);
}
- val.textContent = String(next);
+ syncSettingControlState(el, next);
+ val.dataset.committedValue = String(next);
if (!profile) {
cacheSettingValue(name, next, group);
if (originGroup !== group) cacheSettingValue(name, next, originGroup);
@@ -2396,77 +2843,214 @@ async function renderItems(group, options = {}) {
}
}
- async function editValueDirect() {
- const input = await appPrompt(
- getUIText("setting_value_prompt", "Enter value for {name}\nRange: {min} - {max}", {
- name,
- min: p.min,
- max: p.max,
- }),
- {
- title: getUIText("setting_value_title", "Edit value"),
- defaultValue: val.textContent,
- placeholder: String(p.default),
- confirmLabel: getUIText("ok", "OK"),
- showCancel: false,
- defaultActionLabel: getUIText("default_value", "Default"),
- defaultActionValue: { settingDefaultAction: true, value: String(p.default) },
+ async function applyDelta(sign) {
+ const step = getSettingUnitValue(name);
+ let curv = Number(val.dataset.rawValue);
+ if (Number.isNaN(curv)) curv = Number(p.default);
+
+ let next = curv + sign * step;
+ next = clamp(next, Number(p.min), Number(p.max));
+
+ if (Number.isInteger(Number(p.min)) && Number.isInteger(Number(p.max)) && Number.isInteger(step)) {
+ next = Math.round(next);
+ }
+
+ await commitSettingValue(next);
+ }
+
+ let deltaBusy = false;
+ async function requestDelta(sign) {
+ if (deltaBusy) return;
+ deltaBusy = true;
+ try {
+ await applyDelta(sign);
+ } finally {
+ deltaBusy = false;
+ }
+ }
+
+ function bindDeltaButton(button, sign) {
+ if (!button) return;
+
+ let holdTimer = null;
+ let repeatTimer = null;
+ let pointerActive = false;
+ let activePointerId = null;
+ let ignoreNextClick = false;
+
+ function clearTimers() {
+ if (holdTimer) {
+ clearTimeout(holdTimer);
+ holdTimer = null;
}
- );
- if (input === null) return;
+ if (repeatTimer) {
+ clearTimeout(repeatTimer);
+ repeatTimer = null;
+ }
+ }
- if (input?.settingDefaultAction) {
- const defaultValue = input.value;
- const ok = await appConfirm(getUIText(
- "default_value_confirm",
- "Restore {name} to default value ({value})?",
- { name, value: defaultValue }
- ), {
- title: getUIText("default_value", "Default"),
- confirmLabel: getUIText("ok", "OK"),
- });
- if (!ok) return;
+ function stopHold() {
+ clearTimers();
+ pointerActive = false;
+ button.classList.remove("is-holding");
+ if (activePointerId !== null && typeof button.releasePointerCapture === "function") {
+ try {
+ button.releasePointerCapture(activePointerId);
+ } catch (_) {
+ /* pointer capture may already be released by the browser */
+ }
+ }
+ activePointerId = null;
+ window.setTimeout(() => {
+ ignoreNextClick = false;
+ }, 0);
+ }
+
+ function repeatDelta() {
+ if (!pointerActive) return;
+ requestDelta(sign);
+ repeatTimer = window.setTimeout(repeatDelta, 120);
+ }
+
+ button.addEventListener("pointerdown", (event) => {
+ if (event.button !== undefined && event.button !== 0) return;
+ event.stopPropagation();
+ event.preventDefault();
+ stopHold();
+ pointerActive = true;
+ activePointerId = event.pointerId;
+ ignoreNextClick = true;
+ button.classList.add("is-holding");
+ if (typeof button.setPointerCapture === "function") {
+ try {
+ button.setPointerCapture(activePointerId);
+ } catch (_) {
+ /* pointer capture is best-effort for repeated input */
+ }
+ }
+ requestDelta(sign);
+ holdTimer = window.setTimeout(repeatDelta, 420);
+ });
- const nextDefault = normalizeSettingValue(defaultValue);
- if (nextDefault === null) {
- showAppToast(getUIText("setting_value_invalid", "Enter a valid number."), { tone: "error" });
+ button.addEventListener("pointerup", (event) => {
+ event.stopPropagation();
+ stopHold();
+ });
+ button.addEventListener("pointercancel", stopHold);
+ button.addEventListener("lostpointercapture", stopHold);
+ button.addEventListener("click", (event) => {
+ event.stopPropagation();
+ if (ignoreNextClick) {
+ event.preventDefault();
return;
}
- if (String(nextDefault) === String(val.textContent)) return;
- await commitSettingValue(nextDefault);
- return;
- }
+ requestDelta(sign);
+ });
+ }
+ async function promptSettingValue() {
+ const input = await appPrompt(
+ `min=${p.min}, max=${p.max}, default=${p.default}`,
+ {
+ title: title || name,
+ defaultValue: val.dataset.rawValue ?? String(p.default),
+ placeholder: String(p.default),
+ confirmLabel: getUIText("ok", "OK"),
+ cancelLabel: getUIText("cancel", "Cancel"),
+ showCancel: true,
+ },
+ );
+ if (input === null) return;
const next = normalizeSettingValue(input);
if (next === null) {
showAppToast(getUIText("setting_value_invalid", "Enter a valid number."), { tone: "error" });
return;
}
- if (String(next) === String(val.textContent)) return;
+ if (String(next) === String(val.dataset.rawValue)) return;
await commitSettingValue(next);
}
- async function applyDelta(sign) {
- const step = UNIT_CYCLE[UNIT_INDEX[name]];
- let curv = Number(val.textContent);
- if (Number.isNaN(curv)) curv = Number(p.default);
+ async function promptSettingChoice() {
+ const current = String(val.dataset.rawValue ?? p.default);
+ const choices = getSettingOptionValues(controlConfig).map((optionValue) => {
+ const optionText = String(optionValue);
+ const isCurrent = optionText === current;
+ return {
+ label: getSettingOptionLabel(name, optionValue),
+ value: optionText,
+ selected: isCurrent,
+ className: "setting-choice-option",
+ };
+ });
+ const selected = await openAppDialog({
+ mode: "choice",
+ choiceLayout: "value-grid",
+ title: title || name,
+ html: true,
+ messageHtml: `${escapeHtml(name)}
min=${escapeHtml(p.min)}, max=${escapeHtml(p.max)}, default=${escapeHtml(p.default)}
`,
+ choices,
+ cancelLabel: getUIText("cancel", "Cancel"),
+ showCancel: true,
+ });
+ if (selected === null) return;
+ const next = normalizeSettingValue(selected);
+ if (next === null || String(next) === String(val.dataset.rawValue)) return;
+ await commitSettingValue(next);
+ }
- let next = curv + sign * step;
- next = clamp(next, Number(p.min), Number(p.max));
+ if (toggleInput) {
+ toggleInput.onchange = () => {
+ commitSettingValue(toggleInput.checked ? 1 : 0);
+ };
+ }
- if (Number.isInteger(p.min) && Number.isInteger(p.max) && Number.isInteger(step)) {
- next = Math.round(next);
- }
+ if (unitBtn) {
+ unitBtn.onclick = (event) => {
+ event.stopPropagation();
+ cycleSettingUnitValue(name);
+ setSettingUnitButtonLabel(unitBtn, name);
+ };
+ }
- await commitSettingValue(next);
+ bindDeltaButton(btnMinus, -1);
+ bindDeltaButton(btnPlus, +1);
+
+ val.onclick = (event) => {
+ event.stopPropagation();
+ if (controlConfig.kind === "slider") promptSettingValue();
+ };
+
+ segmentButtons.forEach((button) => {
+ button.onclick = (event) => {
+ event.stopPropagation();
+ const next = normalizeSettingValue(button.dataset.value);
+ if (next === null || String(next) === String(val.dataset.rawValue)) return;
+ commitSettingValue(next);
+ };
+ });
+
+ if (selectInput) {
+ selectInput.onclick = (event) => {
+ event.stopPropagation();
+ promptSettingChoice();
+ };
}
- btnMinus.onclick = () => applyDelta(-1);
- val.onclick = editValueDirect;
- btnPlus.onclick = () => applyDelta(+1);
+ if (sliderInput) {
+ sliderInput.oninput = () => {
+ const next = normalizeSettingValue(sliderInput.value);
+ if (next !== null) syncSettingControlState(el, next);
+ };
+ sliderInput.onchange = () => {
+ const next = normalizeSettingValue(sliderInput.value);
+ if (next === null || String(next) === String(val.dataset.committedValue ?? val.dataset.rawValue)) return;
+ commitSettingValue(next);
+ };
+ }
});
itemsBox.dataset.renderedGroup = group;
+ if (detailMode) itemsBox.dataset.renderedDetail = detailName;
scheduleSettingOverflowSync(itemsBox);
if (pendingSettingFocus?.group === group) {
@@ -2498,7 +3082,7 @@ function bindSettingFavoriteLongPress() {
}
function isIgnoredFavoritePressTarget(target) {
- return Boolean(target?.closest?.(".ctrl, button, input, select, textarea, a"));
+ return isSettingInlineControlTarget(target);
}
itemsBox.addEventListener("pointerdown", (event) => {
@@ -2519,6 +3103,10 @@ function bindSettingFavoriteLongPress() {
if (!press || press.row !== row) return;
press.fired = true;
row.classList.remove("is-longpressing");
+ row.dataset.settingSuppressClick = "1";
+ window.setTimeout(() => {
+ if (row.dataset.settingSuppressClick === "1") delete row.dataset.settingSuppressClick;
+ }, 420);
toggleSettingFavorite(row.dataset.settingName).catch(() => {});
}, SETTING_FAVORITES_LONG_PRESS_MS),
};
@@ -2584,7 +3172,11 @@ async function syncSettingViewportLayout(options = {}) {
syncSettingGroupChrome(targetGroup);
if (typeof centerActiveSettingSubnavTab === "function") centerActiveSettingSubnavTab("auto");
if (!hasRenderedSettingItems(targetGroup)) {
- await renderItems(targetGroup, { scrollMode: "restore", animateItems });
+ await renderItems(targetGroup, {
+ detailName: CURRENT_SETTING_DETAIL || "",
+ scrollMode: "restore",
+ animateItems,
+ });
}
return;
}
@@ -2594,7 +3186,11 @@ async function syncSettingViewportLayout(options = {}) {
showSettingScreen("items", false);
if (typeof centerActiveSettingSubnavTab === "function") centerActiveSettingSubnavTab("auto");
if (!hasRenderedSettingItems(CURRENT_GROUP)) {
- await renderItems(CURRENT_GROUP, { scrollMode: "restore", animateItems });
+ await renderItems(CURRENT_GROUP, {
+ detailName: CURRENT_SETTING_DETAIL || "",
+ scrollMode: "restore",
+ animateItems,
+ });
}
} else {
showSettingScreen("groups", false);
@@ -2638,6 +3234,7 @@ window.addEventListener("carrot:paramsrestored", (event) => {
settingRestoreRefreshTimer = window.setTimeout(() => {
settingRestoreRefreshTimer = null;
renderItems(CURRENT_GROUP, {
+ detailName: CURRENT_SETTING_DETAIL || "",
forceValues: true,
scrollMode: "restore",
scrollTop: currentTop,
diff --git a/selfdrive/carrot/web/js/shared/i18n.js b/selfdrive/carrot/web/js/shared/i18n.js
index 8b6e7fe194..faf3042065 100644
--- a/selfdrive/carrot/web/js/shared/i18n.js
+++ b/selfdrive/carrot/web/js/shared/i18n.js
@@ -363,7 +363,12 @@ function setWebLanguage(lang, options = {}) {
const currentTop = typeof getSettingItemsScrollTop === "function"
? getSettingItemsScrollTop()
: 0;
- renderItems(CURRENT_GROUP, { scrollMode: "restore", scrollTop: currentTop, animateItems: false });
+ renderItems(CURRENT_GROUP, {
+ detailName: (typeof CURRENT_SETTING_DETAIL !== "undefined" && CURRENT_SETTING_DETAIL) ? CURRENT_SETTING_DETAIL : "",
+ scrollMode: "restore",
+ scrollTop: currentTop,
+ animateItems: false,
+ });
}
}
if (dispatch) {
diff --git a/selfdrive/carrot/web/js/shared/ui/dialog.js b/selfdrive/carrot/web/js/shared/ui/dialog.js
index 1594639806..9f5f5c685c 100644
--- a/selfdrive/carrot/web/js/shared/ui/dialog.js
+++ b/selfdrive/carrot/web/js/shared/ui/dialog.js
@@ -7,6 +7,13 @@ let appToastRemoveTimer = null;
let activeAppDialog = null;
let appDialogSerial = 0;
+const APP_DIALOG_VARIANT_CLASSES = [
+ "app-dialog--choice",
+ "app-dialog--choice-list",
+ "app-dialog--choice-grid",
+ "app-dialog--choice-value-grid",
+];
+
function syncModalBodyLock() {
const hasOpenDialog =
@@ -65,6 +72,39 @@ function showAppToast(message, opts = {}) {
/* ── Dialog (alert / confirm / prompt / choice) ─────────── */
+function resetAppDialogPresentation() {
+ if (appDialog) appDialog.classList.remove(...APP_DIALOG_VARIANT_CLASSES);
+ if (appDialogChoices) {
+ appDialogChoices.className = "app-dialog__choices";
+ appDialogChoices.style.removeProperty("--app-dialog-choice-columns");
+ }
+}
+
+function appDialogChoiceText(choice) {
+ if (!choice || choice.labelHtml) return "";
+ return String(choice.label ?? "").trim();
+}
+
+function inferAppDialogChoiceLayout(choices, options = {}) {
+ const explicit = String(options.choiceLayout || options.choiceKind || "").trim();
+ if (explicit === "grid" || explicit === "value-grid" || explicit === "values") return "value-grid";
+ if (explicit === "list" || explicit === "action-list" || explicit === "actions") return "list";
+
+ const shortValueChoices = choices.length > 4 && choices.every((choice) => {
+ const text = appDialogChoiceText(choice);
+ return text && text.length <= 5 && !choice.danger && /^[+-]?(?:\d+|\d+\.\d+|[A-Za-z]{1,4})$/.test(text);
+ });
+ return shortValueChoices ? "value-grid" : "list";
+}
+
+function appDialogChoiceColumns(count, options = {}) {
+ const explicit = Number(options.choiceColumns || options.columns);
+ if (Number.isInteger(explicit) && explicit >= 2 && explicit <= 6) return explicit;
+ if (count <= 4) return Math.max(2, count);
+ if (count <= 25) return 5;
+ return 4;
+}
+
function resolveAppDialog(result) {
if (!activeAppDialog || !appDialog) return;
@@ -80,6 +120,7 @@ function resolveAppDialog(result) {
}
appDialog.hidden = true;
syncModalBodyLock();
+ resetAppDialogPresentation();
if (appDialogChoices) {
appDialogChoices.hidden = true;
appDialogChoices.innerHTML = "";
@@ -140,12 +181,20 @@ function openAppDialog(options = {}) {
const defaultActionLabel = options.defaultActionLabel || "";
const hasDefaultAction = mode === "prompt" && Boolean(defaultActionLabel);
const choices = Array.isArray(options.choices)
- ? options.choices.filter((choice) => choice && (choice.label || choice.labelHtml))
+ ? options.choices.filter((choice) => choice && (choice.label != null || choice.labelHtml))
: [];
const hasChoices = choices.length > 0;
const isChoice = mode === "choice" || hasChoices;
+ const choiceLayout = hasChoices ? inferAppDialogChoiceLayout(choices, options) : "";
const showCancel = mode !== "alert" && options.showCancel !== false;
+ resetAppDialogPresentation();
+ if (appDialog && hasChoices) {
+ appDialog.classList.add("app-dialog--choice");
+ appDialog.classList.add(choiceLayout === "value-grid" ? "app-dialog--choice-grid" : "app-dialog--choice-list");
+ if (choiceLayout === "value-grid") appDialog.classList.add("app-dialog--choice-value-grid");
+ }
+
appDialogTitle.textContent = title;
if (useHtml) appDialogBody.innerHTML = String(messageHtml || message);
else appDialogBody.textContent = String(message);
@@ -180,12 +229,22 @@ function openAppDialog(options = {}) {
if (appDialogChoices) {
appDialogChoices.innerHTML = "";
appDialogChoices.hidden = !hasChoices;
+ appDialogChoices.className = `app-dialog__choices app-dialog__choices--${choiceLayout || "list"}`;
+ if (choiceLayout === "value-grid") {
+ appDialogChoices.style.setProperty("--app-dialog-choice-columns", String(appDialogChoiceColumns(choices.length, options)));
+ } else {
+ appDialogChoices.style.removeProperty("--app-dialog-choice-columns");
+ }
for (const choice of choices) {
const button = document.createElement("button");
button.type = "button";
let btnClass = choice.danger
? "btn btn--danger app-dialog__choiceBtn"
: "btn app-dialog__choiceBtn";
+ btnClass += choiceLayout === "value-grid"
+ ? " app-dialog__choiceBtn--value"
+ : " app-dialog__choiceBtn--action";
+ if (choice.current || choice.selected) btnClass += " is-current";
if (choice.className) btnClass += " " + choice.className;
button.className = btnClass;
if (choice.labelHtml) {
@@ -193,7 +252,6 @@ function openAppDialog(options = {}) {
} else {
button.textContent = String(choice.label);
}
- button.style.cssText = "text-align:left; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;";
button.addEventListener("click", () => resolveAppDialog(choice.value));
appDialogChoices.appendChild(button);
}
@@ -224,8 +282,14 @@ function openAppDialog(options = {}) {
appDialogInput.focus();
appDialogInput.select();
} else if (hasChoices && appDialogChoices) {
- const firstChoice = appDialogChoices.querySelector("button");
- if (firstChoice && typeof firstChoice.focus === "function") firstChoice.focus();
+ const currentChoice = appDialogChoices.querySelector(".is-current");
+ const firstChoice = currentChoice || appDialogChoices.querySelector("button");
+ if (firstChoice && typeof firstChoice.focus === "function") {
+ firstChoice.focus({ preventScroll: Boolean(currentChoice) });
+ if (currentChoice && typeof currentChoice.scrollIntoView === "function") {
+ currentChoice.scrollIntoView({ block: "center", inline: "nearest" });
+ }
+ }
} else if (mode === "choice" && appDialogCancel) {
appDialogCancel.focus();
} else {
diff --git a/selfdrive/carrot/web/js/shared/ui/navigation.js b/selfdrive/carrot/web/js/shared/ui/navigation.js
index ab4811c2bb..4bf0ed7b4b 100644
--- a/selfdrive/carrot/web/js/shared/ui/navigation.js
+++ b/selfdrive/carrot/web/js/shared/ui/navigation.js
@@ -698,9 +698,20 @@ btnBackCar.onclick = () => history.back();
carTitle.onclick = () => history.back();
modelTitle.onclick = () => showCarScreen("makers");
-if (btnBackGroups) btnBackGroups.onclick = () => history.back();
-settingTitle.onclick = () => history.back();
-if (itemsTitle) itemsTitle.onclick = () => history.back();
+function goBackUnlessSettingSplit() {
+ if (
+ CURRENT_PAGE === "setting" &&
+ typeof isCompactLandscapeMode === "function" &&
+ isCompactLandscapeMode()
+ ) {
+ return;
+ }
+ history.back();
+}
+
+if (btnBackGroups) btnBackGroups.onclick = goBackUnlessSettingSplit;
+settingTitle.onclick = goBackUnlessSettingSplit;
+if (itemsTitle) itemsTitle.onclick = goBackUnlessSettingSplit;
btnBackBranch.onclick = () => history.back();
branchTitle.onclick = () => history.back();
diff --git a/selfdrive/carrot_settings.json b/selfdrive/carrot_settings.json
index ce33edc1dd..cc9bb022f2 100644
--- a/selfdrive/carrot_settings.json
+++ b/selfdrive/carrot_settings.json
@@ -1,5 +1,581 @@
{
"apilot": 20220111,
+ "menu": [
+ {
+ "id": "DRIVING",
+ "ko": "주행 제어",
+ "en": "Driving",
+ "zh": "驾驶控制",
+ "groups": [
+ {
+ "id": "START_AUTO",
+ "ko": "시작·오토",
+ "en": "Start & Auto",
+ "zh": "启动·自动",
+ "groups": [
+ {
+ "id": "BASIC_START",
+ "ko": "시작 동작",
+ "en": "Engage",
+ "zh": "起步动作",
+ "params": [
+ "AlwaysLateral",
+ "AutoEngage",
+ "DisableMinSteerSpeed"
+ ]
+ },
+ {
+ "id": "BASIC_AUTOCRUISE",
+ "ko": "오토크루즈",
+ "en": "Auto Cruise",
+ "zh": "自动巡航",
+ "params": [
+ "AutoCruiseControl",
+ "AutoGasTokSpeed",
+ "AutoGasCancelSpeed",
+ "AutoGasSyncSpeed",
+ "CruiseOnDist"
+ ]
+ }
+ ]
+ },
+ {
+ "id": "BUTTON_PRESET",
+ "ko": "버튼·프리셋",
+ "en": "Buttons & Presets",
+ "zh": "按钮·预设",
+ "groups": [
+ {
+ "id": "BUTTON_MODE",
+ "ko": "버튼 모드",
+ "en": "Button Modes",
+ "zh": "按钮模式",
+ "params": [
+ "CruiseButtonMode",
+ "CancelButtonMode",
+ "LfaButtonMode",
+ "PaddleMode"
+ ]
+ },
+ {
+ "id": "BUTTON_UNIT",
+ "ko": "속도 단위",
+ "en": "Speed Units",
+ "zh": "速度单位",
+ "params": [
+ "CruiseSpeedUnit",
+ "CruiseSpeedUnitBasic",
+ "CruiseButtonLongDelay"
+ ]
+ },
+ {
+ "id": "BUTTON_TEST",
+ "ko": "버튼 테스트",
+ "en": "Button Test",
+ "zh": "按钮测试",
+ "params": [
+ "CruiseButtonTest1",
+ "CruiseButtonTest2",
+ "CruiseButtonTest3"
+ ]
+ },
+ {
+ "id": "BASIC_SPEEDTABLE",
+ "ko": "속도 프리셋",
+ "en": "Speed Presets",
+ "zh": "速度预设",
+ "params": [
+ "CruiseSpeed1",
+ "CruiseSpeed2",
+ "CruiseSpeed3",
+ "CruiseSpeed4",
+ "CruiseSpeed5"
+ ]
+ }
+ ]
+ },
+ {
+ "id": "STEER",
+ "ko": "차량 조향",
+ "en": "Steering",
+ "zh": "转向",
+ "groups": [
+ {
+ "id": "STEER_CENTER",
+ "ko": "중앙 보정",
+ "en": "Centering",
+ "zh": "居中校正",
+ "params": [
+ "PathOffset",
+ "CameraYawTrimDeg"
+ ]
+ },
+ {
+ "id": "STEER_FEEL",
+ "ko": "조향감",
+ "en": "Steering Feel",
+ "zh": "转向手感",
+ "params": [
+ "SteerActuatorDelay",
+ "LatSmoothSec",
+ "LatSuspendAngleDeg",
+ "CustomSR",
+ "SteerRatioRate"
+ ]
+ },
+ {
+ "id": "STEER_LANECHANGE",
+ "ko": "차로 변경 (자동 턴)",
+ "en": "Lane Change (Auto Turn)",
+ "zh": "变道 (自动转向)",
+ "params": [
+ "LaneChangeNeedTorque",
+ "LaneChangeDelay",
+ "LaneChangeBsd",
+ "LaneLineCheck",
+ "AutoTurnControl",
+ "AutoTurnControlSpeedTurn",
+ "AutoTurnControlTurnEnd",
+ "AutoTurnMapChange"
+ ]
+ },
+ {
+ "id": "STEER_LANEMODE",
+ "ko": "레인모드",
+ "en": "Lane Mode",
+ "zh": "车道模式",
+ "params": [
+ "LatMpcPathCost",
+ "LatMpcMotionCost",
+ "LatMpcAccelCost",
+ "LatMpcJerkCost",
+ "LatMpcSteeringRateCost",
+ "LatMpcInputOffset",
+ "UseLaneLineSpeed",
+ "UseLaneLineCurveSpeed",
+ "AdjustLaneOffset"
+ ]
+ },
+ {
+ "id": "STEER_TORQUE",
+ "ko": "고급 토크",
+ "en": "Advanced Torque",
+ "zh": "高级扭矩",
+ "groups": [
+ {
+ "id": "STEER_TORQUE_COEFF",
+ "ko": "토크 계수",
+ "en": "Torque Coefficients",
+ "zh": "扭矩系数",
+ "params": [
+ "LateralTorqueCustom",
+ "LateralTorqueAccelFactor",
+ "LateralTorqueFriction",
+ "LateralTorqueKpV",
+ "LateralTorqueKiV",
+ "LateralTorqueKf",
+ "LateralTorqueKd"
+ ]
+ },
+ {
+ "id": "STEER_TORQUE_LIMIT",
+ "ko": "조향 제한",
+ "en": "Steering Limits",
+ "zh": "转向限制",
+ "params": [
+ "CustomSteerMax",
+ "CustomSteerDeltaUp",
+ "CustomSteerDeltaDown",
+ "CustomSteerDeltaUpLC",
+ "CustomSteerDeltaDownLC"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "SPEED",
+ "ko": "속도·감속",
+ "en": "Speed & Decel",
+ "zh": "速度与减速",
+ "groups": [
+ {
+ "id": "SPEED_CAMERA",
+ "ko": "과속카메라",
+ "en": "Speed Camera",
+ "zh": "测速摄像头",
+ "params": [
+ "AutoNaviSpeedCtrlMode",
+ "AutoNaviSpeedCtrlEnd",
+ "AutoNaviSpeedDecelRate",
+ "AutoNaviSpeedSafetyFactor",
+ "AutoNaviCountDownMode"
+ ]
+ },
+ {
+ "id": "SPEED_LIMIT",
+ "ko": "제한속도",
+ "en": "Speed Limit",
+ "zh": "限速",
+ "params": [
+ "AutoRoadSpeedLimitOffset",
+ "AutoRoadSpeedAdjust",
+ "AutoSpeedUptoRoadSpeedLimit"
+ ]
+ },
+ {
+ "id": "SPEED_BUMP",
+ "ko": "방지턱",
+ "en": "Speed Bump",
+ "zh": "减速带",
+ "params": [
+ "AutoNaviSpeedBumpTime",
+ "AutoNaviSpeedBumpSpeed"
+ ]
+ },
+ {
+ "id": "SPEED_CURVE",
+ "ko": "커브·턴",
+ "en": "Curve & Turn",
+ "zh": "弯道与转弯",
+ "params": [
+ "AutoCurveSpeedFactor",
+ "AutoCurveSpeedLowerLimit",
+ "TurnSpeedControlMode",
+ "MapTurnSpeedFactor",
+ "ModelTurnSpeedFactor",
+ "ApplyModelSpeed"
+ ]
+ },
+ {
+ "id": "SPEED_TRAFFIC",
+ "ko": "신호감지",
+ "en": "Traffic Light",
+ "zh": "信号灯",
+ "params": [
+ "TrafficLightDetectMode",
+ "TrafficStopDistanceAdjust"
+ ]
+ }
+ ]
+ },
+ {
+ "id": "CRUISE",
+ "ko": "크루즈·차간",
+ "en": "Cruise & Gap",
+ "zh": "巡航与车距",
+ "groups": [
+ {
+ "id": "CRUISE_ACCEL",
+ "ko": "가속 성향",
+ "en": "Accel Profile",
+ "zh": "加速特性",
+ "groups": [
+ {
+ "id": "CRUISE_DRIVE_MODE",
+ "ko": "드라이브 모드",
+ "en": "Drive Mode",
+ "zh": "驾驶模式",
+ "params": [
+ "MyDrivingMode",
+ "MyDrivingModeAuto"
+ ]
+ },
+ {
+ "id": "CRUISE_ACCEL_TABLE",
+ "ko": "속도별 가속값",
+ "en": "Speed Accel Table",
+ "zh": "速度加速表",
+ "params": [
+ "CruiseMaxVals0",
+ "CruiseMaxVals1",
+ "CruiseMaxVals2",
+ "CruiseMaxVals3",
+ "CruiseMaxVals4",
+ "CruiseMaxVals5",
+ "CruiseMaxVals6"
+ ]
+ }
+ ]
+ },
+ {
+ "id": "CRUISE_STOPGO",
+ "ko": "정차·재출발",
+ "en": "Stop & Resume",
+ "zh": "停车与再起步",
+ "params": [
+ "StopDistanceCarrot",
+ "StoppingAccel",
+ "VEgoStopping",
+ "AChangeCostStarting"
+ ]
+ },
+ {
+ "id": "CRUISE_LONGTUNE",
+ "ko": "가감속 튜닝",
+ "en": "Accel/Brake Tuning",
+ "zh": "加减速调校",
+ "params": [
+ "LongTuningKpV",
+ "LongTuningKiV",
+ "LongTuningKf",
+ "LongActuatorDelay"
+ ]
+ },
+ {
+ "id": "CRUISE_GAP",
+ "ko": "차간거리",
+ "en": "Follow Gap",
+ "zh": "车距",
+ "params": [
+ "TFollowGap1",
+ "TFollowGap2",
+ "TFollowGap3",
+ "TFollowGap4",
+ "DynamicTFollow",
+ "DynamicTFollowLC",
+ "EnableSpeedTF",
+ "TFollowDecelBoost"
+ ]
+ },
+ {
+ "id": "CRUISE_LEAD",
+ "ko": "선행차 반응",
+ "en": "Lead Response",
+ "zh": "前车响应",
+ "params": [
+ "JLeadFactor3",
+ "RadarReactionFactor"
+ ]
+ },
+ {
+ "id": "CRUISE_CARROT",
+ "ko": "당근 크루즈",
+ "en": "Carrot Cruise",
+ "zh": "Carrot巡航",
+ "params": [
+ "CruiseEcoControl",
+ "CarrotCruiseDecel",
+ "CarrotCruiseAtcDecel"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "VEHICLE",
+ "ko": "차량·하드웨어",
+ "en": "Vehicle & Hardware",
+ "zh": "车辆与硬件",
+ "groups": [
+ {
+ "id": "VEH_HYUNDAI",
+ "ko": "현대·기아",
+ "en": "Hyundai·Kia",
+ "zh": "现代·起亚",
+ "params": [
+ "HyundaiCameraSCC",
+ "IsLdwsCar",
+ "HapticFeedbackWhenSpeedCamera"
+ ]
+ },
+ {
+ "id": "VEH_CANFD",
+ "ko": "CANFD·HDA",
+ "en": "CANFD·HDA",
+ "zh": "CANFD·HDA",
+ "params": [
+ "CanfdHDA2",
+ "CanfdDebug",
+ "HDPuse"
+ ]
+ },
+ {
+ "id": "VEH_RADAR",
+ "ko": "레이더",
+ "en": "Radar",
+ "zh": "雷达",
+ "params": [
+ "EnableRadarTracks",
+ "RadarLatFactor",
+ "EnableCornerRadar"
+ ]
+ },
+ {
+ "id": "VEH_DM",
+ "ko": "운전자 모니터링",
+ "en": "Driver Monitor",
+ "zh": "驾驶员监控",
+ "params": [
+ "DisableDM",
+ "MuteDoor",
+ "MuteSeatbelt"
+ ]
+ },
+ {
+ "id": "VEH_AUX",
+ "ko": "차량 보조",
+ "en": "Vehicle Aux",
+ "zh": "车辆辅助",
+ "params": [
+ "MaxAngleFrames",
+ "SpeedFromPCM"
+ ]
+ }
+ ]
+ },
+ {
+ "id": "DISPLAY",
+ "ko": "화면 표시",
+ "en": "Display",
+ "zh": "显示",
+ "groups": [
+ {
+ "id": "DISP_SCREEN",
+ "ko": "정보 표시",
+ "en": "On-screen Info",
+ "zh": "信息显示",
+ "params": [
+ "ShowDebugUI",
+ "ShowTpms",
+ "ShowDateTime",
+ "ShowPathEnd",
+ "ShowDeviceState",
+ "ShowLaneInfo",
+ "ShowRadarInfo",
+ "ShowRouteInfo",
+ "ShowPlotMode"
+ ]
+ },
+ {
+ "id": "DISP_PATH",
+ "ko": "경로 표시",
+ "en": "Path Display",
+ "zh": "路径显示",
+ "params": [
+ "CarrotTireTrajectory",
+ "ShowPathMode",
+ "ShowPathColor",
+ "ShowPathColorCruiseOff",
+ "ShowPathModeLane",
+ "ShowPathColorLane"
+ ]
+ },
+ {
+ "id": "DISP_BRIGHT",
+ "ko": "밝기·주행화면",
+ "en": "Brightness & View",
+ "zh": "亮度与视图",
+ "params": [
+ "ShowCustomBrightness",
+ "ShowModelView"
+ ]
+ },
+ {
+ "id": "DISP_HUD",
+ "ko": "외부 HUD",
+ "en": "External HUD",
+ "zh": "外部HUD",
+ "groups": [
+ {
+ "id": "HUD_BASIC",
+ "ko": "기본",
+ "en": "Basic",
+ "zh": "基本",
+ "params": [
+ "ClusterHud",
+ "ClusterHudBrightness",
+ "ClusterHudTheme"
+ ]
+ },
+ {
+ "id": "HUD_SCREEN",
+ "ko": "화면·카메라",
+ "en": "Screen & Camera",
+ "zh": "画面·摄像头",
+ "params": [
+ "ClusterHudEncoder",
+ "ClusterHudLiveFps",
+ "ClusterHudScreenMode",
+ "ClusterHudCameraViewMode"
+ ]
+ },
+ {
+ "id": "HUD_RADAR",
+ "ko": "레이더 표시",
+ "en": "Radar Display",
+ "zh": "雷达显示",
+ "params": [
+ "ClusterHudRadarInfo",
+ "ClusterHudRadarDisplay",
+ "ClusterHudRadarSourceColor"
+ ]
+ },
+ {
+ "id": "HUD_PERF",
+ "ko": "성능·디버그",
+ "en": "Performance & Debug",
+ "zh": "性能·调试",
+ "params": [
+ "ClusterHudCoreMode",
+ "ClusterHudPriority",
+ "ClusterHudDebug"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "SYSTEM",
+ "ko": "시스템",
+ "en": "System",
+ "zh": "系统",
+ "groups": [
+ {
+ "id": "SYS_RECORD",
+ "ko": "녹화·전원",
+ "en": "Record & Power",
+ "zh": "录制与电源",
+ "params": [
+ "RecordRoadCam",
+ "MaxTimeOffroadMin"
+ ]
+ },
+ {
+ "id": "SYS_NET",
+ "ko": "네트워크·지도",
+ "en": "Network & Map",
+ "zh": "网络与地图",
+ "params": [
+ "HotspotOnBoot",
+ "MapboxStyle"
+ ]
+ },
+ {
+ "id": "SYS_SOUND",
+ "ko": "사운드",
+ "en": "Sound",
+ "zh": "声音",
+ "params": [
+ "SoundVolumeAdjust",
+ "SoundVolumeAdjustEngage"
+ ]
+ },
+ {
+ "id": "SYS_SW",
+ "ko": "소프트웨어",
+ "en": "Software",
+ "zh": "软件",
+ "params": [
+ "SoftwareMenu"
+ ]
+ }
+ ]
+ }
+ ],
"params": [
{
"group": "조향일반",
@@ -9,13 +585,13 @@
"egroup": "LAT",
"etitle": "Lane Deviation Left/Right Correction(0)",
"edescr": "LaneMode only — (-)Left / (+)Right",
+ "cgroup": "转向",
+ "ctitle": "车道偏移左右修正(0)",
+ "cdescr": "仅限车道模式 — (-)左侧 / (+)右侧",
"min": -150,
"max": 150,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "车道偏移左右修正(0)",
- "cdescr": "仅限车道模式 — (-)左侧 / (+)右侧"
+ "unit": 1
},
{
"group": "조향일반",
@@ -25,13 +601,13 @@
"egroup": "LAT",
"etitle": "Camera YAW Correction(0)",
"edescr": "Fine tunes camera yaw alignment.(+: right)",
+ "cgroup": "转向",
+ "ctitle": "摄像头YAW校正(0)",
+ "cdescr": "微调摄像头左右(YAW)值(+: right)",
"min": -200,
"max": 200,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "摄像头YAW校正(0)",
- "cdescr": "微调摄像头左右(YAW)值(+: right)"
+ "unit": 1
},
{
"group": "조향토크",
@@ -41,13 +617,13 @@
"egroup": "LAT_TQ",
"etitle": "_LateralTorqueCustom(0)",
"edescr": "Use Custom Torque(TorqueAccelFactor, FrictionFactor)",
+ "cgroup": "转向",
+ "ctitle": "自定义转向力矩(0)",
+ "cdescr": "使用自定义力矩 (TorqueAccelFactor, FrictionFactor)",
"min": 0,
"max": 1,
"default": 1,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "自定义转向力矩(0)",
- "cdescr": "使用自定义力矩 (TorqueAccelFactor, FrictionFactor)"
+ "unit": 1
},
{
"group": "조향토크",
@@ -57,13 +633,13 @@
"egroup": "LAT_TQ",
"etitle": "_LateralTorqueAccelFactor*0.001(2500)",
"edescr": "As the value decreases, the torque becomes stronger up to a point, then weakens — Uses the value at the strongest point.",
+ "cgroup": "转向",
+ "ctitle": "转向力矩加速系数*0.001(2500)",
+ "cdescr": "随着值减小,力矩会增强到某一点然后变弱 — 请使用力矩最强点的值。",
"min": 1000,
"max": 6000,
"default": 2500,
- "unit": 100,
- "cgroup": "转向",
- "ctitle": "转向力矩加速系数*0.001(2500)",
- "cdescr": "随着值减小,力矩会增强到某一点然后变弱 — 请使用力矩最强点的值。"
+ "unit": 100
},
{
"group": "조향토크",
@@ -73,13 +649,13 @@
"egroup": "LAT_TQ",
"etitle": "_LateralTorqueFriction*0.001(100)",
"edescr": "More fine steering at higher values — 0-50 recommended",
+ "cgroup": "转向",
+ "ctitle": "转向力矩摩擦系数*0.001(100)",
+ "cdescr": "值越高微操越多 — 推荐 0-50",
"min": 0,
"max": 1000,
"default": 100,
- "unit": 10,
- "cgroup": "转向",
- "ctitle": "转向力矩摩擦系数*0.001(100)",
- "cdescr": "值越高微操越多 — 推荐 0-50"
+ "unit": 10
},
{
"group": "조향토크",
@@ -89,13 +665,13 @@
"egroup": "LAT_TQ",
"etitle": "_LateralTorqueKp*0.01(100)",
"edescr": "Steering Response Speed (Instant Reaction) — 140 Recommended",
+ "cgroup": "转向",
+ "ctitle": "转向力矩 Kp*0.01(100)",
+ "cdescr": "转向响应速度 (瞬时反应) — 推荐 140",
"min": 0,
"max": 200,
"default": 100,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "转向力矩 Kp*0.01(100)",
- "cdescr": "转向响应速度 (瞬时反应) — 推荐 140"
+ "unit": 1
},
{
"group": "조향토크",
@@ -105,13 +681,13 @@
"egroup": "LAT_TQ",
"etitle": "_LateralTorqueKi*0.01(10)",
"edescr": "Steering Accumulated Error Correction — 20 Recommended",
+ "cgroup": "转向",
+ "ctitle": "转向力矩 Ki*0.01(10)",
+ "cdescr": "转向累积误差修正 — 推荐 20",
"min": 0,
"max": 200,
"default": 10,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "转向力矩 Ki*0.01(10)",
- "cdescr": "转向累积误差修正 — 推荐 20"
+ "unit": 1
},
{
"group": "조향토크",
@@ -121,13 +697,13 @@
"egroup": "LAT_TQ",
"etitle": "_LateralTorqueKf*0.001(100)",
"edescr": "Steering Feedforward Correction — 85 Recommended",
+ "cgroup": "转向",
+ "ctitle": "转向力矩 Kf*0.001(100)",
+ "cdescr": "转向前馈修正 — 推荐 85",
"min": 0,
"max": 200,
"default": 100,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "转向力矩 Kf*0.001(100)",
- "cdescr": "转向前馈修正 — 推荐 85"
+ "unit": 1
},
{
"group": "조향토크",
@@ -137,13 +713,13 @@
"egroup": "LAT_TQ",
"etitle": "_LateralTorqueKd*0.01(0)",
"edescr": "Steering Derivative Gain, 0 Recommended",
+ "cgroup": "转向",
+ "ctitle": "转向力矩 Kd*0.01(0)",
+ "cdescr": "转向微分增益,推荐 0",
"min": 0,
"max": 10000,
"default": 0,
- "unit": 10,
- "cgroup": "转向",
- "ctitle": "转向力矩 Kd*0.01(0)",
- "cdescr": "转向微分增益,推荐 0"
+ "unit": 10
},
{
"group": "레인모드",
@@ -153,13 +729,13 @@
"egroup": "LANE",
"etitle": "*LATMPC.PathCost(200)",
"edescr": "(LaneMode) Path Following Weight — Higher values prioritize the path",
+ "cgroup": "转向",
+ "ctitle": "横向MPC路径代价(200)",
+ "cdescr": "(车道模式) 路径跟随权重 — 值越高越优先考虑路径",
"min": 0,
"max": 500,
"default": 200,
- "unit": 10,
- "cgroup": "转向",
- "ctitle": "横向MPC路径代价(200)",
- "cdescr": "(车道模式) 路径跟随权重 — 值越高越优先考虑路径"
+ "unit": 10
},
{
"group": "레인모드",
@@ -169,13 +745,13 @@
"egroup": "LANE",
"etitle": "*LATMPC.MotionCost(7)",
"edescr": "(LaneMode) Heading Weight",
+ "cgroup": "转向",
+ "ctitle": "横向MPC运动代价(7)",
+ "cdescr": "(车道模式) 航向权重",
"min": 0,
"max": 500,
"default": 7,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "横向MPC运动代价(7)",
- "cdescr": "(车道模式) 航向权重"
+ "unit": 1
},
{
"group": "레인모드",
@@ -185,13 +761,13 @@
"egroup": "LANE",
"etitle": "*LATMPC.AccelCost(120)",
"edescr": "(LaneMode) Lateral Acceleration Limit — Lower values increase agility but reduce stability",
+ "cgroup": "转向",
+ "ctitle": "横向MPC加速代价(120)",
+ "cdescr": "(车道模式) 侧向加速度限制 — 值越低灵活性越高但稳定性降低",
"min": 0,
"max": 500,
"default": 100,
- "unit": 10,
- "cgroup": "转向",
- "ctitle": "横向MPC加速代价(120)",
- "cdescr": "(车道模式) 侧向加速度限制 — 值越低灵活性越高但稳定性降低"
+ "unit": 10
},
{
"group": "레인모드",
@@ -201,13 +777,13 @@
"egroup": "LANE",
"etitle": "*LATMPC.JerkCost(4)",
"edescr": "(LaneMode) Lower values allow quicker steering — reduces smoothness",
+ "cgroup": "转向",
+ "ctitle": "横向MPC冲击代价(4)",
+ "cdescr": "(车道模式) 值越低允许越快的转向 — 会降低平滑度",
"min": 0,
"max": 200,
"default": 1,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "横向MPC冲击代价(4)",
- "cdescr": "(车道模式) 值越低允许越快的转向 — 会降低平滑度"
+ "unit": 1
},
{
"group": "레인모드",
@@ -217,13 +793,13 @@
"egroup": "LANE",
"etitle": "*LATMPC.SteerRateCost(7)",
"edescr": "(LaneMode) Steering Rate Limit — Lower values make steering more aggressive",
+ "cgroup": "转向",
+ "ctitle": "横向MPC转向速率代价(7)",
+ "cdescr": "(车道模式) 转向速率限制 — 值越低转向越激进",
"min": 0,
"max": 1000,
"default": 7,
- "unit": 100,
- "cgroup": "转向",
- "ctitle": "横向MPC转向速率代价(7)",
- "cdescr": "(车道模式) 转向速率限制 — 值越低转向越激进"
+ "unit": 100
},
{
"group": "레인모드",
@@ -233,13 +809,13 @@
"egroup": "LANE",
"etitle": "*LATMPC.InputOffset(4)",
"edescr": "(LaneMode) MPC Input Compensation — Higher values enter curves earlier",
+ "cgroup": "转向",
+ "ctitle": "横向MPC输入偏移(4)",
+ "cdescr": "(车道模式) MPC 输入补偿 — 值越高进入弯道越早",
"min": 0,
"max": 20,
"default": 4,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "横向MPC输入偏移(4)",
- "cdescr": "(车道模式) MPC 输入补偿 — 值越高进入弯道越早"
+ "unit": 1
},
{
"group": "조향토크",
@@ -249,13 +825,13 @@
"egroup": "LAT_TQ",
"etitle": "_CustomSteerMax(0)",
"edescr": "Maximum Steering Torque — Use the largest value among 270/384/409 that does not cause errors",
+ "cgroup": "转向",
+ "ctitle": "自定义最大转向力矩(0)",
+ "cdescr": "最大转向力矩 — 在 270/384/409 中选择不报错的最大值",
"min": 0,
"max": 30000,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "自定义最大转向力矩(0)",
- "cdescr": "最大转向力矩 — 在 270/384/409 中选择不报错的最大值"
+ "unit": 1
},
{
"group": "조향토크",
@@ -265,13 +841,13 @@
"egroup": "LAT_TQ",
"etitle": "_CustomSteerDeltaUp(0)",
"edescr": "Torque Vehicle — Higher values increase steering wheel turn speed",
+ "cgroup": "转向",
+ "ctitle": "自定义转向增大斜率(0)",
+ "cdescr": "力矩控制车辆 — 值越高方向盘转动速度越快",
"min": 0,
"max": 50,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "自定义转向增大斜率(0)",
- "cdescr": "力矩控制车辆 — 值越高方向盘转动速度越快"
+ "unit": 1
},
{
"group": "조향토크",
@@ -281,13 +857,13 @@
"egroup": "LAT_TQ",
"etitle": "_CustomSteerDeltaDown(0)",
"edescr": "Torque Vehicle — Higher values increase steering wheel release speed",
+ "cgroup": "转向",
+ "ctitle": "自定义转向减小斜率(0)",
+ "cdescr": "力矩控制车辆 — 值越高方向盘回正速度越快",
"min": 0,
"max": 50,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "自定义转向减小斜率(0)",
- "cdescr": "力矩控制车辆 — 值越高方向盘回正速度越快"
+ "unit": 1
},
{
"group": "조향토크",
@@ -297,13 +873,13 @@
"egroup": "LAT_TQ",
"etitle": "_CustomSteerDeltaUpLC(0)",
"edescr": "Torque Vehicle — Temporarily applies SteerDeltaUp during lane changes",
+ "cgroup": "转向",
+ "ctitle": "变道自定义转向增大斜率(0)",
+ "cdescr": "力矩控制车辆 — 变道期间临时应用转向增大斜率",
"min": 0,
"max": 50,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "变道自定义转向增大斜率(0)",
- "cdescr": "力矩控制车辆 — 变道期间临时应用转向增大斜率"
+ "unit": 1
},
{
"group": "조향토크",
@@ -313,13 +889,13 @@
"egroup": "LAT_TQ",
"etitle": "_CustomSteerDeltaDownLC(0)",
"edescr": "Torque Vehicle — Temporarily applies SteerDeltaDown during lane changes",
+ "cgroup": "转向",
+ "ctitle": "变道自定义转向减小斜率(0)",
+ "cdescr": "力矩控制车辆 — 变道期间临时应用转向减小斜率",
"min": 0,
"max": 50,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "变道自定义转向减小斜率(0)",
- "cdescr": "力矩控制车辆 — 变道期间临时应用转向减小斜率"
+ "unit": 1
},
{
"group": "조향튜닝",
@@ -329,13 +905,13 @@
"egroup": "LAT",
"etitle": "SteerActuatorDelay(30)",
"edescr": "Steering Delay Value — Higher values steer earlier. 0 means Live Delay",
+ "cgroup": "转向",
+ "ctitle": "转向执行器延迟(30)",
+ "cdescr": "转向延迟值 — 值越高转向越早。0 表示实时延迟",
"min": 0,
"max": 300,
"default": 30,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "转向执行器延迟(30)",
- "cdescr": "转向延迟值 — 值越高转向越早。0 表示实时延迟"
+ "unit": 1
},
{
"group": "조향튜닝",
@@ -345,13 +921,13 @@
"egroup": "LAT",
"etitle": "LatSmoothSec(13)",
"edescr": "Lat smoothing values — Higher values smoother",
+ "cgroup": "转向",
+ "ctitle": "转向平滑时间(30)",
+ "cdescr": "转向平滑值 — 值越高越平滑",
"min": 1,
"max": 30,
"default": 13,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "转向平滑时间(30)",
- "cdescr": "转向平滑值 — 值越高越平滑"
+ "unit": 1
},
{
"group": "조향튜닝",
@@ -361,13 +937,13 @@
"egroup": "LAT",
"etitle": "AutoSteering Suspend Angle(300)",
"edescr": "Auto steering pauses at large steering angles and resumes when it returns within 15.",
+ "cgroup": "转向",
+ "ctitle": "AutoSteering Suspend Angle(300)",
+ "cdescr": "Auto steering pauses at large steering angles and resumes when it returns within 15.",
"min": 45,
"max": 300,
"default": 300,
- "unit": 10,
- "cgroup": "转向",
- "ctitle": "AutoSteering Suspend Angle(300)",
- "cdescr": "Auto steering pauses at large steering angles and resumes when it returns within 15."
+ "unit": 10
},
{
"group": "크루즈",
@@ -377,13 +953,13 @@
"egroup": "CRUISE",
"etitle": "CruiseOnDist(0cm)",
"edescr": "Cruise ON when releasing the pedal and the front car gets close",
+ "cgroup": "巡航设置",
+ "ctitle": "巡航开启距离(0cm)",
+ "cdescr": "松开油门且前车靠近时开启巡航",
"min": 0,
"max": 2500,
"default": 0,
- "unit": 50,
- "cgroup": "巡航设置",
- "ctitle": "巡航开启距离(0cm)",
- "cdescr": "松开油门且前车靠近时开启巡航"
+ "unit": 50
},
{
"group": "크루즈",
@@ -393,13 +969,13 @@
"egroup": "CRUISE",
"etitle": "CruiseEcoControl(2km/h)",
"edescr": "Temporarily increases the target speed for fuel efficiency",
+ "cgroup": "巡航设置",
+ "ctitle": "巡航节能控制(2km/h)",
+ "cdescr": "为提高燃油效率临时提高目标速度",
"min": 0,
"max": 10,
"default": 2,
- "unit": 1,
- "cgroup": "巡航设置",
- "ctitle": "巡航节能控制(2km/h)",
- "cdescr": "为提高燃油效率临时提高目标速度"
+ "unit": 1
},
{
"group": "크루즈",
@@ -409,13 +985,13 @@
"egroup": "CRUISE",
"etitle": "CarrotCruiseDecel(-1)",
"edescr": "Carrot Cruise Deceleration Setting, -1: Cruise OFF",
+ "cgroup": "巡航设置",
+ "ctitle": "胡萝卜巡航减速度(-1)",
+ "cdescr": "胡萝卜巡航减速度设置,-1: 巡航关闭",
"min": -1,
"max": 200,
"default": -1,
- "unit": 10,
- "cgroup": "巡航设置",
- "ctitle": "胡萝卜巡航减速度(-1)",
- "cdescr": "胡萝卜巡航减速度设置,-1: 巡航关闭"
+ "unit": 10
},
{
"group": "크루즈",
@@ -425,13 +1001,13 @@
"egroup": "CRUISE",
"etitle": "CarrotCruiseDecelATCx0.01(-1)",
"edescr": "Carrot Cruise ATC Deceleration Setting, -1: Not Change",
+ "cgroup": "巡航设置",
+ "ctitle": "胡萝卜巡航 ATC 减速度(-1)",
+ "cdescr": "胡萝卜巡航 ATC 减速度设置,-1: 不改变",
"min": -1,
"max": 200,
"default": -1,
- "unit": 10,
- "cgroup": "巡航设置",
- "ctitle": "胡萝卜巡航 ATC 减速度(-1)",
- "cdescr": "胡萝卜巡航 ATC 减速度设置,-1: 不改变"
+ "unit": 10
},
{
"group": "조향튜닝",
@@ -441,13 +1017,13 @@
"egroup": "LAT",
"etitle": "CustomSteerRatiox0.1(0)",
"edescr": "Steering Ratio (Refer to Vehicle Specs), 0: Uses LiveSteerRatio",
+ "cgroup": "转向",
+ "ctitle": "自定义转向比x0.1(0)",
+ "cdescr": "转向比 (参考车辆参数),0: 使用实时转向比",
"min": 0,
"max": 300,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "自定义转向比x0.1(0)",
- "cdescr": "转向比 (参考车辆参数),0: 使用实时转向比"
+ "unit": 1
},
{
"group": "조향튜닝",
@@ -457,13 +1033,13 @@
"egroup": "LAT",
"etitle": "CustomSteerRatioRatex0.01(100)",
"edescr": "LiveSteerRatio Application Ratio (Requires CustomSR set to 0)",
+ "cgroup": "转向",
+ "ctitle": "自定义转向比率x0.01(100)",
+ "cdescr": "实时转向比应用比例 (需要 CustomSR 设置为 0)",
"min": 30,
"max": 200,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "自定义转向比率x0.01(100)",
- "cdescr": "实时转向比应用比例 (需要 CustomSR 设置为 0)"
+ "unit": 1
},
{
"group": "가속설정",
@@ -473,13 +1049,13 @@
"egroup": "ACCEL",
"etitle": "AccelSet0:0km/h(160)",
"edescr": "Acceleration from 0 km/h to 10 km/h",
+ "cgroup": "加速设置",
+ "ctitle": "加速度设置 0: 0km/h(160)",
+ "cdescr": "0 km/h 到 10 km/h 的加速度",
"min": 1,
"max": 250,
"default": 160,
- "unit": 5,
- "cgroup": "加速设置",
- "ctitle": "加速度设置 0: 0km/h(160)",
- "cdescr": "0 km/h 到 10 km/h 的加速度"
+ "unit": 5
},
{
"group": "가속설정",
@@ -489,13 +1065,13 @@
"egroup": "ACCEL",
"etitle": "AccelSet1:10km/h(160)",
"edescr": "Acceleration from 10 km/h to 40 km/h",
+ "cgroup": "加速设置",
+ "ctitle": "加速度设置 1: 10km/h(160)",
+ "cdescr": "10 km/h 到 40 km/h 的加速度",
"min": 1,
"max": 250,
"default": 160,
- "unit": 5,
- "cgroup": "加速设置",
- "ctitle": "加速度设置 1: 10km/h(160)",
- "cdescr": "10 km/h 到 40 km/h 的加速度"
+ "unit": 5
},
{
"group": "가속설정",
@@ -505,13 +1081,13 @@
"egroup": "ACCEL",
"etitle": "AccelSet2:40km/h(120)",
"edescr": "Acceleration from 40 km/h to 60 km/h",
+ "cgroup": "加速设置",
+ "ctitle": "加速度设置 2: 40km/h(120)",
+ "cdescr": "40 km/h 到 60 km/h 的加速度",
"min": 1,
"max": 250,
"default": 120,
- "unit": 5,
- "cgroup": "加速设置",
- "ctitle": "加速度设置 2: 40km/h(120)",
- "cdescr": "40 km/h 到 60 km/h 的加速度"
+ "unit": 5
},
{
"group": "가속설정",
@@ -521,13 +1097,13 @@
"egroup": "ACCEL",
"etitle": "AccelSet3:60km/h(100)",
"edescr": "Acceleration from 60 km/h to 80 km/h",
+ "cgroup": "加速设置",
+ "ctitle": "加速度设置 3: 60km/h(100)",
+ "cdescr": "60 km/h 到 80 km/h 的加速度",
"min": 1,
"max": 250,
"default": 100,
- "unit": 5,
- "cgroup": "加速设置",
- "ctitle": "加速度设置 3: 60km/h(100)",
- "cdescr": "60 km/h 到 80 km/h 的加速度"
+ "unit": 5
},
{
"group": "가속설정",
@@ -537,13 +1113,13 @@
"egroup": "ACCEL",
"etitle": "AccelSet4:80km/h(80)",
"edescr": "Acceleration from 80 km/h to 110 km/h",
+ "cgroup": "加速设置",
+ "ctitle": "加速度设置 4: 80km/h(80)",
+ "cdescr": "80 km/h 到 110 km/h 的加速度",
"min": 1,
"max": 250,
"default": 80,
- "unit": 5,
- "cgroup": "加速设置",
- "ctitle": "加速度设置 4: 80km/h(80)",
- "cdescr": "80 km/h 到 110 km/h 的加速度"
+ "unit": 5
},
{
"group": "가속설정",
@@ -553,13 +1129,13 @@
"egroup": "ACCEL",
"etitle": "AccelSet5:110km/h(70)",
"edescr": "Acceleration from 110 km/h to 140 km/h",
+ "cgroup": "加速设置",
+ "ctitle": "加速度设置 5: 110km/h(70)",
+ "cdescr": "110 km/h 到 140 km/h 的加速度",
"min": 1,
"max": 250,
"default": 70,
- "unit": 5,
- "cgroup": "加速设置",
- "ctitle": "加速度设置 5: 110km/h(70)",
- "cdescr": "110 km/h 到 140 km/h 的加速度"
+ "unit": 5
},
{
"group": "가속설정",
@@ -569,13 +1145,13 @@
"egroup": "ACCEL",
"etitle": "AccelSet6:140km/h(60)",
"edescr": "Acceleration from 140 km/h",
+ "cgroup": "加速设置",
+ "ctitle": "加速度设置 6: 140km/h(60)",
+ "cdescr": "140 km/h 以上的加速度",
"min": 1,
"max": 250,
"default": 60,
- "unit": 5,
- "cgroup": "加速设置",
- "ctitle": "加速度设置 6: 140km/h(60)",
- "cdescr": "140 km/h 以上的加速度"
+ "unit": 5
},
{
"group": "주행튜닝",
@@ -585,13 +1161,13 @@
"egroup": "LONG",
"etitle": "StopDistance(600)cm",
"edescr": "Stop Distance * 0.8",
+ "cgroup": "纵向控制",
+ "ctitle": "停止距离(600)cm",
+ "cdescr": "停止距离 * 0.8",
"min": 400,
"max": 1000,
"default": 600,
- "unit": 10,
- "cgroup": "纵向控制",
- "ctitle": "停止距离(600)cm",
- "cdescr": "停止距离 * 0.8"
+ "unit": 10
},
{
"group": "주행튜닝",
@@ -601,13 +1177,13 @@
"egroup": "LONG",
"etitle": "AChangeCostStarting",
"edescr": "AccelCost Starting, 0:rapid starting",
+ "cgroup": "纵向控制",
+ "ctitle": "启动加速度限制",
+ "cdescr": "启动加速代价,0: 快速启动",
"min": 0,
"max": 200,
"default": 10,
- "unit": 10,
- "cgroup": "纵向控制",
- "ctitle": "启动加速度限制",
- "cdescr": "启动加速代价,0: 快速启动"
+ "unit": 10
},
{
"group": "주행튜닝",
@@ -617,13 +1193,13 @@
"egroup": "LONG",
"etitle": "TrafficStopDistanceAdjust",
"edescr": "",
+ "cgroup": "纵向控制",
+ "ctitle": "交通信号停止距离调整",
+ "cdescr": "",
"min": -600,
"max": 600,
"default": -150,
- "unit": 100,
- "cgroup": "纵向控制",
- "ctitle": "交通信号停止距离调整",
- "cdescr": ""
+ "unit": 100
},
{
"group": "주행튜닝",
@@ -633,13 +1209,13 @@
"egroup": "LONG",
"etitle": "JerkLeadFactor(0)",
"edescr": "Higher values respond more sensitively to acceleration changes of the lead vehicle",
+ "cgroup": "纵向控制",
+ "ctitle": "前车冲击因子(0)",
+ "cdescr": "值越高对前车加速度变化的反应越敏感",
"min": 0,
"max": 100,
"default": 0,
- "unit": 10,
- "cgroup": "纵向控制",
- "ctitle": "前车冲击因子(0)",
- "cdescr": "值越高对前车加速度变化的反应越敏感"
+ "unit": 10
},
{
"group": "주행튜닝",
@@ -649,13 +1225,13 @@
"egroup": "LONG",
"etitle": "Long KpV(100)x0.01",
"edescr": "Longitudinal Control Proportional Gain (Immediate Error Response) — HKG: 100 Recommended",
+ "cgroup": "纵向控制",
+ "ctitle": "纵向 KpV(100)x0.01",
+ "cdescr": "纵向控制比例增益 (瞬时误差响应) — HKG: 推荐 100",
"min": 0,
"max": 200,
"default": 100,
- "unit": 5,
- "cgroup": "纵向控制",
- "ctitle": "纵向 KpV(100)x0.01",
- "cdescr": "纵向控制比例增益 (瞬时误差响应) — HKG: 推荐 100"
+ "unit": 5
},
{
"group": "주행튜닝",
@@ -665,13 +1241,13 @@
"egroup": "LONG",
"etitle": "Long Kf(100)x0.01",
"edescr": "Longitudinal Feedforward Correction — HKG: 100 Recommended",
+ "cgroup": "纵向控制",
+ "ctitle": "纵向 Kf(100)x0.01",
+ "cdescr": "纵向前馈修正 — HKG: 推荐 100",
"min": 0,
"max": 200,
"default": 0,
- "unit": 5,
- "cgroup": "纵向控制",
- "ctitle": "纵向 Kf(100)x0.01",
- "cdescr": "纵向前馈修正 — HKG: 推荐 100"
+ "unit": 5
},
{
"group": "주행튜닝",
@@ -681,13 +1257,13 @@
"egroup": "LONG",
"etitle": "Long KiV(0)x0.01",
"edescr": "Longitudinal Integral Gain (Cumulative Error Correction) — HKG: 0 Recommended",
+ "cgroup": "纵向控制",
+ "ctitle": "纵向 KiV(0)x0.01",
+ "cdescr": "纵向积分增益 (累积误差修正) — HKG: 推荐 0",
"min": 0,
"max": 2000,
"default": 0,
- "unit": 1,
- "cgroup": "纵向控制",
- "ctitle": "纵向 KiV(0)x0.01",
- "cdescr": "纵向积分增益 (累积误差修正) — HKG: 推荐 0"
+ "unit": 1
},
{
"group": "주행튜닝",
@@ -697,13 +1273,13 @@
"egroup": "LONG",
"etitle": "LongActuatorDelay(20)x0.01",
"edescr": "Longitudinal Delay Value (Higher values lead to earlier acceleration/deceleration) — HKG: 20 Recommeded",
+ "cgroup": "纵向控制",
+ "ctitle": "纵向执行器延迟(20)x0.01",
+ "cdescr": "纵向延迟值 (值越高越早开始加减速) — HKG: 推荐 20",
"min": 0,
"max": 200,
"default": 20,
- "unit": 5,
- "cgroup": "纵向控制",
- "ctitle": "纵向执行器延迟(20)x0.01",
- "cdescr": "纵向延迟值 (值越高越早开始加减速) — HKG: 推荐 20"
+ "unit": 5
},
{
"group": "주행튜닝",
@@ -713,13 +1289,13 @@
"egroup": "LONG",
"etitle": "VEgoStopping(50)x0.01",
"edescr": "Lower values result in quicker starts; setting too low may increase collision risk. (5 recommended)",
+ "cgroup": "纵向控制",
+ "ctitle": "停止/启动灵敏度(50)x0.01",
+ "cdescr": "值越低起步越快;设置过低可能会增加碰撞风险 (推荐 5)",
"min": 1,
"max": 100,
"default": 50,
- "unit": 5,
- "cgroup": "纵向控制",
- "ctitle": "停止/启动灵敏度(50)x0.01",
- "cdescr": "值越低起步越快;设置过低可能会增加碰撞风险 (推荐 5)"
+ "unit": 5
},
{
"group": "주행튜닝",
@@ -729,13 +1305,13 @@
"egroup": "LONG",
"etitle": "Radar reaction factor (100)%",
"edescr": "Lower value: faster response to lead car",
+ "cgroup": "纵向控制",
+ "ctitle": "雷达反应因子 (100)%",
+ "cdescr": "值越低:对前车的反应越快",
"min": 0,
"max": 200,
"default": 100,
- "unit": 1,
- "cgroup": "纵向控制",
- "ctitle": "雷达反应因子 (100)%",
- "cdescr": "值越低:对前车的反应越快"
+ "unit": 1
},
{
"group": "감속제어",
@@ -745,13 +1321,13 @@
"egroup": "DECEL",
"etitle": "CurveSpeedFactor(100%)",
"edescr": "Higher value: slow curve speed",
+ "cgroup": "减速控制",
+ "ctitle": "弯道速度调节比例(100%)",
+ "cdescr": "值越高:弯道速度越慢",
"min": 50,
"max": 300,
"default": 100,
- "unit": 5,
- "cgroup": "减速控制",
- "ctitle": "弯道速度调节比例(100%)",
- "cdescr": "值越高:弯道速度越慢"
+ "unit": 5
},
{
"group": "조향일반",
@@ -761,13 +1337,13 @@
"egroup": "LATSET",
"etitle": "ATC: AutoTurnControl",
"edescr": "(APN)0: not use, 1:laneChange, 2:laneChange+speed, 3:speed",
+ "cgroup": "转向设置",
+ "ctitle": "ATC: 自动转向控制",
+ "cdescr": "(APN) 0: 不使用, 1: 变道, 2: 变道+速度, 3: 速度",
"min": 0,
"max": 3,
"default": 0,
- "unit": 1,
- "cgroup": "转向设置",
- "ctitle": "ATC: 自动转向控制",
- "cdescr": "(APN) 0: 不使用, 1: 变道, 2: 变道+速度, 3: 速度"
+ "unit": 1
},
{
"group": "조향일반",
@@ -777,13 +1353,13 @@
"egroup": "LATSET",
"etitle": "ATC: Turn Speed(20)",
"edescr": "(APN)0: not use, Turn Speed",
+ "cgroup": "转向设置",
+ "ctitle": "ATC: 转向速度(20)",
+ "cdescr": "(APN) 0: 不使用, 转向速度",
"min": 0,
"max": 100,
"default": 20,
- "unit": 5,
- "cgroup": "转向设置",
- "ctitle": "ATC: 转向速度(20)",
- "cdescr": "(APN) 0: 不使用, 转向速度"
+ "unit": 5
},
{
"group": "조향일반",
@@ -793,13 +1369,13 @@
"egroup": "LATSET",
"etitle": "ATC: Speed Ctrl left Time(3)",
"edescr": "(APN) NOO Completion Time Distance (Speed × Time)",
+ "cgroup": "转向设置",
+ "ctitle": "ATC: 速度控制剩余时间(3)",
+ "cdescr": "(APN) NOO 完成时间距离 (速度 × 时间)",
"min": 0,
"max": 30,
"default": 6,
- "unit": 1,
- "cgroup": "转向设置",
- "ctitle": "ATC: 速度控制剩余时间(3)",
- "cdescr": "(APN) NOO 完成时间距离 (速度 × 时间)"
+ "unit": 1
},
{
"group": "조향일반",
@@ -809,13 +1385,13 @@
"egroup": "LATSET",
"etitle": "ATC Helper Map display(0)",
"edescr": "(APN) Turn On Map When ATC",
+ "cgroup": "转向设置",
+ "ctitle": "ATC 辅助地图显示(0)",
+ "cdescr": "(APN) ATC 激活时开启地图",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "转向设置",
- "ctitle": "ATC 辅助地图显示(0)",
- "cdescr": "(APN) ATC 激活时开启地图"
+ "unit": 1
},
{
"group": "버튼설정",
@@ -825,13 +1401,13 @@
"egroup": "BUTN",
"etitle": "Cruise Button Mode(0)",
"edescr": "0:General, 1:User1, 2:User2, 3:User3(Use Speed Tables)",
+ "cgroup": "按键设置",
+ "ctitle": "巡航按钮模式(0)",
+ "cdescr": "0: 常规, 1: 用户1, 2: 用户2, 3: 用户3 (使用速度表)",
"min": 0,
"max": 3,
"default": 0,
- "unit": 1,
- "cgroup": "按键设置",
- "ctitle": "巡航按钮模式(0)",
- "cdescr": "0: 常规, 1: 用户1, 2: 用户2, 3: 用户3 (使用速度表)"
+ "unit": 1
},
{
"group": "버튼설정",
@@ -841,13 +1417,13 @@
"egroup": "BUTN",
"etitle": "Cancel Button Mode(0)",
"edescr": "0:Long control, 1: Long + Lateral",
+ "cgroup": "按键设置",
+ "ctitle": "取消按钮模式(0)",
+ "cdescr": "0: 纵向控制, 1: 纵向 + 横向",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "按键设置",
- "ctitle": "取消按钮模式(0)",
- "cdescr": "0: 纵向控制, 1: 纵向 + 横向"
+ "unit": 1
},
{
"group": "버튼설정",
@@ -857,13 +1433,13 @@
"egroup": "BUTN",
"etitle": "LFA Button Mode(0)",
"edescr": "0:General, 1:Decel&Stop, leadCar ready, 2:CarrotCruise",
+ "cgroup": "按键设置",
+ "ctitle": "LFA 按钮模式(0)",
+ "cdescr": "0: 常规, 1: 减速并停止/前车就绪, 2: 胡萝卜巡航",
"min": 0,
"max": 2,
"default": 0,
- "unit": 1,
- "cgroup": "按键设置",
- "ctitle": "LFA 按钮模式(0)",
- "cdescr": "0: 常规, 1: 减速并停止/前车就绪, 2: 胡萝卜巡航"
+ "unit": 1
},
{
"group": "버튼설정",
@@ -873,13 +1449,13 @@
"egroup": "BUTN",
"etitle": "Cruise Button spam1(8)",
"edescr": "For Non-Long Vehicle Only, Speed Button Signal Send Restriction Time",
+ "cgroup": "按键设置",
+ "ctitle": "巡航按钮连发1(8)",
+ "cdescr": "仅限非纵向控制车辆,速度按钮信号发送限制时间",
"min": 1,
"max": 20,
"default": 0,
- "unit": 1,
- "cgroup": "按键设置",
- "ctitle": "巡航按钮连发1(8)",
- "cdescr": "仅限非纵向控制车辆,速度按钮信号发送限制时间"
+ "unit": 1
},
{
"group": "버튼설정",
@@ -889,13 +1465,13 @@
"egroup": "BUTN",
"etitle": "Cruise Button spam2(30)",
"edescr": "For Non-Long Vehicle Only — Speed Button Signal Send Pause Time",
+ "cgroup": "按键设置",
+ "ctitle": "巡航按钮连发2(30)",
+ "cdescr": "仅限非纵向控制车辆 — 速度按钮信号发送暂停时间",
"min": 1,
"max": 200,
"default": 0,
- "unit": 1,
- "cgroup": "按键设置",
- "ctitle": "巡航按钮连发2(30)",
- "cdescr": "仅限非纵向控制车辆 — 速度按钮信号发送暂停时间"
+ "unit": 1
},
{
"group": "버튼설정",
@@ -905,13 +1481,13 @@
"egroup": "BUTN",
"etitle": "Cruise Button spam3(1)",
"edescr": "For Non-Long Vehicle Only — Consecutive Speed Button Signal Count",
+ "cgroup": "按键设置",
+ "ctitle": "巡航按钮连发3(1)",
+ "cdescr": "仅限非纵向控制车辆 — 连续速度按钮信号计数",
"min": 1,
"max": 20,
"default": 0,
- "unit": 1,
- "cgroup": "按键设置",
- "ctitle": "巡航按钮连发3(1)",
- "cdescr": "仅限非纵向控制车辆 — 连续速度按钮信号计数"
+ "unit": 1
},
{
"group": "버튼설정",
@@ -921,13 +1497,13 @@
"egroup": "BUTN",
"etitle": "Cruise Speed Unit Extra(10)",
"edescr": "SET/DECEL up/down speed unit(mode1,2,3, GasTok)",
+ "cgroup": "按键设置",
+ "ctitle": "巡航速度单位扩展(10)",
+ "cdescr": "SET/DECEL 加减速单位 (模式 1,2,3, GasTok)",
"min": 1,
"max": 100,
"default": 10,
- "unit": 1,
- "cgroup": "按键设置",
- "ctitle": "巡航速度单位扩展(10)",
- "cdescr": "SET/DECEL 加减速单位 (模式 1,2,3, GasTok)"
+ "unit": 1
},
{
"group": "버튼설정",
@@ -937,13 +1513,13 @@
"egroup": "Button Settings",
"etitle": "Cruise Button Long Delay (40)",
"edescr": "Delay before the long-press action is triggered.",
+ "cgroup": "按键设置",
+ "ctitle": "巡航按键长按延迟(40)",
+ "cdescr": "长按按钮后,功能触发前的延迟时间。",
"min": 30,
"max": 100,
"default": 40,
- "unit": 10,
- "cgroup": "按键设置",
- "ctitle": "巡航按键长按延迟(40)",
- "cdescr": "长按按钮后,功能触发前的延迟时间。"
+ "unit": 10
},
{
"group": "버튼설정",
@@ -953,13 +1529,13 @@
"egroup": "BUTN",
"etitle": "Cruise Speed Unit Baic(10)",
"edescr": "SET/DECEL up/down speed unit(Basic unit)",
+ "cgroup": "按键设置",
+ "ctitle": "巡航速度单位基础(10)",
+ "cdescr": "SET/DECEL 加减速单位 (基础单位)",
"min": 1,
"max": 100,
"default": 10,
- "unit": 1,
- "cgroup": "按键设置",
- "ctitle": "巡航速度单位基础(10)",
- "cdescr": "SET/DECEL 加减速单位 (基础单位)"
+ "unit": 1
},
{
"group": "버튼설정",
@@ -969,13 +1545,13 @@
"egroup": "BUTN",
"etitle": "Cruise Speed1(30)",
"edescr": "Button Mode User 3, Stepwise Speed, 0: Road Speed Limit + Auto Speed Increase Offset",
+ "cgroup": "按键设置",
+ "ctitle": "巡航速度1(30)",
+ "cdescr": "按钮模式用户 3, 分段速度, 0: 道路限速 + 自动加速偏移",
"min": 0,
"max": 160,
"default": 10,
- "unit": 10,
- "cgroup": "按键设置",
- "ctitle": "巡航速度1(30)",
- "cdescr": "按钮模式用户 3, 分段速度, 0: 道路限速 + 自动加速偏移"
+ "unit": 10
},
{
"group": "버튼설정",
@@ -985,13 +1561,13 @@
"egroup": "BUTN",
"etitle": "Cruise Speed2(50)",
"edescr": "Button Mode User 3, Second Speed",
+ "cgroup": "按键设置",
+ "ctitle": "巡航速度2(50)",
+ "cdescr": "按钮模式用户 3, 第二段速度",
"min": 1,
"max": 160,
"default": 10,
- "unit": 10,
- "cgroup": "按键设置",
- "ctitle": "巡航速度2(50)",
- "cdescr": "按钮模式用户 3, 第二段速度"
+ "unit": 10
},
{
"group": "버튼설정",
@@ -1001,13 +1577,13 @@
"egroup": "BUTN",
"etitle": "Cruise Speed3(80)",
"edescr": "Button Mode User 3, Third Speed",
+ "cgroup": "按键设置",
+ "ctitle": "巡航速度3(80)",
+ "cdescr": "按钮模式用户 3, 第三段速度",
"min": 1,
"max": 160,
"default": 10,
- "unit": 10,
- "cgroup": "按键设置",
- "ctitle": "巡航速度3(80)",
- "cdescr": "按钮模式用户 3, 第三段速度"
+ "unit": 10
},
{
"group": "버튼설정",
@@ -1017,13 +1593,13 @@
"egroup": "BUTN",
"etitle": "Cruise Speed4(110)",
"edescr": "Button Mode User 3, Fourth Speed",
+ "cgroup": "按键设置",
+ "ctitle": "巡航速度4(110)",
+ "cdescr": "按钮模式用户 3, 第四段速度",
"min": 1,
"max": 160,
"default": 10,
- "unit": 10,
- "cgroup": "按键设置",
- "ctitle": "巡航速度4(110)",
- "cdescr": "按钮模式用户 3, 第四段速度"
+ "unit": 10
},
{
"group": "버튼설정",
@@ -1033,13 +1609,13 @@
"egroup": "BUTN",
"etitle": "Cruise Speed5(130)",
"edescr": "Button Mode User 3, Fifth Speed",
+ "cgroup": "按键设置",
+ "ctitle": "巡航速度5(130)",
+ "cdescr": "按钮模式用户 3, 第五段速度",
"min": 1,
"max": 160,
"default": 10,
- "unit": 10,
- "cgroup": "按键设置",
- "ctitle": "巡航速度5(130)",
- "cdescr": "按钮模式用户 3, 第五段速度"
+ "unit": 10
},
{
"group": "버튼설정",
@@ -1049,13 +1625,13 @@
"egroup": "BUTN",
"etitle": "PaddleShift Mode(0)",
"edescr": "After Regen paddle, 0:Cruise ON, 1:Cruise Ready, 2: decel & cruise ready, 3: CarrotCruise",
+ "cgroup": "按键设置",
+ "ctitle": "换挡拨片模式(0)",
+ "cdescr": "动能回收拨片后, 0: 巡航开启, 1: 巡航就绪, 2: 减速并巡航就绪, 3: 胡萝卜巡航",
"min": 0,
"max": 3,
"default": 1,
- "unit": 1,
- "cgroup": "按键设置",
- "ctitle": "换挡拨片模式(0)",
- "cdescr": "动能回收拨片后, 0: 巡航开启, 1: 巡航就绪, 2: 减速并巡航就绪, 3: 胡萝卜巡航"
+ "unit": 1
},
{
"group": "오토크루즈",
@@ -1065,13 +1641,13 @@
"egroup": "AUTOCRUISE",
"etitle": "Auto Cruise control(HKG only)",
"edescr": "1:Softhold + Auto Cruise, 2:if softhold error",
+ "cgroup": "自动巡航",
+ "ctitle": "自动巡航控制 (仅限现代/起亚)",
+ "cdescr": "1: 软驻车 + 自动巡航, 2: 如果软驻车报错",
"min": 0,
"max": 3,
"default": 0,
- "unit": 1,
- "cgroup": "自动巡航",
- "ctitle": "自动巡航控制 (仅限现代/起亚)",
- "cdescr": "1: 软驻车 + 自动巡航, 2: 如果软驻车报错"
+ "unit": 1
},
{
"group": "오토크루즈",
@@ -1081,13 +1657,13 @@
"egroup": "AUTOCRUISE",
"etitle": "Auto Cruise: Accelerator Tap Start Speed",
"edescr": "Operates only above the set speed — GasTab : Tap the accelerator pedal for 0.6 seconds",
+ "cgroup": "自动巡航",
+ "ctitle": "自动巡航: 踩油门起步速度",
+ "cdescr": "仅在设定速度以上运行 — GasTab: 踩油门 0.6 秒",
"min": 0,
"max": 200,
"default": 0,
- "unit": 5,
- "cgroup": "自动巡航",
- "ctitle": "自动巡航: 踩油门起步速度",
- "cdescr": "仅在设定速度以上运行 — GasTab: 踩油门 0.6 秒"
+ "unit": 5
},
{
"group": "오토크루즈",
@@ -1097,13 +1673,13 @@
"egroup": "AUTOCRUISE",
"etitle": "Auto Cruise: Gas Release Cancel Speed",
"edescr": "When releasing the accelerator pedal, cruise is canceled below this speed.",
+ "cgroup": "自动巡航",
+ "ctitle": "自动巡航: 松开油门取消速度",
+ "cdescr": "松开油门踏板时,当前速度低于设定值则取消巡航。",
"min": 0,
"max": 200,
"default": 30,
- "unit": 5,
- "cgroup": "自动巡航",
- "ctitle": "自动巡航: 松开油门取消速度",
- "cdescr": "松开油门踏板时,当前速度低于设定值则取消巡航。"
+ "unit": 5
},
{
"group": "오토크루즈",
@@ -1113,13 +1689,13 @@
"egroup": "AUTOCRUISE",
"etitle": "Auto Engage on onroad",
"edescr": "1: Steering Only, 2: Steering ON + Cruise Standby",
+ "cgroup": "自动巡航",
+ "ctitle": "上路自动激活",
+ "cdescr": "1: 仅转向, 2: 转向开启 + 巡航待机",
"min": 0,
"max": 2,
"default": 0,
- "unit": 1,
- "cgroup": "自动巡航",
- "ctitle": "上路自动激活",
- "cdescr": "1: 仅转向, 2: 转向开启 + 巡航待机"
+ "unit": 1
},
{
"group": "시작",
@@ -1129,13 +1705,13 @@
"egroup": "START",
"etitle": "Always Lateral",
"edescr": "Allow lateral control even when cruise is not active.\n0: OFF, 1: ON",
+ "cgroup": "启动设置",
+ "ctitle": "全时横向控制",
+ "cdescr": "即使巡航未激活,也允许横向控制。\n0: 关闭, 1: 开启",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "全时横向控制",
- "cdescr": "即使巡航未激活,也允许横向控制。\n0: 关闭, 1: 开启"
+ "unit": 1
},
{
"group": "시작",
@@ -1145,13 +1721,13 @@
"egroup": "START",
"etitle": "Record RoadCam",
"edescr": "1: Standard Camera, 2: Standard Camera + Wide Camera",
+ "cgroup": "启动设置",
+ "ctitle": "记录路面摄像头",
+ "cdescr": "1: 标准摄像头, 2: 标准摄像头 + 广角摄像头",
"min": 0,
"max": 2,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "记录路面摄像头",
- "cdescr": "1: 标准摄像头, 2: 标准摄像头 + 广角摄像头"
+ "unit": 1
},
{
"group": "시작",
@@ -1161,13 +1737,13 @@
"egroup": "START",
"etitle": "Use HDP(CCNC)",
"edescr": "1:While using APN, 2:Always",
+ "cgroup": "启动设置",
+ "ctitle": "使用 HDP (CCNC)",
+ "cdescr": "1: 使用 APN 时, 2: 始终",
"min": 0,
"max": 2,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "使用 HDP (CCNC)",
- "cdescr": "1: 使用 APN 时, 2: 始终"
+ "unit": 1
},
{
"group": "시작",
@@ -1177,13 +1753,13 @@
"egroup": "START",
"etitle": "MapboxStyle",
"edescr": "0: Default Background, 1: Dark Background, 2: Satellite Map",
+ "cgroup": "启动设置",
+ "ctitle": "Mapbox 样式",
+ "cdescr": "0: 默认背景, 1: 深色背景, 2: 卫星地图",
"min": 0,
"max": 2,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "Mapbox 样式",
- "cdescr": "0: 默认背景, 1: 深色背景, 2: 卫星地图"
+ "unit": 1
},
{
"group": "시작",
@@ -1193,13 +1769,13 @@
"egroup": "START",
"etitle": "DisableMinSteerSpeed",
"edescr": "smdps equiped: 1",
+ "cgroup": "启动设置",
+ "ctitle": "解除最小转向速度限制",
+ "cdescr": "配备 smdps: 1",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "解除最小转向速度限制",
- "cdescr": "配备 smdps: 1"
+ "unit": 1
},
{
"group": "시작",
@@ -1209,13 +1785,13 @@
"egroup": "START",
"etitle": "Speed from PCM(StockSCC)",
"edescr": "0: Curve/Camera Deceleration + Long, 1: No Button Spamming (Stock SCC), 2: Curve/Camera Decel, 3: Honda/Toyota",
+ "cgroup": "启动设置",
+ "ctitle": "来自 PCM 的速度 (原厂 SCC)",
+ "cdescr": "0: 弯道/摄像头减速 + 纵向控制, 1: 无按钮连发 (原厂 SCC), 2: 弯道/摄像头减速, 3: 本田/丰田",
"min": 0,
"max": 3,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "来自 PCM 的速度 (原厂 SCC)",
- "cdescr": "0: 弯道/摄像头减速 + 纵向控制, 1: 无按钮连发 (原厂 SCC), 2: 弯道/摄像头减速, 3: 本田/丰田"
+ "unit": 1
},
{
"group": "시작",
@@ -1225,13 +1801,13 @@
"egroup": "START",
"etitle": "PowerOffTime(min)",
"edescr": "When the engine is turned off and the specified time elapses, the comma device will shut down.",
+ "cgroup": "启动设置",
+ "ctitle": "关机时间 (分钟)",
+ "cdescr": "发动机熄火且经过指定时间后,comma 设备将关机。",
"min": 0,
"max": 3000,
"default": 60,
- "unit": 10,
- "cgroup": "启动设置",
- "ctitle": "关机时间 (分钟)",
- "cdescr": "发动机熄火且经过指定时间后,comma 设备将关机。"
+ "unit": 10
},
{
"group": "시작",
@@ -1241,13 +1817,13 @@
"egroup": "START",
"etitle": "DisableDM",
"edescr": "1.DisableDM, 2: +EnableWebRTC, Reboot required",
+ "cgroup": "启动设置",
+ "ctitle": "禁用驾驶员监控",
+ "cdescr": "1. 禁用 DM, 2: + 开启 WebRTC, 需要重启",
"min": 0,
"max": 2,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "禁用驾驶员监控",
- "cdescr": "1. 禁用 DM, 2: + 开启 WebRTC, 需要重启"
+ "unit": 1
},
{
"group": "시작",
@@ -1257,13 +1833,13 @@
"egroup": "START",
"etitle": "MuteDoor",
"edescr": "",
+ "cgroup": "启动设置",
+ "ctitle": "屏蔽车门感应",
+ "cdescr": "",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "屏蔽车门感应",
- "cdescr": ""
+ "unit": 1
},
{
"group": "시작",
@@ -1273,13 +1849,13 @@
"egroup": "START",
"etitle": "MuteSeatbelt",
"edescr": "",
+ "cgroup": "启动设置",
+ "ctitle": "屏蔽安全带感应",
+ "cdescr": "",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "屏蔽安全带感应",
- "cdescr": ""
+ "unit": 1
},
{
"group": "크루즈",
@@ -1289,13 +1865,13 @@
"egroup": "CRUISE",
"etitle": "AutoSpeedUpx:(100)%",
"edescr": "Automatically increases speed on lead car, up to (road speed x ratio)",
+ "cgroup": "巡航设置",
+ "ctitle": "自动加速至: (100)%",
+ "cdescr": "当前方有车时自动加速,最高至 (道路限速 x 比例)",
"min": 0,
"max": 200,
"default": 0,
- "unit": 10,
- "cgroup": "巡航设置",
- "ctitle": "自动加速至: (100)%",
- "cdescr": "当前方有车时自动加速,最高至 (道路限速 x 比例)"
+ "unit": 10
},
{
"group": "감속제어",
@@ -1305,13 +1881,13 @@
"egroup": "CRUISE",
"etitle": "AutoRoadLimitSpeedAdjust (50)%",
"edescr": "-1: set roadlimitspeed, 100: new road speed, 50: median, 0: not change",
+ "cgroup": "巡航设置",
+ "ctitle": "自动道路限速调整 (50)%",
+ "cdescr": "-1: 设置道路限速, 100: 新道路速度, 50: 中值, 0: 不改变",
"min": -1,
"max": 100,
"default": 0,
- "unit": 10,
- "cgroup": "巡航设置",
- "ctitle": "自动道路限速调整 (50)%",
- "cdescr": "-1: 设置道路限速, 100: 新道路速度, 50: 中值, 0: 不改变"
+ "unit": 10
},
{
"group": "크루즈",
@@ -1321,13 +1897,13 @@
"egroup": "CRUISE",
"etitle": "Auto update Cruise speed",
"edescr": "If accelerator is pressed and speed exceeds set speed, update set speed",
+ "cgroup": "巡航设置",
+ "ctitle": "自动更新巡航速度",
+ "cdescr": "如果踩下油门且速度超过设定速度,则更新设定速度",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "巡航设置",
- "ctitle": "自动更新巡航速度",
- "cdescr": "如果踩下油门且速度超过设定速度,则更新设定速度"
+ "unit": 1
},
{
"group": "크루즈",
@@ -1337,13 +1913,13 @@
"egroup": "CRUISE",
"etitle": "Model Speed Apply Ratio",
"edescr": "Applies the model-calculated driving speed by the set ratio.",
+ "cgroup": "巡航设置",
+ "ctitle": "模型车速应用比例",
+ "cdescr": "按设定比例应用模型计算的行驶速度。",
"min": -120,
"max": 120,
"default": 0,
- "unit": 1,
- "cgroup": "巡航设置",
- "ctitle": "模型车速应用比例",
- "cdescr": "按设定比例应用模型计算的行驶速度。"
+ "unit": 1
},
{
"group": "화면",
@@ -1353,13 +1929,13 @@
"egroup": "DISP",
"etitle": "Show Debug Info",
"edescr": "",
+ "cgroup": "显示设置",
+ "ctitle": "显示调试信息",
+ "cdescr": "",
"min": 0,
"max": 2,
"default": 1,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示调试信息",
- "cdescr": ""
+ "unit": 1
},
{
"group": "화면",
@@ -1369,13 +1945,13 @@
"egroup": "DISP",
"etitle": "Show TPMS Info",
"edescr": "0:None, 1: Upper, 2:Lower, 3: Both",
+ "cgroup": "显示设置",
+ "ctitle": "显示胎压 (TPMS) 信息",
+ "cdescr": "0: 无, 1: 上方, 2: 下方, 3: 两侧",
"min": 0,
"max": 3,
"default": 1,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示胎压 (TPMS) 信息",
- "cdescr": "0: 无, 1: 上方, 2: 下方, 3: 两侧"
+ "unit": 1
},
{
"group": "화면",
@@ -1385,13 +1961,13 @@
"egroup": "DISP",
"etitle": "Show Time Info",
"edescr": "0:None, 1:Time/Date, 2:Time, 3:Date",
+ "cgroup": "显示设置",
+ "ctitle": "显示时间信息",
+ "cdescr": "0: 无, 1: 时间/日期, 2: 时间, 3: 日期",
"min": 0,
"max": 3,
"default": 1,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示时间信息",
- "cdescr": "0: 无, 1: 时间/日期, 2: 时间, 3: 日期"
+ "unit": 1
},
{
"group": "화면",
@@ -1401,13 +1977,13 @@
"egroup": "DISP",
"etitle": "Show Path End",
"edescr": "",
+ "cgroup": "显示设置",
+ "ctitle": "显示路径终点",
+ "cdescr": "",
"min": 0,
"max": 1,
"default": 1,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示路径终点",
- "cdescr": ""
+ "unit": 1
},
{
"group": "화면",
@@ -1417,29 +1993,13 @@
"egroup": "DISP",
"etitle": "Show Device Info",
"edescr": "",
- "min": 0,
- "max": 1,
- "default": 1,
- "unit": 1,
"cgroup": "显示设置",
"ctitle": "显示设备信息",
- "cdescr": ""
- },
- {
- "group": "화면",
- "name": "ShowCustomBrightness",
- "title": "화면밝기비율",
- "descr": "화면 밝기를 조절합니다.\n터치나 이벤트 발생 시 일시적으로 밝아집니다.",
- "egroup": "DISP",
- "etitle": "ScreenBrightness ratio",
- "edescr": "Adjusts screen brightness. Temporarily brightens on touch or event.",
+ "cdescr": "",
"min": 0,
- "max": 100,
- "default": 100,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "屏幕亮度比例",
- "cdescr": "调整屏幕亮度。触摸或发生事件时临时变亮。"
+ "max": 1,
+ "default": 1,
+ "unit": 1
},
{
"group": "화면",
@@ -1449,13 +2009,13 @@
"egroup": "DISP",
"etitle": "Show Lane Info",
"edescr": "-1:None, 0:Path, 1:Path+Lane, 2:Path+Lane+RoadEdge",
+ "cgroup": "显示设置",
+ "ctitle": "显示车道信息",
+ "cdescr": "-1: 无, 0: 路径, 1: 路径+车道, 2: 路径+车道+路缘",
"min": -1,
"max": 2,
"default": 1,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示车道信息",
- "cdescr": "-1: 无, 0: 路径, 1: 路径+车道, 2: 路径+车道+路缘"
+ "unit": 1
},
{
"group": "화면",
@@ -1465,13 +2025,13 @@
"egroup": "DISP",
"etitle": "Show Radar Info",
"edescr": "0:None,1:display,2:+relative pos, 3:stopped obstacle",
+ "cgroup": "显示设置",
+ "ctitle": "显示雷达信息",
+ "cdescr": "0: 无, 1: 显示, 2: + 相对位置, 3: 停止的障碍物",
"min": 0,
"max": 3,
"default": 0,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示雷达信息",
- "cdescr": "0: 无, 1: 显示, 2: + 相对位置, 3: 停止的障碍物"
+ "unit": 1
},
{
"group": "화면",
@@ -1481,13 +2041,13 @@
"egroup": "DISP",
"etitle": "Show Route Info",
"edescr": "Operates only when connected to APN. 0: Off, 1: On",
+ "cgroup": "显示设置",
+ "ctitle": "显示路线信息",
+ "cdescr": "仅在连接 APN 时运行。0: 关闭, 1: 开启",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示路线信息",
- "cdescr": "仅在连接 APN 时运行。0: 关闭, 1: 开启"
+ "unit": 1
},
{
"group": "화면패스",
@@ -1497,13 +2057,13 @@
"egroup": "DISP",
"etitle": "Tire Trajectory",
"edescr": "Shows the tire trajectory gradient on the screen.\n 0: Off, 1: On",
+ "cgroup": "显示设置",
+ "ctitle": "显示轮胎轨迹",
+ "cdescr": "显示轮胎轨迹。0: 关闭, 1: 开启",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示轮胎轨迹",
- "cdescr": "显示轮胎轨迹。0: 关闭, 1: 开启"
+ "unit": 1
},
{
"group": "화면패스",
@@ -1513,13 +2073,13 @@
"egroup": "DISP",
"etitle": "Show Path Mode:LaneLess(9)",
"edescr": "0:stock,1,2:REC,3,4:^^,5,6:REC,7,8:^^,9,10,11:smooth^^,12:smooth2^^,13:3lines,14:2lines,15:1lines",
+ "cgroup": "显示设置",
+ "ctitle": "显示路径模式: 无车道 (9)",
+ "cdescr": "0: 原厂, 1,2: 矩形, 3,4: ^^, 5,6: 矩形, 7,8: ^^, 9,10,11: 平滑^^, 12: 平滑2^^, 13: 3线, 14: 2线, 15: 1线",
"min": 0,
"max": 15,
"default": 9,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示路径模式: 无车道 (9)",
- "cdescr": "0: 原厂, 1,2: 矩形, 3,4: ^^, 5,6: 矩形, 7,8: ^^, 9,10,11: 平滑^^, 12: 平滑2^^, 13: 3线, 14: 2线, 15: 1线"
+ "unit": 1
},
{
"group": "화면패스",
@@ -1529,13 +2089,13 @@
"egroup": "DISP",
"etitle": "Show Path Color:LaneLess(12)",
"edescr": "(+10:stroke)0(R),1(O),2(Y),3(B),5(N),6(V),7(K),8(W),9(B),20:Auto",
+ "cgroup": "显示设置",
+ "ctitle": "显示路径颜色: 无车道 (12)",
+ "cdescr": "(+10: 描边) 0(红), 1(橙), 2(黄), 3(蓝), 5(深蓝), 6(紫), 7(黑), 8(白), 9(蓝), 20: 自动",
"min": 0,
"max": 20,
"default": 12,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示路径颜色: 无车道 (12)",
- "cdescr": "(+10: 描边) 0(红), 1(橙), 2(黄), 3(蓝), 5(深蓝), 6(紫), 7(黑), 8(白), 9(蓝), 20: 自动"
+ "unit": 1
},
{
"group": "화면패스",
@@ -1545,13 +2105,13 @@
"egroup": "DISP",
"etitle": "Show Path Color:CruiseOFF(1)",
"edescr": "(+10:stroke)0(R),1(O),2(Y),3(B),5(N),6(V),7(K),8(W),9(B)",
+ "cgroup": "显示设置",
+ "ctitle": "显示路径颜色: 巡航关闭 (1)",
+ "cdescr": "(+10:stroke)0(R),1(O),2(Y),3(B),5(N),6(V),7(K),8(W),9(B)",
"min": 0,
"max": 19,
"default": 1,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示路径颜色: 巡航关闭 (1)",
- "cdescr": "(+10:stroke)0(R),1(O),2(Y),3(B),5(N),6(V),7(K),8(W),9(B)"
+ "unit": 1
},
{
"group": "화면패스",
@@ -1561,13 +2121,13 @@
"egroup": "DISP",
"etitle": "Show Path Mode:LaneMode(11)",
"edescr": "0:stock,1,2:REC,3,4:^^,5,6:REC,7,8:^^,9,10,11:smooth^^,12:smooth2^^,13:3lines,14:2lines,15:1lines",
+ "cgroup": "显示设置",
+ "ctitle": "显示路径模式: 车道模式 (11)",
+ "cdescr": "0: 原厂, 1,2: 矩形, 3,4: ^^, 5,6: 矩形, 7,8: ^^, 9,10,11: 平滑^^, 12: 平滑2^^, 13: 3线, 14: 2线, 15: 1线",
"min": 0,
"max": 15,
"default": 11,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示路径模式: 车道模式 (11)",
- "cdescr": "0: 原厂, 1,2: 矩形, 3,4: ^^, 5,6: 矩形, 7,8: ^^, 9,10,11: 平滑^^, 12: 平滑2^^, 13: 3线, 14: 2线, 15: 1线"
+ "unit": 1
},
{
"group": "화면패스",
@@ -1577,13 +2137,13 @@
"egroup": "DISP",
"etitle": "Show Path Color:LaneMode(3)",
"edescr": "(+10:stroke)0(R),1(O),2(Y),3(B),5(N),6(V),7(K),8(W),9(B),20:Auto",
+ "cgroup": "显示设置",
+ "ctitle": "显示路径颜色: 车道模式 (3)",
+ "cdescr": "(+10: 描边) 0(红), 1(橙), 2(黄), 3(蓝), 5(深蓝), 6(紫), 7(黑), 8(白), 9(蓝), 20: 自动",
"min": 0,
"max": 20,
"default": 3,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示路径颜色: 车道模式 (3)",
- "cdescr": "(+10: 描边) 0(红), 1(橙), 2(黄), 3(蓝), 5(深蓝), 6(紫), 7(黑), 8(白), 9(蓝), 20: 自动"
+ "unit": 1
},
{
"group": "화면",
@@ -1593,13 +2153,13 @@
"egroup": "DISP",
"etitle": "Show Debug Plot(0)",
"edescr": "0:Off, 1:Accel, 2:Speed+Accel, 3:Model, 4:Lead, 5:Lead2, 6:Steer, 7:SteerA, 8:Curvature",
+ "cgroup": "显示设置",
+ "ctitle": "显示调试图表 (0)",
+ "cdescr": "0:关, 1:加速度, 2:速度+加速度, 3:模型, 4:前车, 5:前车2, 6:转向, 7:转角, 8:曲率",
"min": 0,
"max": 8,
"default": 0,
- "unit": 1,
- "cgroup": "显示设置",
- "ctitle": "显示调试图表 (0)",
- "cdescr": "0:关, 1:加速度, 2:速度+加速度, 3:模型, 4:前车, 5:前车2, 6:转向, 7:转角, 8:曲率"
+ "unit": 1
},
{
"group": "레인모드",
@@ -1609,13 +2169,13 @@
"egroup": "LANE",
"etitle": "Laneline: Speed(0)",
"edescr": "Switches to LaneMode when speed exceeds the set speed",
+ "cgroup": "转向",
+ "ctitle": "车道线: 速度 (0)",
+ "cdescr": "当速度超过设定速度时切换到车道模式",
"min": 0,
"max": 200,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "车道线: 速度 (0)",
- "cdescr": "当速度超过设定速度时切换到车道模式"
+ "unit": 1
},
{
"group": "레인모드",
@@ -1625,13 +2185,13 @@
"egroup": "LANE",
"etitle": "Laneline: Curve Speed(0)",
"edescr": "LaneMode is not used below the set speed",
+ "cgroup": "转向",
+ "ctitle": "车道线: 弯道速度 (0)",
+ "cdescr": "低于设定速度时不使用车道模式",
"min": 0,
"max": 200,
"default": 0,
- "unit": 10,
- "cgroup": "转向",
- "ctitle": "车道线: 弯道速度 (0)",
- "cdescr": "低于设定速度时不使用车道模式"
+ "unit": 10
},
{
"group": "레인모드",
@@ -1641,13 +2201,13 @@
"egroup": "LANE",
"etitle": "LaneLine: AdjustLaneOffset (0)cm",
"edescr": "Corrects toward the road edge/inside of the curve",
+ "cgroup": "转向",
+ "ctitle": "车道线: 车道偏移调整 (0)cm",
+ "cdescr": "向路缘/弯道内侧修正",
"min": 0,
"max": 500,
"default": 0,
- "unit": 10,
- "cgroup": "转向",
- "ctitle": "车道线: 车道偏移调整 (0)cm",
- "cdescr": "向路缘/弯道内侧修正"
+ "unit": 10
},
{
"group": "조향일반",
@@ -1657,13 +2217,13 @@
"egroup": "LAT",
"etitle": "LaneChange use steering torque",
"edescr": "0:immediate, 1: need torque(nudge), -1: auto lane change off",
+ "cgroup": "转向",
+ "ctitle": "变道使用转向力矩",
+ "cdescr": "0: 立即变道, 1: 需要力矩 (轻拨), -1: 自动变道关闭",
"min": -1,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "变道使用转向力矩",
- "cdescr": "0: 立即变道, 1: 需要力矩 (轻拨), -1: 自动变道关闭"
+ "unit": 1
},
{
"group": "조향일반",
@@ -1673,13 +2233,13 @@
"egroup": "LAT",
"etitle": "LaneChange delayx0.1s(0)",
"edescr": "Changes lanes after the set time once the turn signal is activated",
+ "cgroup": "转向",
+ "ctitle": "变道延迟 x0.1s(0)",
+ "cdescr": "开启转向灯后在设定时间后变道",
"min": 0,
"max": 100,
"default": 0,
- "unit": 10,
- "cgroup": "转向",
- "ctitle": "变道延迟 x0.1s(0)",
- "cdescr": "开启转向灯后在设定时间后变道"
+ "unit": 10
},
{
"group": "조향일반",
@@ -1689,13 +2249,13 @@
"egroup": "LAT",
"etitle": "LaneChange BSD",
"edescr": "0:BSD detect(allow steer torque), 1: block steer torque, -1: ignore BSD",
+ "cgroup": "转向",
+ "ctitle": "变道盲点监测 (BSD)",
+ "cdescr": "0: BSD 检测 (允许转向力矩), 1: 阻止转向力矩, -1: 忽略 BSD",
"min": -1,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "变道盲点监测 (BSD)",
- "cdescr": "0: BSD 检测 (允许转向力矩), 1: 阻止转向力矩, -1: 忽略 BSD"
+ "unit": 1
},
{
"group": "조향일반",
@@ -1705,13 +2265,13 @@
"egroup": "LAT",
"etitle": "LaneChange LineCheck",
"edescr": "0: Color+Type(block yellow), 1: Type only, 2: Type+torque override solid",
+ "cgroup": "转向",
+ "ctitle": "变道车道判断",
+ "cdescr": "0: 颜色+类型(黄线阻止), 1: 仅类型(虚线/实线), 2: 仅类型+实线扭矩override",
"min": 0,
"max": 2,
"default": 0,
- "unit": 1,
- "cgroup": "转向",
- "ctitle": "变道车道判断",
- "cdescr": "0: 颜色+类型(黄线阻止), 1: 仅类型(虚线/实线), 2: 仅类型+实线扭矩override"
+ "unit": 1
},
{
"group": "시작",
@@ -1721,13 +2281,13 @@
"egroup": "START",
"etitle": "HapticFeedbackSpeedCamera(0)",
"edescr": "0: Disabled, 1: Vibration, 2: Instrument Cluster, 3: HUD Display",
+ "cgroup": "启动设置",
+ "ctitle": "超速照相触感反馈 (0)",
+ "cdescr": "0: 禁用, 1: 振动, 2: 仪表盘, 3: HUD 显示",
"min": 0,
"max": 3,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "超速照相触感反馈 (0)",
- "cdescr": "0: 禁用, 1: 振动, 2: 仪表盘, 3: HUD 显示"
+ "unit": 1
},
{
"group": "시작",
@@ -1737,13 +2297,13 @@
"egroup": "START",
"etitle": "MaxAngleFrames(89)",
"edescr": "89 Recommeded",
+ "cgroup": "启动设置",
+ "ctitle": "最大角度帧数 (89)",
+ "cdescr": "推荐 89",
"min": 80,
"max": 100,
"default": 89,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "最大角度帧数 (89)",
- "cdescr": "推荐 89"
+ "unit": 1
},
{
"group": "시작",
@@ -1753,13 +2313,13 @@
"egroup": "START",
"etitle": "HYUNDAI: CAMERA SCC(0)",
"edescr": "1: Long-con Vehicle, 2: Cruise State Sync (CAN-FD Vehicle), 3: Stock Cruise (CANFD Long harness)",
+ "cgroup": "启动设置",
+ "ctitle": "现代: 摄像头 SCC (0)",
+ "cdescr": "1: 纵向控制车辆, 2: 巡航状态同步 (CAN-FD 车辆), 3: 原厂巡航 (CANFD 纵向线束)",
"min": 0,
"max": 3,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "现代: 摄像头 SCC (0)",
- "cdescr": "1: 纵向控制车辆, 2: 巡航状态同步 (CAN-FD 车辆), 3: 原厂巡航 (CANFD 纵向线束)"
+ "unit": 1
},
{
"group": "시작",
@@ -1769,13 +2329,13 @@
"egroup": "START",
"etitle": "HYUNDAI: LDWS ONLY CAR(0)",
"edescr": "LDWS ONLY CAR",
+ "cgroup": "启动设置",
+ "ctitle": "现代: 仅配备 LDWS 的车辆 (0)",
+ "cdescr": "仅配备 LDWS 的车辆",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "现代: 仅配备 LDWS 的车辆 (0)",
- "cdescr": "仅配备 LDWS 的车辆"
+ "unit": 1
},
{
"group": "시작",
@@ -1785,13 +2345,13 @@
"egroup": "START",
"etitle": "CANFD HDA2(0)",
"edescr": "0:HDA1, 1: HDA2",
+ "cgroup": "启动设置",
+ "ctitle": "CANFD HDA2 (0)",
+ "cdescr": "0: HDA1, 1: HDA2",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "CANFD HDA2 (0)",
- "cdescr": "0: HDA1, 1: HDA2"
+ "unit": 1
},
{
"group": "시작",
@@ -1801,13 +2361,13 @@
"egroup": "START",
"etitle": "CANFD Debug(0)",
"edescr": "",
+ "cgroup": "启动设置",
+ "ctitle": "CANFD 调试 (0)",
+ "cdescr": "",
"min": -1,
"max": 128,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "CANFD 调试 (0)",
- "cdescr": ""
+ "unit": 1
},
{
"group": "레이더설정",
@@ -1817,13 +2377,13 @@
"egroup": "RADAR",
"etitle": "Enable radar tracks(0)",
"edescr": "-2: VOACC vision-only test\n-1: Always use SCC\n0: Use SCC radar\n1: Use radar tracks\n2: Radar tracks + low-speed SCC\n3: Radar tracks + low-speed SCC + cut-in vehicles + stealth vehicles",
+ "cgroup": "雷达设置",
+ "ctitle": "开启雷达轨迹 (0)",
+ "cdescr": "-1: 始终使用 SCC\n0: 使用 SCC 雷达\n1: 使用雷达轨迹\n2: 雷达轨迹 + 低速 SCC\n3: 雷达轨迹 + 低速 SCC + 切入车辆 + 隐形车辆",
"min": -2,
"max": 3,
"default": 0,
- "unit": 1,
- "cgroup": "雷达设置",
- "ctitle": "开启雷达轨迹 (0)",
- "cdescr": "-1: 始终使用 SCC\n0: 使用 SCC 雷达\n1: 使用雷达轨迹\n2: 雷达轨迹 + 低速 SCC\n3: 雷达轨迹 + 低速 SCC + 切入车辆 + 隐形车辆"
+ "unit": 1
},
{
"group": "레이더설정",
@@ -1833,13 +2393,13 @@
"egroup": "RADAR",
"etitle": "Cut-in detection sensitivity(0)",
"edescr": "Higher values catch lane-entering vehicles earlier, but too high may mistake adjacent-lane vehicles for leads.",
+ "cgroup": "雷达设置",
+ "ctitle": "切入检测灵敏度 (0)",
+ "cdescr": "值越高越早发现从旁边车道驶入的车辆,但太高可能把旁边车道车辆当作前车",
"min": 0,
"max": 1000,
"default": 0,
- "unit": 10,
- "cgroup": "雷达设置",
- "ctitle": "切入检测灵敏度 (0)",
- "cdescr": "值越高越早发现从旁边车道驶入的车辆,但太高可能把旁边车道车辆当作前车"
+ "unit": 10
},
{
"group": "레이더설정",
@@ -1849,13 +2409,13 @@
"egroup": "RADAR",
"etitle": "Enable Corner radar(0)",
"edescr": "1:Enable Corner radar, 2: Cutin Detection for CCNC car",
+ "cgroup": "雷达设置",
+ "ctitle": "开启角雷达 (0)",
+ "cdescr": "1: 开启角雷达, 2: CCNC 车辆的切入检测",
"min": 0,
"max": 2,
"default": 0,
- "unit": 1,
- "cgroup": "雷达设置",
- "ctitle": "开启角雷达 (0)",
- "cdescr": "1: 开启角雷达, 2: CCNC 车辆的切入检测"
+ "unit": 1
},
{
"group": "시작",
@@ -1865,13 +2425,13 @@
"egroup": "START",
"etitle": "Enable HotSpot(0)",
"edescr": "Feature to automatically enable hotspot when a USIM is inserted in COMMA",
+ "cgroup": "启动设置",
+ "ctitle": "开启热点 (0)",
+ "cdescr": "在 COMMA 中插入 USIM 卡时自动开启热点的功能",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "开启热点 (0)",
- "cdescr": "在 COMMA 中插入 USIM 卡时自动开启热点的功能"
+ "unit": 1
},
{
"group": "시작",
@@ -1881,13 +2441,13 @@
"egroup": "START",
"etitle": "Enable Software menu",
"edescr": "Turn off on memory error",
+ "cgroup": "启动设置",
+ "ctitle": "开启软件菜单",
+ "cdescr": "内存错误时关闭",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "启动设置",
- "ctitle": "开启软件菜单",
- "cdescr": "内存错误时关闭"
+ "unit": 1
},
{
"group": "시작",
@@ -1897,13 +2457,13 @@
"egroup": "START",
"etitle": "Sound Volume adjust(100%)",
"edescr": "",
+ "cgroup": "启动设置",
+ "ctitle": "音量调节 (100%)",
+ "cdescr": "",
"min": 5,
"max": 200,
"default": 0,
- "unit": 5,
- "cgroup": "启动设置",
- "ctitle": "音量调节 (100%)",
- "cdescr": ""
+ "unit": 5
},
{
"group": "시작",
@@ -1913,13 +2473,13 @@
"egroup": "START",
"etitle": "Sound Volume adjust,Engage(10%)",
"edescr": "",
+ "cgroup": "启动设置",
+ "ctitle": "音量调节,激活音量 (10%)",
+ "cdescr": "",
"min": 5,
"max": 200,
"default": 0,
- "unit": 5,
- "cgroup": "启动设置",
- "ctitle": "音量调节,激活音量 (10%)",
- "cdescr": ""
+ "unit": 5
},
{
"group": "차량간격",
@@ -1929,13 +2489,13 @@
"egroup": "FDIST",
"etitle": "TF(1): TimeFollow1x0.01s(110)",
"edescr": "Following Distance Level 1",
+ "cgroup": "跟车距离",
+ "ctitle": "跟车时间(1): TimeFollow1x0.01s(110)",
+ "cdescr": "跟车距离 1 级",
"min": 40,
"max": 300,
"default": 110,
- "unit": 5,
- "cgroup": "跟车距离",
- "ctitle": "跟车时间(1): TimeFollow1x0.01s(110)",
- "cdescr": "跟车距离 1 级"
+ "unit": 5
},
{
"group": "차량간격",
@@ -1945,13 +2505,13 @@
"egroup": "FDIST",
"etitle": "TF(2): TimeFollow2x0.01s(120)",
"edescr": "Following Distance Level 2",
+ "cgroup": "跟车距离",
+ "ctitle": "跟车时间(2): TimeFollow2x0.01s(120)",
+ "cdescr": "跟车距离 2 级",
"min": 40,
"max": 300,
"default": 120,
- "unit": 5,
- "cgroup": "跟车距离",
- "ctitle": "跟车时间(2): TimeFollow2x0.01s(120)",
- "cdescr": "跟车距离 2 级"
+ "unit": 5
},
{
"group": "차량간격",
@@ -1961,13 +2521,13 @@
"egroup": "FDIST",
"etitle": "TF(3): TimeFollow3x0.01s(140)",
"edescr": "Following Distance Level 3",
+ "cgroup": "跟车距离",
+ "ctitle": "跟车时间(3): TimeFollow3x0.01s(140)",
+ "cdescr": "跟车距离 3 级",
"min": 40,
"max": 300,
"default": 140,
- "unit": 5,
- "cgroup": "跟车距离",
- "ctitle": "跟车时间(3): TimeFollow3x0.01s(140)",
- "cdescr": "跟车距离 3 级"
+ "unit": 5
},
{
"group": "차량간격",
@@ -1977,13 +2537,13 @@
"egroup": "FDIST",
"etitle": "TF(4): TimeFollow4x0.01s(160)",
"edescr": "Following Distance Level 4",
+ "cgroup": "跟车距离",
+ "ctitle": "跟车时间(4): TimeFollow4x0.01s(160)",
+ "cdescr": "跟车距离 4 级",
"min": 40,
"max": 300,
"default": 160,
- "unit": 5,
- "cgroup": "跟车距离",
- "ctitle": "跟车时间(4): TimeFollow4x0.01s(160)",
- "cdescr": "跟车距离 4 级"
+ "unit": 5
},
{
"group": "차량간격",
@@ -1993,13 +2553,13 @@
"egroup": "FDIST",
"etitle": "Dynamic TFollow",
"edescr": "Dynamically adjusts following distance based on changes in lead vehicle motion",
+ "cgroup": "跟车距离",
+ "ctitle": "动态跟车时间",
+ "cdescr": "根据前车运动变化动态调整跟车距离",
"min": 0,
"max": 100,
"default": 0,
- "unit": 1,
- "cgroup": "跟车距离",
- "ctitle": "动态跟车时间",
- "cdescr": "根据前车运动变化动态调整跟车距离"
+ "unit": 1
},
{
"group": "차량간격",
@@ -2009,13 +2569,13 @@
"egroup": "FDIST",
"etitle": "EnableSpeedTF(0)",
"edescr": "-1:0/30/60/90km/h steps\n-2:0/40/80/120km/h steps\n-3:0/50/100/150km/h steps\n1~50%:Reduce TF below 100km/h",
+ "cgroup": "跟车距离",
+ "ctitle": "开启基于速度的跟车时间 (0)",
+ "cdescr": "-1: 0/30/60/90km/h 分段\n-2: 0/40/80/120km/h 分段\n-3: 0/50/100/150km/h 分段\n1~50%: 100km/h 以下减小跟车时间",
"min": -3,
"max": 50,
"default": 0,
- "unit": 1,
- "cgroup": "跟车距离",
- "ctitle": "开启基于速度的跟车时间 (0)",
- "cdescr": "-1: 0/30/60/90km/h 分段\n-2: 0/40/80/120km/h 分段\n-3: 0/50/100/150km/h 分段\n1~50%: 100km/h 以下减小跟车时间"
+ "unit": 1
},
{
"group": "차량간격",
@@ -2025,13 +2585,13 @@
"egroup": "FDIST",
"etitle": "Dynamic TFollow LaneChange(100)%",
"edescr": "Temporarily reduces the gap between vehicles when starting a lane change",
+ "cgroup": "跟车距离",
+ "ctitle": "变道动态跟车时间 (100)%",
+ "cdescr": "变道开始时临时缩小车距",
"min": 20,
"max": 100,
"default": 0,
- "unit": 5,
- "cgroup": "跟车距离",
- "ctitle": "变道动态跟车时间 (100)%",
- "cdescr": "变道开始时临时缩小车距"
+ "unit": 5
},
{
"group": "차량간격",
@@ -2041,13 +2601,13 @@
"egroup": "FDIST",
"etitle": "Decel TF Boost Ratio (30)",
"edescr": "Extra t_follow boost ratio during deceleration. Higher values keep more following distance while slowing down.",
+ "cgroup": "跟车距离",
+ "ctitle": "减速TF增益比例(30)",
+ "cdescr": "减速时额外增加 t_follow 的比例。数值越大,减速时跟车距离越宽松。",
"min": 0,
"max": 100,
"default": 10,
- "unit": 10,
- "cgroup": "跟车距离",
- "ctitle": "减速TF增益比例(30)",
- "cdescr": "减速时额外增加 t_follow 的比例。数值越大,减速时跟车距离越宽松。"
+ "unit": 10
},
{
"group": "감속제어",
@@ -2057,13 +2617,13 @@
"egroup": "FDIST",
"etitle": "AutoCurveSpeed LowerLimit(30)",
"edescr": "Curve Minimum Speed Setting",
+ "cgroup": "跟车距离",
+ "ctitle": "弯道自动减速下限 (30)",
+ "cdescr": "弯道最低速度设置",
"min": 10,
"max": 200,
"default": 30,
- "unit": 10,
- "cgroup": "跟车距离",
- "ctitle": "弯道自动减速下限 (30)",
- "cdescr": "弯道最低速度设置"
+ "unit": 10
},
{
"group": "주행튜닝",
@@ -2073,13 +2633,13 @@
"egroup": "LONG",
"etitle": "StoppingStartAccelx0.01(0)",
"edescr": "stopping acceleration, 0: Traditional method",
+ "cgroup": "纵向控制",
+ "ctitle": "停止起步加速度 x0.01(0)",
+ "cdescr": "停止加速度,0: 传统方式",
"min": -100,
"max": 0,
"default": 0,
- "unit": 10,
- "cgroup": "纵向控制",
- "ctitle": "停止起步加速度 x0.01(0)",
- "cdescr": "停止加速度,0: 传统方式"
+ "unit": 10
},
{
"group": "가속설정",
@@ -2089,13 +2649,13 @@
"egroup": "ACCEL",
"etitle": "DrivingMode:Init(3)",
"edescr": "1: Fuel Economy (ComfortBrake, 10% accel. reduction), 2: Safety (ComfortBrake, 20% accel. reduction), 3: Normal, 4: High Speed (Ignores signals, 20% accel. increase).",
+ "cgroup": "加速设置",
+ "ctitle": "驾驶模式: 初始 (3)",
+ "cdescr": "1: 经济 (舒适刹车, 加速度减少 10%), 2: 安全 (舒适刹车, 加速度减少 20%), 3: 普通, 4: 高速 (忽略信号, 加速度增加 20%)",
"min": 1,
"max": 4,
"default": 3,
- "unit": 1,
- "cgroup": "加速设置",
- "ctitle": "驾驶模式: 初始 (3)",
- "cdescr": "1: 经济 (舒适刹车, 加速度减少 10%), 2: 安全 (舒适刹车, 加速度减少 20%), 3: 普通, 4: 高速 (忽略信号, 加速度增加 20%)"
+ "unit": 1
},
{
"group": "가속설정",
@@ -2105,13 +2665,13 @@
"egroup": "ACCEL",
"etitle": "DrivingMode: Auto",
"edescr": "Safety mode in Congested Conditions; Normal mode when lead vehicle accelerates quickly or 20+km/h.",
+ "cgroup": "加速设置",
+ "ctitle": "驾驶模式: 自动",
+ "cdescr": "拥堵路况进入安全模式;前车加速快或速度超过 20km/h 时进入普通模式",
"min": 0,
"max": 1,
"default": 0,
- "unit": 1,
- "cgroup": "加速设置",
- "ctitle": "驾驶模式: 自动",
- "cdescr": "拥堵路况进入安全模式;前车加速快或速度超过 20km/h 时进入普通模式"
+ "unit": 1
},
{
"group": "감속제어",
@@ -2121,13 +2681,13 @@
"egroup": "SPEED",
"etitle": "TrafficLightDetectMode",
"edescr": "0:None,1:Stopping only, 2:Stop & Go",
+ "cgroup": "速度控制",
+ "ctitle": "红绿灯检测模式",
+ "cdescr": "0: 无, 1: 仅停止, 2: 停止和起步",
"min": 0,
"max": 2,
"default": 2,
- "unit": 1,
- "cgroup": "速度控制",
- "ctitle": "红绿灯检测模式",
- "cdescr": "0: 无, 1: 仅停止, 2: 停止和起步"
+ "unit": 1
},
{
"group": "감속제어",
@@ -2137,13 +2697,13 @@
"egroup": "SPEED",
"etitle": "NaviSpeedEndingPoint(6s)",
"edescr": "Time until decel completes, based on speed x time",
+ "cgroup": "速度控制",
+ "ctitle": "导航减速结束点 (6秒)",
+ "cdescr": "基于 速度 x 时间 的减速完成时间",
"min": 3,
"max": 20,
"default": 6,
- "unit": 1,
- "cgroup": "速度控制",
- "ctitle": "导航减速结束点 (6秒)",
- "cdescr": "基于 速度 x 时间 的减速完成时间"
+ "unit": 1
},
{
"group": "감속제어",
@@ -2153,13 +2713,13 @@
"egroup": "SPEED",
"etitle": "NaviSpeedControlMode(2)",
"edescr": "0: Not Use, 1: Speed cam, 2: cam + speed bump, 3: cam + bump + apn speed cam",
+ "cgroup": "速度控制",
+ "ctitle": "导航减速模式 (2)",
+ "cdescr": "0: 不使用, 1: 限速摄像头, 2: 摄像头 + 减速带, 3: 摄像头 + 减速带 + APN 限速摄像头",
"min": 0,
"max": 3,
"default": 2,
- "unit": 1,
- "cgroup": "速度控制",
- "ctitle": "导航减速模式 (2)",
- "cdescr": "0: 不使用, 1: 限速摄像头, 2: 摄像头 + 减速带, 3: 摄像头 + 减速带 + APN 限速摄像头"
+ "unit": 1
},
{
"group": "감속제어",
@@ -2169,13 +2729,13 @@
"egroup": "SPEED",
"etitle": "RoadSpeedLimitOffset(-1)",
"edescr": "RoadLimitSpeed+Set Value, -1:Not Use",
+ "cgroup": "速度控制",
+ "ctitle": "道路限速偏移 (-1)",
+ "cdescr": "道路限速 + 设定值, -1: 不使用",
"min": -1,
"max": 100,
"default": -1,
- "unit": 1,
- "cgroup": "速度控制",
- "ctitle": "道路限速偏移 (-1)",
- "cdescr": "道路限速 + 设定值, -1: 不使用"
+ "unit": 1
},
{
"group": "감속제어",
@@ -2185,13 +2745,13 @@
"egroup": "SPEED",
"etitle": "SpeedBumpEndingPoint(1s)",
"edescr": "",
+ "cgroup": "速度控制",
+ "ctitle": "减速带结束点 (1秒)",
+ "cdescr": "",
"min": 1,
"max": 50,
"default": 1,
- "unit": 1,
- "cgroup": "速度控制",
- "ctitle": "减速带结束点 (1秒)",
- "cdescr": ""
+ "unit": 1
},
{
"group": "감속제어",
@@ -2201,13 +2761,13 @@
"egroup": "SPEED",
"etitle": "SpeedBumpSpeed(35km/h)",
"edescr": "",
+ "cgroup": "速度控制",
+ "ctitle": "减速带速度 (35km/h)",
+ "cdescr": "",
"min": 10,
"max": 100,
"default": 35,
- "unit": 5,
- "cgroup": "速度控制",
- "ctitle": "减速带速度 (35km/h)",
- "cdescr": ""
+ "unit": 5
},
{
"group": "감속제어",
@@ -2217,13 +2777,13 @@
"egroup": "SPEED",
"etitle": "NaviSpeedDecelRate 0.01m/s^2x(200)",
"edescr": "The lower the value, the further away it decelerates.",
+ "cgroup": "速度控制",
+ "ctitle": "导航减速效率 0.01m/s^2x(200)",
+ "cdescr": "值越低,减速越早(距离越远)。",
"min": 50,
"max": 300,
"default": 200,
- "unit": 10,
- "cgroup": "速度控制",
- "ctitle": "导航减速效率 0.01m/s^2x(200)",
- "cdescr": "值越低,减速越早(距离越远)。"
+ "unit": 10
},
{
"group": "감속제어",
@@ -2233,13 +2793,13 @@
"egroup": "SPEED",
"etitle": "NaviCountDownMode",
"edescr": "0:not use, 1: turn point + speed, 2: turn point + speed + bump",
+ "cgroup": "速度控制",
+ "ctitle": "导航倒计时模式",
+ "cdescr": "0: 不使用, 1: 转向点 + 速度, 2: 转向点 + 速度 + 减速带",
"min": 0,
"max": 2,
"default": 2,
- "unit": 1,
- "cgroup": "速度控制",
- "ctitle": "导航倒计时模式",
- "cdescr": "0: 不使用, 1: 转向点 + 速度, 2: 转向点 + 速度 + 减速带"
+ "unit": 1
},
{
"group": "감속제어",
@@ -2249,13 +2809,13 @@
"egroup": "SPEED",
"etitle": "TurnSpeedControlMode",
"edescr": "0:not use, 1:vision, 2:vision+route, 3:route(always)",
+ "cgroup": "速度控制",
+ "ctitle": "转向速度控制模式",
+ "cdescr": "0: 不使用, 1: 视觉, 2: 视觉 + 路线, 3: 路线 (始终)",
"min": 0,
"max": 3,
"default": 1,
- "unit": 1,
- "cgroup": "速度控制",
- "ctitle": "转向速度控制模式",
- "cdescr": "0: 不使用, 1: 视觉, 2: 视觉 + 路线, 3: 路线 (始终)"
+ "unit": 1
},
{
"group": "감속제어",
@@ -2265,13 +2825,13 @@
"egroup": "SPEED",
"etitle": "MapTurnSpeedFactor",
"edescr": "The smaller the value, the more the speed will decrease along the route.",
+ "cgroup": "速度控制",
+ "ctitle": "地图转向速度因子",
+ "cdescr": "值越小,沿路线减速越多。",
"min": 50,
"max": 300,
"default": 100,
- "unit": 10,
- "cgroup": "速度控制",
- "ctitle": "地图转向速度因子",
- "cdescr": "值越小,沿路线减速越多。"
+ "unit": 10
},
{
"group": "감속제어",
@@ -2281,13 +2841,13 @@
"egroup": "SPEED",
"etitle": "ModelTurnSpeed time(0)x0.1sec",
"edescr": "future model speed",
+ "cgroup": "速度控制",
+ "ctitle": "模型转向速度时间 (0)x0.1s",
+ "cdescr": "未来模型速度",
"min": 0,
"max": 80,
"default": 0,
- "unit": 10,
- "cgroup": "速度控制",
- "ctitle": "模型转向速度时间 (0)x0.1s",
- "cdescr": "未来模型速度"
+ "unit": 10
},
{
"group": "감속제어",
@@ -2297,23 +2857,23 @@
"egroup": "SPEED",
"etitle": "NaviSpeedLimitRatio(105)%",
"edescr": "Reduce speed to the road speed limit*set value at the speed camera",
+ "cgroup": "速度控制",
+ "ctitle": "导航限速比例 (105)%",
+ "cdescr": "在限速摄像头处将速度降至 道路限速 * 设定值",
"min": 80,
"max": 120,
"default": 105,
- "unit": 1,
- "cgroup": "速度控制",
- "ctitle": "导航限速比例 (105)%",
- "cdescr": "在限速摄像头处将速度降至 道路限速 * 设定值"
+ "unit": 1
},
{
"group": "화면",
- "egroup": "DISPLAY",
- "cgroup": "显示",
"name": "ShowCustomBrightness",
"title": "주행중 화면밝기(100%)",
"descr": "주행 시작 약 10초 후 화면밝기 비율\n0: 주변밝기 자동조절\n100: 항상 최대 밝기",
+ "egroup": "DISPLAY",
"etitle": "Onroad Screen Brightness(100%)",
"edescr": "Screen brightness ratio ~10s after driving starts\n0: Auto adjust by ambient light\n100: Always max brightness",
+ "cgroup": "显示",
"ctitle": "行车中屏幕亮度(100%)",
"cdescr": "行车开始约10秒后的屏幕亮度比例\n0: 根据环境亮度自动调节\n100: 始终最大亮度",
"min": 0,
@@ -2323,13 +2883,13 @@
},
{
"group": "화면",
- "egroup": "DISPLAY",
- "cgroup": "显示",
"name": "ShowModelView",
"title": "주행화면 표시 모드(C4)",
"descr": "주행 중 화면 밝기가 설정값 근처까지 낮아졌을 때 표시 방식\n0: 카메라와 모델 표시\n1: 카메라만 표시\n2: 모델만 표시\n3: 카메라와 모델 숨김",
+ "egroup": "DISPLAY",
"etitle": "Onroad Display Mode(C4)",
"edescr": "Display mode when onroad screen brightness reaches the configured level\n0: Show camera and model\n1: Show camera only\n2: Show model only\n3: Hide camera and model",
+ "cgroup": "显示",
"ctitle": "行车画面显示模式(C4)",
"cdescr": "行车中屏幕亮度接近设定值时的显示方式\n0: 显示摄像头和模型\n1: 仅显示摄像头\n2: 仅显示模型\n3: 隐藏摄像头和模型",
"min": 0,
@@ -2339,13 +2899,13 @@
},
{
"group": "외부 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "外部 HUD",
"name": "ClusterHud",
"title": "외부 HUD 활성화(0)",
"descr": "0: 끄기\n1: TURZX 9.2인치\n2: TURZX 12.3인치",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Display(0)",
"edescr": "0: Off\n1: TURZX 9.2 inch\n2: TURZX 12.3 inch",
+ "cgroup": "外部 HUD",
"ctitle": "外部 HUD 显示(0)",
"cdescr": "0: 关闭\n1: TURZX 9.2 英寸\n2: TURZX 12.3 英寸",
"min": 0,
@@ -2355,13 +2915,13 @@
},
{
"group": "외부 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "外部 HUD",
"name": "ClusterHudDebug",
- "title": "\uc678\ubd80 HUD \ub514\ubc84\uae45(0)",
- "descr": "0: \uc628\ub85c\ub4dc\uc5d0\uc11c\ub9cc\n1: \ud56d\uc0c1\n2: \ud56d\uc0c1+UI\n3: \ud56d\uc0c1+Navi",
+ "title": "외부 HUD 디버깅(0)",
+ "descr": "0: 온로드에서만\n1: 항상\n2: 항상+UI\n3: 항상+Navi",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Debug(0)",
"edescr": "0: Onroad only\n1: Always\n2: Always + UI\n3: Always + Navi",
+ "cgroup": "外部 HUD",
"ctitle": "External HUD Debug(0)",
"cdescr": "0: Onroad only\n1: Always\n2: Always + UI\n3: Always + Navi",
"min": 0,
@@ -2370,14 +2930,14 @@
"unit": 1
},
{
- "group": "\uc678\ubd80 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "\u5916\u90e8 HUD",
+ "group": "외부 HUD",
"name": "ClusterHudBrightness",
"title": "외부 HUD 밝기(0)",
"descr": "0: 자동\n1~100: 밝기",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Brightness(0)",
"edescr": "0: Auto\n1-100: Brightness",
+ "cgroup": "外部 HUD",
"ctitle": "外部 HUD 亮度(0)",
"cdescr": "0: 自动\n1-100: 亮度",
"min": 0,
@@ -2387,13 +2947,13 @@
},
{
"group": "외부 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "外部 HUD",
"name": "ClusterHudEncoder",
"title": "외부 HUD 인코더(0)",
"descr": "0: 자동(하드웨어 H264 -> 소프트웨어 H264 -> JPEG)\n1: JPEG\n2: 하드웨어 H264\n3: 소프트웨어 H264(ffmpeg/libx264)",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Encoder(0)",
"edescr": "0: Auto (Hardware H264 -> Software H264 -> JPEG)\n1: JPEG\n2: Hardware H264\n3: Software H264 (ffmpeg/libx264)",
+ "cgroup": "外部 HUD",
"ctitle": "外部 HUD 编码器(0)",
"cdescr": "0: Auto (Hardware H264 -> Software H264 -> JPEG)\n1: JPEG\n2: Hardware H264\n3: Software H264 (ffmpeg/libx264)",
"min": 0,
@@ -2403,13 +2963,13 @@
},
{
"group": "외부 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "外部 HUD",
"name": "ClusterHudTheme",
"title": "외부 HUD 테마(0)",
"descr": "0: 자동\n1: 다크\n2: 라이트",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Theme(0)",
"edescr": "0: Auto\n1: Dark\n2: Light",
+ "cgroup": "外部 HUD",
"ctitle": "外部 HUD 主题(0)",
"cdescr": "0: 自动\n1: 深色\n2: 浅色",
"min": 0,
@@ -2419,13 +2979,13 @@
},
{
"group": "외부 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "外部 HUD",
"name": "ClusterHudLiveFps",
"title": "외부 HUD 라이브 FPS 제한(1)",
"descr": "0: 무제한(진단용)\n1: 10 FPS(기본)\n2: 20 FPS\n3: 30 FPS\n4: 40 FPS\n5: 50 FPS\n6: 60 FPS",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Live FPS Limit(1)",
"edescr": "0: Uncapped (diagnostic)\n1: 10 FPS (default)\n2: 20 FPS\n3: 30 FPS\n4: 40 FPS\n5: 50 FPS\n6: 60 FPS",
+ "cgroup": "外部 HUD",
"ctitle": "外部 HUD 实时 FPS 限制(1)",
"cdescr": "0: Uncapped (diagnostic)\n1: 10 FPS (default)\n2: 20 FPS\n3: 30 FPS\n4: 40 FPS\n5: 50 FPS\n6: 60 FPS",
"min": 0,
@@ -2435,13 +2995,13 @@
},
{
"group": "외부 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "外部 HUD",
"name": "ClusterHudScreenMode",
"title": "외부 HUD 화면 모드(0)",
"descr": "0: 기본\n1: 디버그\n2: 디버그(시스템)\n3: 디버그(그래프1)\n4: 디버그(그래프2)",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Screen Mode(0)",
"edescr": "0: Default\n1: Debug\n2: Debug (system)\n3: Debug (graph1)\n4: Debug (graph2)\n5: Navi Debug",
+ "cgroup": "外部 HUD",
"ctitle": "外部 HUD 画面模式(0)",
"cdescr": "0: 默认\n1: 调试\n2: 调试(系统)\n3: 调试(图表1)\n4: 调试(图表2)",
"min": 0,
@@ -2451,13 +3011,13 @@
},
{
"group": "외부 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "外部 HUD",
"name": "ClusterHudRadarInfo",
"title": "외부 HUD 레이더 정보 표시(4)",
"descr": "0: 표시 안함\n1: 속도(차량만)\n2: 속도,거리(차량만)\n3: 속도(모두)\n4: 속도,거리(모두)",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Radar Info(4)",
"edescr": "0: Off\n1: Speed (vehicles only)\n2: Speed, distance (vehicles only)\n3: Speed (all)\n4: Speed, distance (all)",
+ "cgroup": "外部 HUD",
"ctitle": "外部 HUD 雷达信息(4)",
"cdescr": "0: 关闭\n1: 速度(仅车辆)\n2: 速度,距离(仅车辆)\n3: 速度(全部)\n4: 速度,距离(全部)",
"min": 0,
@@ -2467,13 +3027,13 @@
},
{
"group": "외부 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "外部 HUD",
"name": "ClusterHudRadarDisplay",
"title": "외부 HUD 레이더 표시 옵션(0)",
"descr": "0: 기본(가까운 레이더 포인트 병합)\n1: 상세(레이더 포인트 병합 안함)",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Radar Display(0)",
"edescr": "0: Default (merge nearby radar points)\n1: Detail (raw radar points)",
+ "cgroup": "外部 HUD",
"ctitle": "外部 HUD 雷达显示选项(0)",
"cdescr": "0: 默认(合并相近雷达点)\n1: 详细(不合并雷达点)",
"min": 0,
@@ -2483,13 +3043,13 @@
},
{
"group": "외부 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "外部 HUD",
"name": "ClusterHudRadarSourceColor",
"title": "외부 HUD 레이더 소스 색구분(0)",
"descr": "0: 기본(모든 차량 회색)\n1: 켜짐(SCC=R, HDA=B, RADAR=O)",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Radar Source Colors(0)",
"edescr": "0: Default (all vehicles gray)\n1: On (SCC=R, HDA=B, RADAR=O)",
+ "cgroup": "外部 HUD",
"ctitle": "外部 HUD 雷达来源颜色(0)",
"cdescr": "0: 默认(所有车辆灰色)\n1: 开启(SCC=R, HDA=B, RADAR=O)",
"min": 0,
@@ -2498,14 +3058,14 @@
"unit": 1
},
{
- "group": "\uc678\ubd80 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "\u5916\u90e8 HUD",
+ "group": "외부 HUD",
"name": "ClusterHudCoreMode",
- "title": "\uc678\ubd80 HUD CPU \ucf54\uc5b4 \uc9c0\uc815(0)",
- "descr": "CLUSTER_REALTIME=1\uc77c \ub54c\ub9cc \uc801\uc6a9\n0: 1,2,3,4\n1: \ubaa8\ub4e0 \ucf54\uc5b4\n\ubcc0\uacbd \uc2dc \ud074\ub7ec\uc2a4\ud130 HUD\ub97c \uc7ac\uc2dc\uc791\ud569\ub2c8\ub2e4.",
+ "title": "외부 HUD CPU 코어 지정(0)",
+ "descr": "CLUSTER_REALTIME=1일 때만 적용\n0: 1,2,3,4\n1: 모든 코어\n변경 시 클러스터 HUD를 재시작합니다.",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD CPU Core Mode(0)",
"edescr": "Applies only when CLUSTER_REALTIME=1\n0: cores 1,2,3,4\n1: all cores\nChanging this restarts the cluster HUD process.",
+ "cgroup": "外部 HUD",
"ctitle": "External HUD CPU Core Mode(0)",
"cdescr": "Applies only when CLUSTER_REALTIME=1\n0: cores 1,2,3,4\n1: all cores\nChanging this restarts the cluster HUD process.",
"min": 0,
@@ -2514,14 +3074,14 @@
"unit": 1
},
{
- "group": "\uc678\ubd80 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "\u5916\u90e8 HUD",
+ "group": "외부 HUD",
"name": "ClusterHudPriority",
- "title": "\uc678\ubd80 HUD \uc2e4\uc2dc\uac04 \uc6b0\uc120\uc21c\uc704(10)",
- "descr": "CLUSTER_REALTIME=1\uc77c \ub54c\ub9cc \uc801\uc6a9\n1-99\n\uae30\ubcf8 10\n\ubcc0\uacbd \uc2dc \ud074\ub7ec\uc2a4\ud130 HUD\ub97c \uc7ac\uc2dc\uc791\ud569\ub2c8\ub2e4.",
+ "title": "외부 HUD 실시간 우선순위(10)",
+ "descr": "CLUSTER_REALTIME=1일 때만 적용\n1-99\n기본 10\n변경 시 클러스터 HUD를 재시작합니다.",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Realtime Priority(10)",
"edescr": "Applies only when CLUSTER_REALTIME=1\n1-99\nDefault 10\nChanging this restarts the cluster HUD process.",
+ "cgroup": "外部 HUD",
"ctitle": "External HUD Realtime Priority(10)",
"cdescr": "Applies only when CLUSTER_REALTIME=1\n1-99\nDefault 10\nChanging this restarts the cluster HUD process.",
"min": 1,
@@ -2530,14 +3090,14 @@
"unit": 1
},
{
- "group": "\uc678\ubd80 HUD",
- "egroup": "CLUSTER HUD",
- "cgroup": "\u5916\u90e8 HUD",
+ "group": "외부 HUD",
"name": "ClusterHudCameraViewMode",
- "title": "\uc678\ubd80 HUD \uce74\uba54\ub77c \ubdf0 \ubaa8\ub4dc(0)",
- "descr": "0: \uae30\ubcf8\n1: \ubaa8\ub4dc1(\ud558\ub2e8\ubdf0)",
+ "title": "외부 HUD 카메라 뷰 모드(0)",
+ "descr": "0: 기본\n1: 모드1(하단뷰)",
+ "egroup": "CLUSTER HUD",
"etitle": "External HUD Camera View Mode(0)",
"edescr": "0: Default\n1: Mode 1 (bottom view)",
+ "cgroup": "外部 HUD",
"ctitle": "External HUD Camera View Mode(0)",
"cdescr": "0: Default\n1: Mode 1 (bottom view)",
"min": 0,