diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index e0e223ef..bbcc8258 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -535,16 +535,13 @@ Tabs Tabulátory Variables Proměnné New Variable… Nová proměnná… - Bind Variable… Přiřadit proměnnou… Unbind Variable Zrušit přiřazení proměnné Delete Variable Odstranit proměnnou New Data Set… Nová sada dat… Edit Data Set… Upravit sadu dat… Delete Data Set Odstranit sadu dat - Select Data Set… Vybrat sadu dat… Next Data Set Další sada dat Previous Data Set Předchozí sada dat - Variables Panel Panel proměnných Make Text Dynamic Nastavit text jako dynamický Make Visibility Dynamic Nastavit viditelnost jako dynamickou Capture Data Set Pořídit sadu dat diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index e891d12b..58d4344e 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -3968,11 +3968,8 @@ theme Appearance Erscheinungsbild 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 diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 85cf5259..d52cf1ef 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -3069,11 +3069,8 @@ Previous Data Set Conjunto de datos anterior Data Sets Conjuntos de datos New Variable… Nueva variable… - Bind Variable… Vincular variable… New Data Set… Nuevo conjunto de datos… Edit Data Set… Editar conjunto de datos… - Select Data Set… Seleccionar conjunto de datos… - Variables Panel Panel de variables Data Set Conjunto de datos Kind Tipo Variable Variable diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 04d43fac..76796bd1 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -3066,11 +3066,8 @@ Previous Data Set Jeu de données précédent Data Sets Jeux de données New Variable… Nouvelle variable… - Bind Variable… Lier la variable… New Data Set… Nouveau jeu de données… Edit Data Set… Modifier le jeu de données… - Select Data Set… Sélectionner le jeu de données… - Variables Panel Panneau des variables Data Set Jeu de données Kind Type Variable Variable diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 39f012d5..a9c328e9 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -3069,11 +3069,8 @@ Previous Data Set Set di dati precedente Data Sets Set di dati New Variable… Nuova variabile… - Bind Variable… Associa variabile… New Data Set… Nuovo set di dati… Edit Data Set… Modifica set di dati… - Select Data Set… Seleziona set di dati… - Variables Panel Pannello variabili Data Set Set di dati Kind Tipo Variable Variabile diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 0f2a62a8..6c13d3ae 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -582,11 +582,8 @@ Previous Data Set 前のデータセット Data Sets データセット New Variable… 新規変数… - Bind Variable… 変数をバインド… New Data Set… 新規データセット… Edit Data Set… データセットを編集… - Select Data Set… データセットを選択… - Variables Panel 変数パネル Data Set データセット Kind 種類 Variable 変数 diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index e5465411..b1526a88 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -2531,16 +2531,13 @@ Variable Width Profile Perfil de Largura Variável Variables Variáveis New Variable… Nova variável… - Bind Variable… Associar variável… Unbind Variable Desassociar variável Delete Variable Excluir variável New Data Set… Novo conjunto de dados… Edit Data Set… Editar conjunto de dados… Delete Data Set Excluir conjunto de dados - Select Data Set… Selecionar conjunto de dados… Next Data Set Próximo conjunto de dados Previous Data Set Conjunto de dados anterior - Variables Panel Painel de variáveis Make Text Dynamic Tornar texto dinâmico Make Visibility Dynamic Tornar visibilidade dinâmica Capture Data Set Capturar conjunto de dados diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 8d281e5d..3fd2cfe8 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -3065,11 +3065,8 @@ Previous Data Set Предыдущий набор данных Data Sets Наборы данных New Variable… Новая переменная… - Bind Variable… Привязать переменную… New Data Set… Новый набор данных… Edit Data Set… Изменить набор данных… - Select Data Set… Выбрать набор данных… - Variables Panel Панель переменных Data Set Набор данных Kind Тип Variable Переменная diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 3d8ceea9..8140c543 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -3061,11 +3061,8 @@ Previous Data Set Попередній набір даних Data Sets Набори даних New Variable… Нова змінна… - Bind Variable… Прив’язати змінну… New Data Set… Новий набір даних… Edit Data Set… Змінити набір даних… - Select Data Set… Вибрати набір даних… - Variables Panel Панель змінних Data Set Набір даних Kind Тип Variable Змінна diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 5e31c7e1..9bd0df0e 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -2960,11 +2960,8 @@ Previous Data Set 上一个数据集 Data Sets 数据集 New Variable… 新建变量… - Bind Variable… 绑定变量… New Data Set… 新建数据集… Edit Data Set… 编辑数据集… - Select Data Set… 选择数据集… - Variables Panel 变量面板 Data Set 数据集 Kind 类型 Variable 变量 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index b4deb6f0..a4edda1d 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -3052,11 +3052,8 @@ Previous Data Set 上一個資料集 Data Sets 資料集 New Variable… 新增變數… - Bind Variable… 繫結變數… New Data Set… 新增資料集… Edit Data Set… 編輯資料集… - Select Data Set… 選取資料集… - Variables Panel 變數面板 Data Set 資料集 Kind 類型 Variable 變數 diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index f68f5df6..e0ecb0b0 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -48,34 +48,6 @@ fn library_placeholders() -> Vec { vec![todo("Built-in Libraries"), todo("User Defined"), Sep, todo("Other Library…")] } -/// Window › Variables: the panel, then the commands that define and apply what it shows, in -/// the order the panel does them. The "…" commands open a Variables dialog -/// (`dialogs::variables`), so the menu and the command palette both reach them. -fn variables_window_menu(panel: impl Fn(&'static str, &'static str) -> Item) -> Vec { - vec![ - panel("Variables Panel", crate::panels::variables::ID), - Sep, - c("Make Text Dynamic", "variable.makeTextDynamic"), - c("Make Visibility Dynamic", "variable.makeVisibilityDynamic"), - Sep, - c("New Variable…", "variable.define"), - c("Variable Options…", "variable.rename"), - c("Bind Variable…", "variable.bind"), - c("Unbind Variable", "variable.unbind"), - c("Delete Variable", "variable.delete"), - Sep, - c("Capture Data Set", "dataset.capture"), - c("New Data Set…", "dataset.new"), - c("Edit Data Set…", "dataset.set"), - c("Update Data Set", "dataset.update"), - c("Rename Data Set…", "dataset.rename"), - c("Delete Data Set", "dataset.delete"), - Sep, - c("Select Data Set…", "dataset.select"), - c("Next Data Set", "dataset.next"), - c("Previous Data Set", "dataset.prev"), - ] -} use Item::Sep; /// UI-level commands: (id, label, shortcut, params doc). @@ -2577,7 +2549,7 @@ pub fn menu_tree_named(english_names: bool) -> Vec<(&'static str, Vec)> { panel("Tabs", "tabs"), ], ), - sub("Variables", variables_window_menu(panel)), + panel("Variables", crate::panels::variables::ID), Sep, sub("Brush Libraries", library_placeholders()), sub("Graphic Style Libraries", crate::panels::graphic_styles::window_menu()), diff --git a/crates/ui-egui/src/panels/variables.rs b/crates/ui-egui/src/panels/variables.rs index 96586ce2..7eda3b61 100644 --- a/crates/ui-egui/src/panels/variables.rs +++ b/crates/ui-egui/src/panels/variables.rs @@ -64,6 +64,23 @@ pub(crate) fn select_bound_object(app: &mut VectorcraftApp) { } } +/// What the selection allows the bottom bar's and the panel menu's commands to do. +struct Picked { + selected: Vec, + has_selection: bool, + /// Unbind needs a bound object under the selection, not just any selection. + selection_bound: bool, + /// Make Text Dynamic needs exactly one type object: a text variable only drives type. + single_type: bool, +} + +fn picked(st: &vectorcraft_engine::DocState) -> Picked { + let selected: Vec = st.selection.objects.iter().map(|i| i.0).collect(); + let selection_bound = selected.iter().any(|id| st.doc.variables.bindings.contains_key(&NodeId(*id))); + let single_type = matches!(selected.as_slice(), [one] if st.doc.node(NodeId(*one)).is_some_and(|n| matches!(n.kind, NodeKind::Text(_)))); + Picked { has_selection: !selected.is_empty(), selected, selection_bound, single_type } +} + /// Delete Variable: the highlighted variable only (the command's default); the rest stay. pub(crate) fn delete_highlighted(app: &mut VectorcraftApp) { app.run("variable.delete", json!({})).ok(); @@ -110,13 +127,8 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { }) .collect(); let active = sets.iter().find(|s| s.active); - let selected: Vec = st.selection.objects.iter().map(|i| i.0).collect(); - let has_selection = !selected.is_empty(); + let Picked { selected, has_selection, selection_bound, single_type } = picked(st); let highlighted = highlighted_row(st); - // 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 = 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| { @@ -226,6 +238,7 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) { let bound: Vec = st.doc.variables.bindings.keys().map(|i| i.0).collect(); let highlighted = highlighted_row(st); let highlighted_bound: Vec = highlighted.as_ref().map(|h| bound_objects(st, h)).unwrap_or_default(); + let Picked { selected, has_selection, selection_bound, single_type } = picked(st); if widgets::menu_item(ui, tl!("New Variable…"), true, false) { crate::menus::invoke(app, "variable.define", json!({})); @@ -235,6 +248,18 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) { let name = highlighted.clone().or_else(|| vars.first().cloned()).unwrap_or_default(); crate::dialogs::variables::open(app, "variable.rename", Some(&name)); } + if widgets::menu_item(ui, tl!("Make Text Dynamic"), single_type, false) { + app.run("variable.makeTextDynamic", json!({})).ok(); + } + if widgets::menu_item(ui, tl!("Make Visibility Dynamic"), has_selection, false) { + app.run("variable.makeVisibilityDynamic", json!({})).ok(); + } + if widgets::menu_item(ui, tl!("Unbind Variable"), selection_bound, false) { + app.run("variable.unbind", json!({"ids": selected})).ok(); + } + if widgets::menu_item(ui, tl!("Delete Variable"), highlighted.is_some(), false) { + delete_highlighted(app); + } ui.separator(); if widgets::menu_item(ui, tl!("Capture Data Set"), true, false) { app.run("dataset.capture", json!({})).ok(); @@ -405,38 +430,18 @@ mod tests { } } - /// Every Variables command is in the Window menu, so the feature is reachable without an - /// agent: the palette runs these with empty params, which the dialogs turn into a form. + /// Window › Variables opens the panel, as Window's other panel items do; its commands are in + /// the panel, its menu and the command palette. #[test] - fn every_variables_command_is_in_the_window_menu() { + fn window_variables_opens_the_panel() { let app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); let entries = crate::menus::menu_entries(&app); - let in_menu = |id: &str| entries.iter().any(|e| e.command.as_deref() == Some(id)); - for id in [ - "variable.define", - "variable.rename", - "variable.delete", - "variable.bind", - "variable.unbind", - "variable.makeTextDynamic", - "variable.makeVisibilityDynamic", - "dataset.new", - "dataset.set", - "dataset.capture", - "dataset.update", - "dataset.rename", - "dataset.delete", - "dataset.select", - "dataset.next", - "dataset.prev", - ] { - assert!(in_menu(id), "{id} is not in the Window menu"); - } let panel = entries .iter() .find(|e| e.command.as_deref() == Some("window.panel") && e.params.get("panel").and_then(serde_json::Value::as_str) == Some(ID)) .expect("the Variables panel is listed"); - assert_eq!(panel.path, vec!["Window".to_string(), "Variables".to_string()]); + assert_eq!((panel.path.clone(), panel.label.as_str()), (vec!["Window".to_string()], "Variables")); + assert!(!entries.iter().any(|e| e.path == ["Window", "Variables"]), "no Variables submenu"); } /// A menu item that needs a name opens the dialog rather than running the command with