mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-08 16:30:41 +00:00
Merge pull request #5172 from dotCooCoo/feat/action-options-rename
Actions: the panel menu's Action Options… renames the selected action
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
//! Actions panel › Create New Set (and ≡ › New Set…) and ≡ › Set Options…: the name of a new action
|
||||
//! set, or of the current one.
|
||||
//! Actions panel › Create New Set (and ≡ › New Set…), ≡ › Set Options… and ≡ › Action Options…:
|
||||
//! the name of a new action set, of the current one, or of the selected action.
|
||||
//!
|
||||
//! Fields: `set` (the index of the set renamed; none for a new set) and `name`. OK adds the set and
|
||||
//! makes it the current one, or renames the set.
|
||||
//! Fields: `set` (the index of the set renamed, or of the action's set; none for a new set),
|
||||
//! `action` (the index of the action renamed, in `set`; none for a set) and `name`. OK adds the set
|
||||
//! and makes it the current one, renames the set, or renames the action (`ui.action.rename`). A
|
||||
//! `set` or `action` field that is not the index of a set or action is an error, OK then changes
|
||||
//! no set or action, and the dialog stays open.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
|
||||
@@ -10,14 +13,20 @@ use super::DialogSpec;
|
||||
use crate::state::Dialog;
|
||||
use crate::{VectorcraftApp, widgets};
|
||||
|
||||
/// The dialog kind of New Set and Set Options.
|
||||
/// The dialog kind of New Set, Set Options and Action Options.
|
||||
pub const KIND: &str = "actionSetOptions";
|
||||
|
||||
pub(super) const SPEC: DialogSpec =
|
||||
DialogSpec { heading, body, confirm, ok_enabled: Some(|_, d| !d.str("name").trim().is_empty()), min_width: 300.0, ..DialogSpec::FORM };
|
||||
|
||||
fn heading(d: &Dialog) -> String {
|
||||
if d.fields.contains_key("set") { tl!("Set Options").into() } else { tl!("New Set").into() }
|
||||
if d.fields.contains_key("action") {
|
||||
tl!("Action Options").into()
|
||||
} else if d.fields.contains_key("set") {
|
||||
tl!("Set Options").into()
|
||||
} else {
|
||||
tl!("New Set").into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Open New Set, named "Set N" with the first number no set uses.
|
||||
@@ -34,6 +43,13 @@ pub fn open(app: &mut VectorcraftApp, set: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Open Action Options for the action at `action` in set `set`, if there is one.
|
||||
pub fn open_action(app: &mut VectorcraftApp, set: usize, action: usize) {
|
||||
if let Some(a) = app.ui.action_sets.get(set).and_then(|s| s.actions.get(action)) {
|
||||
app.ui.dialog = Some(Dialog::new(KIND, json!({"set": set, "action": action, "name": a.name})));
|
||||
}
|
||||
}
|
||||
|
||||
fn body(_: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
||||
widgets::label_row(ui, "Name:", 50.0, |ui| {
|
||||
super::form::text(ui, d, "name", 200.0);
|
||||
@@ -47,17 +63,30 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||
if name.is_empty() {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
match d.fields.get("set").and_then(Value::as_u64) {
|
||||
Some(set) => {
|
||||
if let Some(s) = app.ui.action_sets.get_mut(set as usize) {
|
||||
s.name = name;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
app.ui.action_sets.push(crate::panels::actions::ActionSet::new(name, vec![]));
|
||||
app.ui.action_set = Some(app.ui.action_sets.len() - 1);
|
||||
}
|
||||
// The fields the dialog holds choose what OK does, as they choose its heading.
|
||||
if d.fields.contains_key("action") {
|
||||
app.run(crate::panels::actions::RENAME_ACTION, json!({"set": d.fields.get("set"), "action": d.fields.get("action"), "name": name}))?;
|
||||
} else if let Some(set) = d.fields.get("set") {
|
||||
let s = set.as_u64().and_then(|i| usize::try_from(i).ok()).and_then(|i| app.ui.action_sets.get_mut(i)).ok_or("no such action set")?;
|
||||
s.name = name;
|
||||
} else {
|
||||
app.ui.action_sets.push(crate::panels::actions::ActionSet::new(name, vec![]));
|
||||
app.ui.action_set = Some(app.ui.action_sets.len() - 1);
|
||||
}
|
||||
app.ui.dialog = None;
|
||||
Ok(Value::Null)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// The heading names the dialog by what it holds: an action, a set, or neither.
|
||||
#[test]
|
||||
fn the_heading_names_action_options_set_options_or_new_set() {
|
||||
let heading_of = |fields: Value| heading(&Dialog::new(KIND, fields));
|
||||
assert_eq!(heading_of(json!({"set": 1, "action": 0, "name": "Nudge"})), "Action Options");
|
||||
assert_eq!(heading_of(json!({"set": 1, "name": "Mine"})), "Set Options");
|
||||
assert_eq!(heading_of(json!({"name": "Set 1"})), "New Set");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5561,6 +5561,9 @@ axis Y Axis Y ос
|
||||
New Set Нов набор
|
||||
Set Options… Опции на набора…
|
||||
Set Options Опции на набора
|
||||
Action Options… Опции на действието…
|
||||
Action Options Опции на действието
|
||||
Rename Action Преименуване на действие
|
||||
Create New Set Създаване на нов набор
|
||||
Stop Global Edit Край на глобалното редактиране
|
||||
Global Edit Options Опции за глобално редактиране
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5584,6 +5584,9 @@ axis Y Axis Y osa
|
||||
New Set Novi skup
|
||||
Set Options… Opcije skupa…
|
||||
Set Options Opcije skupa
|
||||
Action Options… Opcije akcije…
|
||||
Action Options Opcije akcije
|
||||
Rename Action Preimenuj akciju
|
||||
Create New Set Napravi novi skup
|
||||
Stop Global Edit Zaustavi globalno uređivanje
|
||||
Global Edit Options Opcije globalnog uređivanja
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3744,6 +3744,9 @@ digits Malayalam Malaiàlam
|
||||
Set Keyboard Shortcut Defineix la drecera de teclat
|
||||
Set Mesh Point Color Defineix el color del punt de malla
|
||||
Set Options Defineix les opcions
|
||||
Action Options… Opcions de l’acció…
|
||||
Action Options Opcions de l’acció
|
||||
Rename Action Canvia el nom de l’acció
|
||||
Set Options… Defineix les opcions…
|
||||
Set Preference Defineix la preferència
|
||||
Set Slice Rectangle Defineix el rectangle del tall
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5673,6 +5673,9 @@ axis Y Axis osa Y
|
||||
New Set Nová sada
|
||||
Set Options… Možnosti sady…
|
||||
Set Options Možnosti sady
|
||||
Action Options… Možnosti akce…
|
||||
Action Options Možnosti akce
|
||||
Rename Action Přejmenovat akci
|
||||
Create New Set Vytvořit novou sadu
|
||||
Stop Global Edit Ukončit globální úpravy
|
||||
Global Edit Options Možnosti globálních úprav
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5577,6 +5577,9 @@ axis Y Axis Y-akse
|
||||
New Set Nyt sæt
|
||||
Set Options… Indstillinger for sæt…
|
||||
Set Options Indstillinger for sæt
|
||||
Action Options… Indstillinger for handling…
|
||||
Action Options Indstillinger for handling
|
||||
Rename Action Omdøb handling
|
||||
Create New Set Opret nyt sæt
|
||||
Stop Global Edit Stop global redigering
|
||||
Global Edit Options Indstillinger for global redigering
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5255,6 +5255,9 @@ axis Y Axis Y-Achse
|
||||
New Set Neuer Satz
|
||||
Set Options… Satzoptionen…
|
||||
Set Options Satzoptionen
|
||||
Action Options… Aktionsoptionen…
|
||||
Action Options Aktionsoptionen
|
||||
Rename Action Aktion umbenennen
|
||||
Create New Set Neuen Satz erstellen
|
||||
Stop Global Edit Globale Bearbeitung beenden
|
||||
Global Edit Options Optionen für globale Bearbeitung
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5624,6 +5624,9 @@ axis Y Axis Άξονας Y
|
||||
New Set Νέο σύνολο
|
||||
Set Options… Επιλογές συνόλου…
|
||||
Set Options Επιλογές συνόλου
|
||||
Action Options… Επιλογές ενέργειας…
|
||||
Action Options Επιλογές ενέργειας
|
||||
Rename Action Μετονομασία ενέργειας
|
||||
Create New Set Δημιουργία νέου συνόλου
|
||||
Stop Global Edit Τερματισμός καθολικής επεξεργασίας
|
||||
Global Edit Options Επιλογές καθολικής επεξεργασίας
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 163 and column 5.
|
@@ -5614,6 +5614,9 @@ axis Y Axis Eje Y
|
||||
New Set Nuevo conjunto
|
||||
Set Options… Opciones de conjunto…
|
||||
Set Options Opciones de conjunto
|
||||
Action Options… Opciones de acción…
|
||||
Action Options Opciones de acción
|
||||
Rename Action Cambiar nombre de acción
|
||||
Create New Set Crear nuevo conjunto
|
||||
Stop Global Edit Detener edición global
|
||||
Global Edit Options Opciones de edición global
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5703,6 +5703,9 @@ axis Y Axis Y-akseli
|
||||
New Set Uusi sarja
|
||||
Set Options… Sarjan asetukset…
|
||||
Set Options Sarjan asetukset
|
||||
Action Options… Toiminnon asetukset…
|
||||
Action Options Toiminnon asetukset
|
||||
Rename Action Nimeä toiminto uudelleen
|
||||
Create New Set Luo uusi sarja
|
||||
Stop Global Edit Lopeta yleismuokkaus
|
||||
Global Edit Options Yleismuokkauksen asetukset
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5670,6 +5670,9 @@ axis Y Axis Axe Y
|
||||
New Set Nouveau jeu
|
||||
Set Options… Options du jeu…
|
||||
Set Options Options du jeu
|
||||
Action Options… Options de script…
|
||||
Action Options Options de script
|
||||
Rename Action Renommer le script
|
||||
Create New Set Créer un jeu
|
||||
Stop Global Edit Arrêter la modification globale
|
||||
Global Edit Options Options de modification globale
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5658,6 +5658,9 @@ axis Y Axis Y tengely
|
||||
New Set Új készlet
|
||||
Set Options… Készlet beállításai…
|
||||
Set Options Készlet beállításai
|
||||
Action Options… Művelet beállításai…
|
||||
Action Options Művelet beállításai
|
||||
Rename Action Művelet átnevezése
|
||||
Create New Set Új készlet létrehozása
|
||||
Stop Global Edit Globális szerkesztés befejezése
|
||||
Global Edit Options Globális szerkesztés beállításai
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5577,6 +5577,9 @@ axis Y Axis Sumbu Y
|
||||
New Set Set baru
|
||||
Set Options… Opsi set…
|
||||
Set Options Opsi set
|
||||
Action Options… Opsi tindakan…
|
||||
Action Options Opsi tindakan
|
||||
Rename Action Ganti nama tindakan
|
||||
Create New Set Buat set baru
|
||||
Stop Global Edit Hentikan edit global
|
||||
Global Edit Options Opsi edit global
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2194 and column 5.
|
@@ -5289,6 +5289,9 @@ axis Y Axis Asse Y
|
||||
New Set Nuovo set
|
||||
Set Options… Opzioni set…
|
||||
Set Options Opzioni set
|
||||
Action Options… Opzioni azione…
|
||||
Action Options Opzioni azione
|
||||
Rename Action Rinomina azione
|
||||
Create New Set Crea nuovo set
|
||||
Stop Global Edit Interrompi modifica globale
|
||||
Global Edit Options Opzioni modifica globale
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5356,6 +5356,9 @@ axis Y Axis Y 軸
|
||||
New Set 新規セット
|
||||
Set Options… セットオプション…
|
||||
Set Options セットオプション
|
||||
Action Options… アクションオプション…
|
||||
Action Options アクションオプション
|
||||
Rename Action アクション名を変更
|
||||
Create New Set 新規セットを作成
|
||||
Stop Global Edit グローバル編集を終了
|
||||
Global Edit Options グローバル編集オプション
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5587,6 +5587,9 @@ axis Y Axis Y ღერძი
|
||||
New Set ახალი ნაკრები
|
||||
Set Options… ნაკრების პარამეტრები…
|
||||
Set Options ნაკრების პარამეტრები
|
||||
Action Options… მოქმედების პარამეტრები…
|
||||
Action Options მოქმედების პარამეტრები
|
||||
Rename Action მოქმედების სახელის შეცვლა
|
||||
Create New Set ახალი ნაკრების შექმნა
|
||||
Stop Global Edit გლობალური რედაქტირების დასრულება
|
||||
Global Edit Options გლობალური რედაქტირების პარამეტრები
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5252,6 +5252,9 @@ axis Y Axis Y축
|
||||
New Set 새 세트
|
||||
Set Options… 세트 옵션…
|
||||
Set Options 세트 옵션
|
||||
Action Options… 액션 옵션…
|
||||
Action Options 액션 옵션
|
||||
Rename Action 액션 이름 바꾸기
|
||||
Create New Set 새 세트 만들기
|
||||
Stop Global Edit 전체 편집 중지
|
||||
Global Edit Options 전체 편집 옵션
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5621,6 +5621,9 @@ axis Y Axis Y-as
|
||||
New Set Nieuwe set
|
||||
Set Options… Setopties…
|
||||
Set Options Setopties
|
||||
Action Options… Actieopties…
|
||||
Action Options Actieopties
|
||||
Rename Action Actie hernoemen
|
||||
Create New Set Nieuwe set maken
|
||||
Stop Global Edit Globale bewerking stoppen
|
||||
Global Edit Options Opties voor globale bewerking
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5526,6 +5526,9 @@ axis Y Axis Oś Y
|
||||
New Set Nowy zestaw
|
||||
Set Options… Opcje zestawu…
|
||||
Set Options Opcje zestawu
|
||||
Action Options… Opcje operacji…
|
||||
Action Options Opcje operacji
|
||||
Rename Action Zmień nazwę operacji
|
||||
Create New Set Utwórz nowy zestaw
|
||||
Stop Global Edit Zakończ edycję globalną
|
||||
Global Edit Options Opcje edycji globalnej
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5588,6 +5588,9 @@ axis Y Axis Eixo Y
|
||||
New Set Novo Conjunto
|
||||
Set Options… Opções do Conjunto…
|
||||
Set Options Opções do Conjunto
|
||||
Action Options… Opções da Ação…
|
||||
Action Options Opções da Ação
|
||||
Rename Action Renomear Ação
|
||||
Create New Set Criar Novo Conjunto
|
||||
Stop Global Edit Parar Edição Global
|
||||
Global Edit Options Opções de Edição Global
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -5284,6 +5284,9 @@ axis Y Axis Ось Y
|
||||
New Set Новый набор
|
||||
Set Options… Параметры набора…
|
||||
Set Options Параметры набора
|
||||
Action Options… Параметры действия…
|
||||
Action Options Параметры действия
|
||||
Rename Action Переименовать действие
|
||||
Create New Set Создать новый набор
|
||||
Stop Global Edit Завершить глобальное редактирование
|
||||
Global Edit Options Параметры глобального редактирования
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5696,6 +5696,9 @@ axis Y Axis Y-axel
|
||||
New Set Ny uppsättning
|
||||
Set Options… Alternativ för uppsättning…
|
||||
Set Options Alternativ för uppsättning
|
||||
Action Options… Alternativ för åtgärd…
|
||||
Action Options Alternativ för åtgärd
|
||||
Rename Action Byt namn på åtgärd
|
||||
Create New Set Skapa ny uppsättning
|
||||
Stop Global Edit Avsluta global redigering
|
||||
Global Edit Options Alternativ för global redigering
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -5630,6 +5630,9 @@ axis Y Axis Y ekseni
|
||||
New Set Yeni Set
|
||||
Set Options… Set Seçenekleri…
|
||||
Set Options Set Seçenekleri
|
||||
Action Options… Eylem Seçenekleri…
|
||||
Action Options Eylem Seçenekleri
|
||||
Rename Action Eylemi Yeniden Adlandır
|
||||
Create New Set Yeni Set Oluştur
|
||||
Stop Global Edit Genel Düzenlemeyi Durdur
|
||||
Global Edit Options Genel Düzenleme Seçenekleri
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -5269,6 +5269,9 @@ axis Y Axis Вісь Y
|
||||
New Set Новий набір
|
||||
Set Options… Параметри набору…
|
||||
Set Options Параметри набору
|
||||
Action Options… Параметри дії…
|
||||
Action Options Параметри дії
|
||||
Rename Action Перейменувати дію
|
||||
Create New Set Створити новий набір
|
||||
Stop Global Edit Завершити глобальне редагування
|
||||
Global Edit Options Параметри глобального редагування
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 177 and column 5.
|
@@ -5272,6 +5272,9 @@ axis Y Axis Trục Y
|
||||
New Set Bộ mới
|
||||
Set Options… Tùy chọn bộ…
|
||||
Set Options Tùy chọn bộ
|
||||
Action Options… Tùy chọn hành động…
|
||||
Action Options Tùy chọn hành động
|
||||
Rename Action Đổi tên hành động
|
||||
Create New Set Tạo bộ mới
|
||||
Stop Global Edit Dừng chỉnh sửa toàn cục
|
||||
Global Edit Options Tùy chọn chỉnh sửa toàn cục
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 199 and column 5.
|
@@ -5513,6 +5513,9 @@ axis Y Axis Y 轴
|
||||
New Set 新建组
|
||||
Set Options… 组选项…
|
||||
Set Options 组选项
|
||||
Action Options… 动作选项…
|
||||
Action Options 动作选项
|
||||
Rename Action 重命名动作
|
||||
Create New Set 创建新组
|
||||
Stop Global Edit 停止全局编辑
|
||||
Global Edit Options 全局编辑选项
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5309,6 +5309,9 @@ axis Y Axis Y 軸
|
||||
New Set 新增組
|
||||
Set Options… 組選項…
|
||||
Set Options 組選項
|
||||
Action Options… 動作選項…
|
||||
Action Options 動作選項
|
||||
Rename Action 重新命名動作
|
||||
Create New Set 建立新組
|
||||
Stop Global Edit 停止整體編輯
|
||||
Global Edit Options 整體編輯選項
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -783,6 +783,7 @@ fn run_ui_part11(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<Result
|
||||
crate::dialogs::find_links::find_in_folder_command(app, s("folder"), p.get("ids").and_then(Value::as_array).cloned())
|
||||
}
|
||||
"ui.packageDialog" => crate::dialogs::package::open(app),
|
||||
crate::panels::actions::RENAME_ACTION => crate::panels::actions::rename_action(app, p),
|
||||
"ui.batchDialog" => {
|
||||
let set = p.get("set").and_then(Value::as_u64).unwrap_or(0) as usize;
|
||||
let action = p.get("action").and_then(Value::as_u64).unwrap_or(0) as usize;
|
||||
|
||||
@@ -1113,6 +1113,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
|
||||
"Cmd+Alt+Shift+P",
|
||||
"{} open Package for the saved document (dialog `package`: folder, name, copyLinks, linksFolder, relink, copyFonts, report; a document never saved asks to Save As first); OK saves unsaved changes, runs file.package (the web downloads the zip) and offers file.showPackage",
|
||||
),
|
||||
(
|
||||
crate::panels::actions::RENAME_ACTION,
|
||||
"Rename Action",
|
||||
"",
|
||||
"{set: index, action: index, name} rename the Actions panel's action at action in set (0 is the top set) to name, with spaces trimmed from both ends; its steps stay. The panel menu's Action Options… (dialog `actionSetOptions` with set, action and name) runs this for the selected action. An index past the last set or action, or an empty name, is an error and renames nothing → {name}",
|
||||
),
|
||||
(
|
||||
"ui.batchDialog",
|
||||
"Batch…",
|
||||
|
||||
@@ -76,6 +76,24 @@ pub fn play(app: &mut VectorcraftApp, set: usize, idx: usize) -> Result<Value, S
|
||||
app.run("command.batch", json!({"label": a.name, "commands": commands}))
|
||||
}
|
||||
|
||||
/// The command that renames an action ([`rename_action`]).
|
||||
pub const RENAME_ACTION: &str = "ui.action.rename";
|
||||
|
||||
/// `ui.action.rename {set, action, name}`: renames the action at index `action` of set `set` (0 is
|
||||
/// the top set) to `name` with spaces trimmed from both ends, and keeps its steps. An index past
|
||||
/// the last set or action, or a name with nothing but spaces, is an error, and then nothing is
|
||||
/// renamed. The panel menu's Action Options… runs this for the selected action. → {name}
|
||||
pub fn rename_action(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
|
||||
let index = |k: &str| p.get(k).and_then(Value::as_u64).and_then(|i| usize::try_from(i).ok());
|
||||
let name = p.get("name").and_then(Value::as_str).map(str::trim).unwrap_or_default();
|
||||
let action = index("set").zip(index("action")).and_then(|(s, a)| app.ui.action_sets.get_mut(s)?.actions.get_mut(a)).ok_or("no such action")?;
|
||||
if name.is_empty() {
|
||||
return Err("name is empty".into());
|
||||
}
|
||||
action.name = name.to_string();
|
||||
Ok(json!({ "name": name }))
|
||||
}
|
||||
|
||||
/// The command that deletes action sets ([`delete_sets`]).
|
||||
pub const DELETE_SETS: &str = "ui.actionSet.delete";
|
||||
|
||||
@@ -163,6 +181,14 @@ pub fn delete_sets(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String>
|
||||
d.fields.insert("set".into(), json!(set - sets.iter().filter(|&&s| s < set).count()));
|
||||
}
|
||||
}
|
||||
// The panel's selected action follows its set down too, and is no longer selected when its set
|
||||
// is deleted, so a set made later at its old index does not find it selected.
|
||||
if let Some(ctx) = app.ui_ctx.clone()
|
||||
&& let Some((set, action)) = pstate::<Option<(usize, usize)>>(&ctx, "actions-selected")
|
||||
{
|
||||
let moved = (!sets.contains(&set)).then(|| (set - sets.iter().filter(|&&s| s < set).count(), action));
|
||||
set_pstate::<Option<(usize, usize)>>(&ctx, "actions-selected", moved);
|
||||
}
|
||||
for &s in sets.iter().rev() {
|
||||
app.ui.action_sets.remove(s);
|
||||
}
|
||||
@@ -257,7 +283,9 @@ pub fn duplicate(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
|
||||
|
||||
/// The panel's (≡) menu.
|
||||
pub fn menu(app: &mut VectorcraftApp, ui: &mut egui::Ui) {
|
||||
let selected: Option<(usize, usize)> = pstate(ui.ctx(), "actions-selected");
|
||||
// A selected action counts only while its set is the current one, as the panel shows it: a set
|
||||
// deleted since leaves the stored pair pointing at another set's action.
|
||||
let selected = pstate::<Option<(usize, usize)>>(ui.ctx(), "actions-selected").filter(|&(s, _)| app.ui.action_set == Some(s));
|
||||
let has = selected.and_then(|(s, a)| app.ui.action_sets.get(s).and_then(|set| set.actions.get(a))).is_some();
|
||||
if widgets::menu_item(ui, tl!("New Set…"), true, false) {
|
||||
crate::dialogs::action_set_options::open_new(app);
|
||||
@@ -286,6 +314,11 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut egui::Ui) {
|
||||
{
|
||||
app.status(e);
|
||||
}
|
||||
if widgets::menu_item(ui, tl!("Action Options…"), has, false)
|
||||
&& let Some((s, a)) = selected
|
||||
{
|
||||
crate::dialogs::action_set_options::open_action(app, s, a);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(app: &mut VectorcraftApp, ui: &mut egui::Ui) {
|
||||
@@ -532,6 +565,134 @@ mod tests {
|
||||
assert_eq!(names, [("Default Actions", 6), ("Web", 0)], "the clicked set is renamed, the other kept");
|
||||
}
|
||||
|
||||
/// #1629: the panel menu's Action Options… is off with no action selected, and with an action
|
||||
/// selected it asks for a new name: OK renames that action and keeps its steps, Cancel keeps
|
||||
/// the name.
|
||||
#[test]
|
||||
fn action_options_renames_the_selected_action() {
|
||||
use super::super::tests_appearance::{click, frame_events, text_rect};
|
||||
let mut app = app_with_sets();
|
||||
let ctx = egui::Context::default();
|
||||
let action_options = |ctx: &egui::Context, app: &mut VectorcraftApp| {
|
||||
let texts = frame_events(ctx, app, vec![], menu);
|
||||
let item = texts.iter().find(|(s, _)| s.trim() == "Action Options…").map(|(_, r)| *r).expect("Action Options… in the menu");
|
||||
click(ctx, app, item.center(), menu);
|
||||
};
|
||||
action_options(&ctx, &mut app);
|
||||
assert!(app.ui.dialog.is_none(), "no action selected: Action Options… is off");
|
||||
let texts = frame_events(&ctx, &mut app, vec![], show);
|
||||
click(&ctx, &mut app, text_rect(&texts, "Nudge Again").center(), show);
|
||||
frame_events(&ctx, &mut app, vec![], show);
|
||||
action_options(&ctx, &mut app);
|
||||
let d = app.ui.dialog.as_ref().expect("Action Options opens");
|
||||
assert_eq!((d.kind.as_str(), d.str("name")), (crate::dialogs::action_set_options::KIND, "Nudge Again".to_string()));
|
||||
crate::dialogs::cancel(&mut app);
|
||||
assert_eq!(app.ui.action_sets[1].actions[1].name, "Nudge Again", "Cancel keeps the name");
|
||||
action_options(&ctx, &mut app);
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("name".into(), json!(" Nudge Right "));
|
||||
crate::dialogs::confirm(&mut app).unwrap();
|
||||
assert!(app.ui.dialog.is_none());
|
||||
let names = app.ui.action_sets[1].actions.iter().map(|a| a.name.as_str()).collect::<Vec<_>>();
|
||||
assert_eq!(names, ["Nudge", "Nudge Right"], "the selected action is renamed, trimmed; the other is kept");
|
||||
assert_eq!(app.ui.action_sets[1].actions[1].steps, [("object.move".to_string(), json!({"dx": 1, "dy": 0}))], "the steps stay");
|
||||
assert_eq!(set_names(&app), ["Default Actions", "Mine", "Other"], "no set is renamed");
|
||||
}
|
||||
|
||||
/// `ui.action.rename` renames the action at its set and action indexes and refuses a missing
|
||||
/// index or a name with nothing but spaces, renaming nothing.
|
||||
#[test]
|
||||
fn rename_action_renames_one_action_and_refuses_bad_params() {
|
||||
let mut app = app_with_sets();
|
||||
let names = |app: &VectorcraftApp| app.ui.action_sets[1].actions.iter().map(|a| a.name.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(app.run(RENAME_ACTION, json!({"set": 1, "action": 0, "name": "Push"})).unwrap(), json!({"name": "Push"}));
|
||||
assert_eq!(names(&app), ["Push", "Nudge Again"]);
|
||||
for p in [
|
||||
json!({"set": 1, "action": 2, "name": "X"}),
|
||||
json!({"set": 3, "action": 0, "name": "X"}),
|
||||
json!({"set": 1, "name": "X"}),
|
||||
json!({"action": 0, "name": "X"}),
|
||||
json!({"set": 4_294_967_297u64, "action": 0, "name": "X"}),
|
||||
] {
|
||||
assert_eq!(app.run(RENAME_ACTION, p.clone()).unwrap_err(), "no such action", "{p}");
|
||||
}
|
||||
assert_eq!(app.run(RENAME_ACTION, json!({"set": 1, "action": 0, "name": " "})).unwrap_err(), "name is empty");
|
||||
assert_eq!(app.run(RENAME_ACTION, json!({"set": 1, "action": 0})).unwrap_err(), "name is empty");
|
||||
assert_eq!(names(&app), ["Push", "Nudge Again"], "a refused rename renames nothing");
|
||||
}
|
||||
|
||||
/// OK in Action Options or Set Options whose `set` or `action` field `ui.dialog.set` changed to
|
||||
/// something that is not an index is an error: it renames no set or action, adds no set, and
|
||||
/// keeps the dialog open.
|
||||
#[test]
|
||||
fn options_with_a_field_that_is_not_an_index_change_nothing() {
|
||||
use crate::dialogs::action_set_options::KIND;
|
||||
let mut app = app_with_sets();
|
||||
for fields in [
|
||||
json!({"set": 1, "action": null, "name": "X"}),
|
||||
json!({"set": null, "action": 0, "name": "X"}),
|
||||
json!({"set": 1, "action": 9, "name": "X"}),
|
||||
json!({"set": null, "name": "X"}),
|
||||
json!({"set": 9, "name": "X"}),
|
||||
] {
|
||||
app.ui.dialog = Some(crate::state::Dialog::new(KIND, fields.clone()));
|
||||
assert!(crate::dialogs::confirm(&mut app).is_err(), "{fields}");
|
||||
assert!(app.ui.dialog.is_some(), "the dialog stays open: {fields}");
|
||||
assert_eq!(set_names(&app), ["Default Actions", "Mine", "Other"], "{fields}");
|
||||
let names = app.ui.action_sets[1].actions.iter().map(|a| a.name.as_str()).collect::<Vec<_>>();
|
||||
assert_eq!(names, ["Nudge", "Nudge Again"], "{fields}");
|
||||
}
|
||||
}
|
||||
|
||||
/// After `ui.actionSet.delete` removes a set above the selected action's set, the panel menu's
|
||||
/// Action Options… is off: it does not open for the action that moved to the stored position.
|
||||
#[test]
|
||||
fn action_options_is_off_after_a_set_above_the_selection_is_deleted() {
|
||||
use super::super::tests_appearance::{click, frame_events};
|
||||
let mut app = app_with_sets();
|
||||
let action = |name: &str| Action { name: name.into(), steps: vec![] };
|
||||
app.ui.action_sets[2].actions.push(action("Spin"));
|
||||
app.ui.action_sets.push(ActionSet::new("Last", vec![action("Wrong")]));
|
||||
let ctx = egui::Context::default();
|
||||
app.ui.action_set = Some(2);
|
||||
set_pstate::<Option<(usize, usize)>>(&ctx, "actions-selected", Some((2, 0)));
|
||||
app.run(DELETE_SETS, json!({"sets": [1]})).unwrap();
|
||||
assert_eq!(app.ui.action_set, Some(1), "Other is still current");
|
||||
let texts = frame_events(&ctx, &mut app, vec![], menu);
|
||||
let item = texts.iter().find(|(s, _)| s.trim() == "Action Options…").map(|(_, r)| *r).expect("Action Options… in the menu");
|
||||
click(&ctx, &mut app, item.center(), menu);
|
||||
assert!(app.ui.dialog.is_none(), "Action Options… does not open for Last's action");
|
||||
}
|
||||
|
||||
/// `ui.actionSet.delete` moves the panel's selected action down with its set, and clears it
|
||||
/// when its set is deleted: a new set made at that index, and the action recorded into it, are
|
||||
/// not selected, so the panel menu's Action Options… stays off.
|
||||
#[test]
|
||||
fn deleting_sets_moves_or_clears_the_selected_action() {
|
||||
use super::super::tests_appearance::{click, frame_events};
|
||||
let selected = |ctx: &egui::Context| pstate::<Option<(usize, usize)>>(ctx, "actions-selected");
|
||||
let mut app = app_with_sets();
|
||||
let ctx = egui::Context::default();
|
||||
app.ui_ctx = Some(ctx.clone());
|
||||
app.ui.action_set = Some(1);
|
||||
set_pstate::<Option<(usize, usize)>>(&ctx, "actions-selected", Some((1, 1)));
|
||||
app.run(DELETE_SETS, json!({"sets": [0]})).unwrap();
|
||||
assert_eq!(selected(&ctx), Some((0, 1)), "Nudge Again is still selected, at its set's new index");
|
||||
app.ui.action_sets.push(ActionSet::new("Last", vec![]));
|
||||
app.ui.action_set = Some(2);
|
||||
set_pstate::<Option<(usize, usize)>>(&ctx, "actions-selected", Some((2, 0)));
|
||||
app.ui.action_sets[2].actions.push(Action { name: "Spin".into(), steps: vec![] });
|
||||
app.run(DELETE_SETS, json!({"sets": [2]})).unwrap();
|
||||
assert_eq!(selected(&ctx), None, "the deleted set's action is no longer selected");
|
||||
crate::dialogs::action_set_options::open_new(&mut app);
|
||||
crate::dialogs::confirm(&mut app).unwrap();
|
||||
assert_eq!(app.ui.action_set, Some(2), "the new set is current, at the deleted set's index");
|
||||
app.ui.action_sets[2].actions.push(Action { name: "Recorded".into(), steps: vec![] });
|
||||
let texts = frame_events(&ctx, &mut app, vec![], menu);
|
||||
let item = texts.iter().find(|(s, _)| s.trim() == "Action Options…").map(|(_, r)| *r).expect("Action Options… in the menu");
|
||||
click(&ctx, &mut app, item.center(), menu);
|
||||
assert!(app.ui.dialog.is_none(), "Action Options… does not open for the new set's action");
|
||||
}
|
||||
|
||||
/// An app with the default set and the sets Mine (two actions) and Other.
|
||||
fn app_with_sets() -> VectorcraftApp {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
|
||||
@@ -1686,6 +1686,10 @@ already walks Image Trace. Short agent entry points:
|
||||
is one of the format's extensions (`.svg` and `SVG` give `.svg`, `.JPEG` gives `.jpeg`), and otherwise in the
|
||||
format's first extension (`png8` gives `.png`, `template` gives `.vctemplate`). A step without `format` keeps the
|
||||
source file's extension (`.vectorcraft` over data sets).
|
||||
- Actions: `ui.action.rename {set, action, name}` renames the Actions panel's action at `action` in set `set` (0 is
|
||||
the top set) to `name` with spaces trimmed from both ends, keeps its steps, and returns `{name}`. An index past the
|
||||
last set or action, or an empty name, is an error, and then nothing is renamed. The panel menu's Action Options…
|
||||
runs this for the selected action.
|
||||
- Action sets: `ui.actionSet.delete {sets?: [index], ids?: [id]}` deletes the Actions panel's sets at these indexes
|
||||
(0 is the top set) with their actions, by default the current set, and returns `{deleted}`. An index past the last
|
||||
set is an error, and then no set is deleted. `ids` holds the panel's own set ids, which its question passes: the
|
||||
|
||||
@@ -549,6 +549,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- Variables: when no object is bound to a variable that the data set has a value for, for example after Import Data Sets… defines new variables without binding them, choosing the data set in the Variables panel or stepping to it with the panel's arrows shows a status message, and `dataset.select`, `dataset.next` and `dataset.prev` add the message to the reply as `warning`.
|
||||
- Variables: Lock Variables (`variable.lock`, in the Variables panel's bottom bar and menu) stops variables from being defined, deleted or renamed until they are unlocked, while objects can still be bound and unbound and data sets still change and apply; the lock is saved with the document.
|
||||
- Batch…: Override Save and Override Export name each file with the extension of the format the step writes, however the step spells the format (`.svg` and `SVG` give `.svg`, `png8` gives `.png`), in `action.batch`.
|
||||
- Actions panel: the panel menu's Action Options… renames the selected action and keeps its steps ([Actions panel overview](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/actions-panel-overview.html): "Opens a dialog to rename or assign function keys/colors to the action"; `ui.action.rename`). The dialog has the name only; the function key and color are not there yet.
|
||||
- Actions panel (record/playback, persisted), generic parameter dialogs for every "…" command.
|
||||
- Actions panel: the current set is kept with the UI preferences, so after a restart a recording goes into the set that was current, not into the first set. With no set current, Begin Recording records into the first set and makes it current.
|
||||
- Actions panel: Delete Selection deletes the selected action set with its actions and keeps the other sets ([Actions panel overview](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/actions-panel-overview.html): "Removes the selected action, command, or action set from the panel"; `ui.actionSet.delete`). VectorCraft's own rules, which the overview does not cover: deleting a set asks first, Shift-click on a set's name selects a range of sets to delete together, the panel menu's Delete does the same, and Default Actions and the last set can be deleted. Undo does not bring a deleted set back.
|
||||
|
||||
@@ -296,6 +296,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Live trace result bounds and selection highlights exclude the retained bitmap; source-image views retain it | done | All TraceView modes and rotated result bounds regression-covered; ordinary hidden group behavior retained |
|
||||
| Image Trace panel: the Preview checkbox before Trace chooses whether a setting change traces the selected Image Trace object again at once | done | Per the public documentation, Preview shows the result of the current settings and Trace traces with them (<https://web.archive.org/web/20250831090623/https://helpx.adobe.com/illustrator/using/image-trace.html>). Preview is on by default and kept with the UI preferences; Reset to Default leaves it. Off, changes wait in the panel until Trace applies them as one undo step, or until Preview is turned on again. Changes stay with the object they were made for while another object is selected, and come back when it is selected again. `imageTrace.preview {on?}`, `ui.set {imageTracePreview}`; `panels/image_trace.rs` headless tests (`with_preview_off_a_slider_change_waits_for_trace`, `turning_preview_on_traces_the_changes_that_waited`, `preview_turned_on_with_nothing_selected_traces_when_the_object_is_selected_again`, `settings_that_wait_stay_with_their_object`, `settings_that_wait_come_back_when_their_object_is_selected_again`, `settings_that_wait_are_dropped_when_their_object_changed_since`, `preview_is_kept_with_the_preferences_and_reset_to_default_leaves_it`) |
|
||||
| Toolbar without group labels by default, one or two columns; All Tools drawer by flyout group with shortcuts, its menu (Reset, Basic, Advanced) and Show section | done | #1751; a preference brings the labels back; `toolbar.show` sets the Fill/Stroke, Coloring, Draw Mode and Screen Mode controls |
|
||||
| Actions panel: ≡ › Action Options… renames the selected action ([Actions panel overview](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/actions-panel-overview.html): "Opens a dialog to rename or assign function keys/colors to the action") | partial | `ui.action.rename`; `panels/actions.rs` tests (part of #1629). The dialog has the name only: the function key and color remain |
|
||||
| Actions panel: a clicked action stays selected for Play Current Selection and Delete Selection | partial | #1853 (part of #1629); editing actions and action shortcuts remain |
|
||||
| Actions panel: Create New Set (bottom bar, ≡ › New Set…) names a new set and Set Options… renames the current one; a click on a set's name makes it current and a recording goes into the current set ([helpx: Automation with actions](https://helpx.adobe.com/illustrator/using/automation-actions.html)); the current set is kept with the UI preferences, and with no set current a recording goes into the first set, which becomes current | partial | #3712; the New Action dialog (name, set menu, shortcut, colour) and dragging actions between sets remain |
|
||||
| Actions panel: Delete Selection (bottom bar) deletes the selected set with its actions and keeps the other sets ([Actions panel overview](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/actions-panel-overview.html): "Removes the selected action, command, or action set from the panel") | partial | `ui.actionSet.delete`; `panels/actions.rs` tests. VectorCraft's own rules, which the overview does not cover: deleting a set asks first (a selected action is still deleted at once), Shift-click on a set's name selects a range of sets, ≡ › Delete does the same as the button, and Default Actions and the last set can be deleted. Undo does not restore a deleted set, and recorded commands cannot be selected or deleted |
|
||||
|
||||
Reference in New Issue
Block a user