diff --git a/crates/ui-egui/src/dialogs/variables.rs b/crates/ui-egui/src/dialogs/variables.rs index 2a21eb27..5e1c0f87 100644 --- a/crates/ui-egui/src/dialogs/variables.rs +++ b/crates/ui-egui/src/dialogs/variables.rs @@ -21,6 +21,11 @@ pub const KIND: &str = "variables"; /// The kinds a variable can have, as `variable.define` names them. const KINDS: [&str; 2] = ["text", "visibility"]; +/// What the dialog shows for each of [`KINDS`]. +fn kind_labels() -> [&'static str; 2] { + [tl!("Text"), tl!("Visibility")] +} + pub(super) const SPEC: DialogSpec = DialogSpec { heading: |d| tl!(&d.str("__label")).to_string(), body, confirm, min_width: 380.0, ..DialogSpec::FORM }; @@ -96,7 +101,7 @@ pub fn open(app: &mut VectorcraftApp, id: &str, preselect: Option<&str>) -> bool app.status(if key == "variable" { tl!("no variable to rename").to_string() } else { tl!("no data set to rename").to_string() }); return true; } - fields.insert(key.into(), json!(preselect.filter(|p| names.contains(p)).unwrap_or(names[0]))); + fields.insert(key.into(), json!(preselect.filter(|p| names.contains(p)).or(names.first().copied()).unwrap_or_default())); fields.insert("newName".into(), json!("")); } } @@ -136,10 +141,10 @@ fn value_key(name: &str) -> String { fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { let t = Tokens::get(ui.ctx()); let Some(st) = app.session.active() else { - widgets::dim_label(ui, "No document"); + widgets::dim_label(ui, tl!("No document")); return false; }; - let vars = st.doc.variables.clone(); + let vars = &st.doc.variables; let variable_names: Vec<&str> = vars.variables.iter().map(|v| v.name.as_str()).collect(); let dataset_names: Vec<&str> = vars.datasets.iter().map(|x| x.name.as_str()).collect(); egui::Grid::new("variables-grid").num_columns(2).spacing([12.0, 8.0]).show(ui, |ui| { @@ -150,7 +155,12 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { text(ui, d, "name", 220.0); ui.end_row(); label(ui, tl!("Kind")); - dropdown(ui, d, "kind", &KINDS, 220.0); + // The kinds by their translated names; the field keeps the command's own word. + let labels = kind_labels(); + let shown = KINDS.iter().position(|k| *k == d.str("kind")).and_then(|i| labels.get(i)).copied().unwrap_or_default(); + if let Some(kind) = widgets::dropdown_names(ui, ("variables-dd", "kind"), shown, &labels, 220.0).and_then(|i| KINDS.get(i)) { + d.fields.insert("kind".into(), json!(kind)); + } ui.end_row(); } "variable.bind" => { @@ -182,7 +192,7 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { text(ui, d, "name", 220.0); ui.end_row(); if vars.variables.is_empty() { - widgets::dim_label(ui, "Define a variable first"); + widgets::dim_label(ui, tl!("Define a variable first")); ui.end_row(); return; } @@ -223,16 +233,18 @@ fn checkbox(ui: &mut egui::Ui, d: &mut Dialog, key: &str) -> egui::Response { r } -/// A dropdown over `options` for `key`, written back as it changes. The empty option is first -/// so a fresh dialog can still be filled in; a name that is no longer offered reads as empty -/// rather than being silently swapped for another one. +/// A dropdown over the document's names `options` (shown as they are, never translated) for +/// `key`, written back as it changes. The empty option is first so a fresh dialog can still be +/// filled in; a name that is no longer offered reads as empty rather than being silently +/// swapped for another one. fn dropdown(ui: &mut egui::Ui, d: &mut Dialog, key: &str, options: &[&str], width: f32) { let cur = d.str(key); let mut labels: Vec<&str> = vec![""]; labels.extend_from_slice(options); let shown = if cur.is_empty() || options.contains(&cur.as_str()) { cur.as_str() } else { "" }; - if let Some(i) = widgets::dropdown(ui, ("variables-dd", key), shown, &labels, width) { - d.fields.insert(key.into(), json!(options.get(i.saturating_sub(1)).copied().unwrap_or_default())); + if let Some(i) = widgets::dropdown_names(ui, ("variables-dd", key), shown, &labels, width) { + // The empty option (0) empties the field; the rest are `options`, one along. + d.fields.insert(key.into(), json!(i.checked_sub(1).and_then(|i| options.get(i)).copied().unwrap_or_default())); } } @@ -257,13 +269,15 @@ fn values_of(d: &Dialog, vars: &Variables) -> Value { fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result { let cmd = d.str("__command"); let name = d.str("name"); - let vars = app.session.active().map(|st| st.doc.variables.clone()).unwrap_or_default(); let p = match cmd.as_str() { "variable.define" => json!({"name": name, "kind": d.str("kind")}), "variable.bind" => json!({"variable": d.str("variable")}), "variable.rename" => json!({"name": d.str("variable"), "newName": d.str("newName")}), "dataset.rename" => json!({"name": name, "newName": d.str("newName")}), - "dataset.new" | "dataset.set" => json!({"name": name, "values": values_of(d, &vars)}), + "dataset.new" | "dataset.set" => { + let values = app.session.active().map(|st| values_of(d, &st.doc.variables)).unwrap_or_else(|| json!({})); + json!({"name": name, "values": values}) + } "dataset.select" => json!({"name": name}), _ => json!({}), }; diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index b42a0ddc..e891d12b 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -3954,3 +3954,46 @@ theme Appearance Erscheinungsbild Frosted Mattiert Tiny Lens Kleine Linsen Canvas Leinwand + Highlight Variable Variable hervorheben + New Variable Neue Variable + Delete Variable Variable löschen + List Variables Variablen auflisten + Bind Variable Variable binden + Unbind Variable Variable lösen + New Data Set Neuer Datensatz + Delete Data Set Datensatz löschen + List Data Sets Datensätze auflisten + Select Data Set Datensatz auswählen + Next Data Set Nächster Datensatz + Previous Data Set Vorheriger Datensatz + Data Sets Datensätze + New Variable… Neue Variable… + Bind Variable… Variable binden… + New Data Set… Neuer Datensatz… + Edit Data Set… Datensatz bearbeiten… + Select Data Set… Datensatz auswählen… + Variables Panel Bedienfeld „Variablen“ + Data Set Datensatz + Kind Art + Variable Variable + no document kein Dokument + no data set to edit kein Datensatz zum Bearbeiten + Make Text Dynamic Text dynamisch machen + Make Visibility Dynamic Sichtbarkeit dynamisch machen + Capture Data Set Datensatz erfassen + Update Data Set Datensatz aktualisieren + Rename Data Set… Datensatz umbenennen… + Variable Options… Variablenoptionen… + Select Bound Object Gebundenes Objekt auswählen + Select All Bound Objects Alle gebundenen Objekte auswählen + Multiple objects Mehrere Objekte + New Name Neuer Name + no variable to rename keine Variable zum Umbenennen + no data set to rename kein Datensatz zum Umbenennen + Rename Data Set Datensatz umbenennen + Rename Variable Variable umbenennen + Variable Options Variablenoptionen + Edit Data Set Datensatz bearbeiten + Define a variable first Definieren Sie zuerst eine Variable + Text Text + Visibility Sichtbarkeit diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 8b145dff..85cf5259 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -3079,7 +3079,6 @@ Variable Variable no document no hay documento no data set to edit no hay ningún conjunto de datos que editar - {name} · {kind} · {count} {name} · {kind} · {count} Make Text Dynamic Hacer texto dinámico Make Visibility Dynamic Hacer visible dinámico Capture Data Set Capturar conjunto de datos @@ -4036,3 +4035,8 @@ axis Both Ambos Tiny Lens Lente pequeña Rename Data Set Renombrar conjunto de datos Rename Variable Renombrar variable + Variable Options Opciones de variable + Edit Data Set Editar conjunto de datos + Define a variable first Defina primero una variable + Text Texto + Visibility Visibilidad diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index bdb6eb9f..04d43fac 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -3076,7 +3076,6 @@ Variable Variable no document aucun document no data set to edit aucun jeu de données à modifier - {name} · {kind} · {count} {name} · {kind} · {count} Make Text Dynamic Rendre le texte dynamique Make Visibility Dynamic Rendre la visibilité dynamique Capture Data Set Capturer le jeu de données @@ -4048,3 +4047,8 @@ effect Soft Doux Tiny Lens Petites lentilles Rename Data Set Renommer le jeu de données Rename Variable Renommer la variable + Variable Options Options de variable + Edit Data Set Modifier le jeu de données + Define a variable first Définissez d’abord une variable + Text Texte + Visibility Visibilité diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 4e2ea66b..39f012d5 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -3079,7 +3079,6 @@ Variable Variabile no document nessun documento no data set to edit nessun set di dati da modificare - {name} · {kind} · {count} {name} · {kind} · {count} Make Text Dynamic Rendi testo dinamico Make Visibility Dynamic Rendi visibilità dinamica Capture Data Set Cattura set di dati @@ -4038,3 +4037,8 @@ effect Regular Normale Tiny Lens Lente piccola Rename Data Set Rinomina set di dati Rename Variable Rinomina variabile + Variable Options Opzioni variabile + Edit Data Set Modifica set di dati + Define a variable first Definisci prima una variabile + Text Testo + Visibility Visibilità diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 375717de..0f2a62a8 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -592,7 +592,6 @@ Variable 変数 no document ドキュメントがありません no data set to edit 編集するデータセットがありません - {name} · {kind} · {count} {name} · {kind} · {count} 件 Make Text Dynamic テキストを動的にする Make Visibility Dynamic 表示を動的にする Capture Data Set データセットを取得 @@ -4031,3 +4030,8 @@ effect Vertical 垂直 Frosted すりガラス Tiny Lens 小さなレンズ Rename Data Set データセットの名前を変更 + Variable Options 変数のオプション + Edit Data Set データセットを編集 + Define a variable first 先に変数を定義してください + Text テキスト + Visibility 表示状態 diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index a2e39113..8d281e5d 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -3075,7 +3075,6 @@ Variable Переменная no document нет документа no data set to edit нет набора данных для изменения - {name} · {kind} · {count} {name} · {kind} · {count} Make Text Dynamic Сделать текст динамическим Make Visibility Dynamic Сделать видимость динамической Capture Data Set Записать набор данных @@ -4034,3 +4033,8 @@ axis Both Оба Tiny Lens Мелкие линзы Rename Data Set Переименовать набор данных Rename Variable Переименовать переменную + Variable Options Параметры переменной + Edit Data Set Изменить набор данных + Define a variable first Сначала определите переменную + Text Текст + Visibility Видимость diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 16d5ee66..3d8ceea9 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -3071,7 +3071,6 @@ Variable Змінна no document немає документа no data set to edit немає набору даних для зміни - {name} · {kind} · {count} {name} · {kind} · {count} Make Text Dynamic Зробити текст динамічним Make Visibility Dynamic Зробити видимість динамічною Capture Data Set Записати набір даних @@ -4019,3 +4018,8 @@ axis Both Обидві Tiny Lens Дрібні лінзи Rename Data Set Перейменувати набір даних Rename Variable Перейменувати змінну + Variable Options Параметри змінної + Edit Data Set Змінити набір даних + Define a variable first Спочатку визначте змінну + Text Текст + Visibility Видимість diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index ca479f77..5e31c7e1 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -2970,7 +2970,6 @@ Variable 变量 no document 没有文档 no data set to edit 没有可编辑的数据集 - {name} · {kind} · {count} {name} · {kind} · {count} Make Text Dynamic 使文本动态化 Make Visibility Dynamic 使可见性动态化 Capture Data Set 捕获数据集 @@ -3667,3 +3666,8 @@ effect Vertical 垂直 Tiny Lens 小镜头 Rename Data Set 重命名数据集 Rename Variable 重命名变量 + Variable Options 变量选项 + Edit Data Set 编辑数据集 + Define a variable first 请先定义一个变量 + Text 文本 + Visibility 可见性 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index b409506b..b4deb6f0 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -3062,7 +3062,6 @@ Variable 變數 no document 沒有文件 no data set to edit 沒有可編輯的資料集 - {name} · {kind} · {count} {name} · {kind} · {count} Make Text Dynamic 使文字動態化 Make Visibility Dynamic 使可見性動態化 Capture Data Set 擷取資料集 @@ -3448,3 +3447,8 @@ effect Soft 柔和 Tiny Lens 小鏡頭 Rename Data Set 重新命名資料集 Rename Variable 重新命名變數 + Variable Options 變數選項 + Edit Data Set 編輯資料集 + Define a variable first 請先定義一個變數 + Text 文字 + Visibility 可見性 diff --git a/crates/ui-egui/src/panels/variables.rs b/crates/ui-egui/src/panels/variables.rs index aaa316cc..96586ce2 100644 --- a/crates/ui-egui/src/panels/variables.rs +++ b/crates/ui-egui/src/panels/variables.rs @@ -64,18 +64,14 @@ pub(crate) fn select_bound_object(app: &mut VectorcraftApp) { } } -/// Delete Variable: the highlighted variable only; the rest of the rows stay. +/// Delete Variable: the highlighted variable only (the command's default); the rest stay. pub(crate) fn delete_highlighted(app: &mut VectorcraftApp) { - if let Some(name) = app.session.active().and_then(highlighted_row) { - app.run("variable.delete", json!({"names": [name]})).ok(); - } + app.run("variable.delete", json!({})).ok(); } -/// Delete Data Set: the current one only; the rest of the rows stay. +/// Delete Data Set: the current one only (the command's default); the rest of the rows stay. pub(crate) fn delete_active_dataset(app: &mut VectorcraftApp) { - if let Some(name) = app.session.active().and_then(|st| st.doc.variables.active_dataset.clone()) { - app.run("dataset.delete", json!({"names": [name]})).ok(); - } + app.run("dataset.delete", json!({})).ok(); } pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { @@ -91,14 +87,16 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { .iter() .map(|v| { let bound: Vec = st.doc.variables.objects_of(&v.name).iter().map(|i| i.0).collect(); - let object = match bound.len() { - 0 => String::new(), - 1 => st.doc.node(NodeId(bound[0])).map(|n| n.display_name()).unwrap_or_default(), + let object = match bound.as_slice() { + [] => String::new(), + [one] => st.doc.node(NodeId(*one)).map(|n| n.display_name()).unwrap_or_default(), _ => tl!("Multiple objects").to_string(), }; VarRow { name: v.name.clone(), kind: v.kind, bound, object } }) .collect(); + // What the art holds now, read once for every row's drift check. + let current = st.doc.captured_values(); let sets: Vec = st .doc .variables @@ -108,7 +106,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { name: d.name.clone(), values: d.values.len(), active: st.doc.variables.active_dataset.as_deref() == Some(d.name.as_str()), - matches: st.doc.matches_dataset(&d.name), + matches: d.matches(¤t), }) .collect(); let active = sets.iter().find(|s| s.active); @@ -118,18 +116,18 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { // Unbind needs a bound object under the selection, not just any selection. let selection_bound = selected.iter().any(|id| st.doc.variables.bindings.contains_key(&NodeId(*id))); // Make Text Dynamic needs exactly one type object: a text variable only drives type. - let single_type = selected.len() == 1 && st.doc.node(NodeId(selected[0])).is_some_and(|n| matches!(n.kind, NodeKind::Text(_))); + let single_type = matches!(selected.as_slice(), [one] if st.doc.node(NodeId(*one)).is_some_and(|n| matches!(n.kind, NodeKind::Text(_)))); // The current data set across the top: its name, and the arrows that step through them. ui.horizontal(|ui| { widgets::field_label(ui, tl!("Data Set")); let names: Vec<&str> = sets.iter().map(|s| s.name.as_str()).collect(); let current = active.map(|s| s.name.as_str()).unwrap_or(""); - let picked = widgets::dropdown(ui, "variables-active", current, &names, 160.0); - if let Some(i) = picked - && names.get(i).is_some_and(|n| *n != current) + let picked = widgets::dropdown_names(ui, "variables-active", current, &names, 160.0); + if let Some(name) = picked.and_then(|i| names.get(i)) + && *name != current { - app.run("dataset.select", json!({"name": names[i]})).ok(); + app.run("dataset.select", json!({"name": name})).ok(); } ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { let has = !sets.is_empty();